e7ee5257f097e23bde4d862cc99aec4f6512b918
[platform/core/uifw/libtdm.git] / tools / tdm_test_server.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <signal.h>
40 #include <poll.h>
41 #include <errno.h>
42 #include <time.h>
43 #include <stdint.h>
44
45 #include <tbm_surface.h>
46 #include <tbm_surface_internal.h>
47
48 #include <tdm.h>
49 #include <tdm_log.h>
50 #include <tdm_list.h>
51 #include <tdm_helper.h>
52 #include <tdm_backend.h>
53
54 #include "tdm_macro.h"
55 #include "tdm_private.h"
56 #include "buffers.h"
57
58 ////////////////////////////////////////////////////////////////////////////////
59 struct typestrings {
60         int type;
61         const char *string;
62         const char *desc;
63 };
64
65 struct optstrings {
66         int  type;
67         const char *opt;
68         const char *desc;
69         const char *arg;
70         const char *ex;
71 };
72
73 enum {
74         OPT_QRY,
75         OPT_TST,
76         OPT_GEN,
77 };
78
79 static struct typestrings typestrs[] = {
80         {OPT_QRY, "Query",          NULL},
81         {OPT_TST, "Test",           NULL},
82         {OPT_GEN, "General",        NULL},
83 };
84
85 static struct optstrings optstrs[] = {
86         {
87                 OPT_QRY, "q", "show tdm output, layer information",
88                 NULL, NULL
89         },
90         {
91                 OPT_TST, "a", "set all layer objects for all connected outputs",
92                 NULL, NULL
93         },
94         {
95                 OPT_TST, "o", "set a mode for a output object",
96                 "<output_idx>@<mode>[&<refresh>]", "0@1920x1080"
97         },
98         {
99                 OPT_TST, "l", "set a layer object",
100                 "<layer_idx>[:<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>]]~<w>x<h>[+<x>+<y>][*<transform>]", NULL
101         },
102         {
103                 OPT_TST, "p", "set a PP object.\n\t\t'-l' is used to show the result on screen.",
104                 "<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>]~<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>][*<transform>][&<fps>]", NULL
105         },
106         {
107                 OPT_TST, "c", "catpure a output object or a layer object.\n\t\t'-l' is used to show the result on screen.",
108                 "<output_idx>[,<layer_idx>]~<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>][*<transform>]", NULL
109         },
110         {
111                 OPT_GEN, "w", "set the property of a object",
112                 "<prop_name>:<value>", NULL
113         },
114         {
115                 OPT_GEN, "b", "set the fill(smtpe,tiles,plain) and framebuffer type(scanout,noncachable,wc)",
116                 "<fill>[:<buf_flag>[,<buf_flag2>[,...]]]", NULL
117         },
118         {
119                 OPT_GEN, "v", "update layers every vblank",
120                 NULL, NULL
121         },
122 };
123
124 struct usagestring {
125         const char *string;
126         const char *desc;
127 };
128
129 static struct usagestring usages[] = {
130         {
131                 "-q",
132                 NULL
133         },
134         {
135                 "-a -b plain",
136                 "test all outputs, layers with plain buffers"
137         },
138         {
139                 "-o 0@1920x1080",
140                 "Set the \"1920x1080\" mode to the output 0. And show a buffer via a primary layer of the output 0"
141         },
142         {
143                 "-o 0@1920x1080 -l 1~640x480+50+100",
144                 "Create the 640x480 buffer and show it in the (50,100) pos of screen via the layer 1"
145         },
146         {
147                 "-p 320x240@NV12~480x360+80+40,640x480@AR24 -l 1~640x480+50+100",
148                 "Convert the 320x240@NV12 buffer to the 640x480@AR24 buffer(480x360+80+40) and show the result via the layer 1"
149         },
150 };
151
152 static void
153 usage(char *app_name)
154 {
155         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
156         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
157         int usages_size = sizeof(usages) / sizeof(struct usagestring);
158         int t;
159
160         printf("usage: %s \n\n", app_name);
161
162         for (t = 0; t < type_size; t++) {
163                 int o, f = 1;
164
165                 for (o = 0; o < opt_size; o++)
166                         if (optstrs[o].type == typestrs[t].type) {
167                                 if (f == 1)
168                                         printf(" %s options: %s\n\n", typestrs[t].string, (typestrs[t].desc) ? : "");
169                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
170                                 if (optstrs[o].arg)
171                                         printf("\t\t  %s\n", optstrs[o].arg);
172                                 if (optstrs[o].ex)
173                                         printf("\t\t  ex) %s\n", optstrs[o].ex);
174                                 f = 0;
175                         }
176                 printf("\n");
177         }
178
179         printf(" For example)\n\n");
180
181         for (t = 0; t < usages_size; t++) {
182                 printf("    $ %s %s\n", app_name, usages[t].string);
183                 printf("\t%s\n", usages[t].desc);
184         }
185         printf("\n");
186         exit(0);
187 }
188
189 ////////////////////////////////////////////////////////////////////////////////
190
191 static const char *tdm_buf_flag_names[] = {
192         "scanout",
193         "noncachable",
194         "wc",
195 };
196 TDM_BIT_NAME_FB(buf_flag)
197
198 #define DEFAULT_FORMAT  TBM_FORMAT_ARGB8888
199
200 #define print_size(s) \
201         printf("%dx%d", (s)->h, (s)->v)
202 #define print_pos(p) \
203         printf("%dx%d+%d+%d", (p)->w, (p)->h, (p)->x, (p)->y)
204 #define print_format(f) \
205         if (f) printf("%c%c%c%c", FOURCC_STR(f)); \
206         else printf("NONE")
207 #define print_config(c) \
208         do { \
209                 print_size(&(c)->size); \
210                 printf(" "); \
211                 print_pos(&(c)->pos); \
212                 printf(" "); \
213                 print_format((c)->format); \
214         } while (0)
215 #define print_prop(w) \
216         printf("%s(%d)", (w)->name, ((w)->value).u32)
217
218 typedef struct _tdm_test_server tdm_test_server;
219 typedef struct _tdm_test_server_layer tdm_test_server_layer;
220 typedef struct _tdm_test_server_capture tdm_test_server_capture;
221
222 typedef struct _tdm_test_server_prop {
223         /* args */
224         char name[TDM_NAME_LEN];
225         tdm_value value;
226
227         /* variables for test */
228         struct list_head link;
229 } tdm_test_server_prop;
230
231 typedef struct _tdm_test_server_buffer {
232         /* variables for test */
233         tbm_surface_h b;
234         int in_use;
235         tdm_test_server_layer *l;
236
237         tdm_test_server_capture *c;
238         tdm_buffer_release_handler done;
239 } tdm_test_server_buffer;
240
241 typedef struct _tdm_test_server_output {
242         /* args */
243         int idx;
244         char mode[TDM_NAME_LEN];
245         int refresh;
246
247         /* variables for test */
248         struct list_head link;
249         struct list_head prop_list;
250         struct list_head layer_list;
251         tdm_test_server *data;
252         tdm_output *output;
253
254         int fill_primary_layer;
255 } tdm_test_server_output;
256
257 typedef struct _tdm_test_server_pp {
258         /* args */
259         tdm_info_pp info;
260         int fps;
261
262         /* variables for test */
263         struct list_head link;
264         tdm_test_server *data;
265         tdm_test_server_layer *l;
266         tdm_pp *pp;
267         tbm_surface_h bufs[6];
268         int buf_idx;
269
270         tdm_event_loop_source *timer_source;
271 } tdm_test_server_pp;
272
273 struct _tdm_test_server_capture {
274         /* args */
275         int output_idx;
276         int layer_idx;
277         tdm_info_capture info;
278
279         /* variables for test */
280         struct list_head link;
281         tdm_test_server *data;
282         tdm_test_server_layer *l;
283         tdm_capture *capture;
284 };
285
286 struct _tdm_test_server_layer {
287         /* args */
288         int idx;
289         tdm_info_layer info;
290
291         /* variables for test */
292         struct list_head link;
293         struct list_head prop_list;
294         tdm_test_server *data;
295         tdm_test_server_output *o;
296         tdm_layer *layer;
297         int is_primary;
298         tdm_test_server_pp *owner_p;
299         tdm_test_server_capture *owner_c;
300         tbm_surface_h bufs[3];
301         int buf_idx;
302 };
303
304 struct _tdm_test_server {
305         /* args */
306         int do_query;
307         int do_all;
308         int do_vblank;
309         int bflags;
310         int b_fill;
311
312         /* variables for test */
313         struct list_head output_list;
314         struct list_head pp_list;
315         struct list_head capture_list;
316         tdm_display *display;
317 };
318
319 static void run_test(tdm_test_server *data);
320 static void output_setup(tdm_test_server_output *o);
321 static void layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b);
322 static void capture_attach(tdm_test_server_capture *c, tbm_surface_h b);
323
324 static char*
325 parse_size(tdm_size *size, char *arg)
326 {
327         char *end;
328         size->h = strtol(arg, &end, 10);
329         TDM_EXIT_IF_FAIL(*end == 'x');
330         arg = end + 1;
331         size->v = strtol(arg, &end, 10);
332         return end;
333 }
334
335 static char*
336 parse_pos(tdm_pos *pos, char *arg)
337 {
338         char *end;
339         pos->w = strtol(arg, &end, 10);
340         TDM_EXIT_IF_FAIL(*end == 'x');
341         arg = end + 1;
342         pos->h = strtol(arg, &end, 10);
343         if (*end == '+') {
344                 arg = end + 1;
345                 pos->x = strtol(arg, &end, 10);
346                 TDM_EXIT_IF_FAIL(*end == '+');
347                 arg = end + 1;
348                 pos->y = strtol(arg, &end, 10);
349         }
350         return end;
351 }
352
353 static char*
354 parse_config(tdm_info_config *config, char *arg)
355 {
356         char *end;
357         end = parse_pos(&config->pos, arg);
358         if (*end == ',') {
359                 arg = end + 1;
360                 end = parse_size(&config->size, arg);
361         }
362         if (*end == '@') {
363                 char temp[32];
364                 arg = end + 1;
365                 end = strtostr(temp, 32, arg, TDM_DELIM);
366                 config->format = FOURCC_ID(temp);
367         }
368         return end;
369 }
370
371 static void
372 parse_arg_o(tdm_test_server_output *o, char *arg)
373 {
374         char *end;
375         TDM_EXIT_IF_FAIL(arg != NULL);
376         o->idx = strtol(arg, &end, 10);
377         TDM_EXIT_IF_FAIL(*end == '@');
378         arg = end + 1;
379         end = strtostr(o->mode, TDM_NAME_LEN, arg, TDM_DELIM);
380         if (*end == ',') {
381                 arg = end + 1;
382                 o->refresh = strtol(arg, &end, 10);
383         }
384 }
385
386 static void
387 parse_arg_p(tdm_test_server_pp *p, char *arg)
388 {
389         tdm_info_pp *pp_info = &p->info;
390         char *end;
391         TDM_EXIT_IF_FAIL(arg != NULL);
392         end = parse_config(&pp_info->src_config, arg);
393         TDM_EXIT_IF_FAIL(*end == '~');
394         arg = end + 1;
395         end = parse_config(&pp_info->dst_config, arg);
396         if (*end == '*') {
397                 arg = end + 1;
398                 pp_info->transform = strtol(arg, &end, 10);
399         }
400         if (*end == '&') {
401                 arg = end + 1;
402                 p->fps = strtol(arg, &end, 10);
403         }
404 }
405
406 static void
407 parse_arg_c(tdm_test_server_capture *c, char *arg)
408 {
409         tdm_info_capture *capture_info = &c->info;
410         char *end;
411         TDM_EXIT_IF_FAIL(arg != NULL);
412         c->output_idx = strtol(arg, &end, 10);
413         if (*end == ',') {
414                 arg = end + 1;
415                 c->layer_idx = strtol(arg, &end, 10);
416         }
417         TDM_EXIT_IF_FAIL(*end == '~');
418         arg = end + 1;
419         end = parse_config(&capture_info->dst_config, arg);
420         if (*end == '*') {
421                 arg = end + 1;
422                 capture_info->transform = strtol(arg, &end, 10);
423         }
424 }
425
426 static void
427 parse_arg_l(tdm_test_server_layer *l, char *arg)
428 {
429         tdm_info_layer *layer_info = &l->info;
430         char *end;
431         TDM_EXIT_IF_FAIL(arg != NULL);
432         l->idx = strtol(arg, &end, 10);
433         if (*end == ':') {
434                 arg = end + 1;
435                 end = parse_config(&layer_info->src_config, arg);
436         }
437         TDM_EXIT_IF_FAIL(*end == '~');
438         arg = end + 1;
439         end = parse_pos(&layer_info->dst_pos, arg);
440         if (*end == '*') {
441                 arg = end + 1;
442                 layer_info->transform = strtol(arg, &end, 10);
443         }
444 }
445
446 static void
447 parse_arg_w(tdm_test_server_prop *w, char *arg)
448 {
449         char *end;
450         TDM_EXIT_IF_FAIL(arg != NULL);
451         end = strtostr(w->name, TDM_PATH_LEN, arg, TDM_DELIM);
452         TDM_EXIT_IF_FAIL(*end == ':');
453         arg = end + 1;
454         w->value.u32 = strtol(arg, &end, 10);
455 }
456
457 static void
458 parse_arg_b(tdm_test_server *data, char *arg)
459 {
460         char *end = arg;
461         char temp[TDM_NAME_LEN] = {0,};
462         TDM_EXIT_IF_FAIL(arg != NULL);
463
464         end = strtostr(temp, 32, arg, TDM_DELIM);
465         if (!strncmp(temp, "smpte", 5))
466                 data->b_fill = PATTERN_SMPTE;
467         else if (!strncmp(temp, "tiles", 5))
468                 data->b_fill = PATTERN_TILES;
469         else if (!strncmp(temp, "plain", 5))
470                 data->b_fill = PATTERN_PLAIN;
471         else {
472                 printf("'%s': unknown flag\n", temp);
473                 exit(0);
474         }
475
476         if (*arg == ':') {
477                 data->bflags = 0;
478                 arg = end + 1;
479                 snprintf(temp, TDM_NAME_LEN, "%s", arg);
480                 arg = strtok_r(temp, ",", &end);
481                 while (arg) {
482                         if (!strncmp(arg, "default", 7))
483                                 printf("Ignore '%s' flag\n", arg);
484                         else if (!strncmp(arg, "scanout", 7))
485                                 data->bflags |= TBM_BO_SCANOUT;
486                         else if (!strncmp(arg, "noncachable", 11))
487                                 data->bflags |= TBM_BO_NONCACHABLE;
488                         else if (!strncmp(arg, "wc", 2))
489                                 data->bflags |= TBM_BO_WC;
490                         else {
491                                 printf("'%s': unknown flag\n", arg);
492                                 exit(0);
493                         }
494                         arg = strtok_r(NULL, ",", &end);
495                 }
496         }
497 }
498
499 static void
500 parse_args(tdm_test_server *data, int argc, char *argv[])
501 {
502         tdm_test_server_output *o = NULL;
503         tdm_test_server_layer *l = NULL;
504         tdm_test_server_pp *p = NULL;
505         tdm_test_server_capture *c = NULL;
506         tdm_test_server_prop *w = NULL;
507         void *last_option = NULL;
508         void *last_object = NULL;
509         int i;
510
511         if (argc < 2) {
512                 usage(argv[0]);
513                 exit(0);
514         }
515
516         for (i = 1; i < argc; i++) {
517                 if (!strncmp(argv[i] + 1, "q", 1)) {
518                         data->do_query = 1;
519                         return;
520                 } else if (!strncmp(argv[i] + 1, "a", 1)) {
521                         data->do_all = 1;
522                 } else if (!strncmp(argv[i] + 1, "o", 1)) {
523                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
524                         o = calloc(1, sizeof * o);
525                         TDM_EXIT_IF_FAIL(o != NULL);
526                         o->data = data;
527                         LIST_INITHEAD(&o->layer_list);
528                         LIST_INITHEAD(&o->prop_list);
529                         LIST_ADDTAIL(&o->link, &data->output_list);
530                         parse_arg_o(o, argv[++i]);
531                         last_object = o;
532                 } else if (!strncmp(argv[i] + 1, "p", 1)) {
533                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
534                         p = calloc(1, sizeof * p);
535                         TDM_EXIT_IF_FAIL(p != NULL);
536                         p->data = data;
537                         p->fps = 30;   /* default 30 fps */
538                         LIST_ADDTAIL(&p->link, &data->pp_list);
539                         parse_arg_p(p, argv[++i]);
540                         last_option = p;
541                 } else if (!strncmp(argv[i] + 1, "c", 1)) {
542                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
543                         c = calloc(1, sizeof * c);
544                         TDM_EXIT_IF_FAIL(c != NULL);
545                         c->data = data;
546                         c->output_idx = -1;
547                         c->layer_idx = -1;
548                         LIST_ADDTAIL(&c->link, &data->capture_list);
549                         parse_arg_c(c, argv[++i]);
550                         last_option = c;
551                 } else if (!strncmp(argv[i] + 1, "l", 1)) {
552                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
553                         if (!o) {
554                                 o = calloc(1, sizeof * o);
555                                 TDM_EXIT_IF_FAIL(o != NULL);
556                                 o->data = data;
557                                 LIST_INITHEAD(&o->layer_list);
558                                 LIST_INITHEAD(&o->prop_list);
559                                 LIST_ADDTAIL(&o->link, &data->output_list);
560                         }
561                         l = calloc(1, sizeof * l);
562                         TDM_EXIT_IF_FAIL(l != NULL);
563                         LIST_INITHEAD(&l->prop_list);
564                         LIST_ADDTAIL(&l->link, &o->layer_list);
565                         l->data = data;
566                         l->o = o;
567                         parse_arg_l(l, argv[++i]);
568                         if (p && last_option == p) {
569                                 p->l = l;
570                                 l->owner_p = p;
571                         } else if (c && last_option == c) {
572                                 c->l = l;
573                                 l->owner_c = c;
574                         }
575                         last_object = l;
576                 } else if (!strncmp(argv[i] + 1, "w", 1)) {
577                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
578                         if (!last_object)
579                                 goto no_object;
580                         w = calloc(1, sizeof * w);
581                         TDM_EXIT_IF_FAIL(w != NULL);
582                         if (o && last_object == o)
583                                 LIST_ADDTAIL(&w->link, &o->prop_list);
584                         else if (l && last_object == l)
585                                 LIST_ADDTAIL(&w->link, &l->prop_list);
586                         parse_arg_w(w, argv[++i]);
587                 } else if (!strncmp(argv[i] + 1, "b", 1)) {
588                         parse_arg_b(data, argv[++i]);
589                 } else if (!strncmp(argv[i] + 1, "v", 1)) {
590                         data->do_vblank = 1;
591                 } else {
592                         usage(argv[0]);
593                         exit(0);
594                 }
595         }
596
597         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
598                 if (!p->l)
599                         goto no_layer;
600         }
601         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
602                 if (!c->l)
603                         goto no_layer;
604         }
605
606         return;
607 no_layer:
608         printf("Use '-l' to set a layer for '-p' or '-c'.\n");
609         exit(0);
610 no_object:
611         printf("Use '-o' or '-l' to set a object first.\n");
612         exit(0);
613 all:
614         printf("Can't use '-%s' with '-a'.\n", argv[i] + 1);
615         exit(0);
616 }
617
618 static void
619 interpret_args(tdm_test_server *data)
620 {
621         tdm_test_server_output *o = NULL;
622         tdm_test_server_layer *l = NULL;
623         tdm_error ret;
624
625         /* create the objects of outputs */
626         if (data->do_all) {
627                 int i, output_count;
628
629                 ret = tdm_display_get_output_count(data->display, &output_count);
630                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
631
632                 for (i = 0; i < output_count; i++) {
633                         tdm_output *output = tdm_display_get_output(data->display, i, NULL);
634                         tdm_output_conn_status status;
635                         tdm_output_get_conn_status(output, &status);
636                         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
637                                 continue;
638                         o = calloc(1, sizeof * o);
639                         TDM_EXIT_IF_FAIL(o != NULL);
640                         o->data = data;
641                         LIST_INITHEAD(&o->layer_list);
642                         LIST_INITHEAD(&o->prop_list);
643                         LIST_ADDTAIL(&o->link, &data->output_list);
644                         o->idx = i;
645                         o->fill_primary_layer = 1;
646                 }
647         }
648
649         /* check if the primary layer object exists */
650         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
651                 tdm_output *output;
652                 const tdm_output_mode *mode;
653                 int j, layer_count, primary_index = 0;
654                 tdm_test_server_layer *primary_l = NULL;
655
656                 output_setup(o);
657
658                 output = tdm_display_get_output(data->display, o->idx, &ret);
659                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
660                 ret = tdm_output_get_mode(output, &mode);
661                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
662                 ret = tdm_output_get_layer_count(output, &layer_count);
663                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
664                 ret = tdm_output_get_primary_index(output, &primary_index);
665                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
666
667                 if (LIST_IS_EMPTY(&o->layer_list))
668                         o->fill_primary_layer = 1;
669                 else {
670                         LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
671                                 if (l->idx == primary_index) {
672                                         l->is_primary = 1;
673                                         o->fill_primary_layer = 1;
674                                         primary_l = l;
675                                         break;
676                                 }
677                         }
678                 }
679
680                 if (!primary_l || data->do_all) {
681                         for (j = 0; j < layer_count; j++) {
682                                 if (j != primary_index && !data->do_all)
683                                         continue;
684                                 l = calloc(1, sizeof * l);
685                                 TDM_EXIT_IF_FAIL(l != NULL);
686                                 LIST_INITHEAD(&l->prop_list);
687                                 LIST_ADDTAIL(&l->link, &o->layer_list);
688                                 l->data = data;
689                                 l->o = o;
690                                 l->idx = j;
691                                 if (j == primary_index) {
692                                         l->is_primary = 1;
693                                         l->info.dst_pos.w = mode->hdisplay;
694                                         l->info.dst_pos.h = mode->vdisplay;
695                                         primary_l = l;
696                                 } else {
697                                         l->info.dst_pos.w = TDM_ALIGN(mode->hdisplay / 3, 2);
698                                         l->info.dst_pos.h = TDM_ALIGN(mode->vdisplay / 3, 2);
699                                         l->info.dst_pos.x = TDM_ALIGN(((mode->hdisplay / 3) / layer_count) * j, 2);
700                                         l->info.dst_pos.y = TDM_ALIGN(((mode->vdisplay / 3) / layer_count) * j, 2);
701                                 }
702                         }
703                 }
704
705                 TDM_EXIT_IF_FAIL(primary_l != NULL);
706                 LIST_DEL(&primary_l->link);
707                 LIST_ADD(&primary_l->link, &o->layer_list);
708         }
709
710         /* fill the empty information of layers */
711         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
712                 tdm_output *output;
713                 int minw, minh, maxw, maxh;
714
715                 output = tdm_display_get_output(data->display, o->idx, &ret);
716                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
717                 ret = tdm_output_get_available_size(output, &minw, &minh, &maxw, &maxh, NULL);
718                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
719
720                 /* l->info.src_config.size will be decided when a buffer shows really */
721                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
722                         if (minw > 0 && minh > 0) {
723                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w >= minw);
724                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h >= minh);
725                         }
726                         if (maxw > 0 && maxh > 0) {
727                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w <= maxw);
728                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h <= maxh);
729                         }
730
731                         if (l->owner_p) {
732                                 l->info.src_config.format = l->owner_p->info.dst_config.format;
733                                 if (l->info.src_config.pos.w == 0) {
734                                         TDM_EXIT_IF_FAIL(l->owner_p->info.dst_config.size.h > 0);
735                                         l->info.src_config.pos.w = l->owner_p->info.dst_config.size.h;
736                                         l->info.src_config.pos.h = l->owner_p->info.dst_config.size.v;
737                                 }
738                         } else if (l->owner_c) {
739                                 l->info.src_config.format = l->owner_c->info.dst_config.format;
740                                 if (l->info.src_config.pos.w == 0) {
741                                         TDM_EXIT_IF_FAIL(l->owner_c->info.dst_config.size.h > 0);
742                                         l->info.src_config.pos.w = l->owner_c->info.dst_config.size.h;
743                                         l->info.src_config.pos.h = l->owner_c->info.dst_config.size.v;
744                                 }
745                         } else {
746                                 if (l->info.src_config.pos.w == 0) {
747                                         TDM_EXIT_IF_FAIL(l->info.dst_pos.w > 0);
748                                         l->info.src_config.pos.w = l->info.dst_pos.w;
749                                         l->info.src_config.pos.h = l->info.dst_pos.h;
750                                 }
751                         }
752                 }
753         }
754 }
755
756 static unsigned int tts_screen_prerotation_hint;
757 static tdm_test_server tts_data;
758 static int tts_buffer_key;
759 #define TTS_BUFFER_KEY ((unsigned long)&tts_buffer_key)
760
761 static tbm_surface_h
762 buffer_allocate(int width, int height, int format, int flags)
763 {
764         tdm_test_server_buffer *tb = calloc(1, sizeof *tb);
765         TDM_EXIT_IF_FAIL(tb != NULL);
766         if (tts_screen_prerotation_hint % 180)
767                 TDM_SWAP(width, height);
768         tb->b = tbm_surface_internal_create_with_flags(width, height, format, flags);
769         TDM_EXIT_IF_FAIL(tb->b != NULL);
770         tdm_helper_clear_buffer(tb->b);
771         tbm_surface_internal_add_user_data(tb->b, TTS_BUFFER_KEY, free);
772         tbm_surface_internal_set_user_data(tb->b, TTS_BUFFER_KEY, tb);
773         return tb->b;
774 }
775
776 static tdm_test_server_buffer*
777 get_tts_buffer(tbm_surface_h b)
778 {
779         tdm_test_server_buffer *tb = NULL;
780         tbm_surface_internal_get_user_data(b, TTS_BUFFER_KEY, (void **)&tb);
781         return tb;
782 }
783
784 static void
785 exit_test(int sig)
786 {
787         tdm_test_server *data = &tts_data;
788         tdm_test_server_output *o = NULL, *oo = NULL;
789         tdm_test_server_layer *l = NULL, *ll = NULL;
790         tdm_test_server_pp *p = NULL, *pp = NULL;
791         tdm_test_server_capture *c = NULL, *cc = NULL;
792         tdm_test_server_prop *w = NULL, *ww = NULL;
793         int i;
794
795         printf("got signal: %d\n", sig);
796
797         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
798                 LIST_DEL(&o->link);
799
800                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
801                         LIST_DEL(&l->link);
802
803                         tdm_layer_unset_buffer(l->layer);
804
805                         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) {
806                                 LIST_DEL(&w->link);
807                                 free(w);
808                         }
809                         for (i = 0; i < TDM_ARRAY_SIZE(l->bufs); i++)
810                                 tbm_surface_destroy(l->bufs[i]);
811                         free(l);
812                 }
813
814                 tdm_output_commit(o->output, 0, NULL, NULL);
815
816                 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) {
817                         LIST_DEL(&w->link);
818                         free(w);
819                 }
820
821                 free(o);
822         }
823
824
825         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
826                 LIST_DEL(&p->link);
827
828                 tdm_display_lock(data->display);
829                 tdm_event_loop_source_remove(p->timer_source);
830                 tdm_display_unlock(data->display);
831
832                 tdm_pp_destroy(p->pp);
833                 for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++)
834                         tbm_surface_destroy(p->bufs[i]);
835                 free(p);
836         }
837
838         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
839                 LIST_DEL(&c->link);
840                 tdm_capture_destroy(c->capture);
841                 free(c);
842         }
843
844         if (data->display)
845                 tdm_display_deinit(data->display);
846
847         exit(0);
848 }
849
850 int
851 main(int argc, char *argv[])
852 {
853         tdm_test_server *data = &tts_data;
854         char temp[TDM_SERVER_REPLY_MSG_LEN];
855         int len = sizeof temp;
856         tdm_error ret;
857         const char *value;
858
859         value = (const char*)getenv("SCREEN_PREROTATION_HINT");
860         if (value) {
861                 char *end;
862                 tts_screen_prerotation_hint = strtol(value, &end, 10);
863                 printf("SCREEN_PREROTATION_HINT = %d", tts_screen_prerotation_hint);
864         }
865
866         signal(SIGINT, exit_test);    /* 2 */
867         signal(SIGTERM, exit_test);   /* 15 */
868
869         memset(data, 0, sizeof * data);
870         LIST_INITHEAD(&data->output_list);
871         LIST_INITHEAD(&data->pp_list);
872         LIST_INITHEAD(&data->capture_list);
873
874         /* init value */
875         data->bflags = TBM_BO_SCANOUT;
876         data->b_fill = PATTERN_SMPTE;
877
878         data->display = tdm_display_init(&ret);
879         TDM_EXIT_IF_FAIL(data->display != NULL);
880
881         parse_args(data, argc, argv);
882         interpret_args(data);
883
884         if (data->do_query) {
885                 tdm_helper_get_display_information(data->display, temp, &len);
886                 printf("%s", temp);
887                 goto done;
888         }
889
890         run_test(data);
891
892 done:
893         tdm_display_deinit(data->display);
894
895         return 0;
896 }
897
898 static void
899 output_setup(tdm_test_server_output *o)
900 {
901         tdm_test_server *data = o->data;
902         const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
903         tdm_test_server_prop *w = NULL;
904         const tdm_prop *props;
905         int i, count;
906         tdm_error ret;
907
908         o->output = tdm_display_get_output(data->display, o->idx, &ret);
909         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
910
911         ret = tdm_output_get_available_modes(o->output, &modes, &count);
912         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
913
914         for (i = 0; i < count; i++) {
915                 if (!strncmp(o->mode, modes[i].name, TDM_NAME_LEN) && o->refresh == modes[i].vrefresh) {
916                         found = &modes[i];
917                         printf("found mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
918                         break;
919                 }
920                 if (!best)
921                         best = &modes[i];
922                 if (modes[i].flags & TDM_OUTPUT_MODE_TYPE_PREFERRED)
923                         prefer = &modes[i];
924         }
925         if (!found && prefer) {
926                 found = prefer;
927                 printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
928         }
929         if (!found && best) {
930                 found = best;
931                 printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
932         }
933
934         if (!found) {
935                 printf("couldn't find any mode\n");
936                 exit(0);
937         }
938
939         ret = tdm_output_set_mode(o->output, found);
940         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
941
942         printf("output %d: %s %d\n", o->idx, found->name, found->vrefresh);
943
944         ret = tdm_output_get_available_properties(o->output, &props, &count);
945         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
946
947         LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
948                 for (i = 0; i < count; i++) {
949                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
950                                 continue;
951                         ret = tdm_output_set_property(o->output, props[i].id, w->value);
952                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
953                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
954                         break;
955                 }
956         }
957
958         /* DPMS on forcely at the first time. */
959         ret = tdm_output_set_dpms(o->output, TDM_OUTPUT_DPMS_ON);
960         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
961 }
962
963 static tbm_surface_h
964 layer_get_buffer(tdm_test_server_layer *l)
965 {
966         int i, size = TDM_ARRAY_SIZE(l->bufs);
967         if (!l->bufs[0]) {
968                 for (i = 0; i < size; i++) {
969                         int width = (l->info.src_config.size.h)?:l->info.src_config.pos.w;
970                         int height = (l->info.src_config.size.v)?:l->info.src_config.pos.h;
971                         unsigned int format = (l->info.src_config.format)?:DEFAULT_FORMAT;
972                         int flags = l->o->data->bflags;
973                         tbm_surface_h b = buffer_allocate(width, height, format, flags);
974                         TDM_EXIT_IF_FAIL(b != NULL);
975                         l->bufs[i] = b;
976                 }
977         }
978         for (i = 0; i < size; i++) {
979                 tdm_test_server_buffer *tb = get_tts_buffer(l->bufs[i]);
980                 TDM_EXIT_IF_FAIL(tb != NULL);
981                 if (!tb->in_use)
982                         return l->bufs[i];
983         }
984         printf("no available layer buffer.\n");
985         exit(0);
986 }
987
988 static void
989 layer_cb_commit(tdm_output *output, unsigned int sequence,
990                                 unsigned int tv_sec, unsigned int tv_usec,
991                                 void *user_data)
992 {
993         tdm_test_server_layer *l = user_data;
994         tbm_surface_h b = layer_get_buffer(l);
995         TDM_EXIT_IF_FAIL(b != NULL);
996
997         if (!l->is_primary || l->o->fill_primary_layer)
998                 tdm_test_buffer_fill(b, l->data->b_fill);
999
1000         if (!l->is_primary || l->o->fill_primary_layer)
1001                 layer_show_buffer(l, b);
1002 }
1003
1004 static void
1005 layer_cb_buffer_release(tbm_surface_h b, void *user_data)
1006 {
1007         tdm_test_server_buffer *tb = get_tts_buffer(b);
1008         TDM_EXIT_IF_FAIL(tb != NULL);
1009
1010         tb->in_use = 0;
1011         tdm_buffer_remove_release_handler(b, layer_cb_buffer_release, NULL);
1012         if (tb->done)
1013                 tb->done(b, user_data);
1014 }
1015
1016 static void
1017 layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b)
1018 {
1019         tdm_test_server *data = l->o->data;
1020         tdm_test_server_buffer *tb;
1021         tdm_error ret;
1022
1023         ret = tdm_layer_set_buffer(l->layer, b);
1024         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1025
1026         tb = get_tts_buffer(b);
1027         TDM_EXIT_IF_FAIL(tb != NULL);
1028
1029         tb->in_use = 1;
1030         tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
1031
1032         if (data->do_vblank)
1033                 ret = tdm_output_commit(l->o->output, 0, layer_cb_commit, l);
1034         else
1035                 ret = tdm_output_commit(l->o->output, 0, NULL, NULL);
1036         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1037
1038         printf("show:\tl(%p) b(%p)\n", l, b);
1039 }
1040
1041 static void
1042 layer_setup(tdm_test_server_layer *l, tbm_surface_h b)
1043 {
1044         tdm_test_server_prop *w = NULL;
1045         const tdm_prop *props;
1046         int i, count;
1047         tdm_error ret;
1048         tbm_surface_info_s info;
1049
1050         l->layer = tdm_output_get_layer(l->o->output, l->idx, &ret);
1051         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1052
1053         /* The size and format information should be same with buffer's */
1054         tbm_surface_get_info(b, &info);
1055         if (tts_screen_prerotation_hint % 180) {
1056                 if (IS_RGB(info.format)) {
1057                         l->info.src_config.size.h = info.height;
1058                         l->info.src_config.size.v = info.planes[0].stride >> 2;
1059                 } else {
1060                         l->info.src_config.size.h = info.height;
1061                         l->info.src_config.size.v = info.planes[0].stride;
1062                 }
1063         } else {
1064                 if (IS_RGB(info.format)) {
1065                         l->info.src_config.size.h = info.planes[0].stride >> 2;
1066                         l->info.src_config.size.v = info.height;
1067                 } else {
1068                         l->info.src_config.size.h = info.planes[0].stride;
1069                         l->info.src_config.size.v = info.height;
1070                 }
1071         }
1072         l->info.src_config.format = info.format;
1073
1074         ret = tdm_layer_set_info(l->layer, &l->info);
1075         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1076
1077         printf("layer %d: output(%d) ", l->idx, l->o->idx);
1078         print_config(&l->info.src_config);
1079         printf(" ! ");
1080         print_pos(&l->info.dst_pos);
1081         printf(" transform(%s)\n", tdm_transform_str(l->info.transform));
1082
1083         ret = tdm_layer_get_available_properties(l->layer, &props, &count);
1084         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1085
1086         LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
1087                 for (i = 0; i < count; i++) {
1088                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
1089                                 continue;
1090                         ret = tdm_layer_set_property(l->layer, props[i].id, w->value);
1091                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1092                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
1093                         break;
1094                 }
1095         }
1096 }
1097
1098 static tbm_surface_h
1099 pp_get_buffer(tdm_test_server_pp *p)
1100 {
1101         int i, size = TDM_ARRAY_SIZE(p->bufs);
1102         if (!p->bufs[0]) {
1103                 for (i = 0; i < size; i++) {
1104                         int width = (p->info.src_config.size.h)?:p->info.src_config.pos.w;
1105                         int height = (p->info.src_config.size.v)?:p->info.src_config.pos.h;
1106                         unsigned int format = (p->info.src_config.format)?:DEFAULT_FORMAT;
1107                         tbm_surface_h b = buffer_allocate(width, height, format, 0);
1108                         TDM_EXIT_IF_FAIL(b != NULL);
1109                         p->bufs[i] = b;
1110                 }
1111         }
1112         for (i = 0; i < size; i++) {
1113                 tdm_test_server_buffer *tb = get_tts_buffer(p->bufs[i]);
1114
1115                 if (tb == NULL)
1116                         continue;
1117
1118                 if (!tb->in_use) {
1119                         tdm_test_buffer_fill(p->bufs[i], p->data->b_fill);
1120                         return p->bufs[i];
1121                 }
1122         }
1123         printf("no available pp buffer.\n");
1124         exit(0);
1125 }
1126
1127 static void
1128 pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
1129 {
1130         tdm_test_server_buffer *stb, *dtb;
1131
1132         stb = get_tts_buffer(sb);
1133         TDM_EXIT_IF_FAIL(stb != NULL);
1134
1135         dtb = get_tts_buffer(db);
1136         TDM_EXIT_IF_FAIL(dtb != NULL);
1137
1138         stb->in_use = dtb->in_use = 0;
1139
1140         layer_show_buffer(dtb->l, db);
1141 }
1142
1143 static void
1144 pp_convert_buffer(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1145 {
1146         tdm_test_server_buffer *stb, *dtb;
1147         tdm_error ret;
1148
1149         stb = get_tts_buffer(sb);
1150         TDM_EXIT_IF_FAIL(stb != NULL);
1151
1152         dtb = get_tts_buffer(db);
1153         TDM_EXIT_IF_FAIL(dtb != NULL);
1154
1155         stb->in_use = dtb->in_use = 1;
1156         dtb->l = p->l;
1157
1158         ret = tdm_pp_attach(p->pp, sb, db);
1159         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1160
1161         ret = tdm_pp_commit(p->pp);
1162         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1163
1164         printf("convt:\tp(%p) sb(%p) db(%p)\n", p, sb, db);
1165 }
1166
1167 /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1168  * backend module. I use them only for simulating the video play. When we call
1169  * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1170  * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1171  * called, the display has been already locked. So in this test application,
1172  * we have to unlock/lock the display for testing.
1173  */
1174 static tdm_error
1175 pp_cb_timeout(void *user_data)
1176 {
1177         tdm_test_server_pp *p = user_data;
1178         tdm_test_server *data = p->l->o->data;
1179         tbm_surface_h sb, db;
1180         tdm_error ret;
1181
1182         tdm_display_unlock(data->display);
1183
1184         sb = pp_get_buffer(p);
1185         TDM_EXIT_IF_FAIL(sb != NULL);
1186         db = layer_get_buffer(p->l);
1187         TDM_EXIT_IF_FAIL(db != NULL);
1188
1189         pp_convert_buffer(p, sb, db);
1190
1191         tdm_display_lock(data->display);
1192         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1193         tdm_display_unlock(data->display);
1194         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1195
1196         tdm_display_lock(data->display);
1197
1198         return TDM_ERROR_NONE;
1199 }
1200
1201 static void
1202 pp_setup(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1203 {
1204         tdm_test_server *data;
1205         tbm_surface_info_s info;
1206         tdm_error ret;
1207
1208         if (!p || !p->l || !p->l->o || !p->l->o->data) {
1209                 TDM_ERR("invalid parameter failed");
1210                 exit(0);
1211         }
1212         data = p->l->o->data;
1213
1214         p->pp = tdm_display_create_pp(data->display, &ret);
1215         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1216
1217         /* The size and format information should be same with buffer's */
1218         tbm_surface_get_info(sb, &info);
1219         if (IS_RGB(info.format)) {
1220                 p->info.src_config.size.h = info.planes[0].stride >> 2;
1221                 p->info.src_config.size.v = info.height;
1222         } else {
1223                 p->info.src_config.size.h = info.planes[0].stride;
1224                 p->info.src_config.size.v = info.height;
1225         }
1226         p->info.src_config.format = info.format;
1227
1228         /* The size and format information should be same with buffer's */
1229         tbm_surface_get_info(db, &info);
1230         if (IS_RGB(info.format)) {
1231                 p->info.dst_config.size.h = info.planes[0].stride >> 2;
1232                 p->info.dst_config.size.v = info.height;
1233         } else {
1234                 p->info.dst_config.size.h = info.planes[0].stride;
1235                 p->info.dst_config.size.v = info.height;
1236         }
1237         p->info.dst_config.format = info.format;
1238
1239         ret = tdm_pp_set_info(p->pp, &p->info);
1240         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1241
1242         ret = tdm_pp_set_done_handler(p->pp, pp_cb_done, NULL);
1243         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1244
1245         printf("pp: ");
1246         print_config(&p->info.src_config);
1247         printf(" ! ");
1248         print_config(&p->info.dst_config);
1249         printf(" fps(%d) transform(%s)\n", p->fps, tdm_transform_str(p->info.transform));
1250         printf("\toutput_idx(%d) layer_idx(%d)\n", p->l->o->idx, p->l->idx);
1251
1252         layer_setup(p->l, db);
1253
1254         /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1255          * backend module. I use them only for simulating the video play. When we call
1256          * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1257          * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1258          * called, the display has been already locked. So in this test application,
1259          * we have to unlock/lock the display for testing.
1260          */
1261         tdm_display_lock(data->display);
1262         p->timer_source = tdm_event_loop_add_timer_handler(data->display, pp_cb_timeout, p, &ret);
1263         tdm_display_unlock(data->display);
1264         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1265
1266         tdm_display_lock(data->display);
1267         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1268         tdm_display_unlock(data->display);
1269         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1270 }
1271
1272 static void
1273 capture_cb_buffer_done(tbm_surface_h b, void *user_data)
1274 {
1275         tdm_test_server_buffer *tb;
1276
1277         tb = get_tts_buffer(b);
1278         TDM_EXIT_IF_FAIL(tb != NULL);
1279
1280         capture_attach(tb->c, b);
1281 }
1282
1283 static void
1284 capture_cb_done(tdm_capture *capture, tbm_surface_h b, void *user_data)
1285 {
1286         tdm_test_server_buffer *tb;
1287
1288         tb = get_tts_buffer(b);
1289         TDM_EXIT_IF_FAIL(tb != NULL);
1290
1291         tb->in_use = 0;
1292
1293         tb->done = capture_cb_buffer_done;
1294         layer_show_buffer(tb->l, b);
1295 }
1296
1297 static void
1298 capture_attach(tdm_test_server_capture *c, tbm_surface_h b)
1299 {
1300         tdm_error ret;
1301         tdm_test_server_buffer *tb;
1302
1303         tb = get_tts_buffer(b);
1304         TDM_EXIT_IF_FAIL(tb != NULL);
1305
1306         tb->in_use = 1;
1307         tb->l = c->l;
1308         tb->c = c;
1309
1310         ret = tdm_capture_attach(c->capture, b);
1311         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1312
1313         printf("capture:\tc(%p) b(%p)\n", c, b);
1314
1315         ret = tdm_capture_commit(c->capture);
1316         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1317 }
1318
1319 static void
1320 capture_setup(tdm_test_server_capture *c, tbm_surface_h b)
1321 {
1322         tdm_test_server *data;
1323         tdm_output *output;
1324         tdm_layer *layer;
1325         tbm_surface_info_s info;
1326         tdm_error ret;
1327
1328         if (!c || !c->l || !c->l->o || !c->l->o->data) {
1329                 TDM_ERR("invalid parameter failed");
1330                 exit(0);
1331         }
1332         data = c->l->o->data;
1333
1334         if (c->output_idx != -1 && c->layer_idx == -1) {
1335                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1336                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1337                 c->capture = tdm_output_create_capture(output, &ret);
1338                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1339         } else if (c->output_idx != -1 && c->layer_idx != -1) {
1340                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1341                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1342                 layer = tdm_output_get_layer(output, c->layer_idx, &ret);
1343                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1344                 c->capture = tdm_layer_create_capture(layer, &ret);
1345                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1346         }
1347
1348         TDM_EXIT_IF_FAIL(c->capture != NULL);
1349
1350         /* The size and format information should be same with buffer's */
1351         tbm_surface_get_info(b, &info);
1352         if (IS_RGB(info.format)) {
1353                 c->info.dst_config.size.h = info.planes[0].stride >> 2;
1354                 c->info.dst_config.size.v = info.height;
1355         } else {
1356                 c->info.dst_config.size.h = info.planes[0].stride;
1357                 c->info.dst_config.size.v = info.height;
1358         }
1359         c->info.dst_config.format = info.format;
1360
1361         ret = tdm_capture_set_info(c->capture, &c->info);
1362         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1363
1364         ret = tdm_capture_set_done_handler(c->capture, capture_cb_done, NULL);
1365         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1366
1367         printf("capture: o(%d) l(%d) ", c->output_idx, c->layer_idx);
1368         print_config(&c->info.dst_config);
1369         printf(" transform(%s)\n", tdm_transform_str(c->info.transform));
1370         printf("\toutput_idx(%d) layer_idx(%d)\n", c->l->o->idx, c->l->idx);
1371
1372         layer_setup(c->l, b);
1373 }
1374
1375 static void
1376 run_test(tdm_test_server *data)
1377 {
1378         tdm_test_server_output *o = NULL;
1379         tdm_test_server_layer *l = NULL;
1380         tdm_test_server_pp *p = NULL;
1381         tdm_test_server_capture *c = NULL;
1382         tdm_display_capability caps;
1383         tdm_error ret;
1384
1385         ret = tdm_display_get_capabilities(data->display, &caps);
1386         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1387
1388         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
1389                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1390                         if (!l->owner_p && !l->owner_c) {
1391                                 tbm_surface_h b;
1392                                 b = layer_get_buffer(l);
1393                                 if (!l->is_primary || l->o->fill_primary_layer)
1394                                         tdm_test_buffer_fill(b, data->b_fill);
1395                                 layer_setup(l, b);
1396                                 layer_show_buffer(l, b);
1397                         }
1398                 }
1399         }
1400
1401         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
1402                 tbm_surface_h sb, db;
1403                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_PP, no_pp);
1404                 sb = pp_get_buffer(p);
1405                 TDM_EXIT_IF_FAIL(sb != NULL);
1406                 db = layer_get_buffer(p->l);
1407                 TDM_EXIT_IF_FAIL(db != NULL);
1408                 pp_setup(p, sb, db);
1409                 pp_convert_buffer(p, sb, db);
1410         }
1411
1412         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
1413                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_CAPTURE, no_capture);
1414                 tbm_surface_h b;
1415                 b = layer_get_buffer(c->l);
1416                 capture_setup(c, b);
1417                 capture_attach(c, b);
1418                 b = layer_get_buffer(c->l);
1419                 capture_attach(c, b);
1420                 b = layer_get_buffer(c->l);
1421                 capture_attach(c, b);
1422         }
1423
1424         printf("enter test loop\n");
1425
1426         while (1)
1427                 tdm_display_handle_events(data->display);
1428
1429         return;
1430 no_pp:
1431         printf("no PP capability\n");
1432         exit(0);
1433 no_capture:
1434         printf("no Capture capability\n");
1435         exit(0);
1436 }