correct the format information log
[platform/core/uifw/libtdm.git] / src / tdm_helper.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <png.h>
41 #include <string.h>
42 #include <tbm_surface.h>
43 #include <tbm_surface_internal.h>
44 #include <string.h>
45 #include <time.h>
46 #include <pixman.h>
47
48 #include "tdm.h"
49 #include "tdm_private.h"
50 #include "tdm_helper.h"
51
52 #define PNG_DEPTH 8
53
54 static const char *file_exts[2] = {"png", "yuv"};
55
56 int tdm_dump_enable;
57
58 INTERN unsigned long
59 tdm_helper_get_time_in_millis(void)
60 {
61         struct timespec tp;
62
63         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
64                 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
65
66         return 0;
67 }
68
69 INTERN unsigned long
70 tdm_helper_get_time_in_micros(void)
71 {
72         struct timespec tp;
73
74         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
75                 return (tp.tv_sec * 1000000) + (tp.tv_nsec / 1000L);
76
77         return 0;
78 }
79
80 static void
81 _tdm_helper_dump_raw(const char *file, void *data1, int size1, void *data2,
82                                          int size2, void *data3, int size3)
83 {
84         unsigned int *blocks;
85         FILE *fp = fopen(file, "w+");
86         TDM_RETURN_IF_FAIL(fp != NULL);
87
88         blocks = (unsigned int *)data1;
89         fwrite(blocks, 1, size1, fp);
90
91         if (size2 > 0) {
92                 blocks = (unsigned int *)data2;
93                 fwrite(blocks, 1, size2, fp);
94         }
95
96         if (size3 > 0) {
97                 blocks = (unsigned int *)data3;
98                 fwrite(blocks, 1, size3, fp);
99         }
100
101         fclose(fp);
102 }
103
104 static void
105 _tdm_helper_dump_png(const char *file, const void *data, int width,
106                                          int height)
107 {
108         FILE *fp = fopen(file, "wb");
109         TDM_RETURN_IF_FAIL(fp != NULL);
110
111         png_structp pPngStruct =
112                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
113         if (!pPngStruct) {
114                 fclose(fp);
115                 return;
116         }
117
118         png_infop pPngInfo = png_create_info_struct(pPngStruct);
119         if (!pPngInfo) {
120                 png_destroy_write_struct(&pPngStruct, NULL);
121                 fclose(fp);
122                 return;
123         }
124
125         png_init_io(pPngStruct, fp);
126         png_set_IHDR(pPngStruct,
127                                  pPngInfo,
128                                  width,
129                                  height,
130                                  PNG_DEPTH,
131                                  PNG_COLOR_TYPE_RGBA,
132                                  PNG_INTERLACE_NONE,
133                                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
134
135         png_set_bgr(pPngStruct);
136         png_write_info(pPngStruct, pPngInfo);
137
138         const int pixel_size = 4;       // RGBA
139         png_bytep *row_pointers =
140                 png_malloc(pPngStruct, height * sizeof(png_byte *));
141
142         unsigned int *blocks = (unsigned int *)data;
143         int y = 0;
144         int x = 0;
145
146         for (; y < height; ++y) {
147                 png_bytep row =
148                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
149                 row_pointers[y] = (png_bytep)row;
150                 for (x = 0; x < width; ++x) {
151                         unsigned int curBlock = blocks[y * width + x];
152                         row[x * pixel_size] = (curBlock & 0xFF);
153                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
154                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
155                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
156                 }
157         }
158
159         png_write_image(pPngStruct, row_pointers);
160         png_write_end(pPngStruct, pPngInfo);
161
162         for (y = 0; y < height; y++)
163                 png_free(pPngStruct, row_pointers[y]);
164         png_free(pPngStruct, row_pointers);
165
166         png_destroy_write_struct(&pPngStruct, &pPngInfo);
167
168         fclose(fp);
169 }
170
171 INTERN void
172 tdm_helper_dump_buffer_str(tbm_surface_h buffer, const char *str)
173 {
174         tbm_surface_info_s info;
175         const char *dir = "/tmp/dump-tdm";
176         const char *ext;
177         char file[TDM_PATH_LEN];
178         int ret, bw;
179
180         TDM_RETURN_IF_FAIL(buffer != NULL);
181         TDM_RETURN_IF_FAIL(str != NULL);
182
183         ret = tbm_surface_get_info(buffer, &info);
184         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
185
186         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) {
187                 ext = file_exts[0];
188                 bw = info.planes[0].stride >> 2;
189         } else {
190                 ext = file_exts[1];
191                 bw = info.planes[0].stride;
192         }
193
194         snprintf(file, TDM_PATH_LEN, "%s/%c%c%c%c_%dx%d_%s.%s",
195                          dir, FOURCC_STR(info.format), bw, info.height, str, ext);
196
197         tdm_helper_dump_buffer(buffer, file);
198 }
199
200 EXTERN void
201 tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
202 {
203         tbm_surface_info_s info;
204         int len, ret;
205         const char *ext;
206
207         TDM_RETURN_IF_FAIL(buffer != NULL);
208         TDM_RETURN_IF_FAIL(file != NULL);
209
210         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
211         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
212
213         len = strnlen(file, 1024);
214         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
215                 ext = file_exts[0];
216         else
217                 ext = file_exts[1];
218
219         if (strncmp(file + (len - 3), ext, 3)) {
220                 TDM_ERR("can't dump to '%s' file", file + (len - 3));
221                 tbm_surface_unmap(buffer);
222                 return;
223         }
224
225         switch (info.format) {
226         case TBM_FORMAT_ARGB8888:
227         case TBM_FORMAT_XRGB8888:
228                 _tdm_helper_dump_png(file, info.planes[0].ptr,
229                                                          info.planes[0].stride >> 2, info.height);
230                 break;
231         case TBM_FORMAT_YVU420:
232         case TBM_FORMAT_YUV420:
233                 _tdm_helper_dump_raw(file,
234                                                          info.planes[0].ptr,
235                                                          info.planes[0].stride * info.height,
236                                                          info.planes[1].ptr,
237                                                          info.planes[1].stride * (info.height >> 1),
238                                                          info.planes[2].ptr,
239                                                          info.planes[2].stride * (info.height >> 1));
240                 break;
241         case TBM_FORMAT_NV12:
242         case TBM_FORMAT_NV21:
243                 _tdm_helper_dump_raw(file,
244                                                          info.planes[0].ptr,
245                                                          info.planes[0].stride * info.height,
246                                                          info.planes[1].ptr,
247                                                          info.planes[1].stride * (info.height >> 1), NULL,
248                                                          0);
249                 break;
250         case TBM_FORMAT_YUYV:
251         case TBM_FORMAT_UYVY:
252                 _tdm_helper_dump_raw(file,
253                                                          info.planes[0].ptr,
254                                                          info.planes[0].stride * info.height, NULL, 0,
255                                                          NULL, 0);
256                 break;
257         default:
258                 TDM_ERR("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
259                 tbm_surface_unmap(buffer);
260                 return;
261         }
262
263         tbm_surface_unmap(buffer);
264
265         TDM_INFO("dump %s", file);
266 }
267
268 EXTERN void
269 tdm_helper_clear_buffer(tbm_surface_h buffer)
270 {
271         tbm_surface_info_s info;
272         int ret;
273
274         TDM_RETURN_IF_FAIL(buffer != NULL);
275
276         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
277         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
278
279         switch (info.format) {
280         case TBM_FORMAT_ARGB8888:
281         case TBM_FORMAT_XRGB8888:
282                 memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height);
283                 break;
284         case TBM_FORMAT_YVU420:
285         case TBM_FORMAT_YUV420:
286                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
287                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
288                 memset((char*)info.planes[2].ptr, 0x80, info.planes[2].stride * (info.height >> 1));
289                 break;
290         case TBM_FORMAT_NV12:
291         case TBM_FORMAT_NV21:
292                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
293                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
294                 break;
295         case TBM_FORMAT_YUYV: {
296                 int *ibuf = (int*)info.planes[0].ptr;
297                 int i, size = info.planes[0].stride * info.height / 4;
298
299                 for (i = 0 ; i < size ; i++)
300                         ibuf[i] = 0x10801080;
301         }
302         break;
303         case TBM_FORMAT_UYVY: {
304                 int *ibuf = (int*)info.planes[0].ptr;
305                 int i, size = info.planes[0].stride * info.height / 4;
306
307                 for (i = 0 ; i < size ; i++)
308                         ibuf[i] = 0x80108010; /* YUYV -> 0xVYUY */
309         }
310         break;
311         default:
312                 TDM_ERR("can't clear %c%c%c%c buffer", FOURCC_STR(info.format));
313                 break;
314         }
315
316         tbm_surface_unmap(buffer);
317 }
318
319 EXTERN int
320 tdm_helper_get_fd(const char *env)
321 {
322         const char *value;
323         int fd, newfd, flags, ret;
324
325         value = (const char*)getenv(env);
326         if (!value)
327                 return -1;
328
329         ret = sscanf(value, "%d", &fd);
330         if (ret < 0) {
331                 TDM_ERR("sscanf failed: %m");
332                 return -1;
333         }
334
335         flags = fcntl(fd, F_GETFD);
336         if (flags == -1) {
337                 TDM_ERR("fcntl failed: %m");
338                 return -1;
339         }
340
341         newfd = dup(fd);
342         if (newfd < 0) {
343                 TDM_ERR("dup failed: %m");
344                 return -1;
345         }
346
347         TDM_INFO("%s: fd(%d) newfd(%d)", env, fd, newfd);
348
349         fcntl(newfd, F_SETFD, flags | FD_CLOEXEC);
350
351         return newfd;
352 }
353
354 EXTERN void
355 tdm_helper_set_fd(const char *env, int fd)
356 {
357         char buf[32];
358         int ret;
359
360         snprintf(buf, sizeof(buf), "%d", fd);
361
362         ret = setenv(env, (const char*)buf, 1);
363         if (ret) {
364                 TDM_ERR("setenv failed: %m");
365                 return;
366         }
367
368         if (fd >= 0)
369                 TDM_INFO("%s: fd(%d)", env, fd);
370 }
371
372 EXTERN void
373 tdm_helper_dump_start(char *dumppath, int *count)
374 {
375         if (dumppath == NULL || count == NULL) {
376                 TDM_DBG("tdm_helper_dump dumppath or count is null.");
377                 return;
378         }
379
380         tdm_dump_enable = 1;
381
382         TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath);
383 }
384
385 EXTERN void
386 tdm_helper_dump_stop(void)
387 {
388         tdm_dump_enable = 0;
389
390         TDM_DBG("tdm_helper_dump stop.");
391 }
392
393 static pixman_format_code_t
394 _tdm_helper_pixman_format_get(tbm_format format)
395 {
396         switch (format) {
397         case TBM_FORMAT_ARGB8888:
398                 return PIXMAN_a8r8g8b8;
399         case TBM_FORMAT_XRGB8888:
400                 return PIXMAN_x8r8g8b8;
401         default:
402                 return 0;
403         }
404
405         return 0;
406 }
407
408 static tdm_error
409 _tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
410                                                    int dx, int dy, int dw, int dh, int count)
411 {
412         pixman_image_t *src_img = NULL, *dst_img = NULL;
413         pixman_format_code_t src_format, dst_format;
414         pixman_transform_t t;
415         struct pixman_f_transform ft;
416         pixman_op_t op;
417         tbm_surface_info_s src_info = {0, };
418         tbm_surface_info_s dst_info = {0, };
419         int stride, width;
420         double scale_x, scale_y;
421
422         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
423         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
424
425         if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info)
426                         != TBM_SURFACE_ERROR_NONE) {
427                 TDM_ERR("cannot mmap srcbuf\n");
428                 return TDM_ERROR_OPERATION_FAILED;
429         }
430
431         if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info)
432                         != TBM_SURFACE_ERROR_NONE) {
433                 TDM_ERR("cannot mmap dstbuf\n");
434                 tbm_surface_unmap(srcbuf);
435                 return TDM_ERROR_OPERATION_FAILED;
436         }
437         TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert);
438         TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert);
439
440         /* src */
441         src_format = _tdm_helper_pixman_format_get(src_info.format);
442         TDM_GOTO_IF_FAIL(src_format > 0, cant_convert);
443
444         width = src_info.planes[0].stride / 4;
445         stride = src_info.planes[0].stride;
446         src_img = pixman_image_create_bits(src_format, width, src_info.height,
447                                                                            (uint32_t*)src_info.planes[0].ptr, stride);
448         TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert);
449
450         /* dst */
451         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
452         TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert);
453
454         width = dst_info.planes[0].stride / 4;
455         stride = dst_info.planes[0].stride;
456         dst_img = pixman_image_create_bits(dst_format, width, dst_info.height,
457                                                                            (uint32_t*)dst_info.planes[0].ptr, stride);
458         TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert);
459
460         pixman_f_transform_init_identity(&ft);
461
462         scale_x = (double)src_info.width / dw;
463         scale_y = (double)src_info.height / dh;
464
465         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
466         pixman_f_transform_translate(&ft, NULL, 0, 0);
467         pixman_transform_from_pixman_f_transform(&t, &ft);
468         pixman_image_set_transform(src_img, &t);
469
470         if (count == 0)
471                 op = PIXMAN_OP_SRC;
472         else
473                 op = PIXMAN_OP_OVER;
474
475         pixman_image_composite(op, src_img, NULL, dst_img,
476                                                    0, 0, 0, 0, dx, dy, dw, dh);
477
478         if (src_img)
479                 pixman_image_unref(src_img);
480         if (dst_img)
481                 pixman_image_unref(dst_img);
482
483         tbm_surface_unmap(srcbuf);
484         tbm_surface_unmap(dstbuf);
485
486         return TDM_ERROR_NONE;
487
488 cant_convert:
489         if (src_img)
490                 pixman_image_unref(src_img);
491
492         tbm_surface_unmap(srcbuf);
493         tbm_surface_unmap(dstbuf);
494
495         return TDM_ERROR_OPERATION_FAILED;
496 }
497
498 EXTERN tdm_error
499 tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
500                                                   int x, int y, int w, int h,
501                                                   tdm_helper_capture_handler func, void *data)
502 {
503         tbm_surface_h surface;
504         tdm_error err;
505         int i, count, first = 0;
506
507         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
508         TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
509         TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER);
510         TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER);
511         TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER);
512         TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER);
513         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
514         TDM_RETURN_VAL_IF_FAIL(data != NULL, TDM_ERROR_INVALID_PARAMETER);
515
516         err = tdm_output_get_layer_count(output, &count);
517         if (err != TDM_ERROR_NONE) {
518                 TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err);
519                 return TDM_ERROR_OPERATION_FAILED;
520         }
521         if (count <= 0) {
522                 TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count);
523                 return TDM_ERROR_BAD_MODULE;
524         }
525
526         for (i = count - 1; i >= 0; i--) {
527                 tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
528
529                 surface = tdm_layer_get_displaying_buffer(layer, &err);
530                 if (err != TDM_ERROR_NONE)
531                         continue;
532
533                 err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++);
534                 if (err != TDM_ERROR_NONE)
535                         TDM_DBG("convert fail %d-layer buffer\n", i);
536                 else
537                         TDM_DBG("convert success %d-layer buffer\n", i);
538         }
539
540         func(dst_buffer, data);
541
542         return TDM_ERROR_NONE;
543 }
544
545 EXTERN void
546 tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len)
547 {
548         tdm_private_display *private_display;
549         tdm_backend_module *module_data;
550         tdm_func_output *func_output;
551         tdm_func_layer *func_layer;
552         tdm_private_output *private_output = NULL;
553         tdm_private_layer *private_layer = NULL;
554         tdm_private_pp *private_pp = NULL;
555         tdm_private_capture *private_capture = NULL;
556         tdm_error ret;
557         int i;
558
559         TDM_DBG_RETURN_IF_FAIL(dpy != NULL);
560
561         private_display = dpy;
562         func_output = &private_display->func_output;
563         func_layer = &private_display->func_layer;
564         _pthread_mutex_lock(&private_display->lock);
565
566         /* module information */
567         module_data = private_display->module_data;
568         TDM_SNPRINTF(reply, len, "[TDM backend information]\n");
569         TDM_SNPRINTF(reply, len, "name: %s\n", module_data->name);
570         TDM_SNPRINTF(reply, len, "vendor: %s\n", module_data->vendor);
571         TDM_SNPRINTF(reply, len, "version: %d.%d\n\n",
572                                  (int)TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version),
573                                  (int)TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version));
574
575         /* output information */
576         TDM_SNPRINTF(reply, len, "[Output information]\n");
577         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
578         TDM_SNPRINTF(reply, len, "idx   maker   model   name   type   status   dpms   subpixel   align_w   min   max   phy(mm)\n");
579         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
580         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
581                 TDM_SNPRINTF(reply, len, "%d   %s   %s   %s   %s   %s   %s   %d   %d   %dx%d   %dx%d   %dx%d\n",
582                                          private_output->index, private_output->caps.maker,
583                                          private_output->caps.model, private_output->caps.name,
584                                          tdm_conn_str(private_output->caps.type),
585                                          tdm_status_str(private_output->caps.status),
586                                          tdm_dpms_str(private_output->current_dpms_value),
587                                          private_output->caps.subpixel,
588                                          private_output->caps.preferred_align,
589                                          private_output->caps.min_w, private_output->caps.min_h,
590                                          private_output->caps.max_w, private_output->caps.max_h,
591                                          private_output->caps.mmWidth, private_output->caps.mmHeight);
592
593                 TDM_SNPRINTF(reply, len, "\t%d modes:\n", private_output->caps.mode_count);
594
595                 if (private_output->caps.mode_count > 0) {
596                         const tdm_output_mode *current_mode = NULL;
597
598                         TDM_DBG_GOTO_IF_FAIL(func_output->output_get_mode, unlock);
599                         ret = func_output->output_get_mode(private_output->output_backend, &current_mode);
600                         TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
601
602                         TDM_SNPRINTF(reply, len, "\t\t name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot\n");
603                         for (i = 0; i < private_output->caps.mode_count; i++) {
604                                 char *current = (current_mode == private_output->caps.modes + i) ? "*" : " ";
605                                 TDM_SNPRINTF(reply, len, "\t\t%s%s %d %d %d %d %d %d %d %d %d ",
606                                                          current,
607                                                          private_output->caps.modes[i].name,
608                                                          private_output->caps.modes[i].vrefresh,
609                                                          private_output->caps.modes[i].hdisplay,
610                                                          private_output->caps.modes[i].hsync_start,
611                                                          private_output->caps.modes[i].hsync_end,
612                                                          private_output->caps.modes[i].htotal,
613                                                          private_output->caps.modes[i].vdisplay,
614                                                          private_output->caps.modes[i].vsync_start,
615                                                          private_output->caps.modes[i].vsync_end,
616                                                          private_output->caps.modes[i].vtotal);
617                                 tdm_mode_flag_str(private_output->caps.modes[i].flags, &reply, len);
618                                 TDM_SNPRINTF(reply, len, " ");
619                                 tdm_mode_type_str(private_output->caps.modes[i].type, &reply, len);
620                                 TDM_SNPRINTF(reply, len, "\n");
621                         }
622                 }
623
624                 TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_output->caps.prop_count);
625                 if (private_output->caps.prop_count > 0) {
626                         TDM_SNPRINTF(reply, len, "\t\tname\tidx\tvalue\n");
627                         for (i = 0; i < private_output->caps.prop_count; i++) {
628                                 tdm_value value;
629                                 TDM_DBG_GOTO_IF_FAIL(func_output->output_get_property, unlock);
630                                 ret = func_output->output_get_property(private_output->output_backend,
631                                                                                                            private_output->caps.props[i].id,
632                                                                                                            &value);
633                                 TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
634                                 TDM_SNPRINTF(reply, len, "\t\t%s\t%d\t%d\n",
635                                                          private_output->caps.props[i].name,
636                                                          private_output->caps.props[i].id,
637                                                          value.u32);
638                         }
639                 }
640         }
641         TDM_SNPRINTF(reply, len, "\n");
642
643         /* layer information */
644         TDM_SNPRINTF(reply, len, "[Layer information]\n");
645         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
646         TDM_SNPRINTF(reply, len, "idx   output   zpos   buf   format   size   crop   geometry   transform\n");
647         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
648         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
649                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
650                         if (!private_layer->usable) {
651                                 tdm_info_layer info;
652                                 unsigned int format;
653                                 tdm_size size;
654                                 tbm_surface_info_s buf_info;
655
656                                 TDM_DBG_GOTO_IF_FAIL(func_layer->layer_get_info, unlock);
657                                 memset(&info, 0, sizeof info);
658                                 ret = func_layer->layer_get_info(private_layer->layer_backend, &info);
659                                 TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
660
661                                 format = tbm_surface_get_format(private_layer->showing_buffer);
662                                 tbm_surface_get_info(private_layer->showing_buffer, &buf_info);
663
664                                 if (IS_RGB(format))
665                                         size.h = buf_info.planes[0].stride >> 2;
666                                 else
667                                         size.h = buf_info.planes[0].stride;
668                                 size.v = tbm_surface_get_height(private_layer->showing_buffer);
669
670                                 if (info.src_config.format)
671                                         format = (info.src_config.format)?:format;
672
673                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c   %dx%d   %dx%d+%d+%d   %dx%d+%d+%d   %s\n",
674                                                          private_layer->index,
675                                                          private_output->index,
676                                                          private_layer->caps.zpos,
677                                                          private_layer->showing_buffer, FOURCC_STR(format), size.h, size.v,
678                                                          info.src_config.pos.w, info.src_config.pos.h, info.src_config.pos.x, info.src_config.pos.y,
679                                                          info.dst_pos.w, info.dst_pos.h, info.dst_pos.x, info.dst_pos.y,
680                                                          tdm_transform_str(info.transform));
681                         } else {
682                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   -\n",
683                                                          private_layer->index,
684                                                          private_output->index,
685                                                          private_layer->caps.zpos);
686                         }
687
688                         TDM_SNPRINTF(reply, len, "\tcaps\t: ");
689                         tdm_layer_caps_str(private_layer->caps.capabilities, &reply, len);
690                         TDM_SNPRINTF(reply, len, "\n");
691
692                         TDM_SNPRINTF(reply, len, "\tformats\t: ");
693                         if (private_layer->caps.format_count > 0) {
694                                 const char *sep = "";
695                                 for (i = 0; i < private_layer->caps.format_count; i++) {
696                                         if (private_layer->caps.formats[i] == 0)
697                                                 continue;
698                                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_layer->caps.formats[i]));
699                                         sep = ",";
700                                 }
701                                 TDM_SNPRINTF(reply, len, "\n");
702                         }
703
704                         TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_layer->caps.prop_count);
705                         if (private_layer->caps.prop_count > 0) {
706                                 TDM_SNPRINTF(reply, len, "\t\tname\tidx\tvalue\n");
707                                 for (i = 0; i < private_layer->caps.prop_count; i++) {
708                                         tdm_value value;
709                                         TDM_DBG_GOTO_IF_FAIL(func_layer->layer_get_property, unlock);
710                                         ret = func_layer->layer_get_property(private_layer->layer_backend,
711                                                                                                                  private_layer->caps.props[i].id,
712                                                                                                                  &value);
713                                         TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
714                                         TDM_SNPRINTF(reply, len, "\t\t%s\t%d\t%d\n",
715                                                                  private_layer->caps.props[i].name,
716                                                                  private_layer->caps.props[i].id,
717                                                                  value.u32);
718                                 }
719                         }
720                 }
721         }
722         TDM_SNPRINTF(reply, len, "\n");
723
724         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
725                 const char *sep = "";
726                 TDM_SNPRINTF(reply, len, "[PP information]\n");
727                 TDM_SNPRINTF(reply, len, "caps\t: ");
728                 tdm_pp_caps_str(private_display->caps_pp.capabilities, &reply, len);
729                 TDM_SNPRINTF(reply, len, "\n");
730                 TDM_SNPRINTF(reply, len, "formats\t: ");
731                 for (i = 0; i < private_display->caps_pp.format_count; i++) {
732                         if (private_display->caps_pp.formats[i] == 0)
733                                 continue;
734                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_display->caps_pp.formats[i]));
735                         sep = ",";
736                 }
737                 TDM_SNPRINTF(reply, len, "\n");
738                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
739                                          private_display->caps_pp.min_w, private_display->caps_pp.min_h,
740                                          private_display->caps_pp.max_w, private_display->caps_pp.max_h,
741                                          private_display->caps_pp.preferred_align);
742                 if (!LIST_IS_EMPTY(&private_display->pp_list)) {
743                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
744                         TDM_SNPRINTF(reply, len, "src(format size crop)  |  dst(format size crop)  |  transform\n");
745                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
746                         LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
747                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %dx%d %dx%d+%d+%d | %c%c%c%c %dx%d %dx%d+%d+%d | %s\n",
748                                                          FOURCC_STR(private_pp->info.src_config.format),
749                                                          private_pp->info.src_config.size.h,
750                                                          private_pp->info.src_config.size.v,
751                                                          private_pp->info.src_config.pos.x, private_pp->info.src_config.pos.y,
752                                                          private_pp->info.src_config.pos.w, private_pp->info.src_config.pos.h,
753                                                          FOURCC_STR(private_pp->info.dst_config.format),
754                                                          private_pp->info.dst_config.size.h,
755                                                          private_pp->info.dst_config.size.v,
756                                                          private_pp->info.dst_config.pos.x, private_pp->info.dst_config.pos.y,
757                                                          private_pp->info.dst_config.pos.w, private_pp->info.dst_config.pos.h,
758                                                          tdm_transform_str(private_pp->info.transform));
759                         }
760                 }
761         } else {
762                 TDM_SNPRINTF(reply, len, "[No PP capability]\n");
763         }
764         TDM_SNPRINTF(reply, len, "\n");
765
766         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
767                 const char *sep = "";
768                 TDM_SNPRINTF(reply, len, "[Capture information]\n");
769                 TDM_SNPRINTF(reply, len, "caps\t: ");
770                 tdm_capture_caps_str(private_display->caps_capture.capabilities, &reply, len);
771                 TDM_SNPRINTF(reply, len, "\n");
772                 TDM_SNPRINTF(reply, len, "formats\t: ");
773                 for (i = 0; i < private_display->caps_capture.format_count; i++) {
774                         if (private_display->caps_capture.formats[i] == 0)
775                                 continue;
776                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_display->caps_capture.formats[i]));
777                         sep = ",";
778                 }
779                 TDM_SNPRINTF(reply, len, "\n");
780                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
781                                          private_display->caps_capture.min_w, private_display->caps_capture.min_h,
782                                          private_display->caps_capture.max_w, private_display->caps_capture.max_h,
783                                          private_display->caps_capture.preferred_align);
784                 if (!LIST_IS_EMPTY(&private_display->capture_list)) {
785                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
786                         TDM_SNPRINTF(reply, len, "dst(format size crop)  |  transform\n");
787                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
788                         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
789                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %dx%d %dx%d+%d+%d | %s\n",
790                                                          FOURCC_STR(private_capture->info.dst_config.format),
791                                                          private_capture->info.dst_config.size.h,
792                                                          private_capture->info.dst_config.size.v,
793                                                          private_capture->info.dst_config.pos.x, private_capture->info.dst_config.pos.y,
794                                                          private_capture->info.dst_config.pos.w, private_capture->info.dst_config.pos.h,
795                                                          tdm_transform_str(private_capture->info.transform));
796                         }
797                 }
798         } else {
799                 TDM_SNPRINTF(reply, len, "[No Capture capability]\n");
800         }
801         TDM_SNPRINTF(reply, len, "\n");
802
803 unlock:
804         _pthread_mutex_unlock(&private_display->lock);
805 }