fix memory leak
[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 char *tdm_debug_dump_dir;
58
59 INTERN unsigned long
60 tdm_helper_get_time_in_millis(void)
61 {
62         struct timespec tp;
63
64         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
65                 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
66
67         return 0;
68 }
69
70 INTERN unsigned long
71 tdm_helper_get_time_in_micros(void)
72 {
73         struct timespec tp;
74
75         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
76                 return (tp.tv_sec * 1000000) + (tp.tv_nsec / 1000L);
77
78         return 0;
79 }
80
81 static void
82 _tdm_helper_dump_raw(const char *file, void *data1, int size1, void *data2,
83                                          int size2, void *data3, int size3)
84 {
85         unsigned int *blocks;
86         FILE *fp = fopen(file, "w+");
87         TDM_RETURN_IF_FAIL(fp != NULL);
88
89         blocks = (unsigned int *)data1;
90         fwrite(blocks, 1, size1, fp);
91
92         if (size2 > 0) {
93                 blocks = (unsigned int *)data2;
94                 fwrite(blocks, 1, size2, fp);
95         }
96
97         if (size3 > 0) {
98                 blocks = (unsigned int *)data3;
99                 fwrite(blocks, 1, size3, fp);
100         }
101
102         fclose(fp);
103 }
104
105 static void
106 _tdm_helper_dump_png(const char *file, const void *data, int width,
107                                          int height)
108 {
109         FILE *fp = fopen(file, "wb");
110         TDM_RETURN_IF_FAIL(fp != NULL);
111
112         png_structp pPngStruct =
113                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
114         if (!pPngStruct) {
115                 fclose(fp);
116                 return;
117         }
118
119         png_infop pPngInfo = png_create_info_struct(pPngStruct);
120         if (!pPngInfo) {
121                 png_destroy_write_struct(&pPngStruct, NULL);
122                 fclose(fp);
123                 return;
124         }
125
126         png_init_io(pPngStruct, fp);
127         png_set_IHDR(pPngStruct,
128                                  pPngInfo,
129                                  width,
130                                  height,
131                                  PNG_DEPTH,
132                                  PNG_COLOR_TYPE_RGBA,
133                                  PNG_INTERLACE_NONE,
134                                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
135
136         png_set_bgr(pPngStruct);
137         png_write_info(pPngStruct, pPngInfo);
138
139         const int pixel_size = 4;       // RGBA
140         png_bytep *row_pointers =
141                 png_malloc(pPngStruct, height * sizeof(png_byte *));
142
143         unsigned int *blocks = (unsigned int *)data;
144         int y = 0;
145         int x = 0;
146
147         for (; y < height; ++y) {
148                 png_bytep row =
149                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
150                 row_pointers[y] = (png_bytep)row;
151                 for (x = 0; x < width; ++x) {
152                         unsigned int curBlock = blocks[y * width + x];
153                         row[x * pixel_size] = (curBlock & 0xFF);
154                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
155                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
156                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
157                 }
158         }
159
160         png_write_image(pPngStruct, row_pointers);
161         png_write_end(pPngStruct, pPngInfo);
162
163         for (y = 0; y < height; y++)
164                 png_free(pPngStruct, row_pointers[y]);
165         png_free(pPngStruct, row_pointers);
166
167         png_destroy_write_struct(&pPngStruct, &pPngInfo);
168
169         fclose(fp);
170 }
171
172 INTERN char *
173 tdm_helper_dump_make_directory(const char *path, char *reply, int *len)
174 {
175         char *fullpath = NULL;
176         time_t timer;
177         struct tm *t, *buf = NULL;
178
179         timer = time(NULL);
180
181         buf = calloc(1, sizeof(struct tm));
182         TDM_GOTO_IF_FAIL(buf != NULL, failed_make);
183
184         fullpath = calloc(1, TDM_PATH_LEN * sizeof(char));
185         TDM_GOTO_IF_FAIL(fullpath != NULL, failed_make);
186
187         t = localtime_r(&timer, buf);
188         TDM_GOTO_IF_FAIL(t != NULL, failed_make);
189
190         snprintf(fullpath, TDM_PATH_LEN, "%s/dump_%04d%02d%02d.%02d%02d%02d", path,
191                          t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
192
193         if ((mkdir(fullpath, 0755)) < 0) {
194                 TDM_ERR("mkdir '%s' fail\n", fullpath);
195                 TDM_SNPRINTF(reply, len, "mkdir '%s' fail\n", fullpath);
196                 goto failed_make;
197         }
198
199         free(buf);
200
201         return fullpath;
202 failed_make:
203         if (fullpath)
204                 free(fullpath);
205         if (buf)
206                 free(buf);
207         return NULL;
208 }
209
210 INTERN void
211 tdm_helper_dump_buffer_str(tbm_surface_h buffer, char *dir, char *str)
212 {
213         tbm_surface_info_s info;
214         const char *ext;
215         char file[TDM_PATH_LEN];
216         int ret, bw;
217         char *dump_dir = NULL;
218
219         TDM_RETURN_IF_FAIL(buffer != NULL);
220         TDM_RETURN_IF_FAIL(str != NULL);
221
222         dump_dir = tdm_helper_dump_make_directory(TDM_DUMP_DIR, NULL, NULL);
223
224         if (!dir)
225                 dir = dump_dir;
226
227         TDM_GOTO_IF_FAIL(dir != NULL, done);
228
229         ret = tbm_surface_get_info(buffer, &info);
230         TDM_GOTO_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE, done);
231
232         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) {
233                 ext = file_exts[0];
234                 bw = info.planes[0].stride >> 2;
235         } else {
236                 ext = file_exts[1];
237                 bw = info.planes[0].stride;
238         }
239
240         snprintf(file, TDM_PATH_LEN, "%s/%c%c%c%c_%dx%d_%s.%s",
241                          dir, FOURCC_STR(info.format), bw, info.height, str, ext);
242
243         tdm_helper_dump_buffer(buffer, file);
244
245 done:
246         free(dump_dir);
247 }
248
249 EXTERN void
250 tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
251 {
252         tbm_surface_info_s info;
253         int len, ret;
254         const char *ext;
255
256         TDM_RETURN_IF_FAIL(buffer != NULL);
257         TDM_RETURN_IF_FAIL(file != NULL);
258
259         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
260         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
261
262         len = strnlen(file, 1024);
263         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
264                 ext = file_exts[0];
265         else
266                 ext = file_exts[1];
267
268         if (strncmp(file + (len - 3), ext, 3)) {
269                 TDM_ERR("can't dump to '%s' file", file + (len - 3));
270                 tbm_surface_unmap(buffer);
271                 return;
272         }
273
274         switch (info.format) {
275         case TBM_FORMAT_ARGB8888:
276         case TBM_FORMAT_XRGB8888:
277                 _tdm_helper_dump_png(file, info.planes[0].ptr,
278                                                          info.planes[0].stride >> 2, info.height);
279                 break;
280         case TBM_FORMAT_YVU420:
281         case TBM_FORMAT_YUV420:
282                 _tdm_helper_dump_raw(file,
283                                                          info.planes[0].ptr,
284                                                          info.planes[0].stride * info.height,
285                                                          info.planes[1].ptr,
286                                                          info.planes[1].stride * (info.height >> 1),
287                                                          info.planes[2].ptr,
288                                                          info.planes[2].stride * (info.height >> 1));
289                 break;
290         case TBM_FORMAT_NV12:
291         case TBM_FORMAT_NV21:
292                 _tdm_helper_dump_raw(file,
293                                                          info.planes[0].ptr,
294                                                          info.planes[0].stride * info.height,
295                                                          info.planes[1].ptr,
296                                                          info.planes[1].stride * (info.height >> 1), NULL,
297                                                          0);
298                 break;
299         case TBM_FORMAT_YUYV:
300         case TBM_FORMAT_UYVY:
301                 _tdm_helper_dump_raw(file,
302                                                          info.planes[0].ptr,
303                                                          info.planes[0].stride * info.height, NULL, 0,
304                                                          NULL, 0);
305                 break;
306         default:
307                 TDM_ERR("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
308                 tbm_surface_unmap(buffer);
309                 return;
310         }
311
312         tbm_surface_unmap(buffer);
313
314         TDM_INFO("dump %s", file);
315 }
316
317 EXTERN void
318 tdm_helper_clear_buffer(tbm_surface_h buffer)
319 {
320         tbm_surface_info_s info;
321         int ret;
322
323         TDM_RETURN_IF_FAIL(buffer != NULL);
324
325         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
326         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
327
328         switch (info.format) {
329         case TBM_FORMAT_ARGB8888:
330         case TBM_FORMAT_XRGB8888:
331                 memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height);
332                 break;
333         case TBM_FORMAT_YVU420:
334         case TBM_FORMAT_YUV420:
335                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
336                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
337                 memset((char*)info.planes[2].ptr, 0x80, info.planes[2].stride * (info.height >> 1));
338                 break;
339         case TBM_FORMAT_NV12:
340         case TBM_FORMAT_NV21:
341                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
342                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
343                 break;
344         case TBM_FORMAT_YUYV: {
345                 int *ibuf = (int*)info.planes[0].ptr;
346                 int i, size = info.planes[0].stride * info.height / 4;
347
348                 for (i = 0 ; i < size ; i++)
349                         ibuf[i] = 0x10801080;
350         }
351         break;
352         case TBM_FORMAT_UYVY: {
353                 int *ibuf = (int*)info.planes[0].ptr;
354                 int i, size = info.planes[0].stride * info.height / 4;
355
356                 for (i = 0 ; i < size ; i++)
357                         ibuf[i] = 0x80108010; /* YUYV -> 0xVYUY */
358         }
359         break;
360         default:
361                 TDM_ERR("can't clear %c%c%c%c buffer", FOURCC_STR(info.format));
362                 break;
363         }
364
365         tbm_surface_unmap(buffer);
366 }
367
368 EXTERN int
369 tdm_helper_get_fd(const char *env)
370 {
371         const char *value;
372         int fd, newfd, flags, ret;
373
374         value = (const char*)getenv(env);
375         if (!value)
376                 return -1;
377
378         ret = sscanf(value, "%d", &fd);
379         if (ret < 0) {
380                 TDM_ERR("sscanf failed: %m");
381                 return -1;
382         }
383
384         flags = fcntl(fd, F_GETFD);
385         if (flags == -1) {
386                 TDM_ERR("fcntl failed: %m");
387                 return -1;
388         }
389
390         newfd = dup(fd);
391         if (newfd < 0) {
392                 TDM_ERR("dup failed: %m");
393                 return -1;
394         }
395
396         TDM_INFO("%s: fd(%d) newfd(%d)", env, fd, newfd);
397
398         fcntl(newfd, F_SETFD, flags | FD_CLOEXEC);
399
400         return newfd;
401 }
402
403 EXTERN void
404 tdm_helper_set_fd(const char *env, int fd)
405 {
406         char buf[32];
407         int ret;
408
409         snprintf(buf, sizeof(buf), "%d", fd);
410
411         ret = setenv(env, (const char*)buf, 1);
412         if (ret) {
413                 TDM_ERR("setenv failed: %m");
414                 return;
415         }
416
417         if (fd >= 0)
418                 TDM_INFO("%s: fd(%d)", env, fd);
419 }
420
421 EXTERN void
422 tdm_helper_dump_start(char *dumppath, int *count)
423 {
424         if (dumppath == NULL || count == NULL) {
425                 TDM_DBG("tdm_helper_dump dumppath or count is null.");
426                 return;
427         }
428
429         tdm_dump_enable = 1;
430
431         TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath);
432 }
433
434 EXTERN void
435 tdm_helper_dump_stop(void)
436 {
437         tdm_dump_enable = 0;
438
439         TDM_DBG("tdm_helper_dump stop.");
440 }
441
442 static pixman_format_code_t
443 _tdm_helper_pixman_format_get(tbm_format format)
444 {
445         switch (format) {
446         case TBM_FORMAT_ARGB8888:
447                 return PIXMAN_a8r8g8b8;
448         case TBM_FORMAT_XRGB8888:
449                 return PIXMAN_x8r8g8b8;
450         default:
451                 return 0;
452         }
453
454         return 0;
455 }
456
457 static tdm_error
458 _tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
459                                                    int dx, int dy, int dw, int dh, int count)
460 {
461         pixman_image_t *src_img = NULL, *dst_img = NULL;
462         pixman_format_code_t src_format, dst_format;
463         pixman_transform_t t;
464         struct pixman_f_transform ft;
465         pixman_op_t op;
466         tbm_surface_info_s src_info = {0, };
467         tbm_surface_info_s dst_info = {0, };
468         int stride, width;
469         double scale_x, scale_y;
470
471         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
472         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
473
474         if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info)
475                         != TBM_SURFACE_ERROR_NONE) {
476                 TDM_ERR("cannot mmap srcbuf\n");
477                 return TDM_ERROR_OPERATION_FAILED;
478         }
479
480         if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info)
481                         != TBM_SURFACE_ERROR_NONE) {
482                 TDM_ERR("cannot mmap dstbuf\n");
483                 tbm_surface_unmap(srcbuf);
484                 return TDM_ERROR_OPERATION_FAILED;
485         }
486         TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert);
487         TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert);
488
489         /* src */
490         src_format = _tdm_helper_pixman_format_get(src_info.format);
491         TDM_GOTO_IF_FAIL(src_format > 0, cant_convert);
492
493         width = src_info.planes[0].stride / 4;
494         stride = src_info.planes[0].stride;
495         src_img = pixman_image_create_bits(src_format, width, src_info.height,
496                                                                            (uint32_t*)src_info.planes[0].ptr, stride);
497         TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert);
498
499         /* dst */
500         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
501         TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert);
502
503         width = dst_info.planes[0].stride / 4;
504         stride = dst_info.planes[0].stride;
505         dst_img = pixman_image_create_bits(dst_format, width, dst_info.height,
506                                                                            (uint32_t*)dst_info.planes[0].ptr, stride);
507         TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert);
508
509         pixman_f_transform_init_identity(&ft);
510
511         scale_x = (double)src_info.width / dw;
512         scale_y = (double)src_info.height / dh;
513
514         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
515         pixman_f_transform_translate(&ft, NULL, 0, 0);
516         pixman_transform_from_pixman_f_transform(&t, &ft);
517         pixman_image_set_transform(src_img, &t);
518
519         if (count == 0)
520                 op = PIXMAN_OP_SRC;
521         else
522                 op = PIXMAN_OP_OVER;
523
524         pixman_image_composite(op, src_img, NULL, dst_img,
525                                                    0, 0, 0, 0, dx, dy, dw, dh);
526
527         if (src_img)
528                 pixman_image_unref(src_img);
529         if (dst_img)
530                 pixman_image_unref(dst_img);
531
532         tbm_surface_unmap(srcbuf);
533         tbm_surface_unmap(dstbuf);
534
535         return TDM_ERROR_NONE;
536
537 cant_convert:
538         if (src_img)
539                 pixman_image_unref(src_img);
540
541         tbm_surface_unmap(srcbuf);
542         tbm_surface_unmap(dstbuf);
543
544         return TDM_ERROR_OPERATION_FAILED;
545 }
546
547 EXTERN tdm_error
548 tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
549                                                   int x, int y, int w, int h,
550                                                   tdm_helper_capture_handler func, void *data)
551 {
552         tbm_surface_h surface;
553         tdm_error err;
554         int i, count, first = 0;
555
556         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
557         TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
558         TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER);
559         TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER);
560         TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER);
561         TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER);
562         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
563         TDM_RETURN_VAL_IF_FAIL(data != NULL, TDM_ERROR_INVALID_PARAMETER);
564
565         err = tdm_output_get_layer_count(output, &count);
566         if (err != TDM_ERROR_NONE) {
567                 TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err);
568                 return TDM_ERROR_OPERATION_FAILED;
569         }
570         if (count <= 0) {
571                 TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count);
572                 return TDM_ERROR_BAD_MODULE;
573         }
574
575         for (i = count - 1; i >= 0; i--) {
576                 tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
577
578                 surface = tdm_layer_get_displaying_buffer(layer, &err);
579                 if (err != TDM_ERROR_NONE)
580                         continue;
581
582                 err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++);
583                 if (err != TDM_ERROR_NONE)
584                         TDM_DBG("convert fail %d-layer buffer\n", i);
585                 else
586                         TDM_DBG("convert success %d-layer buffer\n", i);
587         }
588
589         func(dst_buffer, data);
590
591         return TDM_ERROR_NONE;
592 }
593
594 EXTERN void
595 tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len)
596 {
597         tdm_private_display *private_display;
598         tdm_backend_module *module_data;
599         tdm_func_output *func_output;
600         tdm_func_layer *func_layer;
601         tdm_private_output *private_output = NULL;
602         tdm_private_layer *private_layer = NULL;
603         tdm_private_pp *private_pp = NULL;
604         tdm_private_capture *private_capture = NULL;
605         tdm_error ret;
606         int i;
607
608         TDM_DBG_RETURN_IF_FAIL(dpy != NULL);
609
610         private_display = dpy;
611         func_output = &private_display->func_output;
612         func_layer = &private_display->func_layer;
613         _pthread_mutex_lock(&private_display->lock);
614
615         /* module information */
616         module_data = private_display->module_data;
617         TDM_SNPRINTF(reply, len, "[TDM backend information]\n");
618         TDM_SNPRINTF(reply, len, "name: %s\n", module_data->name);
619         TDM_SNPRINTF(reply, len, "vendor: %s\n", module_data->vendor);
620         TDM_SNPRINTF(reply, len, "version: %d.%d\n\n",
621                                  (int)TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version),
622                                  (int)TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version));
623
624         /* output information */
625         TDM_SNPRINTF(reply, len, "[Output information]\n");
626         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
627         TDM_SNPRINTF(reply, len, "idx   maker   model   name   type   status   dpms   subpixel   align_w   min   max   phy(mm)\n");
628         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
629         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
630                 TDM_SNPRINTF(reply, len, "%d   %s   %s   %s   %s   %s   %s   %d   %d   %dx%d   %dx%d   %dx%d\n",
631                                          private_output->index, private_output->caps.maker,
632                                          private_output->caps.model, private_output->caps.name,
633                                          tdm_conn_str(private_output->caps.type),
634                                          tdm_status_str(private_output->caps.status),
635                                          tdm_dpms_str(private_output->current_dpms_value),
636                                          private_output->caps.subpixel,
637                                          private_output->caps.preferred_align,
638                                          private_output->caps.min_w, private_output->caps.min_h,
639                                          private_output->caps.max_w, private_output->caps.max_h,
640                                          private_output->caps.mmWidth, private_output->caps.mmHeight);
641
642                 TDM_SNPRINTF(reply, len, "\t%d modes:\n", private_output->caps.mode_count);
643
644                 if (private_output->caps.mode_count > 0) {
645                         const tdm_output_mode *current_mode = NULL;
646
647                         TDM_DBG_GOTO_IF_FAIL(func_output->output_get_mode, unlock);
648                         ret = func_output->output_get_mode(private_output->output_backend, &current_mode);
649                         TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
650
651                         TDM_SNPRINTF(reply, len, "\t\t name refresh (Hz) clk hdisp hss hse htot vdisp vss vse vtot vscan\n");
652                         for (i = 0; i < private_output->caps.mode_count; i++) {
653                                 char *current = (current_mode == private_output->caps.modes + i) ? "*" : " ";
654                                 TDM_SNPRINTF(reply, len, "\t\t%s%s %d %d %d %d %d %d %d %d %d %d %d ",
655                                                          current,
656                                                          private_output->caps.modes[i].name,
657                                                          private_output->caps.modes[i].vrefresh,
658                                                          private_output->caps.modes[i].clock,
659                                                          private_output->caps.modes[i].hdisplay,
660                                                          private_output->caps.modes[i].hsync_start,
661                                                          private_output->caps.modes[i].hsync_end,
662                                                          private_output->caps.modes[i].htotal,
663                                                          private_output->caps.modes[i].vdisplay,
664                                                          private_output->caps.modes[i].vsync_start,
665                                                          private_output->caps.modes[i].vsync_end,
666                                                          private_output->caps.modes[i].vtotal,
667                                                          private_output->caps.modes[i].vscan);
668                                 tdm_mode_flag_str(private_output->caps.modes[i].flags, &reply, len);
669                                 TDM_SNPRINTF(reply, len, " ");
670                                 tdm_mode_type_str(private_output->caps.modes[i].type, &reply, len);
671                                 TDM_SNPRINTF(reply, len, "\n");
672                         }
673                 }
674
675                 TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_output->caps.prop_count);
676                 if (private_output->caps.prop_count > 0) {
677                         TDM_SNPRINTF(reply, len, "\t\tname\tidx\tvalue\n");
678                         for (i = 0; i < private_output->caps.prop_count; i++) {
679                                 tdm_value value;
680                                 TDM_DBG_GOTO_IF_FAIL(func_output->output_get_property, unlock);
681                                 ret = func_output->output_get_property(private_output->output_backend,
682                                                                                                            private_output->caps.props[i].id,
683                                                                                                            &value);
684                                 TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
685                                 TDM_SNPRINTF(reply, len, "\t\t%s\t%d\t%d\n",
686                                                          private_output->caps.props[i].name,
687                                                          private_output->caps.props[i].id,
688                                                          value.u32);
689                         }
690                 }
691         }
692         TDM_SNPRINTF(reply, len, "\n");
693
694         /* layer information */
695         TDM_SNPRINTF(reply, len, "[Layer information]\n");
696         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
697         TDM_SNPRINTF(reply, len, "idx   output   zpos   buf   format   size   crop   geometry   transform\n");
698         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
699         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
700                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
701                         if (!private_layer->usable) {
702                                 tdm_info_layer info;
703                                 unsigned int format;
704                                 tdm_size size;
705                                 tbm_surface_info_s buf_info;
706
707                                 TDM_DBG_GOTO_IF_FAIL(func_layer->layer_get_info, unlock);
708                                 memset(&info, 0, sizeof info);
709                                 ret = func_layer->layer_get_info(private_layer->layer_backend, &info);
710                                 TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
711
712                                 format = tbm_surface_get_format(private_layer->showing_buffer);
713                                 tbm_surface_get_info(private_layer->showing_buffer, &buf_info);
714
715                                 if (IS_RGB(format))
716                                         size.h = buf_info.planes[0].stride >> 2;
717                                 else
718                                         size.h = buf_info.planes[0].stride;
719                                 size.v = tbm_surface_get_height(private_layer->showing_buffer);
720
721                                 if (info.src_config.format)
722                                         format = (info.src_config.format)?:format;
723
724                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c   %dx%d   %dx%d+%d+%d   %dx%d+%d+%d   %s\n",
725                                                          private_layer->index,
726                                                          private_output->index,
727                                                          private_layer->caps.zpos,
728                                                          private_layer->showing_buffer, FOURCC_STR(format), size.h, size.v,
729                                                          info.src_config.pos.w, info.src_config.pos.h, info.src_config.pos.x, info.src_config.pos.y,
730                                                          info.dst_pos.w, info.dst_pos.h, info.dst_pos.x, info.dst_pos.y,
731                                                          tdm_transform_str(info.transform));
732                         } else {
733                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   -\n",
734                                                          private_layer->index,
735                                                          private_output->index,
736                                                          private_layer->caps.zpos);
737                         }
738
739                         TDM_SNPRINTF(reply, len, "\tcaps\t: ");
740                         tdm_layer_caps_str(private_layer->caps.capabilities, &reply, len);
741                         TDM_SNPRINTF(reply, len, "\n");
742
743                         TDM_SNPRINTF(reply, len, "\tformats\t: ");
744                         if (private_layer->caps.format_count > 0) {
745                                 const char *sep = "";
746                                 for (i = 0; i < private_layer->caps.format_count; i++) {
747                                         if (private_layer->caps.formats[i] == 0)
748                                                 continue;
749                                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_layer->caps.formats[i]));
750                                         sep = ",";
751                                 }
752                                 TDM_SNPRINTF(reply, len, "\n");
753                         }
754
755                         TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_layer->caps.prop_count);
756                         if (private_layer->caps.prop_count > 0) {
757                                 TDM_SNPRINTF(reply, len, "\t\tname\tidx\tvalue\n");
758                                 for (i = 0; i < private_layer->caps.prop_count; i++) {
759                                         tdm_value value;
760                                         TDM_DBG_GOTO_IF_FAIL(func_layer->layer_get_property, unlock);
761                                         ret = func_layer->layer_get_property(private_layer->layer_backend,
762                                                                                                                  private_layer->caps.props[i].id,
763                                                                                                                  &value);
764                                         TDM_DBG_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, unlock);
765                                         TDM_SNPRINTF(reply, len, "\t\t%s\t%d\t%d\n",
766                                                                  private_layer->caps.props[i].name,
767                                                                  private_layer->caps.props[i].id,
768                                                                  value.u32);
769                                 }
770                         }
771                 }
772         }
773         TDM_SNPRINTF(reply, len, "\n");
774
775         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
776                 const char *sep = "";
777                 TDM_SNPRINTF(reply, len, "[PP information]\n");
778                 TDM_SNPRINTF(reply, len, "caps\t: ");
779                 tdm_pp_caps_str(private_display->caps_pp.capabilities, &reply, len);
780                 TDM_SNPRINTF(reply, len, "\n");
781                 TDM_SNPRINTF(reply, len, "formats\t: ");
782                 for (i = 0; i < private_display->caps_pp.format_count; i++) {
783                         if (private_display->caps_pp.formats[i] == 0)
784                                 continue;
785                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_display->caps_pp.formats[i]));
786                         sep = ",";
787                 }
788                 TDM_SNPRINTF(reply, len, "\n");
789                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
790                                          private_display->caps_pp.min_w, private_display->caps_pp.min_h,
791                                          private_display->caps_pp.max_w, private_display->caps_pp.max_h,
792                                          private_display->caps_pp.preferred_align);
793                 if (!LIST_IS_EMPTY(&private_display->pp_list)) {
794                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
795                         TDM_SNPRINTF(reply, len, "src(format size crop)  |  dst(format size crop)  |  transform\n");
796                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
797                         LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
798                                 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",
799                                                          FOURCC_STR(private_pp->info.src_config.format),
800                                                          private_pp->info.src_config.size.h,
801                                                          private_pp->info.src_config.size.v,
802                                                          private_pp->info.src_config.pos.x, private_pp->info.src_config.pos.y,
803                                                          private_pp->info.src_config.pos.w, private_pp->info.src_config.pos.h,
804                                                          FOURCC_STR(private_pp->info.dst_config.format),
805                                                          private_pp->info.dst_config.size.h,
806                                                          private_pp->info.dst_config.size.v,
807                                                          private_pp->info.dst_config.pos.x, private_pp->info.dst_config.pos.y,
808                                                          private_pp->info.dst_config.pos.w, private_pp->info.dst_config.pos.h,
809                                                          tdm_transform_str(private_pp->info.transform));
810                         }
811                 }
812         } else {
813                 TDM_SNPRINTF(reply, len, "[No PP capability]\n");
814         }
815         TDM_SNPRINTF(reply, len, "\n");
816
817         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
818                 const char *sep = "";
819                 TDM_SNPRINTF(reply, len, "[Capture information]\n");
820                 TDM_SNPRINTF(reply, len, "caps\t: ");
821                 tdm_capture_caps_str(private_display->caps_capture.capabilities, &reply, len);
822                 TDM_SNPRINTF(reply, len, "\n");
823                 TDM_SNPRINTF(reply, len, "formats\t: ");
824                 for (i = 0; i < private_display->caps_capture.format_count; i++) {
825                         if (private_display->caps_capture.formats[i] == 0)
826                                 continue;
827                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_display->caps_capture.formats[i]));
828                         sep = ",";
829                 }
830                 TDM_SNPRINTF(reply, len, "\n");
831                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
832                                          private_display->caps_capture.min_w, private_display->caps_capture.min_h,
833                                          private_display->caps_capture.max_w, private_display->caps_capture.max_h,
834                                          private_display->caps_capture.preferred_align);
835                 if (!LIST_IS_EMPTY(&private_display->capture_list)) {
836                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
837                         TDM_SNPRINTF(reply, len, "dst(format size crop)  |  transform\n");
838                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
839                         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
840                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %dx%d %dx%d+%d+%d | %s\n",
841                                                          FOURCC_STR(private_capture->info.dst_config.format),
842                                                          private_capture->info.dst_config.size.h,
843                                                          private_capture->info.dst_config.size.v,
844                                                          private_capture->info.dst_config.pos.x, private_capture->info.dst_config.pos.y,
845                                                          private_capture->info.dst_config.pos.w, private_capture->info.dst_config.pos.h,
846                                                          tdm_transform_str(private_capture->info.transform));
847                         }
848                 }
849         } else {
850                 TDM_SNPRINTF(reply, len, "[No Capture capability]\n");
851         }
852         TDM_SNPRINTF(reply, len, "\n");
853
854 unlock:
855         _pthread_mutex_unlock(&private_display->lock);
856 }