Merge branch 'tizen' into sandbox/cyeon/devel
[platform/core/uifw/libtdm.git] / tools / tdm_test_client.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 <poll.h>
40 #include <errno.h>
41 #include <time.h>
42 #include <stdint.h>
43 #include <png.h>
44
45 #include "tdm_client.h"
46 #include "tdm_macro.h"
47 #include "buffers.h"
48
49 #define CHECK_V_STEP 0
50
51 typedef struct _tdm_test_client_arg {
52         char *output_name;
53         int fps;
54         int sync;
55         int interval;
56         int offset;
57         int enable_fake;
58         int pid;
59         char *vblank_name;
60 } tdm_test_client_arg;
61
62 typedef struct _tdm_test_client {
63         tdm_test_client_arg args;
64
65         int do_query;
66         int do_vblank;
67         int do_voutput;
68         int waiting;
69
70         tdm_client *client;
71         tdm_client_voutput *voutput;
72         tdm_client_output *output;
73 } tdm_test_client;
74
75 struct typestrings {
76         int type;
77         const char *string;
78 };
79
80 struct optstrings {
81         int  type;
82         const char *opt;
83         const char *desc;
84         const char *arg;
85         const char *ex;
86 };
87
88 enum {
89         OPT_QRY,
90         OPT_TST,
91         OPT_GNR,
92 };
93
94 static struct typestrings typestrs[] = {
95         {OPT_QRY, "Query"},
96         {OPT_TST, "Test"},
97         {OPT_GNR, "General"},
98 };
99
100 static struct optstrings optstrs[] = {
101         {OPT_QRY, "qo", "output objects info", "<output_name>", "primary"},
102         {OPT_TST, "v", "vblank test", "<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake][^vblank_name]", "primary,0@60~1+0*1^test"},
103         {OPT_TST, "V", "virtual output test", NULL, NULL},
104 };
105
106 static void
107 usage(char *app_name)
108 {
109         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
110         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
111         int t;
112
113         printf("usage: %s \n\n", app_name);
114
115         for (t = 0; t < type_size; t++) {
116                 int o, f = 1;
117
118                 for (o = 0; o < opt_size; o++)
119                         if (optstrs[o].type == typestrs[t].type) {
120                                 if (f == 1)
121                                         printf(" %s options:\n\n", typestrs[t].string);
122                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
123                                 if (optstrs[o].arg)
124                                         printf("\t\t  %s\n", optstrs[o].arg);
125                                 if (optstrs[o].ex)
126                                         printf("\t\t  ex) %s\n", optstrs[o].ex);
127                                 f = 0;
128                         }
129                 printf("\n");
130         }
131
132         exit(0);
133 }
134
135 //"<output_name>"
136 static void
137 parse_arg_qo(tdm_test_client *data, char *arg)
138 {
139         char name[TDM_NAME_LEN];
140         strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
141         data->args.output_name = strndup(name, TDM_NAME_LEN);
142 }
143
144 //"<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]"
145 static void
146 parse_arg_v(tdm_test_client *data, char *arg)
147 {
148         char *end = arg;
149         char name[TDM_NAME_LEN];
150
151         end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
152         data->args.output_name = strndup(name, TDM_NAME_LEN);
153
154         if (*end == ',') {
155                 arg = end + 1;
156                 data->args.sync = strtol(arg, &end, 10);
157         }
158
159         if (*end == '@') {
160                 arg = end + 1;
161                 data->args.fps = strtol(arg, &end, 10);
162         }
163
164         if (*end == '~') {
165                 arg = end + 1;
166                 data->args.interval = strtol(arg, &end, 10);
167         }
168
169         if (*end == '+' || *end == '-') {
170                 arg = end;
171                 data->args.offset = strtol(arg, &end, 10);
172         }
173
174         if (*end == '*') {
175                 arg = end + 1;
176                 data->args.enable_fake = strtol(arg, &end, 10);
177         }
178
179         if (*end == '^') {
180                 char name[TDM_NAME_LEN];
181                 arg = end + 1;
182                 end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
183                 data->args.vblank_name = strndup(name, TDM_NAME_LEN);
184         }
185 }
186
187 static void
188 parse_args(tdm_test_client *data, int argc, char *argv[])
189 {
190         int i;
191
192         if (argc < 2) {
193                 usage(argv[0]);
194                 exit(0);
195         }
196
197         memset(data, 0, sizeof *data);
198         data->args.interval = 1;
199
200         for (i = 1; i < argc; i++) {
201                 if (!strncmp(argv[i] + 1, "qo", 2)) {
202                         data->do_query = 1;
203                         parse_arg_qo(data, argv[++i]);
204                 } else if (!strncmp(argv[i] + 1, "v", 1)) {
205                         data->do_vblank = 1;
206                         parse_arg_v(data, argv[++i]);
207                 } else if (!strncmp(argv[i] + 1, "V", 1)) {
208                         data->do_voutput = 1;
209                 } else {
210                         usage(argv[0]);
211                         exit(0);
212                 }
213         }
214 }
215
216 static double
217 get_time(void)
218 {
219         struct timespec tp;
220
221         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
222                 return (double)tp.tv_sec + ((double)tp.tv_nsec) / 1000000000.0;
223
224         return 0;
225 }
226
227 static void
228 _client_vblank_handler(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
229                                            unsigned int tv_sec, unsigned int tv_usec, void *user_data)
230 {
231         tdm_test_client *data = user_data;
232         double cur, vbl;
233         static double p_vbl = 0;
234
235         data->waiting = 0;
236
237         if (error == TDM_ERROR_DPMS_OFF) {
238                 printf("exit: dpms off\n");
239                 exit(0);
240         }
241
242         if (error != TDM_ERROR_NONE) {
243                 printf("exit: error(%d)\n", error);
244                 exit(0);
245         }
246
247         cur = get_time();
248         vbl = (double)tv_sec + ((double)tv_usec) / 1000000.0;
249
250         printf("vblank              : %.6f us vbl(%.6f)\n", vbl - p_vbl, vbl);
251
252         if (cur - vbl > 0.002) /* 2ms */
253                 printf("kernel -> tdm-client: %.0f us\n", (cur - vbl) * 1000000.0);
254
255         p_vbl = vbl;
256 }
257
258 static char *conn_str[3] = {"disconnected", "connected", "mode_setted"};
259 static char *dpms_str[4] = {"on", "standy", "suspend", "off"};
260
261 static void
262 _client_output_handler(tdm_client_output *output, tdm_output_change_type type,
263                                            tdm_value value, void *user_data)
264 {
265         if (type == TDM_OUTPUT_CHANGE_CONNECTION)
266                 printf("output %s.\n", conn_str[value.u32]);
267         else if (type == TDM_OUTPUT_CHANGE_DPMS)
268                 printf("dpms %s.\n", dpms_str[value.u32]);
269 }
270
271 static void
272 do_query(tdm_test_client *data)
273 {
274         tdm_client_output *output;
275         tdm_output_conn_status status;
276         tdm_output_dpms dpms;
277         unsigned int refresh;
278         tdm_error error;
279
280         output = tdm_client_get_output(data->client, NULL, &error);
281         if (error != TDM_ERROR_NONE) {
282                 printf("tdm_client_get_output failed\n");
283                 return;
284         }
285
286         error = tdm_client_output_get_conn_status(output, &status);
287         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
288         error = tdm_client_output_get_dpms(output, &dpms);
289         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
290         error = tdm_client_output_get_refresh_rate(output, &refresh);
291         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
292
293         printf("tdm_output \"%s\"\n", data->args.output_name);
294         printf("\tstatus : %s\n", conn_str[status]);
295         printf("\tdpms : %s\n", dpms_str[dpms]);
296         printf("\trefresh : %d\n", refresh);
297 }
298
299 static void
300 do_vblank(tdm_test_client *data)
301 {
302         tdm_client_output *output;
303         tdm_client_vblank *vblank = NULL;
304         tdm_error error;
305         int fd = -1;
306         struct pollfd fds;
307
308         output = tdm_client_get_output(data->client, data->args.output_name, &error);
309         if (error != TDM_ERROR_NONE) {
310                 printf("tdm_client_get_output failed\n");
311                 return;
312         }
313
314         error = tdm_client_output_add_change_handler(output, _client_output_handler, NULL);
315         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
316
317         vblank = tdm_client_output_create_vblank(output, &error);
318         if (error != TDM_ERROR_NONE) {
319                 printf("tdm_client_output_create_vblank failed\n");
320                 return;
321         }
322
323         error = tdm_client_vblank_set_name(vblank, data->args.vblank_name);
324         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
325         error = tdm_client_vblank_set_enable_fake(vblank, data->args.enable_fake);
326         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
327         error = tdm_client_vblank_set_sync(vblank, data->args.sync);
328         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
329         if (data->args.fps > 0) {
330                 error = tdm_client_vblank_set_fps(vblank, data->args.fps);
331                 TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
332         }
333         error = tdm_client_vblank_set_offset(vblank, data->args.offset);
334         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
335
336         error = tdm_client_get_fd(data->client, &fd);
337         if (error != TDM_ERROR_NONE || fd < 0) {
338                 printf("tdm_client_get_fd failed\n");
339                 goto done;
340         }
341
342         fds.events = POLLIN;
343         fds.fd = fd;
344         fds.revents = 0;
345
346         while (1) {
347                 int ret;
348
349                 if (!data->waiting) {
350                         error = tdm_client_vblank_wait(vblank, data->args.interval,
351                                                                                    _client_vblank_handler, data);
352                         if (error == TDM_ERROR_DPMS_OFF) {
353                                 printf("tdm_client_vblank_wait failed (dpms off)\n");
354                                 goto done;
355                         }
356                         if (error != TDM_ERROR_NONE) {
357                                 printf("tdm_client_vblank_wait failed (error: %d)\n", error);
358                                 goto done;
359                         }
360                         data->waiting = 1;
361                 }
362
363                 if (!data->args.sync) {
364                         ret = poll(&fds, 1, -1);
365                         if (ret < 0) {
366                                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
367                                         continue;
368                                 else {
369                                         printf("poll failed: %m\n");
370                                         goto done;
371                                 }
372                         }
373
374                         error = tdm_client_handle_events(data->client);
375                         if (error != TDM_ERROR_NONE) {
376                                 printf("tdm_client_handle_events failed\n");
377                                 goto done;
378                         }
379                 }
380         }
381
382 done:
383         if (vblank)
384                 tdm_client_vblank_destroy(vblank);
385 }
386
387 #define PNG_DEPTH 8
388
389 void
390 _tdm_client_get_buffer_full_size(tbm_surface_h buffer, int *buffer_w, int *buffer_h)
391 {
392         tbm_surface_info_s info;
393         int ret;
394
395         TDM_RETURN_IF_FAIL(buffer != NULL);
396
397         ret = tbm_surface_get_info(buffer, &info);
398         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
399
400         if (buffer_w) {
401                 if (IS_RGB(info.format))
402                         *buffer_w = info.planes[0].stride >> 2;
403                 else
404                         *buffer_w = info.planes[0].stride;
405         }
406
407         if (buffer_h)
408                 *buffer_h = info.planes[0].size / info.planes[0].stride;
409 }
410
411 static void
412 _tdm_client_dump_png(const char *file, const void *data, int width,
413                                          int height)
414 {
415         FILE *fp;
416
417         fp = fopen(file, "wb");
418         TDM_RETURN_IF_FAIL(fp != NULL);
419
420         png_structp pPngStruct =
421                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
422         if (!pPngStruct) {
423                 fclose(fp);
424                 return;
425         }
426
427         png_infop pPngInfo = png_create_info_struct(pPngStruct);
428         if (!pPngInfo) {
429                 png_destroy_write_struct(&pPngStruct, NULL);
430                 fclose(fp);
431                 return;
432         }
433
434         png_init_io(pPngStruct, fp);
435         png_set_IHDR(pPngStruct,
436                                  pPngInfo,
437                                  width,
438                                  height,
439                                  PNG_DEPTH,
440                                  PNG_COLOR_TYPE_RGBA,
441                                  PNG_INTERLACE_NONE,
442                                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
443
444         png_set_bgr(pPngStruct);
445         png_write_info(pPngStruct, pPngInfo);
446
447         const int pixel_size = 4;       // RGBA
448         png_bytep *row_pointers =
449                 png_malloc(pPngStruct, height * sizeof(png_byte *));
450         if (!row_pointers) {
451                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
452                 fclose(fp);
453                 return;
454         }
455
456         unsigned int *blocks = (unsigned int *)data;
457         int y = 0;
458         int x = 0;
459
460         for (; y < height; ++y) {
461                 png_bytep row =
462                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
463                 if (!row) {
464                         for (x = 0; x < y; x++)
465                                 png_free(pPngStruct, row_pointers[x]);
466                         png_free(pPngStruct, row_pointers);
467                         png_destroy_write_struct(&pPngStruct, &pPngInfo);
468                         fclose(fp);
469                         return;
470                 }
471
472                 row_pointers[y] = (png_bytep)row;
473                 for (x = 0; x < width; ++x) {
474                         unsigned int curBlock = blocks[y * width + x];
475                         row[x * pixel_size] = (curBlock & 0xFF);
476                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
477                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
478                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
479                 }
480         }
481
482         png_write_image(pPngStruct, row_pointers);
483         png_write_end(pPngStruct, pPngInfo);
484
485         for (y = 0; y < height; y++)
486                 png_free(pPngStruct, row_pointers[y]);
487         png_free(pPngStruct, row_pointers);
488
489         png_destroy_write_struct(&pPngStruct, &pPngInfo);
490
491         fclose(fp);
492 }
493
494 void
495 _tdm_client_dump_buffer(tbm_surface_h buffer, const char *file)
496 {
497         char temp[TDM_PATH_LEN] = {0,};
498         tbm_surface_info_s info;
499         int len, ret;
500         const char *ext;
501         int bo_cnt;
502         int bw, bh;
503         char *dot, *p = temp;
504         const char *file_exts[2] = {"png", "raw"};
505
506         TDM_RETURN_IF_FAIL(buffer != NULL);
507         TDM_RETURN_IF_FAIL(file != NULL);
508
509         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
510         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
511
512         if (IS_RGB(info.format))
513                 ext = file_exts[0];
514         else
515                 ext = file_exts[1];
516
517         dot = strrchr(file, '.');
518         if (!dot || strlen(dot + 1) != 3 || strncmp(dot + 1, ext, 3)) {
519                 len = strnlen(file, TDM_PATH_LEN - 5);
520                 strncat(p, file, len);
521                 p += len;
522                 *(p++) = '.';
523                 strncat(p, ext, 4);
524                 p += 3;
525                 *p = '\0';
526         } else {
527                 len = strnlen(file, TDM_PATH_LEN - 1);
528                 strncat(p, file, len);
529                 p += len;
530                 *p = '\0';
531         }
532
533         _tdm_client_get_buffer_full_size(buffer, &bw, &bh);
534
535         bo_cnt = tbm_surface_internal_get_num_bos(buffer);
536         TDM_DBG("buffer: bo_cnt(%d) %dx%d(%dx%d) %c%c%c%c, plane: (%p+%d, %d,%d) (%p+%d, %d,%d) (%p+%d, %d,%d)",
537                         bo_cnt, bw, bh, info.width, info.height, FOURCC_STR(info.format),
538                         info.planes[0].ptr, info.planes[0].offset, info.planes[0].stride, info.planes[0].size,
539                         info.planes[1].ptr, info.planes[1].offset, info.planes[1].stride, info.planes[1].size,
540                         info.planes[2].ptr, info.planes[2].offset, info.planes[2].stride, info.planes[2].size);
541
542         _tdm_client_dump_png(temp, info.planes[0].ptr, bw, bh);
543
544         tbm_surface_unmap(buffer);
545
546         printf("dump %s\n", temp);
547 }
548
549 static void
550 _dump_buffer(tbm_surface_h buffer, int count)
551 {
552         char temp[TDM_PATH_LEN] = {0,};
553
554         snprintf(temp, TDM_PATH_LEN, "/tmp/%c%c%c%c_%dx%d_%d",
555                 FOURCC_STR(tbm_surface_get_format(buffer)),
556                 tbm_surface_get_width(buffer),
557                 tbm_surface_get_height(buffer),
558                 count);
559         _tdm_client_dump_buffer(buffer, temp);
560 }
561
562 static void
563 _voutput_commit(tdm_client_voutput *voutput, tbm_surface_h buffer, void *user_data)
564 {
565         tdm_test_client *data = (tdm_test_client *)user_data;
566         static int count = 0;
567
568         TDM_EXIT_IF_FAIL(data != NULL);
569         TDM_EXIT_IF_FAIL(buffer != NULL);
570
571         if ((count < 10) || (count >= 31 && count <= 40))
572                 _dump_buffer(buffer, count);
573         count++;
574
575         if (count == 30) {
576                 printf("client: %d commited(%p), mode change request to index 1\n", count, buffer);
577                 tdm_client_voutput_set_mode(data->voutput, 1);
578         } else if (count == 50) {
579                 printf("client: %d commited(%p), disconnect\n", count, buffer);
580                 tdm_client_voutput_disconnect(data->voutput);
581         } else {
582                 printf("client: %d commited(%p)\n", count, buffer);
583         }
584
585         tdm_client_voutput_commit_done(voutput);
586 }
587
588 static void
589 _voutput_output_handler(tdm_client_output *output, tdm_output_change_type type,
590                                            tdm_value value, void *user_data)
591 {
592         tdm_client_voutput *voutput = NULL;
593         tdm_output_conn_status status;
594         tdm_test_client *data;
595         unsigned int width, height;
596
597         data = (tdm_test_client *) user_data;
598         TDM_RETURN_IF_FAIL(data != NULL);
599         voutput = data->voutput;
600         TDM_RETURN_IF_FAIL(voutput != NULL);
601
602         if (type == TDM_OUTPUT_CHANGE_CONNECTION) {
603                 status = (tdm_output_conn_status)value.u32;
604                 printf("output %s.\n", conn_str[value.u32]);
605
606                 if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
607                         printf("client: disconnected, destroy voutput\n");
608                         tdm_client_output_remove_change_handler(output, _voutput_output_handler, data);
609 #if CHECK_V_STEP
610                         printf("press enter to continuet\n");
611                         getchar();
612 #endif
613                         tdm_client_voutput_destroy(voutput);
614                 } else if (status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
615                         printf("client: connected\n");
616                 } else if (status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED) {
617                         tdm_client_output_get_mode(output, &width, &height);
618                         printf("client: mode setted(%dx%d)\n", width, height);
619 #if CHECK_V_STEP
620                         printf("press enter to continuet\n");
621                         getchar();
622 #endif
623                 }
624         } else if (type == TDM_OUTPUT_CHANGE_DPMS) {
625                 printf("output %s.\n", dpms_str[value.u32]);
626         }
627 }
628
629 static void
630 _voutput_make_available_mode(tdm_client_output_mode *modes, int count)
631 {
632         int i;
633         for (i = 0 ; i < count; i++) {
634                 modes[i].clock = 25200;
635                 modes[i].hdisplay = 640 * (count - i);
636                 modes[i].hsync_start = 656;
637                 modes[i].hsync_end = 752;
638                 modes[i].htotal = 800;
639                 modes[i].hskew = 0;
640                 modes[i].vdisplay = 480 * (count - i);
641                 modes[i].vsync_start = 490;
642                 modes[i].vsync_end = 492;
643                 modes[i].vtotal = 525;
644                 modes[i].vscan = 0;
645                 modes[i].vrefresh = 30;
646                 modes[i].flags = 0;
647                 modes[i].type = 0;
648                 snprintf(modes[i].name, TDM_NAME_LEN, "%dx%d_%d", modes[i].hdisplay, modes[i].vdisplay, i);
649         }
650 }
651
652 static void
653 do_voutput(tdm_test_client *data)
654 {
655         tdm_client_voutput *voutput = NULL;
656         tdm_client_output *output = NULL;
657         tdm_client_output_mode modes[2];
658         tdm_error ret = TDM_ERROR_NONE;
659
660         printf("virtual output test - client\n");
661
662         voutput = tdm_client_create_voutput(data->client, "virtual-test", &ret);
663         TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
664
665         ret = tdm_client_voutput_add_commit_handler(voutput, _voutput_commit, data);
666         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
667
668         output = tdm_client_voutput_get_client_output(voutput, &ret);
669         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
670
671         ret = tdm_client_output_add_change_handler(output, _voutput_output_handler, data);
672         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
673
674         ret = tdm_client_voutput_set_physical_size(voutput, 300, 200);
675         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
676
677         _voutput_make_available_mode(modes, 2);
678         ret = tdm_client_voutput_set_available_modes(voutput, modes, 2);
679         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
680 #if CHECK_V_STEP
681         printf("virtual output test - press enter to connect\n");
682         getchar();
683 #endif
684         ret = tdm_client_voutput_connect(voutput);
685         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, done);
686
687         data->voutput = voutput;
688         data->output = output;
689
690         while (1) {
691                 tdm_client_handle_events_timeout(data->client, 1000);
692         }
693
694 done:
695         if (voutput)
696                 tdm_client_voutput_destroy(voutput);
697 }
698
699 static tdm_test_client ttc_data;
700
701 int
702 main(int argc, char *argv[])
703 {
704         tdm_test_client *data = &ttc_data;
705         tdm_error error;
706
707         /* for testing */
708         const char *xdg = (const char*)getenv("XDG_RUNTIME_DIR");
709         if (!xdg) {
710                 char buf[32];
711                 snprintf(buf, sizeof(buf), "/run");
712                 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
713                 if (ret != 0)
714                         exit(0);
715         }
716
717         /* for tbm_bufmgr_init */
718         const char *s  = (const char*)getenv("TBM_DISPLAY_SERVER");
719         if (!s) {
720                 char buf[32];
721                 snprintf(buf, sizeof(buf), "1");
722                 int ret = setenv("TBM_DISPLAY_SERVER", (const char*)buf, 1);
723                 if (ret != 0)
724                         exit(0);
725         }
726
727         parse_args(data, argc, argv);
728
729         printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d) pid(%d)\n",
730                    data->args.sync, data->args.fps, data->args.interval,
731                    data->args.offset, data->args.enable_fake, data->args.pid);
732
733         data->client = tdm_client_create(&error);
734         if (error != TDM_ERROR_NONE) {
735                 printf("tdm_client_create failed\n");
736                 goto done;
737         }
738
739         if (data->do_query)
740                 do_query(data);
741         if (data->do_vblank)
742                 do_vblank(data);
743         if (data->do_voutput)
744                 do_voutput(data);
745
746 done:
747         if (data->args.output_name)
748                 free(data->args.output_name);
749         if (data->args.vblank_name)
750                 free(data->args.vblank_name);
751         if (data->client)
752                 tdm_client_destroy(data->client);
753
754         return 0;
755 }