summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorjk7744.park <jk7744.park@samsung.com>2015-10-24 15:28:19 +0900
committerjk7744.park <jk7744.park@samsung.com>2015-10-24 15:28:19 +0900
commit841a80cb5613b15fd5d7d256e21ab0a69df081e9 (patch)
tree56e13bf65224f1554bd6cf4033f223b3ceb5d0e4 /tests
parentcb41fec8f453fd5dc9fb1d4a92a6d49f043578fc (diff)
downloadxserver-xorg-video-exynos-accepted/tizen_2.4_mobile.tar.gz
xserver-xorg-video-exynos-accepted/tizen_2.4_mobile.tar.bz2
xserver-xorg-video-exynos-accepted/tizen_2.4_mobile.zip
Diffstat (limited to 'tests')
-rw-r--r--tests/functional/Makefile.am1
-rw-r--r--tests/functional/hwa_test/Makefile.am9
-rw-r--r--tests/functional/hwa_test/hwa_sample.c531
-rw-r--r--tests/functional/hwa_test/hwa_sample.h79
-rw-r--r--tests/functional/hwc_test/Makefile.am41
-rw-r--r--tests/functional/hwc_test/aux_apps.c324
-rw-r--r--tests/functional/hwc_test/aux_apps.h47
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/aux_draw.c265
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/dri2.c394
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.c227
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.h135
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3_inner.h82
-rw-r--r--tests/functional/hwc_test/aux_dri2_dri3_lib/dri3.c542
-rwxr-xr-xtests/functional/hwc_test/aux_dri2_dri3_lib/fps.c108
-rwxr-xr-xtests/functional/hwc_test/aux_dri2_dri3_lib/fps.h47
-rw-r--r--tests/functional/hwc_test/clock.c316
-rwxr-xr-xtests/functional/hwc_test/hwc_sample/hwc-sample.c1377
-rw-r--r--tests/functional/hwc_test/hwc_sample/hwc-sample.h69
-rw-r--r--tests/functional/hwc_test/hwc_sample/hwc-thread.c0
-rw-r--r--tests/functional/hwc_test/hwc_sample/list.h24
-rwxr-xr-xtests/functional/hwc_test/launch.sh48
-rw-r--r--tests/functional/hwc_test/snowflake.c327
-rwxr-xr-xtests/functional/hwc_test/square_bubbles/square_bubbles.c647
-rw-r--r--tests/functional/hwc_test/wander_stripe.c259
-rw-r--r--tests/functional/pixmap_copy_test/Makefile.am9
-rw-r--r--tests/functional/pixmap_copy_test/pixmap_copy.c122
-rw-r--r--tests/functional/xv_test/Makefile.am12
-rw-r--r--tests/functional/xv_test/data.c242
-rw-r--r--tests/functional/xv_test/data.h18
-rw-r--r--tests/functional/xv_test/test_xv_resize.c520
-rw-r--r--tests/functional/xv_test/test_xv_resize.h6
-rw-r--r--tests/functional/xv_test/xcb_api.c258
-rw-r--r--tests/functional/xv_test/xcb_api.h80
-rw-r--r--tests/functional/xv_test/xv_test.c219
-rw-r--r--tests/functional/xv_test/xv_test.h111
35 files changed, 7496 insertions, 0 deletions
diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am
new file mode 100644
index 0000000..1990d80
--- /dev/null
+++ b/tests/functional/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = xv_test hwc_test hwa_test pixmap_copy_test
diff --git a/tests/functional/hwa_test/Makefile.am b/tests/functional/hwa_test/Makefile.am
new file mode 100644
index 0000000..51df582
--- /dev/null
+++ b/tests/functional/hwa_test/Makefile.am
@@ -0,0 +1,9 @@
+if HAVE_FT
+ bin_PROGRAMS = hwa_sample
+
+hwa_sample_CFLAGS = $(HWA_TEST_CFLAGS)
+hwa_sample_LDADD = $(HWA_TEST_LIBS)
+hwa_sample_SOURCES = \
+@top_srcdir@/tests/functional/hwa_test/hwa_sample.c
+
+endif
diff --git a/tests/functional/hwa_test/hwa_sample.c b/tests/functional/hwa_test/hwa_sample.c
new file mode 100644
index 0000000..7fc6ee2
--- /dev/null
+++ b/tests/functional/hwa_test/hwa_sample.c
@@ -0,0 +1,531 @@
+
+/* Standart headers */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <getopt.h>
+
+/* X Server's headers */
+#include <X11/Xlib.h>
+#include <xcb/xcb.h>
+#include <xcb/hwa.h>
+#include <xcb/dri3.h>
+#include <xcb/randr.h>
+
+#include "hwa_sample.h"
+
+void test_hwc( void );
+
+xcb_connection_t *c;
+xcb_generic_error_t *error;
+
+xcb_randr_crtc_t randr_crtc = 0;
+char con_name[20] = {0,};
+
+int main( int argc, char **argv )
+{
+ int rez;
+ int option_index;
+ int enable;
+ int angle;
+ char *scale_params = NULL;
+ const char* short_options = "ic:r:a:x:s:h:o:";
+
+ const struct option long_options[] =
+ {
+ {"help",no_argument,NULL,'?'},
+ {"info",no_argument,NULL,'i'},
+ {"version",no_argument,NULL,'v'},
+ {"cursore",required_argument,NULL,'c'},
+ {"cursorr",required_argument,NULL,'r'},
+ {"accessibility",required_argument,NULL,'a'},
+ {"scale",required_argument,NULL,'x'},
+ {"show",required_argument,NULL,'s'},
+ {"hide",required_argument,NULL,'h'},
+ {"output",required_argument,NULL,'o'},
+ {NULL,0,NULL,0}
+ };
+
+ c = xcb_connect (NULL, NULL);
+
+ while ( ( rez = getopt_long_only( argc,argv, short_options, long_options,&option_index ) ) != -1 )
+ {
+ switch(rez)
+ {
+ case '?':
+ help();
+ break;
+
+ case 'i':
+ extensions_info();
+ break;
+
+ case 'v':
+ hwa_query_version();
+ break;
+
+ case 'c':
+ enable = atoi(optarg);
+ hwa_cursor_enable( enable );
+ break;
+
+ case 'r':
+ angle = atoi(optarg);
+ hwa_cursor_rotate( angle );
+ break;
+
+ case 'a':
+ enable = atoi(optarg);
+ hwa_accessibility( enable );
+
+ break;
+
+ case 'x':
+ scale_params = (char *)calloc(30, sizeof( char ) );
+
+ enable = 0;
+
+ optind--;
+ for( ;optind < argc; optind++)
+ {
+ if ( 2 == optind )
+ enable = atoi(argv[optind]);
+ else
+ strcpy( scale_params, argv[optind] );
+ }
+
+ hwa_scale( enable, scale_params );
+ free( scale_params );
+
+ break;
+
+ case 's':
+ printf("show layer = %s\n",optarg);
+ hwa_show_layer(atoi(optarg));
+
+ break;
+
+ case 'h':
+ printf("hide layer= %s\n",optarg);
+ hwa_hide_layer(atoi(optarg));
+ break;
+
+ /*
+ * TODO
+ * output selector need implement
+ * */
+ case 'o':
+ printf("[%s] output chosen \n",optarg);
+ strcpy( con_name, optarg);
+ printf("con_name = [%s] \n",con_name);
+ break;
+
+ default:
+ PRINT(4);
+ printf("ERROR: found unknown option\n\n");
+
+ help();
+ break;
+ }
+ }
+
+ xcb_disconnect(c);
+
+ return 0;
+}
+
+void extensions_info( void )
+{
+ xcb_list_extensions_reply_t *rep;
+ xcb_query_extension_reply_t *q_rep;
+
+ xcb_list_extensions_cookie_t ext_cookie;
+ xcb_query_extension_cookie_t query_c;
+
+ ext_cookie = xcb_list_extensions( c );
+ rep = xcb_list_extensions_reply( c, ext_cookie, &error );
+ xcb_flush(c);
+
+
+ /* List all Extensions which X Server supports */
+ printf( "\n-----------------------------------\n");
+
+ xcb_str_iterator_t str_iter = xcb_list_extensions_names_iterator( rep );
+
+ printf( "+++ index %d\n+++ %d\n", str_iter.index, str_iter.rem );
+
+ while (str_iter.rem)
+ {
+ printf("%d bytes: ", xcb_str_name_length(str_iter.data));
+ fwrite(xcb_str_name(str_iter.data), 1, xcb_str_name_length(str_iter.data), stdout);
+ printf("\n");
+ fixed_xcb_str_next(&str_iter);
+ }
+
+ printf( "\n-----------------------------------\n");
+
+ /* Check does X Server support HWA */
+ query_c = xcb_query_extension( c, 3, "HWA" );
+ q_rep = xcb_query_extension_reply( c, query_c, &error );
+
+ printf( "\n-----------------------------------\n");
+ printf( "Check HWA:\n"
+ "present: %d\n"
+ "major opcode: %d\n"
+ "first event: %d\n"
+ "first error: %d\n",
+ q_rep->present,
+ q_rep->major_opcode,
+ q_rep->first_event,
+ q_rep->first_error );
+
+ /* TODO process errors */
+
+ free(rep);
+ free(q_rep);
+ printf( "-----------------------------------\n");
+}
+
+void hwa_query_version( void )
+{
+ xcb_hwa_query_version_cookie_t hwa_version_cookie;
+ xcb_hwa_query_version_reply_t *hwa_version_reply = NULL;
+
+ /* 111 and 222 are just random numbers */
+ hwa_version_cookie = xcb_hwa_query_version ( c, 111, 222 );
+ xcb_flush(c);
+
+ hwa_version_reply = xcb_hwa_query_version_reply( c, hwa_version_cookie, &error );
+
+ if(hwa_version_reply)
+ {
+ printf( "\n-----------------------------------\n");
+ printf("Query Version:\n");
+ printf("hwa_query_version: Call was ok\nmajor_version=%d\nminor_version=%d \n",
+ hwa_version_reply->major_version,
+ hwa_version_reply->minor_version );
+ printf( "-----------------------------------\n");
+
+ free(hwa_version_reply);
+ }
+ else
+ {
+ printf("hwa_query_version: ERROR" );
+ }
+
+
+}
+
+void hwa_cursor_enable( int enable )
+{
+ xcb_hwa_cursor_enable_cookie_t cursor_cookie;
+ xcb_hwa_cursor_enable_reply_t *cursor_enb_reply = NULL;
+
+ cursor_cookie = xcb_hwa_cursor_enable_unchecked( c, enable );
+ xcb_flush(c);
+
+ cursor_enb_reply = xcb_hwa_cursor_enable_reply( c,cursor_cookie, &error);
+
+ if(cursor_enb_reply)
+ {
+ printf( "\n-----------------------------------\n");
+ printf("Cursor Enable:\n");
+ printf("hwa_cursor_enable: Call was ok\nreply.status=%d \n", cursor_enb_reply->status );
+ printf( "-----------------------------------\n");
+
+ free(cursor_enb_reply);
+ }
+ else
+ {
+ printf("hwa_cursor_enable: ERROR" );
+ exit(1);
+ }
+}
+
+void hwa_cursor_rotate( int angle )
+{
+ xcb_hwa_cursor_rotate_cookie_t cursor_rotate_cookie;
+ xcb_hwa_cursor_rotate_reply_t *cursor_rot_reply = NULL;
+
+ /*hwa_cursor_enable( ON );*/
+
+ randr_crtc = (xcb_randr_crtc_t) get_crtc_via_randr("LVDS1");
+
+ cursor_rotate_cookie = xcb_hwa_cursor_rotate_unchecked (c, randr_crtc, angle );
+ xcb_flush(c);
+ cursor_rot_reply = xcb_hwa_cursor_rotate_reply ( c, cursor_rotate_cookie, &error);
+
+ if(cursor_rot_reply)
+ {
+ printf( "\n-----------------------------------\n");
+ printf("Cursor Rotate:\n");
+ printf("hwa_cursor_rotate: Call was ok\nreply.status=%d, angle = %d \n ", cursor_rot_reply->status, angle );
+ printf( "-----------------------------------\n");
+
+ free(cursor_rot_reply);
+ }
+ else
+ {
+ printf("hwa_cursor_rotate: ERROR" );
+ }
+}
+
+void hwa_accessibility( int enable )
+{
+ xcb_hwa_screen_invert_negative_cookie_t hwa_scrn_invert_cookie = {0,};
+ xcb_hwa_screen_invert_negative_reply_t *hwa_scrn_invert_reply = NULL;
+
+ int crtc = get_crtc_via_randr("LVDS1");
+ if (-1 == crtc)
+ {
+ printf ("Didn't find randr crtc!! :\n");
+ exit (0);
+ }
+
+ hwa_scrn_invert_cookie = xcb_hwa_screen_invert_negative( c, crtc, enable );
+ xcb_flush(c);
+
+ hwa_scrn_invert_reply = xcb_hwa_screen_invert_negative_reply( c, hwa_scrn_invert_cookie, &error );
+
+ if(hwa_scrn_invert_reply)
+ {
+ printf( "\n-----------------------------------\n");
+ printf("Accessibility:\n");
+ printf("hwa_accessibility: Call was ok\nreply.status=%d \n", hwa_scrn_invert_reply->status );
+ printf( "-----------------------------------\n");
+
+ free(hwa_scrn_invert_reply);
+ }
+ else
+ {
+ printf("hwa_accessibility: ERROR" );
+ }
+}
+
+void hwa_scale( int enable, char* scale_param )
+{
+ xcb_hwa_screen_scale_cookie_t hwa_scale_cookie;
+ xcb_hwa_screen_scale_reply_t *hwa_scale_reply;
+
+ int x = 0, y = 0, width = 0, height = 0;
+ int crtc = -1;
+
+ if( enable && !scale_param )
+ {
+ printf( "hwa_scale: ERROR, parameters was not specified\n");
+ help();
+ exit(1);
+ }
+ else if ( enable && scale_param )
+ {
+ int *xywh = pars_params( scale_param );
+
+ printf("x=%d y=%d w=%d h=%d\n",
+ xywh[0],
+ xywh[1],
+ xywh[2],
+ xywh[3] );
+
+ int i = 0;
+ for( ; i < NUM_PARAMS; i++ )
+ {
+ if( 0 > xywh[i] )
+ {
+ printf( "hwa_scale: ERROR, At least four parameters must be specified herein\n"
+ " Parameters must not to be negative\n");
+ free(xywh);
+ exit(1);
+ }
+ }
+
+ x = xywh[0];
+ y = xywh[1];
+ width = xywh[2];
+ height = xywh[3];
+
+ free(xywh);
+ }
+ else if( 0 == enable )
+ {
+ x = 0;
+ y = 0;
+ width = 0;
+ height = 0;
+ }
+
+ crtc = get_crtc_via_randr("LVDS1");
+ if (-1 == crtc)
+ {
+ printf ("Didn't find randr crtc!! :\n");
+ exit (0);
+ }
+
+ hwa_scale_cookie = xcb_hwa_screen_scale( c, crtc , enable, x, y, width, height );
+ hwa_scale_reply = xcb_hwa_screen_scale_reply ( c, hwa_scale_cookie, &error );
+
+ if(hwa_scale_reply)
+ {
+ printf( "\n-----------------------------------\n");
+ printf("Scale:\n");
+ printf("hwa_scale: Call was ok\nreply.status=%d \n", hwa_scale_reply->status );
+ printf( "-----------------------------------\n");
+
+ free(hwa_scale_reply);
+ }
+ else
+ {
+ printf("hwa_scale: ERROR" );
+ }
+}
+
+void hwa_show_layer(int layer)
+{
+ randr_crtc = (xcb_randr_crtc_t) get_crtc_via_randr("LVDS1");
+ if (-1 == randr_crtc)
+ {
+ printf ("Didn't find randr crtc!! :\n");
+ exit (0);
+ }
+
+ printf ("<=== Overlay Layer Show ==> \n");
+ printf ("<=== Randr crtc=%d, layer=%d ==> \n", randr_crtc, layer);
+ xcb_hwa_overlay_show_layer (c, (xcb_randr_crtc_t) randr_crtc, layer);
+ xcb_flush (c);
+
+}
+
+void hwa_hide_layer( int layer )
+{
+ randr_crtc = (xcb_randr_crtc_t) get_crtc_via_randr("LVDS1");
+ if (-1 == randr_crtc)
+ {
+ printf ("Didn't find randr crtc!! :\n");
+ exit (0);
+ }
+
+ printf ("<=== Overlay Layer Hide ==> \n");
+ printf ("<=== Randr crtc=%d, layer=%d ==> \n", randr_crtc, layer);
+ xcb_hwa_overlay_hide_layer (c, (xcb_randr_crtc_t) randr_crtc, layer);
+ xcb_flush (c);
+
+}
+
+/*
+ * output = LVDS, HDMI, Virtual
+ *
+ * */
+int get_crtc_via_randr( char* output_to_find )
+{
+ xcb_randr_get_screen_resources_cookie_t screenresc_cookie;
+ xcb_randr_get_screen_resources_reply_t* screenresc_reply = NULL;
+ xcb_randr_crtc_t randrcrtc_first;
+ int i = 0, k = 0;
+
+ /* Get the first X screen */
+ xcb_screen_t* x_first_screen = xcb_setup_roots_iterator( xcb_get_setup(c)).data;
+
+ xcb_window_t x_window_dummy = xcb_generate_id(c);
+
+ /* Create dummy X window */
+ xcb_create_window(c, 0, x_window_dummy, x_first_screen->root, 0, 0, 1, 1, 0, 0, 0, 0, 0);
+
+ //Flush pending requests to the X server
+ xcb_flush(c);
+
+ //Send a request for screen resources to the X server
+ screenresc_cookie = xcb_randr_get_screen_resources( c, x_window_dummy );
+
+ /* Take reply from Xserver */
+ screenresc_reply = xcb_randr_get_screen_resources_reply( c, screenresc_cookie, 0);
+
+ if(screenresc_reply)
+ {
+
+ /* Take each crtc, and create screen for each of them*/
+ xcb_randr_crtc_t *randr_crtcs = xcb_randr_get_screen_resources_crtcs(screenresc_reply);
+
+ for (i = 0; i < screenresc_reply->num_crtcs; ++i)
+ {
+ /* We take information of the output crtc */
+ xcb_randr_get_crtc_info_cookie_t crtc_info_cookie =
+ xcb_randr_get_crtc_info (c, randr_crtcs [i], XCB_CURRENT_TIME);
+ xcb_randr_get_crtc_info_reply_t *crtc_randr_info =
+ xcb_randr_get_crtc_info_reply (c, crtc_info_cookie, NULL);
+
+ /* Ignore CRTC if it hasn't OUTPUT */
+ if (!xcb_randr_get_crtc_info_outputs_length (crtc_randr_info))
+ continue;
+
+ xcb_randr_output_t *randr_outputs = xcb_randr_get_crtc_info_outputs (crtc_randr_info);
+
+ for (k = 0; k < xcb_randr_get_crtc_info_outputs_length (crtc_randr_info); ++k)
+ {
+ xcb_randr_get_output_info_cookie_t output_info_cookie =
+ xcb_randr_get_output_info (c, randr_outputs [k], XCB_CURRENT_TIME);
+ xcb_randr_get_output_info_reply_t *output_randr_info =
+ xcb_randr_get_output_info_reply (c, output_info_cookie, NULL);
+
+ if (!output_randr_info)
+ continue;
+
+ int length = xcb_randr_get_output_info_name_length (output_randr_info);
+
+ /* Add null to name, it doesn't '\0' terminated */
+ char *outputname = malloc ((length + 1) * sizeof(char *));
+ memcpy (outputname, xcb_randr_get_output_info_name (output_randr_info), length);
+ outputname [length] = '\0';
+
+ /*
+ printf ("<-Screen[%i] INFO: (%s):\n", j, name);
+ printf (" width_mm: %i\n", output_info_r->mm_width);
+ printf (" height_mm: %i\n", output_info_r->mm_height);
+ */
+
+ if (!strcmp (outputname, output_to_find)){
+ randrcrtc_first = output_randr_info->crtc;
+ free (output_randr_info);
+ free (crtc_randr_info);
+ printf ("<-RANDR CRTCID= %d\n",randrcrtc_first );
+ return randrcrtc_first;
+ }
+
+ free (output_randr_info);
+ }
+
+ free (crtc_randr_info);
+ }
+
+ free (screenresc_reply);
+ }
+ else
+ return -1;
+
+ return -1;
+}
+
+int* pars_params( char* scale_param )
+{
+ int indx = 0;
+ int i = 0;
+ int* xywh = (int*)calloc( NUM_PARAMS, sizeof( int ) );
+ char *delimeter = ":";
+
+ for( ; i < NUM_PARAMS; i++ )
+ xywh[i] = -1;
+
+ char *token = (char *)strtok( scale_param, delimeter );
+
+ while( token != NULL )
+ {
+ xywh[indx++] = atoi(token);
+ token = (char *)strtok( NULL, delimeter );
+ }
+
+ return xywh;
+}
+
+
+
+
+
diff --git a/tests/functional/hwa_test/hwa_sample.h b/tests/functional/hwa_test/hwa_sample.h
new file mode 100644
index 0000000..cfc6e44
--- /dev/null
+++ b/tests/functional/hwa_test/hwa_sample.h
@@ -0,0 +1,79 @@
+/*
+ * hwa_sample.h
+ *
+ * Created on: Mar 20, 2015
+ * Author: roma
+ */
+
+#ifndef HWA_SAMPLE_H_
+#define HWA_SAMPLE_H_
+
+/* Standart headers */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <getopt.h>
+
+/* X Server's headers */
+#include <X11/Xlib.h>
+#include <xcb/xcb.h>
+#include <xcb/hwa.h>
+#include <xcb/dri3.h>
+#include <xcb/randr.h>
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#define NUM_ARG 2
+#define NUM_PARAMS 4
+
+#define ON 1
+#define OFF 1
+
+#define PRINT( a ) ( printf("%d\n", a) )
+
+void
+fixed_xcb_str_next(xcb_str_iterator_t* it)
+{
+ it->data = (void*) ((char*) it->data + it->data->name_len + 1);
+ --it->rem;
+}
+
+void xcb_init( void );
+
+void help( void )
+{
+ printf( " \nUsage options:\n\n"
+ " --version HWA query version\n"
+ " --info list all extension and get some data about HWA \n"
+ " -c --cursore [0-1] 0:disable 1:enable\n"
+ " -r --cursorr [0-90-180-270-360] are angle degrees to be turned cursor.\n\n"
+ " -a --accessibility [0-1] 0:disable 1:enable.\n\n"
+ " -x --scale [0-1] [x:y:width:height] 0:disable 1:enable \n"
+ " if enable was chosen x:y:width:height must be specified.\n\n"
+ " <-SHOW/HIDE Layer options:-> \n"
+ " -s --show [0-1] 0: UI Layer, 1: XV Layer.\n"
+ " -h --hide [0-1] 0: UI Layer, 1: XV Layer.\n"
+ );
+}
+
+void hwa_query_version( void );
+void hwa_cursor_enable( int enable );
+void hwa_cursor_rotate( int angle );
+void hwa_accessibility( int enable );
+void hwa_scale( int enable, char* scale_param );
+void extensions_info( void );
+
+int get_crtc_via_randr( char* output_to_find );
+int* pars_params( char* scale_param );
+
+void hwa_show_layer( int layer );
+void hwa_hide_layer( int layer );
+
+
+
+
+
+
+#endif /* HWA_SAMPLE_H_ */
diff --git a/tests/functional/hwc_test/Makefile.am b/tests/functional/hwc_test/Makefile.am
new file mode 100644
index 0000000..3a3cfdf
--- /dev/null
+++ b/tests/functional/hwc_test/Makefile.am
@@ -0,0 +1,41 @@
+if HAVE_FT
+
+ lib_LTLIBRARIES = libdri2_dri3.la
+ libdri2_dri3_la_CFLAGS = $(HWC_TEST_CFLAGS)
+ libdri2_dri3_la_LIBADD = $(HWC_TEST_LIBS) -lpthread
+ libdri2_dri3_la_LDFLAGS = -avoid-version
+ libdri2_dri3_la_SOURCES = aux_dri2_dri3_lib/dri2_dri3.c \
+ aux_dri2_dri3_lib/dri2.c \
+ aux_dri2_dri3_lib/dri3.c \
+ aux_dri2_dri3_lib/fps.c \
+ aux_dri2_dri3_lib/aux_draw.c
+
+ bin_PROGRAMS = hwc-sample square-bubbles clock snowflake wander-stripe
+
+ hwc_sample_CFLAGS = $(HWC_TEST_CFLAGS)
+ hwc_sample_LDADD = $(HWC_TEST_LIBS) -lpthread
+ hwc_sample_SOURCES = ./hwc_sample/hwc-sample.c \
+ ./hwc_sample/hwc-thread.c
+
+ square_bubbles_CFLAGS = $(HWC_TEST_CFLAGS)
+ square_bubbles_LDADD = $(HWC_TEST_LIBS) -lm -lX11
+ square_bubbles_SOURCES = ./square_bubbles/square_bubbles.c
+
+ clock_CFLAGS = $(HWC_TEST_CFLAGS) -I@top_srcdir@/tests/functional/hwc_test/aux_dri2_dri3_lib
+ clock_LDADD = $(HWC_TEST_LIBS) libdri2_dri3.la -lm
+ clock_SOURCES = ./clock.c \
+ ./aux_apps.c
+
+ snowflake_CFLAGS = $(HWC_TEST_CFLAGS) -I@top_srcdir@/tests/functional/hwc_test/aux_dri2_dri3_lib
+ snowflake_LDADD = $(HWC_TEST_LIBS) libdri2_dri3.la -lm
+ snowflake_SOURCES = ./snowflake.c \
+ ./aux_apps.c
+
+ wander_stripe_CFLAGS = $(HWC_TEST_CFLAGS) -I@top_srcdir@/tests/functional/hwc_test/aux_dri2_dri3_lib
+ wander_stripe_LDADD = $(HWC_TEST_LIBS) libdri2_dri3.la
+ wander_stripe_SOURCES = ./wander_stripe.c \
+ ./aux_apps.c
+
+# install-data-hook:
+ dist_data_DATA = launch.sh
+endif
diff --git a/tests/functional/hwc_test/aux_apps.c b/tests/functional/hwc_test/aux_apps.c
new file mode 100644
index 0000000..5a1d2fb
--- /dev/null
+++ b/tests/functional/hwc_test/aux_apps.c
@@ -0,0 +1,324 @@
+/**************************************************************************
+
+ auxilary module's source
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <xcb/composite.h>
+
+#include "aux_apps.h"
+#include "dri2_dri3.h"
+
+extern xcb_rectangle_t wnd_pos;
+extern int mode;
+extern uint32_t present_bufs;
+extern uint32_t swap_interval;
+extern uint32_t root_parent;
+
+// get name of app, which uses this library
+//========================================================================
+char*
+app_name (void)
+{
+ FILE* f;
+ char* slash;
+ static int initialized;
+ static char app_name[128];
+
+ if (initialized)
+ return app_name;
+
+ // get the application name
+ f = fopen ("/proc/self/cmdline", "r");
+
+ if (!f)
+ return NULL;
+
+ if (fgets (app_name, sizeof(app_name), f) == NULL)
+ {
+ fclose (f);
+ return NULL;
+ }
+
+ fclose (f);
+
+ if ((slash = strrchr (app_name, '/')) != NULL)
+ {
+ memmove (app_name, slash + 1, strlen(slash));
+ }
+
+ initialized = 1;
+
+ return app_name;
+}
+
+//
+//========================================================================
+void
+print_help (void)
+{
+ printf ("%s - test application.\n"
+ "This app can be used to test dri2, dri3, present and hwc extensions.\n"
+ "You can choose work mode among dri2, present or dri3 + present modes.\n"
+ "You can use this app wiht hwc-sample to test hwc extension (with dri2, present or dri3 + present).\n"
+ "You can set amount of buffers for present work mode, by default app uses triple buffering in present\n"
+ "mode, amount of buffers in dri2 mode depends on ddx driver implementation.\n"
+ "You can use this app with square-bubbles to test properly window's size & position changes.\n"
+ "To test flip mode, you must launch app in full-screen mode.\n"
+ "By default frame rate is limited to (vblank)vertical blank (60 Hz), so you cann't see fps more then 60,\n"
+ "you can disable binding to vblank - set swap interval to 0.\n\n"
+ "available options:\n"
+ "\t -geo 'width'x'height' -- set window's size,\n"
+ "\t -geo 'width'x'height' 'x' 'y' -- set window's geometry,\n"
+ "\t -dri3 -- dri3 + present Exts. mode (default mode),\n"
+ "\t -dri2 -- dri2 Exts. mode,\n"
+ "\t -present -- present Exts. mode,\n"
+ "\t -present_bufs -- amount of buffers used in no-dri2 mode (default value: 3),\n"
+ "\t -s_i -- buffers swap interval (both dri2 and present) (default value: 1),\n"
+ "\t -root_parent -- is parent a root window (default value: 1).\n", app_name());
+}
+
+// parse command line
+// if you want to do some specific for your app - implement yourself's cmd parsing
+//========================================================================
+void
+cmd_parse (int argc, char* const argv[])
+{
+ int i;
+
+ if (argc < 2) return;
+
+ // if we want to set window's size and position
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-geo"))
+ {
+ if ((i + 1 < argc) && (i + 2 >= argc))
+ sscanf (argv[i + 1], "%hux%hu", &wnd_pos.width, &wnd_pos.height);
+ else if (i + 3 < argc)
+ {
+ sscanf (argv[i + 1], "%hux%hu", &wnd_pos.width, &wnd_pos.height);
+ sscanf (argv[i + 2], "%hd", &wnd_pos.x);
+ sscanf (argv[i + 3], "%hd", &wnd_pos.y);
+ }
+ break;
+ }
+ }
+
+ // if we want to use dri3 + present Exts.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-dri3"))
+ {
+ mode = DRI3_PRESENT_MODE;
+ break;
+ }
+ }
+
+ // if we want to use dri2 Ext.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-dri2"))
+ {
+ mode = DRI2_MODE;
+ break;
+ }
+ }
+
+ // if we want to use present Exts.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-present"))
+ {
+ mode = PRESENT_MODE;
+ break;
+ }
+ }
+
+ // if we want to set amount of buffers for present usage.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-present_bufs") && (argc - i > 1))
+ {
+ sscanf (argv[i + 1], "%u", &present_bufs);
+ break;
+ }
+ }
+
+ // if we want to set buffer swap interval.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-s_i") && (argc - i > 1))
+ {
+ sscanf (argv[i + 1], "%u", &swap_interval);
+ break;
+ }
+ }
+
+ // if we want to insert window between root and window to render.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-root_parent") && (argc - i > 1))
+ {
+ sscanf (argv[i + 1], "%u", &root_parent);
+ break;
+ }
+ }
+
+ // if we want to print help
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-help") || !strcmp (argv[i], "-h"))
+ {
+ print_help ();
+ exit (0);
+ }
+ }
+}
+
+// check is composite extension existed
+//========================================================================
+int
+check_composite_ext (xcb_connection_t* dpy)
+{
+ if (!dpy) return 0;
+
+ xcb_composite_query_version_cookie_t q_c;
+ xcb_composite_query_version_reply_t* q_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ q_c = xcb_composite_query_version (dpy, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION);
+ q_r = xcb_composite_query_version_reply (dpy, q_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while composite_query_version call.\n");
+ return 0;
+ }
+ else
+ printf ("composite extension: %d.%d.\n", q_r->major_version, q_r->minor_version);
+
+ free (q_r);
+
+ return 1;
+}
+
+// create window with 'background' background
+// root_parent - if cleared, then two windows will be created (parent and child),
+// and id of child window will be returned
+//===================================================================
+xcb_window_t
+create_window (xcb_connection_t* dpy, uint32_t background, uint32_t root_parent, char* name)
+{
+ uint32_t window_mask;
+ uint32_t window_values[3];
+ xcb_window_t wnd, wnd_child;
+ xcb_screen_t* screen;
+ uint16_t border_width;
+ uint32_t gravity;
+ int is_composite_ext = 0;
+
+ if (!dpy || !name)
+ return 0;
+
+ if(root_parent)
+ is_composite_ext = 0;//check_composite_ext (dpy);
+
+ // copy xeyes behavior... :-)
+ border_width = root_parent ? 0 : 1;
+ gravity = root_parent ? XCB_GRAVITY_BIT_FORGET : XCB_GRAVITY_NORTH_WEST;
+
+ // get first screen of display
+ screen = xcb_setup_roots_iterator (xcb_get_setup (dpy)).data;
+
+ window_mask = XCB_CW_BACK_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_EVENT_MASK;
+ window_values[0] = 0x00;//background;
+ window_values[1] = gravity;
+ window_values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
+
+ wnd = xcb_generate_id (dpy);
+ xcb_create_window (dpy, DEPTH, wnd, screen->root, wnd_pos.x, wnd_pos.y,
+ wnd_pos.width, wnd_pos.height, border_width, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen->root_visual, window_mask, window_values);
+
+ // hwc-sample and square_bubbles manipulate only named windows
+ xcb_change_property (dpy, XCB_PROP_MODE_REPLACE, wnd, XCB_ATOM_WM_NAME,
+ XCB_ATOM_STRING, 8, strlen (name), name);
+
+ // see XSizeHints struct definintion in X11/Xutil.h
+ // The x, y, width, and height members are now obsolete, but wihtout them
+ // WM doesn't listen our request about keep window's size.
+ uint32_t x_size_hints[] =
+ {
+ 3, // user specified x, y & user specified width, height
+ (uint32_t)wnd_pos.x, (uint32_t)wnd_pos.y,
+ (uint32_t)wnd_pos.width, (uint32_t)wnd_pos.height,
+ 0, 0, // int min_width, min_height;
+ 0, 0, // int max_width, max_height;
+ 0, 0, // int width_inc, height_inc;
+ 0,0, 0,0, // struct { int x; int y; } min_aspect, max_aspect;
+ 0, 0, // int base_width, base_height;
+ 0 // int win_gravity;
+ };
+
+ // set WM_NORMAL_HINTS property
+ xcb_change_property (dpy, XCB_PROP_MODE_REPLACE, wnd, XCB_ATOM_WM_NORMAL_HINTS,
+ XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(x_size_hints)/sizeof(uint32_t),
+ x_size_hints);
+
+ if(root_parent && is_composite_ext)
+ {
+ printf ("wnd: 0x%x will be redirected.\n", wnd);
+ xcb_composite_redirect_window (dpy, wnd, XCB_COMPOSITE_REDIRECT_MANUAL);
+ }
+
+ // Make window visible
+ xcb_map_window (dpy, wnd);
+
+ // copy xeyes behavior... :-)
+ if(!root_parent)
+ {
+ window_values[1] = XCB_GRAVITY_BIT_FORGET;
+
+ wnd_child = xcb_generate_id (dpy);
+ xcb_create_window (dpy, DEPTH, wnd_child, wnd, 0, 0,
+ wnd_pos.width, wnd_pos.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen->root_visual, window_mask, window_values);
+
+ // Make window visible
+ xcb_map_window (dpy, wnd_child);
+
+ return wnd_child;
+ }
+
+ return wnd;
+}
+
diff --git a/tests/functional/hwc_test/aux_apps.h b/tests/functional/hwc_test/aux_apps.h
new file mode 100644
index 0000000..8292bd6
--- /dev/null
+++ b/tests/functional/hwc_test/aux_apps.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+
+ auxilary module's header
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#ifndef _AUX_APPS_H
+#define _AUX_APPS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <xcb/xcb.h>
+
+void cmd_parse (int argc, char* const argv[]);
+xcb_window_t create_window (xcb_connection_t* dpy, uint32_t background, uint32_t root_parent, char* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/aux_draw.c b/tests/functional/hwc_test/aux_dri2_dri3_lib/aux_draw.c
new file mode 100644
index 0000000..0fa5ecf
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/aux_draw.c
@@ -0,0 +1,265 @@
+/**************************************************************************
+
+ source of auxiliary functions for direct rendering
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dri2_dri3.h"
+
+// set pixel with 'color' in 'buf' on (x, y) position
+// no memory bound out checks, do it within caller !!!
+//========================================================================
+static inline void
+draw_point (int x, int y, void* buf, uint16_t stride, unsigned int color)
+{
+ *((int*)(buf + x*(BPP/8) + y*stride)) = color;
+}
+
+// draws line(s) into bo (Bresenham algorithm)
+// points_num - number of elements of xcb_point_t array
+// points - array of points, which will be used to draw line(s)
+// line(s) is(are) drawn between each pair of points
+// any attempts to draw line(s), which is(are) out of pixmap/bo size are rejected
+//=========================================================================
+int raw_draw_line (const bo_t* bo_e, uint32_t points_num, const xcb_point_t* points,
+ unsigned int color)
+{
+ tbm_bo bo = NULL;
+ tbm_bo_handle hndl;
+ uint16_t stride;
+ uint16_t width, height;
+
+ int x, y, x1, x2, y1, y2;
+ int dx, dy, error, direct, invert;
+ int temp, i;
+
+ if (!points || points_num < 2 || !bo_e)
+ {
+ printf ("raw_draw_line: invalid input parameters.\n");
+ return 1;
+ }
+
+ hndl.ptr = NULL;
+ bo = bo_e->bo;
+ stride = bo_e->stride;
+ width = bo_e->width;
+ height = bo_e->height;
+
+ hndl = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ if (!hndl.ptr)
+ {
+ printf ("raw_draw_line: Error while tbm_bo_map.\n");
+ exit (1);
+ }
+
+ // x1, y1 - first point (in pixels)
+ // x2, y2 - second point (in pixels)
+ // x grows from left to right
+ // y grows from up to down
+ // draw (points_num - 1) line(s)
+ for (i = 0; i < points_num - 1; i++)
+ {
+ x1 = points->x;
+ y1 = points++->y;
+ x2 = points->x;
+ y2 = points->y;
+
+ if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0)
+ {
+ printf ("raw_draw_line: invalid input parameters.\n");
+ continue;
+ }
+
+ if (x1 > (width - 1) || x2 > (width - 1) || y1 > (height - 1) || y2 > (height - 1))
+ {
+ printf ("raw_draw_line: you are beyond image boundaries:\n"
+ " x1 = %d, y1 = %d, x2 = %d, y2 = %d, \twidth = %hu, height = %hu\n",
+ x1, y1, x2, y2, width, height);
+ continue;
+ }
+
+ // to draw vertical lines
+ if (x1 == x2)
+ {
+ // we bypass image from bottom to top coordinates, so we must
+ // swap points if it necessary
+ if (y2 < y1)
+ {
+ temp = y1;
+ y1 = y2;
+ y2 = temp;
+ }
+
+ for (y = y1; y <= y2; y++)
+ draw_point (x1, y, hndl.ptr, stride, color);
+
+ continue;
+ }
+
+ // if y-component of line is changed quickly then x-component,
+ // we must exchange axis to use Bresenham algorithm more effectively,
+ // due to that we have for cycle from x1 to x2, therefore we can change
+ // body of for cycle insted exchange axis, but this's not pretty
+ invert = abs (y2 - y1) > abs (x2 - x1);
+ if (invert)
+ {
+ temp = x1;
+ x1 = y1;
+ y1 = temp;
+
+ temp = x2;
+ x2 = y2;
+ y2 = temp;
+ }
+
+ // algorithm can draw line only if x of first point is less
+ // then x of second point, so we simple swap points if it's necessary
+ if (x1 > x2)
+ {
+ temp = x1;
+ x1 = x2;
+ x2 = temp;
+
+ temp = y1;
+ y1 = y2;
+ y2 = temp;
+ }
+
+ // where do we go while draw line: up(or straight) or down
+ if (y2 < y1)
+ direct = -1;
+ else
+ direct = 1;
+
+ error = 0;
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+
+ // to draw another cases of line (it's Bresenham algorithm implementation,
+ // which supports varios line's directions)
+ for (x = x1, y = y1; x <= x2; x++)
+ {
+ draw_point (invert ? y : x, invert ? x : y, hndl.ptr, stride, color);
+
+ error += dy;
+
+ if (error * 2 >= dx)
+ {
+ y += direct;
+ error -= dx;
+ }
+ }
+ } // for (i = 0; i < points_num - 1; i++)
+
+ tbm_bo_unmap (bo);
+
+ return 0;
+}
+
+// draw filled rect into bo
+// rect_num - amount of rectangles to draw (in current implemantation must be '1')
+// rects - array of rectangles to draw
+// any attempts to draw rectangle, which is out of pixmap/bo size are rejected
+// draw only one rectangle !!!
+//=========================================================================
+int raw_fill_rect (const bo_t* bo_e, uint32_t rect_num, const xcb_rectangle_t* rects,
+ unsigned int color)
+{
+ tbm_bo bo = NULL;
+ tbm_bo_handle hndl;
+ uint16_t height;
+ uint16_t width;
+ uint16_t stride;
+ int i, j;
+
+ if (
+ rects->x < 0 || rects->y < 0 || rects->width <= 0 || rects->height <= 0 ||
+ !rect_num || rect_num > 1 || !rects || !bo_e
+ )
+ {
+ printf ("raw_fill_rect: invalid input parameters.\n");
+ return 1;
+ }
+
+ bo = bo_e->bo;
+ stride = bo_e->stride;
+ width = bo_e->width;
+ height = bo_e->height;
+
+ if (rects->x + rects->width > width || rects->y + rects->height > height)
+ {
+ printf ("raw_fill_rect: you are beyond image boundaries:\n"
+ " x = %d, y = %d, width = %d, height = %d, widht_bo = %hu, height_bo = %hu.\n",
+ rects->x, rects->y, rects->width, rects->height, width, height);
+ return 1;
+ }
+
+ hndl = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ if (!hndl.ptr)
+ {
+ printf ("raw_fill_rect: Error while tbm_bo_map.\n");
+ exit (1);
+ }
+
+ // this code works quikly then below code.
+ // if caller wants to clear (black color) all bo.
+ // another colors cann't be used due to memset semantic
+ // (memset use only low byte of second parameter)
+ if (width == rects->width && height == rects->height && !color)
+ {
+ memset (hndl.ptr, 0, bo_e->stride * bo_e->height);
+ goto success;
+ }
+
+ // x grows from left to right
+ // y grows from up to down
+
+ // shift to pixel, from which we must draw
+ hndl.ptr += rects->x*(BPP/8) + rects->y*stride;
+
+ // memory boundaries were checked above
+ for (i = 0; i < rects->height; i++)
+ {
+ for (j = 0; j < rects->width; j++)
+ {
+ *((int*)hndl.ptr) = (int)color;
+ hndl.ptr += (BPP/8);
+ }
+
+ // shift to pixel, from which we must draw
+ hndl.ptr -= j*(BPP/8) - stride;
+ }
+
+success:
+ tbm_bo_unmap (bo);
+
+ return 0;
+}
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2.c b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2.c
new file mode 100644
index 0000000..0340f13
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2.c
@@ -0,0 +1,394 @@
+/**************************************************************************
+
+ dri2 backend
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implements preparing dri2 extension to use and dri2 events handling
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <xcb/dri2.h>
+
+#include "dri2_dri3_inner.h"
+
+
+#define CACHE_BO_SIZE (3)
+
+typedef struct dri2_info_t
+{
+ int drm_fd;
+ drm_magic_t drm_magic;
+ char* device_name;
+ char* driver_name;
+ tbm_bufmgr bufmgr;
+ const xcb_query_extension_reply_t* dri2_ext;
+}dri2_info_t;
+
+static dri2_info_t dri2_info;
+
+// cycle bo's cache
+static bo_t bo_cache[CACHE_BO_SIZE];
+static uint32_t bo_cache_idx;
+
+
+// next two functions avoid call to tbm_bo_import, when we have tbm_bo for
+// appropriate buf_name, returned by dri2 extension
+
+// returns, if exist, tbm_bo for gem object's name 'buf_name'
+//========================================================================
+static tbm_bo
+get_tbm_bo_from_cache (uint32_t buf_name)
+{
+ int i;
+
+ for (i = 0; i < CACHE_BO_SIZE; i++)
+ {
+ if (bo_cache[i].name == buf_name) return bo_cache[i].bo;
+ }
+
+ return NULL;
+}
+
+// add bo to cycle bo's cache
+//========================================================================
+static void
+add_bo_to_cache (const bo_t* bo)
+{
+ if (!bo) return;
+
+ if (bo_cache[bo_cache_idx].bo)
+ tbm_bo_unref(bo_cache[bo_cache_idx].bo);
+
+ memcpy ((bo_cache + bo_cache_idx++), bo, sizeof(bo_t));
+ bo_cache_idx %= CACHE_BO_SIZE;
+}
+
+// wrap over DRI2GetBuffers request
+// return all information for rendering
+//========================================================================
+static bo_t
+get_bo (void)
+{
+ bo_t bo;
+ uint32_t attachments;
+ xcb_dri2_get_buffers_cookie_t get_buf_c;
+ xcb_dri2_get_buffers_reply_t* get_buf_r = NULL;
+ xcb_generic_error_t* xcb_errors = NULL;
+ xcb_dri2_dri2_buffer_t* dri2_buf = NULL;
+
+ attachments = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
+
+ get_buf_c = xcb_dri2_get_buffers (display.dpy, display.wnd, 1, 1, &attachments);
+ get_buf_r = xcb_dri2_get_buffers_reply (display.dpy, get_buf_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ set_error ("Error while xcb_dri2_get_buffers call.\n");
+ pthread_cancel(thread_id);
+ }
+
+ dri2_buf = xcb_dri2_get_buffers_buffers (get_buf_r);
+ if (!dri2_buf)
+ {
+ free (get_buf_r);
+ set_error ("dri2_buf = NULL.\n");
+ pthread_cancel(thread_id);
+ }
+
+ bo.stride = dri2_buf->pitch;
+ bo.width = get_buf_r->width;
+ bo.height = get_buf_r->height;
+ bo.name = dri2_buf->name;
+
+ // cache bos
+ bo.bo = get_tbm_bo_from_cache (bo.name);
+ if (!bo.bo)
+ {
+ bo.bo = tbm_bo_import (dri2_info.bufmgr, bo.name);
+ add_bo_to_cache (&bo);
+ }
+
+ // this memory will be used for next xcb_dri2_get_buffers_buffers calls,
+ // so don't need to free it
+ //free (dri2_buf);
+
+ DEBUG_OUT ("buf_name: %u, bo: %p, stride: %u, cpp: %u, flags: %u, width: %u, "
+ "height: %u, count: %u\n",
+ bo.name, bo.bo, bo.stride, dri2_buf->cpp, dri2_buf->flags,
+ bo.width, bo.height, get_buf_r->count);
+
+ free (get_buf_r);
+
+ return bo;
+}
+
+// this function is called in event handling and calls app's callbacks to draw
+//========================================================================
+static void
+draw (void)
+{
+ bo_t bo;
+
+ TIME_START();
+ bo = get_bo ();
+ TIME_END ("get_bo");
+
+ TIME_START();
+
+ if (gr_ctx.draw_funcs.raw_clear)
+ gr_ctx.draw_funcs.raw_clear (&bo);
+
+ if (gr_ctx.draw_funcs.raw_draw)
+ gr_ctx.draw_funcs.raw_draw (&bo);
+
+ TIME_END ("draw");
+}
+
+// wrap over DRI2SwapBuffers request
+// this function is called in event handling
+//========================================================================
+static void
+swap_buffers (uint32_t msc_hi, uint32_t msc_lo)
+{
+ DEBUG_OUT ("ask to swap buffers for window: 0x%x at msc_hi: %u, msc_lo: %u\n",
+ display.wnd, msc_hi, msc_lo);
+
+ TIME_START();
+ xcb_dri2_swap_buffers (display.dpy, display.wnd, msc_hi, msc_lo, 0, 0, 0 ,0);
+ TIME_END ("xcb_dri2_swap_buffers");
+
+#ifdef _DEBUG_
+ printf ("----------------------------\n");
+#endif
+}
+
+
+//========================================================================
+//========================================================================
+//========================================================================
+
+
+// check dri2 extension, connect, authenticate, create dri2 drawable
+// and initiate tizen buffer manager
+// return 0 if success, 1 otherwise
+//===================================================================
+int
+prepare_dri2_ext (void)
+{
+ xcb_dri2_query_version_cookie_t query_ver_c;
+ xcb_dri2_query_version_reply_t* query_ver_r = NULL;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ xcb_dri2_connect_cookie_t connect_c;
+ xcb_dri2_connect_reply_t* connect_r = NULL;
+
+ xcb_dri2_authenticate_cookie_t auth_c;
+ xcb_dri2_authenticate_reply_t* auth_r = NULL;
+
+ int res;
+
+ // whait for main thread
+ usleep (500000);
+
+ // dri2_query_version
+
+ query_ver_c = xcb_dri2_query_version (display.dpy, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION);
+ query_ver_r = xcb_dri2_query_version_reply (display.dpy, query_ver_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ set_error ("Error while dri2_query_version call.\n");
+ return 1;
+ }
+
+ printf ("DRI2 Extension: %u.%u.\n", query_ver_r->major_version, query_ver_r->minor_version);
+
+ free (query_ver_r);
+
+ // dri2_connect
+
+ connect_c = xcb_dri2_connect (display.dpy, display.screen->root, XCB_DRI2_DRIVER_TYPE_DRI);
+ connect_r = xcb_dri2_connect_reply (display.dpy, connect_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ set_error ("Error while dri2_connect call.\n");
+ return 1;
+ }
+
+ dri2_info.driver_name = xcb_dri2_connect_driver_name (connect_r);
+ dri2_info.device_name = xcb_dri2_connect_device_name (connect_r);
+ free (connect_r);
+
+ printf ("DRI2 driver_name: %s, device_name: %s.\n", dri2_info.driver_name, dri2_info.device_name);
+
+ // open drm device
+ dri2_info.drm_fd = open (dri2_info.device_name, O_RDWR);
+ if (dri2_info.drm_fd < 0)
+ {
+ char* temp = malloc (512);
+
+ sprintf (temp, "Error while open call for file: %s.\n", dri2_info.device_name);
+ set_error (temp);
+ free (temp);
+
+ return 1;
+ }
+
+ // dri2_authenticate
+ res = drmGetMagic (dri2_info.drm_fd, &dri2_info.drm_magic);
+ if (res)
+ {
+ close (dri2_info.drm_fd);
+ set_error ("Error while drmGetMagic call.\n");
+ return 1;
+ }
+
+ auth_c = xcb_dri2_authenticate (display.dpy, display.screen->root, (uint32_t)dri2_info.drm_magic);
+ auth_r = xcb_dri2_authenticate_reply (display.dpy, auth_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ close (dri2_info.drm_fd);
+ free (xcb_errors);
+ set_error ("Error while dri2_authenticate call.\n");
+ return 1;
+ }
+
+ if (!auth_r->authenticated)
+ {
+ close (dri2_info.drm_fd);
+ set_error ("Error while dri2_authenticate call.\n");
+ return 1;
+ }
+
+ free (auth_r);
+
+ xcb_dri2_create_drawable (display.dpy, display.wnd);
+
+ // for determine dri2's events
+ dri2_info.dri2_ext = xcb_get_extension_data (display.dpy, &xcb_dri2_id);
+
+ dri2_info.bufmgr = tbm_bufmgr_init (dri2_info.drm_fd);
+
+ return 0;
+}
+
+// dri2 events loop
+//========================================================================
+void
+dri2_loop (void)
+{
+ xcb_generic_event_t* event = NULL;
+#ifndef _DEBUG_
+ struct timespec start;
+#endif
+ uint64_t target_msc = 0;
+
+ draw ();
+ swap_buffers (0, 0);
+
+ while (1)
+ {
+ xcb_flush (display.dpy);
+ DEBUG_OUT("before xcb_wait_for_event.\n");
+ event = xcb_wait_for_event (display.dpy);
+ DEBUG_OUT("after xcb_wait_for_event.\n");
+ if (!event)
+ {
+ printf("event is NULL.\n");
+ break;
+ }
+
+ switch (event->response_type)
+ {
+ default:
+ {
+ // if XCB_DRI2_BUFFER_SWAP_COMPLETE event
+ if (event->response_type == dri2_info.dri2_ext->first_event +
+ XCB_DRI2_BUFFER_SWAP_COMPLETE)
+ {
+ xcb_dri2_buffer_swap_complete_event_t* ev;
+ ev = (xcb_dri2_buffer_swap_complete_event_t*)event;
+
+#ifdef _DEBUG_
+ DEBUG_OUT ("XCB_DRI2_BUFFER_SWAP_COMPLETE:\n");
+ switch (ev->event_type)
+ {
+ case XCB_DRI2_EVENT_TYPE_EXCHANGE_COMPLETE:
+ DEBUG_OUT (" EXCHANGE_COMPLETE.\n");
+ break;
+ case XCB_DRI2_EVENT_TYPE_BLIT_COMPLETE:
+ DEBUG_OUT (" BLIT_COMPLETE.\n");
+ break;
+ case XCB_DRI2_EVENT_TYPE_FLIP_COMPLETE:
+ DEBUG_OUT (" FLIP_COMPLETE.\n");
+ break;
+ }
+ DEBUG_OUT (" drawable: 0x%x, msc_hi: %u, msc_lo: %u, sbc: %u, "
+ "ust_hi: %u, ust_lo: %u\n",
+ ev->drawable, ev->msc_hi, ev->msc_lo, ev->sbc,
+ ev->ust_hi, ev->ust_lo);
+
+#endif
+ // adjust target_msc to real msc
+ target_msc = ((uint64_t)ev->msc_hi << 32) | (uint64_t)ev->msc_lo;
+
+ // prepare target_msc for use when DRI2InvalidateBuffers event is came
+ target_msc += 2*gr_ctx.params.swap_interval;
+ }
+ else if (event->response_type == dri2_info.dri2_ext->first_event +
+ XCB_DRI2_INVALIDATE_BUFFERS)
+ {
+#ifdef _DEBUG_
+ xcb_dri2_invalidate_buffers_event_t* ev;
+ ev = (xcb_dri2_invalidate_buffers_event_t*)event;
+
+ DEBUG_OUT ("XCB_DRI2_INVALIDATE_BUFFERS.\n drawable: 0x%x\n", ev->drawable);
+#else
+ fps_calc( &start );
+ clock_gettime( CLOCK_REALTIME, &start );
+#endif
+ // we draw frame when obtained DRI2InvalidateBuffers event due to be able to
+ // handle situation when DRI2InvalidateBuffers event signals about mismatching
+ // drawable and buffer sizes and DRI2BufferSwapComplete event will not be issued and
+ // delivered to us and we will hang out in xcb_wait_for_event, so we draw frame
+ // here and for swap it use target_msc obtained from DRI2BufferSwapComplete event
+ // on previous swap
+ draw ();
+ swap_buffers ((uint32_t)(target_msc >> 32), (uint32_t)(target_msc & 0xFFFFFFFF));
+ }
+ }
+ break;
+ }
+ }// while (1)
+}
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.c b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.c
new file mode 100644
index 0000000..b59cc57
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.c
@@ -0,0 +1,227 @@
+/**************************************************************************
+
+ dri2_dri3 dispatcher's source
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implemets dri2/dri3 dispatcher and some auxiliary functions
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+
+#include "dri2_dri3_inner.h"
+
+display_t display;
+graphics_ctx gr_ctx;
+pthread_t thread_id;
+xcb_rectangle_t wnd_pos;
+
+static char* error;
+
+static void* dri2_dri3 (void* arg);
+static int init_graphic_context (void);
+
+// this function gets copy of passed arguments !!!
+// dpy - connection to Xserver, initialized by client, used for obtain wnd's geometry
+// draw_funcs - set of callback function to drawing, which functions to use
+// will be dedicated according to mode value
+// mode - mode in which dri2_dri3 module will work
+// window - window's id in which drawing will be occured
+// params - dri2/dri3 configure parameters
+//=========================================================================
+int init_dri2_dri3 (xcb_connection_t* dpy, const draw_funcs_t* draw_funcs,
+ int mode, xcb_window_t window, const dri2_dri3_params_t* params)
+{
+ int res;
+
+ if (!draw_funcs || !dpy || !params)
+ {
+ set_error ("invalid input arguments");
+ return 1;
+ }
+
+ display.client_dpy = dpy; // used for obtain window's geometry only
+ display.dpy = xcb_connect (NULL, NULL); // dpy from client cann't be used
+ // for processing dri2/dri3 events
+ // get first screen of display
+ display.screen = xcb_setup_roots_iterator (xcb_get_setup (display.dpy)).data;
+ display.wnd = window;
+
+ gr_ctx.mode = mode;
+ memcpy (&gr_ctx.draw_funcs, draw_funcs, sizeof (gr_ctx.draw_funcs));
+ memcpy (&gr_ctx.params, params, sizeof (gr_ctx.params));
+
+ get_wnd_geometry (display.wnd, &wnd_pos);
+
+ res = pthread_create (&thread_id, NULL, dri2_dri3, NULL);
+ if (res)
+ {
+ set_error ("error while pthread_create");
+ return 1;
+ }
+
+ return 0;
+}
+
+// any dri2_dri3 module's functions return error code or message,
+// only DRI2_DRI3_TRUE or DRI2_DRI3_FALSE
+// use this function, if you need, to obtain more detail information about error
+// you must free memory, pointed by returned value
+//=========================================================================
+char* get_last_error (void)
+{
+ char* temp;
+
+ if (!error) return NULL;
+
+ // TODO: need thread synchronize
+ temp = strdup (error);
+ free (error);
+ error = NULL;
+
+ return temp;
+}
+
+
+//========================================================================
+//========================================================================
+//========================================================================
+
+
+// dri2/dri3 xcb events loop
+//========================================================================
+static void*
+dri2_dri3 (void* arg)
+{
+ int res;
+
+ res = init_graphic_context ();
+ if (res)
+ pthread_cancel(thread_id);
+
+ switch (gr_ctx.mode)
+ {
+ case DRI2_MODE:
+ {
+ dri2_loop ();
+ }
+ break;
+
+ case DRI3_PRESENT_MODE:
+ case PRESENT_MODE:
+ {
+ dri3_loop ();
+ }
+ break;
+ }
+
+ return NULL;
+}
+
+// fill gr_ctx struct to use it on drawing and presenting on screen phases
+// return 0 if success, 1 otherwise
+//===================================================================
+static int
+init_graphic_context (void)
+{
+ int res;
+
+ switch (gr_ctx.mode)
+ {
+ case DRI2_MODE:
+ {
+ res = prepare_dri2_ext ();
+ if (res) return 1;
+
+ printf ("usecase: dri2.\n");
+ }
+ break;
+
+ case DRI3_PRESENT_MODE:
+ case PRESENT_MODE:
+ {
+ res = prepare_dri3_present_ext ();
+ if (res) return 1;
+
+ if (gr_ctx.mode == DRI3_PRESENT_MODE)
+ printf ("usecase: dri3 + present.\n");
+ else
+ printf ("usecase: present.\n");
+ }
+ break;
+
+ default:
+ printf ("invalid gr_ctx.mode.\n");
+ break;
+ }
+
+ return 0;
+}
+
+// return geometry of specified, by win_id, window
+//========================================================================
+void
+get_wnd_geometry (xcb_window_t win_id, xcb_rectangle_t* geometry)
+{
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t* reply = NULL;
+ xcb_generic_error_t* error = NULL;
+
+ if (!geometry)
+ {
+ printf ("error while get_wnd_geometry call.\n");
+ exit (1);
+ }
+
+ cookie = xcb_get_geometry (display.client_dpy, win_id);
+ reply = xcb_get_geometry_reply (display.client_dpy, cookie, &error);
+ if (error)
+ {
+ printf ("error while xcb_get_geometry call.\n");
+ free (error);
+ exit (1);
+ }
+
+ geometry->x = reply->x;
+ geometry->y = reply->y;
+ geometry->width = reply->width;
+ geometry->height = reply->height;
+
+ free (reply);
+}
+
+// for inner use
+//===================================================================
+void
+set_error (const char* str)
+{
+ // to prevent rewriting of previous error message
+ if (!error) error = strdup (str);
+}
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.h b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.h
new file mode 100644
index 0000000..5b12e44
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3.h
@@ -0,0 +1,135 @@
+/**************************************************************************
+
+ dri2_dri3 library's source
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// dri2_dri3 library's API
+
+#ifndef _DRI2_DRI3_H
+#define _DRI2_DRI3_H
+
+#include <xcb/xcb.h>
+#include <tbm_bufmgr.h>
+
+#ifdef _DEBUG_
+ #define DEBUG_OUT(format, args...) { printf("%s: "format, __FUNCTION__, ##args); }
+#else
+ #define DEBUG_OUT(...) {;}
+#endif
+
+#define BPP (32) // bits per pixel
+#define DEPTH (24)
+
+#define DRI2_DRI3_TRUE 0x1
+#define DRI2_DRI3_FALSE 0x0
+
+// modes for use in init_dri2_dri3() function
+#define DRI2_MODE 0x0
+#define DRI3_MODE 0x1
+#define DRI3_PRESENT_MODE 0x2
+#define PRESENT_MODE 0x4
+
+typedef struct dri2_dri3_params_t
+{
+ uint32_t num_of_bufs; // number of buffers for use with Present extension only
+ uint64_t swap_interval; // buffer(frame) swap interval
+} dri2_dri3_params_t;
+
+// describes buffer for direct access
+typedef struct bo_t
+{
+ tbm_bo bo; // these bos represents such gem object as pxmap in graphics_ctx_t structure
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t name; // name of gem object, used only by dri2
+ int dma_buf_fd; // fd of dmabuf file, used only by dri3
+} bo_t;
+
+typedef void (*xcb_clear_func_ptr)(xcb_drawable_t drawable, uint32_t draw_w, uint32_t draw_h);
+typedef void (*xcb_draw_func_ptr)(xcb_drawable_t drawable, uint32_t draw_w, uint32_t draw_h);
+
+typedef void (*raw_clear_func_ptr)(const bo_t* bo_e);
+typedef void (*raw_draw_func_ptr)(const bo_t* bo_e);
+
+typedef struct draw_funcs_t
+{
+ xcb_clear_func_ptr xcb_clear;
+ xcb_draw_func_ptr xcb_draw;
+ raw_clear_func_ptr raw_clear;
+ raw_draw_func_ptr raw_draw;
+} draw_funcs_t;
+
+
+// this function gets copy of passed arguments !!!
+// dpy - connection to Xserver, initialized by client, used for obtain wnd's geometry
+// draw_funcs - set of callback function to drawing, which functions to use
+// will be dedicated according to mode value
+// mode - mode in which dri2_dri3 module will work
+// window - window's id in which drawing will be occured
+// params - dri2/dri3 configure parameters
+// Note: if you use PRESENT_MODE or DRI3_PRESENT_MODE size of pixmaps or bos
+// mayn't be equal size of window, now it isn't used, but maybe in future...
+// therefore xcb_clear_func_ptr and xcb_draw_func_ptr functions have passed
+// real size of pixmaps or bos as second and third arguments
+__attribute__ ((visibility ("default")))
+int init_dri2_dri3 (xcb_connection_t* dpy, const draw_funcs_t* draw_funcs,
+ int mode, xcb_window_t window, const dri2_dri3_params_t* params);
+
+// any dri2_dri3 module's functions return error code or message,
+// only DRI2_DRI3_TRUE or DRI2_DRI3_FALSE
+// use this function, if you need, to obtain more detail information about error
+// you must free memory, pointed by returned value
+__attribute__ ((visibility ("default")))
+char* get_last_error (void);
+
+// you can use this auxiliary functions to direct drawing in bo
+
+// draws line(s) into tbm_bo (Bresenham algorithm)
+// bo_e - pointer to struct returned by raw_draw or raw_clear function
+// points_num - number of elements of xcb_point_t array
+// points - array of points, which will be used to draw line(s)
+// color - color of line(s)
+// line(s) is(are) drawn between each pair of points
+// any attempts to draw line(s), which is(are) out of pixmap/bo size are rejected
+__attribute__ ((visibility ("default")))
+int raw_draw_line (const bo_t* bo_e, uint32_t points_num, const xcb_point_t* points,
+ unsigned int color);
+
+// draw filled rect into tbm_bo
+// bo_e - pointer to struct returned by raw_draw or raw_clear function
+// rect_num - amount of rectangles to draw (in current implemantation must be '1')
+// rects - array of rectangles to draw
+// color - color of rectangle
+// any attempts to draw rectangle, which is out of pixmap/bo size are rejected
+// draw only one rectangle !!!
+__attribute__ ((visibility ("default")))
+int raw_fill_rect (const bo_t* bo_e, uint32_t rect_num, const xcb_rectangle_t* rects,
+ unsigned int color);
+
+#endif
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3_inner.h b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3_inner.h
new file mode 100644
index 0000000..491d267
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri2_dri3_inner.h
@@ -0,0 +1,82 @@
+/**************************************************************************
+
+ dri2_dri3 library's inner header
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#ifndef _DRI2_DRI3_INNER_H
+#define _DRI2_DRI3_INNER_H
+
+#include <xf86drm.h>
+
+#include "dri2_dri3.h"
+#include "fps.h"
+
+#ifdef _DEBUG_
+ #define TIME_START()\
+ {\
+ struct timespec start;\
+ clock_gettime (CLOCK_REALTIME, &start);
+ #define TIME_END(str) \
+ DEBUG_OUT ("%s: %f.\n", str, get_time_diff (&start) / 1000000.0f);\
+ }
+#else
+ #define TIME_START() {;}
+ #define TIME_END(...) {;}
+#endif
+
+typedef struct display_t
+{
+ xcb_connection_t* dpy;
+ xcb_connection_t* client_dpy;
+ xcb_screen_t* screen;
+ xcb_window_t wnd;
+} display_t;
+
+typedef struct graphics_ctx_t
+{
+ int mode;
+ draw_funcs_t draw_funcs;
+ dri2_dri3_params_t params;
+} graphics_ctx;
+
+extern display_t display;
+extern graphics_ctx gr_ctx;
+extern pthread_t thread_id;
+
+extern xcb_rectangle_t wnd_pos;
+
+void get_wnd_geometry (xcb_window_t win_id, xcb_rectangle_t* geometry);
+void set_error (const char* str);
+
+int prepare_dri2_ext (void);
+void dri2_loop (void);
+
+int prepare_dri3_present_ext (void);
+void dri3_loop (void);
+
+#endif
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/dri3.c b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri3.c
new file mode 100644
index 0000000..0075fc6
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/dri3.c
@@ -0,0 +1,542 @@
+/**************************************************************************
+
+ dri3 backend
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implements preparing dri3 extension to use and dri3 events handling
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+#include <xcb/dri3.h>
+#pragma pack(push, 1)
+#include <xcb/present.h>
+#pragma pack(pop)
+
+
+#include "dri2_dri3_inner.h"
+
+typedef struct dri3_buffer_t
+{
+ xcb_pixmap_t pxmap;
+ bo_t bo;
+ xcb_rectangle_t pxmap_size; // bo size is equal pixmap size and can be found in bo field
+ uint32_t busy; // whether pixmap busy or not
+
+ // whether pixmap must be reallocated, due to wnd size changes, or not
+ uint32_t buff_must_be_realloc;
+} dri3_buffer_t;
+
+typedef struct dri3_present_info_t
+{
+ int drm_fd;
+ tbm_bufmgr bufmgr;
+ const xcb_query_extension_reply_t* present_ext;
+} dri3_present_info_t;
+
+static dri3_buffer_t* dri3_buffers;
+static dri3_present_info_t dri3_present_info;
+
+static uint64_t target_msc;
+
+// check present extenstion
+// return 0 if success, 1 otherwise
+//===================================================================
+static int
+check_present_ext (void)
+{
+ xcb_present_query_version_cookie_t c;
+ xcb_present_query_version_reply_t* r = NULL;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ c = xcb_present_query_version (display.dpy, XCB_PRESENT_MAJOR_VERSION, XCB_PRESENT_MINOR_VERSION);
+ r = xcb_present_query_version_reply (display.dpy, c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("Error while Present Extension query_version call.\n");
+ return 1;
+ }
+ else
+ printf ("Present Extension: %d.%d.\n", r->major_version, r->minor_version);
+
+ free (r);
+
+ return 0;
+}
+
+// check dri3 extenstion and ask X server to send us auth drm_fd (fd of drm device file)
+// return -1, if error was occured,
+// otherwise drm_fd
+//===================================================================
+static int
+prepare_dri3_ext (void)
+{
+ int* drm_fd_p = NULL;
+ int drm_fd;
+ xcb_dri3_query_version_cookie_t query_version_c;
+ xcb_dri3_query_version_reply_t* query_version_r = NULL;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ xcb_dri3_open_cookie_t open_c;
+ xcb_dri3_open_reply_t* open_r = NULL;
+
+ // query version ---------------------
+
+ query_version_c = xcb_dri3_query_version (display.dpy, XCB_DRI3_MAJOR_VERSION, XCB_DRI3_MINOR_VERSION);
+ query_version_r = xcb_dri3_query_version_reply (display.dpy, query_version_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("Error while DRI3 Extension query_version call.\n");
+ return -1;
+ }
+ else
+ printf ("DRI3 Extension: %d.%d.\n", query_version_r->major_version, query_version_r->minor_version);
+
+ free (query_version_r);
+
+ // open ------------------------------
+
+ // I don't know why open call require drawable, maybe it dedicates screen and drm device
+ // which is responsible for showing this screen ?
+ // about third parameter I'm still in confuse.
+ open_c = xcb_dri3_open (display.dpy, (xcb_drawable_t)display.screen->root, 0);
+ open_r = xcb_dri3_open_reply (display.dpy, open_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("Error while DRI3 Extension open call.\n");
+ return -1;
+ }
+
+ drm_fd_p = xcb_dri3_open_reply_fds (display.dpy, open_r);
+ drm_fd = *drm_fd_p;
+
+ printf (" drm fd provided by DRI3: %d.\n", drm_fd);
+ printf (" OBSERVE: nfd returned by open_dri: %d.\n", open_r->nfd);
+
+ // this memory will be used for next xcb_dri3_open_reply_fds calls, if we will do them,
+ // so don't need to free it
+ //free (drm_fd_p);
+ free (open_r);
+
+ return drm_fd;
+}
+
+// obtains tbm_bo(bo_t) from pixmap via dri3 extension
+// aborts app, if error was occured,
+// otherwise returns tbm_bo(bo_t), that represents such gem object that pixmap represents
+//===================================================================
+static bo_t
+get_bo_from_pixmap (xcb_pixmap_t pixmap)
+{
+ bo_t bo;
+ int* dma_buf_fd = NULL;
+ xcb_dri3_buffer_from_pixmap_cookie_t bf_from_pixmap_c;
+ xcb_dri3_buffer_from_pixmap_reply_t* bf_from_pixmap_r = NULL;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ DEBUG_OUT ("before xcb_dri3_buffer_from_pixmap.\n");
+ bf_from_pixmap_c = xcb_dri3_buffer_from_pixmap (display.dpy, pixmap);
+
+ DEBUG_OUT ("before xcb_dri3_buffer_from_pixmap_reply.\n");
+ bf_from_pixmap_r = xcb_dri3_buffer_from_pixmap_reply (display.dpy, bf_from_pixmap_c,
+ &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("Error while DRI3 Extension buffer_from_pixmap call.\n");
+ exit (1);
+ }
+
+ DEBUG_OUT ("size: %u, w: %hu, h: %hu, stride: %hu, bpp: %hhu, depth: %hhu.\n",
+ (bf_from_pixmap_r)->size, (bf_from_pixmap_r)->width,
+ (bf_from_pixmap_r)->height, (bf_from_pixmap_r)->stride,
+ (bf_from_pixmap_r)->bpp, (bf_from_pixmap_r)->depth);
+
+ dma_buf_fd = xcb_dri3_buffer_from_pixmap_reply_fds (display.dpy, bf_from_pixmap_r);
+
+ DEBUG_OUT ("dma_buf fd, returned by dri3, for pixmap[0x%06x]: %d.\n", pixmap, *dma_buf_fd);
+
+ bo.bo = tbm_bo_import_fd (dri3_present_info.bufmgr, (tbm_fd)(*dma_buf_fd));
+ if (!bo.bo)
+ {
+ free (bf_from_pixmap_r);
+ printf ("Error while tbm_bo_import_fd call.\n");
+ exit (1);
+ }
+
+ bo.dma_buf_fd = *dma_buf_fd;
+ bo.width = bf_from_pixmap_r->width;
+ bo.height = bf_from_pixmap_r->height;
+ bo.stride = bf_from_pixmap_r->stride;
+ // now, I don't see any necessity to use these values
+ // bf_from_pixmap_r->depth;
+ // bf_from_pixmap_r->bpp;
+
+ DEBUG_OUT ("OBSERVE: nfd returned by buffer_from_pixmap: %d.\n", bf_from_pixmap_r->nfd);
+
+ // this memory will be used for next xcb_dri3_buffer_from_pixmap_reply_fds calls,
+ // so don't need to free it
+ //free (dma_buf_fd);
+ free (bf_from_pixmap_r);
+
+ return bo;
+}
+
+// this function is called in event handling and calls app's callbacks to draw
+//========================================================================
+static void
+draw (uint32_t idx)
+{
+ if (gr_ctx.mode == DRI3_PRESENT_MODE || gr_ctx.mode == DRI3_MODE)
+ {
+ bo_t back_bo;
+
+ // library client must not be able to do any changes in real bo object,
+ // now it isn't important, but what about a future ?
+ memcpy (&back_bo, &dri3_buffers[idx].bo, sizeof (back_bo));
+
+ if (gr_ctx.draw_funcs.raw_clear)
+ gr_ctx.draw_funcs.raw_clear (&back_bo);
+
+ if (gr_ctx.draw_funcs.raw_draw)
+ gr_ctx.draw_funcs.raw_draw (&back_bo);
+
+ DEBUG_OUT ("render in tbm bo: 0x%p (tied pixmap: 0x%x)\n", dri3_buffers[idx].bo.bo,
+ dri3_buffers[idx].pxmap);
+ }
+ else if (gr_ctx.mode == PRESENT_MODE)
+ {
+ xcb_pixmap_t back_pxmap;
+ xcb_rectangle_t pxmap_size;
+
+ back_pxmap = dri3_buffers[idx].pxmap;
+ pxmap_size = dri3_buffers[idx].pxmap_size;
+
+ if (gr_ctx.draw_funcs.xcb_clear)
+ gr_ctx.draw_funcs.xcb_clear (back_pxmap, pxmap_size.width, pxmap_size.height);
+
+ if (gr_ctx.draw_funcs.xcb_draw)
+ gr_ctx.draw_funcs.xcb_draw (back_pxmap, pxmap_size.width, pxmap_size.height);
+
+ DEBUG_OUT ("render in pixmap: 0x%x.\n", back_pxmap);
+ }
+}
+
+// wrap over present pixmap request
+//========================================================================
+static void
+swap_buffers (uint64_t msc, uint32_t idx)
+{
+ xcb_pixmap_t back_pxmap;
+
+ back_pxmap = dri3_buffers[idx].pxmap;
+
+ xcb_present_pixmap (display.dpy, display.wnd, back_pxmap, idx,
+ 0, 0, 0, 0, 0, 0, 0, XCB_PRESENT_OPTION_NONE, msc, 0, 0, 0, NULL);
+
+ DEBUG_OUT ("swap pixmap[%d]: 0x%x, msc: %llu\n", idx, back_pxmap, msc);
+
+ // block pixmap/bo to next draw and swap operations
+ dri3_buffers[idx].busy = 1;
+}
+
+// reallocate dri3_buff and corresponding pixmap and tbm bo
+// idx - index inner array of dri3 buffers
+//===================================================================
+static void
+realloc_dri3_buff (uint32_t idx, uint16_t width, uint16_t height)
+{
+ if (idx >= gr_ctx.params.num_of_bufs) return;
+
+ // release dmabuf file, old bo and pixmap
+ if (gr_ctx.mode != PRESENT_MODE)
+ {
+ if (dri3_buffers[idx].bo.bo)
+ {
+ tbm_bo_unref(dri3_buffers[idx].bo.bo);
+ DEBUG_OUT ("tbm bo: 0x%p has been unrefed.\n", dri3_buffers[idx].bo.bo);
+ }
+
+ if (dri3_buffers[idx].bo.dma_buf_fd)
+ close (dri3_buffers[idx].bo.dma_buf_fd);
+ }
+
+ if (dri3_buffers[idx].pxmap)
+ {
+ xcb_free_pixmap(display.dpy, dri3_buffers[idx].pxmap);
+ DEBUG_OUT ("pixmap: 0x%x has been freed.\n", dri3_buffers[idx].pxmap);
+ }
+
+ // create new bo and pixmap
+ dri3_buffers[idx].pxmap_size.width = width;
+ dri3_buffers[idx].pxmap_size.height = height;
+ dri3_buffers[idx].pxmap = xcb_generate_id (display.dpy);
+ xcb_create_pixmap (display.dpy, DEPTH, dri3_buffers[idx].pxmap, display.wnd,
+ dri3_buffers[idx].pxmap_size.width,
+ dri3_buffers[idx].pxmap_size.height);
+
+ DEBUG_OUT ("pixmap: 0x%x has been created.\n", dri3_buffers[idx].pxmap);
+
+ // creates bo, tied toward pixmap, to do direct drawing in it
+ if (gr_ctx.mode != PRESENT_MODE)
+ dri3_buffers[idx].bo = get_bo_from_pixmap (dri3_buffers[idx].pxmap);
+
+ dri3_buffers[idx].buff_must_be_realloc = 0;
+
+ DEBUG_OUT ("buffer: %u has been reallocated (tbm_bo: 0x%p, pixamp: 0x%x, wxh: %hux%hu).\n",
+ idx, dri3_buffers[idx].bo.bo, dri3_buffers[idx].pxmap, width, height);
+}
+
+//========================================================================
+//========================================================================
+//========================================================================
+
+
+// checks dri3 and present extensions, does dri3_open request and initiates
+// tizen buffer manager
+// return 0 if success, 1 otherwise
+//===================================================================
+int
+prepare_dri3_present_ext (void)
+{
+ uint32_t present_eid;
+ int i;
+
+ // present initialization
+
+ if (check_present_ext ()) return 1;
+
+ // ask present extension to notify us about events
+ present_eid = xcb_generate_id (display.dpy);
+ xcb_present_select_input (display.dpy, present_eid, display.wnd,
+ XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
+
+ // for determine dri3's events
+ dri3_present_info.present_ext = xcb_get_extension_data (display.dpy, &xcb_present_id);
+ if (!dri3_present_info.present_ext)
+ {
+ printf ("Error while xcb_get_extension_data call.\n");
+ return 1;
+ }
+
+ // dri3 initialization
+
+ if (gr_ctx.mode != PRESENT_MODE)
+ {
+ dri3_present_info.drm_fd = prepare_dri3_ext();
+ if (dri3_present_info.drm_fd < 0) return 1;
+ dri3_present_info.bufmgr = tbm_bufmgr_init (dri3_present_info.drm_fd);
+ }
+
+ // allocate neccessary memory for dri3 buffers
+ dri3_buffers = calloc (gr_ctx.params.num_of_bufs, sizeof (dri3_buffer_t));
+
+ // set up dri3 buffers
+ for (i = 0; i < gr_ctx.params.num_of_bufs; i++)
+ realloc_dri3_buff (i, wnd_pos.width, wnd_pos.height);
+
+ printf ("%u buffer(s) will be used.\n", gr_ctx.params.num_of_bufs);
+
+ return 0;
+}
+
+// dri3 events loop
+//========================================================================
+void
+dri3_loop (void)
+{
+ xcb_generic_event_t* event = NULL;
+ xcb_ge_generic_event_t* generic_event = NULL;
+ int i;
+#ifndef _DEBUG_
+ struct timespec start;
+#endif
+
+ // ask to be notifed by present extension about current msc
+ xcb_present_notify_msc (display.dpy, display.wnd, 0, 0, 0, 0);
+
+ while (1)
+ {
+ xcb_flush (display.dpy);
+ event = xcb_wait_for_event (display.dpy);
+ if (!event)
+ {
+ DEBUG_OUT ("event returned by xcb_wait_for_event is NULL.\n");
+ break;
+ }
+
+ switch (event->response_type)
+ {
+ case XCB_GE_GENERIC:
+ {
+ generic_event = (xcb_ge_generic_event_t*)event;
+
+ // if event is from present Ext.
+ if (generic_event->extension == dri3_present_info.present_ext->major_opcode)
+ {
+ switch (generic_event->event_type)
+ {
+ case XCB_PRESENT_CONFIGURE_NOTIFY:
+ {
+ xcb_present_configure_notify_event_t* config_ev;
+ config_ev = (xcb_present_configure_notify_event_t*)event;
+
+ DEBUG_OUT ("XCB_PRESENT_CONFIGURE_NOTIFY: (%hd, %hd) [%hux%hu]\n",
+ config_ev->x, config_ev->y, config_ev->width, config_ev->height);
+
+ for (i = 0; i < gr_ctx.params.num_of_bufs; i++)
+ dri3_buffers[i].buff_must_be_realloc = 1;
+
+ wnd_pos.x = config_ev->x;
+ wnd_pos.y = config_ev->y;
+ wnd_pos.width = config_ev->width;
+ wnd_pos.height = config_ev->height;
+ }
+ break;
+
+ case XCB_PRESENT_COMPLETE_NOTIFY:
+ {
+ DEBUG_OUT ("XCB_PRESENT_COMPLETE_NOTIFY:\n");
+
+ xcb_present_complete_notify_event_t* complete_ev;
+ complete_ev = (xcb_present_complete_notify_event_t*)event;
+
+ if (complete_ev->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+ {
+#ifdef _DEBUG_
+ DEBUG_OUT (" XCB_PRESENT_COMPLETE_KIND_PIXMAP, serial = %u, msc = %llu, ",
+ complete_ev->serial, complete_ev->msc);
+ switch (complete_ev->mode)
+ {
+ case XCB_PRESENT_COMPLETE_MODE_COPY:
+ printf ("COPY.\n");
+ break;
+ case XCB_PRESENT_COMPLETE_MODE_FLIP:
+ printf ("FLIP.\n");
+ break;
+ case XCB_PRESENT_COMPLETE_MODE_SKIP:
+ printf ("SKIP.\n");
+ break;
+
+ default:
+ printf (" What is it?\n");
+ break;
+ }
+#endif
+ }
+ else if (complete_ev->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC)
+ {
+ DEBUG_OUT ("XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC\n");
+
+ // compute msc to use with present_pixmap request
+ target_msc = complete_ev->msc + gr_ctx.params.swap_interval;
+ }
+#ifndef _DEBUG_
+ fps_calc( &start );
+ clock_gettime( CLOCK_REALTIME, &start );
+#endif
+ // if some delays are occured
+ if (target_msc <= complete_ev->msc)
+ target_msc = complete_ev->msc + gr_ctx.params.swap_interval;
+
+ // complete_ev->msc - number of frame that is displayed now,
+ // or will be displayed soon, after vblank end.
+ // so we draw new frames in idle pixmaps and ask to present
+ // our frames to next mscs with some interval.
+
+ // if we obtained XCB_PRESENT_IDLE_NOTIFY event without
+ // XCB_PRESENT_COMPLETE_NOTIFY, this means that present
+ // drop our frame and we can draw new frame, and ask to
+ // present it immediately, without waiting for XCB_PRESENT_COMPLETE_NOTIFY
+ // event, that will be delivered with some delay, but in this case,
+ // we don't know about real msc and new present may results new drop,
+ // so we will do present only when handling XCB_PRESENT_COMPLETE_NOTIFY event,
+ // despite of some performance decrease
+ for (i = 0; i < gr_ctx.params.num_of_bufs; i++)
+ {
+ // if buffer is busy (non-idle)
+ if (dri3_buffers[i].busy)
+ continue;
+
+ draw (i); // draw our mesh
+ swap_buffers (target_msc, i);
+
+ target_msc += gr_ctx.params.swap_interval;
+ }
+ }
+ break;
+
+ case XCB_PRESENT_IDLE_NOTIFY:
+ {
+ xcb_present_idle_notify_event_t* idle_ev;
+ idle_ev = (xcb_present_idle_notify_event_t*)event;
+
+ if (idle_ev->serial >= gr_ctx.params.num_of_bufs)
+ {
+ set_error ("invalid parameters from present extension.\n");
+ pthread_cancel(thread_id);
+ }
+
+ DEBUG_OUT ("----------------------------\n"
+ "XCB_PRESENT_IDLE_NOTIFY: pixmap: 0x%x (tied tbm bo: 0x%p), serial: %u, event: %u\n",
+ idle_ev->pixmap, dri3_buffers[idle_ev->serial].bo.bo, idle_ev->serial, idle_ev->event);
+
+ // unblock pixmap/bo to next draw and swap operations
+ dri3_buffers[idle_ev->serial].busy = 0;
+
+ // adjust pixmap/bo size to wnd's size before start render into it
+ if (dri3_buffers[idle_ev->serial].buff_must_be_realloc)
+ realloc_dri3_buff (idle_ev->serial, wnd_pos.width, wnd_pos.height);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ } //case XCB_GE_GENERIC:
+ break;
+
+ default:
+ DEBUG_OUT ("dri3_loop: default case.\n event->response_type = %d.\n",
+ event->response_type);
+ break;
+ } //switch (event->response_type)
+ } //while (1)
+}
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.c b/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.c
new file mode 100755
index 0000000..29df183
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.c
@@ -0,0 +1,108 @@
+/**************************************************************************
+
+ fps computation module's source
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#include <stdio.h>
+
+#include "fps.h"
+
+#define BILLION 1000000000
+#define BILLION_F 1000000000.0f
+
+#define FPS_AVERAGE 1 // fps average value (in seconds)
+
+// for fps calculation
+//=====================================================================================
+void
+fps_calc (const struct timespec* start)
+{
+ struct timespec end;
+ double time_diff;
+ double fps;
+
+ static double sum_fps;
+ static time_t prev_time;
+ static int cnt = 1;
+
+ if (!start) return;
+
+ // note: start variable contains start time of time-execution measured code section
+
+ // get time end of time-execution measured code section
+ clock_gettime (CLOCK_REALTIME, &end);
+
+ // get difference in nanoseconds
+ time_diff = (double)( ( end.tv_sec - start->tv_sec ) * BILLION +
+ ( end.tv_nsec - start->tv_nsec ) );
+
+ // get frames per second value
+ fps = BILLION_F / time_diff;
+
+ // average fps calculation
+ if (end.tv_sec - prev_time >= FPS_AVERAGE)
+ {
+ printf ("\033[8D");
+ printf (" ");
+ printf ("\033[8D");
+ printf ("%8.1f", sum_fps/cnt);
+ fflush (stdout);
+
+ cnt = 0;
+ sum_fps = 0;
+
+ prev_time = end.tv_sec;
+ }
+ else
+ {
+ cnt++;
+ sum_fps += fps;
+ }
+}
+
+// return time diff (between time in 'start' and time when this function is called)
+// in nanoseconds
+//=====================================================================================
+double
+get_time_diff (const struct timespec* start)
+{
+ struct timespec end;
+ double time_diff;
+
+ if (!start) return 0;
+
+ // note: start variable contains start time of time-execution measured code section
+
+ // get time end of time-execution measured code section
+ clock_gettime (CLOCK_REALTIME, &end);
+
+ // get difference in nanoseconds
+ time_diff = (double)( ( end.tv_sec - start->tv_sec ) * BILLION +
+ ( end.tv_nsec - start->tv_nsec ) );
+ return time_diff;
+}
diff --git a/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.h b/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.h
new file mode 100755
index 0000000..bef0100
--- /dev/null
+++ b/tests/functional/hwc_test/aux_dri2_dri3_lib/fps.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+
+ fps computation module's header
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+#ifndef _FPS_H
+#define _FPS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+
+void fps_calc (const struct timespec* start);
+double get_time_diff (const struct timespec* start);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/functional/hwc_test/clock.c b/tests/functional/hwc_test/clock.c
new file mode 100644
index 0000000..97b24e8
--- /dev/null
+++ b/tests/functional/hwc_test/clock.c
@@ -0,0 +1,316 @@
+/**************************************************************************
+
+ watch
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Roman Marchenko <r.marchenko@samsung.com>
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implements analog watch for using in semiautomatic tests for
+// keep safe ddx driver devoloping
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <math.h>
+
+#include "aux_apps.h"
+#include "dri2_dri3.h"
+
+
+#define DEGREE_PER_SECOND (6)
+
+
+typedef struct _point
+{
+ int x, y;
+ int color;
+} PointRec, *PointPtr;
+
+typedef struct _circle
+{
+ PointRec center;
+ int R;
+} CircleRec, *CirclePtr;
+
+typedef struct _warch
+{
+ CircleRec crcl;
+ int time;
+} WatchRec, *WatchPtr;
+
+
+xcb_connection_t* dpy = NULL;
+xcb_screen_t* screen = NULL;
+xcb_rectangle_t wnd_pos = {100, 100, 200, 200};
+
+// work behavior flags: (see aux_apps.c for details)
+
+// mode of work (dri2/dri3+present)
+int mode = DRI3_PRESENT_MODE; // by default dri3 + present will be used
+int stop;
+WatchRec watch;
+uint32_t present_bufs = 3;
+uint32_t swap_interval = 1;
+uint32_t root_parent = 1;
+
+// functions set for render watch:
+
+inline void
+set_point(PointPtr p, uint32_t *map, uint32_t pitch, uint32_t size)
+{
+ int off = (pitch * p->y + p->x);
+ if (off < size && off >= 0)
+ map[off] = p->color;
+}
+
+inline void
+draw_point(PointPtr p, uint32_t *map, uint32_t pitch, uint32_t size)
+{
+ set_point(p, map, pitch, size);
+
+ p->x += 1;
+ set_point(p, map, pitch, size);
+ p->x -= 1;
+
+ p->y += 1;
+ set_point(p, map, pitch, size);
+ p->y -= 1;
+
+ p->x -= 1;
+ set_point(p, map, pitch, size);
+ p->x += 1;
+
+ p->y -= 1;
+ set_point(p, map, pitch, size);
+ p->y += 1;
+}
+
+void
+draw_circle(CirclePtr c, uint32_t *map, uint32_t pitch, uint32_t size)
+{
+ double x0 = c->center.x;
+ double y0 = c->center.y;
+ double R = c->R;
+
+ PointRec p = { 0, 0, c->center.color };
+
+ double fi;
+ int a;
+ for (a = 0; a < 360; a += DEGREE_PER_SECOND)
+ {
+ fi = M_PI / 180 * a;
+ p.x = (int) (x0 + R * cos(fi));
+ p.y = (int) (y0 + R * sin(fi));
+ draw_point(&p, map, pitch, size);
+ }
+}
+
+void
+draw_watch(WatchPtr w, uint32_t *map, uint32_t pitch, uint32_t size)
+{
+ draw_circle(&w->crcl, map, pitch, size);
+
+ //drawing hand of the clock, use the change of radius
+ PointRec p = { 0, 0, w->crcl.center.color };
+
+ double fi = M_PI / 180 * (w->time * DEGREE_PER_SECOND);
+
+ int R;
+ for (R = 0; R < (w->crcl.R - 3); R += 10)
+ {
+ p.x = (int) (w->crcl.center.x + R * cos(fi));
+ p.y = (int) (w->crcl.center.y + R * sin(fi));
+ draw_point(&p, map, pitch, size);
+ }
+}
+
+/*
+//
+//===================================================================
+void
+rotate (void)
+{
+ #define REFRESHE_TIME (16.0) // in ms
+
+ struct timespec current;
+ static struct timespec prev;
+ double time_diff;
+
+ clock_gettime (CLOCK_REALTIME, &current);
+
+ // get difference in nanoseconds
+ time_diff = (double)( ( current.tv_sec - prev.tv_sec ) * 1000000000 +
+ ( current.tv_nsec - prev.tv_nsec ) );
+
+ if (time_diff / 1000000.0 > REFRESHE_TIME)
+ {
+ prev = current;
+
+ watch.time++;
+ }
+
+ #undef REFRESHE_TIME
+}
+*/
+
+// direct accessing memory clear callback
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_clear (const bo_t* bo_e)
+{
+ xcb_rectangle_t rect;
+
+ if (!bo_e)
+ {
+ printf ("raw_clear: invalid parameters.\n");
+ return;
+ }
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = bo_e->width;
+ rect.height = bo_e->height;
+
+ // simple draw black rectangle with size as window has
+ raw_fill_rect (bo_e, 1, &rect, screen->black_pixel);
+}
+
+// direct accessing memory draw callback (watch drawing)
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_draw (const bo_t* bo_e)
+{
+ tbm_bo_handle hndl;
+ int* temp_map;
+ int i;
+
+ if (!bo_e)
+ {
+ printf ("raw_draw: invalid parameters.\n");
+ return;
+ }
+
+ watch.crcl.R = (bo_e->width > bo_e->height) ? bo_e->height/2 : bo_e->width/2;
+ watch.crcl.center.x = bo_e->width / 2;
+ watch.crcl.center.y = bo_e->height / 2;
+
+ hndl = tbm_bo_map (bo_e->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ if (!hndl.ptr)
+ {
+ printf ("raw_draw_line: Error while tbm_bo_map.\n");
+ exit (1);
+ }
+
+ // clear buffer
+ // we set all transparency bits to make buffer content fully
+ // un-transparency, actually to see this content over other buffers
+ temp_map = (int*)hndl.ptr;
+ for (i = 0; i < (bo_e->stride * bo_e->height)/sizeof(int); i++)
+ *temp_map++ = 0xff000000;
+
+ draw_watch (&watch, (uint32_t*)hndl.ptr, bo_e->stride/4,
+ tbm_bo_size (bo_e->bo)/4);
+
+ if (!stop)
+ watch.time++;//rotate ();
+
+ tbm_bo_unmap (bo_e->bo);
+}
+
+//
+//===================================================================
+int
+main (int argc, char** argv)
+{
+ xcb_generic_event_t* event = NULL;
+ xcb_window_t main_wnd;
+ draw_funcs_t draw_func;
+ dri2_dri3_params_t params;
+ int res;
+
+ cmd_parse (argc, argv);
+
+ dpy = xcb_connect (NULL, NULL);
+
+ // get first screen of display
+ screen = xcb_setup_roots_iterator (xcb_get_setup (dpy)).data;
+
+ main_wnd = create_window (dpy, 0xff, root_parent, "clock");
+
+ watch.crcl.R = (wnd_pos.width > wnd_pos.height) ? wnd_pos.height/2 : wnd_pos.width/2;
+ watch.crcl.center.x = wnd_pos.width / 2;
+ watch.crcl.center.y = wnd_pos.height / 2;
+ watch.crcl.center.color = 0xff00ff00; // set all transparency bits
+
+ draw_func.raw_clear = NULL;
+ draw_func.raw_draw = raw_draw;
+ draw_func.xcb_clear = NULL;
+ draw_func.xcb_draw = NULL;
+
+ params.num_of_bufs = present_bufs;
+ params.swap_interval = swap_interval;
+
+ // inside init_dri2_dri3 new thread, responsible for dri2/dri3/present events
+ // handling, will be created
+ res = init_dri2_dri3 (dpy, &draw_func, mode, main_wnd, &params);
+ if (res)
+ {
+ printf ("init_dri2_dri3: %s.\n", get_last_error());
+ exit (1);
+ }
+
+ printf ("before xcb loop.\n");
+
+ while (1)
+ {
+ xcb_flush (dpy);
+ event = xcb_wait_for_event (dpy);
+ if (!event) break;
+
+ switch (event->response_type)
+ {
+ case XCB_EXPOSE:
+ DEBUG_OUT ("XCB_MAP_WINDOW\n");
+ break;
+
+ // if we are notified by XCB_BUTTON_PRESS event, we start/stop
+ // to change our frames, simple draw the same thing
+ case XCB_BUTTON_PRESS:
+ stop ^= 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/functional/hwc_test/hwc_sample/hwc-sample.c b/tests/functional/hwc_test/hwc_sample/hwc-sample.c
new file mode 100755
index 0000000..4e8ce0e
--- /dev/null
+++ b/tests/functional/hwc_test/hwc_sample/hwc-sample.c
@@ -0,0 +1,1377 @@
+/**************************************************************************
+
+ hwc_sample
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: SooChan Lim <sc1.lim@samsung.com>
+ Contact: Olexandr Rozov <o.rozov@samsung.com>
+ Contact: Roman Marchenko <r.marchenko@samsung.com>
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+/* This file contains implementation of software/hardware composition manager.
+ This app uses hwc, composite and damage extensions to create image of screen
+ from window's contents by using copy_area/drm planes.*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <dlog.h>
+
+#include <xcb/composite.h>
+#include <xcb/damage.h>
+#include <xcb/hwc.h>
+
+#include "list.h"
+
+#define _DEBUG_
+#ifdef _DEBUG_
+ #define DEBUG_OUT(format, args...) { ALOG(LOG_INFO, "HWC_SAMPLE", format, ##args); }
+#else
+ #define DEBUG_OUT(...) {;}
+#endif
+
+typedef struct cmd_options_t
+{
+ int not_use_hw_layers; // whether we want to use hardware layers to make compositing or not
+} cmd_options_t;
+
+// thus structure describes window in window's list
+typedef struct window_t
+{
+ struct list_head list_member;
+ xcb_window_t wnd_id; // X11 client sees only this id
+ xcb_window_t parent_id; // parent, after reparenting !
+ xcb_pixmap_t wnd_content; // refered to off-screen storage of redirected window
+ xcb_hwc_draw_info_t hwc_info; // info for use in hwc_set_drawable
+ uint8_t use_hw_layer; // whether this window must be compositing via hardware layer
+ uint8_t off_hw_layer; // user can specify use or not hw layer for this window
+ uint8_t is_hidden; // is window hidden, this means window doesn't participate
+ // in composition
+ xcb_damage_damage_t damage;
+} window_t;
+
+typedef struct window_manager_t
+{
+ struct list_head wnds_list_head; // list of grabbed windows, arranged by stack order position
+ u_int32_t amount; // amout of windows in above list
+ const xcb_query_extension_reply_t* damage_ext; // for determine damage's events
+ u_int32_t max_amount_hw_layers; // maximum available hardware layers
+ u_int32_t cur_amount_hw_layers; // current amount of utilized hardware layers
+ xcb_gcontext_t gc_soft_composite; // used for software compositing
+ xcb_gcontext_t gc_fill_root_buf; // used to fill root buffer
+
+ // to avoid flickering, we just composite all windows to this pixmap, then, after
+ // composition of all window completed, composite this pixmap to root window
+ xcb_pixmap_t root_buffer;
+
+ // information about windows which will be composited via hardware layers
+ xcb_hwc_draw_info_t* hwc_info;
+ cmd_options_t cmd_opts; // cmd line options
+
+ // window pushed out from hw layer stack, when some window was set on top of this stack,
+ // this variable used for composite pushed out window in software only mode in time
+ // when hw composition for this (some) window occur
+ struct window_t* pushed_from_hw_stack;
+
+} window_manager_t;
+
+xcb_connection_t* xcb_dpy;
+xcb_screen_t* xcb_screen;
+
+window_manager_t wm;
+
+// update root window
+//========================================================================
+static void
+_update_root (void)
+{
+ // composite root_buffer to root window to show on screen
+ xcb_copy_area (xcb_dpy, wm.root_buffer, xcb_screen->root, wm.gc_soft_composite, 0, 0,
+ 0, 0, xcb_screen->width_in_pixels, xcb_screen->height_in_pixels);
+ DEBUG_OUT (" composite root_buffer to root wnd.\n");
+}
+
+// update root_buffer, that can be then copied to root window via _update_root()
+//========================================================================
+static void
+_update_root_buf (window_t* wnd)
+{
+ if (!wnd) return;
+
+ // composite window to root_buffer
+ xcb_copy_area (xcb_dpy, wnd->wnd_content, wm.root_buffer, wm.gc_soft_composite, 0, 0,
+ wnd->hwc_info.dstX, wnd->hwc_info.dstY, wnd->hwc_info.dstWidth,
+ wnd->hwc_info.dstHeight);
+ DEBUG_OUT (" off-screen storage: 0x%06x of wnd: 0x%06x (child wnd: 0x%06x) has been"
+ " composited to root_buffer at %hd, %hd, [%hux%hu].\n", wnd->wnd_content,
+ wnd->parent_id, wnd->wnd_id, wnd->hwc_info.dstX, wnd->hwc_info.dstY,
+ wnd->hwc_info.dstWidth, wnd->hwc_info.dstHeight);
+}
+
+// fill root buffer before composite on it
+//========================================================================
+static void
+_fill_root_buffer (void)
+{
+ xcb_rectangle_t rect;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = xcb_screen->width_in_pixels;
+ rect.height = xcb_screen->height_in_pixels;
+
+ xcb_poly_fill_rectangle (xcb_dpy, wm.root_buffer, wm.gc_fill_root_buf, 1, &rect);
+
+ DEBUG_OUT ("root_buffer has been filled.\n");
+}
+
+//
+//========================================================================
+static void
+_hwc_set_print_info (void)
+{
+ int i;
+
+ DEBUG_OUT (" hwc_set_drawable:\n");
+
+ for (i = 0; i < wm.cur_amount_hw_layers; i++)
+ DEBUG_OUT (" drawable: 0x%06x, composite_method: %d, from %hd, %hd [ %hux%hu], "
+ "to %hd, %hd [%hux%hu].\n",
+ wm.hwc_info[i].drawable, wm.hwc_info[i].composite_methods,
+ wm.hwc_info[i].srcX, wm.hwc_info[i].srcY, wm.hwc_info[i].srcWidth, wm.hwc_info[i].srcHeight,
+ wm.hwc_info[i].dstX, wm.hwc_info[i].dstY, wm.hwc_info[i].dstWidth, wm.hwc_info[i].dstHeight);
+}
+
+// do compositing of one drawable
+// drawable - window id user application knows about which (passed root wnd will be ignored) !!!
+//========================================================================
+static void
+composite_drawable (xcb_drawable_t drawable)
+{
+ window_t* wnd;
+ int update_root = 0;
+
+ // iterate over grabbed windows list, from topmost window to lowermost window
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ // look for window which must be recomposited
+ if (wnd->wnd_id != drawable || wnd->wnd_id == xcb_screen->root) continue;
+
+ // if we in software only composite mode
+ if (wm.cmd_opts.not_use_hw_layers)
+ {
+ _update_root_buf (wnd);
+ _update_root ();
+
+ break;
+ }
+ else
+ {
+ // if wnd isn't on hw layer, copy window content to root window
+ if (!wnd->use_hw_layer)
+ {
+ update_root = 1;
+ _update_root_buf (wnd);
+ }
+
+ // if window is on hw layer it can pushed out, from hw layer stack, window that
+ // was on hw layer previously (it can be occurred after MapRequest for some window),
+ // so we must do sw composition for this pushed out window
+ else if (wm.pushed_from_hw_stack)
+ {
+ update_root = 1;
+ _update_root_buf (wm.pushed_from_hw_stack);
+ wm.pushed_from_hw_stack = NULL;
+ }
+
+ // composite root_buffer to root window to show on screen, if root buffer was changed
+ if (update_root) _update_root ();
+
+ // we must reset drawables, the main reason to do this, for windows which are on hw
+ // layers, is that present extension in X server makes swap of buffers, not copy
+ // (see present/present.c in Xorg) and we cann't distinguish no-dri, dri2 and present windows
+ xcb_hwc_set_drawable (xcb_dpy, 0, wm.cur_amount_hw_layers, wm.hwc_info);
+ _hwc_set_print_info ();
+
+ break;
+ }
+ }
+
+ xcb_flush (xcb_dpy);
+}
+
+// do compositing of all windows, in any cases root window will be updated
+//========================================================================
+static void
+composite_all (void)
+{
+ window_t* wnd;
+
+ DEBUG_OUT ("compositing of all windows:\n");
+
+ // fill root buffer before composite on it
+ _fill_root_buffer ();
+
+ // if user doesn't want to do hardware compositing
+ if (wm.cmd_opts.not_use_hw_layers)
+ {
+ // iterate over grabbed windows list, from lowermost window to topmost window
+ // NOTE: this implementation of list ala stack, so we must use _prev suffix
+ list_for_each_prev_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ if (wnd->wnd_id == xcb_screen->root)
+ continue;
+
+ _update_root_buf (wnd);
+ }
+
+ _update_root ();
+ }
+ else
+ {
+ list_for_each_prev_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ if (wnd->use_hw_layer || wnd->wnd_id == xcb_screen->root) continue;
+
+ _update_root_buf (wnd);
+ }
+
+ // composite root_buffer to root window to show on screen,
+ _update_root ();
+
+ xcb_hwc_set_drawable (xcb_dpy, 0, wm.cur_amount_hw_layers, wm.hwc_info);
+ _hwc_set_print_info ();
+ }
+
+ xcb_flush (xcb_dpy);
+}
+
+// return geometry of specified, by win_id, window (via second parameter)
+// return -1 if fail
+//========================================================================
+static int
+get_wnd_geometry (xcb_window_t win_id, xcb_get_geometry_reply_t* geo)
+{
+ xcb_get_geometry_cookie_t gg_c;
+ xcb_get_geometry_reply_t* gg_r = NULL;
+ xcb_generic_error_t* xcb_error = NULL;
+
+ if (!geo) return -1;
+
+ gg_c = xcb_get_geometry (xcb_dpy, win_id);
+ gg_r = xcb_get_geometry_reply (xcb_dpy, gg_c, &xcb_error);
+ if (xcb_error)
+ {
+ printf ("error while xcb_get_geometry call.\n");
+ free (xcb_error);
+ return -1;
+ }
+
+ memcpy (geo, gg_r, sizeof(xcb_get_geometry_reply_t));
+
+ free (gg_r);
+
+ return 0;
+}
+
+// turn on external window events tracking
+// in this function we ask X server to send us DestroyNotify, UnmapNotify events
+// for window specified via @wnd->wnd_id
+//========================================================================
+static int
+turn_on_track_ext_wnd_events (window_t* wnd)
+{
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t* xcb_error;
+
+ uint32_t value_mask;
+ uint32_t value_list[1];
+
+ if (!wnd) return -1;
+
+ value_mask = XCB_CW_EVENT_MASK;
+ value_list[0] = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+
+ // ask X server to send us DestroyNotify, UnmapNotify and other notify events
+ // for @wnd->wnd_id window
+ cookie = xcb_change_window_attributes_checked (xcb_dpy, wnd->wnd_id, value_mask, value_list);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_change_window_attributes call.\n");
+ free (xcb_error);
+ return -1;
+ }
+
+ printf (" turn on events tracking for external window: 0x%06x.\n\n", wnd->wnd_id);
+
+ return 0;
+}
+
+// TODO:
+//========================================================================
+static void
+unreparent_wnd (xcb_window_t wnd_id, xcb_window_t parent_id)
+{
+ xcb_destroy_window (xcb_dpy, parent_id);
+}
+
+// create new window @parent_id with parent like parent of @wnd_id,
+// with same geometry, visual, border width and depth, and reparent
+// @wnd_id to new parent @parent_id
+//========================================================================
+static int
+reparent_wnd (xcb_window_t wnd_id, xcb_window_t* parent_id)
+{
+ xcb_get_geometry_reply_t geo;
+
+ xcb_get_window_attributes_cookie_t get_attr_c;
+ xcb_get_window_attributes_reply_t* get_attr_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ xcb_query_tree_cookie_t query_tree_c;
+ xcb_query_tree_reply_t* query_tree_r;
+
+ xcb_void_cookie_t cookie;
+ int res;
+
+ if (!parent_id) return -1;
+
+ get_attr_c = xcb_get_window_attributes (xcb_dpy, wnd_id);
+ get_attr_r = xcb_get_window_attributes_reply (xcb_dpy, get_attr_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ printf ("error while xcb_get_window_attributes call.\n");
+ free (xcb_errors);
+ return -1;
+ }
+
+ // for determine parent of window, identifiable by wnd_id
+ query_tree_c = xcb_query_tree (xcb_dpy, wnd_id);
+ query_tree_r = xcb_query_tree_reply (xcb_dpy, query_tree_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ printf ("error while query_tree call.\n");
+ free (xcb_errors);
+ goto fail_1;
+ }
+
+ res = get_wnd_geometry (wnd_id, &geo);
+ if (res < 0)
+ goto fail_2;
+
+ *parent_id = xcb_generate_id (xcb_dpy);
+
+ cookie = xcb_create_window_checked (xcb_dpy, geo.depth, *parent_id, query_tree_r->parent,
+ geo.x, geo.y, geo.width, geo.height, geo.border_width,
+ get_attr_r->_class, get_attr_r->visual, 0, NULL);
+ if ((xcb_errors = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_create_window call.\n");
+ free (xcb_errors);
+ goto fail_2;
+ }
+
+ cookie = xcb_reparent_window_checked (xcb_dpy, wnd_id, *parent_id, 0, 0);
+ if ((xcb_errors = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_reparent_window call.\n");
+ xcb_destroy_window (xcb_dpy, *parent_id);
+ free (xcb_errors);
+ goto fail_2;
+ }
+
+ xcb_map_window (xcb_dpy, wnd_id);
+
+ free (query_tree_r);
+ free (get_attr_r);
+
+ return 0;
+
+ // we cann't reparent window
+fail_2:
+ free (query_tree_r);
+fail_1:
+ free (get_attr_r);
+ return -1;
+}
+
+// this function determines for which windows hw layers will be used, for composition
+// Note: only this function can change @wnd->use_hw_layer field !!!
+//========================================================================
+static void
+_reorder_hw_layers_stack (void)
+{
+ window_t* wnd;
+ int i = 0;
+
+ // iterate over grabbed windows list, from topmost window to lowermost window
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ // if window isn't hidden, if user allowed to use hw layer for this window
+ if (wnd->wnd_id != xcb_screen->root && !wnd->is_hidden && !wnd->off_hw_layer && i < (wm.max_amount_hw_layers - 1))
+ {
+ i++;
+ wnd->use_hw_layer = 1;
+ }
+ else
+ {
+ // in this branch, only one window can has use_hw_layer field set to 1
+ // this is window pushed out from hw layers stack, so we must save it
+ // and, then, when we will do composition for window that push, we also
+ // will do composition for pushed out window
+ if (wnd->use_hw_layer)
+ wm.pushed_from_hw_stack = wnd;
+
+ wnd->use_hw_layer = 0; // all other window will be composited via sw way, except root wnd
+ }
+ }
+
+ // Note: if some window was mapped it can result to push out lowest window (in hw layers stack)
+ // from hw layers stack. And if window was unmapped (hidden) in can result to push in
+ // window (for which wasn't available hw layer previously) to hw layer stack.
+}
+
+// this function fills wm.hwc_info array used for hw composition (hwc_set_drawable request)
+// we must call this function when:
+// we have grabbed window - new grabbed window must be set on topmost hw layer
+// wnd hierarchy is changed - to show this changes
+// wnd geometry has been changed - to show this changes
+// wnd was unmapped (hidden) - to show this changes
+// NOTE: only this function can change wm.hwc_info array !!!
+//========================================================================
+static void
+set_hw_layers_stack (void)
+{
+ window_t* wnd;
+ int i = 0;
+
+ _reorder_hw_layers_stack ();
+
+ // reset hw layers stack
+ memset (wm.hwc_info, 0, wm.max_amount_hw_layers * sizeof(xcb_hwc_draw_info_t));
+
+ // iterate over grabbed windows list, from topmost window to lowermost window
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ // root is lowermost window in list
+ if (wnd->wnd_id == xcb_screen->root)
+ memcpy (&wm.hwc_info[i++], &wnd->hwc_info, sizeof(wnd->hwc_info));
+ else if (wnd->use_hw_layer && i < (wm.max_amount_hw_layers - 1))
+ memcpy (&wm.hwc_info[i++], &wnd->hwc_info, sizeof(wnd->hwc_info));
+ }
+
+ // set current amount of utilized hw layers to use in hwc_set_drawable request
+ wm.cur_amount_hw_layers = i;
+}
+
+// init/reinit info for set window on hw layer
+// wnd - id of window which hwc_info must be changed
+// return -1 if fail
+//========================================================================
+static int
+init_hwc_info (window_t* wnd)
+{
+ xcb_get_geometry_reply_t geo;
+ int res;
+
+ if (!wnd) return -1;
+
+ res = get_wnd_geometry (wnd->wnd_id, &geo);
+ if (res < 0) return -1;
+
+ wnd->hwc_info.drawable = wnd->wnd_id;
+
+ wnd->hwc_info.srcX = 0;
+ wnd->hwc_info.srcY = 0;
+ wnd->hwc_info.srcWidth = geo.width;
+ wnd->hwc_info.srcHeight = geo.height;
+
+ wnd->hwc_info.dstX = geo.x;
+ wnd->hwc_info.dstY = geo.y;
+ wnd->hwc_info.dstWidth = geo.width;
+ wnd->hwc_info.dstHeight = geo.height;
+
+ wnd->hwc_info.composite_methods = XCB_HWC_COMPOSITE_METHOD_DEFAULT;
+
+ return 0;
+}
+
+// ungrab window - forget about window
+// undo operations were done when window was grabbed
+//========================================================================
+static void
+ungrab_wnd (xcb_window_t wnd_id)
+{
+ window_t* wnd;
+ int res = 0;
+
+ // iterate over grabbed windows list
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ if (wnd->wnd_id == wnd_id)
+ {
+ res = 1;
+ break;
+ }
+ }
+
+ // check if we are asked to ungrab ungrabbed window
+ if (!res) return;
+
+ // if we here we must ungrab window
+
+ printf ("ungrab window: 0x%06x\n", wnd_id);
+
+ wm.amount--;
+
+ // just undo what have done when window grabbing was
+ xcb_damage_destroy (xcb_dpy, wnd->damage);
+ xcb_free_pixmap (xcb_dpy, wnd->wnd_content);
+ xcb_composite_unredirect_window (xcb_dpy, wnd->parent_id, XCB_COMPOSITE_REDIRECT_MANUAL);
+ xcb_destroy_window (xcb_dpy, wnd->parent_id);
+ list_del (&wnd->list_member);
+ free (wnd);
+
+ // we destroy (unlink) window, so we must reset hw layers stack to new condition
+ if (!wm.cmd_opts.not_use_hw_layers)
+ set_hw_layers_stack ();
+}
+
+// grab window - 'grab' means allocate window_t structure, add it to list of grabbed windows,
+// fill it fields, reparent window, redirect parent window, obtain pixmap refered to off-screen
+// storage of parent window, ask notice about damage on window, turn on external window events
+// tracking and prepare hw layer stack
+// wnd_id - id of window to grab
+//========================================================================
+static void
+grab_wnd (xcb_window_t wnd_id)
+{
+ window_t* wnd;
+ xcb_generic_error_t* xcb_error;
+ xcb_void_cookie_t cookie;
+ int res;
+
+ // iterate over grabbed windows list, maybe we have grabbed window already
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ if (wnd->wnd_id == wnd_id) return;
+ }
+
+ printf ("grab window: 0x%06x\n", wnd_id);
+
+ // if we here, window hasn't be grabbed yet, so grap it
+ wnd = (window_t*)calloc (1, sizeof(window_t));
+
+ // add window to begin of grabbed windows list
+ // so we will obtain stack-ala list
+ list_add (&wnd->list_member, &wm.wnds_list_head);
+
+ wnd->wnd_id = wnd_id;
+
+ // prepare information to use in hwc_set_drawable request
+ res = init_hwc_info (wnd);
+ if (res < 0)
+ goto fail_1;
+
+ // we mustn't reparent, redirect, create damage, obtain off-screen pixmap
+ // and reoder hw layers stack for root window
+ if (wnd->wnd_id != xcb_screen->root)
+ {
+ cookie = xcb_grab_server_checked (xcb_dpy);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_grab_server call.\n");
+ free(xcb_error);
+ goto fail_1;
+ }
+
+ res = reparent_wnd (wnd->wnd_id, &wnd->parent_id);
+ if (res < 0)
+ goto fail_1;
+
+ cookie = xcb_composite_redirect_window_checked (xcb_dpy, wnd->parent_id, XCB_COMPOSITE_REDIRECT_MANUAL);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_composite_redirect_window call.\n");
+ free(xcb_error);
+ goto fail_2;
+ }
+
+ printf (" window: 0x%06x (child wnd: 0x%06x) has been redirected to off-screen storage.\n",
+ wnd->parent_id, wnd->wnd_id);
+
+ xcb_map_window (xcb_dpy, wnd->parent_id);
+
+ // obtain pixmap refered to off-screen storage of redirected window
+ wnd->wnd_content = xcb_generate_id (xcb_dpy);
+ cookie = xcb_composite_name_window_pixmap_checked (xcb_dpy, wnd->parent_id, wnd->wnd_content);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_composite_name_window_pixmap call.\n");
+ free(xcb_error);
+ goto fail_3;
+ }
+
+ printf (" off-screen storage: 0x%06x for window: 0x%06x (child wnd: 0x%06x) has been obtained.\n",
+ wnd->wnd_content, wnd->parent_id, wnd->wnd_id);
+
+ // we track damage notification for window user know about which, not for it parent !
+ wnd->damage = xcb_generate_id (xcb_dpy);
+ cookie = xcb_damage_create_checked (xcb_dpy, wnd->damage, wnd->wnd_id, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_damage_create call.\n");
+ free(xcb_error);
+ goto fail_4;
+ }
+
+ printf (" damage object: 0x%06x for window: 0x%06x (child wnd: 0x%06x) has been created.\n",
+ wnd->damage, wnd->parent_id, wnd->wnd_id);
+
+ cookie = xcb_ungrab_server_checked (xcb_dpy);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_ungrab_server call.\n");
+ free(xcb_error);
+ goto fail_5;
+ }
+
+ // we must do this due to inability to set XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT and
+ // XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY flags together (for root wnd), so we must track
+ // events for all windows, via turn on tracking events for each window itself, no for
+ // their parent, as we did for MAP_REQUEST event
+ res = turn_on_track_ext_wnd_events (wnd);
+ if (res < 0) goto fail_5;
+ }
+
+ // we have grabbed new window, so we must reset hw layers stack to new condition
+ if (!wm.cmd_opts.not_use_hw_layers)
+ set_hw_layers_stack ();
+
+ wm.amount++;
+
+ return;
+
+ // we cann't grab this window
+fail_5:
+ xcb_damage_destroy (xcb_dpy, wnd->damage);
+fail_4:
+ xcb_free_pixmap (xcb_dpy, wnd->wnd_content);
+fail_3:
+ xcb_composite_unredirect_window (xcb_dpy, wnd->parent_id, XCB_COMPOSITE_REDIRECT_MANUAL);
+fail_2:
+ unreparent_wnd (wnd->wnd_id, wnd->parent_id);
+fail_1:
+ list_del (&wnd->list_member);
+ free (wnd);
+
+ return;
+}
+
+//
+//========================================================================
+/*static void
+show_wnd (xcb_window_t wnd_id)
+{
+
+}*/
+
+// when X11 client issue UnmapRequest for @wnd_id window we must remove this window
+// from composition process, it isn't ungrabbing, we only 'hide' window from
+// compositor and accordingly from user
+//========================================================================
+static void
+hide_wnd (xcb_window_t wnd_id)
+{
+ window_t* wnd;
+ xcb_generic_error_t* xcb_error;
+ xcb_void_cookie_t cookie;
+ int res = 0;
+
+ // iterate over grabbed windows list
+ list_for_each_entry (wnd, &wm.wnds_list_head, list_member)
+ {
+ if (wnd->wnd_id == wnd_id)
+ {
+ res = 1;
+ break;
+ }
+ }
+
+ // check if we are asked to hide ungrabbed window
+ if (!res) return;
+
+ // if we here we must hide window
+
+ printf ("hide window: 0x%06x\n", wnd_id);
+
+ // hide window to avoid it to be composition participant
+ wnd->is_hidden = 1;
+
+ // destroy damage to avoid unneccessary damage events, for this hidden window, handling
+ cookie = xcb_damage_destroy_checked (xcb_dpy, wnd->damage);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_damage_destroy call.\n");
+ free(xcb_error);
+ }
+
+ // we hide window, so we must reset hw layers stack to new condition
+ if (!wm.cmd_opts.not_use_hw_layers)
+ set_hw_layers_stack ();
+}
+
+// check does @wnd_id window exist
+// return -1 if doesn't, 0 otherwise
+//========================================================================
+static int
+check_wnd_existing (xcb_window_t wnd_id)
+{
+ xcb_generic_error_t* xcb_error;
+ xcb_void_cookie_t cookie;
+
+ cookie = xcb_unmap_window_checked (xcb_dpy, wnd_id);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ free(xcb_error);
+ return -1;
+ }
+
+ return 0;
+}
+
+// handle X11 protocol events for children of root window
+//========================================================================
+static void
+handle_x11_events (xcb_generic_event_t* xcb_event)
+{
+ xcb_generic_error_t* xcb_error;
+ xcb_void_cookie_t cookie;
+ int ret;
+
+ if (!xcb_event) return;
+
+ switch (xcb_event->response_type)
+ {
+ #ifdef _DEBUG_
+ case XCB_CLIENT_MESSAGE:
+ {
+ xcb_client_message_event_t* client_msg;
+ client_msg = (xcb_client_message_event_t*)xcb_event;
+
+ DEBUG_OUT ("client message for window: 0x%06x, type: %u, format: %hhu.\n",
+ client_msg->window, client_msg->type, client_msg->format);
+ }
+ break;
+ #endif
+
+ // when another X11 client call MapRequest we are notified about this, and only we
+ // can issue real MapRequest request
+ case XCB_MAP_REQUEST:
+ {
+ xcb_map_request_event_t* map_request;
+ map_request = (xcb_map_request_event_t*)xcb_event;
+
+ printf ("somebody try to map window: 0x%06x.\n", map_request->window);
+
+ grab_wnd (map_request->window);
+
+ // after new window was grabbed we must composite it, only it
+ composite_drawable (map_request->window);
+ }
+ break;
+
+ // when X11 client unmaps window, via xcb_unmap_window or just close sX11 connection,
+ // for example, just kills app's process
+ case XCB_UNMAP_NOTIFY:
+ {
+ break;
+ xcb_unmap_notify_event_t* unmap_notify;
+ unmap_notify = (xcb_unmap_notify_event_t*)xcb_event;
+
+ printf ("unmap notify: window: 0x%06x, event: 0x%06x.\n", unmap_notify->window,
+ unmap_notify->event);
+
+ hide_wnd (unmap_notify->window);
+
+ // check does window still exist (UnmapNotify can be sent just before DestroyNotify,
+ // so we must not call composite_all() for XCB_UNMAP_NOTIFY handler, we will call it
+ // for XCB_DESTROY_NOTIFY handler)
+ xcb_grab_server (xcb_dpy);
+
+ ret = check_wnd_existing (unmap_notify->window);
+ if (ret < 0)
+ {
+ printf (" window: 0x%06x still doesn't exist :-).\n", unmap_notify->window);
+ xcb_ungrab_server (xcb_dpy);
+ break;
+ }
+
+ // after window was hidden we must composite all, currently...
+ composite_all ();
+
+ // TODO: it is very expensive way...
+ xcb_ungrab_server (xcb_dpy);
+ }
+ break;
+
+ // when X11 client destroys window, via xcb_destroy_window or just close sX11 connection,
+ // for example, just kills app's process
+ case XCB_DESTROY_NOTIFY:
+ {
+ xcb_destroy_notify_event_t* destroy_notify;
+ destroy_notify = (xcb_destroy_notify_event_t*)xcb_event;
+
+ printf ("destroy notify: window: 0x%06x, event: 0x%06x.\n", destroy_notify->window,
+ destroy_notify->event);
+
+ ungrab_wnd (destroy_notify->window);
+
+ // after window was ungrabbed we must composite all, currently...
+ composite_all ();
+ }
+ break;
+
+ default:
+ {
+ // handle damage events
+ // when client app has finished draw operations we receive damage notification
+ if (xcb_event->response_type == wm.damage_ext->first_event + XCB_DAMAGE_NOTIFY)
+ {
+ xcb_damage_notify_event_t* damage_ev;
+ damage_ev = (xcb_damage_notify_event_t*)xcb_event;
+
+ DEBUG_OUT ("damage notification for wnd: 0x%06x, area: %hd %hd [%hux%hu], geo: %hd %hd [%hux%hu].\n", damage_ev->drawable,
+ damage_ev->area.x, damage_ev->area.y, damage_ev->area.width, damage_ev->area.height,
+ damage_ev->geometry.x, damage_ev->geometry.y, damage_ev->geometry.width, damage_ev->geometry.height);
+
+ cookie = xcb_damage_subtract_checked (xcb_dpy, damage_ev->damage, XCB_NONE, XCB_NONE);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_damage_subtract call.\n");
+ free(xcb_error);
+ }
+
+ // we do composite only for window damage event has received for which
+ composite_drawable (damage_ev->drawable);
+ }
+ }
+ }
+}
+
+// find all windows, which are root window's childrens and print information about them
+// return -1 if fail
+//========================================================================
+static int
+find_all_window_ids (xcb_window_t** wnds_list, u_int32_t* wnds_amount)
+{
+ xcb_query_tree_cookie_t q_c;
+ xcb_query_tree_reply_t* q_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+ int i;
+
+ if (!wnds_list || !wnds_amount) return -1;
+
+ q_c = xcb_query_tree (xcb_dpy, xcb_screen->root);
+ q_r = xcb_query_tree_reply (xcb_dpy, q_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while query_tree call.\n");
+ return -1;
+ }
+
+ // don't free *wnds_list, it points on no dynamic allocated memory
+ *wnds_list = xcb_query_tree_children (q_r);
+ *wnds_amount = xcb_query_tree_children_length (q_r);
+
+ // print info -----------------------------------
+
+ printf (" RootWindow: 0x%06x.\n", xcb_screen->root);
+ printf (" root_return: 0x%06x.\n", q_r->root);
+ printf (" parent_return: 0x%06x.\n", q_r->parent);
+ printf (" nchildren_return: %u.\n", *wnds_amount);
+
+ free (q_r);
+
+ printf ("\nnumber window's id window's name\n");
+ printf (" 0 0x%06x root\n", xcb_screen->root);
+
+ for (i = 0; i < *wnds_amount; i++)
+ {
+ xcb_get_property_cookie_t gp_c;
+ xcb_get_property_reply_t* gp_r;
+ char* window_name;
+
+ gp_c = xcb_get_property (xcb_dpy, 0, (*wnds_list)[i], XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 0);
+ gp_r = xcb_get_property_reply (xcb_dpy, gp_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ window_name = NULL;
+ }
+ else
+ {
+ if(!xcb_get_property_value_length (gp_r))
+ window_name = NULL;
+ else
+ window_name = xcb_get_property_value (gp_r);
+
+ free (gp_r);
+ }
+
+ printf (" %d ", i + 1);
+ printf (" 0x%06x ", (*wnds_list)[i]);
+ printf (" %s\n", window_name);
+
+ if (window_name)
+ free (window_name);
+
+ }
+ printf ("\n");
+
+ return 0;
+}
+
+// fill ai structure by using information about external windows
+// ask X server to give us messages, which will be generated to external
+// windows (for interception them)
+//==================================================================
+static int
+grab_external_wnds (void)
+{
+ xcb_window_t* wnds_list = NULL;
+ uint32_t wnds_amount = 0;
+ int i, res;
+
+ xcb_window_t* wnds_list_cp = NULL;
+
+ printf ("\ngrab root window:\n ");
+
+ // add root window to list of grabbed windows
+ grab_wnd (xcb_screen->root);
+
+ printf ("grab all external windows:\n");
+
+ res = find_all_window_ids (&wnds_list, &wnds_amount);
+ if (res < 0) return -1;
+
+ // if no external windows are on this time we don't grab them :-)
+ if (!wnds_amount) return 0;
+
+ // we must do copy, because wnds_list points to array
+ // allocated inside xcb, so it will be rewritten on next xcb_query_tree call
+ // we mustn't free memory wnds_list points into, because it is not dynamic
+ // allocated memory
+ wnds_list_cp = (xcb_window_t*)calloc (wnds_amount, sizeof(xcb_window_t));
+ memcpy (wnds_list_cp, wnds_list, wnds_amount * sizeof(xcb_window_t));
+
+ for (i = 0; i < wnds_amount; i++)
+ grab_wnd (wnds_list_cp[i]);
+
+ free (wnds_list_cp);
+
+ return 0;
+}
+
+// prepare HWC extension for use
+// return -1 if fail, otherwise amount of available layers(planes)
+//========================================================================
+static int
+hwc_ext_prepare (xcb_connection_t* c, xcb_screen_t* screen)
+{
+ xcb_hwc_query_version_cookie_t q_c;
+ xcb_hwc_query_version_reply_t* q_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ xcb_hwc_open_cookie_t o_c;
+ xcb_hwc_open_reply_t* o_r;
+
+ xcb_void_cookie_t s_i_c;
+ uint32_t max_layer;
+
+ if (!c || !screen) return -1;
+
+ // TODO: define XCB_HWC_MAJOR_VERSION is set to 1, but current version of hwc extension,
+ // supported by X server is 2
+ q_c = xcb_hwc_query_version (c, 2, XCB_HWC_MINOR_VERSION);
+ q_r = xcb_hwc_query_version_reply (c, q_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while HWC query_version call.\n");
+ return -1;
+ }
+ else if (q_r->major_version != 2 || q_r->minor_version != XCB_HWC_MINOR_VERSION)
+ {
+ printf ("HWC extension versions mismatch (between server: %u.%u and client: %u.%u).\n",
+ q_r->major_version, q_r->minor_version, XCB_HWC_MAJOR_VERSION, XCB_HWC_MINOR_VERSION);
+ free (q_r);
+ return -1;
+ }
+
+ printf ("HWC extension: %d.%d.\n", q_r->major_version, q_r->minor_version);
+
+ free (q_r);
+
+ o_c = xcb_hwc_open (c, 0);
+ o_r = xcb_hwc_open_reply (c, o_c, &xcb_errors);
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while HWC open call.\n");
+ return -1;
+ }
+
+ max_layer = o_r->maxlayer;
+ free (o_r);
+
+ printf (" hwc_open: maximum amount of hardware layers available to use: %u.\n", max_layer);
+
+ // TODO: no define for mask for this call (third parameter),
+ // and I'm not sure about second parameter
+ s_i_c = xcb_hwc_select_input_checked (c, screen->root, 1);
+
+ if ((xcb_errors = xcb_request_check (c, s_i_c)))
+ {
+ printf ("error while xcb_hwc_select_input call.\n");
+ free(xcb_errors);
+ return -1;
+ }
+
+ return max_layer;
+}
+
+// prepare DAMAGE extension for use
+// return NULL if fail
+//==================================================================
+static const xcb_query_extension_reply_t*
+damage_ext_prepare (xcb_connection_t* c)
+{
+ xcb_damage_query_version_cookie_t q_c;
+ xcb_damage_query_version_reply_t* q_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+ const xcb_query_extension_reply_t* damage_ext;
+
+ if (!c) return NULL;
+
+ // for determine damage's events
+ damage_ext = xcb_get_extension_data (c, &xcb_damage_id);
+ if (!damage_ext)
+ {
+ printf ("error while xcb_get_extension_data call.\n");
+ return NULL;
+ }
+
+ q_c = xcb_damage_query_version (c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
+ q_r = xcb_damage_query_version_reply (c, q_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while DAMAGE extension query_version call.\n");
+ return NULL;
+ }
+ else if (q_r->major_version != XCB_DAMAGE_MAJOR_VERSION || q_r->minor_version != XCB_DAMAGE_MINOR_VERSION)
+ {
+ printf ("DAMAGE extension versions mismatch (between server: %u.%u and client: %u.%u).\n",
+ q_r->major_version, q_r->minor_version, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
+ free (q_r);
+ return NULL;
+ }
+
+ printf ("DAMAGE extension: %d.%d.\n", q_r->major_version, q_r->minor_version);
+ printf (" major_opcode: %hhu, first_event: %hhu, first_erorr: %hhu.\n",
+ damage_ext->major_opcode, damage_ext->first_event, damage_ext->first_error);
+
+ free (q_r);
+
+ return damage_ext;
+}
+
+// prepare COMPOSITE extension for use
+// return -1 if fail
+//========================================================================
+static int
+composite_ext_prepare (xcb_connection_t* c)
+{
+ xcb_composite_query_version_cookie_t q_c;
+ xcb_composite_query_version_reply_t* q_r;
+ xcb_generic_error_t* xcb_errors = NULL;
+
+ if (!c) return -1;
+
+ q_c = xcb_composite_query_version (c, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION);
+ q_r = xcb_composite_query_version_reply (c, q_c, &xcb_errors);
+
+ if (xcb_errors)
+ {
+ free (xcb_errors);
+ printf ("error while COMPOSITE query_version call.\n");
+ return -1;
+ }
+ else if (q_r->major_version != XCB_COMPOSITE_MAJOR_VERSION || q_r->minor_version != XCB_COMPOSITE_MINOR_VERSION)
+ {
+ printf ("COMPOSITE extension versions mismatch (between server: %u.%u and client: %u.%u).\n",
+ q_r->major_version, q_r->minor_version, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION);
+ free (q_r);
+ return -1;
+ }
+
+ printf ("COMPOSITE extension: %d.%d.\n", q_r->major_version, q_r->minor_version);
+
+ free (q_r);
+
+ return 0;
+}
+
+// create root_buffer to composite on it contents of windows (to avoid flickering)
+// after all window contents will be on root_buffer composite it to root window to show
+// also we ask X server to send us MapRequest, ConfigureRequest, CirculateRequest and
+// ResizeRequest events for all root's children.
+// (these request are sent when somebody try to map, reconfigure or resize root's children
+// window, and we can decide what to do whith this request.
+// for example: when somebody issues MapRequest via xcb_map_window, real map isn't occured, but
+// MapRequest event is sent us and we can properly react on it.)
+// also fill root_buffer pixmap and root window
+// return -1 if fail
+//========================================================================
+static int
+prepare_root (void)
+{
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t* xcb_error;
+
+ uint32_t value_mask;
+ uint32_t value_list[1];
+
+ wm.root_buffer = xcb_generate_id (xcb_dpy);
+ cookie = xcb_create_pixmap_checked (xcb_dpy, xcb_screen->root_depth, wm.root_buffer, xcb_screen->root,
+ xcb_screen->width_in_pixels, xcb_screen->height_in_pixels);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_create_pixmap call.\n");
+ free(xcb_error);
+ return -1;
+ }
+
+ value_mask = XCB_CW_EVENT_MASK;
+ value_list[0] = XCB_EVENT_MASK_RESIZE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
+
+ // this call must be done after any windows create call !!!
+ // also we ask X server to send us MapRequest, ConfigureRequest, CirculateRequest and
+ // ResizeRequest events for all root's children.
+ cookie = xcb_change_window_attributes_checked (xcb_dpy, xcb_screen->root, value_mask, value_list);
+ if ((xcb_error = xcb_request_check (xcb_dpy, cookie)))
+ {
+ printf ("error while xcb_change_window_attributes call.\n");
+ free(xcb_error);
+ return -1;
+ }
+
+ return 0;
+}
+
+//
+//========================================================================
+static xcb_gcontext_t
+create_gc (xcb_connection_t* c, xcb_screen_t* screen, uint32_t foreground)
+{
+ xcb_gcontext_t gc;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t* error;
+ uint32_t value[2];
+
+ if (!c || !screen)
+ {
+ printf ("error while create_gc call.\n");
+ exit (EXIT_FAILURE);
+ }
+
+ value[0] = XCB_GX_COPY;
+ value[1] = foreground;
+
+ gc = xcb_generate_id (c);
+ cookie = xcb_create_gc_checked (c, gc, screen->root, XCB_GC_FUNCTION | XCB_GC_FOREGROUND, value);
+ xcb_flush (c);
+
+ if ((error = xcb_request_check (c, cookie)))
+ {
+ printf ("error while xcb_create_gc call.\n");
+ free(error);
+ exit (EXIT_FAILURE);
+ }
+
+ return gc;
+}
+
+//
+//==================================================================
+static void
+usage (char *argv)
+{
+ printf ("This application is simple sw/hw compositor manager. It can be used to test "
+ "ddx's side of hwc, dri2 and dri3/present extensions.\n"
+ "You can launch clients apps and then launch this compositor manager, or you "
+ "can launch firstly compositor manager and then\nclient apps.\n\n");
+
+ printf ("%s usage : \n", argv);
+ printf (" %s (options) (parameters)\n", argv);
+ printf (" (options) :\n");
+ printf (" -no_hw : don't use hw layers to composition (only software composition)\n");
+}
+
+// parse command line
+// returns -1 if failed
+//==================================================================
+static int
+check_options (int argc, char *argv[])
+{
+ int j = 0;
+
+ if (!argv) return -1;
+
+ // check if we want to know how use this app
+ for (j = 1; j < argc; j++)
+ {
+ if (!strcmp (argv[j], "--help"))
+ {
+ usage (argv[0]);
+ return -1;
+ }
+ }
+
+ // check if we don't want to use hardware layers
+ for (j = 1; j < argc; j++)
+ {
+ if (!strcmp (argv[j], "--no_hw"))
+ {
+ wm.cmd_opts.not_use_hw_layers = 1; // we will do only software composition
+ break;
+ }
+ }
+
+ return 0;
+}
+
+//
+//========================================================================
+int
+main (int argc, char *argv[])
+{
+ xcb_generic_event_t* xcb_event = NULL;
+ int res;
+
+ // parse cmdline
+ res = check_options (argc, argv);
+ if (res < 0) goto fail;
+
+ // open the connection to the X server
+ xcb_dpy = xcb_connect (NULL, NULL);
+ res = xcb_connection_has_error (xcb_dpy);
+ if (res > 0)
+ {
+ printf ("error while open X display.\n");
+ goto fail;
+ }
+
+ // get first screen of display
+ xcb_screen = xcb_setup_roots_iterator (xcb_get_setup (xcb_dpy)).data;
+ if (!xcb_screen)
+ {
+ printf ("error while obtain first screen of X display.\n");
+ goto fail;
+ }
+
+ wm.gc_soft_composite = create_gc (xcb_dpy, xcb_screen, 0x00);
+ wm.gc_fill_root_buf = create_gc (xcb_dpy, xcb_screen, 0x555555);
+
+ res = prepare_root ();
+ if (res < 0) goto fail;
+
+ // prepare extensions needed for this window manager
+ res = composite_ext_prepare (xcb_dpy);
+ if (res < 0) goto fail;
+
+ wm.damage_ext = damage_ext_prepare (xcb_dpy);
+ if (!wm.damage_ext) goto fail;
+
+ res = hwc_ext_prepare (xcb_dpy, xcb_screen);
+ if (res < 0) goto fail;
+
+ wm.max_amount_hw_layers = res;
+
+ // if we haven't available hardware layers, we will use only software compositing
+ if (wm.max_amount_hw_layers)
+ wm.hwc_info = calloc (wm.max_amount_hw_layers, sizeof(xcb_hwc_draw_info_t));
+
+ // init list of grabbed windows
+ list_init (&wm.wnds_list_head);
+
+ // grab external windows
+ res = grab_external_wnds ();
+ if (res < 0) goto fail;
+
+ // in this point we have list of grabbed windows, arranged by stack order position,
+ // so we can do compositing (software or hardware depend on not_use_hw_layers flag and amount of
+ // available hardware layers)
+
+ composite_all ();
+
+ // events handle loop
+
+ while (1)
+ {
+ xcb_flush (xcb_dpy);
+ xcb_event = xcb_wait_for_event (xcb_dpy);
+ if (!xcb_event)
+ {
+ printf ("event returned by xcb_wait_for_event is NULL.\n");
+ goto fail;
+ }
+
+ DEBUG_OUT ("event: %hhu.\n", xcb_event->response_type);
+
+ handle_x11_events (xcb_event);
+ free (xcb_event);
+ }
+
+fail:
+ printf ("abnormal exit.\n");
+
+ if (wm.gc_fill_root_buf)
+ xcb_free_gc (xcb_dpy, wm.gc_fill_root_buf);
+
+ if (wm.gc_soft_composite)
+ xcb_free_gc (xcb_dpy, wm.gc_soft_composite);
+
+ if (xcb_dpy)
+ xcb_disconnect (xcb_dpy);
+
+ return 1;
+}
diff --git a/tests/functional/hwc_test/hwc_sample/hwc-sample.h b/tests/functional/hwc_test/hwc_sample/hwc-sample.h
new file mode 100644
index 0000000..f41a302
--- /dev/null
+++ b/tests/functional/hwc_test/hwc_sample/hwc-sample.h
@@ -0,0 +1,69 @@
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+//#include <X11/X.h>
+#include <X11/Xlib.h>
+//#include <X11/Xutil.h>
+//#include <X11/Xatom.h>
+//#include <X11/Xos.h>
+//#include <X11/cursorfont.h>
+//#include <X11/extensions/hwc.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#define AMOUNT_OF_PLANES 4
+
+// hwc_set values:
+// 1 - set pixmap(s)
+// 2 - set window(s) (internal or external)
+// 3 - loop
+// 4 - move window
+// 5 - resize window
+
+typedef struct _ThreadData
+{
+ //Pixmap pixmap;
+ int width;
+ int height;
+
+ pthread_t thread;
+} ThreadData;
+
+struct app_info
+{
+ int maxLayer;
+ int count;
+ int wnd_to_change;
+ //Drawable draws[AMOUNT_OF_PLANES];
+ //XRectangle dst[AMOUNT_OF_PLANES];
+ //XRectangle src[AMOUNT_OF_PLANES];
+ int hwc_set; // picked work mode
+ int use_root;
+ int hwc_unset;
+ int hwc_loop;
+ int redirect; // whether X server does redirect to each created window or not
+ int not_use_hw_layers; // whether we want to use hardware layers to make compositing or not
+ int set_all_ext_wnds; // whether we want to use all existing external windows or not
+ int set_spec_ext_wnds; // only specified wnds
+ int num_of_ext_wnds; // amount of all/specified external windows to want to set
+ //Window* ext_wnd_ids; // array of specified external windows id's
+};
+
+extern struct app_info ai;
+//extern Window root, change_size, move_btn, change_stack_order;
+extern int wd1, ht1;
+extern int dispsize_width, dispsize_height;
+
+extern void* thread1_hwcsample (void *data);
+void change_focus (void);
+void hwc_set (void);
+void hwc_movew (void);
+void hwc_resizew (void);
+
+int launch_clients (char* clients[], int num_of_clients);
+
+#endif
diff --git a/tests/functional/hwc_test/hwc_sample/hwc-thread.c b/tests/functional/hwc_test/hwc_sample/hwc-thread.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/functional/hwc_test/hwc_sample/hwc-thread.c
diff --git a/tests/functional/hwc_test/hwc_sample/list.h b/tests/functional/hwc_test/hwc_sample/list.h
new file mode 100644
index 0000000..51a841d
--- /dev/null
+++ b/tests/functional/hwc_test/hwc_sample/list.h
@@ -0,0 +1,24 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+#include <X11/X.h>
+#include <xorg/list.h>
+
+// just because without xorg_ prefix macros look more pretty
+// Note: this isn't bridge between linux kernel list and xorg list.
+#define list_head xorg_list
+#define list_entry xorg_list_entry
+#define list_add xorg_list_add
+#define list_append xorg_list_append
+#define list_del xorg_list_del
+#define list_for_each_entry xorg_list_for_each_entry
+
+// be carefully, this macros checked only in gdb
+#define list_for_each_prev_entry(pos, head, member) \
+ for (pos = __container_of((head)->prev, pos, member);\
+ &pos->member != (head);\
+ pos = __container_of(pos->member.prev, pos, member))
+
+#define list_init xorg_list_init
+
+#endif
diff --git a/tests/functional/hwc_test/launch.sh b/tests/functional/hwc_test/launch.sh
new file mode 100755
index 0000000..9009e96
--- /dev/null
+++ b/tests/functional/hwc_test/launch.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# restart X server without Enlightenment
+echo -n "restart X server..."
+
+pkill X
+startx --only 2> /dev/null
+sleep 2
+
+echo " ok."
+
+echo -n "close all windows..."
+
+# sometimes, after startx --only, we have few strange windows,
+# we must close them to proper work of hwc-sample and square_bubbles
+square_bubbles -cls > /dev/null
+
+echo " ok."
+
+echo "start apps:"
+
+snowflake -geo 200x200 100 100&
+snowflake -geo 200x200 200 200&
+snowflake -geo 200x200 500 500&
+
+echo " snowflake -geo 200x200 100 100"
+echo " snowflake -geo 200x200 200 200"
+echo " snowflake -geo 200x200 500 500"
+
+sleep 1
+
+echo -n "start square_bubbles..."
+square_bubbles -m -s > /dev/null &
+echo " ok."
+
+echo " sleep 15 sec"
+sleep 15
+
+echo -n "start hwc_sample..."
+hwc_sample -redir -setr > /dev/null &
+echo " ok."
+
+echo " sleep 15 sec"
+sleep 15
+
+pkill square_bubbles
+pkill hwc_sample
+pkill snowflake
diff --git a/tests/functional/hwc_test/snowflake.c b/tests/functional/hwc_test/snowflake.c
new file mode 100644
index 0000000..ee1fee0
--- /dev/null
+++ b/tests/functional/hwc_test/snowflake.c
@@ -0,0 +1,327 @@
+/**************************************************************************
+
+ rotated snowflake
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Roman Peresipkyn <r.peresipkyn@samsung.com>
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implements rotated snowflake for using in semiautomatic tests for
+// keep safe ddx driver devoloping
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+
+#include "aux_apps.h"
+#include "dri2_dri3.h"
+
+
+#define DEPTH (24)
+
+#define ROTATE_SPEED (-180.0) // degrees per second
+#define MARGIN (10)
+#define SNOWFLAKE_POINTS (36)
+
+typedef struct point_t
+{
+ double x;
+ double y;
+} point;
+
+typedef struct matrix_t
+{
+ double a1;
+ double a2;
+ double b1;
+ double b2;
+} matrix;
+
+xcb_connection_t* dpy = NULL;
+xcb_screen_t* screen = NULL;
+xcb_rectangle_t wnd_pos = {100, 100, 150, 150};
+
+// work behavior flags: (see aux_apps.c for details)
+
+// mode of work (dri2/dri3+present)
+int mode = DRI3_PRESENT_MODE; // by default dri3 + present will be used
+int stop;
+double rotate_speed = ROTATE_SPEED;
+uint32_t present_bufs = 3;
+uint32_t swap_interval = 1;
+uint32_t root_parent = 1;
+
+// matrix for rotation
+matrix current_rot;
+
+// our mesh
+const point snowflake[SNOWFLAKE_POINTS] = {
+ // up-down
+ {0.0, -4.0 * 0.25}, {0.0, 4.0 * 0.25},
+
+ // left-right
+ {-4.0 * 0.25, 0.0}, {4.0 * 0.25, 0.0},
+
+ // upleft-downright
+ {-3.0 * 0.25, 3.0 * 0.25}, {3.0 * 0.25, -3.0 * 0.25},
+
+ // upright-downleft
+ {3.0 * 0.25, 3.0 * 0.25}, {-3.0 * 0.25, -3.0 * 0.25},
+
+ // branch up-right
+ {2.0 * 0.25, 3.0 * 0.25}, {2.0 * 0.25, 2.0 * 0.25}, {3.0 * 0.25, 2.0 * 0.25},
+
+ // branch up
+ {-1.0 * 0.25, 4.0 * 0.25}, {0.0, 3.0 * 0.25}, {1.0 * 0.25, 4.0 * 0.25},
+
+ // branch up-left
+ {-2.0 * 0.25, 3.0 * 0.25}, {-2.0 * 0.25, 2.0 * 0.25}, {-3.0 * 0.25, 2.0 * 0.25},
+
+ // branch left
+ {-4.0 * 0.25, 1.0 * 0.25}, {-3.0 * 0.25, 0.0 * 0.25}, {-4.0 * 0.25, -1.0 * 0.25},
+
+ // branch down-left
+ {-3.0 * 0.25, -2.0 * 0.25}, {-2.0 * 0.25, -2.0 * 0.25}, {-2.0 * 0.25, -3.0 * 0.25},
+
+ // branch down
+ {-1.0 * 0.25, -4.0 * 0.25}, {0.0 * 0.25, -3.0 * 0.25}, {1.0 * 0.25, -4.0 * 0.25},
+
+ // branch down-right
+ {2.0 * 0.25, -3.0 * 0.25}, {2.0 * 0.25, -2.0 * 0.25}, {3.0 * 0.25, -2.0 * 0.25},
+
+ // branch right
+ {4.0 * 0.25, -1.0 * 0.25}, {3.0 * 0.25, 0.0 * 0.25}, {4.0 * 0.25, 1.0 * 0.25},
+
+ //
+ {-1.5 * 0.25, 0.0 * 0.25}, {0.0 * 0.25, 1.5 * 0.25}, {1.5 * 0.25, 0.0 * 0.25}, {0.0 * 0.25, -1.5 * 0.25}
+};
+
+// calculate rotation matrix 'mtrx' for rotate at angle 'alpha'
+//===================================================================
+inline void
+set_rotation_matrix (double alpha, matrix* mtrx)
+{
+ mtrx->a1 = cos (alpha);
+ mtrx->a2 = -sin (alpha);
+ mtrx->b1 = -mtrx->a2;
+ mtrx->b2 = mtrx->a1;
+}
+
+// make fps-independent rotation
+//===================================================================
+void
+rotate (void)
+{
+ #define REFRESHE_TIME (16.0) // in ms
+
+ static double angle;
+ struct timespec current;
+ static struct timespec prev;
+ double time_diff;
+
+ clock_gettime (CLOCK_REALTIME, &current);
+
+ // get difference in nanoseconds
+ time_diff = (double)( ( current.tv_sec - prev.tv_sec ) * 1000000000 +
+ ( current.tv_nsec - prev.tv_nsec ) );
+
+ if (time_diff / 1000000.0 > REFRESHE_TIME)
+ {
+ prev = current;
+
+ angle += rotate_speed * 2.0 * M_PI / 360.0 * (REFRESHE_TIME/1000.0);
+
+ set_rotation_matrix (angle, &current_rot);
+ }
+
+ #undef REFRESHE_TIME
+}
+
+// direct accessing memory clear callback
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_clear (const bo_t* bo_e)
+{
+ xcb_rectangle_t rect;
+
+ if (!bo_e)
+ {
+ printf ("raw_clear: invalid parameters.\n");
+ return;
+ }
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = bo_e->width;
+ rect.height = bo_e->height;
+
+ // simple draw black rectangle with size as window has
+ raw_fill_rect (bo_e, 1, &rect, 0xff000000 | screen->black_pixel);
+}
+
+// direct accessing memory draw callback (snowflake drawing)
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_draw (const bo_t* bo_e)
+{
+ int i;
+ point temp[SNOWFLAKE_POINTS];
+ xcb_point_t xcb_points[SNOWFLAKE_POINTS + 1];
+
+ if (!bo_e)
+ {
+ printf ("raw_draw: invalid parameters.\n");
+ return;
+ }
+
+ for (i = 0; i < SNOWFLAKE_POINTS; i++)
+ {
+ // calculate point's coords (in OpenGL world) of mesh taking in account
+ // current rotate angle (current_rot matrix)
+ temp[i].x = snowflake[i].x * current_rot.a1 + snowflake[i].y * current_rot.a2;
+ temp[i].y = snowflake[i].x * current_rot.b1 + snowflake[i].y * current_rot.b2;
+
+ // convert coordinates into X world
+ xcb_points[i].x = MARGIN + (1.0 / 2.0) * (temp[i].x + 1.0) * (bo_e->width - 2 * MARGIN);
+ xcb_points[i].y = MARGIN + (-1.0 / 2.0) * (temp[i].y - 1.0) * (bo_e->height - 2 * MARGIN);
+ }
+
+ raw_draw_line (bo_e, 2, &xcb_points[0], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 2, &xcb_points[2], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 2, &xcb_points[4], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 2, &xcb_points[6], 0xff000000 | screen->white_pixel);
+
+ raw_draw_line (bo_e, 3, &xcb_points[8], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[11], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[14], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[17], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[20], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[23], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[26], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[29], 0xff000000 | screen->white_pixel);
+ raw_draw_line (bo_e, 3, &xcb_points[29], 0xff000000 | screen->white_pixel);
+
+ xcb_points[SNOWFLAKE_POINTS] = xcb_points[32]; // loop
+ raw_draw_line (bo_e, 5, &xcb_points[32], screen->white_pixel);
+
+ if (stop) return;
+
+ rotate ();
+}
+
+// parse command line
+//========================================================================
+void
+cmd_parse_inner (int argc, char* const argv[])
+{
+ int i;
+
+ if (argc < 2) return;
+
+ // if we want to set rotate speed.
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-rot_speed") && (argc - i > 1))
+ {
+ sscanf (argv[i + 1], "%lf", &rotate_speed);
+ break;
+ }
+ }
+
+ // call default cl parser to parse another arguments
+ cmd_parse (argc, argv);
+ }
+
+//
+//===================================================================
+int
+main (int argc, char** argv)
+{
+ xcb_generic_event_t* event = NULL;
+ xcb_window_t main_wnd;
+ draw_funcs_t draw_func;
+ dri2_dri3_params_t params;
+ int res;
+
+ cmd_parse_inner (argc, argv);
+
+ dpy = xcb_connect (NULL, NULL);
+
+ // get first screen of display
+ screen = xcb_setup_roots_iterator (xcb_get_setup (dpy)).data;
+
+ main_wnd = create_window (dpy, 0xff, root_parent, "rotated snowflake");
+
+ draw_func.raw_clear = raw_clear;
+ draw_func.raw_draw = raw_draw;
+ draw_func.xcb_clear = NULL;
+ draw_func.xcb_draw = NULL;
+
+ params.num_of_bufs = present_bufs;
+ params.swap_interval = swap_interval;
+
+ // inside init_dri2_dri3 new thread, responsible for dri2/dri3/present events
+ // handling, will be created
+ res = init_dri2_dri3 (dpy, &draw_func, mode, main_wnd, &params);
+ if (res)
+ {
+ printf ("init_dri2_dri3: %s.\n", get_last_error());
+ exit (1);
+ }
+
+ printf ("before xcb loop.\n");
+
+ while (1)
+ {
+ xcb_flush (dpy);
+ event = xcb_wait_for_event (dpy);
+ if (!event) break;
+
+ switch (event->response_type)
+ {
+ case XCB_EXPOSE:
+ DEBUG_OUT ("XCB_MAP_WINDOW\n");
+ break;
+
+ // if we are notified by XCB_BUTTON_PRESS event, we start/stop
+ // to change our frames, simple draw the same thing
+ case XCB_BUTTON_PRESS:
+ stop ^= 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/functional/hwc_test/square_bubbles/square_bubbles.c b/tests/functional/hwc_test/square_bubbles/square_bubbles.c
new file mode 100755
index 0000000..f454f0c
--- /dev/null
+++ b/tests/functional/hwc_test/square_bubbles/square_bubbles.c
@@ -0,0 +1,647 @@
+/**************************************************************************
+
+ square_bubbles
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// This file implements window's manipulation like side-bump bubbles
+// through Xlib. This app can be used with hwc-sample to pretty view of HWC work.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <math.h>
+#include <fcntl.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#define _DEBUG 1
+#define MAX_WNDS (3) // apart root window
+#define SCREEN_WIDTH (720)
+#define SCREEN_HEIGHT (1280)
+#define ODD_INTERVAL (10) // interval of wnd's size odd changing (in seconds)
+#define RESIZE_SPEED (0.8) // radians per second
+
+typedef enum Direct_t
+{
+ UP_RIGHT,
+ DOWN_RIGHT,
+ UP_LEFT,
+ DOWN_LEFT
+} Direct;
+
+typedef struct bubbles_t
+{
+ XRectangle curr_geometry;
+ XRectangle first_geometry;
+ u_int32_t x_range;
+ u_int32_t y_range;
+ Window id;
+ Direct direct;
+ double angle;
+} bubbles;
+
+// Xsever specific variables
+Display* dpy;
+Window root;
+int depth;
+int screen;
+
+// information about all external windows (with names)
+Window* root_childrens;
+unsigned int nchildrens;
+
+bubbles square_bubbles[MAX_WNDS];
+unsigned int real_cnt;
+
+// we can only close all windows by pass '-cls' to this app
+int cls; // whether we need to close all windows or not
+
+int move; // whether we need to move all windows or not
+int change_size; // whether we need to change size of all windows or not
+int delay = 50; // delay between bubbles's position&size calculation in ms
+
+int debug = 1; // whether we want to print or not
+
+int all_wnds = 1; // whether we want to manipulate all windows or not
+int odd_size; // whether we want to use odd sizes of windows
+
+void cmd_parse (int argc, char* argv[]);
+int find_all_window_ids (void);
+XRectangle get_wnd_geometry (Window win_id);
+void shift_wnd (bubbles* s_b);
+
+// this function returns randomized 32 bit unsigned value
+// in order to bypass prevent (static analizator) warning (don't use rand() function)
+//========================================================================
+u_int32_t
+hand_made_rand (void)
+{
+ int ret, fd;
+ u_int32_t rand_number;
+
+ fd = open ("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ return 11; // why 11, why not?
+
+ // simple read 4 random bytes from /dev/urandom
+ ret = read (fd, &rand_number, sizeof(u_int32_t));
+ if (ret < 0 || ret != sizeof(rand_number))
+ rand_number = 11; // why 11, why not?
+
+ close (fd);
+
+ return rand_number;
+}
+
+//========================================================================
+int
+main (int argc, char* argv[])
+{
+ int i;
+
+ cmd_parse (argc, argv);
+
+ if (!change_size && !move)
+ {
+ printf ("nothing to do, specify what you want (i.e: square_bubbles -m -s).\n");
+ return 1;
+ }
+
+ // delay is passed in ms, but usleep requires delay in mcs
+ delay *= 1000;
+
+ dpy = XOpenDisplay ( NULL);
+
+ if (!dpy)
+ {
+ printf ("error while XOpenDisplay call.\n");
+ return 1;
+ }
+
+ root = DefaultRootWindow(dpy);
+ screen = DefaultScreen(dpy);
+ depth = DefaultDepth(dpy, screen);
+
+ if (all_wnds)
+ {
+ // allocate memory for root_childrens[] array
+ if (find_all_window_ids ())
+ {
+ XCloseDisplay (dpy);
+ return 0;
+ }
+ }
+
+ // we can supply up to MAX_WNDS windows only
+ real_cnt = nchildrens <= MAX_WNDS ? nchildrens : MAX_WNDS;
+
+ if (!real_cnt)
+ {
+ printf ("no windows to manipulate.\n");
+ XCloseDisplay (dpy);
+ return 0;
+ }
+
+ // prior initialization
+ for (i = 0; i < real_cnt; i++)
+ {
+ square_bubbles[i].id = root_childrens[i];
+ square_bubbles[i].curr_geometry = get_wnd_geometry (root_childrens[i]);
+ square_bubbles[i].direct = hand_made_rand () % 4;
+
+ memcpy (&square_bubbles[i].first_geometry, &square_bubbles[i].curr_geometry,
+ sizeof(square_bubbles[i].first_geometry));
+ square_bubbles[i].x_range = square_bubbles[i].first_geometry.width / 4;
+ square_bubbles[i].y_range = square_bubbles[i].first_geometry.height / 4;
+ }
+
+ while (1)
+ {
+ for (i = 0; i < real_cnt; i++)
+ {
+ shift_wnd (&square_bubbles[i]);
+
+ XMoveResizeWindow (dpy, square_bubbles[i].id, square_bubbles[i].curr_geometry.x,
+ square_bubbles[i].curr_geometry.y, square_bubbles[i].curr_geometry.width,
+ square_bubbles[i].curr_geometry.height);
+
+#ifdef _DEBUG
+ printf (" move and resize wnd (id: 0x%06lx) to %d,%d [%dx%d].\n", square_bubbles[i].id,
+ square_bubbles[i].curr_geometry.x, square_bubbles[i].curr_geometry.y,
+ square_bubbles[i].curr_geometry.width, square_bubbles[i].curr_geometry.height);
+#endif
+ }
+ XFlush (dpy);
+ usleep (delay);
+ }
+
+ if (all_wnds)
+ XFree ((void*) root_childrens);
+ else
+ free ((void*) root_childrens);
+
+ XCloseDisplay (dpy);
+
+ return 0;
+}
+
+// parse command line
+//========================================================================
+void
+cmd_parse (int argc, char* argv[])
+{
+ int i;
+
+ if (argc < 2) return;
+
+ // if we want to obtain help
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-help"))
+ {
+ printf ("usage:\n");
+ printf (" -help : print this help.\n");
+ printf (" -cls : close all root's children windows.\n");
+ printf (" -m : move bubbles.\n");
+ printf (" -s : change bubbles's size.\n");
+ printf (" -delay : delay between bubbles's position&size calculation in ms.\n");
+ printf (" -odd : use window's odd sizes.\n");
+ printf ("\n");
+ break;
+ }
+ }
+
+ // if we want to close all windows
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-cls"))
+ {
+ cls = 1;
+ return;
+ }
+ }
+
+ // if we want to move windows
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-m"))
+ {
+ move = 1;
+ break;
+ }
+ }
+
+ // if we want to change windows's size
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-s"))
+ {
+ change_size = 1;
+ break;
+ }
+ }
+
+ // if we want to change delay in ms
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-delay"))
+ {
+ if (i + 1 >= argc)
+ printf ("error while argument parsing. i.e: square_bubbles -m -delay 30\n");
+ else
+ sscanf (argv[i + 1], "%d", &delay);
+ break;
+ }
+ }
+
+ // check if we want to set specified windows
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-set"))
+ {
+ // if we have 'square_bubbles -set'
+ if (i + 1 >= argc)
+ {
+ all_wnds = 1; // set all windows
+ printf ("all named windows will be used.\n");
+ }
+
+ // if we have 'square_bubbles -set wnd_ids'
+ // we simple store all specified numbers (in hex), after '-set' key, as
+ // a window's ids in allocated array (root_childrens[])
+ else
+ {
+ all_wnds = 0; // set specified windows
+ nchildrens = argc - i - 1;
+
+ root_childrens = (Window*) calloc (nchildrens, sizeof(Window));
+
+ while (++i < argc)
+ sscanf (argv[i], "%lx", root_childrens++);
+
+ root_childrens -= nchildrens;
+
+ printf ("these named windows will be used:\n");
+
+ for (i = 0; i < nchildrens; i++)
+ printf (" wnd's id: 0x%06lx.\n", root_childrens[i]);
+ }
+
+ break;
+ }
+ }
+
+ // if we want to use even/odd size switch
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-odd"))
+ {
+ odd_size = 1;
+ break;
+ }
+ }
+}
+
+// find all windows, which are root window's childrens and have names, and
+// print information about them
+//========================================================================
+int
+find_all_window_ids (void)
+{
+ int i;
+ Window root_return;
+ Window parent_return;
+ char* window_name = NULL;
+
+ int j;
+ Window* tmp = NULL;
+
+ // find all windows, which are childrens of root window and store their
+ // id's in 'tmp[] array'
+ if (!XQueryTree (dpy, RootWindow(dpy, screen), &root_return, &parent_return, &tmp, &nchildrens))
+ {
+ printf ("error while first XQueryTree call.\n");
+ return 1;
+ }
+
+ if (cls)
+ {
+ // destroy all windows
+ for (i = 0; i < nchildrens; i++)
+ XDestroyWindow (dpy, tmp[i]);
+
+ XFree ((void*) tmp);
+ return 1;
+ }
+
+ // calculate amount of named windows
+ for (i = 0, j = 0; i < nchildrens; i++)
+ {
+ if (XFetchName (dpy, tmp[i], &window_name))
+ {
+ j++;
+ XFree ((void*) window_name);
+ }
+ }
+
+ root_childrens = calloc (j, sizeof(Window));
+
+ // create array root_childrens[] which consists of wnd's id to named windows only
+ for (i = 0, j = 0; i < nchildrens; i++)
+ {
+ if (XFetchName (dpy, tmp[i], &window_name))
+ {
+ root_childrens[j++] = tmp[i];
+ XFree ((void*) window_name);
+ }
+ }
+
+ nchildrens = j;
+
+ printf (" RootWindow: 0x%06lx.\n", RootWindow(dpy, screen));
+ printf (" root_return: 0x%06lx.\n", root_return);
+ printf (" parent_return: 0x%06lx.\n", parent_return);
+ printf (" nchildren_return: %d.\n", nchildrens);
+
+ printf ("\nnumber window's id window's name\n");
+
+ for (i = 0; i < nchildrens && i < MAX_WNDS; i++)
+ {
+ printf (" %d ", i);
+ printf (" 0x%06lx ", root_childrens[i]);
+
+ XFetchName (dpy, root_childrens[i], &window_name);
+ printf (" %s\n", window_name);
+ XFree ((void*) window_name);
+ }
+ printf ("\n\n");
+
+ XFlush (dpy);
+
+ return 0;
+}
+
+// return geometry of specified, by win_id, window
+//========================================================================
+XRectangle
+get_wnd_geometry (Window win_id)
+{
+ XRectangle geometry;
+ XWindowAttributes win_attr;
+
+ XGetWindowAttributes (dpy, win_id, &win_attr);
+
+ geometry.x = win_attr.x;
+ geometry.y = win_attr.y;
+ geometry.width = win_attr.width;
+ geometry.height = win_attr.height;
+
+ return geometry;
+}
+
+// calculate new coordinates
+//========================================================================
+void
+shift_wnd (bubbles* s_b)
+{
+ short x_step = 5;
+ short y_step = 5;
+ int width;
+ int height;
+
+ // each ODD_INTERVAL seconds we change wnd's size odd mode
+ int up_edge = ODD_INTERVAL * 1E6 / delay;
+ static int cnt_odd;
+ static int even = 1;
+
+ if (!s_b) return;
+
+ if (change_size)
+ {
+ width = s_b->x_range * sin (s_b->angle) + s_b->first_geometry.width;
+ height = s_b->y_range * sin (s_b->angle) + s_b->first_geometry.height;
+
+ // if we want to use odd size of windows (first condition)
+ if ((odd_size) && (cnt_odd++ >= up_edge))
+ {
+ cnt_odd = 0;
+ even ^= 0x01;
+ printf ("even/odd wnd's size changed.\n");
+ }
+
+ // make even w&h
+ if (even)
+ {
+ width &= ~0x01;
+ height &= ~0x01;
+ }
+ // make odd w&h (w&h values is checked in followed code)
+ else
+ {
+ width |= 0x01;
+ height |= 0x01;
+ }
+
+ if ((s_b->curr_geometry.x + width <= (SCREEN_WIDTH - 1))
+ && (s_b->curr_geometry.y + s_b->curr_geometry.height <= (SCREEN_HEIGHT - 1)))
+ {
+ s_b->curr_geometry.width = width;
+ s_b->curr_geometry.height = height;
+ s_b->angle += RESIZE_SPEED * delay * 1E-6;
+ }
+ }
+
+ if (!move) return;
+
+ switch (s_b->direct)
+ {
+ case UP_RIGHT:
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y -= y_step;
+
+ // if bubble has striked in up right corner,
+ // it will be pushed to up_left direct
+
+ // right side bump
+ if (s_b->curr_geometry.x + s_b->curr_geometry.width > (SCREEN_WIDTH - 1))
+ {
+ if (s_b->curr_geometry.y <= 0)
+ {
+ printf ("UP_RIGHT: right side bump\n");
+ s_b->curr_geometry.y = y_step;
+ }
+
+ s_b->direct = UP_LEFT;
+
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y -= y_step;
+ }
+
+ // top side bump
+ else if (s_b->curr_geometry.y < 0)
+ {
+ if (s_b->curr_geometry.x + s_b->curr_geometry.width >= (SCREEN_WIDTH - 1))
+ {
+ printf ("UP_RIGHT: top side bump\n");
+ s_b->curr_geometry.x -= x_step;
+ }
+
+ s_b->direct = DOWN_RIGHT;
+
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y += y_step;
+ }
+ break;
+
+ case DOWN_RIGHT:
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y += y_step;
+
+ // if bubble has striked in bottom right corner,
+ // it will be pushed to down_left direct
+
+ // right side bump
+ if (s_b->curr_geometry.x + s_b->curr_geometry.width > (SCREEN_WIDTH - 1))
+ {
+ if (s_b->curr_geometry.y + s_b->curr_geometry.height >= (SCREEN_HEIGHT - 1))
+ {
+ printf ("DOWN_RIGHT: right side bump\n");
+ s_b->curr_geometry.y = (SCREEN_HEIGHT - 1) - s_b->curr_geometry.height - y_step;
+ }
+
+ s_b->direct = DOWN_LEFT;
+
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y += y_step;
+ }
+
+ // bottom side bump
+ else if (s_b->curr_geometry.y + s_b->curr_geometry.height > (SCREEN_HEIGHT - 1))
+ {
+ if (s_b->curr_geometry.x + s_b->curr_geometry.width >= (SCREEN_WIDTH - 1))
+ {
+ printf ("DOWN_RIGHT: bottom side bump\n");
+ s_b->curr_geometry.x -= x_step;
+ }
+
+ s_b->direct = UP_RIGHT;
+
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y -= y_step;
+ }
+ break;
+
+ case UP_LEFT:
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y -= y_step;
+
+ // if bubble has striked in top left corner,
+ // it will be pushed to up_right direct
+
+ // left side bump
+ if (s_b->curr_geometry.x < 0)
+ {
+ if (s_b->curr_geometry.y <= 0)
+ {
+ printf ("UP_LEFT: left side bump\n");
+ s_b->curr_geometry.y = y_step;
+ }
+
+ s_b->direct = UP_RIGHT;
+
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y -= y_step;
+ }
+
+ // top side bump
+ else if (s_b->curr_geometry.y < 0)
+ {
+ if (s_b->curr_geometry.x <= 0)
+ {
+ printf ("UP_LEFT: top side bump\n");
+ s_b->curr_geometry.x = x_step;
+ }
+
+ s_b->direct = DOWN_LEFT;
+
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y += y_step;
+ }
+ break;
+
+ case DOWN_LEFT:
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y += y_step;
+
+ // if bubble has striked in bottom left corner,
+ // it will be pushed to down_right direct
+
+ // left side bump
+ if (s_b->curr_geometry.x < 0)
+ {
+ if (s_b->curr_geometry.y + s_b->curr_geometry.height >= (SCREEN_HEIGHT - 1))
+ {
+ printf ("DOWN_LEFT: left side bump\n");
+ s_b->curr_geometry.y = (SCREEN_HEIGHT - 1) - s_b->curr_geometry.height - y_step;
+ }
+
+ s_b->direct = DOWN_RIGHT;
+
+ s_b->curr_geometry.x += x_step;
+ s_b->curr_geometry.y += y_step;
+ }
+
+ // bottom side bump
+ else if (s_b->curr_geometry.y + s_b->curr_geometry.height > (SCREEN_HEIGHT - 1))
+ {
+ if (s_b->curr_geometry.x <= 0)
+ {
+ printf ("DOWN_LEFT: bottom side bump\n");
+ s_b->curr_geometry.x = x_step;
+ }
+
+ s_b->direct = UP_LEFT;
+
+ s_b->curr_geometry.x -= x_step;
+ s_b->curr_geometry.y -= y_step;
+ }
+ break;
+
+ default:
+ printf (" no correct direction.\n");
+ break;
+ }
+
+ if (s_b->curr_geometry.x < 0 || s_b->curr_geometry.y < 0)
+ {
+ printf ("error with calculation algorithm.\n");
+ exit (1);
+ }
+}
diff --git a/tests/functional/hwc_test/wander_stripe.c b/tests/functional/hwc_test/wander_stripe.c
new file mode 100644
index 0000000..9195660
--- /dev/null
+++ b/tests/functional/hwc_test/wander_stripe.c
@@ -0,0 +1,259 @@
+/**************************************************************************
+
+ wander_strip
+
+ Copyright 2010 - 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Contact: Keith Packard <keithp@keithp.com>
+ Contact: Sergey Sizonov <s.sizonov@samsung.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+// this file implements wander_stripe for using in semiautomatic tests for
+// keep safe ddx driver devoloping
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+#include "aux_apps.h"
+#include "dri2_dri3.h"
+
+
+xcb_connection_t* dpy = NULL;
+xcb_screen_t* screen = NULL;
+xcb_rectangle_t wnd_pos = {100, 100, 200, 200};
+xcb_rectangle_t wander_strip;
+xcb_gc_t gc;
+
+// work behavior flags: (see aux_apps.c for details)
+
+// mode of work (dri2/dri3+present)
+int mode = DRI3_PRESENT_MODE; // by default dri3 + present will be used
+int stop;
+int x_step = 1;
+uint32_t present_bufs = 3;
+uint32_t swap_interval = 1;
+uint32_t root_parent = 1;
+
+
+// direct accessing memory clear callback
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_clear (const bo_t* bo_e)
+{
+ xcb_rectangle_t rect;
+
+ if (!bo_e)
+ {
+ printf ("raw_clear: invalid parameters.\n");
+ return;
+ }
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = bo_e->width;
+ rect.height = bo_e->height;
+
+ // draw white rectangle with size as window has
+ raw_fill_rect (bo_e, 1, &rect, 0xff000000 | screen->white_pixel);
+}
+
+// direct accessing memory draw callback (wander stripe drawing)
+// bo_e - contains all information to do direct render in memory
+//===================================================================
+void
+raw_draw (const bo_t* bo_e)
+{
+ static int x;
+
+ if (!bo_e)
+ {
+ printf ("raw_draw: invalid parameters.\n");
+ return;
+ }
+
+ wander_strip.height = bo_e->height;
+ wander_strip.width = bo_e->width / 4;
+
+ // move stripe
+ if (x_step > 0)
+ {
+ if (x + wander_strip.width > bo_e->width)
+ {
+ x_step = -x_step;
+ x += x_step;
+ }
+ }
+ else
+ {
+ if (x < 0)
+ {
+ x_step = -x_step;
+ x += x_step;
+ }
+ }
+
+ wander_strip.x = x;
+
+ // draw white wrandered rectangle
+ raw_fill_rect (bo_e, 1, &wander_strip, 0xff0000ff);
+
+ if (!stop)
+ x += x_step;
+}
+
+// xcb based draw callback (wander stripe drawing)
+// drawable - drawable to render into it
+// draw_w, draw_h - size of drawable
+//===================================================================
+void
+xcb_draw (xcb_drawable_t drawable, uint32_t draw_w, uint32_t draw_h)
+{
+ static int x;
+ uint32_t gc_mask;
+ uint32_t gc_values;
+ xcb_rectangle_t temp_rect;
+
+ // draw white rectangle with size as window has
+ gc_mask = XCB_GC_FOREGROUND;
+ gc_values = 0xffffffff;
+
+ xcb_change_gc (dpy, gc, gc_mask, &gc_values);
+ temp_rect.x = 0;
+ temp_rect.y = 0;
+ temp_rect.width = draw_w;
+ temp_rect.height = draw_h;
+ xcb_poly_fill_rectangle(dpy, drawable, gc, 1, &temp_rect);
+
+ // draw black wander strip
+ gc_mask = XCB_GC_FOREGROUND;
+ gc_values = 0x0;
+ xcb_change_gc (dpy, gc, gc_mask, &gc_values);
+
+ wander_strip.height = draw_h;
+
+ // move stripe
+ if (x_step > 0)
+ {
+ if (x + wander_strip.width > draw_w)
+ {
+ x_step = -x_step;
+ x += x_step;
+ }
+ }
+ else
+ {
+ if (x < 0)
+ {
+ x_step = -x_step;
+ x += x_step;
+ }
+ }
+
+ wander_strip.x = x;
+
+ // draw white wrandered rectangle
+ xcb_poly_fill_rectangle (dpy, drawable, gc, 1, &wander_strip);
+
+ if (!stop)
+ x += x_step;
+
+ xcb_flush (dpy);
+}
+
+//
+//===================================================================
+int
+main (int argc, char** argv)
+{
+ xcb_generic_event_t* event = NULL;
+ xcb_window_t main_wnd;
+ draw_funcs_t draw_func;
+ dri2_dri3_params_t params;
+ int res;
+
+ cmd_parse (argc, argv);
+
+ dpy = xcb_connect (NULL, NULL);
+
+ // get first screen of display
+ screen = xcb_setup_roots_iterator (xcb_get_setup (dpy)).data;
+
+ main_wnd = create_window (dpy, 0xff, root_parent, "wander stripe");
+
+ gc = xcb_generate_id (dpy);
+ xcb_create_gc (dpy, gc, main_wnd, 0, NULL);
+
+ draw_func.raw_clear = raw_clear;
+ draw_func.raw_draw = raw_draw;
+ draw_func.xcb_draw = xcb_draw;
+ draw_func.xcb_clear = NULL;
+
+ // init for drawing
+ wander_strip.y = 0;
+ wander_strip.width = wnd_pos.width / 4;
+ wander_strip.height = wnd_pos.height;
+
+ params.num_of_bufs = present_bufs;
+ params.swap_interval = swap_interval;
+
+ // inside init_dri2_dri3 new thread, responsible for dri2/dri3/present events
+ // handling, will be created
+ res = init_dri2_dri3 (dpy, &draw_func, mode, main_wnd, &params);
+ if (res)
+ {
+ printf ("init_dri2_dri3: %s.\n", get_last_error());
+ exit (1);
+ }
+
+ printf ("before xcb loop.\n");
+
+ while (1)
+ {
+ xcb_flush (dpy);
+ event = xcb_wait_for_event (dpy);
+ if (!event) break;
+
+ switch (event->response_type)
+ {
+ case XCB_EXPOSE:
+ DEBUG_OUT ("XCB_MAP_WINDOW\n");
+ break;
+
+ // if we are notified by XCB_BUTTON_PRESS event, we start/stop
+ // to change our frames, simple draw the same thing
+ case XCB_BUTTON_PRESS:
+ stop ^= 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/functional/pixmap_copy_test/Makefile.am b/tests/functional/pixmap_copy_test/Makefile.am
new file mode 100644
index 0000000..13c461f
--- /dev/null
+++ b/tests/functional/pixmap_copy_test/Makefile.am
@@ -0,0 +1,9 @@
+if HAVE_FT
+ bin_PROGRAMS = pixmap_copy
+
+pixmap_copy_CFLAGS = $(PIXMAP_COPY_TEST_CFLAGS)
+pixmap_copy_LDADD = $(PIXMAP_COPY_TEST_LIBS)
+pixmap_copy_SOURCES = \
+@top_srcdir@/tests/functional/pixmap_copy_test/pixmap_copy.c
+
+endif
diff --git a/tests/functional/pixmap_copy_test/pixmap_copy.c b/tests/functional/pixmap_copy_test/pixmap_copy.c
new file mode 100644
index 0000000..b6bbbcc
--- /dev/null
+++ b/tests/functional/pixmap_copy_test/pixmap_copy.c
@@ -0,0 +1,122 @@
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#define ERROR(str, arg...) \
+ do \
+ { \
+ printf(str, ##arg); \
+ exit(1); \
+ } \
+ while(0) \
+
+#define WIDTH 720
+#define HEIGHT 1280
+
+extern int errno;
+
+int main(int argc, char **argv)
+{
+ Display *display;
+ Window window;
+ Visual *visual;
+ Pixmap pixmap, pixmap2;
+ GC gr_context;
+ XGCValues gr_values;
+ XSetWindowAttributes attributes;
+ int depth = 0;
+ int screen = 0;
+ int num = 0;
+ time_t start, current;
+
+/* Connect to X Server */
+ if ((display = XOpenDisplay(NULL)) == NULL)
+ ERROR("Can't connect X server: %s\n", strerror(errno));
+
+/* Get default screen, visual etc */
+ screen = XDefaultScreen(display);
+ visual = XDefaultVisual(display,screen);
+ depth = XDefaultDepth(display,screen);
+ attributes.background_pixel = XWhitePixel(display,screen);
+
+ printf("depth %d\n", depth);
+
+/* Create window */
+ window = XCreateWindow(display, XRootWindow(display,screen),
+ 0, 0, WIDTH, HEIGHT, 0, depth, InputOutput,
+ visual , CWBackPixel, &attributes);
+
+/* Chose events we are intrested in */
+ XSelectInput(display, window, ExposureMask | KeyPressMask);
+ XFlush(display);
+
+/* Create pxmap */
+ pixmap = XCreatePixmap(display, window, WIDTH, HEIGHT, depth);
+
+/* Create graphic contexts */
+ gr_values.foreground = 0xAABBCC;
+ gr_context = XCreateGC(display, pixmap, GCForeground, &gr_values);
+
+ XFillRectangle(display, pixmap, gr_context, 0, 0, WIDTH, HEIGHT);
+ XCopyArea(display, pixmap, window, gr_context, 0, 0, WIDTH, HEIGHT, 0, 0);
+
+/* Display the window on screen*/
+ XMapWindow(display, window);
+ XFlush(display);
+
+
+/*--------------- pixmap -> window -----------------*/
+
+ printf("-------------------------\n");
+ printf("wait 2\n");
+ sleep(2);
+ printf("start\n\n");
+
+ num = 0;
+ start = time(NULL);
+ while (time(&current) < start + 5)
+ {
+ XCopyArea(display, pixmap, window, gr_context, 0, 0, WIDTH, HEIGHT, 0, 0);
+ ++num;
+ XFlush(display);
+ }
+
+ printf("pixmap -> window: %d\n", num);
+ printf("-------------------------\n\n");
+
+ pixmap2 = XCreatePixmap(display, window, WIDTH, HEIGHT, depth);
+ XFillRectangle(display, pixmap2, gr_context, 0, 0, WIDTH, HEIGHT);
+ XFlush(display);
+
+
+/*--------------- pixmap -> pixmap -----------------*/
+
+ printf("-------------------------\n");
+ printf("wait 2\n");
+ sleep(2);
+ printf("start\n\n");
+
+ num = 0;
+ start = time(NULL);
+ while (time(&current) < start + 5)
+ {
+ XCopyArea(display, pixmap, pixmap2, gr_context, 0, 0, WIDTH, HEIGHT, 0, 0);
+ ++num;
+ XFlush(display);
+ }
+
+ printf("pixmap -> pixmap: %d\n", num);
+ printf("-------------------------\n");
+
+
+/* Close connection with X */
+ XCloseDisplay(display);
+
+ return 0;
+}
+
diff --git a/tests/functional/xv_test/Makefile.am b/tests/functional/xv_test/Makefile.am
new file mode 100644
index 0000000..67f3fd6
--- /dev/null
+++ b/tests/functional/xv_test/Makefile.am
@@ -0,0 +1,12 @@
+if HAVE_FT
+bin_PROGRAMS = test_xv
+test_xv_CFLAGS = @XV_TEST_CFLAGS@ \
+-I@top_srcdir@/tests/functional/xv_test \
+-I@top_srcdir@/src/xv
+test_xv_LDADD = @XV_TEST_LIBS@
+test_xv_SOURCES = \
+@top_srcdir@/tests/functional/xv_test/xv_test.c \
+@top_srcdir@/tests/functional/xv_test/data.c \
+@top_srcdir@/tests/functional/xv_test/xcb_api.c \
+@top_srcdir@/tests/functional/xv_test/test_xv_resize.c
+endif
diff --git a/tests/functional/xv_test/data.c b/tests/functional/xv_test/data.c
new file mode 100644
index 0000000..08ca1d4
--- /dev/null
+++ b/tests/functional/xv_test/data.c
@@ -0,0 +1,242 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "data.h"
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <tbm_bufmgr.h>
+#include <xf86drm.h>
+#include <assert.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include "xv_types.h"
+#include <string.h>
+
+static tbm_bufmgr bufmgr_p = NULL;
+typedef struct
+{
+ int fd;
+ error_s error;
+} dri_fd_s;
+
+static dri_fd_s
+open_dri2 (xcb_connection_t *c, xcb_screen_t *screen)
+{
+ xcb_dri2_connect_cookie_t dri2_conn_ck;
+ xcb_dri2_connect_reply_t *dri2_conn_reply_p = NULL;
+ xcb_dri2_authenticate_cookie_t dri2_auth_ck;
+ xcb_dri2_authenticate_reply_t *dri2_auth_reply_p = NULL;
+ xcb_generic_error_t *error_p = NULL;
+ int error = -1;
+ dri_fd_s ret = {};
+ char *device_name_p = NULL;
+ drm_magic_t drm_magic;
+ xcb_window_t window_id = screen->root;
+
+ dri2_conn_ck = xcb_dri2_connect(c, window_id, XCB_DRI2_DRIVER_TYPE_DRI);
+ dri2_conn_reply_p = xcb_dri2_connect_reply(c, dri2_conn_ck, &error_p);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't connect to DRI2 driver";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+ device_name_p = strndup(xcb_dri2_connect_device_name (dri2_conn_reply_p),
+ xcb_dri2_connect_device_name_length (dri2_conn_reply_p));
+
+ ret.fd = open(device_name_p, O_RDWR);
+
+ if (ret.fd < 0)
+ {
+ ret.error.error_str = "Can't open DRI2 file descriptor";
+ ret.error.error_code = ret.fd;
+ goto close;
+ }
+
+ error = drmGetMagic(ret.fd, &drm_magic);
+ if (error < 0)
+ {
+ ret.error.error_str = "Can't get drm magic";
+ ret.error.error_code = error;
+ goto close;
+ }
+
+ dri2_auth_ck = xcb_dri2_authenticate(c, window_id, drm_magic);
+ dri2_auth_reply_p = xcb_dri2_authenticate_reply(c, dri2_auth_ck, &error_p);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't auth DRI2";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+close:
+ if (error_p)
+ free(error_p);
+ if (dri2_conn_reply_p)
+ free(dri2_conn_reply_p);
+ if (dri2_auth_reply_p)
+ free(dri2_auth_reply_p);
+ if (device_name_p)
+ free(device_name_p);
+ return ret;
+}
+
+static shm_data_s
+open_shm(xcb_connection_t *c, size_t data_size)
+{
+ xcb_generic_error_t *error_p = NULL;
+ shm_data_s ret_shm = {};
+
+ ret_shm.shm_seg_id = xcb_generate_id (c);
+
+ int shm_id = shmget (IPC_PRIVATE, data_size, IPC_CREAT | 0777);
+ if (shm_id == -1)
+ {
+ ret_shm.error.error_str = "shm alloc error";
+ ret_shm.error.error_code = shm_id;
+ goto close;
+ }
+
+ ret_shm.shm_seg_addr = shmat (shm_id, NULL, 0);
+ if (!ret_shm.shm_seg_addr)
+ {
+ ret_shm.error.error_str = "shm attach error";
+ goto close;
+ }
+ xcb_void_cookie_t xcb_shm_c =
+ xcb_shm_attach_checked (c, ret_shm.shm_seg_id, shm_id, 0);
+ error_p = xcb_request_check (c, xcb_shm_c);
+ if (error_p)
+ {
+ ret_shm.error.error_str = "xcb_shm attach error";
+ goto close;
+ }
+close:
+ shmctl (shm_id, IPC_RMID, NULL);
+ if (error_p)
+ free(error_p);
+ return ret_shm;
+}
+
+static tbm_bo
+get_data_random (size_t size, tbm_bufmgr bufmgr)
+{
+ FILE *fp = fopen ("/dev/urandom", "r");
+ if (fp == NULL)
+ {
+ return NULL;
+ }
+
+ tbm_bo tbo = tbm_bo_alloc (bufmgr, size, TBM_BO_DEFAULT);
+ if (tbo == NULL)
+ {
+ return NULL;
+ }
+
+ /* copy raw data to tizen buffer object */
+ tbm_bo_handle bo_handle = tbm_bo_map (tbo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+ size_t error = fread (bo_handle.ptr, 1, size , fp);
+ tbm_bo_unmap (tbo);
+ fclose (fp);
+ if (error == 0)
+ {
+ tbm_bo_unref(tbo);
+ tbo = NULL;
+ }
+ return tbo;
+}
+
+shm_data_s
+get_image_random (xcb_connection_t *p_xcb_conn, xcb_screen_t *screen,
+ size_t *sizes, int num_planes)
+{
+ shm_data_s ret = {0,};
+ XV_DATA_PTR xv_data = NULL;
+ if (bufmgr_p == NULL)
+ {
+ dri_fd_s dri2 = open_dri2 (p_xcb_conn, screen);
+ if (dri2.error.error_str)
+ {
+ ret.error = dri2.error;
+ goto close_l;
+ }
+ bufmgr_p = tbm_bufmgr_init (dri2.fd);
+ if (!bufmgr_p)
+ {
+ ret.error.error_str = "Can't open TBM connection\n";
+ ret.error.error_code = 0;
+ goto close_l;
+ }
+ }
+
+ if (sizes == NULL)
+ {
+ ret.error.error_str = "Sizes argument is NULL";
+ goto close_l;
+ }
+
+ if (num_planes > 3 || num_planes < 1)
+ {
+ ret.error.error_str = "Wrong num_planes argument";
+ goto close_l;
+ }
+ size_t full_size = 0;
+ int i;
+ for (i = 0; i < num_planes; i++)
+ {
+ full_size += sizes[i];
+ }
+ ret = open_shm(p_xcb_conn, full_size);
+ if (ret.error.error_str)
+ goto close_l;
+
+ xv_data = ret.shm_seg_addr;
+ XV_INIT_DATA (xv_data);
+ tbm_bo temp_bo = NULL;
+ switch (num_planes)
+ {
+ case 3:
+ temp_bo = get_data_random (sizes[2], bufmgr_p);
+ if (temp_bo == NULL)
+ {
+ ret.error.error_str = "Can't alloc tbm object";
+ goto close_l;
+ }
+ xv_data->CrBuf = tbm_bo_export(temp_bo);
+ case 2:
+ temp_bo = get_data_random (sizes[1], bufmgr_p);
+ if (temp_bo == NULL)
+ {
+ ret.error.error_str = "Can't alloc tbm object";
+ goto close_l;
+ }
+ xv_data->CbBuf = tbm_bo_export(temp_bo);
+ case 1:
+ temp_bo = get_data_random (sizes[0], bufmgr_p);
+ if (temp_bo == NULL)
+ {
+ ret.error.error_str = "Can't alloc tbm object\n";
+ goto close_l;
+ }
+ xv_data->YBuf = tbm_bo_export(temp_bo);
+ break;
+ }
+
+ return ret;
+close_l:
+ // TODO: Close DRI
+ // TODO: Close tbm
+ if (xv_data)
+ {
+ if (xv_data->YBuf != 0)
+ tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->YBuf));
+ if (xv_data->CbBuf != 0)
+ tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->CbBuf));
+ if (xv_data->CrBuf != 0)
+ tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->CrBuf));
+ }
+
+ return ret;
+}
+
diff --git a/tests/functional/xv_test/data.h b/tests/functional/xv_test/data.h
new file mode 100644
index 0000000..81329c0
--- /dev/null
+++ b/tests/functional/xv_test/data.h
@@ -0,0 +1,18 @@
+#ifndef DATA_H
+#define DATA_H
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#include <xcb/xv.h>
+#include "xv_test.h"
+
+typedef struct
+{
+ xcb_shm_seg_t shm_seg_id;
+ void *shm_seg_addr;
+ error_s error;
+} shm_data_s;
+
+shm_data_s get_image_random (xcb_connection_t *xcb_conn_p, xcb_screen_t *screen,
+ size_t * sizes, int num_planes);
+
+#endif // DATA_H
diff --git a/tests/functional/xv_test/test_xv_resize.c b/tests/functional/xv_test/test_xv_resize.c
new file mode 100644
index 0000000..0c77dd7
--- /dev/null
+++ b/tests/functional/xv_test/test_xv_resize.c
@@ -0,0 +1,520 @@
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <tbm_bufmgr.h>
+#include <assert.h>
+#include "xv_test.h"
+#include "data.h"
+#include "xcb_api.h"
+
+typedef struct
+{
+ xcb_atom_t atom_hflip;
+ xcb_atom_t atom_vflip;
+ xcb_atom_t atom_rotate;
+ xcb_atom_t atom_buffer;
+ error_s error;
+} test_atom_s;
+
+typedef struct
+{
+ size_t steps;
+ rectangle_s *src_crop_p;
+ rectangle_s *dst_crop_p;
+} route_map_s;
+
+typedef struct
+{
+ error_s error;
+ route_map_s route_map;
+} get_route_map_s;
+
+typedef struct
+{
+ xcb_xv_port_t xv_open_port;
+ test_atom_s atoms;
+ xcb_connection_t *xcb_conn_p;
+ xcb_screen_t *screen_p;
+ xcb_window_t window_id;
+ xcb_gcontext_t gc_id;
+ route_map_s route_map;
+} test_data_s;
+
+static test_data_s *st_test_data_p = NULL;
+
+static error_s test_xv_resize_prepare(xcb_connection_t *xcb_conn_p,
+ xcb_screen_t * screen_p, rule_s rule);
+
+static error_s test_xv_resize_run(xcb_connection_t *xcb_conn_p,
+ xcb_screen_t * screen_p, rule_s rule);
+
+static error_s test_xv_resize_close(xcb_connection_t *xcb_conn_p,
+ xcb_screen_t * screen_p, rule_s rule);
+
+test_atom_s
+create_atoms (xcb_connection_t *xcb_conn_p)
+{
+ char const *atom_name_a[4] = {
+ "_USER_WM_PORT_ATTRIBUTE_HFLIP",
+ "_USER_WM_PORT_ATTRIBUTE_VFLIP",
+ "_USER_WM_PORT_ATTRIBUTE_ROTATION",
+ "XV_RETURN_BUFFER"};
+ xcb_intern_atom_cookie_t atom_ck_a[4] = {};
+ xcb_intern_atom_reply_t *atom_reply_p = NULL;
+ test_atom_s ret = {};
+ xcb_generic_error_t *error_p = NULL;
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ atom_ck_a[i] =
+ xcb_intern_atom (xcb_conn_p, 0, (uint16_t) strlen(atom_name_a[i]),
+ atom_name_a[i]);
+ }
+ for (i = 0; i < 4; i++)
+ {
+ atom_reply_p =
+ xcb_intern_atom_reply (xcb_conn_p , atom_ck_a[i], &error_p);
+
+ if (error_p)
+ {
+ ret.error.error_str = "Can't register atom";
+ ret.error.error_code = error_p->error_code;
+ goto close_l;
+ }
+ if (atom_reply_p == NULL)
+ {
+ ret.error.error_str = "Can't register atom";
+ goto close_l;
+ }
+ switch (i)
+ {
+ case 0:
+ ret.atom_hflip = atom_reply_p->atom;
+ break;
+ case 1:
+ ret.atom_vflip = atom_reply_p->atom;
+ break;
+ case 2:
+ ret.atom_rotate = atom_reply_p->atom;
+ break;
+ case 3:
+ ret.atom_buffer = atom_reply_p->atom;
+ break;
+ }
+ free(atom_reply_p);
+ atom_reply_p = NULL;
+ }
+
+close_l:
+
+ if (error_p)
+ free(error_p);
+ if (atom_reply_p)
+ free(atom_reply_p);
+ return ret;
+}
+
+get_route_map_s
+create_route_map (rule_s *rules)
+{
+ get_route_map_s ret = {};
+ rectangle_s *src_crop_p = NULL;
+ rectangle_s *dst_crop_p = NULL;
+ if (rules == NULL)
+ {
+ ret.error.error_str = "Wrong input arguments";
+ goto close_l;
+ }
+ size_t steps_width = (rules->max_width - rules->min_width)/10;
+ size_t steps_height = (rules->max_height - rules->max_height)/10;
+ size_t steps = (max(steps_width, steps_height))*2;
+
+ src_crop_p = calloc(steps, sizeof(rectangle_s));
+ if (!src_crop_p)
+ {
+ ret.error.error_str = "Can't alloc memory";
+ goto close_l;
+ }
+ dst_crop_p = calloc(steps, sizeof(rectangle_s));
+ if (!dst_crop_p)
+ {
+ ret.error.error_str = "Can't alloc memory";
+ goto close_l;
+ }
+// pace_dst_crop.height = (uint32_t)
+// ((double)(rules->max_size.height - rules->min_size.height)/
+// (rules->steps * 2));
+// pace_dst_crop.width = (uint32_t)
+// ((double)(rules->max_size.width - rules->min_size.width)/
+// (rules->steps * 2));
+// pace_src_crop.height = (uint32_t)
+// ((double)(rules->image_height - rules->min_size.height)/
+// (rules->steps * 2));
+// pace_src_crop.width = (uint32_t)
+// ((double)(rules->image_width - rules->min_size.width)/
+// (rules->steps * 2));
+ if (!rules->src_change)
+ {
+ src_crop_p[0].x = 0;
+ src_crop_p[0].y = 0;
+ src_crop_p[0].width = rules->image_width;
+ src_crop_p[0].height = rules->image_height;
+ }
+ else
+ {
+ src_crop_p[0].x = 0;
+ src_crop_p[0].y = 0;
+ src_crop_p[0].width = rules->min_width;
+ src_crop_p[0].height = rules->min_height;
+ }
+
+ if (!rules->dst_change)
+ {
+ dst_crop_p[0].x = 0;
+ dst_crop_p[0].y = 0;
+ dst_crop_p[0].width = rules->image_width;
+ dst_crop_p[0].height = rules->image_height;
+ }
+ else
+ {
+ dst_crop_p[0].x = 0;
+ dst_crop_p[0].y = 0;
+ dst_crop_p[0].width = rules->min_width;
+ dst_crop_p[0].height = rules->min_height;
+ }
+ int i;
+ for (i = 1; i < (steps/2); i++)
+ {
+ if (!rules->src_change)
+ {
+ src_crop_p[i].x = 0;
+ src_crop_p[i].y = 0;
+ src_crop_p[i].width = rules->image_width;
+ src_crop_p[i].height = rules->image_height;
+ }
+ else
+ {
+ src_crop_p[i].x = 0;
+ src_crop_p[i].y = 0;
+ src_crop_p[i].width =
+ ((src_crop_p[i-1].width + 10) <= rules->image_width) ?
+ (src_crop_p[i-1].width + 10) : src_crop_p[i-1].width;
+ src_crop_p[i].height =
+ ((src_crop_p[i-1].height + 10) <= rules->image_height) ?
+ (src_crop_p[i-1].height + 10) : src_crop_p[i-1].height;
+ }
+ if (!rules->dst_change)
+ {
+ dst_crop_p[i].x = 0;
+ dst_crop_p[i].y = 0;
+ dst_crop_p[i].width = rules->image_width;
+ dst_crop_p[i].height = rules->image_height;
+ }
+ else
+ {
+ dst_crop_p[i].x = 0;
+ dst_crop_p[i].y = 0;
+ dst_crop_p[i].width =
+ ((dst_crop_p[i-1].width + 10) <= rules->max_width) ?
+ (dst_crop_p[i-1].width + 10) : dst_crop_p[i-1].width;
+ dst_crop_p[i].height =
+ ((dst_crop_p[i-1].height + 10) <= rules->max_height) ?
+ (dst_crop_p[i-1].height + 10) : dst_crop_p[i-1].height;
+ }
+ }
+ for (i = (steps/2); i < steps; i++)
+ {
+ if (!rules->src_change)
+ {
+ src_crop_p[i].x = 0;
+ src_crop_p[i].y = 0;
+ src_crop_p[i].width = rules->image_width;
+ src_crop_p[i].height = rules->image_height;
+ }
+ else
+ {
+ src_crop_p[i].x = 0;
+ src_crop_p[i].y = 0;
+ src_crop_p[i].width =
+ ((src_crop_p[i-1].width - 10) >= rules->min_width) ?
+ (src_crop_p[i-1].width - 10) : src_crop_p[i-1].width;
+ src_crop_p[i].height =
+ ((src_crop_p[i-1].height - 10) >= rules->min_height) ?
+ (src_crop_p[i-1].height - 10) : src_crop_p[i-1].height;
+ }
+ if (!rules->dst_change)
+ {
+ dst_crop_p[i].x = 0;
+ dst_crop_p[i].y = 0;
+ dst_crop_p[i].width = rules->image_width;
+ dst_crop_p[i].height = rules->image_height;
+ }
+ else
+ {
+ dst_crop_p[i].x = 0;
+ dst_crop_p[i].y = 0;
+ dst_crop_p[i].width =
+ ((dst_crop_p[i-1].width - 10) >= rules->min_width) ?
+ (dst_crop_p[i-1].width - 10) : dst_crop_p[i-1].width;
+ dst_crop_p[i].height =
+ ((dst_crop_p[i-1].height - 10) >= rules->min_height) ?
+ (dst_crop_p[i-1].height - 10) : dst_crop_p[i-1].height;
+ }
+ }
+
+ ret.route_map.src_crop_p = src_crop_p;
+ ret.route_map.dst_crop_p = dst_crop_p;
+ ret.route_map.steps = steps;
+ return ret;
+close_l:
+ if (src_crop_p)
+ free(src_crop_p);
+ if (dst_crop_p)
+ free(dst_crop_p);
+ return ret;
+}
+test_case_s
+test_xv_resize_init (void)
+{
+ test_case_s ret = {};
+ ret.prepare_test = test_xv_resize_prepare;
+ ret.run_test = test_xv_resize_run;
+ ret.close_test = test_xv_resize_close;
+ return ret;
+}
+
+
+static error_s
+test_xv_resize_prepare(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+ error_s ret = {};
+ st_test_data_p = malloc(sizeof(test_data_s));
+ DBG;
+ if (!st_test_data_p)
+ {
+ ret.error_str = "Can't alloc memory for test_data_s";
+ ret.error_code = 0;
+ goto close_l;
+ }
+ st_test_data_p->xcb_conn_p = xcb_conn_p;
+ st_test_data_p->screen_p = screen_p;
+ DBG;
+ get_xv_port_s xv_port = open_adaptor (xcb_conn_p, screen_p->root);
+ if (xv_port.error.error_str)
+ {
+ ret = xv_port.error;
+ goto close_l;
+ }
+ DBG;
+ st_test_data_p->xv_open_port = xv_port.xv_port_id;
+ st_test_data_p->atoms = create_atoms (xcb_conn_p);
+ if(st_test_data_p->atoms.error.error_str)
+ {
+ ret = st_test_data_p->atoms.error;
+ goto close_l;
+ }
+ DBG;
+
+ get_window_s window = create_window(xcb_conn_p, screen_p);
+ if (window.error.error_str)
+ {
+ ret = window.error;
+ goto close_l;
+ }
+ st_test_data_p->window_id = window.window_id;
+ get_gc_s gc = create_gc (xcb_conn_p, st_test_data_p->window_id, screen_p);
+ if (gc.error.error_str)
+ {
+ ret = gc.error;
+ goto close_l;
+ }
+ st_test_data_p->gc_id = gc.gc_id;
+
+ get_route_map_s route = create_route_map (&rule);
+
+ if (route.error.error_str)
+ {
+ ret = route.error;
+ goto close_l;
+ }
+
+ st_test_data_p->route_map = route.route_map;
+ return ret;
+
+close_l:
+ DBG;
+ if (st_test_data_p)
+ free(st_test_data_p);
+/* TODO: close port */
+ st_test_data_p = NULL;
+ return ret;
+}
+static
+error_s
+test_xv_resize_run(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+
+ DBG;
+ xcb_generic_error_t *error_p = NULL;
+ error_s ret = {};
+ shm_data_s shm;
+ if (st_test_data_p == NULL)
+ {
+ ret.error_str = "Wrong argument";
+ return ret;
+ }
+ frame_attr_s frame[st_test_data_p->route_map.steps];
+
+ DBG;
+ get_image_attr_s image_attr =
+ get_image_attr (xcb_conn_p, st_test_data_p->xv_open_port,
+ rule.image_fourcc, rule.image_width, rule.image_height);
+ DBG;
+ if (image_attr.error.error_str)
+ {
+ ret = image_attr.error;
+ goto close_l;
+ }
+ /* get raw data */
+
+ size_t max_j = rule.count_uniqes_frames;
+ DBG;
+ int i,j = 0;
+ for (i = 0; i < st_test_data_p->route_map.steps; i++)
+ {
+
+ if (i == 0)
+ printf("Generate data:\n");
+ if (i < max_j)
+ {
+ shm = get_image_random (xcb_conn_p, screen_p,
+ image_attr.image.sizes,
+ image_attr.image.num_planes);
+ if (shm.error.error_str)
+ {
+ ret = shm.error;
+ goto close_l;
+ }
+ frame[i].segment = shm.shm_seg_id;
+ printf("%f%%\n", ((double)i/max_j));
+ }
+ else
+ {
+ if (j == max_j)
+ {
+ j = 0;
+ }
+ frame[i].segment = frame[j].segment;
+ j++;
+ }
+
+ frame[i].image_p = &image_attr.image;
+ frame[i].src_crop_p = &st_test_data_p->route_map.src_crop_p[i];
+ frame[i].dst_crop_p = &st_test_data_p->route_map.dst_crop_p[i];
+
+ }
+ DBG;
+ xcb_void_cookie_t map_window_ck =
+ xcb_map_window_checked (xcb_conn_p, st_test_data_p->window_id);
+ xcb_void_cookie_t put_image_ck =
+ put_image (xcb_conn_p, st_test_data_p->xv_open_port,
+ st_test_data_p->window_id, st_test_data_p->gc_id, &frame[0]);
+ j = 1;
+
+ error_p = xcb_request_check (xcb_conn_p, map_window_ck);
+ if (error_p)
+ {
+ ret.error_str = "Can't make transparent window";
+ ret.error_code = error_p->error_code;
+ goto close_l;
+ }
+
+ xcb_generic_event_t *e;
+ xcb_client_message_event_t* msg;
+ DBG;
+ while (1)
+ {
+ e = xcb_poll_for_event(xcb_conn_p);
+ while (e)
+ {
+ switch (e->response_type)
+ {
+ case XCB_CLIENT_MESSAGE:
+ msg = (xcb_client_message_event_t *)e;
+ if (msg->type == st_test_data_p->atoms.atom_buffer)
+ {
+ unsigned int keys[3] = {0, };
+ keys[0] = msg->data.data32[0];
+ keys[1] = msg->data.data32[1];
+ keys[2] = msg->data.data32[2];
+ printf ("receive: %d, %d, %d (<= Xorg)\n",
+ keys[0], keys[1], keys[2]);
+ }
+
+ break;
+ case XCB_EXPOSE:
+ break;
+ default:
+ break;
+ }
+ free(e);
+ e = xcb_poll_for_event(xcb_conn_p);
+ }
+
+ error_p = xcb_request_check (xcb_conn_p, put_image_ck);
+ if (error_p)
+ {
+ ret.error_str = "Can't draw image frame";
+ ret.error_code = error_p->error_code;
+ goto close_l;
+ }
+ if (j >= st_test_data_p->route_map.steps)
+ j = 0;
+ put_image_ck = put_image (xcb_conn_p, st_test_data_p->xv_open_port,
+ st_test_data_p->window_id, st_test_data_p->gc_id,
+ &frame[j]);
+ printf("src:(%dwx%dh) dst: (%dwx%dh)\n",
+ frame[j].src_crop_p->width, frame[j].src_crop_p->height,
+ frame[j].dst_crop_p->width, frame[j].dst_crop_p->height);
+ j++;
+ usleep(1000000/rule.frame_per_second);
+ }
+
+close_l:
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+static error_s
+test_xv_resize_close(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+ error_s ret = {};
+ return ret;
+}
+
+#if 0
+xcb_xv_list_image_formats_reply_t *list =
+ xcb_xv_list_image_formats_reply (conn,
+ xcb_xv_list_image_formats (conn, a->base_id), NULL);
+if (list == NULL)
+ return NULL;
+
+/* Check available XVideo chromas */
+xcb_xv_query_image_attributes_reply_t *attr = NULL;
+unsigned rank = UINT_MAX;
+
+for (const xcb_xv_image_format_info_t *f =
+ xcb_xv_list_image_formats_format (list),
+ *f_end =
+ f + xcb_xv_list_image_formats_format_length (list);
+ f < f_end;
+ f++)
+#endif
diff --git a/tests/functional/xv_test/test_xv_resize.h b/tests/functional/xv_test/test_xv_resize.h
new file mode 100644
index 0000000..fdff351
--- /dev/null
+++ b/tests/functional/xv_test/test_xv_resize.h
@@ -0,0 +1,6 @@
+#ifndef TEST_XV_RESIZE_H
+#define TEST_XV_RESIZE_H
+#include "xv_test.h"
+test_case_s test_xv_resize_init (void);
+
+#endif // TEST_XV_RESIZE_H
diff --git a/tests/functional/xv_test/xcb_api.c b/tests/functional/xv_test/xcb_api.c
new file mode 100644
index 0000000..4f5b013
--- /dev/null
+++ b/tests/functional/xv_test/xcb_api.c
@@ -0,0 +1,258 @@
+#include "xcb_api.h"
+get_image_attr_s
+get_image_attr(xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+ uint32_t fourcc_id, uint16_t width, uint16_t height)
+{
+ get_image_attr_s ret = {};
+ xcb_generic_error_t *error_p = NULL;
+ xcb_xv_query_image_attributes_reply_t * xv_attr_reply_p = NULL;
+
+ if (!xcb_conn_p || xv_port == XCB_XV_BAD_PORT)
+ {
+ ret.error.error_str = "Wrong arguments";
+ ret.error.error_code = 0;
+ goto close;
+ }
+
+ xcb_xv_query_image_attributes_cookie_t xv_attr_ck =
+ xcb_xv_query_image_attributes (xcb_conn_p /**< */,
+ xv_port /**< */,
+ fourcc_id /**< */,
+ width /**< */,
+ height /**< */);
+ xv_attr_reply_p =
+ xcb_xv_query_image_attributes_reply (xcb_conn_p /**< */,
+ xv_attr_ck /**< */,
+ &error_p /**< */);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't query image attr";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+ if (xv_attr_reply_p->data_size == 0)
+ {
+ ret.error.error_str = "Wrong input data format";
+ ret.error.error_code = 0;
+ goto close;
+ }
+
+ const uint32_t *offsets=
+ xcb_xv_query_image_attributes_offsets (xv_attr_reply_p);
+ const uint32_t *pitches=
+ xcb_xv_query_image_attributes_pitches (xv_attr_reply_p);
+ ret.image.num_planes = xv_attr_reply_p->num_planes;
+ ret.image.full_size = xv_attr_reply_p->data_size;
+ ret.image.fourcc_id = fourcc_id;
+ ret.image.width = xv_attr_reply_p->width;
+ ret.image.height = xv_attr_reply_p->height;
+ switch (ret.image.num_planes)
+ {
+ case 3:
+ ret.image.sizes[0] = offsets[1];
+ ret.image.sizes[1] = offsets[2] - offsets[1];
+ ret.image.sizes[2] = ret.image.full_size - offsets[2];
+ break;
+ case 2:
+ ret.image.sizes[1] = ret.image.full_size - offsets[1];
+ ret.image.sizes[0] = offsets[1];
+ break;
+ case 1:
+ ret.image.sizes[0] = ret.image.full_size;
+ break;
+ default:
+ ret.error.error_str = "Wrong input data format";
+ goto close;
+ break;
+ }
+ int i;
+ for (i = 0; i < ret.image.num_planes; ++i)
+ {
+ ret.image.offsets[i] = offsets[i];
+ ret.image.pitches[i] = pitches[i];
+ }
+
+close:
+
+ if (error_p)
+ free(error_p);
+ if (xv_attr_reply_p)
+ free(xv_attr_reply_p);
+
+ return ret;
+}
+
+xcb_void_cookie_t
+put_image (xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+ xcb_window_t window_id, xcb_gcontext_t gc_id, frame_attr_s *frame_p)
+{
+ xcb_void_cookie_t ret = {};
+ ret = xcb_xv_shm_put_image_checked (
+ xcb_conn_p, xv_port, window_id, gc_id,
+ frame_p->segment, frame_p->image_p->fourcc_id, 0,
+ frame_p->src_crop_p->x, frame_p->src_crop_p->y,
+ frame_p->src_crop_p->width, frame_p->src_crop_p->height,
+ frame_p->dst_crop_p->x, frame_p->dst_crop_p->y,
+ frame_p->dst_crop_p->width, frame_p->dst_crop_p->height,
+ frame_p->image_p->width, frame_p->image_p->height, 0);
+ return ret;
+}
+
+get_xv_port_s
+open_adaptor (xcb_connection_t *xcb_conn_p, xcb_window_t window_id)
+{
+ xcb_generic_error_t *error_p = NULL;
+ get_xv_port_s ret = {};
+ xcb_xv_adaptor_info_iterator_t xv_adaptor_iter;
+ xcb_xv_grab_port_reply_t *xv_grab_port_p = NULL;
+ xcb_xv_query_adaptors_cookie_t xv_adaptor_ck =
+ xcb_xv_query_adaptors (xcb_conn_p, window_id);
+ xcb_xv_query_adaptors_reply_t *xv_adaptors_list_p =
+ xcb_xv_query_adaptors_reply (xcb_conn_p, xv_adaptor_ck, &error_p);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't query xv adaptor";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+ for (xv_adaptor_iter = xcb_xv_query_adaptors_info_iterator (xv_adaptors_list_p);
+ xv_adaptor_iter.rem > 0;
+ xcb_xv_adaptor_info_next (&xv_adaptor_iter))
+ {
+ if (!(xv_adaptor_iter.data->type & XCB_XV_TYPE_IMAGE_MASK))
+ continue;
+ int i;
+ for (i = 0; i < xv_adaptor_iter.data->num_ports; i++)
+ {
+ xcb_xv_port_t xv_port = xv_adaptor_iter.data->base_id + i;
+ xcb_xv_grab_port_cookie_t xv_grab_port_c =
+ xcb_xv_grab_port (xcb_conn_p, xv_port, XCB_CURRENT_TIME);
+ xv_grab_port_p =
+ xcb_xv_grab_port_reply (xcb_conn_p, xv_grab_port_c, &error_p);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't query xv adaptor";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+ if (xv_grab_port_p && xv_grab_port_p->result == 0)
+ {
+ ret.xv_port_id = xv_port;
+ break;
+ }
+ }
+ if (ret.xv_port_id != 0)
+ {
+ break;
+ }
+ }
+
+close:
+ if (xv_adaptors_list_p)
+ free(xv_adaptors_list_p);
+ if (xv_grab_port_p)
+ free(xv_grab_port_p);
+ if (error_p)
+ free(error_p);
+
+ return ret;
+}
+
+get_gc_s
+create_gc (xcb_connection_t *xcb_conn_p, xcb_drawable_t drawable_id, xcb_screen_t * screen_p)
+{
+ get_gc_s ret = {};
+ xcb_void_cookie_t gc_ck;
+ xcb_generic_error_t *error_p = NULL;
+ uint32_t values[2];
+ ret.gc_id = xcb_generate_id (xcb_conn_p);
+ uint32_t mask = XCB_GC_GRAPHICS_EXPOSURES;
+ values[0] = 0;
+// values[0] = screen_p->white_pixel;
+ gc_ck = xcb_create_gc_checked (xcb_conn_p, ret.gc_id, drawable_id, mask, values);
+
+ error_p = xcb_request_check (xcb_conn_p, gc_ck);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't create graphic context";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+close:
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+get_window_s
+create_window (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p)
+{
+ get_window_s ret = {};
+ ret.window_id = xcb_generate_id (xcb_conn_p);
+ uint32_t mask;
+ uint32_t values[3];
+ xcb_generic_error_t *error_p = NULL;
+ mask = XCB_CW_EVENT_MASK;
+// values[0] = screen_p->black_pixel;
+ values[0] = XCB_EVENT_MASK_EXPOSURE;
+ xcb_void_cookie_t window_ck =
+ xcb_create_window_checked (xcb_conn_p,
+ screen_p->root_depth,
+ ret.window_id, screen_p->root,
+ 0, 0, screen_p->width_in_pixels,
+ screen_p->height_in_pixels,
+ 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen_p->root_visual,
+ mask, values);
+
+ error_p = xcb_request_check (xcb_conn_p, window_ck);
+ if (error_p)
+ {
+ ret.error.error_str = "Can't create window";
+ ret.error.error_code = error_p->error_code;
+ goto close;
+ }
+
+close:
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+static xcb_format_t *
+find_format_by_depth (const xcb_setup_t *setup, uint8_t depth)
+{
+ xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
+ xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
+ for(; fmt != fmtend; ++fmt)
+ if(fmt->depth == depth)
+ return fmt;
+ return 0;
+}
+
+#if 1
+xcb_void_cookie_t
+make_transparent (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p,
+ xcb_drawable_t drawable_id, xcb_gcontext_t gc_id)
+{
+ xcb_format_t *fmt = find_format_by_depth(xcb_get_setup (xcb_conn_p), 32);
+
+ uint32_t base = 1920 * fmt->bits_per_pixel;
+ uint32_t pad = fmt->scanline_pad >> 3;
+ uint32_t b = base + pad - 1;
+ /* faster if pad is a power of two */
+ if (((pad - 1) & pad) == 0)
+ b = b & -pad;
+ else
+ b = b - b % pad;
+ uint32_t size = 1080 * b;
+ uint8_t *data = (uint8_t *)calloc (1, size);
+ return
+ xcb_put_image_checked (xcb_conn_p, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable_id, gc_id,
+ screen_p->width_in_pixels, screen_p->height_in_pixels, 0, 0,
+ 0, 32, size, data);
+}
+#endif
diff --git a/tests/functional/xv_test/xcb_api.h b/tests/functional/xv_test/xcb_api.h
new file mode 100644
index 0000000..5eaf9e5
--- /dev/null
+++ b/tests/functional/xv_test/xcb_api.h
@@ -0,0 +1,80 @@
+#ifndef XV_API_H
+#define XV_API_H
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/xfixes.h>
+
+#include <xcb/xcb_util.h>
+#include "xv_test.h"
+
+typedef struct
+{
+ uint32_t width;
+ uint32_t height;
+} size_s;
+
+typedef struct
+{
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+} rectangle_s;
+
+typedef struct
+{
+ uint32_t fourcc_id;
+ uint16_t num_planes;
+ size_t full_size;
+ size_t sizes[3];
+ uint32_t offsets[3];
+ uint32_t pitches[3];
+ uint32_t width;
+ uint32_t height;
+} image_attr_s;
+
+typedef struct
+{
+ rectangle_s *src_crop_p;
+ rectangle_s *dst_crop_p;
+ image_attr_s *image_p;
+ xcb_shm_seg_t segment;
+} frame_attr_s;
+
+typedef struct
+{
+ xcb_xv_port_t xv_port_id;
+ error_s error;
+} get_xv_port_s;
+
+typedef struct
+{
+ error_s error;
+ image_attr_s image;
+} get_image_attr_s;
+
+typedef struct
+{
+ xcb_window_t window_id;
+ error_s error;
+} get_window_s;
+
+typedef struct
+{
+ xcb_gcontext_t gc_id;
+ error_s error;
+} get_gc_s;
+
+get_gc_s create_gc (xcb_connection_t *xcb_conn_p, xcb_drawable_t drawable_id, xcb_screen_t * screen_p);
+get_window_s create_window (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p);
+
+
+get_image_attr_s get_image_attr(xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+ uint32_t fourcc_id, uint16_t width, uint16_t height);
+get_xv_port_s open_adaptor (xcb_connection_t *xcb_conn_p, xcb_window_t window_id);
+xcb_void_cookie_t put_image (xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+ xcb_window_t window_id, xcb_gcontext_t gc_id, frame_attr_s *frame_p);
+
+xcb_void_cookie_t make_transparent (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p,
+ xcb_drawable_t drawable_id, xcb_gcontext_t gc_id);
+#endif // XV_API_H
diff --git a/tests/functional/xv_test/xv_test.c b/tests/functional/xv_test/xv_test.c
new file mode 100644
index 0000000..e6929c6
--- /dev/null
+++ b/tests/functional/xv_test/xv_test.c
@@ -0,0 +1,219 @@
+#include "xv_test.h"
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xcb/dri2.h>
+#include <xf86drm.h>
+#include <fcntl.h>
+#include "xv_types.h"
+#include <tbm_bufmgr.h>
+#include "data.h"
+#include <sys/time.h>
+#include "test_xv_resize.h"
+
+typedef struct
+{
+ size_t num_tests;
+ test_case_s * test_case_array;
+ error_s * error_array;
+} test_map_s;
+
+error_s
+check_xv (xcb_connection_t *xcb_conn_p)
+{
+ xcb_xv_query_extension_cookie_t xv_cookie;
+ xcb_xv_query_extension_reply_t *xv_reply = NULL;
+ xcb_generic_error_t * error_p = NULL;
+ error_s ret = {};
+ xv_cookie = xcb_xv_query_extension (xcb_conn_p);
+ xv_reply = xcb_xv_query_extension_reply (xcb_conn_p, xv_cookie, &error_p);
+ if (error_p)
+ {
+ ret.error_str = "Can't find xv extension";
+ ret.error_code = error_p->error_code;
+ }
+
+ if (xv_reply)
+ free(xv_reply);
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+error_s
+check_shm (xcb_connection_t *xcb_conn_p)
+{
+ xcb_shm_query_version_cookie_t shm_cookie;
+ xcb_shm_query_version_reply_t *shm_reply_p = NULL;
+ xcb_generic_error_t * error_p = NULL;
+ error_s ret = {};
+ shm_cookie = xcb_shm_query_version (xcb_conn_p);
+ shm_reply_p = xcb_shm_query_version_reply (xcb_conn_p, shm_cookie, &error_p);
+ if (error_p)
+ {
+ ret.error_str = "Can't find shm extension";
+ ret.error_code = error_p->error_code;
+ }
+
+ if (shm_reply_p)
+ free(shm_reply_p);
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+error_s
+check_dri2 (xcb_connection_t *xcb_conn_p)
+{
+ error_s ret = {};
+ xcb_generic_error_t *error_p = NULL;
+ xcb_dri2_query_version_cookie_t xcb_dri2_ck =
+ xcb_dri2_query_version (xcb_conn_p,
+ XCB_DRI2_MAJOR_VERSION,
+ XCB_DRI2_MINOR_VERSION);
+ xcb_dri2_query_version_reply_t * xcb_dri2_reply_p =
+ xcb_dri2_query_version_reply (xcb_conn_p,
+ xcb_dri2_ck,
+ &error_p);
+ if (error_p)
+ {
+ ret.error_str = "Can't find dri2 extension";
+ ret.error_code = error_p->error_code;
+ }
+
+ if (xcb_dri2_reply_p)
+ free(xcb_dri2_reply_p);
+ if (error_p)
+ free(error_p);
+ return ret;
+}
+
+rule_s
+make_rule (xcb_connection_t *xcb_conn_p, xcb_screen_t *screen_p)
+{
+ rule_s ret = {};
+ ret.count_frame_per_change = 2;
+ ret.count_uniqes_frames = 10;
+ ret.frame_per_second = 30;
+ ret.max_width = screen_p->width_in_pixels;
+ ret.max_height = screen_p->height_in_pixels;
+ ret.dst_change = 1;
+ ret.src_change = 0;
+ ret.min_height = 100;
+ ret.min_width = 100;
+ ret.image_width = 640;
+ ret.image_height = 480;
+ ret.image_fourcc = FOURCC_SR32;
+ return ret;
+}
+
+test_map_s
+init_tests (void)
+{
+ test_map_s ret = {};
+ ret.num_tests = 1;
+ ret.test_case_array = calloc(ret.num_tests, sizeof(test_case_s));
+ if (ret.test_case_array == NULL)
+ {
+ fprintf(stderr, "Can't alloc memory for test");
+ ret.num_tests = 0;
+ goto error_close;
+ }
+
+ ret.error_array = calloc(ret.num_tests, sizeof(error_s));
+ if (ret.error_array == NULL)
+ {
+ fprintf(stderr, "Can't alloc memory for test");
+ ret.num_tests = 0;
+ goto error_close;
+ }
+ ret.test_case_array[0] = test_xv_resize_init();
+ return ret;
+error_close:
+ if (ret.test_case_array)
+ free(ret.test_case_array);
+ if (ret.error_array)
+ free(ret.error_array);
+
+ return ret;
+}
+
+int main ()
+{
+ xcb_screen_iterator_t screen_iter;
+ xcb_connection_t *xcb_conn_p;
+ const xcb_setup_t *setup;
+ xcb_screen_t *screen_p;
+ int screen_number;
+ test_map_s tests = {};
+ rule_s rule_p = {};
+ error_s ret;
+ /* getting the connection */
+ xcb_conn_p = xcb_connect (NULL, &screen_number);
+ if (!xcb_conn_p)
+ {
+ fprintf(stderr, "ERROR: can't connect to an X server\n");
+ }
+ ret = check_xv (xcb_conn_p);
+ exit_if_fail (ret);
+ ret = check_shm (xcb_conn_p);
+ exit_if_fail (ret);
+ ret = check_dri2 (xcb_conn_p);
+ exit_if_fail (ret);
+ DBG;
+ /* getting the current screen */
+ setup = xcb_get_setup (xcb_conn_p);
+ screen_p = NULL;
+ screen_iter = xcb_setup_roots_iterator (setup);
+ for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
+ if (screen_number == 0)
+ {
+ screen_p = screen_iter.data;
+ break;
+ }
+ if (!screen_p) {
+ fprintf (stderr, "ERROR: can't get the current screen\n");
+ xcb_disconnect (xcb_conn_p);
+ return -1;
+ }
+ rule_p = make_rule (xcb_conn_p, screen_p);
+ tests = init_tests();
+ if (tests.num_tests == 0)
+ {
+ fprintf (stderr, "Nothing to test. num_tests = 0\n");
+ return 0;
+ }
+ int i;
+ DBG;
+ for (i = 0; i < tests.num_tests; i++)
+ {
+ ret = tests.test_case_array[i].prepare_test(xcb_conn_p, screen_p, rule_p);
+ if (ret.error_str)
+ {
+ tests.error_array[i] = ret;
+ continue;
+ }
+ ret = tests.test_case_array[i].run_test(xcb_conn_p, screen_p, rule_p);
+ if (ret.error_str)
+ {
+ tests.error_array[i] = ret;
+ continue;
+ }
+ ret = tests.test_case_array[i].close_test(xcb_conn_p, screen_p, rule_p);
+ if (ret.error_str)
+ {
+ tests.error_array[i] = ret;
+ continue;
+ }
+ }
+ for (i = 0; i < tests.num_tests; i++)
+ {
+ fprintf(stderr, "%s %d\n", tests.error_array[i].error_str,
+ tests.error_array[i].error_code);
+ }
+ return 0;
+}
diff --git a/tests/functional/xv_test/xv_test.h b/tests/functional/xv_test/xv_test.h
new file mode 100644
index 0000000..3c33e27
--- /dev/null
+++ b/tests/functional/xv_test/xv_test.h
@@ -0,0 +1,111 @@
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <xcb/xcb.h>
+
+#include <xf86drm.h>
+#include <tbm_bufmgr.h>
+
+#include "xv_types.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define max(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+#define min(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a < _b ? _a : _b; })
+
+#define exit_if_fail(error_s) \
+ {if (error_s.error_str) {\
+ fprintf (stderr, "Error: '%s' code: '%d'\n", \
+ error_s.error_str, error_s.error_code); \
+ exit(-1);}}
+
+#define C(b,m) (((b) >> (m)) & 0xFF)
+#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0))
+#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24)
+#define FOURCC_RGB565 FOURCC('R','G','B','P')
+#define FOURCC_RGB32 FOURCC('R','G','B','4')
+#define FOURCC_I420 FOURCC('I','4','2','0')
+#define FOURCC_SR16 FOURCC('S','R','1','6')
+#define FOURCC_SR32 FOURCC('S','R','3','2')
+#define FOURCC_S420 FOURCC('S','4','2','0')
+
+#define FOURCC_SN12 FOURCC('S','N','1','2')
+#define XVIMAGE_SN12 \
+ { \
+ FOURCC_SN12, \
+ XvYUV, \
+ LSBFirst, \
+ {'S','N','1','2', \
+ 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
+ 12, \
+ XvPlanar, \
+ 2, \
+ 0, 0, 0, 0, \
+ 8, 8, 8, \
+ 1, 2, 2, \
+ 1, 2, 2, \
+ {'Y','U','V', \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
+ XvTopToBottom \
+ }
+
+#define DBG \
+{printf("%s %d\n", __FUNCTION__, __LINE__);}
+
+typedef struct
+{
+ uint32_t min_width;
+ uint32_t min_height;
+ uint32_t max_width;
+ uint32_t max_height;
+ int src_change;
+ int dst_change;
+ uint32_t image_width;
+ uint32_t image_height;
+ uint32_t image_fourcc;
+ size_t count_frame_per_change;
+ size_t frame_per_second;
+ size_t count_uniqes_frames;
+ /* TODO: More rules */
+} rule_s;
+
+typedef struct
+{
+ uint8_t error_code;
+ char const * error_str;
+} error_s;
+
+typedef error_s (*prepare_test_case) (xcb_connection_t *, xcb_screen_t *, rule_s);
+typedef error_s (*run_test_case) (xcb_connection_t *, xcb_screen_t *, rule_s);
+typedef error_s (*close_test_case)(xcb_connection_t *, xcb_screen_t *, rule_s);
+
+typedef struct _test_case_s
+{
+ prepare_test_case prepare_test;
+ run_test_case run_test;
+ close_test_case close_test;
+} test_case_s;
+#endif