correct email address
[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 <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 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <png.h>
41 #include <pixman.h>
42
43 #include "tdm_private.h"
44
45 #define PNG_DEPTH 8
46
47 static const char *file_exts[2] = {"png", "yuv"};
48
49 int tdm_dump_enable;
50 char *tdm_debug_dump_dir;
51
52 EXTERN double
53 tdm_helper_get_time(void)
54 {
55         struct timespec tp;
56
57         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
58                 return (double)tp.tv_sec + ((double)tp.tv_nsec) / 1000000000.0;
59
60         return 0;
61 }
62
63 static int
64 _tdm_helper_check_file_is_symbolic_link(const char* path)
65 {
66         struct stat sb;
67
68         if (!path)
69                 return 0;
70
71         if (stat(path, &sb) != 0)
72                 return 0;
73
74         if (S_ISLNK(sb.st_mode))
75                 return 1;
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;
86
87         if (_tdm_helper_check_file_is_symbolic_link(file)) {
88                 TDM_ERR("'%s' may be symbolic link\n", file);
89                 return;
90         }
91
92         fp = fopen(file, "w+");
93         TDM_RETURN_IF_FAIL(fp != NULL);
94
95         blocks = (unsigned int *)data1;
96         fwrite(blocks, 1, size1, fp);
97
98         if (size2 > 0) {
99                 blocks = (unsigned int *)data2;
100                 fwrite(blocks, 1, size2, fp);
101         }
102
103         if (size3 > 0) {
104                 blocks = (unsigned int *)data3;
105                 fwrite(blocks, 1, size3, fp);
106         }
107
108         fclose(fp);
109 }
110
111 static void
112 _tdm_helper_dump_png(const char *file, const void *data, int width,
113                                          int height)
114 {
115         FILE *fp;
116
117         if (_tdm_helper_check_file_is_symbolic_link(file)) {
118                 TDM_ERR("'%s' may be symbolic link\n", file);
119                 return;
120         }
121
122         fp = fopen(file, "wb");
123         TDM_RETURN_IF_FAIL(fp != NULL);
124
125         png_structp pPngStruct =
126                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
127         if (!pPngStruct) {
128                 fclose(fp);
129                 return;
130         }
131
132         png_infop pPngInfo = png_create_info_struct(pPngStruct);
133         if (!pPngInfo) {
134                 png_destroy_write_struct(&pPngStruct, NULL);
135                 fclose(fp);
136                 return;
137         }
138
139         png_init_io(pPngStruct, fp);
140         png_set_IHDR(pPngStruct,
141                                  pPngInfo,
142                                  width,
143                                  height,
144                                  PNG_DEPTH,
145                                  PNG_COLOR_TYPE_RGBA,
146                                  PNG_INTERLACE_NONE,
147                                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
148
149         png_set_bgr(pPngStruct);
150         png_write_info(pPngStruct, pPngInfo);
151
152         const int pixel_size = 4;       // RGBA
153         png_bytep *row_pointers =
154                 png_malloc(pPngStruct, height * sizeof(png_byte *));
155         if (!row_pointers) {
156                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
157                 fclose(fp);
158                 return;
159         }
160
161         unsigned int *blocks = (unsigned int *)data;
162         int y = 0;
163         int x = 0;
164
165         for (; y < height; ++y) {
166                 png_bytep row =
167                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
168                 if (!row) {
169                         for (x = 0; x < y; x++)
170                                 png_free(pPngStruct, row_pointers[x]);
171                         png_free(pPngStruct, row_pointers);
172                         png_destroy_write_struct(&pPngStruct, &pPngInfo);
173                         fclose(fp);
174                         return;
175                 }
176
177                 row_pointers[y] = (png_bytep)row;
178                 for (x = 0; x < width; ++x) {
179                         unsigned int curBlock = blocks[y * width + x];
180                         row[x * pixel_size] = (curBlock & 0xFF);
181                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
182                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
183                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
184                 }
185         }
186
187         png_write_image(pPngStruct, row_pointers);
188         png_write_end(pPngStruct, pPngInfo);
189
190         for (y = 0; y < height; y++)
191                 png_free(pPngStruct, row_pointers[y]);
192         png_free(pPngStruct, row_pointers);
193
194         png_destroy_write_struct(&pPngStruct, &pPngInfo);
195
196         fclose(fp);
197 }
198
199 /* LCOV_EXCL_START */
200 INTERN char *
201 tdm_helper_dump_make_directory(const char *path, char *reply, int *len)
202 {
203         char *fullpath = NULL;
204         time_t timer;
205         struct tm *t, *buf = NULL;
206
207         timer = time(NULL);
208
209         buf = calloc(1, sizeof(struct tm));
210         TDM_GOTO_IF_FAIL(buf != NULL, failed_make);
211
212         fullpath = calloc(1, TDM_PATH_LEN * sizeof(char));
213         TDM_GOTO_IF_FAIL(fullpath != NULL, failed_make);
214
215         t = localtime_r(&timer, buf);
216         TDM_GOTO_IF_FAIL(t != NULL, failed_make);
217
218         snprintf(fullpath, TDM_PATH_LEN, "%s/dump_%04d%02d%02d.%02d%02d%02d", path,
219                          t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
220
221         if ((mkdir(fullpath, 0755)) < 0) {
222                 TDM_ERR("mkdir '%s' fail\n", fullpath);
223                 TDM_SNPRINTF(reply, len, "mkdir '%s' fail\n", fullpath);
224                 goto failed_make;
225         }
226
227         free(buf);
228
229         return fullpath;
230 failed_make:
231         if (fullpath)
232                 free(fullpath);
233         if (buf)
234                 free(buf);
235         return NULL;
236 }
237
238 EXTERN void
239 tdm_helper_dump_buffer_str(tbm_surface_h buffer, char *dir, char *str)
240 {
241         tbm_surface_info_s info;
242         char file[TDM_PATH_LEN];
243         int ret, bw, bh;
244
245         TDM_RETURN_IF_FAIL(buffer != NULL);
246         TDM_RETURN_IF_FAIL(str != NULL);
247
248         if (!dir)
249                 dir = ".";
250
251         ret = tbm_surface_get_info(buffer, &info);
252         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
253
254         tdm_helper_get_buffer_full_size(buffer, &bw, &bh);
255
256         snprintf(file, TDM_PATH_LEN, "%s/%c%c%c%c_%dx%d_%dx%d_%s",
257                          dir, FOURCC_STR(info.format), bw, bh, info.width, info.height, str);
258
259         tdm_helper_dump_buffer(buffer, file);
260 }
261 /* LCOV_EXCL_STOP */
262
263 EXTERN void
264 tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
265 {
266         char temp[TDM_PATH_LEN] = {0,};
267         tbm_surface_info_s info;
268         int len, ret;
269         const char *ext;
270         int bo_cnt;
271         int bw, bh;
272         char *dot, *p = temp;
273
274         TDM_RETURN_IF_FAIL(buffer != NULL);
275         TDM_RETURN_IF_FAIL(file != NULL);
276
277         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
278         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
279
280         if (IS_RGB(info.format))
281                 ext = file_exts[0];
282         else
283                 ext = file_exts[1];
284
285         dot = strrchr(file, '.');
286         if (!dot || strlen(dot + 1) != 3 || strncmp(dot + 1, ext, 3)) {
287                 len = strnlen(file, TDM_PATH_LEN - 5);
288                 strncat(p, file, len);
289                 p += len;
290                 *(p++) = '.';
291                 strncat(p, ext, 3);
292                 p += 3;
293                 *p = '\0';
294         } else {
295                 len = strnlen(file, TDM_PATH_LEN - 1);
296                 strncat(p, file, len);
297                 p += len;
298                 *p = '\0';
299         }
300
301         tdm_helper_get_buffer_full_size(buffer, &bw, &bh);
302
303         bo_cnt = tbm_surface_internal_get_num_bos(buffer);
304         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)",
305                         bo_cnt, bw, bh, info.width, info.height, FOURCC_STR(info.format),
306                         info.planes[0].ptr, info.planes[0].offset, info.planes[0].stride, info.planes[0].size,
307                         info.planes[1].ptr, info.planes[1].offset, info.planes[1].stride, info.planes[1].size,
308                         info.planes[2].ptr, info.planes[2].offset, info.planes[2].stride, info.planes[2].size);
309
310         switch (info.format) {
311         case TBM_FORMAT_ARGB8888:
312         case TBM_FORMAT_XRGB8888:
313                 _tdm_helper_dump_png(temp, info.planes[0].ptr, bw, bh);
314                 break;
315         case TBM_FORMAT_YVU420:
316         case TBM_FORMAT_YUV420:
317                 _tdm_helper_dump_raw((const char*)temp,
318                                                          info.planes[0].ptr,
319                                                          info.planes[0].size,
320                                                          info.planes[1].ptr,
321                                                          info.planes[1].size,
322                                                          info.planes[2].ptr,
323                                                          info.planes[2].size);
324                 break;
325         case TBM_FORMAT_NV12:
326         case TBM_FORMAT_NV21:
327                 _tdm_helper_dump_raw((const char*)temp,
328                                                          info.planes[0].ptr,
329                                                          info.planes[0].size,
330                                                          info.planes[1].ptr,
331                                                          info.planes[1].size, NULL,
332                                                          0);
333                 break;
334         default:
335                 TDM_ERR("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
336                 tbm_surface_unmap(buffer);
337                 return;
338         }
339
340         tbm_surface_unmap(buffer);
341
342         TDM_INFO("dump %s", temp);
343 }
344
345 EXTERN void
346 tdm_helper_clear_buffer_color(tbm_surface_h buffer, tdm_pos *pos, unsigned int color)
347 {
348         tbm_surface_info_s info;
349         int ret;
350
351         TDM_RETURN_IF_FAIL(buffer != NULL);
352
353         ret = tbm_surface_map(buffer, TBM_OPTION_READ, &info);
354         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
355
356         switch (info.format) {
357         case TBM_FORMAT_ARGB8888:
358         case TBM_FORMAT_XRGB8888:
359                 if (!pos) {
360                         memset(info.planes[0].ptr, 0, info.planes[0].stride * info.height);
361                 } else {
362                         unsigned char *p;
363                         int x, y;
364                         for (y = pos->y; y <= (pos->y + pos->h); y++) {
365                                 p = info.planes[0].ptr + info.planes[0].stride * y;
366                                 for (x = pos->x; x <= (pos->x + pos->w); x++) {
367                                         unsigned int *ibuf = (unsigned int*)p;
368                                         ibuf[x] = color;
369                                 }
370                         }
371                 }
372                 break;
373         case TBM_FORMAT_YVU420:
374         case TBM_FORMAT_YUV420:
375                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
376                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
377                 memset((char*)info.planes[2].ptr, 0x80, info.planes[2].stride * (info.height >> 1));
378                 break;
379         case TBM_FORMAT_NV12:
380         case TBM_FORMAT_NV21:
381                 memset((char*)info.planes[0].ptr, 0x10, info.planes[0].stride * info.height);
382                 memset((char*)info.planes[1].ptr, 0x80, info.planes[1].stride * (info.height >> 1));
383                 break;
384         default:
385                 TDM_ERR("can't clear %c%c%c%c buffer", FOURCC_STR(info.format));
386                 break;
387         }
388
389         tbm_surface_unmap(buffer);
390 }
391
392 EXTERN void
393 tdm_helper_clear_buffer_pos(tbm_surface_h buffer, tdm_pos *pos)
394 {
395         TDM_RETURN_IF_FAIL(buffer != NULL);
396
397         tdm_helper_clear_buffer_color(buffer, pos, 0);
398 }
399
400 EXTERN void
401 tdm_helper_clear_buffer(tbm_surface_h buffer)
402 {
403         TDM_RETURN_IF_FAIL(buffer != NULL);
404
405         tdm_helper_clear_buffer_pos(buffer, NULL);
406 }
407
408 EXTERN void
409 tdm_helper_get_buffer_full_size(tbm_surface_h buffer, int *buffer_w, int *buffer_h)
410 {
411         tbm_surface_info_s info;
412         int ret;
413
414         TDM_RETURN_IF_FAIL(buffer != NULL);
415
416         ret = tbm_surface_get_info(buffer, &info);
417         TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
418
419         if (buffer_w) {
420                 if (IS_RGB(info.format))
421                         *buffer_w = info.planes[0].stride >> 2;
422                 else
423                         *buffer_w = info.planes[0].stride;
424         }
425
426         if (buffer_h)
427                 *buffer_h = info.planes[0].size / info.planes[0].stride;
428 }
429
430 static pixman_format_code_t
431 _tdm_helper_pixman_format_get(tbm_format format)
432 {
433         switch (format) {
434         case TBM_FORMAT_ARGB8888:
435                 return PIXMAN_a8r8g8b8;
436         case TBM_FORMAT_XRGB8888:
437                 return PIXMAN_x8r8g8b8;
438         default:
439                 return 0;
440         }
441
442         return 0;
443 }
444
445 EXTERN tdm_error
446 tdm_helper_convert_buffer(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
447                                                   tdm_pos *srcpos, tdm_pos *dstpos,
448                                                   tdm_transform transform, int over)
449 {
450         tbm_surface_info_s src_info, dst_info;
451         pixman_image_t *src_img = NULL, *dst_img = NULL;
452         pixman_format_code_t src_format, dst_format;
453         double scale_x, scale_y;
454         int rotate_step, bos;
455         pixman_transform_t t;
456         struct pixman_f_transform ft;
457         pixman_op_t op;
458         int src_stride, dst_stride;
459         int buf_width, err;
460         tdm_error ret = TDM_ERROR_OPERATION_FAILED;
461
462         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
463         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
464
465         bos = tbm_surface_internal_get_num_bos(srcbuf);
466         TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED);
467
468         bos = tbm_surface_internal_get_num_bos(dstbuf);
469         TDM_RETURN_VAL_IF_FAIL(bos == 1, TDM_ERROR_OPERATION_FAILED);
470
471         err = tbm_surface_map(srcbuf, TBM_OPTION_READ, &src_info);
472         TDM_RETURN_VAL_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, TDM_ERROR_OPERATION_FAILED);
473
474         err = tbm_surface_map(dstbuf, TBM_OPTION_WRITE, &dst_info);
475         TDM_GOTO_IF_FAIL(err == TBM_SURFACE_ERROR_NONE, unmap_srcbuf);
476
477         /* not handle buffers which have 2 more gem handles */
478         TDM_GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, unmap_dstbuf);
479         TDM_GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, unmap_dstbuf);
480
481         src_format = _tdm_helper_pixman_format_get(src_info.format);
482         TDM_GOTO_IF_FAIL(src_format > 0, unmap_dstbuf);
483         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
484         TDM_GOTO_IF_FAIL(dst_format > 0, unmap_dstbuf);
485
486         buf_width = src_info.planes[0].stride >> 2;
487         src_stride = src_info.planes[0].stride;
488         src_img = pixman_image_create_bits(src_format, buf_width, src_info.height,
489                                                                            (uint32_t*)src_info.planes[0].ptr, src_stride);
490         TDM_GOTO_IF_FAIL(src_img, unref_img);
491
492         buf_width = dst_info.planes[0].stride >> 2;
493         dst_stride = dst_info.planes[0].stride;
494         dst_img = pixman_image_create_bits(dst_format, buf_width, dst_info.height,
495                                                                            (uint32_t*)dst_info.planes[0].ptr, dst_stride);
496         TDM_GOTO_IF_FAIL(dst_img, unref_img);
497
498         pixman_f_transform_init_identity(&ft);
499
500         if (transform & TDM_TRANSFORM_FLIPPED) {
501                 pixman_f_transform_scale(&ft, NULL, -1, 1);
502                 pixman_f_transform_translate(&ft, NULL, dstpos->w, 0);
503         }
504
505         rotate_step = transform & 0x3;
506         if (rotate_step > 0) {
507                 int c, s, tx = 0, ty = 0;
508                 switch (rotate_step) {
509                 case 1:
510                         c = 0, s = -1, tx = -dstpos->w;
511                         break;
512                 case 2:
513                         c = -1, s = 0, tx = -dstpos->w, ty = -dstpos->h;
514                         break;
515                 case 3:
516                         c = 0, s = 1, ty = -dstpos->h;
517                         break;
518                 }
519                 pixman_f_transform_translate(&ft, NULL, tx, ty);
520                 pixman_f_transform_rotate(&ft, NULL, c, s);
521         }
522
523         if (rotate_step % 2 == 0) {
524                 scale_x = (double)srcpos->w / dstpos->w;
525                 scale_y = (double)srcpos->h / dstpos->h;
526         } else {
527                 scale_x = (double)srcpos->w / dstpos->h;
528                 scale_y = (double)srcpos->h / dstpos->w;
529         }
530
531         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
532         pixman_f_transform_translate(&ft, NULL, srcpos->x, srcpos->y);
533         pixman_transform_from_pixman_f_transform(&t, &ft);
534         pixman_image_set_transform(src_img, &t);
535
536         op = (!over) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER;
537
538         pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0,
539                                                    dstpos->x, dstpos->y, dstpos->w, dstpos->h);
540
541         ret = TDM_ERROR_NONE;
542
543 unref_img:
544         if (src_img)
545                 pixman_image_unref(src_img);
546         if (dst_img)
547                 pixman_image_unref(dst_img);
548 unmap_dstbuf:
549         tbm_surface_unmap(dstbuf);
550 unmap_srcbuf:
551         tbm_surface_unmap(srcbuf);
552
553         return ret;
554 }
555
556 /* LCOV_EXCL_START */
557 EXTERN int
558 tdm_helper_get_fd(const char *env)
559 {
560         if (strncmp(env, "TBM_DRM_MASTER_FD", 17) && strncmp(env, "TDM_DRM_MASTER_FD", 17)) {
561                 TDM_INFO("DEPRECATED! '%s'", env);
562                 return -1;
563         }
564
565         return tbm_drm_helper_get_master_fd();
566 }
567
568 EXTERN void
569 tdm_helper_set_fd(const char *env, int fd)
570 {
571         if (strncmp(env, "TBM_DRM_MASTER_FD", 17) && strncmp(env, "TDM_DRM_MASTER_FD", 17)) {
572                 TDM_INFO("DEPRECATED! '%s'", env);
573                 return;
574         }
575
576         tbm_drm_helper_set_tbm_master_fd(fd);
577 }
578 /* LCOV_EXCL_STOP */
579
580 EXTERN void
581 tdm_helper_dump_start(char *dumppath, int *count)
582 {
583         if (dumppath == NULL || count == NULL) {
584                 TDM_DBG("tdm_helper_dump dumppath or count is null.");
585                 return;
586         }
587
588         tdm_dump_enable = 1;
589
590         TDM_DBG("tdm_helper_dump start.(path : %s)", dumppath);
591 }
592
593 EXTERN void
594 tdm_helper_dump_stop(void)
595 {
596         tdm_dump_enable = 0;
597
598         TDM_DBG("tdm_helper_dump stop.");
599 }
600
601 /* LCOV_EXCL_START */
602 static tdm_error
603 _tdm_helper_buffer_convert(tbm_surface_h srcbuf, tbm_surface_h dstbuf,
604                                                    int dx, int dy, int dw, int dh, int count)
605 {
606         pixman_image_t *src_img = NULL, *dst_img = NULL;
607         pixman_format_code_t src_format, dst_format;
608         pixman_transform_t t;
609         struct pixman_f_transform ft;
610         pixman_op_t op;
611         tbm_surface_info_s src_info = {0, };
612         tbm_surface_info_s dst_info = {0, };
613         int stride, width;
614         double scale_x, scale_y;
615
616         TDM_RETURN_VAL_IF_FAIL(srcbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
617         TDM_RETURN_VAL_IF_FAIL(dstbuf != NULL, TDM_ERROR_INVALID_PARAMETER);
618
619         if (tbm_surface_map(srcbuf, TBM_SURF_OPTION_READ, &src_info) != TBM_SURFACE_ERROR_NONE) {
620                 TDM_ERR("cannot mmap srcbuf\n");
621                 return TDM_ERROR_OPERATION_FAILED;
622         }
623
624         if (tbm_surface_map(dstbuf, TBM_SURF_OPTION_WRITE, &dst_info) != TBM_SURFACE_ERROR_NONE) {
625                 TDM_ERR("cannot mmap dstbuf\n");
626                 tbm_surface_unmap(srcbuf);
627                 return TDM_ERROR_OPERATION_FAILED;
628         }
629         TDM_GOTO_IF_FAIL(src_info.num_planes == 1, cant_convert);
630         TDM_GOTO_IF_FAIL(dst_info.num_planes == 1, cant_convert);
631
632         /* src */
633         src_format = _tdm_helper_pixman_format_get(src_info.format);
634         TDM_GOTO_IF_FAIL(src_format > 0, cant_convert);
635
636         width = src_info.planes[0].stride / 4;
637         stride = src_info.planes[0].stride;
638         src_img = pixman_image_create_bits(src_format, width, src_info.height,
639                                                                            (uint32_t*)src_info.planes[0].ptr, stride);
640         TDM_GOTO_IF_FAIL(src_img != NULL, cant_convert);
641
642         /* dst */
643         dst_format = _tdm_helper_pixman_format_get(dst_info.format);
644         TDM_GOTO_IF_FAIL(dst_format > 0, cant_convert);
645
646         width = dst_info.planes[0].stride / 4;
647         stride = dst_info.planes[0].stride;
648         dst_img = pixman_image_create_bits(dst_format, width, dst_info.height,
649                                                                            (uint32_t*)dst_info.planes[0].ptr, stride);
650         TDM_GOTO_IF_FAIL(dst_img != NULL, cant_convert);
651
652         pixman_f_transform_init_identity(&ft);
653
654         scale_x = (double)src_info.width / dw;
655         scale_y = (double)src_info.height / dh;
656
657         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
658         pixman_f_transform_translate(&ft, NULL, 0, 0);
659         pixman_transform_from_pixman_f_transform(&t, &ft);
660         pixman_image_set_transform(src_img, &t);
661
662         if (count == 0)
663                 op = PIXMAN_OP_SRC;
664         else
665                 op = PIXMAN_OP_OVER;
666
667         pixman_image_composite(op, src_img, NULL, dst_img,
668                                                    0, 0, 0, 0, dx, dy, dw, dh);
669
670         if (src_img)
671                 pixman_image_unref(src_img);
672         if (dst_img)
673                 pixman_image_unref(dst_img);
674
675         tbm_surface_unmap(srcbuf);
676         tbm_surface_unmap(dstbuf);
677
678         return TDM_ERROR_NONE;
679
680 cant_convert:
681         if (src_img)
682                 pixman_image_unref(src_img);
683
684         tbm_surface_unmap(srcbuf);
685         tbm_surface_unmap(dstbuf);
686
687         return TDM_ERROR_OPERATION_FAILED;
688 }
689 /* LCOV_EXCL_STOP */
690
691
692 EXTERN tdm_error
693 tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
694                                                   int x, int y, int w, int h,
695                                                   tdm_helper_capture_handler func, void *data)
696 {
697         tbm_surface_h surface;
698         tdm_error err;
699         int i, count, first = 0;
700
701         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
702         TDM_RETURN_VAL_IF_FAIL(dst_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
703         TDM_RETURN_VAL_IF_FAIL(x >= 0, TDM_ERROR_INVALID_PARAMETER);
704         TDM_RETURN_VAL_IF_FAIL(y >= 0, TDM_ERROR_INVALID_PARAMETER);
705         TDM_RETURN_VAL_IF_FAIL(w >= 0, TDM_ERROR_INVALID_PARAMETER);
706         TDM_RETURN_VAL_IF_FAIL(h >= 0, TDM_ERROR_INVALID_PARAMETER);
707         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
708
709         err = tdm_output_get_layer_count(output, &count);
710         if (err != TDM_ERROR_NONE) {
711                 TDM_ERR("tdm_output_get_layer_count fail(%d)\n", err);
712                 return TDM_ERROR_OPERATION_FAILED;
713         }
714         if (count <= 0) {
715                 TDM_ERR("tdm_output_get_layer_count err(%d, %d)\n", err, count);
716                 return TDM_ERROR_BAD_MODULE;
717         }
718
719         for (i = count - 1; i >= 0; i--) {
720                 tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
721
722                 surface = tdm_layer_get_displaying_buffer(layer, &err);
723                 if (err != TDM_ERROR_NONE)
724                         continue;
725
726                 err = _tdm_helper_buffer_convert(surface, dst_buffer, x, y, w, h, first++);
727                 if (err != TDM_ERROR_NONE)
728                         TDM_DBG("convert fail %d-layer buffer\n", i);
729                 else
730                         TDM_DBG("convert success %d-layer buffer\n", i);
731         }
732
733         func(dst_buffer, data);
734
735         return TDM_ERROR_NONE;
736 }
737
738 static char *
739 _tdm_helper_get_backend_information(tdm_private_module *private_module, char *reply, int *len)
740 {
741         tdm_backend_module *module_data;
742         tdm_func_output *func_output;
743         tdm_func_layer *func_layer;
744         tdm_private_output *private_output = NULL;
745         tdm_private_layer *private_layer = NULL;
746         tdm_private_pp *private_pp = NULL;
747         tdm_private_capture *private_capture = NULL;
748         tdm_error ret;
749         int i;
750
751         func_output = &private_module->func_output;
752         func_layer = &private_module->func_layer;
753
754         /* module information */
755         module_data = private_module->module_data;
756         TDM_SNPRINTF(reply, len, "['%s' backend information]\n", module_data->name);
757         TDM_SNPRINTF(reply, len, "vendor: %s\n", module_data->vendor);
758         TDM_SNPRINTF(reply, len, "version: %d.%d\n\n",
759                                  (int)TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version),
760                                  (int)TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version));
761
762         /* output information */
763         TDM_SNPRINTF(reply, len, "['%s' backend output information]\n", module_data->name);
764         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
765         TDM_SNPRINTF(reply, len, "idx   maker   model   name   type   status   dpms   subpixel   align_w   min   max   phy(mm)\n");
766         TDM_SNPRINTF(reply, len, "--------------------------------------------------------------------------------------------\n");
767         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
768                 TDM_SNPRINTF(reply, len, "%d   %s   %s   %s   %s   %s   %s   %u   %d   %dx%d   %dx%d   %ux%u\n",
769                                          private_output->index, private_output->caps.maker,
770                                          private_output->caps.model, private_output->caps.name,
771                                          tdm_conn_str(private_output->caps.type),
772                                          tdm_status_str(private_output->caps.status),
773                                          tdm_dpms_str(private_output->current_dpms_value),
774                                          private_output->caps.subpixel,
775                                          TDM_FRONT_VALUE(private_output->caps.preferred_align),
776                                          TDM_FRONT_VALUE(private_output->caps.min_w),
777                                          TDM_FRONT_VALUE(private_output->caps.min_h),
778                                          TDM_FRONT_VALUE(private_output->caps.max_w),
779                                          TDM_FRONT_VALUE(private_output->caps.max_h),
780                                          private_output->caps.mmWidth, private_output->caps.mmHeight);
781
782                 TDM_SNPRINTF(reply, len, "\t%u modes:\n", private_output->caps.mode_count);
783
784                 if (private_output->caps.mode_count > 0) {
785                         TDM_SNPRINTF(reply, len, "\t\t name refresh (Hz) clk hdisp hss hse htot vdisp vss vse vtot vscan\n");
786                         for (i = 0; i < private_output->caps.mode_count; i++) {
787                                 char *current = (private_output->current_mode == private_output->caps.modes + i) ? "*" : " ";
788                                 TDM_SNPRINTF(reply, len, "\t\t%s%s %u %u %u %u %u %u %u %u %u %u %u ",
789                                                          current,
790                                                          private_output->caps.modes[i].name,
791                                                          private_output->caps.modes[i].vrefresh,
792                                                          private_output->caps.modes[i].clock,
793                                                          private_output->caps.modes[i].hdisplay,
794                                                          private_output->caps.modes[i].hsync_start,
795                                                          private_output->caps.modes[i].hsync_end,
796                                                          private_output->caps.modes[i].htotal,
797                                                          private_output->caps.modes[i].vdisplay,
798                                                          private_output->caps.modes[i].vsync_start,
799                                                          private_output->caps.modes[i].vsync_end,
800                                                          private_output->caps.modes[i].vtotal,
801                                                          private_output->caps.modes[i].vscan);
802                                 tdm_mode_flag_str(private_output->caps.modes[i].flags, &reply, len);
803                                 TDM_SNPRINTF(reply, len, " ");
804                                 tdm_mode_type_str(private_output->caps.modes[i].type, &reply, len);
805                                 TDM_SNPRINTF(reply, len, "\n");
806                         }
807                 }
808
809                 TDM_SNPRINTF(reply, len, "\t%d properties:\n", private_output->caps.prop_count);
810                 if (private_output->caps.prop_count > 0) {
811                         TDM_SNPRINTF(reply, len, "\t\tname\ttype\tidx\tvalue\n");
812                         for (i = 0; i < private_output->caps.prop_count; i++) {
813                                 tdm_value value;
814                                 TDM_DBG_RETURN_VAL_IF_FAIL(func_output->output_get_property, reply);
815                                 ret = func_output->output_get_property(private_output->output_backend,
816                                                                                                            private_output->caps.props[i].id,
817                                                                                                            &value);
818                                 TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
819                                 TDM_SNPRINTF(reply, len, "\t\t%s\t%s\t%u\t",
820                                                          private_output->caps.props[i].name,
821                                                          tdm_value_type_str(private_output->caps.props[i].type),
822                                                          private_output->caps.props[i].id);
823                                 switch (private_output->caps.props[i].type) {
824                                 case TDM_VALUE_TYPE_PTR:
825                                         TDM_SNPRINTF(reply, len, "%p\n", value.ptr);
826                                         break;
827                                 case TDM_VALUE_TYPE_INT32:
828                                         TDM_SNPRINTF(reply, len, "%d\n", value.s32);
829                                         break;
830                                 case TDM_VALUE_TYPE_INT64:
831                                         TDM_SNPRINTF(reply, len, "%"PRId64"\n", value.s64);
832                                         break;
833                                 case TDM_VALUE_TYPE_UINT64:
834                                         TDM_SNPRINTF(reply, len, "%"PRIu64"\n", value.u64);
835                                         break;
836                                 case TDM_VALUE_TYPE_UINT32:
837                                 default:
838                                         TDM_SNPRINTF(reply, len, "%u\n", value.u32);
839                                         break;
840                                 }
841                         }
842                 }
843         }
844         TDM_SNPRINTF(reply, len, "\n");
845
846         /* layer information */
847         TDM_SNPRINTF(reply, len, "['%s' backend layer information]\n", module_data->name);
848         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
849         TDM_SNPRINTF(reply, len, "idx   output   zpos   buf   format   size   crop   geometry   transform\n");
850         TDM_SNPRINTF(reply, len, "-----------------------------------------------------------------------\n");
851         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
852                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
853                         if (!private_layer->usable) {
854                                 tdm_info_layer info;
855                                 unsigned int format;
856                                 tdm_size size;
857                                 tbm_surface_info_s buf_info;
858
859                                 TDM_DBG_RETURN_VAL_IF_FAIL(func_layer->layer_get_info, reply);
860                                 memset(&info, 0, sizeof info);
861                                 ret = func_layer->layer_get_info(private_layer->layer_backend, &info);
862                                 TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
863
864                                 if (!private_layer->showing_buffer)
865                                         continue;
866
867                                 format = tbm_surface_get_format(private_layer->showing_buffer->buffer);
868                                 tbm_surface_get_info(private_layer->showing_buffer->buffer, &buf_info);
869
870                                 if (IS_RGB(format))
871                                         size.h = buf_info.planes[0].stride >> 2;
872                                 else
873                                         size.h = buf_info.planes[0].stride;
874                                 size.v = tbm_surface_get_height(private_layer->showing_buffer->buffer);
875
876                                 if (info.src_config.format)
877                                         format = (info.src_config.format) ? : format;
878
879                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c   %ux%u   %ux%u+%u+%u   %ux%u+%u+%u   %s\n",
880                                                          private_layer->index,
881                                                          private_output->index,
882                                                          private_layer->caps.zpos,
883                                                          private_layer->showing_buffer->buffer, FOURCC_STR(format), size.h, size.v,
884                                                          info.src_config.pos.w, info.src_config.pos.h, info.src_config.pos.x, info.src_config.pos.y,
885                                                          info.dst_pos.w, info.dst_pos.h, info.dst_pos.x, info.dst_pos.y,
886                                                          tdm_transform_str(info.transform));
887                         } else {
888                                 TDM_SNPRINTF(reply, len, "%d   %d   %d   -\n",
889                                                          private_layer->index,
890                                                          private_output->index,
891                                                          private_layer->caps.zpos);
892                         }
893
894                         TDM_SNPRINTF(reply, len, "\tcaps\t: ");
895                         tdm_layer_caps_str(private_layer->caps.capabilities, &reply, len);
896                         TDM_SNPRINTF(reply, len, "\n");
897
898                         TDM_SNPRINTF(reply, len, "\tformats\t: ");
899                         if (private_layer->caps.format_count > 0) {
900                                 const char *sep = "";
901                                 for (i = 0; i < private_layer->caps.format_count; i++) {
902                                         if (private_layer->caps.formats[i] == 0)
903                                                 continue;
904                                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_layer->caps.formats[i]));
905                                         sep = ",";
906                                 }
907                                 TDM_SNPRINTF(reply, len, "\n");
908                         }
909
910                         TDM_SNPRINTF(reply, len, "\t%u properties:\n", private_layer->caps.prop_count);
911                         if (private_layer->caps.prop_count > 0) {
912                                 TDM_SNPRINTF(reply, len, "\t\tname\ttype\tidx\tvalue\n");
913                                 for (i = 0; i < private_layer->caps.prop_count; i++) {
914                                         tdm_value value;
915                                         TDM_DBG_RETURN_VAL_IF_FAIL(func_layer->layer_get_property, reply);
916                                         ret = func_layer->layer_get_property(private_layer->layer_backend,
917                                                                                                                  private_layer->caps.props[i].id,
918                                                                                                                  &value);
919                                         TDM_DBG_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, reply);
920                                         TDM_SNPRINTF(reply, len, "\t\t%s\t%s\t%u\t",
921                                                                  private_layer->caps.props[i].name,
922                                                                  tdm_value_type_str(private_output->caps.props[i].type),
923                                                                  private_layer->caps.props[i].id);
924                                 switch (private_layer->caps.props[i].type) {
925                                 case TDM_VALUE_TYPE_PTR:
926                                         TDM_SNPRINTF(reply, len, "%p\n", value.ptr);
927                                         break;
928                                 case TDM_VALUE_TYPE_INT32:
929                                         TDM_SNPRINTF(reply, len, "%d\n", value.s32);
930                                         break;
931                                 case TDM_VALUE_TYPE_INT64:
932                                         TDM_SNPRINTF(reply, len, "%"PRId64"\n", value.s64);
933                                         break;
934                                 case TDM_VALUE_TYPE_UINT64:
935                                         TDM_SNPRINTF(reply, len, "%"PRIu64"\n", value.u64);
936                                         break;
937                                 case TDM_VALUE_TYPE_UINT32:
938                                 default:
939                                         TDM_SNPRINTF(reply, len, "%u\n", value.u32);
940                                         break;
941                                 }
942                                 }
943                         }
944                 }
945         }
946         TDM_SNPRINTF(reply, len, "\n");
947
948         if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
949                 const char *sep = "";
950                 TDM_SNPRINTF(reply, len, "['%s' backend PP information]\n", module_data->name);
951                 TDM_SNPRINTF(reply, len, "caps\t: ");
952                 tdm_pp_caps_str(private_module->caps_pp.capabilities, &reply, len);
953                 TDM_SNPRINTF(reply, len, "\n");
954                 TDM_SNPRINTF(reply, len, "formats\t: ");
955                 for (i = 0; i < private_module->caps_pp.format_count; i++) {
956                         if (private_module->caps_pp.formats[i] == 0)
957                                 continue;
958                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_module->caps_pp.formats[i]));
959                         sep = ",";
960                 }
961                 TDM_SNPRINTF(reply, len, "\n");
962                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
963                                          TDM_FRONT_VALUE(private_module->caps_pp.min_w),
964                                          TDM_FRONT_VALUE(private_module->caps_pp.min_h),
965                                          TDM_FRONT_VALUE(private_module->caps_pp.max_w),
966                                          TDM_FRONT_VALUE(private_module->caps_pp.max_h),
967                                          TDM_FRONT_VALUE(private_module->caps_pp.preferred_align));
968                 if (!LIST_IS_EMPTY(&private_module->pp_list)) {
969                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
970                         TDM_SNPRINTF(reply, len, "src(format size crop)  |  dst(format size crop)  |  transform\n");
971                         TDM_SNPRINTF(reply, len, "-------------------------------------------------------------\n");
972                         LIST_FOR_EACH_ENTRY(private_pp, &private_module->pp_list, link) {
973                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %ux%u %ux%u+%u+%u | %c%c%c%c %ux%u %ux%u+%u+%u | %s\n",
974                                                          FOURCC_STR(private_pp->info.src_config.format),
975                                                          private_pp->info.src_config.size.h,
976                                                          private_pp->info.src_config.size.v,
977                                                          private_pp->info.src_config.pos.x, private_pp->info.src_config.pos.y,
978                                                          private_pp->info.src_config.pos.w, private_pp->info.src_config.pos.h,
979                                                          FOURCC_STR(private_pp->info.dst_config.format),
980                                                          private_pp->info.dst_config.size.h,
981                                                          private_pp->info.dst_config.size.v,
982                                                          private_pp->info.dst_config.pos.x, private_pp->info.dst_config.pos.y,
983                                                          private_pp->info.dst_config.pos.w, private_pp->info.dst_config.pos.h,
984                                                          tdm_transform_str(private_pp->info.transform));
985                         }
986                 }
987         } else {
988                 TDM_SNPRINTF(reply, len, "['%s' backend No PP capability]\n", module_data->name);
989         }
990         TDM_SNPRINTF(reply, len, "\n");
991
992         if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
993                 const char *sep = "";
994                 TDM_SNPRINTF(reply, len, "['%s' backend capture information]\n", module_data->name);
995                 TDM_SNPRINTF(reply, len, "caps\t: ");
996                 tdm_capture_caps_str(private_module->caps_capture.capabilities, &reply, len);
997                 TDM_SNPRINTF(reply, len, "\n");
998                 TDM_SNPRINTF(reply, len, "formats\t: ");
999                 for (i = 0; i < private_module->caps_capture.format_count; i++) {
1000                         if (private_module->caps_capture.formats[i] == 0)
1001                                 continue;
1002                         TDM_SNPRINTF(reply, len, "%s%c%c%c%c", sep, FOURCC_STR(private_module->caps_capture.formats[i]));
1003                         sep = ",";
1004                 }
1005                 TDM_SNPRINTF(reply, len, "\n");
1006                 TDM_SNPRINTF(reply, len, "size\t: min(%dx%d) max(%dx%d) align_w(%d)\n",
1007                                          TDM_FRONT_VALUE(private_module->caps_capture.min_w),
1008                                          TDM_FRONT_VALUE(private_module->caps_capture.min_h),
1009                                          TDM_FRONT_VALUE(private_module->caps_capture.max_w),
1010                                          TDM_FRONT_VALUE(private_module->caps_capture.max_h),
1011                                          TDM_FRONT_VALUE(private_module->caps_capture.preferred_align));
1012                 if (!LIST_IS_EMPTY(&private_module->capture_list)) {
1013                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
1014                         TDM_SNPRINTF(reply, len, "dst(format size crop)  |  transform\n");
1015                         TDM_SNPRINTF(reply, len, "-----------------------------------\n");
1016                         LIST_FOR_EACH_ENTRY(private_capture, &private_module->capture_list, link) {
1017                                 TDM_SNPRINTF(reply, len, "%c%c%c%c %ux%u %ux%u+%u+%u | %s\n",
1018                                                          FOURCC_STR(private_capture->info.dst_config.format),
1019                                                          private_capture->info.dst_config.size.h,
1020                                                          private_capture->info.dst_config.size.v,
1021                                                          private_capture->info.dst_config.pos.x, private_capture->info.dst_config.pos.y,
1022                                                          private_capture->info.dst_config.pos.w, private_capture->info.dst_config.pos.h,
1023                                                          tdm_transform_str(private_capture->info.transform));
1024                         }
1025                 }
1026         } else {
1027                 TDM_SNPRINTF(reply, len, "['%s' backend No Capture capability]\n", module_data->name);
1028         }
1029         TDM_SNPRINTF(reply, len, "\n");
1030         return reply;
1031 }
1032
1033 EXTERN void
1034 tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len)
1035 {
1036         tdm_private_display *private_display;
1037         tdm_private_module *private_module = NULL;
1038
1039         TDM_DBG_RETURN_IF_FAIL(dpy != NULL);
1040
1041         private_display = dpy;
1042
1043         _pthread_mutex_lock(&private_display->lock);
1044
1045         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
1046                 reply = _tdm_helper_get_backend_information(private_module, reply, len);
1047         }
1048
1049         _pthread_mutex_unlock(&private_display->lock);
1050 }
1051
1052 /* LCOV_EXCL_START */
1053 EXTERN int
1054 tdm_helper_commit_per_vblank_enabled(tdm_display *dpy)
1055 {
1056         TDM_DEPRECATED("Use tdm_helper_output_commit_per_vblank_enabled");
1057
1058         return 0;
1059 }
1060 /* LCOV_EXCL_STOP */
1061
1062 EXTERN int
1063 tdm_helper_output_commit_per_vblank_enabled(tdm_output *output)
1064 {
1065         tdm_private_output *private_output = output;
1066
1067         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, -1);
1068
1069         return !!private_output->commit_per_vblank;
1070 }
1071
1072 EXTERN unsigned int
1073 tdm_helper_output_vblank_timer_expired(tdm_output *output)
1074 {
1075         tdm_private_output *private_output = output;
1076
1077         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, -1);
1078
1079         return private_output->vblank_timeout_timer_expired;
1080 }