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