virtual: add virtual output mode set test to tdm_test
[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 <boram1288.park@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_TST, "V", "virtual output test.\n\t\t'-l' is used to show the result on screen.",
112                 NULL, NULL
113         },
114         {
115                 OPT_GEN, "w", "set the property of a object",
116                 "<prop_name>:<value>", NULL
117         },
118         {
119                 OPT_GEN, "b", "set the fill(smtpe,tiles,plain) and framebuffer type(scanout,noncachable,wc)",
120                 "<fill>[:<buf_flag>[,<buf_flag2>[,...]]]", NULL
121         },
122         {
123                 OPT_GEN, "v", "update layers every vblank",
124                 NULL, NULL
125         },
126 };
127
128 struct usagestring {
129         const char *string;
130         const char *desc;
131 };
132
133 static struct usagestring usages[] = {
134         {
135                 "-q",
136                 NULL
137         },
138         {
139                 "-a -b plain",
140                 "test all outputs, layers with plain buffers"
141         },
142         {
143                 "-o 0@1920x1080",
144                 "Set the \"1920x1080\" mode to the output 0. And show a buffer via a primary layer of the output 0"
145         },
146         {
147                 "-o 0@1920x1080 -l 1~640x480+50+100",
148                 "Create the 640x480 buffer and show it in the (50,100) pos of screen via the layer 1"
149         },
150         {
151                 "-p 320x240@NV12~480x360+80+40,640x480@AR24 -l 1~640x480+50+100",
152                 "Convert the 320x240@NV12 buffer to the 640x480@AR24 buffer(480x360+80+40) and show the result via the layer 1"
153         },
154 };
155
156 static void
157 usage(char *app_name)
158 {
159         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
160         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
161         int usages_size = sizeof(usages) / sizeof(struct usagestring);
162         int t;
163
164         printf("usage: %s \n\n", app_name);
165
166         for (t = 0; t < type_size; t++) {
167                 int o, f = 1;
168
169                 for (o = 0; o < opt_size; o++)
170                         if (optstrs[o].type == typestrs[t].type) {
171                                 if (f == 1)
172                                         printf(" %s options: %s\n\n", typestrs[t].string, (typestrs[t].desc) ? : "");
173                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
174                                 if (optstrs[o].arg)
175                                         printf("\t\t  %s\n", optstrs[o].arg);
176                                 if (optstrs[o].ex)
177                                         printf("\t\t  ex) %s\n", optstrs[o].ex);
178                                 f = 0;
179                         }
180                 printf("\n");
181         }
182
183         printf(" For example)\n\n");
184
185         for (t = 0; t < usages_size; t++) {
186                 printf("    $ %s %s\n", app_name, usages[t].string);
187                 printf("\t%s\n", usages[t].desc);
188         }
189         printf("\n");
190 }
191
192 ////////////////////////////////////////////////////////////////////////////////
193
194 static const char *tdm_buf_flag_names[] = {
195         "scanout",
196         "noncachable",
197         "wc",
198 };
199 TDM_BIT_NAME_FB(buf_flag)
200
201 #define DEFAULT_FORMAT  TBM_FORMAT_ARGB8888
202
203 #define print_size(s) \
204         printf("%dx%d", (s)->h, (s)->v)
205 #define print_pos(p) \
206         printf("%dx%d+%d+%d", (p)->w, (p)->h, (p)->x, (p)->y)
207 #define print_format(f) \
208         if (f) printf("%c%c%c%c", FOURCC_STR(f)); \
209         else printf("NONE")
210 #define print_config(c) \
211         do { \
212                 print_size(&(c)->size); \
213                 printf(" "); \
214                 print_pos(&(c)->pos); \
215                 printf(" "); \
216                 print_format((c)->format); \
217         } while (0)
218 #define print_prop(w) \
219         printf("%s(%d)", (w)->name, ((w)->value).u32)
220
221 typedef struct _tdm_test_server tdm_test_server;
222 typedef struct _tdm_test_server_layer tdm_test_server_layer;
223 typedef struct _tdm_test_server_capture tdm_test_server_capture;
224 typedef struct _tdm_test_server_voutput tdm_test_server_voutput;
225
226 typedef struct _tdm_test_server_prop {
227         /* args */
228         char name[TDM_NAME_LEN];
229         tdm_value value;
230
231         /* variables for test */
232         struct list_head link;
233 } tdm_test_server_prop;
234
235 typedef struct _tdm_test_server_buffer {
236         /* variables for test */
237         tbm_surface_h b;
238         int in_use;
239         tdm_test_server_layer *l;
240
241         tdm_test_server_capture *c;
242         tdm_buffer_release_handler done;
243 } tdm_test_server_buffer;
244
245 typedef struct _tdm_test_server_output {
246         /* args */
247         int idx;
248         char mode[TDM_NAME_LEN];
249         int refresh;
250
251         /* variables for test */
252         struct list_head link;
253         struct list_head prop_list;
254         struct list_head layer_list;
255         tdm_test_server *data;
256         tdm_output *output;
257
258         int fill_primary_layer;
259 } tdm_test_server_output;
260
261 typedef struct _tdm_test_server_pp {
262         /* args */
263         tdm_info_pp info;
264         int fps;
265
266         /* variables for test */
267         struct list_head link;
268         tdm_test_server *data;
269         tdm_test_server_layer *l;
270         tdm_pp *pp;
271         tbm_surface_h bufs[6];
272         int buf_idx;
273
274         tdm_event_loop_source *timer_source;
275 } tdm_test_server_pp;
276
277 struct _tdm_test_server_capture {
278         /* args */
279         int output_idx;
280         int layer_idx;
281         tdm_info_capture info;
282
283         /* variables for test */
284         struct list_head link;
285         tdm_test_server *data;
286         tdm_test_server_layer *l;
287         tdm_capture *capture;
288 };
289
290 struct _tdm_test_server_layer {
291         /* args */
292         int idx;
293         tdm_info_layer info;
294
295         /* variables for test */
296         struct list_head link;
297         struct list_head prop_list;
298         tdm_test_server *data;
299         tdm_test_server_output *o;
300         tdm_layer *layer;
301         int is_primary;
302         tdm_test_server_pp *owner_p;
303         tdm_test_server_capture *owner_c;
304         tbm_surface_h bufs[3];
305         int buf_idx;
306 };
307
308 struct _tdm_test_server_voutput {
309         struct list_head link;
310         tdm_test_server *data;
311         tdm_output *output;
312         tdm_layer *layer;
313         tbm_surface_h bufs[3];
314         int buf_idx;
315         int need_mode_change;
316         int index;
317 };
318
319 struct _tdm_test_server {
320         /* args */
321         int do_query;
322         int do_all;
323         int do_vblank;
324         int do_voutput;
325         int bflags;
326         int b_fill;
327
328         /* variables for test */
329         struct list_head output_list;
330         struct list_head pp_list;
331         struct list_head capture_list;
332         struct list_head voutput_list;
333         tdm_display *display;
334 };
335
336 static void destroy(tdm_test_server *data);
337 static void run_test(tdm_test_server *data);
338 static void output_setup(tdm_test_server_output *o);
339 static void layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b);
340 static void capture_attach(tdm_test_server_capture *c, tbm_surface_h b);
341 static void _vlayer_show_buffer(tdm_test_server_voutput *voutput);
342 static void _voutput_layer_init(tdm_test_server_voutput *voutput);
343
344 static char*
345 parse_size(tdm_size *size, char *arg)
346 {
347         char *end;
348         size->h = strtol(arg, &end, 10);
349         TDM_EXIT_IF_FAIL(*end == 'x');
350         arg = end + 1;
351         size->v = strtol(arg, &end, 10);
352         return end;
353 }
354
355 static char*
356 parse_pos(tdm_pos *pos, char *arg)
357 {
358         char *end;
359         pos->w = strtol(arg, &end, 10);
360         TDM_EXIT_IF_FAIL(*end == 'x');
361         arg = end + 1;
362         pos->h = strtol(arg, &end, 10);
363         if (*end == '+') {
364                 arg = end + 1;
365                 pos->x = strtol(arg, &end, 10);
366                 TDM_EXIT_IF_FAIL(*end == '+');
367                 arg = end + 1;
368                 pos->y = strtol(arg, &end, 10);
369         }
370         return end;
371 }
372
373 static char*
374 parse_config(tdm_info_config *config, char *arg)
375 {
376         char *end;
377         end = parse_pos(&config->pos, arg);
378         if (*end == ',') {
379                 arg = end + 1;
380                 end = parse_size(&config->size, arg);
381         }
382         if (*end == '@') {
383                 char temp[32];
384                 arg = end + 1;
385                 end = strtostr(temp, 32, arg, TDM_DELIM);
386                 config->format = FOURCC_ID(temp);
387         }
388         return end;
389 }
390
391 static void
392 parse_arg_o(tdm_test_server_output *o, char *arg)
393 {
394         char *end;
395         TDM_EXIT_IF_FAIL(arg != NULL);
396         o->idx = strtol(arg, &end, 10);
397         TDM_EXIT_IF_FAIL(*end == '@');
398         arg = end + 1;
399         end = strtostr(o->mode, TDM_NAME_LEN, arg, TDM_DELIM);
400         if (*end == ',') {
401                 arg = end + 1;
402                 o->refresh = strtol(arg, &end, 10);
403         }
404 }
405
406 static void
407 parse_arg_p(tdm_test_server_pp *p, char *arg)
408 {
409         tdm_info_pp *pp_info = &p->info;
410         char *end;
411         TDM_EXIT_IF_FAIL(arg != NULL);
412         end = parse_config(&pp_info->src_config, arg);
413         TDM_EXIT_IF_FAIL(*end == '~');
414         arg = end + 1;
415         end = parse_config(&pp_info->dst_config, arg);
416         if (*end == '*') {
417                 arg = end + 1;
418                 pp_info->transform = strtol(arg, &end, 10);
419         }
420         if (*end == '&') {
421                 arg = end + 1;
422                 p->fps = strtol(arg, &end, 10);
423         }
424 }
425
426 static void
427 parse_arg_c(tdm_test_server_capture *c, char *arg)
428 {
429         tdm_info_capture *capture_info = &c->info;
430         char *end;
431         TDM_EXIT_IF_FAIL(arg != NULL);
432         c->output_idx = strtol(arg, &end, 10);
433         if (*end == ',') {
434                 arg = end + 1;
435                 c->layer_idx = strtol(arg, &end, 10);
436         }
437         TDM_EXIT_IF_FAIL(*end == '~');
438         arg = end + 1;
439         end = parse_config(&capture_info->dst_config, arg);
440         if (*end == '*') {
441                 arg = end + 1;
442                 capture_info->transform = strtol(arg, &end, 10);
443         }
444         if (*end == '^') {
445                 arg = end + 1;
446                 if (strtol(arg, &end, 10) > 0)
447                         capture_info->type = TDM_CAPTURE_TYPE_STREAM;
448                 else
449                         capture_info->type = TDM_CAPTURE_TYPE_ONESHOT;
450         }
451 }
452
453 static void
454 parse_arg_l(tdm_test_server_layer *l, char *arg)
455 {
456         tdm_info_layer *layer_info = &l->info;
457         char *end;
458         TDM_EXIT_IF_FAIL(arg != NULL);
459         l->idx = strtol(arg, &end, 10);
460         if (*end == ':') {
461                 arg = end + 1;
462                 end = parse_config(&layer_info->src_config, arg);
463         }
464         TDM_EXIT_IF_FAIL(*end == '~');
465         arg = end + 1;
466         end = parse_pos(&layer_info->dst_pos, arg);
467         if (*end == '*') {
468                 arg = end + 1;
469                 layer_info->transform = strtol(arg, &end, 10);
470         }
471 }
472
473 static void
474 parse_arg_w(tdm_test_server_prop *w, char *arg)
475 {
476         char *end;
477         TDM_EXIT_IF_FAIL(arg != NULL);
478         end = strtostr(w->name, TDM_PATH_LEN, arg, TDM_DELIM);
479         TDM_EXIT_IF_FAIL(*end == ':');
480         arg = end + 1;
481         w->value.u32 = strtol(arg, &end, 10);
482 }
483
484 static void
485 parse_arg_b(tdm_test_server *data, char *arg)
486 {
487         char *end = arg;
488         char temp[TDM_NAME_LEN] = {0,};
489         TDM_EXIT_IF_FAIL(arg != NULL);
490
491         end = strtostr(temp, 32, arg, TDM_DELIM);
492         if (!strncmp(temp, "smpte", 5))
493                 data->b_fill = PATTERN_SMPTE;
494         else if (!strncmp(temp, "tiles", 5))
495                 data->b_fill = PATTERN_TILES;
496         else if (!strncmp(temp, "plain", 5))
497                 data->b_fill = PATTERN_PLAIN;
498         else {
499                 printf("'%s': unknown flag\n", temp);
500                 exit(0);
501         }
502
503         if (*arg == ':') {
504                 data->bflags = 0;
505                 arg = end + 1;
506                 snprintf(temp, TDM_NAME_LEN, "%s", arg);
507                 arg = strtok_r(temp, ",", &end);
508                 while (arg) {
509                         if (!strncmp(arg, "default", 7))
510                                 printf("Ignore '%s' flag\n", arg);
511                         else if (!strncmp(arg, "scanout", 7))
512                                 data->bflags |= TBM_BO_SCANOUT;
513                         else if (!strncmp(arg, "noncachable", 11))
514                                 data->bflags |= TBM_BO_NONCACHABLE;
515                         else if (!strncmp(arg, "wc", 2))
516                                 data->bflags |= TBM_BO_WC;
517                         else {
518                                 printf("'%s': unknown flag\n", arg);
519                                 exit(0);
520                         }
521                         arg = strtok_r(NULL, ",", &end);
522                 }
523         }
524 }
525
526 static void
527 parse_args(tdm_test_server *data, int argc, char *argv[])
528 {
529         tdm_test_server_output *o = NULL;
530         tdm_test_server_layer *l = NULL;
531         tdm_test_server_pp *p = NULL;
532         tdm_test_server_capture *c = NULL;
533         tdm_test_server_prop *w = NULL;
534         void *last_option = NULL;
535         void *last_object = NULL;
536         int i;
537
538         if (argc < 2) {
539                 usage(argv[0]);
540                 destroy(data);
541                 exit(0);
542         }
543
544         for (i = 1; i < argc; i++) {
545                 if (!strncmp(argv[i] + 1, "q", 1)) {
546                         data->do_query = 1;
547                         return;
548                 } else if (!strncmp(argv[i] + 1, "a", 1)) {
549                         data->do_all = 1;
550                 } else if (!strncmp(argv[i] + 1, "o", 1)) {
551                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
552                         o = calloc(1, sizeof * o);
553                         TDM_EXIT_IF_FAIL(o != NULL);
554                         o->data = data;
555                         LIST_INITHEAD(&o->layer_list);
556                         LIST_INITHEAD(&o->prop_list);
557                         LIST_ADDTAIL(&o->link, &data->output_list);
558                         parse_arg_o(o, argv[++i]);
559                         last_object = o;
560                 } else if (!strncmp(argv[i] + 1, "p", 1)) {
561                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
562                         p = calloc(1, sizeof * p);
563                         TDM_EXIT_IF_FAIL(p != NULL);
564                         p->data = data;
565                         p->fps = 30;   /* default 30 fps */
566                         LIST_ADDTAIL(&p->link, &data->pp_list);
567                         parse_arg_p(p, argv[++i]);
568                         last_option = p;
569                 } else if (!strncmp(argv[i] + 1, "c", 1)) {
570                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
571                         c = calloc(1, sizeof * c);
572                         TDM_EXIT_IF_FAIL(c != NULL);
573                         c->data = data;
574                         c->output_idx = -1;
575                         c->layer_idx = -1;
576                         LIST_ADDTAIL(&c->link, &data->capture_list);
577                         parse_arg_c(c, argv[++i]);
578                         last_option = c;
579                 } else if (!strncmp(argv[i] + 1, "l", 1)) {
580                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
581                         if (!o) {
582                                 o = calloc(1, sizeof * o);
583                                 TDM_EXIT_IF_FAIL(o != NULL);
584                                 o->data = data;
585                                 LIST_INITHEAD(&o->layer_list);
586                                 LIST_INITHEAD(&o->prop_list);
587                                 LIST_ADDTAIL(&o->link, &data->output_list);
588                         }
589                         l = calloc(1, sizeof * l);
590                         TDM_EXIT_IF_FAIL(l != NULL);
591                         LIST_INITHEAD(&l->prop_list);
592                         LIST_ADDTAIL(&l->link, &o->layer_list);
593                         l->data = data;
594                         l->o = o;
595                         parse_arg_l(l, argv[++i]);
596                         if (p && last_option == p) {
597                                 p->l = l;
598                                 l->owner_p = p;
599                         } else if (c && last_option == c) {
600                                 c->l = l;
601                                 l->owner_c = c;
602                         }
603                         last_object = l;
604                 } else if (!strncmp(argv[i] + 1, "w", 1)) {
605                         TDM_GOTO_IF_FAIL(data->do_all == 0, all);
606                         if (!last_object)
607                                 goto no_object;
608                         w = calloc(1, sizeof * w);
609                         TDM_EXIT_IF_FAIL(w != NULL);
610                         if (o && last_object == o)
611                                 LIST_ADDTAIL(&w->link, &o->prop_list);
612                         else if (l && last_object == l)
613                                 LIST_ADDTAIL(&w->link, &l->prop_list);
614                         parse_arg_w(w, argv[++i]);
615                 } else if (!strncmp(argv[i] + 1, "b", 1)) {
616                         parse_arg_b(data, argv[++i]);
617                 } else if (!strncmp(argv[i] + 1, "v", 1)) {
618                         data->do_vblank = 1;
619                 } else if (!strncmp(argv[i] + 1, "V", 1)) {
620                         data->do_voutput = 1;
621                 } else {
622                         usage(argv[0]);
623                         destroy(data);
624                         exit(0);
625                 }
626         }
627
628         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
629                 if (!p->l)
630                         goto no_layer;
631         }
632         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
633                 if (!c->l)
634                         goto no_layer;
635         }
636
637         return;
638 no_layer:
639         printf("Use '-l' to set a layer for '-p' or '-c'.\n");
640         exit(0);
641 no_object:
642         printf("Use '-o' or '-l' to set a object first.\n");
643         exit(0);
644 all:
645         printf("Can't use '-%s' with '-a'.\n", argv[i] + 1);
646         exit(0);
647 }
648
649 static void
650 interpret_args(tdm_test_server *data)
651 {
652         tdm_test_server_output *o = NULL;
653         tdm_test_server_layer *l = NULL;
654         tdm_error ret;
655
656         /* create the objects of outputs */
657         if (data->do_all) {
658                 int i, output_count;
659
660                 ret = tdm_display_get_output_count(data->display, &output_count);
661                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
662
663                 for (i = 0; i < output_count; i++) {
664                         tdm_output *output = tdm_display_get_output(data->display, i, NULL);
665                         tdm_output_conn_status status;
666                         ret = tdm_output_get_conn_status(output, &status);
667                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
668
669                         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
670                                 continue;
671                         o = calloc(1, sizeof * o);
672                         TDM_EXIT_IF_FAIL(o != NULL);
673                         o->data = data;
674                         LIST_INITHEAD(&o->layer_list);
675                         LIST_INITHEAD(&o->prop_list);
676                         LIST_ADDTAIL(&o->link, &data->output_list);
677                         o->idx = i;
678                         o->fill_primary_layer = 1;
679                 }
680         }
681
682         /* check if the primary layer object exists */
683         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
684                 tdm_output *output;
685                 const tdm_output_mode *mode;
686                 int j, layer_count, primary_index = 0;
687                 tdm_test_server_layer *primary_l = NULL;
688
689                 output_setup(o);
690
691                 output = tdm_display_get_output(data->display, o->idx, &ret);
692                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
693                 ret = tdm_output_get_mode(output, &mode);
694                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
695                 ret = tdm_output_get_layer_count(output, &layer_count);
696                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
697                 ret = tdm_output_get_primary_index(output, &primary_index);
698                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
699
700                 if (LIST_IS_EMPTY(&o->layer_list))
701                         o->fill_primary_layer = 1;
702                 else {
703                         LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
704                                 if (l->idx == primary_index) {
705                                         l->is_primary = 1;
706                                         o->fill_primary_layer = 1;
707                                         primary_l = l;
708                                         break;
709                                 }
710                         }
711                 }
712
713                 if (!primary_l || data->do_all) {
714                         for (j = 0; j < layer_count; j++) {
715                                 if (j != primary_index && !data->do_all)
716                                         continue;
717                                 l = calloc(1, sizeof * l);
718                                 TDM_EXIT_IF_FAIL(l != NULL);
719                                 LIST_INITHEAD(&l->prop_list);
720                                 LIST_ADDTAIL(&l->link, &o->layer_list);
721                                 l->data = data;
722                                 l->o = o;
723                                 l->idx = j;
724                                 if (j == primary_index) {
725                                         l->is_primary = 1;
726                                         l->info.dst_pos.w = mode->hdisplay;
727                                         l->info.dst_pos.h = mode->vdisplay;
728                                         primary_l = l;
729                                 } else {
730                                         l->info.dst_pos.w = TDM_ALIGN(mode->hdisplay / 3, 2);
731                                         l->info.dst_pos.h = TDM_ALIGN(mode->vdisplay / 3, 2);
732                                         l->info.dst_pos.x = TDM_ALIGN(((mode->hdisplay / 3) / layer_count) * j, 2);
733                                         l->info.dst_pos.y = TDM_ALIGN(((mode->vdisplay / 3) / layer_count) * j, 2);
734                                 }
735                         }
736                 }
737
738                 TDM_EXIT_IF_FAIL(primary_l != NULL);
739                 LIST_DEL(&primary_l->link);
740                 LIST_ADD(&primary_l->link, &o->layer_list);
741         }
742
743         /* fill the empty information of layers */
744         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
745                 tdm_output *output;
746                 int minw, minh, maxw, maxh;
747
748                 output = tdm_display_get_output(data->display, o->idx, &ret);
749                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
750                 ret = tdm_output_get_available_size(output, &minw, &minh, &maxw, &maxh, NULL);
751                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
752
753                 /* l->info.src_config.size will be decided when a buffer shows really */
754                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
755                         if (minw > 0 && minh > 0) {
756                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w >= minw);
757                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h >= minh);
758                         }
759                         if (maxw > 0 && maxh > 0) {
760                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.w <= maxw);
761                                 TDM_EXIT_IF_FAIL(l->info.dst_pos.h <= maxh);
762                         }
763
764                         if (l->owner_p) {
765                                 l->info.src_config.format = l->owner_p->info.dst_config.format;
766                                 if (l->info.src_config.pos.w == 0) {
767                                         TDM_EXIT_IF_FAIL(l->owner_p->info.dst_config.size.h > 0);
768                                         l->info.src_config.pos.w = l->owner_p->info.dst_config.size.h;
769                                         l->info.src_config.pos.h = l->owner_p->info.dst_config.size.v;
770                                 }
771                         } else if (l->owner_c) {
772                                 l->info.src_config.format = l->owner_c->info.dst_config.format;
773                                 if (l->info.src_config.pos.w == 0) {
774                                         TDM_EXIT_IF_FAIL(l->owner_c->info.dst_config.size.h > 0);
775                                         l->info.src_config.pos.w = l->owner_c->info.dst_config.size.h;
776                                         l->info.src_config.pos.h = l->owner_c->info.dst_config.size.v;
777                                 }
778                         } else {
779                                 if (l->info.src_config.pos.w == 0) {
780                                         TDM_EXIT_IF_FAIL(l->info.dst_pos.w > 0);
781                                         l->info.src_config.pos.w = l->info.dst_pos.w;
782                                         l->info.src_config.pos.h = l->info.dst_pos.h;
783                                 }
784                         }
785                 }
786         }
787 }
788
789 static tdm_test_server tts_data;
790 static int tts_buffer_key;
791 #define TTS_BUFFER_KEY ((unsigned long)&tts_buffer_key)
792
793 static tbm_surface_h
794 buffer_allocate(int width, int height, int format, int flags)
795 {
796         tdm_test_server_buffer *tb = calloc(1, sizeof *tb);
797         TDM_EXIT_IF_FAIL(tb != NULL);
798         tb->b = tbm_surface_internal_create_with_flags(width, height, format, flags);
799         TDM_EXIT_IF_FAIL(tb->b != NULL);
800         tdm_helper_clear_buffer(tb->b);
801         tbm_surface_internal_add_user_data(tb->b, TTS_BUFFER_KEY, free);
802         tbm_surface_internal_set_user_data(tb->b, TTS_BUFFER_KEY, tb);
803         return tb->b;
804 }
805
806 static tdm_test_server_buffer*
807 get_tts_buffer(tbm_surface_h b)
808 {
809         tdm_test_server_buffer *tb = NULL;
810         tbm_surface_internal_get_user_data(b, TTS_BUFFER_KEY, (void **)&tb);
811         return tb;
812 }
813
814 static void
815 _voutput_buff_deinit(tdm_test_server_voutput *voutput)
816 {
817         int i;
818
819         for (i = 0; i < 3; i++) {
820                 if (!voutput->bufs[i]) continue;
821
822                 tbm_surface_destroy(voutput->bufs[i]);
823                 voutput->bufs[i] = NULL;
824         }
825 }
826
827 static void
828 _voutput_buff_init(tdm_test_server_voutput *voutput)
829 {
830         tdm_output *output = voutput->output;
831         const tdm_output_mode *mode;
832         tdm_error ret = TDM_ERROR_NONE;
833         int i;
834
835         ret = tdm_output_get_mode(output, &mode);
836         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
837
838         for (i = 0; i < 3; i++) {
839                 tbm_surface_h b = tbm_surface_internal_create_with_flags(mode->hdisplay, mode->vdisplay, DEFAULT_FORMAT, 0);
840                 TDM_EXIT_IF_FAIL(b != NULL);
841                 tdm_test_buffer_fill(b, i);
842                 voutput->bufs[i] = b;
843         }
844 }
845 static void
846 _vlayer_cb_commit(tdm_layer *layer, unsigned int sequence,
847                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
848 {
849         tdm_test_server_voutput *voutput = (tdm_test_server_voutput *)user_data;
850         TDM_EXIT_IF_FAIL(voutput != NULL);
851         tdm_output_conn_status status;
852         tdm_error ret;
853
854         printf("voutput cb:\t %d: l(%p) b(%p)\n", voutput->buf_idx, voutput->layer, voutput->bufs[voutput->buf_idx]);
855
856         ret = tdm_output_get_conn_status(voutput->output, &status);
857         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
858
859         if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) return;
860
861         if (voutput->need_mode_change) {
862                 const tdm_output_mode *modes;
863                 int count = 0;
864
865                 tdm_output_get_available_modes(voutput->output, &modes, &count);
866                 if (count > voutput->index) {
867                         const tdm_output_mode *mode, *current;
868
869                         ret = tdm_output_get_mode(voutput->output, &current);
870                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
871
872                         mode = &modes[voutput->index];
873
874                         if (mode != current) {
875                                 printf("mode change to %d (%dx%d, %d)\n",
876                                         voutput->index, mode->hdisplay, mode->vdisplay, mode->vrefresh);
877                                 _voutput_buff_deinit(voutput);
878                                 _voutput_buff_init(voutput);
879
880                                 ret = tdm_output_set_mode(voutput->output, mode);
881                                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
882
883                                 _voutput_layer_init(voutput);
884                                 voutput->buf_idx = 2;
885                         }
886                 }
887                 voutput->need_mode_change = 0;
888         }
889
890         voutput->buf_idx++;
891         _vlayer_show_buffer(voutput);
892 }
893
894 static void
895 _vlayer_show_buffer(tdm_test_server_voutput *voutput)
896 {
897         tdm_error ret;
898         int index;
899         if (voutput->buf_idx == 3)
900                 voutput->buf_idx = 0;
901
902         index = voutput->buf_idx;
903
904         ret = tdm_layer_set_buffer(voutput->layer, voutput->bufs[index]);
905         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
906
907         ret = tdm_layer_commit(voutput->layer, _vlayer_cb_commit, voutput);
908         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
909
910         printf("voutput show:\t %d: l(%p) b(%p)\n", index, voutput->layer, voutput->bufs[index]);
911 }
912
913 static void
914 _voutput_layer_init(tdm_test_server_voutput *voutput)
915 {
916         tdm_output *output = voutput->output;
917         const tdm_output_mode *mode;
918         tdm_info_layer layer_info;
919         tbm_surface_info_s info;
920         tdm_error ret = TDM_ERROR_NONE;
921
922         ret = tdm_output_get_mode(output, &mode);
923         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
924
925         TDM_ERR("modeinfo : %dx%d %d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
926
927         voutput->layer = tdm_output_get_layer(output, 0, &ret);
928         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
929
930         _voutput_buff_init(voutput);
931
932         tbm_surface_get_info(voutput->bufs[0], &info);
933         memset(&layer_info, 0x0, sizeof(tdm_info_layer));
934         if (IS_RGB(info.format)) {
935                 layer_info.src_config.size.h = info.planes[0].stride >> 2;
936                 layer_info.src_config.size.v  = info.height;
937         } else {
938                 layer_info.src_config.size.h = info.planes[0].stride;
939                 layer_info.src_config.size.v  = info.height;
940         }
941         layer_info.src_config.format = info.format;
942
943         layer_info.src_config.size.h = mode->hdisplay;
944         layer_info.src_config.size.v = mode->vdisplay;
945         layer_info.src_config.pos.x = 0;
946         layer_info.src_config.pos.y = 0;
947         layer_info.src_config.pos.w = mode->hdisplay;
948         layer_info.src_config.pos.h = mode->vdisplay;
949         layer_info.dst_pos.x = 0;
950         layer_info.dst_pos.y = 0;
951         layer_info.dst_pos.w = mode->hdisplay;
952         layer_info.dst_pos.h = mode->vdisplay;
953         layer_info.transform = TDM_TRANSFORM_NORMAL;
954
955         ret = tdm_layer_set_info(voutput->layer, &layer_info);
956         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
957 }
958
959 static void
960 _voutput_connect(tdm_test_server_voutput *voutput)
961 {
962         tdm_output *output;
963         const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
964         int i, count;
965         tdm_error ret;
966
967         output = voutput->output;
968
969         ret = tdm_output_get_available_modes(output, &modes, &count);
970         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
971
972         for (i = 0; i < count; i++) {
973                 if (!best)
974                         best = &modes[i];
975                 if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
976                         prefer = &modes[i];
977         }
978         if (prefer) {
979                 found = prefer;
980                 printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
981         }
982         if (!found && best) {
983                 found = best;
984                 printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
985         }
986         if (!found) {
987                 printf("couldn't find any mode\n");
988                 exit(0);
989         }
990
991         ret = tdm_output_set_mode(output, found);
992         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
993
994         printf("output: %s %d\n", found->name, found->vrefresh);
995
996         ret = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
997         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
998 }
999
1000 static void
1001 _voutput_disconnect(tdm_test_server_voutput *voutput)
1002 {
1003         tdm_output *output;
1004         tdm_error ret;
1005
1006         output = voutput->output;
1007
1008         printf("output: %p disconnect\n", voutput);
1009
1010         ret = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
1011         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1012 }
1013
1014 static void
1015 _tdm_test_server_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data)
1016 {
1017         tdm_test_server_voutput *voutput = NULL;
1018         tdm_output_conn_status status;
1019
1020         voutput = (tdm_test_server_voutput *)user_data;
1021         TDM_EXIT_IF_FAIL(voutput != NULL);
1022
1023         switch (type) {
1024         case TDM_OUTPUT_CHANGE_CONNECTION:
1025                 status = (tdm_output_conn_status)value.u32;
1026                 if (status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
1027                         _voutput_connect(voutput);
1028                         _voutput_layer_init(voutput);
1029                         _vlayer_show_buffer(voutput);
1030                 } else if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1031                         _voutput_disconnect(voutput);
1032                 }
1033                 break;
1034         default:
1035                 break;
1036         }
1037 }
1038
1039 static void
1040 _tdm_test_server_cb_output_mode_change(tdm_output *output, unsigned int index, void *user_data)
1041 {
1042         tdm_test_server_voutput *voutput = NULL;
1043         const tdm_output_mode *modes;
1044         int count = 0;
1045         tdm_error ret;
1046
1047         voutput = (tdm_test_server_voutput *)user_data;
1048         TDM_EXIT_IF_FAIL(voutput != NULL);
1049
1050         ret = tdm_output_get_available_modes(output, &modes, &count);
1051         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
1052         TDM_RETURN_IF_FAIL(index < count);
1053
1054         voutput->need_mode_change = 1;
1055         voutput->index = index;
1056
1057         printf("mode change request. index:%d\n", index);
1058 }
1059
1060 static void
1061 _tdm_output_cb_destroy_handler(tdm_output *output, void *user_data)
1062 {
1063         tdm_test_server_voutput *voutput = NULL;
1064
1065         voutput = (tdm_test_server_voutput *)user_data;
1066         TDM_EXIT_IF_FAIL(voutput != NULL);
1067
1068         tdm_output_remove_mode_change_request_handler(output, _tdm_test_server_cb_output_mode_change, voutput);
1069         tdm_output_remove_change_handler(output, _tdm_test_server_cb_output_change, voutput);
1070         tdm_output_remove_destroy_handler(output, _tdm_output_cb_destroy_handler, voutput);
1071
1072         LIST_DEL(&voutput->link);
1073
1074         _voutput_buff_deinit(voutput);
1075
1076         printf("voutput: %p destroy\n", voutput);
1077
1078         free(voutput);
1079 }
1080
1081 static void
1082 _tdm_output_cb_create_handler(tdm_display *dpy, tdm_output *output, void *user_data)
1083 {
1084         tdm_test_server *data;
1085         tdm_test_server_voutput *voutput = NULL;
1086         tdm_error ret = TDM_ERROR_NONE;
1087
1088         printf("voutput create call\n");
1089
1090         data = (tdm_test_server *)user_data;
1091         TDM_EXIT_IF_FAIL(data != NULL);
1092
1093         voutput = calloc(1, sizeof *voutput);
1094         TDM_EXIT_IF_FAIL(voutput != NULL);
1095
1096         ret = tdm_output_add_change_handler(output, _tdm_test_server_cb_output_change, voutput);
1097         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1098
1099         ret = tdm_output_add_mode_change_request_handler(output, _tdm_test_server_cb_output_mode_change, voutput);
1100         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1101
1102         ret = tdm_output_add_destroy_handler(output, _tdm_output_cb_destroy_handler, voutput);
1103         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1104
1105         voutput->output = output;
1106         voutput->data = data;
1107
1108         printf("voutput %p create done\n", voutput);
1109
1110         LIST_ADDTAIL(&voutput->link, &data->voutput_list);
1111 }
1112
1113 static void
1114 destroy(tdm_test_server *data)
1115 {
1116         tdm_test_server_output *o = NULL, *oo = NULL;
1117         tdm_test_server_layer *l = NULL, *ll = NULL;
1118         tdm_test_server_pp *p = NULL, *pp = NULL;
1119         tdm_test_server_capture *c = NULL, *cc = NULL;
1120         tdm_test_server_prop *w = NULL, *ww = NULL;
1121         tdm_test_server_voutput *v = NULL, *vv = NULL;
1122         tdm_error ret;
1123         int i;
1124
1125         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
1126                 LIST_DEL(&c->link);
1127                 tdm_capture_destroy(c->capture);
1128                 free(c);
1129         }
1130
1131         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
1132                 tdm_display_lock(data->display);
1133                 tdm_event_loop_source_remove(p->timer_source);
1134                 tdm_display_unlock(data->display);
1135
1136                 tdm_pp_destroy(p->pp);
1137         }
1138
1139         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
1140                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
1141                         ret = tdm_layer_unset_buffer(l->layer);
1142                         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1143                 }
1144                 ret = tdm_layer_commit(l->layer, NULL, NULL);
1145                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1146         }
1147
1148         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
1149                 LIST_DEL(&p->link);
1150                 for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++)
1151                         tbm_surface_destroy(p->bufs[i]);
1152                 free(p);
1153         }
1154
1155         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
1156                 LIST_DEL(&o->link);
1157                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
1158                         LIST_DEL(&l->link);
1159                         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) {
1160                                 LIST_DEL(&w->link);
1161                                 free(w);
1162                         }
1163                         for (i = 0; i < TDM_ARRAY_SIZE(l->bufs); i++)
1164                                 tbm_surface_destroy(l->bufs[i]);
1165                         free(l);
1166                 }
1167                 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) {
1168                         LIST_DEL(&w->link);
1169                         free(w);
1170                 }
1171
1172                 free(o);
1173         }
1174
1175         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &data->voutput_list, link) {
1176                 _voutput_buff_deinit(v);
1177                 LIST_DEL(&v->link);
1178                 free(v);
1179         }
1180
1181         if (data->do_voutput)
1182                 tdm_display_remove_output_create_handler(data->display, _tdm_output_cb_create_handler, data);
1183
1184         if (data->display)
1185                 tdm_display_deinit(data->display);
1186
1187         exit(0);
1188 }
1189
1190 int
1191 main(int argc, char *argv[])
1192 {
1193         tdm_test_server *data = &tts_data;
1194         char temp[TDM_SERVER_REPLY_MSG_LEN];
1195         int len = sizeof temp;
1196         tdm_error ret;
1197
1198 #if 1 /* for testing */
1199         const char *s = (const char*)getenv("XDG_RUNTIME_DIR");
1200         if (!s) {
1201                 char buf[32];
1202                 snprintf(buf, sizeof(buf), "/run");
1203                 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
1204                 if (ret != 0)
1205                         exit(0);
1206         }
1207
1208         s = (const char*)getenv("TBM_DISPLAY_SERVER");
1209         if (!s) {
1210                 char buf[32];
1211                 snprintf(buf, sizeof(buf), "1");
1212                 int ret = setenv("TBM_DISPLAY_SERVER", (const char*)buf, 1);
1213                 if (ret != 0)
1214                         exit(0);
1215         }
1216 #endif
1217
1218         memset(data, 0, sizeof * data);
1219         LIST_INITHEAD(&data->output_list);
1220         LIST_INITHEAD(&data->pp_list);
1221         LIST_INITHEAD(&data->capture_list);
1222         LIST_INITHEAD(&data->voutput_list);
1223
1224         /* init value */
1225         data->bflags = TBM_BO_SCANOUT;
1226         data->b_fill = PATTERN_SMPTE;
1227
1228         data->display = tdm_display_init(&ret);
1229         TDM_EXIT_IF_FAIL(data->display != NULL);
1230
1231         parse_args(data, argc, argv);
1232         interpret_args(data);
1233
1234         if (data->do_query) {
1235                 tdm_helper_get_display_information(data->display, temp, &len);
1236                 printf("%s", temp);
1237                 goto done;
1238         }
1239
1240         if (data->do_voutput) {
1241                 printf("support virtual output - server\n");
1242                 ret = tdm_display_add_output_create_handler(data->display, _tdm_output_cb_create_handler, data);
1243                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1244         }
1245
1246         run_test(data);
1247
1248 done:
1249         tdm_display_deinit(data->display);
1250
1251         return 0;
1252 }
1253
1254 static void
1255 output_setup(tdm_test_server_output *o)
1256 {
1257         tdm_test_server *data = o->data;
1258         const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
1259         tdm_test_server_prop *w = NULL;
1260         const tdm_prop *props;
1261         int i, count;
1262         tdm_error ret;
1263
1264         o->output = tdm_display_get_output(data->display, o->idx, &ret);
1265         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1266
1267         ret = tdm_output_get_available_modes(o->output, &modes, &count);
1268         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1269
1270         for (i = 0; i < count; i++) {
1271                 if (!strncmp(o->mode, modes[i].name, TDM_NAME_LEN) && o->refresh == modes[i].vrefresh) {
1272                         found = &modes[i];
1273                         printf("found mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
1274                         break;
1275                 }
1276                 if (!best)
1277                         best = &modes[i];
1278                 if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
1279                         prefer = &modes[i];
1280         }
1281         if (!found && prefer) {
1282                 found = prefer;
1283                 printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
1284         }
1285         if (!found && best) {
1286                 found = best;
1287                 printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
1288         }
1289
1290         if (!found) {
1291                 printf("couldn't find any mode\n");
1292                 exit(0);
1293         }
1294
1295         ret = tdm_output_set_mode(o->output, found);
1296         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1297
1298         printf("output %d: %s %d\n", o->idx, found->name, found->vrefresh);
1299
1300         ret = tdm_output_get_available_properties(o->output, &props, &count);
1301         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1302
1303         LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
1304                 for (i = 0; i < count; i++) {
1305                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
1306                                 continue;
1307                         ret = tdm_output_set_property(o->output, props[i].id, w->value);
1308                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1309                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
1310                         break;
1311                 }
1312         }
1313
1314         /* DPMS on forcely at the first time. */
1315         ret = tdm_output_set_dpms(o->output, TDM_OUTPUT_DPMS_ON);
1316         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1317 }
1318
1319 static tbm_surface_h
1320 layer_get_buffer(tdm_test_server_layer *l)
1321 {
1322         int i, size = TDM_ARRAY_SIZE(l->bufs);
1323         if (!l->bufs[0]) {
1324                 for (i = 0; i < size; i++) {
1325                         int width = (l->info.src_config.size.h) ? : l->info.src_config.pos.w;
1326                         int height = (l->info.src_config.size.v) ? : l->info.src_config.pos.h;
1327                         unsigned int format = (l->info.src_config.format) ? : DEFAULT_FORMAT;
1328                         int flags = l->o->data->bflags;
1329                         tbm_surface_h b = buffer_allocate(width, height, format, flags);
1330                         TDM_EXIT_IF_FAIL(b != NULL);
1331                         l->bufs[i] = b;
1332                 }
1333         }
1334         for (i = 0; i < size; i++) {
1335                 tdm_test_server_buffer *tb = get_tts_buffer(l->bufs[i]);
1336                 TDM_EXIT_IF_FAIL(tb != NULL);
1337                 if (!tb->in_use)
1338                         return l->bufs[i];
1339         }
1340         printf("no available layer buffer.\n");
1341         exit(0);
1342 }
1343
1344 static void
1345 layer_cb_commit(tdm_layer *layer, unsigned int sequence,
1346                                 unsigned int tv_sec, unsigned int tv_usec,
1347                                 void *user_data)
1348 {
1349         tdm_test_server_layer *l = user_data;
1350         tbm_surface_h b = layer_get_buffer(l);
1351         TDM_EXIT_IF_FAIL(b != NULL);
1352
1353         if (!l->is_primary || l->o->fill_primary_layer)
1354                 tdm_test_buffer_fill(b, l->data->b_fill);
1355
1356         if (!l->is_primary || l->o->fill_primary_layer)
1357                 layer_show_buffer(l, b);
1358 }
1359
1360 static void
1361 layer_cb_buffer_release(tbm_surface_h b, void *user_data)
1362 {
1363         tdm_test_server_buffer *tb = get_tts_buffer(b);
1364         TDM_EXIT_IF_FAIL(tb != NULL);
1365
1366         tb->in_use = 0;
1367         tdm_buffer_remove_release_handler(b, layer_cb_buffer_release, NULL);
1368         if (tb->done)
1369                 tb->done(b, user_data);
1370 }
1371
1372 static void
1373 layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b)
1374 {
1375         tdm_test_server *data = l->o->data;
1376         tdm_test_server_buffer *tb;
1377         tdm_error ret;
1378
1379         ret = tdm_layer_set_buffer(l->layer, b);
1380         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1381
1382         tb = get_tts_buffer(b);
1383         TDM_EXIT_IF_FAIL(tb != NULL);
1384
1385         tb->in_use = 1;
1386         ret = tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
1387         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1388
1389         if (data->do_vblank)
1390                 ret = tdm_layer_commit(l->layer, layer_cb_commit, l);
1391         else
1392                 ret = tdm_layer_commit(l->layer, NULL, NULL);
1393         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1394
1395         printf("show:\tl(%p) b(%p)\n", l, b);
1396 }
1397
1398 static void
1399 layer_setup(tdm_test_server_layer *l, tbm_surface_h b)
1400 {
1401         tdm_test_server_prop *w = NULL;
1402         const tdm_prop *props;
1403         int i, count;
1404         tdm_error ret;
1405         tbm_surface_info_s info;
1406
1407         l->layer = tdm_output_get_layer(l->o->output, l->idx, &ret);
1408         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1409
1410         /* The size and format information should be same with buffer's */
1411         tbm_surface_get_info(b, &info);
1412         if (IS_RGB(info.format)) {
1413                 l->info.src_config.size.h = info.planes[0].stride >> 2;
1414                 l->info.src_config.size.v = info.height;
1415         } else {
1416                 l->info.src_config.size.h = info.planes[0].stride;
1417                 l->info.src_config.size.v = info.height;
1418         }
1419         l->info.src_config.format = info.format;
1420
1421         ret = tdm_layer_set_info(l->layer, &l->info);
1422         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1423
1424         printf("layer %d: output(%d) ", l->idx, l->o->idx);
1425         print_config(&l->info.src_config);
1426         printf(" ! ");
1427         print_pos(&l->info.dst_pos);
1428         printf(" transform(%s)\n", tdm_transform_str(l->info.transform));
1429
1430         ret = tdm_layer_get_available_properties(l->layer, &props, &count);
1431         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1432
1433         LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
1434                 for (i = 0; i < count; i++) {
1435                         if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
1436                                 continue;
1437                         ret = tdm_layer_set_property(l->layer, props[i].id, w->value);
1438                         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1439                         printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
1440                         break;
1441                 }
1442         }
1443 }
1444
1445 static tbm_surface_h
1446 pp_get_buffer(tdm_test_server_pp *p)
1447 {
1448         int i, size = TDM_ARRAY_SIZE(p->bufs);
1449         if (!p->bufs[0]) {
1450                 for (i = 0; i < size; i++) {
1451                         int width = (p->info.src_config.size.h) ? : p->info.src_config.pos.w;
1452                         int height = (p->info.src_config.size.v) ? : p->info.src_config.pos.h;
1453                         unsigned int format = (p->info.src_config.format) ? : DEFAULT_FORMAT;
1454                         tbm_surface_h b = buffer_allocate(width, height, format, 0);
1455                         TDM_EXIT_IF_FAIL(b != NULL);
1456                         p->bufs[i] = b;
1457                 }
1458         }
1459         for (i = 0; i < size; i++) {
1460                 tdm_test_server_buffer *tb = get_tts_buffer(p->bufs[i]);
1461
1462                 if (tb == NULL)
1463                         continue;
1464
1465                 if (!tb->in_use) {
1466                         tdm_test_buffer_fill(p->bufs[i], p->data->b_fill);
1467                         return p->bufs[i];
1468                 }
1469         }
1470         printf("no available pp buffer.\n");
1471         exit(0);
1472 }
1473
1474 static void
1475 pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
1476 {
1477         tdm_test_server_buffer *stb, *dtb;
1478
1479         stb = get_tts_buffer(sb);
1480         TDM_EXIT_IF_FAIL(stb != NULL);
1481
1482         dtb = get_tts_buffer(db);
1483         TDM_EXIT_IF_FAIL(dtb != NULL);
1484
1485         stb->in_use = dtb->in_use = 0;
1486
1487         layer_show_buffer(dtb->l, db);
1488 }
1489
1490 static void
1491 pp_convert_buffer(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1492 {
1493         tdm_test_server_buffer *stb, *dtb;
1494         tdm_error ret;
1495
1496         stb = get_tts_buffer(sb);
1497         TDM_EXIT_IF_FAIL(stb != NULL);
1498
1499         dtb = get_tts_buffer(db);
1500         TDM_EXIT_IF_FAIL(dtb != NULL);
1501
1502         stb->in_use = dtb->in_use = 1;
1503         dtb->l = p->l;
1504
1505         ret = tdm_pp_attach(p->pp, sb, db);
1506         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1507
1508         ret = tdm_pp_commit(p->pp);
1509         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1510
1511         printf("convt:\tp(%p) sb(%p) db(%p)\n", p, sb, db);
1512 }
1513
1514 /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1515  * backend module. I use them only for simulating the video play. When we call
1516  * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1517  * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1518  * called, the display has been already locked. So in this test application,
1519  * we have to unlock/lock the display for testing.
1520  */
1521 static tdm_error
1522 pp_cb_timeout(void *user_data)
1523 {
1524         tdm_test_server_pp *p = user_data;
1525         tdm_test_server *data = p->l->o->data;
1526         tbm_surface_h sb, db;
1527         tdm_error ret;
1528
1529         tdm_display_unlock(data->display);
1530
1531         sb = pp_get_buffer(p);
1532         TDM_EXIT_IF_FAIL(sb != NULL);
1533         db = layer_get_buffer(p->l);
1534         TDM_EXIT_IF_FAIL(db != NULL);
1535
1536         pp_convert_buffer(p, sb, db);
1537
1538         tdm_display_lock(data->display);
1539         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1540         tdm_display_unlock(data->display);
1541         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1542
1543         tdm_display_lock(data->display);
1544
1545         return TDM_ERROR_NONE;
1546 }
1547
1548 static void
1549 pp_setup(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1550 {
1551         tdm_test_server *data;
1552         tbm_surface_info_s info;
1553         tdm_error ret;
1554
1555         if (!p || !p->l || !p->l->o || !p->l->o->data) {
1556                 TDM_ERR("invalid parameter failed");
1557                 exit(0);
1558         }
1559         data = p->l->o->data;
1560
1561         p->pp = tdm_display_create_pp(data->display, &ret);
1562         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1563
1564         /* The size and format information should be same with buffer's */
1565         tbm_surface_get_info(sb, &info);
1566         if (IS_RGB(info.format)) {
1567                 p->info.src_config.size.h = info.planes[0].stride >> 2;
1568                 p->info.src_config.size.v = info.height;
1569         } else {
1570                 p->info.src_config.size.h = info.planes[0].stride;
1571                 p->info.src_config.size.v = info.height;
1572         }
1573         p->info.src_config.format = info.format;
1574
1575         /* The size and format information should be same with buffer's */
1576         tbm_surface_get_info(db, &info);
1577         if (IS_RGB(info.format)) {
1578                 p->info.dst_config.size.h = info.planes[0].stride >> 2;
1579                 p->info.dst_config.size.v = info.height;
1580         } else {
1581                 p->info.dst_config.size.h = info.planes[0].stride;
1582                 p->info.dst_config.size.v = info.height;
1583         }
1584         p->info.dst_config.format = info.format;
1585
1586         ret = tdm_pp_set_info(p->pp, &p->info);
1587         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1588
1589         ret = tdm_pp_set_done_handler(p->pp, pp_cb_done, NULL);
1590         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1591
1592         printf("pp: ");
1593         print_config(&p->info.src_config);
1594         printf(" ! ");
1595         print_config(&p->info.dst_config);
1596         printf(" fps(%d) transform(%s)\n", p->fps, tdm_transform_str(p->info.transform));
1597         printf("\toutput_idx(%d) layer_idx(%d)\n", p->l->o->idx, p->l->idx);
1598
1599         layer_setup(p->l, db);
1600
1601         /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1602          * backend module. I use them only for simulating the video play. When we call
1603          * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1604          * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1605          * called, the display has been already locked. So in this test application,
1606          * we have to unlock/lock the display for testing.
1607          */
1608         tdm_display_lock(data->display);
1609         p->timer_source = tdm_event_loop_add_timer_handler(data->display, pp_cb_timeout, p, &ret);
1610         tdm_display_unlock(data->display);
1611         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1612
1613         tdm_display_lock(data->display);
1614         ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1615         tdm_display_unlock(data->display);
1616         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1617 }
1618
1619 static void
1620 capture_cb_buffer_done(tbm_surface_h b, void *user_data)
1621 {
1622         tdm_test_server_buffer *tb;
1623
1624         tb = get_tts_buffer(b);
1625         TDM_EXIT_IF_FAIL(tb != NULL);
1626
1627         capture_attach(tb->c, b);
1628 }
1629
1630 static void
1631 capture_cb_done(tdm_capture *capture, tbm_surface_h b, void *user_data)
1632 {
1633         tdm_test_server_buffer *tb;
1634
1635         tb = get_tts_buffer(b);
1636         TDM_EXIT_IF_FAIL(tb != NULL);
1637
1638         tb->in_use = 0;
1639
1640         tb->done = capture_cb_buffer_done;
1641         layer_show_buffer(tb->l, b);
1642 }
1643
1644 static void
1645 capture_attach(tdm_test_server_capture *c, tbm_surface_h b)
1646 {
1647         tdm_error ret;
1648         tdm_test_server_buffer *tb;
1649
1650         tb = get_tts_buffer(b);
1651         TDM_EXIT_IF_FAIL(tb != NULL);
1652
1653         tb->in_use = 1;
1654         tb->l = c->l;
1655         tb->c = c;
1656
1657         ret = tdm_capture_attach(c->capture, b);
1658         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1659
1660         printf("capture:\tc(%p) b(%p)\n", c, b);
1661
1662         ret = tdm_capture_commit(c->capture);
1663         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1664 }
1665
1666 static void
1667 capture_setup(tdm_test_server_capture *c, tbm_surface_h b)
1668 {
1669         tdm_test_server *data;
1670         tdm_output *output;
1671         tdm_layer *layer;
1672         tbm_surface_info_s info;
1673         tdm_error ret;
1674
1675         if (!c || !c->l || !c->l->o || !c->l->o->data) {
1676                 TDM_ERR("invalid parameter failed");
1677                 exit(0);
1678         }
1679         data = c->l->o->data;
1680
1681         if (c->output_idx != -1 && c->layer_idx == -1) {
1682                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1683                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1684                 c->capture = tdm_output_create_capture(output, &ret);
1685                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1686         } else if (c->output_idx != -1 && c->layer_idx != -1) {
1687                 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1688                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1689                 layer = tdm_output_get_layer(output, c->layer_idx, &ret);
1690                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1691                 c->capture = tdm_layer_create_capture(layer, &ret);
1692                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1693         }
1694
1695         TDM_EXIT_IF_FAIL(c->capture != NULL);
1696
1697         /* The size and format information should be same with buffer's */
1698         tbm_surface_get_info(b, &info);
1699         if (IS_RGB(info.format)) {
1700                 c->info.dst_config.size.h = info.planes[0].stride >> 2;
1701                 c->info.dst_config.size.v = info.height;
1702         } else {
1703                 c->info.dst_config.size.h = info.planes[0].stride;
1704                 c->info.dst_config.size.v = info.height;
1705         }
1706         c->info.dst_config.format = info.format;
1707         c->info.type = TDM_CAPTURE_TYPE_ONESHOT;
1708
1709         ret = tdm_capture_set_info(c->capture, &c->info);
1710         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1711
1712         ret = tdm_capture_set_done_handler(c->capture, capture_cb_done, NULL);
1713         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1714
1715         printf("capture: o(%d) l(%d) ", c->output_idx, c->layer_idx);
1716         print_config(&c->info.dst_config);
1717         printf(" transform(%s)\n", tdm_transform_str(c->info.transform));
1718         printf("\toutput_idx(%d) layer_idx(%d)\n", c->l->o->idx, c->l->idx);
1719
1720         layer_setup(c->l, b);
1721 }
1722
1723 static void
1724 run_test(tdm_test_server *data)
1725 {
1726         tdm_test_server_output *o = NULL;
1727         tdm_test_server_layer *l = NULL;
1728         tdm_test_server_pp *p = NULL;
1729         tdm_test_server_capture *c = NULL;
1730         tdm_display_capability caps;
1731         tdm_error ret;
1732
1733         ret = tdm_display_get_capabilities(data->display, &caps);
1734         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1735
1736         LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
1737                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1738                         if (!l->owner_p && !l->owner_c) {
1739                                 tbm_surface_h b;
1740                                 b = layer_get_buffer(l);
1741                                 if (!l->is_primary || l->o->fill_primary_layer)
1742                                         tdm_test_buffer_fill(b, data->b_fill);
1743                                 layer_setup(l, b);
1744                                 layer_show_buffer(l, b);
1745                         }
1746                 }
1747         }
1748
1749         LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
1750                 tbm_surface_h sb, db;
1751                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_PP, no_pp);
1752                 sb = pp_get_buffer(p);
1753                 TDM_EXIT_IF_FAIL(sb != NULL);
1754                 db = layer_get_buffer(p->l);
1755                 TDM_EXIT_IF_FAIL(db != NULL);
1756                 pp_setup(p, sb, db);
1757                 pp_convert_buffer(p, sb, db);
1758         }
1759
1760         LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
1761                 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_CAPTURE, no_capture);
1762                 tbm_surface_h b;
1763                 b = layer_get_buffer(c->l);
1764                 capture_setup(c, b);
1765                 capture_attach(c, b);
1766                 b = layer_get_buffer(c->l);
1767                 capture_attach(c, b);
1768                 b = layer_get_buffer(c->l);
1769                 capture_attach(c, b);
1770         }
1771
1772         printf("enter test loop\n");
1773
1774         while (1) {
1775                 ret = tdm_display_handle_events(data->display);
1776                 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1777         }
1778
1779         destroy(data);
1780
1781         return;
1782 no_pp:
1783         printf("no PP capability\n");
1784         exit(0);
1785 no_capture:
1786         printf("no Capture capability\n");
1787         exit(0);
1788 }