test: add color conversion test option in putsurface
[platform/upstream/libva.git] / test / putsurface / putsurface_common.c
1 /*
2  * Copyright (c) 2008-2009 Intel Corporation. All Rights Reserved.
3  *
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:
11  * 
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  * 
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.
23  */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <getopt.h>
29
30 #include <sys/time.h>
31
32 #include <unistd.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <assert.h>
38 #include <pthread.h>
39
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.
43  *
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. */
50
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__); \
54     exit(1);                                                            \
55 }
56 #include "../loadsurface.h"
57
58 #define SURFACE_NUM 16
59
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];
65
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;
84
85
86 typedef struct {
87     char* fmt_str;
88     unsigned int fourcc;
89 } fourcc_map;
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},
99 };
100 unsigned int map_str_to_vafourcc (char * str)
101 {
102     int i;
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;
106         }
107     }
108
109     return 0;
110
111 }
112 char* map_vafourcc_to_str (unsigned int format)
113 {
114     static char unknown_format[] = "unknown-format";
115     int i;
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;
119         }
120     }
121
122     return unknown_format;
123
124 }
125
126 int csc_preparation ()
127 {
128     VAStatus va_status;
129     int i;
130     
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;
135     
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) {
141             find_dst_fourcc = 1;
142         }
143     }
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));
147         goto cleanup;
148     }
149
150     // 2. make sure src_fourcc is supported for vaSurface
151     VASurfaceAttrib s_attrib[1];
152     va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc,
153                                           NULL, 0,&config_id);
154     CHECK_VASTATUS(va_status, "vaCreateConfig");
155
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;
160
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;
167         goto cleanup;
168     }
169
170     // 3 create all objs required by csc
171     // 3.1 vaSurface with src fourcc
172     va_status = vaCreateSurfaces(
173         va_dpy,
174         VA_RT_FORMAT_YUV420, surface_width, surface_height,
175         &surface_id[0], SURFACE_NUM,
176         s_attrib, 1
177     );
178     CHECK_VASTATUS(va_status,"vaCreateSurfaces");
179
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;
185     
186     va_status = vaCreateImage(va_dpy, &image_format,
187                     surface_width, surface_height,
188                     &csc_dst_fourcc_image);
189     CHECK_VASTATUS(va_status,"vaCreateImage");
190     
191
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, 
197                                  s_attrib, 1);
198     CHECK_VASTATUS(va_status,"vaCreateSurfaces");
199
200
201 cleanup:
202     return test_color_conversion;
203 }
204
205 static VASurfaceID get_next_free_surface(int *index)
206 {
207     VASurfaceStatus surface_status;
208     int i;
209
210     assert(index);
211
212     if (multi_thread == 0) {
213         i = *index;
214         i++;
215         if (i == SURFACE_NUM)
216             i = 0;
217         *index = i;
218
219         return surface_id[i];
220     }
221     
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)
226         {
227             if (0 == pthread_mutex_trylock(&surface_mutex[i]))
228             {
229                 *index = i;
230                 break;
231             }
232         }
233     }
234
235     if (i==SURFACE_NUM)
236         return VA_INVALID_SURFACE;
237     else
238         return surface_id[i];
239 }
240
241 static int upload_source_YUV_once_for_all()
242 {
243     VAImage surface_image;
244     void *surface_p=NULL, *U_start,*V_start;
245     VAStatus va_status;
246     int box_width_loc=8;
247     int row_shift_loc=0;
248     int i;
249     
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);
253         
254         row_shift_loc++;
255         if (row_shift_loc==(2*box_width_loc)) row_shift_loc= 0;
256     }
257     printf("\n");
258
259     return 0;
260 }
261
262 /*
263  * Helper function for profiling purposes
264  */
265 static unsigned long get_tick_count(void)
266 {
267     struct timeval tv;
268     if (gettimeofday(&tv, NULL))
269         return 0;
270     return tv.tv_usec/1000+tv.tv_sec*1000;
271 }
272
273 static void update_clipbox(VARectangle *cliprects, int width, int height)
274 {
275     if (test_clip == 0)
276         return;
277             
278     srand((unsigned)time(NULL));
279                 
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));
284
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);
292 }
293
294 static void* putsurface_thread(void *data)
295 {
296     int width=win_width, height=win_height;
297     void *drawable = data;
298     int quit = 0;
299     VAStatus vaStatus;
300     int row_shift = 0;
301     int index = 0;
302     unsigned int frame_num=0, start_time, putsurface_time;
303     VARectangle cliprects[2]; /* client supplied clip list */
304     int continue_display = 0;
305     
306     if (drawable == drawable_thread0)
307         printf("Enter into thread0\n\n");
308     if (drawable == drawable_thread1)
309         printf("Enter into thread1\n\n");
310     
311     putsurface_time = 0;
312     while (!quit) {
313         VASurfaceID surface_id = VA_INVALID_SURFACE;
314         
315         while (surface_id == VA_INVALID_SURFACE)
316             surface_id = get_next_free_surface(&index);
317
318         if (verbose) printf("Thread: %p Display surface 0x%x,\n", drawable, surface_id);
319
320         if (multi_thread)
321             upload_surface(va_dpy, surface_id, box_width, row_shift, display_field);
322
323         if (check_event)
324             pthread_mutex_lock(&gmutex);
325         
326         start_time = get_tick_count();
327         if ((continue_display == 0) && getenv("FRAME_STOP")) {
328             char c;
329             printf("Press any key to display frame %d...(c/C to continue)\n", frame_num);
330             c = getchar();
331             if (c == 'c' || c == 'C')
332                 continue_display = 1;
333         }
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));
338             }
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");
343             
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");
349             
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,
353                                     0,0,width,height,
354                                     (test_clip==0)?NULL:&cliprects[0],
355                                     (test_clip==0)?0:2,
356                                     display_field);
357             CHECK_VASTATUS(vaStatus,"vaPutSurface");
358     
359         }
360         else {
361             vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable),
362                                     0,0,surface_width,surface_height,
363                                     0,0,width,height,
364                                     (test_clip==0)?NULL:&cliprects[0],
365                                     (test_clip==0)?0:2,
366                                     display_field);
367             CHECK_VASTATUS(vaStatus,"vaPutSurface");
368         }
369     
370         putsurface_time += (get_tick_count() - start_time);
371         
372         if (check_event)
373             pthread_mutex_unlock(&gmutex);
374         
375         pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */
376         
377         if ((frame_num % 0xff) == 0) {
378             fprintf(stderr, "%.2f FPS             \r", 256000.0 / (float)putsurface_time);
379             putsurface_time = 0;
380             update_clipbox(cliprects, width, height);
381         }
382         
383         if (check_event)
384             check_window_event(win_display, drawable, &width, &height, &quit);
385
386         if (multi_thread) { /* reload surface content */
387             row_shift++;
388             if (row_shift==(2*box_width)) row_shift= 0;
389         }
390         
391         if (frame_rate != 0) /* rough framerate control */
392             usleep(1000/frame_rate*1000);
393
394         frame_num++;
395         if (frame_num >= frame_num_total)
396             quit = 1;
397     }
398     
399     if (drawable == drawable_thread1)    
400         pthread_exit(NULL);
401     
402     return 0;
403 }
404 int main(int argc,char **argv)
405 {
406     int major_ver, minor_ver;
407     VAStatus va_status;
408     pthread_t thread1;
409     int ret;
410     char c;
411     int i;
412     char str_src_fmt[5], str_dst_fmt[5];
413
414     static struct option long_options[] =
415                  {
416                    {"fmt1",  required_argument,       NULL, '1'},
417                    {"fmt2",  required_argument,       NULL, '2'},
418                    {0, 0, 0, 0}
419                  };
420
421     while ((c =getopt_long(argc,argv,"w:h:g:r:d:f:tcep?n:1:2:v", long_options, NULL)) != EOF) {
422         switch (c) {
423             case '?':
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");
437                 exit(0);
438                 break;
439             case 'g':
440                 ret = sscanf(optarg, "%dx%d+%d+%d", &win_width, &win_height, &win_x, &win_y);
441                 if (ret != 4) {
442                     printf("invalid window geometry, must be widthxheight+x_location+y_location\n");
443                     exit(0);
444                 } else
445                     printf("Create window at (%d, %d), width = %d, height = %d\n",
446                            win_x, win_y, win_width, win_height);
447                 break;
448             case 'r':
449                 frame_rate = atoi(optarg);
450                 break;
451             case 'w':
452                 surface_width = atoi(optarg);
453                 break;
454             case 'h':
455                 surface_height = atoi(optarg);
456                 break;
457             case 'n':
458                 frame_num_total = atoi(optarg);
459                 break;
460             case 'd':
461                 box_width = atoi(optarg);
462                 break;
463             case 't':
464                 multi_thread = 1;
465                 printf("Two threads to do vaPutSurface\n");
466                 break;
467             case 'e':
468                 check_event = 0;
469                 break;
470             case 'p':
471                 put_pixmap = 1;
472                 break;
473             case 'c':
474                 test_clip = 1;
475                 break;
476             case 'f':
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;
483                 } else
484                     printf("The validate input for -f is: 1(top field)/2(bottom field)\n");
485                 break;
486             case '1':
487                 sscanf(optarg, "%s", str_src_fmt);
488                 csc_src_fourcc = map_str_to_vafourcc (str_src_fmt);
489                 
490                                 if (!csc_src_fourcc) {
491                     printf("invalid fmt1: %s\n", str_src_fmt );
492                     exit(0);
493                 }
494                 break;
495             case '2':
496                 sscanf(optarg, "%s", str_dst_fmt);
497                 csc_dst_fourcc = map_str_to_vafourcc (str_dst_fmt);
498                 
499                                 if (!csc_dst_fourcc) {
500                     printf("invalid fmt1: %s\n", str_dst_fmt );
501                     exit(0);
502                 }
503                 break;
504             case 'v':
505                 verbose = 1;
506                 printf("Enable verbose output\n");
507                 break;
508         }
509     }
510
511     if (csc_src_fourcc && csc_dst_fourcc) {
512         test_color_conversion = 1;
513     }
514     
515     win_display = (void *)open_display();
516     if (win_display == NULL) {
517         fprintf(stderr, "Can't open the connection of display!\n");
518         exit(-1);
519     }
520     create_window(win_display, win_x, win_y, win_width, win_height);
521
522     va_dpy = vaGetDisplay(win_display);
523     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
524     CHECK_VASTATUS(va_status, "vaInitialize");
525
526     if (test_color_conversion) {
527         ret = csc_preparation();
528     }
529     if (!test_color_conversion || !ret ) {
530         va_status = vaCreateSurfaces(
531             va_dpy,
532             VA_RT_FORMAT_YUV420, surface_width, surface_height,
533             &surface_id[0], SURFACE_NUM,
534             NULL, 0
535         );
536         }
537     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
538     if (multi_thread == 0) /* upload the content for all surfaces */
539         upload_source_YUV_once_for_all();
540     
541     if (check_event)
542         pthread_mutex_init(&gmutex, NULL);
543    
544     for(i = 0; i< SURFACE_NUM; i++)
545         pthread_mutex_init(&surface_mutex[i], NULL);
546     
547     if (multi_thread == 1) 
548         ret = pthread_create(&thread1, NULL, putsurface_thread, (void*)drawable_thread1);
549
550     putsurface_thread((void *)drawable_thread0);
551
552     if (multi_thread == 1) 
553         pthread_join(thread1, (void **)&ret);
554     printf("thread1 is free\n");
555
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");
560         
561         va_status = vaDestroyImage(va_dpy, csc_dst_fourcc_image.image_id);
562         CHECK_VASTATUS(va_status,"vaDestroyImage");
563         vaDestroyConfig (va_dpy, config_id);
564     }
565     
566     vaDestroySurfaces(va_dpy,&surface_id[0],SURFACE_NUM);    
567     vaTerminate(va_dpy);
568
569     close_display(win_display);
570     
571     return 0;
572 }