2 * Copyright (c) 2008-2009 Intel Corporation. All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <sys/types.h>
40 /*currently, if XCheckWindowEvent was called in more than one thread, it would cause
41 * XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
42 * after 87 requests (83 known processed) with 0 events remaining.
44 * X Error of failed request: BadGC (invalid GC parameter)
45 * Major opcode of failed request: 60 (X_FreeGC)
46 * Resource id in failed request: 0x600034
47 * Serial number of failed request: 398
48 * Current serial number in output stream: 399
49 * The root cause is unknown. */
51 #define CHECK_VASTATUS(va_status,func) \
52 if (va_status != VA_STATUS_SUCCESS) { \
53 fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
56 #include "../loadsurface.h"
58 #define SURFACE_NUM 16
60 static void *win_display;
61 static VADisplay va_dpy;
62 static VAConfigID config_id;
63 static VASurfaceID surface_id[SURFACE_NUM];
64 static pthread_mutex_t surface_mutex[SURFACE_NUM];
66 static void *drawable_thread0, *drawable_thread1;
67 static int surface_width = 352, surface_height = 288;
68 static int win_x = 0, win_y = 0;
69 static int win_width = 352, win_height = 288;
70 static int frame_rate = 0;
71 static unsigned long long frame_num_total = ~0;
72 static int check_event = 1;
73 static int put_pixmap = 0;
74 static int test_clip = 0;
75 static int display_field = VA_FRAME_PICTURE;
76 static pthread_mutex_t gmutex;
77 static int box_width = 32;
78 static int multi_thread = 0;
79 static int verbose = 0;
80 static int test_color_conversion = 0;
81 static int csc_src_fourcc = 0, csc_dst_fourcc = 0;
82 static VAImage csc_dst_fourcc_image;
83 static VASurfaceID csc_render_surface;
90 fourcc_map va_fourcc_map[] = {
91 {"YUYV", VA_FOURCC_YUY2},
92 {"YUY2", VA_FOURCC_YUY2},
93 {"NV12", VA_FOURCC_NV12},
94 {"YV12", VA_FOURCC_YV12},
95 {"BGRA", VA_FOURCC_BGRA},
96 {"RGBA", VA_FOURCC_RGBA},
97 {"BGRX", VA_FOURCC_BGRX},
98 {"RGBX", VA_FOURCC_RGBX},
100 unsigned int map_str_to_vafourcc (char * str)
103 for (i=0; i< sizeof(va_fourcc_map)/sizeof(fourcc_map); i++) {
104 if (!strcmp(va_fourcc_map[i].fmt_str, str)) {
105 return va_fourcc_map[i].fourcc;
112 char* map_vafourcc_to_str (unsigned int format)
114 static char unknown_format[] = "unknown-format";
116 for (i=0; i< sizeof(va_fourcc_map)/sizeof(fourcc_map); i++) {
117 if (va_fourcc_map[i].fourcc == format) {
118 return va_fourcc_map[i].fmt_str;
122 return unknown_format;
126 int csc_preparation ()
131 // 1. make sure dst fourcc is supported for vaImage
132 #define MAX_IMAGE_FORMAT_COUNT 10
133 VAImageFormat format_list[MAX_IMAGE_FORMAT_COUNT];
134 int num_formats = 0, find_dst_fourcc = 0;
136 va_status = vaQueryImageFormats(va_dpy, format_list,&num_formats);
137 printf("num_formats: %d\n", num_formats);
138 assert(num_formats<MAX_IMAGE_FORMAT_COUNT);
139 for (i=0; i<num_formats; i++) {
140 if (format_list[i].fourcc == csc_dst_fourcc) {
144 if (!find_dst_fourcc) {
145 test_color_conversion = 0;
146 printf("vaImage doesn't support %s, skip additional color conversion\n", map_vafourcc_to_str(csc_dst_fourcc));
150 // 2. make sure src_fourcc is supported for vaSurface
151 VASurfaceAttrib s_attrib[1];
152 va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc,
154 CHECK_VASTATUS(va_status, "vaCreateConfig");
156 s_attrib[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
157 s_attrib[0].type = VASurfaceAttribPixelFormat;
158 s_attrib[0].value.type = VAGenericValueTypeInteger;
159 s_attrib[0].value.value.i = csc_src_fourcc;
161 va_status = vaGetSurfaceAttributes(va_dpy, config_id, s_attrib, 1);
162 CHECK_VASTATUS(va_status,"vaGetSurfaceAttributes");
163 if (! (s_attrib[0].flags & VA_SURFACE_ATTRIB_SETTABLE)) {
164 printf("vaSurface doesn't support %s, skip additional color conversion\n", map_vafourcc_to_str(csc_src_fourcc));
165 vaDestroyConfig (va_dpy, config_id);
166 test_color_conversion = 0;
170 // 3 create all objs required by csc
171 // 3.1 vaSurface with src fourcc
172 va_status = vaCreateSurfaces(
174 VA_RT_FORMAT_YUV420, surface_width, surface_height,
175 &surface_id[0], SURFACE_NUM,
178 CHECK_VASTATUS(va_status,"vaCreateSurfaces");
180 // 3.2 vaImage with dst fourcc
181 VAImageFormat image_format;
182 image_format.fourcc = csc_dst_fourcc;
183 image_format.byte_order = VA_LSB_FIRST;
184 image_format.bits_per_pixel = 16;
186 va_status = vaCreateImage(va_dpy, &image_format,
187 surface_width, surface_height,
188 &csc_dst_fourcc_image);
189 CHECK_VASTATUS(va_status,"vaCreateImage");
192 // 3.3 create a temp VASurface for final rendering(vaPutSurface)
193 s_attrib[0].value.value.i = VA_FOURCC_NV12;
194 va_status = vaCreateSurfaces(va_dpy, VA_RT_FORMAT_YUV420,
195 surface_width, surface_height,
196 &csc_render_surface, 1,
198 CHECK_VASTATUS(va_status,"vaCreateSurfaces");
202 return test_color_conversion;
205 static VASurfaceID get_next_free_surface(int *index)
207 VASurfaceStatus surface_status;
212 if (multi_thread == 0) {
215 if (i == SURFACE_NUM)
219 return surface_id[i];
222 for (i=0; i<SURFACE_NUM; i++) {
223 surface_status = (VASurfaceStatus)0;
224 vaQuerySurfaceStatus(va_dpy, surface_id[i], &surface_status);
225 if (surface_status == VASurfaceReady)
227 if (0 == pthread_mutex_trylock(&surface_mutex[i]))
236 return VA_INVALID_SURFACE;
238 return surface_id[i];
241 static int upload_source_YUV_once_for_all()
243 VAImage surface_image;
244 void *surface_p=NULL, *U_start,*V_start;
250 for (i=0; i<SURFACE_NUM; i++) {
251 printf("\rLoading data into surface %d.....", i);
252 upload_surface(va_dpy, surface_id[i], box_width_loc, row_shift_loc, 0);
255 if (row_shift_loc==(2*box_width_loc)) row_shift_loc= 0;
263 * Helper function for profiling purposes
265 static unsigned long get_tick_count(void)
268 if (gettimeofday(&tv, NULL))
270 return tv.tv_usec/1000+tv.tv_sec*1000;
273 static void update_clipbox(VARectangle *cliprects, int width, int height)
278 srand((unsigned)time(NULL));
280 cliprects[0].x = (rand() % width);
281 cliprects[0].y = (rand() % height);
282 cliprects[0].width = (rand() % (width - cliprects[0].x));
283 cliprects[0].height = (rand() % (height - cliprects[0].y));
285 cliprects[1].x = (rand() % width);
286 cliprects[1].y = (rand() % height);
287 cliprects[1].width = (rand() % (width - cliprects[1].x));
288 cliprects[1].height = (rand() % (height - cliprects[1].y));
289 printf("\nTest clip (%d,%d, %d x %d) and (%d,%d, %d x %d) \n",
290 cliprects[0].x, cliprects[0].y, cliprects[0].width, cliprects[0].height,
291 cliprects[1].x, cliprects[1].y, cliprects[1].width, cliprects[1].height);
294 static void* putsurface_thread(void *data)
296 int width=win_width, height=win_height;
297 void *drawable = data;
302 unsigned int frame_num=0, start_time, putsurface_time;
303 VARectangle cliprects[2]; /* client supplied clip list */
304 int continue_display = 0;
306 if (drawable == drawable_thread0)
307 printf("Enter into thread0\n\n");
308 if (drawable == drawable_thread1)
309 printf("Enter into thread1\n\n");
313 VASurfaceID surface_id = VA_INVALID_SURFACE;
315 while (surface_id == VA_INVALID_SURFACE)
316 surface_id = get_next_free_surface(&index);
318 if (verbose) printf("Thread: %p Display surface 0x%x,\n", drawable, surface_id);
321 upload_surface(va_dpy, surface_id, box_width, row_shift, display_field);
324 pthread_mutex_lock(&gmutex);
326 start_time = get_tick_count();
327 if ((continue_display == 0) && getenv("FRAME_STOP")) {
329 printf("Press any key to display frame %d...(c/C to continue)\n", frame_num);
331 if (c == 'c' || c == 'C')
332 continue_display = 1;
334 if (test_color_conversion) {
335 static int _put_surface_count = 0;
336 if (_put_surface_count++ %50 == 0) {
337 printf("do additional colorcoversion from %s to %s\n", map_vafourcc_to_str(csc_src_fourcc), map_vafourcc_to_str(csc_dst_fourcc));
339 // get image from surface, csc_src_fourcc to csc_dst_fourcc conversion happens
340 vaStatus = vaGetImage(va_dpy, surface_id, 0, 0,
341 surface_width, surface_height, csc_dst_fourcc_image.image_id);
342 CHECK_VASTATUS(vaStatus,"vaGetImage");
344 // render csc_dst_fourcc image to temp surface
345 vaStatus = vaPutImage(va_dpy, csc_render_surface, csc_dst_fourcc_image.image_id,
346 0, 0, surface_width, surface_height,
347 0, 0, surface_width, surface_height);
348 CHECK_VASTATUS(vaStatus,"vaPutImage");
350 // render the temp surface, it should be same with original surface without color conversion test
351 vaStatus = vaPutSurface(va_dpy, csc_render_surface, CAST_DRAWABLE(drawable),
352 0,0,surface_width,surface_height,
354 (test_clip==0)?NULL:&cliprects[0],
357 CHECK_VASTATUS(vaStatus,"vaPutSurface");
361 vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable),
362 0,0,surface_width,surface_height,
364 (test_clip==0)?NULL:&cliprects[0],
367 CHECK_VASTATUS(vaStatus,"vaPutSurface");
370 putsurface_time += (get_tick_count() - start_time);
373 pthread_mutex_unlock(&gmutex);
375 pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */
377 if ((frame_num % 0xff) == 0) {
378 fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time);
380 update_clipbox(cliprects, width, height);
384 check_window_event(win_display, drawable, &width, &height, &quit);
386 if (multi_thread) { /* reload surface content */
388 if (row_shift==(2*box_width)) row_shift= 0;
391 if (frame_rate != 0) /* rough framerate control */
392 usleep(1000/frame_rate*1000);
395 if (frame_num >= frame_num_total)
399 if (drawable == drawable_thread1)
404 int main(int argc,char **argv)
406 int major_ver, minor_ver;
412 char str_src_fmt[5], str_dst_fmt[5];
414 static struct option long_options[] =
416 {"fmt1", required_argument, NULL, '1'},
417 {"fmt2", required_argument, NULL, '2'},
421 while ((c =getopt_long(argc,argv,"w:h:g:r:d:f:tcep?n:1:2:v", long_options, NULL)) != EOF) {
424 printf("putsurface <options>\n");
425 printf(" -g <widthxheight+x_location+y_location> window geometry\n");
426 printf(" -w/-h resolution of surface\n");
427 printf(" -r <framerate>\n");
428 printf(" -d the dimension of black/write square box, default is 32\n");
429 printf(" -t multi-threads\n");
430 printf(" -c test clipbox\n");
431 printf(" -f <1/2> top field, or bottom field\n");
432 printf(" -1 source format (fourcc) for color conversion test\n");
433 printf(" -2 dest format (fourcc) for color conversion test\n");
434 printf(" --fmt1 same to -1\n");
435 printf(" --fmt2 same to -2\n");
436 printf(" -v verbose output\n");
440 ret = sscanf(optarg, "%dx%d+%d+%d", &win_width, &win_height, &win_x, &win_y);
442 printf("invalid window geometry, must be widthxheight+x_location+y_location\n");
445 printf("Create window at (%d, %d), width = %d, height = %d\n",
446 win_x, win_y, win_width, win_height);
449 frame_rate = atoi(optarg);
452 surface_width = atoi(optarg);
455 surface_height = atoi(optarg);
458 frame_num_total = atoi(optarg);
461 box_width = atoi(optarg);
465 printf("Two threads to do vaPutSurface\n");
477 if (atoi(optarg) == 1) {
478 printf("Display TOP field\n");
479 display_field = VA_TOP_FIELD;
480 } else if (atoi(optarg) == 2) {
481 printf("Display BOTTOM field\n");
482 display_field = VA_BOTTOM_FIELD;
484 printf("The validate input for -f is: 1(top field)/2(bottom field)\n");
487 sscanf(optarg, "%s", str_src_fmt);
488 csc_src_fourcc = map_str_to_vafourcc (str_src_fmt);
490 if (!csc_src_fourcc) {
491 printf("invalid fmt1: %s\n", str_src_fmt );
496 sscanf(optarg, "%s", str_dst_fmt);
497 csc_dst_fourcc = map_str_to_vafourcc (str_dst_fmt);
499 if (!csc_dst_fourcc) {
500 printf("invalid fmt1: %s\n", str_dst_fmt );
506 printf("Enable verbose output\n");
511 if (csc_src_fourcc && csc_dst_fourcc) {
512 test_color_conversion = 1;
515 win_display = (void *)open_display();
516 if (win_display == NULL) {
517 fprintf(stderr, "Can't open the connection of display!\n");
520 create_window(win_display, win_x, win_y, win_width, win_height);
522 va_dpy = vaGetDisplay(win_display);
523 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
524 CHECK_VASTATUS(va_status, "vaInitialize");
526 if (test_color_conversion) {
527 ret = csc_preparation();
529 if (!test_color_conversion || !ret ) {
530 va_status = vaCreateSurfaces(
532 VA_RT_FORMAT_YUV420, surface_width, surface_height,
533 &surface_id[0], SURFACE_NUM,
537 CHECK_VASTATUS(va_status, "vaCreateSurfaces");
538 if (multi_thread == 0) /* upload the content for all surfaces */
539 upload_source_YUV_once_for_all();
542 pthread_mutex_init(&gmutex, NULL);
544 for(i = 0; i< SURFACE_NUM; i++)
545 pthread_mutex_init(&surface_mutex[i], NULL);
547 if (multi_thread == 1)
548 ret = pthread_create(&thread1, NULL, putsurface_thread, (void*)drawable_thread1);
550 putsurface_thread((void *)drawable_thread0);
552 if (multi_thread == 1)
553 pthread_join(thread1, (void **)&ret);
554 printf("thread1 is free\n");
556 if (test_color_conversion) {
557 // destroy temp surface/image
558 va_status = vaDestroySurfaces(va_dpy, &csc_render_surface, 1);
559 CHECK_VASTATUS(va_status,"vaDestroySurfaces");
561 va_status = vaDestroyImage(va_dpy, csc_dst_fourcc_image.image_id);
562 CHECK_VASTATUS(va_status,"vaDestroyImage");
563 vaDestroyConfig (va_dpy, config_id);
566 vaDestroySurfaces(va_dpy,&surface_id[0],SURFACE_NUM);
569 close_display(win_display);