17c0121a599f4227f8a425592a6928c722bfee8b
[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>][^stream]", 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 }
187
188 ////////////////////////////////////////////////////////////////////////////////
189
190 static const char *tdm_buf_flag_names[] = {
191         "scanout",
192         "noncachable",
193         "wc",
194 };
195 TDM_BIT_NAME_FB(buf_flag)
196
197 #define DEFAULT_FORMAT  TBM_FORMAT_ARGB8888
198
199 #define print_size(s) \
200         printf("%dx%d", (s)->h, (s)->v)
201 #define print_pos(p) \
202         printf("%dx%d+%d+%d", (p)->w, (p)->h, (p)->x, (p)->y)
203 #define print_format(f) \
204         if (f) printf("%c%c%c%c", FOURCC_STR(f)); \
205         else printf("NONE")
206 #define print_config(c) \
207         do { \
208                 print_size(&(c)->size); \
209                 printf(" "); \
210                 print_pos(&(c)->pos); \
211                 printf(" "); \
212                 print_format((c)->format); \
213         } while (0)
214 #define print_prop(w) \
215         printf("%s(%d)", (w)->name, ((w)->value).u32)
216
217 typedef struct _tdm_test_server tdm_test_server;
218 typedef struct _tdm_test_server_layer tdm_test_server_layer;
219 typedef struct _tdm_test_server_capture tdm_test_server_capture;
220
221 typedef struct _tdm_test_server_prop {
222         /* args */
223         char name[TDM_NAME_LEN];
224         tdm_value value;
225
226         /* variables for test */
227         struct list_head link;
228 } tdm_test_server_prop;
229
230 typedef struct _tdm_test_server_buffer {
231         /* variables for test */
232         tbm_surface_h b;
233         int in_use;
234         tdm_test_server_layer *l;
235
236         tdm_test_server_capture *c;
237         tdm_buffer_release_handler done;
238 } tdm_test_server_buffer;
239
240 typedef struct _tdm_test_server_output {
241         /* args */
242         int idx;
243         char mode[TDM_NAME_LEN];
244         int refresh;
245
246         /* variables for test */
247         struct list_head link;
248         struct list_head prop_list;
249         struct list_head layer_list;
250         tdm_test_server *data;
251         tdm_output *output;
252
253         int fill_primary_layer;
254 } tdm_test_server_output;
255
256 typedef struct _tdm_test_server_pp {
257         /* args */
258         tdm_info_pp info;
259         int fps;
260
261         /* variables for test */
262         struct list_head link;
263         tdm_test_server *data;
264         tdm_test_server_layer *l;
265         tdm_pp *pp;
266         tbm_surface_h bufs[6];
267         int buf_idx;
268
269         tdm_event_loop_source *timer_source;
270 } tdm_test_server_pp;
271
272 struct _tdm_test_server_capture {
273         /* args */
274         int output_idx;
275         int layer_idx;
276         tdm_info_capture info;
277
278         /* variables for test */
279         struct list_head link;
280         tdm_test_server *data;
281         tdm_test_server_layer *l;
282         tdm_capture *capture;
283 };
284
285 struct _tdm_test_server_layer {
286         /* args */
287         int idx;
288         tdm_info_layer info;
289
290         /* variables for test */
291         struct list_head link;
292         struct list_head prop_list;
293         tdm_test_server *data;
294         tdm_test_server_output *o;
295         tdm_layer *layer;
296         int is_primary;
297         tdm_test_server_pp *owner_p;
298         tdm_test_server_capture *owner_c;
299         tbm_surface_h bufs[3];
300         int buf_idx;
301 };
302
303 struct _tdm_test_server {
304         /* args */
305         int do_query;
306         int do_all;
307         int do_vblank;
308         int bflags;
309         int b_fill;
310
311         /* variables for test */
312         struct list_head output_list;
313         struct list_head pp_list;
314         struct list_head capture_list;
315         tdm_display *display;
316 };
317
318 static void destroy(tdm_test_server *data);
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         if (*end == '^') {
425                 arg = end + 1;
426                 if (strtol(arg, &end, 10) > 0)
427                         capture_info->type = TDM_CAPTURE_TYPE_STREAM;
428                 else
429                         capture_info->type = TDM_CAPTURE_TYPE_ONESHOT;
430         }
431 }
432
433 static void
434 parse_arg_l(tdm_test_server_layer *l, char *arg)
435 {
436         tdm_info_layer *layer_info = &l->info;
437         char *end;
438         TDM_EXIT_IF_FAIL(arg != NULL);
439         l->idx = strtol(arg, &end, 10);
440         if (*end == ':') {
441                 arg = end + 1;
442                 end = parse_config(&layer_info->src_config, arg);
443         }
444         TDM_EXIT_IF_FAIL(*end == '~');
445         arg = end + 1;
446         end = parse_pos(&layer_info->dst_pos, arg);
447         if (*end == '*') {
448                 arg = end + 1;
449                 layer_info->transform = strtol(arg, &end, 10);
450         }
451 }
452
453 static void
454 parse_arg_w(tdm_test_server_prop *w, char *arg)
455 {
456         char *end;
457         TDM_EXIT_IF_FAIL(arg != NULL);
458         end = strtostr(w->name, TDM_PATH_LEN, arg, TDM_DELIM);
459         TDM_EXIT_IF_FAIL(*end == ':');
460         arg = end + 1;
461         w->value.u32 = strtol(arg, &end, 10);
462 }
463
464 static void
465 parse_arg_b(tdm_test_server *data, char *arg)
466 {
467         char *end = arg;
468         char temp[TDM_NAME_LEN] = {0,};
469         TDM_EXIT_IF_FAIL(arg != NULL);
470
471         end = strtostr(temp, 32, arg, TDM_DELIM);
472         if (!strncmp(temp, "smpte", 5))
473                 data->b_fill = PATTERN_SMPTE;
474         else if (!strncmp(temp, "tiles", 5))
475                 data->b_fill = PATTERN_TILES;
476         else if (!strncmp(temp, "plain", 5))
477                 data->b_fill = PATTERN_PLAIN;
478         else {
479                 printf("'%s': unknown flag\n", temp);
480                 exit(0);
481         }
482
483         if (*arg == ':') {
484                 data->bflags = 0;
485                 arg = end + 1;
486                 snprintf(temp, TDM_NAME_LEN, "%s", arg);
487                 arg = strtok_r(temp, ",", &end);
488                 while (arg) {
489                         if (!strncmp(arg, "default", 7))
490                                 printf("Ignore '%s' flag\n", arg);
491                         else if (!strncmp(arg, "scanout", 7))
492                                 data->bflags |= TBM_BO_SCANOUT;
493                         else if (!strncmp(arg, "noncachable", 11))
494                                 data->bflags |= TBM_BO_NONCACHABLE;
495                         else if (!strncmp(arg, "wc", 2))
496                                 data->bflags |= TBM_BO_WC;
497                         else {
498                                 printf("'%s': unknown flag\n", arg);
499                                 exit(0);
500                         }
501                         arg = strtok_r(NULL, ",", &end);
502                 }
503         }
504 }
505
506 static void
507 parse_args(tdm_test_server *data, int argc, char *argv[])
508 {
509         tdm_test_server_output *o = NULL;
510         tdm_test_server_layer *l = NULL;
511         tdm_test_server_pp *p = NULL;
512         tdm_test_server_capture *c = NULL;
513         tdm_test_server_prop *w = NULL;
514         void *last_option = NULL;
515         void *last_object = NULL;
516         int i;
517
518         if (argc < 2) {
519                 usage(argv[0]);
520                 destroy(data);
521                 exit(0);
522         }
523
524         for (i = 1; i < argc; i++) {
525                 if (!strncmp(argv[i] + 1, "q", 1)) {
526                         data->do_query = 1;
527                         return;
528                 } else if (!strncmp(argv[i] + 1, "a", 1)) {
529                         data->do_all = 1;
530                 } else if (!strncmp(argv[i] + 1, "o", 1)) {
531                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
532                         o = calloc(1, sizeof * o);
533                         TDM_EXIT_IF_FAIL(o != NULL);
534                         o->data = data;
535                         LIST_INITHEAD(&o->layer_list);
536                         LIST_INITHEAD(&o->prop_list);
537                         LIST_ADDTAIL(&o->link, &data->output_list);
538                         parse_arg_o(o, argv[++i]);
539                         last_object = o;
540                 } else if (!strncmp(argv[i] + 1, "p", 1)) {
541                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
542                         p = calloc(1, sizeof * p);
543                         TDM_EXIT_IF_FAIL(p != NULL);
544                         p->data = data;
545                         p->fps = 30;   /* default 30 fps */
546                         LIST_ADDTAIL(&p->link, &data->pp_list);
547                         parse_arg_p(p, argv[++i]);
548                         last_option = p;
549                 } else if (!strncmp(argv[i] + 1, "c", 1)) {
550                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
551                         c = calloc(1, sizeof * c);
552                         TDM_EXIT_IF_FAIL(c != NULL);
553                         c->data = data;
554                         c->output_idx = -1;
555                         c->layer_idx = -1;
556                         LIST_ADDTAIL(&c->link, &data->capture_list);
557                         parse_arg_c(c, argv[++i]);
558                         last_option = c;
559                 } else if (!strncmp(argv[i] + 1, "l", 1)) {
560                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
561                         if (!o) {
562                                 o = calloc(1, sizeof * o);
563                                 TDM_EXIT_IF_FAIL(o != NULL);
564                                 o->data = data;
565                                 LIST_INITHEAD(&o->layer_list);
566                                 LIST_INITHEAD(&o->prop_list);
567                                 LIST_ADDTAIL(&o->link, &data->output_list);
568                         }
569                         l = calloc(1, sizeof * l);
570                         TDM_EXIT_IF_FAIL(l != NULL);
571                         LIST_INITHEAD(&l->prop_list);
572                         LIST_ADDTAIL(&l->link, &o->layer_list);
573                         l->data = data;
574                         l->o = o;
575                         parse_arg_l(l, argv[++i]);
576                         if (p && last_option == p) {
577                                 p->l = l;
578                                 l->owner_p = p;
579                         } else if (c && last_option == c) {
580                                 c->l = l;
581                                 l->owner_c = c;
582                         }
583                         last_object = l;
584                 } else if (!strncmp(argv[i] + 1, "w", 1)) {
585                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
586                         if (!last_object)
587                                 goto no_object;
588                         w = calloc(1, sizeof * w);
589                         TDM_EXIT_IF_FAIL(w != NULL);
590                         if (o && last_object == o)
591                                 LIST_ADDTAIL(&w->link, &o->prop_list);
592                         else if (l && last_object == l)
593                                 LIST_ADDTAIL(&w->link, &l->prop_list);
594                         parse_arg_w(w, argv[++i]);
595                 } else if (!strncmp(argv[i] + 1, "b", 1)) {
596                         parse_arg_b(data, argv[++i]);
597                 } else if (!strncmp(argv[i] + 1, "v", 1)) {
598                         data->do_vblank = 1;
599                 } else {
600                         usage(argv[0]);
601                         destroy(data);
602                         exit(0);
603                 }
604         }
605
606         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
607                 if (!p->l)
608                         goto no_layer;
609         }
610         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
611                 if (!c->l)
612                         goto no_layer;
613         }
614
615         return;
616 no_layer:
617         printf("Use '-l' to set a layer for '-p' or '-c'.\n");
618         exit(0);
619 no_object:
620         printf("Use '-o' or '-l' to set a object first.\n");
621         exit(0);
622 all:
623         printf("Can't use '-%s' with '-a'.\n", argv[i] + 1);
624         exit(0);
625 }
626
627 static void
628 interpret_args(tdm_test_server *data)
629 {
630         tdm_test_server_output *o = NULL;
631         tdm_test_server_layer *l = NULL;
632         tdm_error ret;
633
634         /* create the objects of outputs */
635         if (data->do_all) {
636                 int i, output_count;
637
638                 ret = tdm_display_get_output_count(data->display, &output_count);
639                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
640
641                 for (i = 0; i < output_count; i++) {
642                         tdm_output *output = tdm_display_get_output(data->display, i, NULL);
643                         tdm_output_conn_status status;
644                         ret = tdm_output_get_conn_status(output, &status);
645                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
646
647                         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
648                                 continue;
649                         o = calloc(1, sizeof * o);
650                         TDM_EXIT_IF_FAIL(o != NULL);
651                         o->data = data;
652                         LIST_INITHEAD(&o->layer_list);
653                         LIST_INITHEAD(&o->prop_list);
654                         LIST_ADDTAIL(&o->link, &data->output_list);
655                         o->idx = i;
656                         o->fill_primary_layer = 1;
657                 }
658         }
659
660         /* check if the primary layer object exists */
661         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
662                 tdm_output *output;
663                 const tdm_output_mode *mode;
664                 int j, layer_count, primary_index = 0;
665                 tdm_test_server_layer *primary_l = NULL;
666
667                 output_setup(o);
668
669                 output = tdm_display_get_output(data->display, o->idx, &ret);
670                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
671                 ret = tdm_output_get_mode(output, &mode);
672                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
673                 ret = tdm_output_get_layer_count(output, &layer_count);
674                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
675                 ret = tdm_output_get_primary_index(output, &primary_index);
676                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
677
678                 if (LIST_IS_EMPTY(&o->layer_list))
679                         o->fill_primary_layer = 1;
680                 else {
681                         LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
682                                 if (l->idx == primary_index) {
683                                         l->is_primary = 1;
684                                         o->fill_primary_layer = 1;
685                                         primary_l = l;
686                                         break;
687                                 }
688                         }
689                 }
690
691                 if (!primary_l || data->do_all) {
692                         for (j = 0; j < layer_count; j++) {
693                                 if (j != primary_index && !data->do_all)
694                                         continue;
695                                 l = calloc(1, sizeof * l);
696                                 TDM_EXIT_IF_FAIL(l != NULL);
697                                 LIST_INITHEAD(&l->prop_list);
698                                 LIST_ADDTAIL(&l->link, &o->layer_list);
699                                 l->data = data;
700                                 l->o = o;
701                                 l->idx = j;
702                                 if (j == primary_index) {
703                                         l->is_primary = 1;
704                                         l->info.dst_pos.w = mode->hdisplay;
705                                         l->info.dst_pos.h = mode->vdisplay;
706                                         primary_l = l;
707                                 } else {
708                                         l->info.dst_pos.w = TDM_ALIGN(mode->hdisplay / 3, 2);
709                                         l->info.dst_pos.h = TDM_ALIGN(mode->vdisplay / 3, 2);
710                                         l->info.dst_pos.x = TDM_ALIGN(((mode->hdisplay / 3) / layer_count) * j, 2);
711                                         l->info.dst_pos.y = TDM_ALIGN(((mode->vdisplay / 3) / layer_count) * j, 2);
712                                 }
713                         }
714                 }
715
716                 TDM_EXIT_IF_FAIL(primary_l != NULL);
717                 LIST_DEL(&primary_l->link);
718                 LIST_ADD(&primary_l->link, &o->layer_list);
719         }
720
721         /* fill the empty information of layers */
722         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
723                 tdm_output *output;
724                 int minw, minh, maxw, maxh;
725
726                 output = tdm_display_get_output(data->display, o->idx, &ret);
727                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
728                 ret = tdm_output_get_available_size(output, &minw, &minh, &maxw, &maxh, NULL);
729                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
730
731                 /* l->info.src_config.size will be decided when a buffer shows really */
732                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
733                         if (minw > 0 && minh > 0) {
734                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w >= minw);
735                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h >= minh);
736                         }
737                         if (maxw > 0 && maxh > 0) {
738                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w <= maxw);
739                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h <= maxh);
740                         }
741
742                         if (l->owner_p) {
743                                 l->info.src_config.format = l->owner_p->info.dst_config.format;
744                                 if (l->info.src_config.pos.w == 0) {
745                                         TDM_EXIT_IF_FAIL(l->owner_p->info.dst_config.size.h > 0);
746                                         l->info.src_config.pos.w = l->owner_p->info.dst_config.size.h;
747                                         l->info.src_config.pos.h = l->owner_p->info.dst_config.size.v;
748                                 }
749                         } else if (l->owner_c) {
750                                 l->info.src_config.format = l->owner_c->info.dst_config.format;
751                                 if (l->info.src_config.pos.w == 0) {
752                                         TDM_EXIT_IF_FAIL(l->owner_c->info.dst_config.size.h > 0);
753                                         l->info.src_config.pos.w = l->owner_c->info.dst_config.size.h;
754                                         l->info.src_config.pos.h = l->owner_c->info.dst_config.size.v;
755                                 }
756                         } else {
757                                 if (l->info.src_config.pos.w == 0) {
758                                         TDM_EXIT_IF_FAIL(l->info.dst_pos.w > 0);
759                                         l->info.src_config.pos.w = l->info.dst_pos.w;
760                                         l->info.src_config.pos.h = l->info.dst_pos.h;
761                                 }
762                         }
763                 }
764         }
765 }
766
767 static tdm_test_server tts_data;
768 static int tts_buffer_key;
769 #define TTS_BUFFER_KEY ((unsigned long)&tts_buffer_key)
770
771 static tbm_surface_h
772 buffer_allocate(int width, int height, int format, int flags)
773 {
774         tdm_test_server_buffer *tb = calloc(1, sizeof *tb);
775         TDM_EXIT_IF_FAIL(tb != NULL);
776         tb->b = tbm_surface_internal_create_with_flags(width, height, format, flags);
777         TDM_EXIT_IF_FAIL(tb->b != NULL);
778         tdm_helper_clear_buffer(tb->b);
779         tbm_surface_internal_add_user_data(tb->b, TTS_BUFFER_KEY, free);
780         tbm_surface_internal_set_user_data(tb->b, TTS_BUFFER_KEY, tb);
781         return tb->b;
782 }
783
784 static tdm_test_server_buffer*
785 get_tts_buffer(tbm_surface_h b)
786 {
787         tdm_test_server_buffer *tb = NULL;
788         tbm_surface_internal_get_user_data(b, TTS_BUFFER_KEY, (void **)&tb);
789         return tb;
790 }
791
792 static void
793 destroy(tdm_test_server *data)
794 {
795         tdm_test_server_output *o = NULL, *oo = NULL;
796         tdm_test_server_layer *l = NULL, *ll = NULL;
797         tdm_test_server_pp *p = NULL, *pp = NULL;
798         tdm_test_server_capture *c = NULL, *cc = NULL;
799         tdm_test_server_prop *w = NULL, *ww = NULL;
800         tdm_error ret;
801         int i;
802
803         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
804                 LIST_DEL(&c->link);
805                 tdm_capture_destroy(c->capture);
806                 free(c);
807         }
808
809         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
810                 tdm_display_lock(data->display);
811                 tdm_event_loop_source_remove(p->timer_source);
812                 tdm_display_unlock(data->display);
813
814                 tdm_pp_destroy(p->pp);
815         }
816
817         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
818                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
819                         ret = tdm_layer_unset_buffer(l->layer);
820                         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
821                 }
822                 ret = tdm_layer_commit(l->layer, NULL, NULL);
823                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
824         }
825
826         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
827                 LIST_DEL(&p->link);
828                 for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++)
829                         tbm_surface_destroy(p->bufs[i]);
830                 free(p);
831         }
832
833         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
834                 LIST_DEL(&o->link);
835                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
836                         LIST_DEL(&l->link);
837                         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) {
838                                 LIST_DEL(&w->link);
839                                 free(w);
840                         }
841                         for (i = 0; i < TDM_ARRAY_SIZE(l->bufs); i++)
842                                 tbm_surface_destroy(l->bufs[i]);
843                         free(l);
844                 }
845                 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) {
846                         LIST_DEL(&w->link);
847                         free(w);
848                 }
849
850                 free(o);
851         }
852
853         if (data->display)
854                 tdm_display_deinit(data->display);
855
856         exit(0);
857 }
858
859 int
860 main(int argc, char *argv[])
861 {
862         tdm_test_server *data = &tts_data;
863         char temp[TDM_SERVER_REPLY_MSG_LEN];
864         int len = sizeof temp;
865         tdm_error ret;
866
867 #if 1 /* for testing */
868         const char *s = (const char*)getenv("XDG_RUNTIME_DIR");
869         if (!s) {
870                 char buf[32];
871                 snprintf(buf, sizeof(buf), "/run");
872                 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
873                 if (ret != 0)
874                         exit(0);
875         }
876
877         s = (const char*)getenv("TBM_DISPLAY_SERVER");
878         if (!s) {
879                 char buf[32];
880                 snprintf(buf, sizeof(buf), "1");
881                 int ret = setenv("TBM_DISPLAY_SERVER", (const char*)buf, 1);
882                 if (ret != 0)
883                         exit(0);
884         }
885 #endif
886
887         memset(data, 0, sizeof * data);
888         LIST_INITHEAD(&data->output_list);
889         LIST_INITHEAD(&data->pp_list);
890         LIST_INITHEAD(&data->capture_list);
891
892         /* init value */
893         data->bflags = TBM_BO_SCANOUT;
894         data->b_fill = PATTERN_SMPTE;
895
896         data->display = tdm_display_init(&ret);
897         TDM_EXIT_IF_FAIL(data->display != NULL);
898
899         parse_args(data, argc, argv);
900         interpret_args(data);
901
902         if (data->do_query) {
903                 tdm_helper_get_display_information(data->display, temp, &len);
904                 printf("%s", temp);
905                 goto done;
906         }
907
908         run_test(data);
909
910 done:
911         tdm_display_deinit(data->display);
912
913         return 0;
914 }
915
916 static void
917 output_setup(tdm_test_server_output *o)
918 {
919         tdm_test_server *data = o->data;
920         const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
921         tdm_test_server_prop *w = NULL;
922         const tdm_prop *props;
923         int i, count;
924         tdm_error ret;
925
926         o->output = tdm_display_get_output(data->display, o->idx, &ret);
927         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
928
929         ret = tdm_output_get_available_modes(o->output, &modes, &count);
930         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
931
932         for (i = 0; i < count; i++) {
933                 if (!strncmp(o->mode, modes[i].name, TDM_NAME_LEN) && o->refresh == modes[i].vrefresh) {
934                         found = &modes[i];
935                         printf("found mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
936                         break;
937                 }
938                 if (!best)
939                         best = &modes[i];
940                 if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
941                         prefer = &modes[i];
942         }
943         if (!found && prefer) {
944                 found = prefer;
945                 printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
946         }
947         if (!found && best) {
948                 found = best;
949                 printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
950         }
951
952         if (!found) {
953                 printf("couldn't find any mode\n");
954                 exit(0);
955         }
956
957         ret = tdm_output_set_mode(o->output, found);
958         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
959
960         printf("output %d: %s %d\n", o->idx, found->name, found->vrefresh);
961
962         ret = tdm_output_get_available_properties(o->output, &props, &count);
963         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
964
965         LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
966                 for (i = 0; i < count; i++) {
967                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
968                                 continue;
969                         ret = tdm_output_set_property(o->output, props[i].id, w->value);
970                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
971                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
972                         break;
973                 }
974         }
975
976         /* DPMS on forcely at the first time. */
977         ret = tdm_output_set_dpms(o->output, TDM_OUTPUT_DPMS_ON);
978         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
979 }
980
981 static tbm_surface_h
982 layer_get_buffer(tdm_test_server_layer *l)
983 {
984         int i, size = TDM_ARRAY_SIZE(l->bufs);
985         if (!l->bufs[0]) {
986                 for (i = 0; i < size; i++) {
987                         int width = (l->info.src_config.size.h) ? : l->info.src_config.pos.w;
988                         int height = (l->info.src_config.size.v) ? : l->info.src_config.pos.h;
989                         unsigned int format = (l->info.src_config.format) ? : DEFAULT_FORMAT;
990                         int flags = l->o->data->bflags;
991                         tbm_surface_h b = buffer_allocate(width, height, format, flags);
992                         TDM_EXIT_IF_FAIL(b != NULL);
993                         l->bufs[i] = b;
994                 }
995         }
996         for (i = 0; i < size; i++) {
997                 tdm_test_server_buffer *tb = get_tts_buffer(l->bufs[i]);
998                 TDM_EXIT_IF_FAIL(tb != NULL);
999                 if (!tb->in_use)
1000                         return l->bufs[i];
1001         }
1002         printf("no available layer buffer.\n");
1003         exit(0);
1004 }
1005
1006 static void
1007 layer_cb_commit(tdm_layer *layer, unsigned int sequence,
1008                                 unsigned int tv_sec, unsigned int tv_usec,
1009                                 void *user_data)
1010 {
1011         tdm_test_server_layer *l = user_data;
1012         tbm_surface_h b = layer_get_buffer(l);
1013         TDM_EXIT_IF_FAIL(b != NULL);
1014
1015         if (!l->is_primary || l->o->fill_primary_layer)
1016                 tdm_test_buffer_fill(b, l->data->b_fill);
1017
1018         if (!l->is_primary || l->o->fill_primary_layer)
1019                 layer_show_buffer(l, b);
1020 }
1021
1022 static void
1023 layer_cb_buffer_release(tbm_surface_h b, void *user_data)
1024 {
1025         tdm_test_server_buffer *tb = get_tts_buffer(b);
1026         TDM_EXIT_IF_FAIL(tb != NULL);
1027
1028         tb->in_use = 0;
1029         tdm_buffer_remove_release_handler(b, layer_cb_buffer_release, NULL);
1030         if (tb->done)
1031                 tb->done(b, user_data);
1032 }
1033
1034 static void
1035 layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b)
1036 {
1037         tdm_test_server *data = l->o->data;
1038         tdm_test_server_buffer *tb;
1039         tdm_error ret;
1040
1041         ret = tdm_layer_set_buffer(l->layer, b);
1042         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1043
1044         tb = get_tts_buffer(b);
1045         TDM_EXIT_IF_FAIL(tb != NULL);
1046
1047         tb->in_use = 1;
1048         ret = tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
1049         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1050
1051         if (data->do_vblank)
1052                 ret = tdm_layer_commit(l->layer, layer_cb_commit, l);
1053         else
1054                 ret = tdm_layer_commit(l->layer, NULL, NULL);
1055         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1056
1057         printf("show:\tl(%p) b(%p)\n", l, b);
1058 }
1059
1060 static void
1061 layer_setup(tdm_test_server_layer *l, tbm_surface_h b)
1062 {
1063         tdm_test_server_prop *w = NULL;
1064         const tdm_prop *props;
1065         int i, count;
1066         tdm_error ret;
1067         tbm_surface_info_s info;
1068
1069         l->layer = tdm_output_get_layer(l->o->output, l->idx, &ret);
1070         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1071
1072         /* The size and format information should be same with buffer's */
1073         tbm_surface_get_info(b, &info);
1074         if (IS_RGB(info.format)) {
1075                 l->info.src_config.size.h = info.planes[0].stride >> 2;
1076                 l->info.src_config.size.v = info.height;
1077         } else {
1078                 l->info.src_config.size.h = info.planes[0].stride;
1079                 l->info.src_config.size.v = info.height;
1080         }
1081         l->info.src_config.format = info.format;
1082
1083         ret = tdm_layer_set_info(l->layer, &l->info);
1084         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1085
1086         printf("layer %d: output(%d) ", l->idx, l->o->idx);
1087         print_config(&l->info.src_config);
1088         printf(" ! ");
1089         print_pos(&l->info.dst_pos);
1090         printf(" transform(%s)\n", tdm_transform_str(l->info.transform));
1091
1092         ret = tdm_layer_get_available_properties(l->layer, &props, &count);
1093         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1094
1095         LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
1096                 for (i = 0; i < count; i++) {
1097                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
1098                                 continue;
1099                         ret = tdm_layer_set_property(l->layer, props[i].id, w->value);
1100                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1101                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
1102                         break;
1103                 }
1104         }
1105 }
1106
1107 static tbm_surface_h
1108 pp_get_buffer(tdm_test_server_pp *p)
1109 {
1110         int i, size = TDM_ARRAY_SIZE(p->bufs);
1111         if (!p->bufs[0]) {
1112                 for (i = 0; i < size; i++) {
1113                         int width = (p->info.src_config.size.h) ? : p->info.src_config.pos.w;
1114                         int height = (p->info.src_config.size.v) ? : p->info.src_config.pos.h;
1115                         unsigned int format = (p->info.src_config.format) ? : DEFAULT_FORMAT;
1116                         tbm_surface_h b = buffer_allocate(width, height, format, 0);
1117                         TDM_EXIT_IF_FAIL(b != NULL);
1118                         p->bufs[i] = b;
1119                 }
1120         }
1121         for (i = 0; i < size; i++) {
1122                 tdm_test_server_buffer *tb = get_tts_buffer(p->bufs[i]);
1123
1124                 if (tb == NULL)
1125                         continue;
1126
1127                 if (!tb->in_use) {
1128                         tdm_test_buffer_fill(p->bufs[i], p->data->b_fill);
1129                         return p->bufs[i];
1130                 }
1131         }
1132         printf("no available pp buffer.\n");
1133         exit(0);
1134 }
1135
1136 static void
1137 pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
1138 {
1139         tdm_test_server_buffer *stb, *dtb;
1140
1141         stb = get_tts_buffer(sb);
1142         TDM_EXIT_IF_FAIL(stb != NULL);
1143
1144         dtb = get_tts_buffer(db);
1145         TDM_EXIT_IF_FAIL(dtb != NULL);
1146
1147         stb->in_use = dtb->in_use = 0;
1148
1149         layer_show_buffer(dtb->l, db);
1150 }
1151
1152 static void
1153 pp_convert_buffer(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1154 {
1155         tdm_test_server_buffer *stb, *dtb;
1156         tdm_error ret;
1157
1158         stb = get_tts_buffer(sb);
1159         TDM_EXIT_IF_FAIL(stb != NULL);
1160
1161         dtb = get_tts_buffer(db);
1162         TDM_EXIT_IF_FAIL(dtb != NULL);
1163
1164         stb->in_use = dtb->in_use = 1;
1165         dtb->l = p->l;
1166
1167         ret = tdm_pp_attach(p->pp, sb, db);
1168         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1169
1170         ret = tdm_pp_commit(p->pp);
1171         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1172
1173         printf("convt:\tp(%p) sb(%p) db(%p)\n", p, sb, db);
1174 }
1175
1176 /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1177  * backend module. I use them only for simulating the video play. When we call
1178  * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1179  * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1180  * called, the display has been already locked. So in this test application,
1181  * we have to unlock/lock the display for testing.
1182  */
1183 static tdm_error
1184 pp_cb_timeout(void *user_data)
1185 {
1186         tdm_test_server_pp *p = user_data;
1187         tdm_test_server *data = p->l->o->data;
1188         tbm_surface_h sb, db;
1189         tdm_error ret;
1190
1191         tdm_display_unlock(data->display);
1192
1193         sb = pp_get_buffer(p);
1194         TDM_EXIT_IF_FAIL(sb != NULL);
1195         db = layer_get_buffer(p->l);
1196         TDM_EXIT_IF_FAIL(db != NULL);
1197
1198         pp_convert_buffer(p, sb, db);
1199
1200         tdm_display_lock(data->display);
1201         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1202         tdm_display_unlock(data->display);
1203         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1204
1205         tdm_display_lock(data->display);
1206
1207         return TDM_ERROR_NONE;
1208 }
1209
1210 static void
1211 pp_setup(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1212 {
1213         tdm_test_server *data;
1214         tbm_surface_info_s info;
1215         tdm_error ret;
1216
1217         if (!p || !p->l || !p->l->o || !p->l->o->data) {
1218                 TDM_ERR("invalid parameter failed");
1219                 exit(0);
1220         }
1221         data = p->l->o->data;
1222
1223         p->pp = tdm_display_create_pp(data->display, &ret);
1224         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1225
1226         /* The size and format information should be same with buffer's */
1227         tbm_surface_get_info(sb, &info);
1228         if (IS_RGB(info.format)) {
1229                 p->info.src_config.size.h = info.planes[0].stride >> 2;
1230                 p->info.src_config.size.v = info.height;
1231         } else {
1232                 p->info.src_config.size.h = info.planes[0].stride;
1233                 p->info.src_config.size.v = info.height;
1234         }
1235         p->info.src_config.format = info.format;
1236
1237         /* The size and format information should be same with buffer's */
1238         tbm_surface_get_info(db, &info);
1239         if (IS_RGB(info.format)) {
1240                 p->info.dst_config.size.h = info.planes[0].stride >> 2;
1241                 p->info.dst_config.size.v = info.height;
1242         } else {
1243                 p->info.dst_config.size.h = info.planes[0].stride;
1244                 p->info.dst_config.size.v = info.height;
1245         }
1246         p->info.dst_config.format = info.format;
1247
1248         ret = tdm_pp_set_info(p->pp, &p->info);
1249         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1250
1251         ret = tdm_pp_set_done_handler(p->pp, pp_cb_done, NULL);
1252         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1253
1254         printf("pp: ");
1255         print_config(&p->info.src_config);
1256         printf(" ! ");
1257         print_config(&p->info.dst_config);
1258         printf(" fps(%d) transform(%s)\n", p->fps, tdm_transform_str(p->info.transform));
1259         printf("\toutput_idx(%d) layer_idx(%d)\n", p->l->o->idx, p->l->idx);
1260
1261         layer_setup(p->l, db);
1262
1263         /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1264          * backend module. I use them only for simulating the video play. When we call
1265          * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1266          * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1267          * called, the display has been already locked. So in this test application,
1268          * we have to unlock/lock the display for testing.
1269          */
1270         tdm_display_lock(data->display);
1271         p->timer_source = tdm_event_loop_add_timer_handler(data->display, pp_cb_timeout, p, &ret);
1272         tdm_display_unlock(data->display);
1273         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1274
1275         tdm_display_lock(data->display);
1276         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1277         tdm_display_unlock(data->display);
1278         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1279 }
1280
1281 static void
1282 capture_cb_buffer_done(tbm_surface_h b, void *user_data)
1283 {
1284         tdm_test_server_buffer *tb;
1285
1286         tb = get_tts_buffer(b);
1287         TDM_EXIT_IF_FAIL(tb != NULL);
1288
1289         capture_attach(tb->c, b);
1290 }
1291
1292 static void
1293 capture_cb_done(tdm_capture *capture, tbm_surface_h b, void *user_data)
1294 {
1295         tdm_test_server_buffer *tb;
1296
1297         tb = get_tts_buffer(b);
1298         TDM_EXIT_IF_FAIL(tb != NULL);
1299
1300         tb->in_use = 0;
1301
1302         tb->done = capture_cb_buffer_done;
1303         layer_show_buffer(tb->l, b);
1304 }
1305
1306 static void
1307 capture_attach(tdm_test_server_capture *c, tbm_surface_h b)
1308 {
1309         tdm_error ret;
1310         tdm_test_server_buffer *tb;
1311
1312         tb = get_tts_buffer(b);
1313         TDM_EXIT_IF_FAIL(tb != NULL);
1314
1315         tb->in_use = 1;
1316         tb->l = c->l;
1317         tb->c = c;
1318
1319         ret = tdm_capture_attach(c->capture, b);
1320         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1321
1322         printf("capture:\tc(%p) b(%p)\n", c, b);
1323
1324         ret = tdm_capture_commit(c->capture);
1325         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1326 }
1327
1328 static void
1329 capture_setup(tdm_test_server_capture *c, tbm_surface_h b)
1330 {
1331         tdm_test_server *data;
1332         tdm_output *output;
1333         tdm_layer *layer;
1334         tbm_surface_info_s info;
1335         tdm_error ret;
1336
1337         if (!c || !c->l || !c->l->o || !c->l->o->data) {
1338                 TDM_ERR("invalid parameter failed");
1339                 exit(0);
1340         }
1341         data = c->l->o->data;
1342
1343         if (c->output_idx != -1 && c->layer_idx == -1) {
1344                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1345                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1346                 c->capture = tdm_output_create_capture(output, &ret);
1347                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1348         } else if (c->output_idx != -1 && c->layer_idx != -1) {
1349                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1350                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1351                 layer = tdm_output_get_layer(output, c->layer_idx, &ret);
1352                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1353                 c->capture = tdm_layer_create_capture(layer, &ret);
1354                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1355         }
1356
1357         TDM_EXIT_IF_FAIL(c->capture != NULL);
1358
1359         /* The size and format information should be same with buffer's */
1360         tbm_surface_get_info(b, &info);
1361         if (IS_RGB(info.format)) {
1362                 c->info.dst_config.size.h = info.planes[0].stride >> 2;
1363                 c->info.dst_config.size.v = info.height;
1364         } else {
1365                 c->info.dst_config.size.h = info.planes[0].stride;
1366                 c->info.dst_config.size.v = info.height;
1367         }
1368         c->info.dst_config.format = info.format;
1369         c->info.type = TDM_CAPTURE_TYPE_ONESHOT;
1370
1371         ret = tdm_capture_set_info(c->capture, &c->info);
1372         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1373
1374         ret = tdm_capture_set_done_handler(c->capture, capture_cb_done, NULL);
1375         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1376
1377         printf("capture: o(%d) l(%d) ", c->output_idx, c->layer_idx);
1378         print_config(&c->info.dst_config);
1379         printf(" transform(%s)\n", tdm_transform_str(c->info.transform));
1380         printf("\toutput_idx(%d) layer_idx(%d)\n", c->l->o->idx, c->l->idx);
1381
1382         layer_setup(c->l, b);
1383 }
1384
1385 static void
1386 run_test(tdm_test_server *data)
1387 {
1388         tdm_test_server_output *o = NULL;
1389         tdm_test_server_layer *l = NULL;
1390         tdm_test_server_pp *p = NULL;
1391         tdm_test_server_capture *c = NULL;
1392         tdm_display_capability caps;
1393         tdm_error ret;
1394
1395         ret = tdm_display_get_capabilities(data->display, &caps);
1396         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1397
1398         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
1399                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1400                         if (!l->owner_p && !l->owner_c) {
1401                                 tbm_surface_h b;
1402                                 b = layer_get_buffer(l);
1403                                 if (!l->is_primary || l->o->fill_primary_layer)
1404                                         tdm_test_buffer_fill(b, data->b_fill);
1405                                 layer_setup(l, b);
1406                                 layer_show_buffer(l, b);
1407                         }
1408                 }
1409         }
1410
1411         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
1412                 tbm_surface_h sb, db;
1413                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_PP, no_pp);
1414                 sb = pp_get_buffer(p);
1415                 TDM_EXIT_IF_FAIL(sb != NULL);
1416                 db = layer_get_buffer(p->l);
1417                 TDM_EXIT_IF_FAIL(db != NULL);
1418                 pp_setup(p, sb, db);
1419                 pp_convert_buffer(p, sb, db);
1420         }
1421
1422         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
1423                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_CAPTURE, no_capture);
1424                 tbm_surface_h b;
1425                 b = layer_get_buffer(c->l);
1426                 capture_setup(c, b);
1427                 capture_attach(c, b);
1428                 b = layer_get_buffer(c->l);
1429                 capture_attach(c, b);
1430                 b = layer_get_buffer(c->l);
1431                 capture_attach(c, b);
1432         }
1433
1434         printf("enter test loop\n");
1435
1436         while (1) {
1437                 ret = tdm_display_handle_events(data->display);
1438                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1439         }
1440
1441         destroy(data);
1442
1443         return;
1444 no_pp:
1445         printf("no PP capability\n");
1446         exit(0);
1447 no_capture:
1448         printf("no Capture capability\n");
1449         exit(0);
1450 }