1 /**************************************************************************
5 * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
45 #include <tbm_surface.h>
46 #include <tbm_surface_internal.h>
51 #include "tdm_helper.h"
52 #include "tdm_backend.h"
54 #include "tdm_macro.h"
55 #include "tdm_private.h"
58 ////////////////////////////////////////////////////////////////////////////////
79 static struct typestrings typestrs[] = {
80 {OPT_QRY, "Query", NULL},
81 {OPT_TST, "Test", NULL},
82 {OPT_GEN, "General", NULL},
85 static struct optstrings optstrs[] = {
87 OPT_QRY, "q", "show tdm output, layer information",
91 OPT_TST, "a", "set all layer objects for all connected outputs",
95 OPT_TST, "o", "set a mode for a output object",
96 "<output_idx>@<mode>[&<refresh>]", "0@1920x1080"
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
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
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
111 OPT_GEN, "w", "set the property of a object",
112 "<prop_name>:<value>", NULL
115 OPT_GEN, "b", "set the fill(smtpe,tiles,plain) and framebuffer type(scanout,noncachable,wc)",
116 "<fill>[:<buf_flag>[,<buf_flag2>[,...]]]", NULL
119 OPT_GEN, "v", "update layers every vblank",
129 static struct usagestring usages[] = {
136 "test all outputs, layers with plain buffers"
140 "Set the \"1920x1080\" mode to the output 0. And show a buffer via a primary layer of the output 0"
143 "-o 0@1920x1080 -l 1~640x480+50+100",
144 "Create the 640x480 buffer and show it in the (50,100) pos of screen via the layer 1"
147 "-p 320x240@NV12~480x360+80+40,640x480@AR24 -l 1~640x480+50+100",
148 "Convert the 320x240@NV12 buffer to the 640x480@AR24 buffer(480x360+80+40) and show the result via the layer 1"
153 usage(char *app_name)
155 int type_size = sizeof(typestrs) / sizeof(struct typestrings);
156 int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
157 int usages_size = sizeof(usages) / sizeof(struct usagestring);
160 printf("usage: %s \n\n", app_name);
162 for (t = 0; t < type_size; t++) {
165 for (o = 0; o < opt_size; o++)
166 if (optstrs[o].type == typestrs[t].type) {
168 printf(" %s options: %s\n\n", typestrs[t].string, (typestrs[t].desc) ? : "");
169 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
171 printf("\t\t %s\n", optstrs[o].arg);
173 printf("\t\t ex) %s\n", optstrs[o].ex);
179 printf(" For example)\n\n");
181 for (t = 0; t < usages_size; t++) {
182 printf(" $ %s %s\n", app_name, usages[t].string);
183 printf("\t%s\n", usages[t].desc);
188 ////////////////////////////////////////////////////////////////////////////////
190 static const char *tdm_buf_flag_names[] = {
195 TDM_BIT_NAME_FB(buf_flag)
197 #define DEFAULT_FORMAT TBM_FORMAT_ARGB8888
199 #define print_size(s) \
200 printf("%dx%d", (s)->h, (s)->v)
201 #define print_pos(p) \
202 printf("%dx%d+%d+%d", (p)->w, (p)->h, (p)->x, (p)->y)
203 #define print_format(f) \
204 if (f) printf("%c%c%c%c", FOURCC_STR(f)); \
206 #define print_config(c) \
208 print_size(&(c)->size); \
210 print_pos(&(c)->pos); \
212 print_format((c)->format); \
214 #define print_prop(w) \
215 printf("%s(%d)", (w)->name, ((w)->value).u32)
217 typedef struct _tdm_test_server tdm_test_server;
218 typedef struct _tdm_test_server_layer tdm_test_server_layer;
219 typedef struct _tdm_test_server_capture tdm_test_server_capture;
221 typedef struct _tdm_test_server_prop {
223 char name[TDM_NAME_LEN];
226 /* variables for test */
227 struct list_head link;
228 } tdm_test_server_prop;
230 typedef struct _tdm_test_server_buffer {
231 /* variables for test */
234 tdm_test_server_layer *l;
236 tdm_test_server_capture *c;
237 tdm_buffer_release_handler done;
238 } tdm_test_server_buffer;
240 typedef struct _tdm_test_server_output {
243 char mode[TDM_NAME_LEN];
246 /* variables for test */
247 struct list_head link;
248 struct list_head prop_list;
249 struct list_head layer_list;
250 tdm_test_server *data;
253 int fill_primary_layer;
254 } tdm_test_server_output;
256 typedef struct _tdm_test_server_pp {
261 /* variables for test */
262 struct list_head link;
263 tdm_test_server *data;
264 tdm_test_server_layer *l;
266 tbm_surface_h bufs[6];
269 tdm_event_loop_source *timer_source;
270 } tdm_test_server_pp;
272 struct _tdm_test_server_capture {
276 tdm_info_capture info;
278 /* variables for test */
279 struct list_head link;
280 tdm_test_server *data;
281 tdm_test_server_layer *l;
282 tdm_capture *capture;
285 struct _tdm_test_server_layer {
290 /* variables for test */
291 struct list_head link;
292 struct list_head prop_list;
293 tdm_test_server *data;
294 tdm_test_server_output *o;
297 tdm_test_server_pp *owner_p;
298 tdm_test_server_capture *owner_c;
299 tbm_surface_h bufs[3];
303 struct _tdm_test_server {
311 /* variables for test */
312 struct list_head output_list;
313 struct list_head pp_list;
314 struct list_head capture_list;
315 tdm_display *display;
318 static void destroy(tdm_test_server *data);
319 static void run_test(tdm_test_server *data);
320 static void output_setup(tdm_test_server_output *o);
321 static void layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b);
322 static void capture_attach(tdm_test_server_capture *c, tbm_surface_h b);
325 parse_size(tdm_size *size, char *arg)
328 size->h = strtol(arg, &end, 10);
329 TDM_EXIT_IF_FAIL(*end == 'x');
331 size->v = strtol(arg, &end, 10);
336 parse_pos(tdm_pos *pos, char *arg)
339 pos->w = strtol(arg, &end, 10);
340 TDM_EXIT_IF_FAIL(*end == 'x');
342 pos->h = strtol(arg, &end, 10);
345 pos->x = strtol(arg, &end, 10);
346 TDM_EXIT_IF_FAIL(*end == '+');
348 pos->y = strtol(arg, &end, 10);
354 parse_config(tdm_info_config *config, char *arg)
357 end = parse_pos(&config->pos, arg);
360 end = parse_size(&config->size, arg);
365 end = strtostr(temp, 32, arg, TDM_DELIM);
366 config->format = FOURCC_ID(temp);
372 parse_arg_o(tdm_test_server_output *o, char *arg)
375 TDM_EXIT_IF_FAIL(arg != NULL);
376 o->idx = strtol(arg, &end, 10);
377 TDM_EXIT_IF_FAIL(*end == '@');
379 end = strtostr(o->mode, TDM_NAME_LEN, arg, TDM_DELIM);
382 o->refresh = strtol(arg, &end, 10);
387 parse_arg_p(tdm_test_server_pp *p, char *arg)
389 tdm_info_pp *pp_info = &p->info;
391 TDM_EXIT_IF_FAIL(arg != NULL);
392 end = parse_config(&pp_info->src_config, arg);
393 TDM_EXIT_IF_FAIL(*end == '~');
395 end = parse_config(&pp_info->dst_config, arg);
398 pp_info->transform = strtol(arg, &end, 10);
402 p->fps = strtol(arg, &end, 10);
407 parse_arg_c(tdm_test_server_capture *c, char *arg)
409 tdm_info_capture *capture_info = &c->info;
411 TDM_EXIT_IF_FAIL(arg != NULL);
412 c->output_idx = strtol(arg, &end, 10);
415 c->layer_idx = strtol(arg, &end, 10);
417 TDM_EXIT_IF_FAIL(*end == '~');
419 end = parse_config(&capture_info->dst_config, arg);
422 capture_info->transform = strtol(arg, &end, 10);
426 if (strtol(arg, &end, 10) > 0)
427 capture_info->type = TDM_CAPTURE_TYPE_STREAM;
429 capture_info->type = TDM_CAPTURE_TYPE_ONESHOT;
434 parse_arg_l(tdm_test_server_layer *l, char *arg)
436 tdm_info_layer *layer_info = &l->info;
438 TDM_EXIT_IF_FAIL(arg != NULL);
439 l->idx = strtol(arg, &end, 10);
442 end = parse_config(&layer_info->src_config, arg);
444 TDM_EXIT_IF_FAIL(*end == '~');
446 end = parse_pos(&layer_info->dst_pos, arg);
449 layer_info->transform = strtol(arg, &end, 10);
454 parse_arg_w(tdm_test_server_prop *w, char *arg)
457 TDM_EXIT_IF_FAIL(arg != NULL);
458 end = strtostr(w->name, TDM_PATH_LEN, arg, TDM_DELIM);
459 TDM_EXIT_IF_FAIL(*end == ':');
461 w->value.u32 = strtol(arg, &end, 10);
465 parse_arg_b(tdm_test_server *data, char *arg)
468 char temp[TDM_NAME_LEN] = {0,};
469 TDM_EXIT_IF_FAIL(arg != NULL);
471 end = strtostr(temp, 32, arg, TDM_DELIM);
472 if (!strncmp(temp, "smpte", 5))
473 data->b_fill = PATTERN_SMPTE;
474 else if (!strncmp(temp, "tiles", 5))
475 data->b_fill = PATTERN_TILES;
476 else if (!strncmp(temp, "plain", 5))
477 data->b_fill = PATTERN_PLAIN;
479 printf("'%s': unknown flag\n", temp);
486 snprintf(temp, TDM_NAME_LEN, "%s", arg);
487 arg = strtok_r(temp, ",", &end);
489 if (!strncmp(arg, "default", 7))
490 printf("Ignore '%s' flag\n", arg);
491 else if (!strncmp(arg, "scanout", 7))
492 data->bflags |= TBM_BO_SCANOUT;
493 else if (!strncmp(arg, "noncachable", 11))
494 data->bflags |= TBM_BO_NONCACHABLE;
495 else if (!strncmp(arg, "wc", 2))
496 data->bflags |= TBM_BO_WC;
498 printf("'%s': unknown flag\n", arg);
501 arg = strtok_r(NULL, ",", &end);
507 parse_args(tdm_test_server *data, int argc, char *argv[])
509 tdm_test_server_output *o = NULL;
510 tdm_test_server_layer *l = NULL;
511 tdm_test_server_pp *p = NULL;
512 tdm_test_server_capture *c = NULL;
513 tdm_test_server_prop *w = NULL;
514 void *last_option = NULL;
515 void *last_object = NULL;
524 for (i = 1; i < argc; i++) {
525 if (!strncmp(argv[i] + 1, "q", 1)) {
528 } else if (!strncmp(argv[i] + 1, "a", 1)) {
530 } else if (!strncmp(argv[i] + 1, "o", 1)) {
531 TDM_GOTO_IF_FAIL(data->do_all == 0, all);
532 o = calloc(1, sizeof * o);
533 TDM_EXIT_IF_FAIL(o != NULL);
535 LIST_INITHEAD(&o->layer_list);
536 LIST_INITHEAD(&o->prop_list);
537 LIST_ADDTAIL(&o->link, &data->output_list);
538 parse_arg_o(o, argv[++i]);
540 } else if (!strncmp(argv[i] + 1, "p", 1)) {
541 TDM_GOTO_IF_FAIL(data->do_all == 0, all);
542 p = calloc(1, sizeof * p);
543 TDM_EXIT_IF_FAIL(p != NULL);
545 p->fps = 30; /* default 30 fps */
546 LIST_ADDTAIL(&p->link, &data->pp_list);
547 parse_arg_p(p, argv[++i]);
549 } else if (!strncmp(argv[i] + 1, "c", 1)) {
550 TDM_GOTO_IF_FAIL(data->do_all == 0, all);
551 c = calloc(1, sizeof * c);
552 TDM_EXIT_IF_FAIL(c != NULL);
556 LIST_ADDTAIL(&c->link, &data->capture_list);
557 parse_arg_c(c, argv[++i]);
559 } else if (!strncmp(argv[i] + 1, "l", 1)) {
560 TDM_GOTO_IF_FAIL(data->do_all == 0, all);
562 o = calloc(1, sizeof * o);
563 TDM_EXIT_IF_FAIL(o != NULL);
565 LIST_INITHEAD(&o->layer_list);
566 LIST_INITHEAD(&o->prop_list);
567 LIST_ADDTAIL(&o->link, &data->output_list);
569 l = calloc(1, sizeof * l);
570 TDM_EXIT_IF_FAIL(l != NULL);
571 LIST_INITHEAD(&l->prop_list);
572 LIST_ADDTAIL(&l->link, &o->layer_list);
575 parse_arg_l(l, argv[++i]);
576 if (p && last_option == p) {
579 } else if (c && last_option == c) {
584 } else if (!strncmp(argv[i] + 1, "w", 1)) {
585 TDM_GOTO_IF_FAIL(data->do_all == 0, all);
588 w = calloc(1, sizeof * w);
589 TDM_EXIT_IF_FAIL(w != NULL);
590 if (o && last_object == o)
591 LIST_ADDTAIL(&w->link, &o->prop_list);
592 else if (l && last_object == l)
593 LIST_ADDTAIL(&w->link, &l->prop_list);
594 parse_arg_w(w, argv[++i]);
595 } else if (!strncmp(argv[i] + 1, "b", 1)) {
596 parse_arg_b(data, argv[++i]);
597 } else if (!strncmp(argv[i] + 1, "v", 1)) {
606 LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
610 LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
617 printf("Use '-l' to set a layer for '-p' or '-c'.\n");
620 printf("Use '-o' or '-l' to set a object first.\n");
623 printf("Can't use '-%s' with '-a'.\n", argv[i] + 1);
628 interpret_args(tdm_test_server *data)
630 tdm_test_server_output *o = NULL;
631 tdm_test_server_layer *l = NULL;
634 /* create the objects of outputs */
638 ret = tdm_display_get_output_count(data->display, &output_count);
639 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
641 for (i = 0; i < output_count; i++) {
642 tdm_output *output = tdm_display_get_output(data->display, i, NULL);
643 tdm_output_conn_status status;
644 ret = tdm_output_get_conn_status(output, &status);
645 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
647 if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
649 o = calloc(1, sizeof * o);
650 TDM_EXIT_IF_FAIL(o != NULL);
652 LIST_INITHEAD(&o->layer_list);
653 LIST_INITHEAD(&o->prop_list);
654 LIST_ADDTAIL(&o->link, &data->output_list);
656 o->fill_primary_layer = 1;
660 /* check if the primary layer object exists */
661 LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
663 const tdm_output_mode *mode;
664 int j, layer_count, primary_index = 0;
665 tdm_test_server_layer *primary_l = NULL;
669 output = tdm_display_get_output(data->display, o->idx, &ret);
670 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
671 ret = tdm_output_get_mode(output, &mode);
672 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
673 ret = tdm_output_get_layer_count(output, &layer_count);
674 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
675 ret = tdm_output_get_primary_index(output, &primary_index);
676 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
678 if (LIST_IS_EMPTY(&o->layer_list))
679 o->fill_primary_layer = 1;
681 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
682 if (l->idx == primary_index) {
684 o->fill_primary_layer = 1;
691 if (!primary_l || data->do_all) {
692 for (j = 0; j < layer_count; j++) {
693 if (j != primary_index && !data->do_all)
695 l = calloc(1, sizeof * l);
696 TDM_EXIT_IF_FAIL(l != NULL);
697 LIST_INITHEAD(&l->prop_list);
698 LIST_ADDTAIL(&l->link, &o->layer_list);
702 if (j == primary_index) {
704 l->info.dst_pos.w = mode->hdisplay;
705 l->info.dst_pos.h = mode->vdisplay;
708 l->info.dst_pos.w = TDM_ALIGN(mode->hdisplay / 3, 2);
709 l->info.dst_pos.h = TDM_ALIGN(mode->vdisplay / 3, 2);
710 l->info.dst_pos.x = TDM_ALIGN(((mode->hdisplay / 3) / layer_count) * j, 2);
711 l->info.dst_pos.y = TDM_ALIGN(((mode->vdisplay / 3) / layer_count) * j, 2);
716 TDM_EXIT_IF_FAIL(primary_l != NULL);
717 LIST_DEL(&primary_l->link);
718 LIST_ADD(&primary_l->link, &o->layer_list);
721 /* fill the empty information of layers */
722 LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
724 int minw, minh, maxw, maxh;
726 output = tdm_display_get_output(data->display, o->idx, &ret);
727 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
728 ret = tdm_output_get_available_size(output, &minw, &minh, &maxw, &maxh, NULL);
729 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
731 /* l->info.src_config.size will be decided when a buffer shows really */
732 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
733 if (minw > 0 && minh > 0) {
734 TDM_EXIT_IF_FAIL(l->info.dst_pos.w >= minw);
735 TDM_EXIT_IF_FAIL(l->info.dst_pos.h >= minh);
737 if (maxw > 0 && maxh > 0) {
738 TDM_EXIT_IF_FAIL(l->info.dst_pos.w <= maxw);
739 TDM_EXIT_IF_FAIL(l->info.dst_pos.h <= maxh);
743 l->info.src_config.format = l->owner_p->info.dst_config.format;
744 if (l->info.src_config.pos.w == 0) {
745 TDM_EXIT_IF_FAIL(l->owner_p->info.dst_config.size.h > 0);
746 l->info.src_config.pos.w = l->owner_p->info.dst_config.size.h;
747 l->info.src_config.pos.h = l->owner_p->info.dst_config.size.v;
749 } else if (l->owner_c) {
750 l->info.src_config.format = l->owner_c->info.dst_config.format;
751 if (l->info.src_config.pos.w == 0) {
752 TDM_EXIT_IF_FAIL(l->owner_c->info.dst_config.size.h > 0);
753 l->info.src_config.pos.w = l->owner_c->info.dst_config.size.h;
754 l->info.src_config.pos.h = l->owner_c->info.dst_config.size.v;
757 if (l->info.src_config.pos.w == 0) {
758 TDM_EXIT_IF_FAIL(l->info.dst_pos.w > 0);
759 l->info.src_config.pos.w = l->info.dst_pos.w;
760 l->info.src_config.pos.h = l->info.dst_pos.h;
767 static tdm_test_server tts_data;
768 static int tts_buffer_key;
769 #define TTS_BUFFER_KEY ((unsigned long)&tts_buffer_key)
772 buffer_allocate(int width, int height, int format, int flags)
774 tdm_test_server_buffer *tb = calloc(1, sizeof *tb);
775 TDM_EXIT_IF_FAIL(tb != NULL);
776 tb->b = tbm_surface_internal_create_with_flags(width, height, format, flags);
777 TDM_EXIT_IF_FAIL(tb->b != NULL);
778 tdm_helper_clear_buffer(tb->b);
779 tbm_surface_internal_add_user_data(tb->b, TTS_BUFFER_KEY, free);
780 tbm_surface_internal_set_user_data(tb->b, TTS_BUFFER_KEY, tb);
784 static tdm_test_server_buffer*
785 get_tts_buffer(tbm_surface_h b)
787 tdm_test_server_buffer *tb = NULL;
788 tbm_surface_internal_get_user_data(b, TTS_BUFFER_KEY, (void **)&tb);
793 destroy(tdm_test_server *data)
795 tdm_test_server_output *o = NULL, *oo = NULL;
796 tdm_test_server_layer *l = NULL, *ll = NULL;
797 tdm_test_server_pp *p = NULL, *pp = NULL;
798 tdm_test_server_capture *c = NULL, *cc = NULL;
799 tdm_test_server_prop *w = NULL, *ww = NULL;
803 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
805 tdm_capture_destroy(c->capture);
809 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
810 tdm_display_lock(data->display);
811 tdm_event_loop_source_remove(p->timer_source);
812 tdm_display_unlock(data->display);
814 tdm_pp_destroy(p->pp);
817 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
818 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
819 ret = tdm_layer_unset_buffer(l->layer);
820 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
822 ret = tdm_layer_commit(l->layer, NULL, NULL);
823 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
826 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
828 for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++)
829 tbm_surface_destroy(p->bufs[i]);
833 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
835 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
837 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) {
841 for (i = 0; i < TDM_ARRAY_SIZE(l->bufs); i++)
842 tbm_surface_destroy(l->bufs[i]);
845 LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) {
854 tdm_display_deinit(data->display);
860 main(int argc, char *argv[])
862 tdm_test_server *data = &tts_data;
863 char temp[TDM_SERVER_REPLY_MSG_LEN];
864 int len = sizeof temp;
867 #if 1 /* for testing */
868 const char *s = (const char*)getenv("XDG_RUNTIME_DIR");
871 snprintf(buf, sizeof(buf), "/run");
872 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
877 s = (const char*)getenv("TBM_DISPLAY_SERVER");
880 snprintf(buf, sizeof(buf), "1");
881 int ret = setenv("TBM_DISPLAY_SERVER", (const char*)buf, 1);
887 memset(data, 0, sizeof * data);
888 LIST_INITHEAD(&data->output_list);
889 LIST_INITHEAD(&data->pp_list);
890 LIST_INITHEAD(&data->capture_list);
893 data->bflags = TBM_BO_SCANOUT;
894 data->b_fill = PATTERN_SMPTE;
896 data->display = tdm_display_init(&ret);
897 TDM_EXIT_IF_FAIL(data->display != NULL);
899 parse_args(data, argc, argv);
900 interpret_args(data);
902 if (data->do_query) {
903 tdm_helper_get_display_information(data->display, temp, &len);
911 tdm_display_deinit(data->display);
917 output_setup(tdm_test_server_output *o)
919 tdm_test_server *data = o->data;
920 const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
921 tdm_test_server_prop *w = NULL;
922 const tdm_prop *props;
926 o->output = tdm_display_get_output(data->display, o->idx, &ret);
927 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
929 ret = tdm_output_get_available_modes(o->output, &modes, &count);
930 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
932 for (i = 0; i < count; i++) {
933 if (!strncmp(o->mode, modes[i].name, TDM_NAME_LEN) && o->refresh == modes[i].vrefresh) {
935 printf("found mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
940 if (modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
943 if (!found && prefer) {
945 printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
947 if (!found && best) {
949 printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
953 printf("couldn't find any mode\n");
957 ret = tdm_output_set_mode(o->output, found);
958 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
960 printf("output %d: %s %d\n", o->idx, found->name, found->vrefresh);
962 ret = tdm_output_get_available_properties(o->output, &props, &count);
963 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
965 LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
966 for (i = 0; i < count; i++) {
967 if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
969 ret = tdm_output_set_property(o->output, props[i].id, w->value);
970 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
971 printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
976 /* DPMS on forcely at the first time. */
977 ret = tdm_output_set_dpms(o->output, TDM_OUTPUT_DPMS_ON);
978 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
982 layer_get_buffer(tdm_test_server_layer *l)
984 int i, size = TDM_ARRAY_SIZE(l->bufs);
986 for (i = 0; i < size; i++) {
987 int width = (l->info.src_config.size.h) ? : l->info.src_config.pos.w;
988 int height = (l->info.src_config.size.v) ? : l->info.src_config.pos.h;
989 unsigned int format = (l->info.src_config.format) ? : DEFAULT_FORMAT;
990 int flags = l->o->data->bflags;
991 tbm_surface_h b = buffer_allocate(width, height, format, flags);
992 TDM_EXIT_IF_FAIL(b != NULL);
996 for (i = 0; i < size; i++) {
997 tdm_test_server_buffer *tb = get_tts_buffer(l->bufs[i]);
998 TDM_EXIT_IF_FAIL(tb != NULL);
1002 printf("no available layer buffer.\n");
1007 layer_cb_commit(tdm_layer *layer, unsigned int sequence,
1008 unsigned int tv_sec, unsigned int tv_usec,
1011 tdm_test_server_layer *l = user_data;
1012 tbm_surface_h b = layer_get_buffer(l);
1013 TDM_EXIT_IF_FAIL(b != NULL);
1015 if (!l->is_primary || l->o->fill_primary_layer)
1016 tdm_test_buffer_fill(b, l->data->b_fill);
1018 if (!l->is_primary || l->o->fill_primary_layer)
1019 layer_show_buffer(l, b);
1023 layer_cb_buffer_release(tbm_surface_h b, void *user_data)
1025 tdm_test_server_buffer *tb = get_tts_buffer(b);
1026 TDM_EXIT_IF_FAIL(tb != NULL);
1029 tdm_buffer_remove_release_handler(b, layer_cb_buffer_release, NULL);
1031 tb->done(b, user_data);
1035 layer_show_buffer(tdm_test_server_layer *l, tbm_surface_h b)
1037 tdm_test_server *data = l->o->data;
1038 tdm_test_server_buffer *tb;
1041 ret = tdm_layer_set_buffer(l->layer, b);
1042 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1044 tb = get_tts_buffer(b);
1045 TDM_EXIT_IF_FAIL(tb != NULL);
1048 ret = tdm_buffer_add_release_handler(b, layer_cb_buffer_release, NULL);
1049 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1051 if (data->do_vblank)
1052 ret = tdm_layer_commit(l->layer, layer_cb_commit, l);
1054 ret = tdm_layer_commit(l->layer, NULL, NULL);
1055 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1057 printf("show:\tl(%p) b(%p)\n", l, b);
1061 layer_setup(tdm_test_server_layer *l, tbm_surface_h b)
1063 tdm_test_server_prop *w = NULL;
1064 const tdm_prop *props;
1067 tbm_surface_info_s info;
1069 l->layer = tdm_output_get_layer(l->o->output, l->idx, &ret);
1070 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1072 /* The size and format information should be same with buffer's */
1073 tbm_surface_get_info(b, &info);
1074 if (IS_RGB(info.format)) {
1075 l->info.src_config.size.h = info.planes[0].stride >> 2;
1076 l->info.src_config.size.v = info.height;
1078 l->info.src_config.size.h = info.planes[0].stride;
1079 l->info.src_config.size.v = info.height;
1081 l->info.src_config.format = info.format;
1083 ret = tdm_layer_set_info(l->layer, &l->info);
1084 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1086 printf("layer %d: output(%d) ", l->idx, l->o->idx);
1087 print_config(&l->info.src_config);
1089 print_pos(&l->info.dst_pos);
1090 printf(" transform(%s)\n", tdm_transform_str(l->info.transform));
1092 ret = tdm_layer_get_available_properties(l->layer, &props, &count);
1093 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1095 LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
1096 for (i = 0; i < count; i++) {
1097 if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
1099 ret = tdm_layer_set_property(l->layer, props[i].id, w->value);
1100 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1101 printf("\tprop '%s': %d\n", props[i].name, w->value.u32);
1107 static tbm_surface_h
1108 pp_get_buffer(tdm_test_server_pp *p)
1110 int i, size = TDM_ARRAY_SIZE(p->bufs);
1112 for (i = 0; i < size; i++) {
1113 int width = (p->info.src_config.size.h) ? : p->info.src_config.pos.w;
1114 int height = (p->info.src_config.size.v) ? : p->info.src_config.pos.h;
1115 unsigned int format = (p->info.src_config.format) ? : DEFAULT_FORMAT;
1116 tbm_surface_h b = buffer_allocate(width, height, format, 0);
1117 TDM_EXIT_IF_FAIL(b != NULL);
1121 for (i = 0; i < size; i++) {
1122 tdm_test_server_buffer *tb = get_tts_buffer(p->bufs[i]);
1128 tdm_test_buffer_fill(p->bufs[i], p->data->b_fill);
1132 printf("no available pp buffer.\n");
1137 pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
1139 tdm_test_server_buffer *stb, *dtb;
1141 stb = get_tts_buffer(sb);
1142 TDM_EXIT_IF_FAIL(stb != NULL);
1144 dtb = get_tts_buffer(db);
1145 TDM_EXIT_IF_FAIL(dtb != NULL);
1147 stb->in_use = dtb->in_use = 0;
1149 layer_show_buffer(dtb->l, db);
1153 pp_convert_buffer(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1155 tdm_test_server_buffer *stb, *dtb;
1158 stb = get_tts_buffer(sb);
1159 TDM_EXIT_IF_FAIL(stb != NULL);
1161 dtb = get_tts_buffer(db);
1162 TDM_EXIT_IF_FAIL(dtb != NULL);
1164 stb->in_use = dtb->in_use = 1;
1167 ret = tdm_pp_attach(p->pp, sb, db);
1168 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1170 ret = tdm_pp_commit(p->pp);
1171 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1173 printf("convt:\tp(%p) sb(%p) db(%p)\n", p, sb, db);
1176 /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1177 * backend module. I use them only for simulating the video play. When we call
1178 * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1179 * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1180 * called, the display has been already locked. So in this test application,
1181 * we have to unlock/lock the display for testing.
1184 pp_cb_timeout(void *user_data)
1186 tdm_test_server_pp *p = user_data;
1187 tdm_test_server *data = p->l->o->data;
1188 tbm_surface_h sb, db;
1191 tdm_display_unlock(data->display);
1193 sb = pp_get_buffer(p);
1194 TDM_EXIT_IF_FAIL(sb != NULL);
1195 db = layer_get_buffer(p->l);
1196 TDM_EXIT_IF_FAIL(db != NULL);
1198 pp_convert_buffer(p, sb, db);
1200 tdm_display_lock(data->display);
1201 ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1202 tdm_display_unlock(data->display);
1203 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1205 tdm_display_lock(data->display);
1207 return TDM_ERROR_NONE;
1211 pp_setup(tdm_test_server_pp *p, tbm_surface_h sb, tbm_surface_h db)
1213 tdm_test_server *data;
1214 tbm_surface_info_s info;
1217 if (!p || !p->l || !p->l->o || !p->l->o->data) {
1218 TDM_ERR("invalid parameter failed");
1221 data = p->l->o->data;
1223 p->pp = tdm_display_create_pp(data->display, &ret);
1224 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1226 /* The size and format information should be same with buffer's */
1227 tbm_surface_get_info(sb, &info);
1228 if (IS_RGB(info.format)) {
1229 p->info.src_config.size.h = info.planes[0].stride >> 2;
1230 p->info.src_config.size.v = info.height;
1232 p->info.src_config.size.h = info.planes[0].stride;
1233 p->info.src_config.size.v = info.height;
1235 p->info.src_config.format = info.format;
1237 /* The size and format information should be same with buffer's */
1238 tbm_surface_get_info(db, &info);
1239 if (IS_RGB(info.format)) {
1240 p->info.dst_config.size.h = info.planes[0].stride >> 2;
1241 p->info.dst_config.size.v = info.height;
1243 p->info.dst_config.size.h = info.planes[0].stride;
1244 p->info.dst_config.size.v = info.height;
1246 p->info.dst_config.format = info.format;
1248 ret = tdm_pp_set_info(p->pp, &p->info);
1249 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1251 ret = tdm_pp_set_done_handler(p->pp, pp_cb_done, NULL);
1252 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1255 print_config(&p->info.src_config);
1257 print_config(&p->info.dst_config);
1258 printf(" fps(%d) transform(%s)\n", p->fps, tdm_transform_str(p->info.transform));
1259 printf("\toutput_idx(%d) layer_idx(%d)\n", p->l->o->idx, p->l->idx);
1261 layer_setup(p->l, db);
1263 /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
1264 * backend module. I use them only for simulating the video play. When we call
1265 * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
1266 * the TDM display. And when the callback function of tdm_event_loop_xxx() is
1267 * called, the display has been already locked. So in this test application,
1268 * we have to unlock/lock the display for testing.
1270 tdm_display_lock(data->display);
1271 p->timer_source = tdm_event_loop_add_timer_handler(data->display, pp_cb_timeout, p, &ret);
1272 tdm_display_unlock(data->display);
1273 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1275 tdm_display_lock(data->display);
1276 ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
1277 tdm_display_unlock(data->display);
1278 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1282 capture_cb_buffer_done(tbm_surface_h b, void *user_data)
1284 tdm_test_server_buffer *tb;
1286 tb = get_tts_buffer(b);
1287 TDM_EXIT_IF_FAIL(tb != NULL);
1289 capture_attach(tb->c, b);
1293 capture_cb_done(tdm_capture *capture, tbm_surface_h b, void *user_data)
1295 tdm_test_server_buffer *tb;
1297 tb = get_tts_buffer(b);
1298 TDM_EXIT_IF_FAIL(tb != NULL);
1302 tb->done = capture_cb_buffer_done;
1303 layer_show_buffer(tb->l, b);
1307 capture_attach(tdm_test_server_capture *c, tbm_surface_h b)
1310 tdm_test_server_buffer *tb;
1312 tb = get_tts_buffer(b);
1313 TDM_EXIT_IF_FAIL(tb != NULL);
1319 ret = tdm_capture_attach(c->capture, b);
1320 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1322 printf("capture:\tc(%p) b(%p)\n", c, b);
1324 ret = tdm_capture_commit(c->capture);
1325 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1329 capture_setup(tdm_test_server_capture *c, tbm_surface_h b)
1331 tdm_test_server *data;
1334 tbm_surface_info_s info;
1337 if (!c || !c->l || !c->l->o || !c->l->o->data) {
1338 TDM_ERR("invalid parameter failed");
1341 data = c->l->o->data;
1343 if (c->output_idx != -1 && c->layer_idx == -1) {
1344 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1345 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1346 c->capture = tdm_output_create_capture(output, &ret);
1347 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1348 } else if (c->output_idx != -1 && c->layer_idx != -1) {
1349 output = tdm_display_get_output(data->display, c->output_idx, &ret);
1350 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1351 layer = tdm_output_get_layer(output, c->layer_idx, &ret);
1352 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1353 c->capture = tdm_layer_create_capture(layer, &ret);
1354 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1357 TDM_EXIT_IF_FAIL(c->capture != NULL);
1359 /* The size and format information should be same with buffer's */
1360 tbm_surface_get_info(b, &info);
1361 if (IS_RGB(info.format)) {
1362 c->info.dst_config.size.h = info.planes[0].stride >> 2;
1363 c->info.dst_config.size.v = info.height;
1365 c->info.dst_config.size.h = info.planes[0].stride;
1366 c->info.dst_config.size.v = info.height;
1368 c->info.dst_config.format = info.format;
1369 c->info.type = TDM_CAPTURE_TYPE_ONESHOT;
1371 ret = tdm_capture_set_info(c->capture, &c->info);
1372 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1374 ret = tdm_capture_set_done_handler(c->capture, capture_cb_done, NULL);
1375 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1377 printf("capture: o(%d) l(%d) ", c->output_idx, c->layer_idx);
1378 print_config(&c->info.dst_config);
1379 printf(" transform(%s)\n", tdm_transform_str(c->info.transform));
1380 printf("\toutput_idx(%d) layer_idx(%d)\n", c->l->o->idx, c->l->idx);
1382 layer_setup(c->l, b);
1386 run_test(tdm_test_server *data)
1388 tdm_test_server_output *o = NULL;
1389 tdm_test_server_layer *l = NULL;
1390 tdm_test_server_pp *p = NULL;
1391 tdm_test_server_capture *c = NULL;
1392 tdm_display_capability caps;
1395 ret = tdm_display_get_capabilities(data->display, &caps);
1396 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1398 LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
1399 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1400 if (!l->owner_p && !l->owner_c) {
1402 b = layer_get_buffer(l);
1403 if (!l->is_primary || l->o->fill_primary_layer)
1404 tdm_test_buffer_fill(b, data->b_fill);
1406 layer_show_buffer(l, b);
1411 LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
1412 tbm_surface_h sb, db;
1413 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_PP, no_pp);
1414 sb = pp_get_buffer(p);
1415 TDM_EXIT_IF_FAIL(sb != NULL);
1416 db = layer_get_buffer(p->l);
1417 TDM_EXIT_IF_FAIL(db != NULL);
1418 pp_setup(p, sb, db);
1419 pp_convert_buffer(p, sb, db);
1422 LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
1423 TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_CAPTURE, no_capture);
1425 b = layer_get_buffer(c->l);
1426 capture_setup(c, b);
1427 capture_attach(c, b);
1428 b = layer_get_buffer(c->l);
1429 capture_attach(c, b);
1430 b = layer_get_buffer(c->l);
1431 capture_attach(c, b);
1434 printf("enter test loop\n");
1437 ret = tdm_display_handle_events(data->display);
1438 TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
1445 printf("no PP capability\n");
1448 printf("no Capture capability\n");