use stat() to check if symbolic link
[platform/core/uifw/libtbm.git] / src / tbm_surface_internal.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33
34 #include <stdio.h>
35 #include <time.h>
36 #include <sys/time.h>
37 #include "tbm_bufmgr.h"
38 #include "tbm_bufmgr_int.h"
39 #include "tbm_surface_internal.h"
40 #include "list.h"
41 #include <png.h>
42 #include <pixman.h>
43
44 static tbm_bufmgr g_surface_bufmgr;
45 static pthread_mutex_t tbm_surface_lock;
46 void _tbm_surface_mutex_unlock(void);
47
48 #define C(b, m)              (((b) >> (m)) & 0xFF)
49 #define B(c, s)              ((((unsigned int)(c)) & 0xff) << (s))
50 #define FOURCC(a, b, c, d)     (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0))
51 #define FOURCC_STR(id)      C(id, 0), C(id, 8), C(id, 16), C(id, 24)
52 #define FOURCC_ID(str)      FOURCC(((char*)str)[0], ((char*)str)[1], ((char*)str)[2], ((char*)str)[3])
53
54 /* check condition */
55 #define TBM_SURFACE_RETURN_IF_FAIL(cond) {\
56         if (!(cond)) {\
57                 TBM_LOG_E("'%s' failed.\n", #cond);\
58                 _tbm_surface_mutex_unlock();\
59                 return;\
60         } \
61 }
62
63 #define TBM_SURFACE_RETURN_VAL_IF_FAIL(cond, val) {\
64         if (!(cond)) {\
65                 TBM_LOG_E("'%s' failed.\n", #cond);\
66                 _tbm_surface_mutex_unlock();\
67                 return val;\
68         } \
69 }
70
71 /* LCOV_EXCL_START */
72 static double
73 _tbm_surface_internal_get_time(void)
74 {
75         struct timespec tp;
76         unsigned int time;
77
78         clock_gettime(CLOCK_MONOTONIC, &tp);
79         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
80
81         return time / 1000.0;
82 }
83
84 static void
85 _tbm_surface_internal_debug_data_delete(tbm_surface_debug_data *debug_data)
86 {
87         LIST_DEL(&debug_data->item_link);
88
89         if (debug_data->key) free(debug_data->key);
90         if (debug_data->value) free(debug_data->value);
91         free(debug_data);
92 }
93
94 char *
95 _tbm_surface_internal_format_to_str(tbm_format format)
96 {
97         switch (format) {
98         case TBM_FORMAT_C8:
99                 return "TBM_FORMAT_C8";
100         case TBM_FORMAT_RGB332:
101                 return "TBM_FORMAT_RGB332";
102         case TBM_FORMAT_BGR233:
103                 return "TBM_FORMAT_BGR233";
104         case TBM_FORMAT_XRGB4444:
105                 return "TBM_FORMAT_XRGB4444";
106         case TBM_FORMAT_XBGR4444:
107                 return "TBM_FORMAT_XBGR4444";
108         case TBM_FORMAT_RGBX4444:
109                 return "TBM_FORMAT_RGBX4444";
110         case TBM_FORMAT_BGRX4444:
111                 return "TBM_FORMAT_BGRX4444";
112         case TBM_FORMAT_ARGB4444:
113                 return "TBM_FORMAT_ARGB4444";
114         case TBM_FORMAT_ABGR4444:
115                 return "TBM_FORMAT_ABGR4444";
116         case TBM_FORMAT_RGBA4444:
117                 return "TBM_FORMAT_RGBA4444";
118         case TBM_FORMAT_BGRA4444:
119                 return "TBM_FORMAT_BGRA4444";
120         case TBM_FORMAT_XRGB1555:
121                 return "TBM_FORMAT_XRGB1555";
122         case TBM_FORMAT_XBGR1555:
123                 return "TBM_FORMAT_XBGR1555";
124         case TBM_FORMAT_RGBX5551:
125                 return "TBM_FORMAT_RGBX5551";
126         case TBM_FORMAT_BGRX5551:
127                 return "TBM_FORMAT_BGRX5551";
128         case TBM_FORMAT_ARGB1555:
129                 return "TBM_FORMAT_ARGB1555";
130         case TBM_FORMAT_ABGR1555:
131                 return "TBM_FORMAT_ABGR1555";
132         case TBM_FORMAT_RGBA5551:
133                 return "TBM_FORMAT_RGBA5551";
134         case TBM_FORMAT_BGRA5551:
135                 return "TBM_FORMAT_BGRA5551";
136         case TBM_FORMAT_RGB565:
137                 return "TBM_FORMAT_RGB565";
138         case TBM_FORMAT_BGR565:
139                 return "TBM_FORMAT_BGR565";
140         case TBM_FORMAT_RGB888:
141                 return "TBM_FORMAT_RGB888";
142         case TBM_FORMAT_BGR888:
143                 return "TBM_FORMAT_BGR888";
144         case TBM_FORMAT_XRGB8888:
145                 return "TBM_FORMAT_XRGB8888";
146         case TBM_FORMAT_XBGR8888:
147                 return "TBM_FORMAT_XBGR8888";
148         case TBM_FORMAT_RGBX8888:
149                 return "TBM_FORMAT_RGBX8888";
150         case TBM_FORMAT_BGRX8888:
151                 return "TBM_FORMAT_BGRX8888";
152         case TBM_FORMAT_ARGB8888:
153                 return "TBM_FORMAT_ARGB8888";
154         case TBM_FORMAT_ABGR8888:
155                 return "TBM_FORMAT_ABGR8888";
156         case TBM_FORMAT_RGBA8888:
157                 return "TBM_FORMAT_RGBA8888";
158         case TBM_FORMAT_BGRA8888:
159                 return "TBM_FORMAT_BGRA8888";
160         case TBM_FORMAT_XRGB2101010:
161                 return "TBM_FORMAT_XRGB2101010";
162         case TBM_FORMAT_XBGR2101010:
163                 return "TBM_FORMAT_XBGR2101010";
164         case TBM_FORMAT_RGBX1010102:
165                 return "TBM_FORMAT_RGBX1010102";
166         case TBM_FORMAT_BGRX1010102:
167                 return "TBM_FORMAT_BGRX1010102";
168         case TBM_FORMAT_ARGB2101010:
169                 return "TBM_FORMAT_ARGB2101010";
170         case TBM_FORMAT_ABGR2101010:
171                 return "TBM_FORMAT_ABGR2101010";
172         case TBM_FORMAT_RGBA1010102:
173                 return "TBM_FORMAT_RGBA1010102";
174         case TBM_FORMAT_BGRA1010102:
175                 return "TBM_FORMAT_BGRA1010102";
176         case TBM_FORMAT_YUYV:
177                 return "TBM_FORMAT_YUYV";
178         case TBM_FORMAT_YVYU:
179                 return "TBM_FORMAT_YVYU";
180         case TBM_FORMAT_UYVY:
181                 return "TBM_FORMAT_UYVY";
182         case TBM_FORMAT_VYUY:
183                 return "TBM_FORMAT_VYUY";
184         case TBM_FORMAT_AYUV:
185                 return "TBM_FORMAT_AYUV";
186         case TBM_FORMAT_NV12:
187                 return "TBM_FORMAT_NV12";
188         case TBM_FORMAT_NV21:
189                 return "TBM_FORMAT_NV21";
190         case TBM_FORMAT_NV16:
191                 return "TBM_FORMAT_NV16";
192         case TBM_FORMAT_NV61:
193                 return "TBM_FORMAT_NV61";
194         case TBM_FORMAT_YUV410:
195                 return "TBM_FORMAT_YUV410";
196         case TBM_FORMAT_YVU410:
197                 return "TBM_FORMAT_YVU410";
198         case TBM_FORMAT_YUV411:
199                 return "TBM_FORMAT_YUV411";
200         case TBM_FORMAT_YVU411:
201                 return "TBM_FORMAT_YVU411";
202         case TBM_FORMAT_YUV420:
203                 return "TBM_FORMAT_YUV420";
204         case TBM_FORMAT_YVU420:
205                 return "TBM_FORMAT_YVU420";
206         case TBM_FORMAT_YUV422:
207                 return "TBM_FORMAT_YUV422";
208         case TBM_FORMAT_YVU422:
209                 return "TBM_FORMAT_YVU422";
210         case TBM_FORMAT_YUV444:
211                 return "TBM_FORMAT_YUV444";
212         case TBM_FORMAT_YVU444:
213                 return "TBM_FORMAT_YVU444";
214         case TBM_FORMAT_NV12MT:
215                 return "TBM_FORMAT_NV12MT";
216         default:
217                 return "unknwon";
218         }
219 }
220
221 static bool
222 _tbm_surface_mutex_init(void)
223 {
224         static bool tbm_surface_mutex_init = false;
225
226         if (tbm_surface_mutex_init)
227                 return true;
228
229         if (pthread_mutex_init(&tbm_surface_lock, NULL)) {
230                 TBM_LOG_E("fail: pthread_mutex_init for tbm_surface_lock.\n");
231                 return false;
232         }
233
234         tbm_surface_mutex_init = true;
235
236         return true;
237 }
238
239 void
240 _tbm_surface_mutex_lock(void)
241 {
242         if (!_tbm_surface_mutex_init()) {
243                 TBM_LOG_E("fail: _tbm_surface_mutex_init.\n");
244                 return;
245         }
246
247         pthread_mutex_lock(&tbm_surface_lock);
248 }
249
250 void
251 _tbm_surface_mutex_unlock(void)
252 {
253         pthread_mutex_unlock(&tbm_surface_lock);
254 }
255
256 static void
257 _init_surface_bufmgr(void)
258 {
259         g_surface_bufmgr = tbm_bufmgr_init(-1);
260 }
261
262 static void
263 _deinit_surface_bufmgr(void)
264 {
265         if (!g_surface_bufmgr)
266                 return;
267
268         tbm_bufmgr_deinit(g_surface_bufmgr);
269         g_surface_bufmgr = NULL;
270 }
271 /* LCOV_EXCL_STOP */
272
273 static int
274 _tbm_surface_internal_is_valid(tbm_surface_h surface)
275 {
276         tbm_surface_h old_data = NULL;
277
278         TBM_RETURN_VAL_IF_FAIL(g_surface_bufmgr, 0);
279         TBM_RETURN_VAL_IF_FAIL(surface, 0);
280
281         if (!LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
282                 LIST_FOR_EACH_ENTRY(old_data, &g_surface_bufmgr->surf_list, item_link) {
283                         if (old_data == surface) {
284                                 TBM_TRACE("tbm_surface(%p)\n", surface);
285                                 return 1;
286                         }
287                 }
288         }
289
290         TBM_LOG_E("error: No valid tbm_surface(%p)\n", surface);
291
292         return 0;
293 }
294
295 static int
296 _tbm_surface_internal_query_plane_data(tbm_surface_h surface,
297                                        int plane_idx, uint32_t *size, uint32_t *offset, uint32_t *pitch, int *bo_idx)
298 {
299         TBM_RETURN_VAL_IF_FAIL(surface, 0);
300         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
301
302         struct _tbm_surface *surf = (struct _tbm_surface *)surface;
303         struct _tbm_bufmgr *mgr = surf->bufmgr;
304         int ret = 0;
305
306         TBM_RETURN_VAL_IF_FAIL(mgr != NULL, 0);
307         TBM_RETURN_VAL_IF_FAIL(surf->info.width > 0, 0);
308         TBM_RETURN_VAL_IF_FAIL(surf->info.height > 0, 0);
309         TBM_RETURN_VAL_IF_FAIL(surf->info.format > 0, 0);
310
311         if (!mgr->backend->surface_get_plane_data)
312                 return 0;
313
314         ret = mgr->backend->surface_get_plane_data(surf->info.width,
315                         surf->info.height, surf->info.format, plane_idx, size, offset, pitch, bo_idx);
316         if (!ret) {
317                 /* LCOV_EXCL_START */
318                 TBM_LOG_E("Fail to surface_get_plane_data. surface(%p)\n", surface);
319                 return 0;
320                 /* LCOV_EXCL_STOP */
321         }
322
323         return 1;
324 }
325
326 static void
327 _tbm_surface_internal_destroy(tbm_surface_h surface)
328 {
329         int i;
330         tbm_bufmgr bufmgr = surface->bufmgr;
331         tbm_user_data *old_data = NULL, *tmp = NULL;
332         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
333
334         /* destory the user_data_list */
335         if (!LIST_IS_EMPTY(&surface->user_data_list)) {
336                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &surface->user_data_list, item_link) {
337                         TBM_DBG("free user_data\n");
338                         user_data_delete(old_data);
339                 }
340         }
341
342         for (i = 0; i < surface->num_bos; i++) {
343                 surface->bos[i]->surface = NULL;
344
345                 tbm_bo_unref(surface->bos[i]);
346                 surface->bos[i] = NULL;
347         }
348
349         if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
350                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &surface->debug_data_list, item_link)
351                         _tbm_surface_internal_debug_data_delete(debug_old_data);
352         }
353
354         LIST_DEL(&surface->item_link);
355
356         free(surface);
357         surface = NULL;
358
359         if (LIST_IS_EMPTY(&bufmgr->surf_list)) {
360                 LIST_DELINIT(&bufmgr->surf_list);
361
362                 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
363                         LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
364                                 _tbm_surface_internal_debug_data_delete(debug_old_data);
365                         }
366                 }
367
368                 _deinit_surface_bufmgr();
369         }
370 }
371
372 /* LCOV_EXCL_START */
373 static int
374 _tbm_surface_check_file_is_symbolic_link(const char* path)
375 {
376         struct stat sb;
377
378         if (!path)
379                 return 0;
380
381         if (stat(path, &sb) != 0)
382                 return 0;
383
384         if (S_ISLNK(sb.st_mode))
385                 return 1;
386
387         return 0;
388 }
389 /* LCOV_EXCL_STOP */
390
391 int
392 tbm_surface_internal_is_valid(tbm_surface_h surface)
393 {
394         int ret = 0;
395
396         _tbm_surface_mutex_lock();
397
398         /* Return silently if surface is null. */
399         if (!surface) {
400                 _tbm_surface_mutex_unlock();
401                 return 0;
402         }
403
404         ret = _tbm_surface_internal_is_valid(surface);
405
406         _tbm_surface_mutex_unlock();
407
408         return ret;
409 }
410
411 int
412 tbm_surface_internal_query_supported_formats(uint32_t **formats,
413                 uint32_t *num)
414 {
415         TBM_RETURN_VAL_IF_FAIL(formats, 0);
416         TBM_RETURN_VAL_IF_FAIL(num, 0);
417
418         struct _tbm_bufmgr *mgr;
419         int ret = 0;
420         bool bufmgr_initialized = false;
421
422         _tbm_surface_mutex_lock();
423
424         if (!g_surface_bufmgr) {
425                 _init_surface_bufmgr();
426                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
427                 bufmgr_initialized = true;
428         }
429
430         mgr = g_surface_bufmgr;
431
432         if (!mgr->backend->surface_supported_format)
433                 goto fail;
434
435         ret = mgr->backend->surface_supported_format(formats, num);
436         if (!ret)  {
437                 /* LCOV_EXCL_START */
438                 TBM_LOG_E("Fail to surface_supported_format.\n");
439                 goto fail;
440                 /* LCOV_EXCL_START */
441         }
442
443         TBM_TRACE("tbm_bufmgr(%p) format num(%u)\n", g_surface_bufmgr, *num);
444
445         _tbm_surface_mutex_unlock();
446
447         return ret;
448
449 /* LCOV_EXCL_START */
450 fail:
451         if (bufmgr_initialized) {
452                 LIST_DELINIT(&g_surface_bufmgr->surf_list);
453                 _deinit_surface_bufmgr();
454         }
455         _tbm_surface_mutex_unlock();
456
457         TBM_LOG_E("error: tbm_bufmgr(%p)\n", g_surface_bufmgr);
458
459         return 0;
460 /* LCOV_EXCL_STOP */
461 }
462
463 int
464 tbm_surface_internal_get_num_planes(tbm_format format)
465 {
466         int num_planes = 0;
467
468         switch (format) {
469         case TBM_FORMAT_C8:
470         case TBM_FORMAT_RGB332:
471         case TBM_FORMAT_BGR233:
472         case TBM_FORMAT_XRGB4444:
473         case TBM_FORMAT_XBGR4444:
474         case TBM_FORMAT_RGBX4444:
475         case TBM_FORMAT_BGRX4444:
476         case TBM_FORMAT_ARGB4444:
477         case TBM_FORMAT_ABGR4444:
478         case TBM_FORMAT_RGBA4444:
479         case TBM_FORMAT_BGRA4444:
480         case TBM_FORMAT_XRGB1555:
481         case TBM_FORMAT_XBGR1555:
482         case TBM_FORMAT_RGBX5551:
483         case TBM_FORMAT_BGRX5551:
484         case TBM_FORMAT_ARGB1555:
485         case TBM_FORMAT_ABGR1555:
486         case TBM_FORMAT_RGBA5551:
487         case TBM_FORMAT_BGRA5551:
488         case TBM_FORMAT_RGB565:
489         case TBM_FORMAT_BGR565:
490         case TBM_FORMAT_RGB888:
491         case TBM_FORMAT_BGR888:
492         case TBM_FORMAT_XRGB8888:
493         case TBM_FORMAT_XBGR8888:
494         case TBM_FORMAT_RGBX8888:
495         case TBM_FORMAT_BGRX8888:
496         case TBM_FORMAT_ARGB8888:
497         case TBM_FORMAT_ABGR8888:
498         case TBM_FORMAT_RGBA8888:
499         case TBM_FORMAT_BGRA8888:
500         case TBM_FORMAT_XRGB2101010:
501         case TBM_FORMAT_XBGR2101010:
502         case TBM_FORMAT_RGBX1010102:
503         case TBM_FORMAT_BGRX1010102:
504         case TBM_FORMAT_ARGB2101010:
505         case TBM_FORMAT_ABGR2101010:
506         case TBM_FORMAT_RGBA1010102:
507         case TBM_FORMAT_BGRA1010102:
508         case TBM_FORMAT_YUYV:
509         case TBM_FORMAT_YVYU:
510         case TBM_FORMAT_UYVY:
511         case TBM_FORMAT_VYUY:
512         case TBM_FORMAT_AYUV:
513                 num_planes = 1;
514                 break;
515         case TBM_FORMAT_NV12:
516         case TBM_FORMAT_NV12MT:
517         case TBM_FORMAT_NV21:
518         case TBM_FORMAT_NV16:
519         case TBM_FORMAT_NV61:
520                 num_planes = 2;
521                 break;
522         case TBM_FORMAT_YUV410:
523         case TBM_FORMAT_YVU410:
524         case TBM_FORMAT_YUV411:
525         case TBM_FORMAT_YVU411:
526         case TBM_FORMAT_YUV420:
527         case TBM_FORMAT_YVU420:
528         case TBM_FORMAT_YUV422:
529         case TBM_FORMAT_YVU422:
530         case TBM_FORMAT_YUV444:
531         case TBM_FORMAT_YVU444:
532                 num_planes = 3;
533                 break;
534
535         default:
536                 break;
537         }
538
539         TBM_TRACE("tbm_format(%s) num_planes(%d)\n", _tbm_surface_internal_format_to_str(format), num_planes);
540
541         return num_planes;
542 }
543
544 int
545 tbm_surface_internal_get_bpp(tbm_format format)
546 {
547
548         int bpp = 0;
549
550         switch (format) {
551         case TBM_FORMAT_C8:
552         case TBM_FORMAT_RGB332:
553         case TBM_FORMAT_BGR233:
554                 bpp = 8;
555                 break;
556         case TBM_FORMAT_XRGB4444:
557         case TBM_FORMAT_XBGR4444:
558         case TBM_FORMAT_RGBX4444:
559         case TBM_FORMAT_BGRX4444:
560         case TBM_FORMAT_ARGB4444:
561         case TBM_FORMAT_ABGR4444:
562         case TBM_FORMAT_RGBA4444:
563         case TBM_FORMAT_BGRA4444:
564         case TBM_FORMAT_XRGB1555:
565         case TBM_FORMAT_XBGR1555:
566         case TBM_FORMAT_RGBX5551:
567         case TBM_FORMAT_BGRX5551:
568         case TBM_FORMAT_ARGB1555:
569         case TBM_FORMAT_ABGR1555:
570         case TBM_FORMAT_RGBA5551:
571         case TBM_FORMAT_BGRA5551:
572         case TBM_FORMAT_RGB565:
573         case TBM_FORMAT_BGR565:
574                 bpp = 16;
575                 break;
576         case TBM_FORMAT_RGB888:
577         case TBM_FORMAT_BGR888:
578                 bpp = 24;
579                 break;
580         case TBM_FORMAT_XRGB8888:
581         case TBM_FORMAT_XBGR8888:
582         case TBM_FORMAT_RGBX8888:
583         case TBM_FORMAT_BGRX8888:
584         case TBM_FORMAT_ARGB8888:
585         case TBM_FORMAT_ABGR8888:
586         case TBM_FORMAT_RGBA8888:
587         case TBM_FORMAT_BGRA8888:
588         case TBM_FORMAT_XRGB2101010:
589         case TBM_FORMAT_XBGR2101010:
590         case TBM_FORMAT_RGBX1010102:
591         case TBM_FORMAT_BGRX1010102:
592         case TBM_FORMAT_ARGB2101010:
593         case TBM_FORMAT_ABGR2101010:
594         case TBM_FORMAT_RGBA1010102:
595         case TBM_FORMAT_BGRA1010102:
596         case TBM_FORMAT_YUYV:
597         case TBM_FORMAT_YVYU:
598         case TBM_FORMAT_UYVY:
599         case TBM_FORMAT_VYUY:
600         case TBM_FORMAT_AYUV:
601                 bpp = 32;
602                 break;
603         case TBM_FORMAT_NV12:
604         case TBM_FORMAT_NV12MT:
605         case TBM_FORMAT_NV21:
606                 bpp = 12;
607                 break;
608         case TBM_FORMAT_NV16:
609         case TBM_FORMAT_NV61:
610                 bpp = 16;
611                 break;
612         case TBM_FORMAT_YUV410:
613         case TBM_FORMAT_YVU410:
614                 bpp = 9;
615                 break;
616         case TBM_FORMAT_YUV411:
617         case TBM_FORMAT_YVU411:
618         case TBM_FORMAT_YUV420:
619         case TBM_FORMAT_YVU420:
620                 bpp = 12;
621                 break;
622         case TBM_FORMAT_YUV422:
623         case TBM_FORMAT_YVU422:
624                 bpp = 16;
625                 break;
626         case TBM_FORMAT_YUV444:
627         case TBM_FORMAT_YVU444:
628                 bpp = 24;
629                 break;
630         default:
631                 break;
632         }
633
634         TBM_TRACE("tbm_format(%s) bpp(%d)\n", _tbm_surface_internal_format_to_str(format), bpp);
635
636         return bpp;
637 }
638
639 tbm_surface_h
640 tbm_surface_internal_create_with_flags(int width, int height,
641                                        int format, int flags)
642 {
643         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
644         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
645
646         struct _tbm_bufmgr *mgr;
647         struct _tbm_surface *surf = NULL;
648         uint32_t size = 0;
649         uint32_t offset = 0;
650         uint32_t stride = 0;
651         uint32_t bo_size = 0;
652         int bo_idx;
653         int i, j;
654         bool bufmgr_initialized = false;
655
656         _tbm_surface_mutex_lock();
657
658         if (!g_surface_bufmgr) {
659                 _init_surface_bufmgr();
660                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
661                 bufmgr_initialized = true;
662         }
663
664         mgr = g_surface_bufmgr;
665         if (!TBM_BUFMGR_IS_VALID(mgr)) {
666                 TBM_LOG_E("The bufmgr is invalid\n");
667                 goto check_valid_fail;
668         }
669
670         surf = calloc(1, sizeof(struct _tbm_surface));
671         if (!surf) {
672                 /* LCOV_EXCL_START */
673                 TBM_LOG_E("fail to alloc surf\n");
674                 goto alloc_surf_fail;
675                 /* LCOV_EXCL_STOP */
676         }
677
678         surf->bufmgr = mgr;
679         surf->info.width = width;
680         surf->info.height = height;
681         surf->info.format = format;
682         surf->info.bpp = tbm_surface_internal_get_bpp(format);
683         surf->info.num_planes = tbm_surface_internal_get_num_planes(format);
684         surf->refcnt = 1;
685
686         /* get size, stride and offset bo_idx */
687         for (i = 0; i < surf->info.num_planes; i++) {
688                 if (!_tbm_surface_internal_query_plane_data(surf, i, &size,
689                                                 &offset, &stride, &bo_idx)) {
690                         TBM_LOG_E("fail to query plane data\n");
691                         goto query_plane_data_fail;
692                 }
693
694                 surf->info.planes[i].size = size;
695                 surf->info.planes[i].offset = offset;
696                 surf->info.planes[i].stride = stride;
697                 surf->planes_bo_idx[i] = bo_idx;
698         }
699
700         surf->num_bos = 1;
701
702         for (i = 0; i < surf->info.num_planes; i++) {
703                 surf->info.size += surf->info.planes[i].size;
704
705                 if (surf->num_bos < surf->planes_bo_idx[i] + 1)
706                         surf->num_bos = surf->planes_bo_idx[i] + 1;
707         }
708
709         surf->flags = flags;
710
711         for (i = 0; i < surf->num_bos; i++) {
712                 bo_size = 0;
713                 for (j = 0; j < surf->info.num_planes; j++) {
714                         if (surf->planes_bo_idx[j] == i)
715                                 bo_size += surf->info.planes[j].size;
716                 }
717
718                 if (mgr->backend->surface_bo_alloc) {
719                         /* LCOV_EXCL_START */
720                         tbm_bo bo = NULL;
721                         void *bo_priv = NULL;
722
723                         bo = calloc(1, sizeof(struct _tbm_bo));
724                         if (!bo) {
725                                 TBM_LOG_E("fail to alloc bo struct\n");
726                                 goto alloc_bo_fail;
727                         }
728
729                         bo->bufmgr = surf->bufmgr;
730
731                         pthread_mutex_lock(&surf->bufmgr->lock);
732
733                         bo_priv = mgr->backend->surface_bo_alloc(bo, width, height, format, flags, i);
734                         if (!bo_priv) {
735                                 TBM_LOG_E("fail to alloc bo priv\n");
736                                 free(bo);
737                                 pthread_mutex_unlock(&surf->bufmgr->lock);
738                                 goto alloc_bo_fail;
739                         }
740
741                         bo->ref_cnt = 1;
742                         bo->flags = flags;
743                         bo->priv = bo_priv;
744
745                         LIST_INITHEAD(&bo->user_data_list);
746
747                         LIST_ADD(&bo->item_link, &surf->bufmgr->bo_list);
748
749                         pthread_mutex_unlock(&surf->bufmgr->lock);
750
751                         surf->bos[i] = bo;
752                         /* LCOV_EXCL_STOP */
753                 } else {
754                         surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
755                         if (!surf->bos[i]) {
756                                 TBM_LOG_E("fail to alloc bo idx:%d\n", i);
757                                 goto alloc_bo_fail;
758                         }
759                 }
760
761                 _tbm_bo_set_surface(surf->bos[i], surf);
762         }
763
764         TBM_TRACE("width(%d) height(%d) format(%s) flags(%d) tbm_surface(%p)\n", width, height,
765                         _tbm_surface_internal_format_to_str(format), flags, surf);
766
767         LIST_INITHEAD(&surf->user_data_list);
768         LIST_INITHEAD(&surf->debug_data_list);
769
770         LIST_ADD(&surf->item_link, &mgr->surf_list);
771
772         _tbm_surface_mutex_unlock();
773
774         return surf;
775
776 /* LCOV_EXCL_START */
777 alloc_bo_fail:
778         for (j = 0; j < i; j++) {
779                 if (surf->bos[j])
780                         tbm_bo_unref(surf->bos[j]);
781         }
782 query_plane_data_fail:
783         free(surf);
784 alloc_surf_fail:
785 check_valid_fail:
786         if (bufmgr_initialized && mgr) {
787                 LIST_DELINIT(&mgr->surf_list);
788                 _deinit_surface_bufmgr();
789         }
790         _tbm_surface_mutex_unlock();
791
792         TBM_LOG_E("error: width(%d) height(%d) format(%s) flags(%d)\n",
793                         width, height,
794                         _tbm_surface_internal_format_to_str(format), flags);
795 /* LCOV_EXCL_STOP */
796
797         return NULL;
798 }
799
800 tbm_surface_h
801 tbm_surface_internal_create_with_bos(tbm_surface_info_s *info,
802                                      tbm_bo *bos, int num)
803 {
804         TBM_RETURN_VAL_IF_FAIL(bos, NULL);
805         TBM_RETURN_VAL_IF_FAIL(info, NULL);
806         TBM_RETURN_VAL_IF_FAIL(info->num_planes > 0, NULL);
807         TBM_RETURN_VAL_IF_FAIL(num > 0, NULL);
808         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
809
810         struct _tbm_bufmgr *mgr;
811         struct _tbm_surface *surf = NULL;
812         int i;
813         bool bufmgr_initialized = false;
814
815         _tbm_surface_mutex_lock();
816
817         if (!g_surface_bufmgr) {
818                 _init_surface_bufmgr();
819                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
820                 bufmgr_initialized = true;
821         }
822
823         mgr = g_surface_bufmgr;
824         if (!TBM_BUFMGR_IS_VALID(mgr)) {
825                 TBM_LOG_E("fail to validate the Bufmgr.\n");
826                 goto check_valid_fail;
827         }
828
829         surf = calloc(1, sizeof(struct _tbm_surface));
830         if (!surf) {
831                 /* LCOV_EXCL_START */
832                 TBM_LOG_E("fail to allocate struct _tbm_surface.\n");
833                 goto alloc_surf_fail;
834                 /* LCOV_EXCL_STOP */
835         }
836
837         surf->bufmgr = mgr;
838         surf->info.width = info->width;
839         surf->info.height = info->height;
840         surf->info.format = info->format;
841         if (info->bpp > 0)
842                 surf->info.bpp = info->bpp;
843         else
844                 surf->info.bpp = tbm_surface_internal_get_bpp(info->format);
845         surf->info.num_planes = info->num_planes;
846         surf->refcnt = 1;
847
848         /* get size, stride and offset */
849         for (i = 0; i < info->num_planes; i++) {
850                 surf->info.planes[i].offset = info->planes[i].offset;
851                 surf->info.planes[i].stride = info->planes[i].stride;
852
853                 if (info->planes[i].size > 0)
854                         surf->info.planes[i].size = info->planes[i].size;
855                 else {
856                         uint32_t size = 0, offset = 0, stride = 0;
857                         int32_t bo_idx = 0;
858
859                         _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride, &bo_idx);
860                         surf->info.planes[i].size = size;
861                 }
862
863                 if (num == 1)
864                         surf->planes_bo_idx[i] = 0;
865                 else
866                         surf->planes_bo_idx[i] = i;
867         }
868
869         if (info->size > 0) {
870                 surf->info.size = info->size;
871         } else {
872                 surf->info.size = 0;
873                 for (i = 0; i < info->num_planes; i++)
874                         surf->info.size += surf->info.planes[i].size;
875         }
876
877         surf->flags = TBM_BO_DEFAULT;
878
879         /* create only one bo */
880         surf->num_bos = num;
881         for (i = 0; i < num; i++) {
882                 if (bos[i] == NULL) {
883                         TBM_LOG_E("bos[%d] is null.\n", i);
884                         goto check_bo_fail;
885                 }
886
887                 surf->bos[i] = tbm_bo_ref(bos[i]);
888                 _tbm_bo_set_surface(bos[i], surf);
889         }
890
891         TBM_TRACE("tbm_surface(%p) width(%u) height(%u) format(%s) bo_num(%d)\n", surf,
892                         info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
893
894         LIST_INITHEAD(&surf->user_data_list);
895         LIST_INITHEAD(&surf->debug_data_list);
896
897         LIST_ADD(&surf->item_link, &mgr->surf_list);
898
899         _tbm_surface_mutex_unlock();
900
901         return surf;
902
903 /* LCOV_EXCL_START */
904 check_bo_fail:
905         for (i = 0; i < num; i++) {
906                 if (surf->bos[i])
907                         tbm_bo_unref(surf->bos[i]);
908         }
909         free(surf);
910 alloc_surf_fail:
911 check_valid_fail:
912         if (bufmgr_initialized && mgr) {
913                 LIST_DELINIT(&mgr->surf_list);
914                 _deinit_surface_bufmgr();
915         }
916         _tbm_surface_mutex_unlock();
917
918         TBM_LOG_E("error: width(%u) height(%u) format(%s) bo_num(%d)\n",
919                         info->width, info->height,
920                         _tbm_surface_internal_format_to_str(info->format), num);
921 /* LCOV_EXCL_STOP */
922
923         return NULL;
924 }
925
926 void
927 tbm_surface_internal_destroy(tbm_surface_h surface)
928 {
929         _tbm_surface_mutex_lock();
930
931         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
932
933         surface->refcnt--;
934
935         if (surface->refcnt > 0) {
936                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
937                 _tbm_surface_mutex_unlock();
938                 return;
939         }
940
941         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
942
943         if (surface->refcnt == 0)
944                 _tbm_surface_internal_destroy(surface);
945
946         _tbm_surface_mutex_unlock();
947 }
948
949 void
950 tbm_surface_internal_ref(tbm_surface_h surface)
951 {
952         _tbm_surface_mutex_lock();
953
954         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
955
956         surface->refcnt++;
957
958         TBM_TRACE("tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
959
960         _tbm_surface_mutex_unlock();
961 }
962
963 void
964 tbm_surface_internal_unref(tbm_surface_h surface)
965 {
966         _tbm_surface_mutex_lock();
967
968         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
969
970         surface->refcnt--;
971
972         if (surface->refcnt > 0) {
973                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
974                 _tbm_surface_mutex_unlock();
975                 return;
976         }
977
978         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
979
980         if (surface->refcnt == 0)
981                 _tbm_surface_internal_destroy(surface);
982
983         _tbm_surface_mutex_unlock();
984 }
985
986 int
987 tbm_surface_internal_get_num_bos(tbm_surface_h surface)
988 {
989         struct _tbm_surface *surf;
990         int num;
991
992         _tbm_surface_mutex_lock();
993
994         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
995
996         surf = (struct _tbm_surface *)surface;
997         num = surf->num_bos;
998
999         TBM_TRACE("tbm_surface(%p) num_bos(%d)\n", surface, num);
1000
1001         _tbm_surface_mutex_unlock();
1002
1003         return num;
1004 }
1005
1006 tbm_bo
1007 tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
1008 {
1009         struct _tbm_surface *surf;
1010         tbm_bo bo;
1011
1012         _tbm_surface_mutex_lock();
1013
1014         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
1015         TBM_SURFACE_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
1016
1017         surf = (struct _tbm_surface *)surface;
1018         bo = surf->bos[bo_idx];
1019
1020         TBM_TRACE("tbm_surface(%p) bo_idx(%d) tbm_bo(%p)\n", surface, bo_idx, bo);
1021
1022         _tbm_surface_mutex_unlock();
1023
1024         return bo;
1025 }
1026
1027 unsigned int
1028 tbm_surface_internal_get_size(tbm_surface_h surface)
1029 {
1030         struct _tbm_surface *surf;
1031         unsigned int size;
1032
1033         _tbm_surface_mutex_lock();
1034
1035         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1036
1037         surf = (struct _tbm_surface *)surface;
1038         size = surf->info.size;
1039
1040         TBM_TRACE("tbm_surface(%p) size(%u)\n", surface, size);
1041
1042         _tbm_surface_mutex_unlock();
1043
1044         return size;
1045 }
1046
1047 int
1048 tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx,
1049                                     uint32_t *size, uint32_t *offset, uint32_t *pitch)
1050 {
1051         struct _tbm_surface *surf;
1052
1053         _tbm_surface_mutex_lock();
1054
1055         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1056         TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1057
1058         surf = (struct _tbm_surface *)surface;
1059
1060         if (plane_idx >= surf->info.num_planes) {
1061                 TBM_TRACE("error: tbm_surface(%p) plane_idx(%d)\n", surface, plane_idx);
1062                 _tbm_surface_mutex_unlock();
1063                 return 0;
1064         }
1065
1066         if (size)
1067                 *size = surf->info.planes[plane_idx].size;
1068
1069         if (offset)
1070                 *offset = surf->info.planes[plane_idx].offset;
1071
1072         if (pitch)
1073                 *pitch = surf->info.planes[plane_idx].stride;
1074
1075         TBM_TRACE("tbm_surface(%p) plane_idx(%d) size(%u) offset(%u) pitch(%u)\n", surface, plane_idx,
1076                                 surf->info.planes[plane_idx].size, surf->info.planes[plane_idx].offset,
1077                                 surf->info.planes[plane_idx].stride);
1078
1079         _tbm_surface_mutex_unlock();
1080
1081         return 1;
1082 }
1083
1084 int
1085 tbm_surface_internal_get_info(tbm_surface_h surface, int opt,
1086                               tbm_surface_info_s *info, int map)
1087 {
1088         struct _tbm_surface *surf;
1089         tbm_bo_handle bo_handles[4];
1090         int num_bos = 0;
1091         tbm_bo bos[4];
1092         int planes_bo_idx[TBM_SURF_PLANE_MAX];
1093         int i, j;
1094
1095         _tbm_surface_mutex_lock();
1096
1097         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1098
1099         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
1100
1101         surf = (struct _tbm_surface *)surface;
1102
1103         memset(info, 0x00, sizeof(tbm_surface_info_s));
1104         info->width = surf->info.width;
1105         info->height = surf->info.height;
1106         info->format = surf->info.format;
1107         info->bpp = surf->info.bpp;
1108         info->size = surf->info.size;
1109         info->num_planes = surf->info.num_planes;
1110
1111         for (i = 0; i < surf->info.num_planes; i++) {
1112                 info->planes[i].size = surf->info.planes[i].size;
1113                 info->planes[i].offset = surf->info.planes[i].offset;
1114                 info->planes[i].stride = surf->info.planes[i].stride;
1115                 planes_bo_idx[i] = surf->planes_bo_idx[i];
1116         }
1117
1118         for (i = 0; i < surf->num_bos; i++)
1119                 bos[i] = surf->bos[i];
1120
1121         num_bos = surf->num_bos;
1122
1123         if (map == 1) {
1124                 _tbm_surface_mutex_unlock();
1125                 for (i = 0; i < num_bos; i++) {
1126                         bo_handles[i] = tbm_bo_map(bos[i], TBM_DEVICE_CPU, opt);
1127                         if (bo_handles[i].ptr == NULL) {
1128                                 for (j = 0; j < i; j++)
1129                                         tbm_bo_unmap(bos[j]);
1130
1131                                 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1132                                 return 0;
1133                         }
1134                 }
1135                 _tbm_surface_mutex_lock();
1136         } else {
1137                 for (i = 0; i < num_bos; i++) {
1138                         bo_handles[i] = tbm_bo_get_handle(bos[i], TBM_DEVICE_CPU);
1139                         if (bo_handles[i].ptr == NULL) {
1140                                 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1141                                 _tbm_surface_mutex_unlock();
1142                                 return 0;
1143                         }
1144                 }
1145         }
1146
1147         for (i = 0; i < info->num_planes; i++) {
1148                 if (bo_handles[planes_bo_idx[i]].ptr)
1149                         info->planes[i].ptr = bo_handles[planes_bo_idx[i]].ptr + info->planes[i].offset;
1150         }
1151
1152         TBM_TRACE("tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1153
1154         _tbm_surface_mutex_unlock();
1155
1156         return 1;
1157 }
1158
1159 void
1160 tbm_surface_internal_unmap(tbm_surface_h surface)
1161 {
1162         struct _tbm_surface *surf;
1163         int i;
1164
1165         _tbm_surface_mutex_lock();
1166
1167         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1168
1169         surf = (struct _tbm_surface *)surface;
1170
1171         for (i = 0; i < surf->num_bos; i++)
1172                 tbm_bo_unmap(surf->bos[i]);
1173
1174         TBM_TRACE("tbm_surface(%p)\n", surface);
1175
1176         _tbm_surface_mutex_unlock();
1177 }
1178
1179 unsigned int
1180 tbm_surface_internal_get_width(tbm_surface_h surface)
1181 {
1182         struct _tbm_surface *surf;
1183         unsigned int width;
1184
1185         _tbm_surface_mutex_lock();
1186
1187         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1188
1189         surf = (struct _tbm_surface *)surface;
1190         width = surf->info.width;
1191
1192         TBM_TRACE("tbm_surface(%p) width(%u)\n", surface, width);
1193
1194         _tbm_surface_mutex_unlock();
1195
1196         return width;
1197 }
1198
1199 unsigned int
1200 tbm_surface_internal_get_height(tbm_surface_h surface)
1201 {
1202         struct _tbm_surface *surf;
1203         unsigned int height;
1204
1205         _tbm_surface_mutex_lock();
1206
1207         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1208
1209         surf = (struct _tbm_surface *)surface;
1210         height = surf->info.height;
1211
1212         TBM_TRACE("tbm_surface(%p) height(%u)\n", surface, height);
1213
1214         _tbm_surface_mutex_unlock();
1215
1216         return height;
1217
1218 }
1219
1220 tbm_format
1221 tbm_surface_internal_get_format(tbm_surface_h surface)
1222 {
1223         struct _tbm_surface *surf;
1224         tbm_format format;
1225
1226         _tbm_surface_mutex_lock();
1227
1228         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1229
1230         surf = (struct _tbm_surface *)surface;
1231         format = surf->info.format;
1232
1233         TBM_TRACE("tbm_surface(%p) format(%s)\n", surface, _tbm_surface_internal_format_to_str(format));
1234
1235         _tbm_surface_mutex_unlock();
1236
1237         return format;
1238 }
1239
1240 int
1241 tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
1242 {
1243         struct _tbm_surface *surf;
1244         int bo_idx;
1245
1246         _tbm_surface_mutex_lock();
1247
1248         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1249         TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1250
1251         surf = (struct _tbm_surface *)surface;
1252         bo_idx = surf->planes_bo_idx[plane_idx];
1253
1254         TBM_TRACE("tbm_surface(%p) plane_idx(%d) bo_idx(%d)\n", surface, plane_idx, bo_idx);
1255
1256         _tbm_surface_mutex_unlock();
1257
1258         return bo_idx;
1259 }
1260
1261 int
1262 tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key,
1263                                    tbm_data_free data_free_func)
1264 {
1265         tbm_user_data *data;
1266
1267         _tbm_surface_mutex_lock();
1268
1269         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1270
1271         /* check if the data according to the key exist if so, return false. */
1272         data = user_data_lookup(&surface->user_data_list, key);
1273         if (data) {
1274                 TBM_TRACE("warning: user data already exist tbm_surface(%p) key(%lu)\n", surface, key);
1275                 _tbm_surface_mutex_unlock();
1276                 return 0;
1277         }
1278
1279         data = user_data_create(key, data_free_func);
1280         if (!data) {
1281                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1282                 _tbm_surface_mutex_unlock();
1283                 return 0;
1284         }
1285
1286         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, data);
1287
1288         LIST_ADD(&data->item_link, &surface->user_data_list);
1289
1290         _tbm_surface_mutex_unlock();
1291
1292         return 1;
1293 }
1294
1295 int
1296 tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key,
1297                                    void *data)
1298 {
1299         tbm_user_data *old_data;
1300
1301         _tbm_surface_mutex_lock();
1302
1303         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1304
1305         old_data = user_data_lookup(&surface->user_data_list, key);
1306         if (!old_data) {
1307                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1308                 _tbm_surface_mutex_unlock();
1309                 return 0;
1310         }
1311
1312         if (old_data->data && old_data->free_func)
1313                 old_data->free_func(old_data->data);
1314
1315         old_data->data = data;
1316
1317         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1318
1319         _tbm_surface_mutex_unlock();
1320
1321         return 1;
1322 }
1323
1324 int
1325 tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key,
1326                                    void **data)
1327 {
1328         tbm_user_data *old_data;
1329
1330         _tbm_surface_mutex_lock();
1331
1332         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1333
1334         if (!data) {
1335                 TBM_LOG_E("error: tbm_surface(%p) key(%lu)\n", surface, key);
1336                 _tbm_surface_mutex_unlock();
1337                 return 0;
1338         }
1339         *data = NULL;
1340
1341         old_data = user_data_lookup(&surface->user_data_list, key);
1342         if (!old_data) {
1343                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1344                 _tbm_surface_mutex_unlock();
1345                 return 0;
1346         }
1347
1348         *data = old_data->data;
1349
1350         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1351
1352         _tbm_surface_mutex_unlock();
1353
1354         return 1;
1355 }
1356
1357 int
1358 tbm_surface_internal_delete_user_data(tbm_surface_h surface,
1359                                       unsigned long key)
1360 {
1361         tbm_user_data *old_data = (void *)0;
1362
1363         _tbm_surface_mutex_lock();
1364
1365         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1366
1367         old_data = user_data_lookup(&surface->user_data_list, key);
1368         if (!old_data) {
1369                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1370                 _tbm_surface_mutex_unlock();
1371                 return 0;
1372         }
1373
1374         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1375
1376         user_data_delete(old_data);
1377
1378         _tbm_surface_mutex_unlock();
1379
1380         return 1;
1381 }
1382
1383 /* LCOV_EXCL_START */
1384 unsigned int
1385 _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
1386 {
1387         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1388
1389         return surface->debug_pid;
1390 }
1391
1392 void
1393 tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
1394 {
1395         _tbm_surface_mutex_lock();
1396
1397         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1398
1399         surface->debug_pid = pid;
1400
1401         _tbm_surface_mutex_unlock();
1402 }
1403
1404 static tbm_surface_debug_data *
1405 _tbm_surface_internal_debug_data_create(char *key, char *value)
1406 {
1407         tbm_surface_debug_data *debug_data = NULL;
1408
1409         debug_data = calloc(1, sizeof(tbm_surface_debug_data));
1410         if (!debug_data)
1411                 return NULL;
1412
1413         if (key) debug_data->key = strdup(key);
1414         if (value) debug_data->value = strdup(value);
1415
1416         return debug_data;
1417 }
1418
1419 int
1420 tbm_surface_internal_set_debug_data(tbm_surface_h surface, char *key, char *value)
1421 {
1422         tbm_surface_debug_data *debug_data = NULL;
1423         tbm_surface_debug_data *old_data = NULL, *tmp = NULL;
1424         tbm_bufmgr bufmgr = NULL;
1425
1426         _tbm_surface_mutex_lock();
1427
1428         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1429         TBM_SURFACE_RETURN_VAL_IF_FAIL(key, 0);
1430
1431         bufmgr = surface->bufmgr;
1432
1433         TBM_SURFACE_RETURN_VAL_IF_FAIL(bufmgr, 0);
1434
1435         if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1436                 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1437                         if (old_data) {
1438                                 if (!strcmp(old_data->key, key)) {
1439                                         if (old_data->value && value && !strncmp(old_data->value, value, strlen(old_data->value))) {
1440                                                 TBM_TRACE("tbm_surface(%p) Already exist key(%s) and value(%s)!\n", surface, key, value);
1441                                                 goto add_debug_key_list;
1442                                         }
1443
1444                                         if (old_data->value)
1445                                                 free(old_data->value);
1446
1447                                         if (value)
1448                                                 old_data->value = strdup(value);
1449                                         else
1450                                                 old_data->value = NULL;
1451
1452                                         goto add_debug_key_list;
1453                                 }
1454                         }
1455                 }
1456         }
1457
1458         debug_data = _tbm_surface_internal_debug_data_create(key, value);
1459         if (!debug_data) {
1460                 TBM_LOG_E("error: tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1461                 _tbm_surface_mutex_unlock();
1462                 return 0;
1463         }
1464
1465         TBM_TRACE("tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1466
1467         LIST_ADD(&debug_data->item_link, &surface->debug_data_list);
1468
1469 add_debug_key_list:
1470         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1471                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bufmgr->debug_key_list, item_link) {
1472                         if (!strcmp(old_data->key, key)) {
1473                                 _tbm_surface_mutex_unlock();
1474                                 return 1;
1475                         }
1476                 }
1477         }
1478
1479         debug_data = _tbm_surface_internal_debug_data_create(key, NULL);
1480         LIST_ADD(&debug_data->item_link, &bufmgr->debug_key_list);
1481
1482         _tbm_surface_mutex_unlock();
1483
1484         return 1;
1485 }
1486
1487 char *
1488 _tbm_surface_internal_get_debug_data(tbm_surface_h surface, char *key)
1489 {
1490         tbm_surface_debug_data *old_data = NULL;
1491
1492         TBM_SURFACE_RETURN_VAL_IF_FAIL(surface, NULL);
1493
1494         if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1495                 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1496                         if (!strcmp(old_data->key, key))
1497                                 return old_data->value;
1498                 }
1499         }
1500
1501         return NULL;
1502 }
1503
1504 typedef struct _tbm_surface_dump_info tbm_surface_dump_info;
1505 typedef struct _tbm_surface_dump_buf_info tbm_surface_dump_buf_info;
1506
1507 struct _tbm_surface_dump_buf_info {
1508         int index;
1509         tbm_bo bo;
1510         int size;
1511         int dirty;
1512         int dirty_shm;
1513         int shm_stride;
1514         int shm_h;
1515         char name[1024];
1516
1517         tbm_surface_info_s info;
1518
1519         struct list_head link;
1520 };
1521
1522 struct _tbm_surface_dump_info {
1523         char *path;  // copy???
1524         int dump_max;
1525         int count;
1526         struct list_head *link;
1527         struct list_head surface_list; /* link of surface */
1528 };
1529
1530 static tbm_surface_dump_info *g_dump_info = NULL;
1531 static const char *dump_postfix[2] = {"png", "yuv"};
1532 static double scale_factor;
1533
1534 static void
1535 _tbm_surface_internal_dump_file_raw(const char *file, void *data1, int size1,
1536                                 void *data2, int size2, void *data3, int size3)
1537 {
1538         FILE *fp;
1539         unsigned int *blocks;
1540
1541         if (_tbm_surface_check_file_is_symbolic_link(file))
1542                 TBM_LOG_E("%s is symbolic link\n", file);
1543
1544         fp = fopen(file, "w+");
1545         TBM_RETURN_IF_FAIL(fp != NULL);
1546
1547         blocks = (unsigned int *)data1;
1548         fwrite(blocks, 1, size1, fp);
1549
1550         if (size2 > 0) {
1551                 blocks = (unsigned int *)data2;
1552                 fwrite(blocks, 1, size2, fp);
1553         }
1554
1555         if (size3 > 0) {
1556                 blocks = (unsigned int *)data3;
1557                 fwrite(blocks, 1, size3, fp);
1558         }
1559
1560         fclose(fp);
1561 }
1562
1563 static void
1564 _tbm_surface_internal_dump_file_png(const char *file, const void *data, int width, int height, int format)
1565 {
1566         unsigned int *blocks = (unsigned int *)data;
1567         FILE *fp;
1568         int pixel_size;
1569         png_bytep *row_pointers;
1570         int depth = 8, y;
1571
1572         if (_tbm_surface_check_file_is_symbolic_link(file))
1573                 TBM_LOG_E("%s is symbolic link\n", file);
1574
1575         fp = fopen(file, "wb");
1576         TBM_RETURN_IF_FAIL(fp != NULL);
1577
1578         png_structp pPngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1579                                                         NULL, NULL, NULL);
1580         if (!pPngStruct) {
1581                 TBM_LOG_E("fail to create a png write structure.\n");
1582                 fclose(fp);
1583                 return;
1584         }
1585
1586         png_infop pPngInfo = png_create_info_struct(pPngStruct);
1587         if (!pPngInfo) {
1588                 TBM_LOG_E("fail to create a png info structure.\n");
1589                 png_destroy_write_struct(&pPngStruct, NULL);
1590                 fclose(fp);
1591                 return;
1592         }
1593
1594         png_init_io(pPngStruct, fp);
1595         if (format == TBM_FORMAT_XRGB8888) {
1596                 pixel_size = 3;
1597                 png_set_IHDR(pPngStruct,
1598                                 pPngInfo,
1599                                 width,
1600                                 height,
1601                                 depth,
1602                                 PNG_COLOR_TYPE_RGB,
1603                                 PNG_INTERLACE_NONE,
1604                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1605         } else {
1606                 pixel_size = 4;
1607                 png_set_IHDR(pPngStruct,
1608                                 pPngInfo,
1609                                 width,
1610                                 height,
1611                                 depth,
1612                                 PNG_COLOR_TYPE_RGBA,
1613                                 PNG_INTERLACE_NONE,
1614                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1615         }
1616
1617         png_set_bgr(pPngStruct);
1618         png_write_info(pPngStruct, pPngInfo);
1619
1620         row_pointers = png_malloc(pPngStruct, height * sizeof(png_byte *));
1621         if (!row_pointers) {
1622                 TBM_LOG_E("fail to allocate the png row_pointers.\n");
1623                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
1624                 fclose(fp);
1625                 return;
1626         }
1627
1628         for (y = 0; y < height; ++y) {
1629                 png_bytep row;
1630                 int x = 0;
1631
1632                 row = png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
1633                 if (!row) {
1634                         TBM_LOG_E("fail to allocate the png row.\n");
1635                         for (x = 0; x < y; x++)
1636                                 png_free(pPngStruct, row_pointers[x]);
1637                         png_free(pPngStruct, row_pointers);
1638                         png_destroy_write_struct(&pPngStruct, &pPngInfo);
1639                         fclose(fp);
1640                         return;
1641                 }
1642                 row_pointers[y] = (png_bytep)row;
1643
1644                 for (x = 0; x < width; ++x) {
1645                         unsigned int curBlock = blocks[y * width + x];
1646
1647                         if (pixel_size == 3) { // XRGB8888
1648                                 row[x * pixel_size] = (curBlock & 0xFF);
1649                                 row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1650                                 row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1651                         } else { // ARGB8888
1652                                 row[x * pixel_size] = (curBlock & 0xFF);
1653                                 row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1654                                 row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1655                                 row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
1656                         }
1657                 }
1658         }
1659
1660         png_write_image(pPngStruct, row_pointers);
1661         png_write_end(pPngStruct, pPngInfo);
1662
1663         for (y = 0; y < height; y++)
1664                 png_free(pPngStruct, row_pointers[y]);
1665         png_free(pPngStruct, row_pointers);
1666
1667         png_destroy_write_struct(&pPngStruct, &pPngInfo);
1668
1669         fclose(fp);
1670 }
1671
1672 void
1673 tbm_surface_internal_dump_start(char *path, int w, int h, int count)
1674 {
1675         TBM_RETURN_IF_FAIL(path != NULL);
1676         TBM_RETURN_IF_FAIL(w > 0);
1677         TBM_RETURN_IF_FAIL(h > 0);
1678         TBM_RETURN_IF_FAIL(count > 0);
1679
1680         tbm_surface_dump_buf_info *buf_info = NULL;
1681         tbm_surface_h tbm_surface;
1682         tbm_surface_info_s info;
1683         int buffer_size, i;
1684
1685         /* check running */
1686         if (g_dump_info) {
1687                 TBM_LOG_W("waring already running the tbm_surface_internal_dump.\n");
1688                 return;
1689         }
1690
1691         g_dump_info = calloc(1, sizeof(struct _tbm_surface_dump_info));
1692         TBM_RETURN_IF_FAIL(g_dump_info);
1693
1694         LIST_INITHEAD(&g_dump_info->surface_list);
1695         g_dump_info->count = 0;
1696         g_dump_info->dump_max = count;
1697
1698         /* get buffer size */
1699         tbm_surface = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
1700         if (tbm_surface == NULL) {
1701                 TBM_LOG_E("tbm_surface_create fail\n");
1702                 free(g_dump_info);
1703                 g_dump_info = NULL;
1704                 return;
1705         }
1706
1707         if (TBM_SURFACE_ERROR_NONE != tbm_surface_get_info(tbm_surface, &info)) {
1708                 TBM_LOG_E("tbm_surface_get_info fail\n");
1709                 tbm_surface_destroy(tbm_surface);
1710                 free(g_dump_info);
1711                 g_dump_info = NULL;
1712                 return;
1713         }
1714         buffer_size = info.size;
1715         tbm_surface_destroy(tbm_surface);
1716
1717         /* create dump lists */
1718         for (i = 0; i < count; i++) {
1719                 tbm_bo bo = NULL;
1720
1721                 buf_info = calloc(1, sizeof(tbm_surface_dump_buf_info));
1722                 TBM_GOTO_VAL_IF_FAIL(buf_info, fail);
1723
1724                 bo = tbm_bo_alloc(g_surface_bufmgr, buffer_size, TBM_BO_DEFAULT);
1725                 if (bo == NULL) {
1726                         TBM_LOG_E("fail to allocate the tbm_bo[%d]\n", i);
1727                         free(buf_info);
1728                         goto fail;
1729                 }
1730
1731                 buf_info->index = i;
1732                 buf_info->bo = bo;
1733                 buf_info->size = buffer_size;
1734
1735                 LIST_ADDTAIL(&buf_info->link, &g_dump_info->surface_list);
1736         }
1737
1738         g_dump_info->path = path;
1739         g_dump_info->link = &g_dump_info->surface_list;
1740
1741         scale_factor = 0.0;
1742
1743         TBM_LOG_I("Dump Start.. path:%s, count:%d\n", g_dump_info->path, count);
1744
1745         return;
1746
1747 fail:
1748         /* free resources */
1749         if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1750                 tbm_surface_dump_buf_info *tmp;
1751
1752                 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1753                         tbm_bo_unref(buf_info->bo);
1754                         LIST_DEL(&buf_info->link);
1755                         free(buf_info);
1756                 }
1757         }
1758
1759         TBM_LOG_E("Dump Start fail.. path:%s\n", g_dump_info->path);
1760
1761         free(g_dump_info);
1762         g_dump_info = NULL;
1763
1764         return;
1765 }
1766
1767 void
1768 tbm_surface_internal_dump_with_scale_start(char *path, int w, int h, int count, double scale)
1769 {
1770         if (scale > 0.0) {
1771                 w *= scale;
1772                 h *= scale;
1773         }
1774
1775         tbm_surface_internal_dump_start(path, w, h, count);
1776         scale_factor = scale;
1777 }
1778
1779 void
1780 tbm_surface_internal_dump_end(void)
1781 {
1782         tbm_surface_dump_buf_info *buf_info = NULL, *tmp = NULL;
1783         tbm_bo_handle bo_handle;
1784
1785         if (!g_dump_info)
1786                 return;
1787
1788         if (LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1789                 free(g_dump_info);
1790                 g_dump_info = NULL;
1791                 return;
1792         }
1793
1794         /* make files */
1795         LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1796                 char file[2048];
1797
1798                 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
1799                 if (bo_handle.ptr == NULL) {
1800                         tbm_bo_unref(buf_info->bo);
1801                         LIST_DEL(&buf_info->link);
1802                         free(buf_info);
1803                         continue;
1804                 }
1805
1806                 snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name);
1807                 TBM_LOG_I("Dump File.. %s generated.\n", file);
1808
1809                 if (buf_info->dirty) {
1810                         void *ptr1 = NULL, *ptr2 = NULL;
1811
1812                         switch (buf_info->info.format) {
1813                         case TBM_FORMAT_ARGB8888:
1814                                 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1815                                                         buf_info->info.planes[0].stride >> 2,
1816                                                         buf_info->info.height, TBM_FORMAT_ARGB8888);
1817                                 break;
1818                         case TBM_FORMAT_XRGB8888:
1819                                 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1820                                                         buf_info->info.planes[0].stride >> 2,
1821                                                         buf_info->info.height, TBM_FORMAT_XRGB8888);
1822                                 break;
1823                         case TBM_FORMAT_YVU420:
1824                         case TBM_FORMAT_YUV420:
1825                                 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1826                                 ptr2 = ptr1 + buf_info->info.planes[1].stride * (buf_info->info.height >> 1);
1827                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1828                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1829                                                         ptr1,
1830                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1831                                                         ptr2,
1832                                                         buf_info->info.planes[2].stride * (buf_info->info.height >> 1));
1833                                 break;
1834                         case TBM_FORMAT_NV12:
1835                         case TBM_FORMAT_NV21:
1836                                 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1837                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1838                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1839                                                         ptr1,
1840                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1841                                                         NULL, 0);
1842                                 break;
1843                         case TBM_FORMAT_YUYV:
1844                         case TBM_FORMAT_UYVY:
1845                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1846                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1847                                                         NULL, 0, NULL, 0);
1848                                 break;
1849                         default:
1850                                 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(buf_info->info.format));
1851                                 break;
1852                         }
1853                 } else if (buf_info->dirty_shm)
1854                         _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1855                                                         buf_info->shm_stride >> 2,
1856                                                         buf_info->shm_h, 0);
1857
1858                 tbm_bo_unmap(buf_info->bo);
1859                 tbm_bo_unref(buf_info->bo);
1860                 LIST_DEL(&buf_info->link);
1861                 free(buf_info);
1862         }
1863
1864         free(g_dump_info);
1865         g_dump_info = NULL;
1866
1867         TBM_LOG_I("Dump End..\n");
1868 }
1869
1870 static pixman_format_code_t
1871 _tbm_surface_internal_pixman_format_get(tbm_format format)
1872 {
1873         switch (format) {
1874         case TBM_FORMAT_ARGB8888:
1875                 return PIXMAN_a8r8g8b8;
1876         case TBM_FORMAT_XRGB8888:
1877                 return PIXMAN_x8r8g8b8;
1878         default:
1879                 return 0;
1880         }
1881
1882         return 0;
1883 }
1884
1885 /**
1886  * This function supports only if a buffer has below formats.
1887  * - TBM_FORMAT_ARGB8888
1888  * - TBM_FORMAT_XRGB8888
1889  */
1890 static tbm_surface_error_e
1891 _tbm_surface_internal_buffer_scale(void *src_ptr, void *dst_ptr,
1892                                                                    int format, int src_stride, int src_w, int src_h,
1893                                                                    int dst_stride, int dst_w, int dst_h)
1894 {
1895         pixman_image_t *src_img = NULL, *dst_img = NULL;
1896         pixman_format_code_t pixman_format;
1897         pixman_transform_t t;
1898         struct pixman_f_transform ft;
1899         double scale_x, scale_y;
1900
1901         TBM_RETURN_VAL_IF_FAIL(src_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1902         TBM_RETURN_VAL_IF_FAIL(dst_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1903
1904         pixman_format = _tbm_surface_internal_pixman_format_get(format);
1905         TBM_RETURN_VAL_IF_FAIL(pixman_format > 0, TBM_SURFACE_ERROR_INVALID_OPERATION);
1906
1907         /* src */
1908         src_img = pixman_image_create_bits(pixman_format, src_w, src_h,
1909                                                                            (uint32_t*)src_ptr, src_stride);
1910         TBM_GOTO_VAL_IF_FAIL(src_img != NULL, cant_convert);
1911
1912         /* dst */
1913         dst_img = pixman_image_create_bits(pixman_format, dst_w, dst_h,
1914                                                                            (uint32_t*)dst_ptr, dst_stride);
1915         TBM_GOTO_VAL_IF_FAIL(dst_img != NULL, cant_convert);
1916
1917         pixman_f_transform_init_identity(&ft);
1918
1919         scale_x = (double)src_w / dst_w;
1920         scale_y = (double)src_h / dst_h;
1921
1922         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
1923         pixman_f_transform_translate(&ft, NULL, 0, 0);
1924         pixman_transform_from_pixman_f_transform(&t, &ft);
1925         pixman_image_set_transform(src_img, &t);
1926
1927         pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img,
1928                                                    0, 0, 0, 0, 0, 0, dst_w, dst_h);
1929
1930         pixman_image_unref(src_img);
1931         pixman_image_unref(dst_img);
1932
1933         return TBM_SURFACE_ERROR_NONE;
1934
1935 cant_convert:
1936         if (src_img)
1937                 pixman_image_unref(src_img);
1938
1939         return TBM_SURFACE_ERROR_INVALID_OPERATION;
1940 }
1941
1942 #define MAX_BOS         4       // This value is came from bos[4] in struct _tbm_surface
1943 #define KEY_LEN         5       // "_XXXX"
1944 #define KEYS_LEN        KEY_LEN * MAX_BOS
1945
1946 static char *_tbm_surface_internal_get_keys(tbm_surface_h surface)
1947 {
1948         char *keys, temp_key[KEY_LEN + 1];
1949         struct _tbm_surface *surf;
1950         int i, num_bos;
1951         tbm_bo bo;
1952
1953         _tbm_surface_mutex_lock();
1954
1955         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
1956
1957         surf = (struct _tbm_surface *)surface;
1958
1959         num_bos = surf->num_bos;
1960         if (num_bos > MAX_BOS)
1961                 num_bos = MAX_BOS;
1962
1963         keys = calloc(KEYS_LEN + 1, sizeof(char));
1964         if (!keys) {
1965                 TBM_LOG_E("Failed to alloc memory");
1966                 _tbm_surface_mutex_unlock();
1967                 return NULL;
1968         }
1969
1970         for (i = 0; i < num_bos; i++) {
1971                 memset(temp_key, 0x00, KEY_LEN + 1);
1972                 bo = surf->bos[i];
1973                 snprintf(temp_key, KEY_LEN, "_%d", tbm_bo_export(bo));
1974                 strncat(keys, temp_key, KEY_LEN);
1975         }
1976
1977         _tbm_surface_mutex_unlock();
1978
1979         return keys;
1980 }
1981
1982 static void _tbm_surface_internal_put_keys(char *keys)
1983 {
1984         if (keys)
1985                 free(keys);
1986 }
1987
1988 void
1989 tbm_surface_internal_dump_buffer(tbm_surface_h surface, const char *type)
1990 {
1991         TBM_RETURN_IF_FAIL(surface != NULL);
1992         TBM_RETURN_IF_FAIL(type != NULL);
1993
1994         tbm_surface_dump_buf_info *buf_info;
1995         struct list_head *next_link;
1996         tbm_surface_info_s info;
1997         tbm_bo_handle bo_handle;
1998         const char *postfix;
1999         const char *format = NULL;
2000         char *keys;
2001         int ret;
2002
2003         if (!g_dump_info)
2004                 return;
2005
2006         next_link = g_dump_info->link->next;
2007         TBM_RETURN_IF_FAIL(next_link != NULL);
2008
2009         if (next_link == &g_dump_info->surface_list) {
2010                 next_link = next_link->next;
2011                 TBM_RETURN_IF_FAIL(next_link != NULL);
2012         }
2013
2014         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
2015         TBM_RETURN_IF_FAIL(buf_info != NULL);
2016
2017         ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
2018         TBM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
2019
2020         if (scale_factor > 0.0) {
2021                 const int bpp = 4;
2022
2023                 if (info.format != TBM_FORMAT_ARGB8888 && info.format != TBM_FORMAT_XRGB8888) {
2024                         TBM_LOG_W("Dump with scale skip. unsupported format(%s)\n",
2025                                           _tbm_surface_internal_format_to_str(info.format));
2026                         tbm_surface_unmap(surface);
2027                         return;
2028                 }
2029
2030                 memset(&buf_info->info, 0, sizeof(tbm_surface_info_s));
2031
2032                 buf_info->info.width = info.width * scale_factor;
2033                 buf_info->info.height = info.height * scale_factor;
2034                 buf_info->info.format = info.format;
2035                 buf_info->info.bpp = tbm_surface_internal_get_bpp(buf_info->info.format);
2036                 buf_info->info.num_planes = 1;
2037                 buf_info->info.planes[0].stride = buf_info->info.width * bpp;
2038                 buf_info->info.size = buf_info->info.width * buf_info->info.height * bpp;
2039
2040                 if (buf_info->info.size > buf_info->size) {
2041                         TBM_LOG_W("Dump with scale skip. surface over created buffer size(%u, %d)\n",
2042                                         buf_info->info.size, buf_info->size);
2043                         tbm_surface_unmap(surface);
2044                         return;
2045                 }
2046         } else {
2047                 if (info.size > buf_info->size) {
2048                         TBM_LOG_W("Dump skip. surface over created buffer size(%u, %d)\n",
2049                                         info.size, buf_info->size);
2050                         tbm_surface_unmap(surface);
2051                         return;
2052                 }
2053
2054                 /* make the file information */
2055                 memcpy(&buf_info->info, &info, sizeof(tbm_surface_info_s));
2056         }
2057
2058         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) {
2059                 postfix = dump_postfix[0];
2060                 format = _tbm_surface_internal_format_to_str(info.format);
2061         } else
2062                 postfix = dump_postfix[1];
2063
2064         keys = _tbm_surface_internal_get_keys(surface);
2065         if (!keys) {
2066                 TBM_LOG_E("fail to get keys");
2067                 tbm_surface_unmap(surface);
2068                 return;
2069         }
2070
2071         /* dump */
2072         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2073         if (!bo_handle.ptr) {
2074                 TBM_LOG_E("fail to map bo");
2075                 _tbm_surface_internal_put_keys(keys);
2076                 tbm_surface_unmap(surface);
2077                 return;
2078         }
2079         memset(bo_handle.ptr, 0x00, buf_info->size);
2080
2081         switch (info.format) {
2082         case TBM_FORMAT_ARGB8888:
2083         case TBM_FORMAT_XRGB8888:
2084                 snprintf(buf_info->name, sizeof(buf_info->name),
2085                                 "%10.3f_%03d%s_%p_%s-%s.%s",
2086                                  _tbm_surface_internal_get_time(),
2087                                  g_dump_info->count++, keys, surface, format, type, postfix);
2088
2089                 if (scale_factor > 0.0) {
2090                         ret = _tbm_surface_internal_buffer_scale(info.planes[0].ptr,
2091                                                                                                          bo_handle.ptr,
2092                                                                                                          buf_info->info.format,
2093                                                                                                          info.planes[0].stride,
2094                                                                                                          info.width, info.height,
2095                                                                                                          buf_info->info.planes[0].stride,
2096                                                                                                          buf_info->info.width,
2097                                                                                                          buf_info->info.height);
2098                         if (ret != TBM_SURFACE_ERROR_NONE) {
2099                                 TBM_LOG_E("fail to scale buffer");
2100                                 tbm_bo_unmap(buf_info->bo);
2101                                 _tbm_surface_internal_put_keys(keys);
2102                                 tbm_surface_unmap(surface);
2103                                 return;
2104                         }
2105                 } else
2106                         memcpy(bo_handle.ptr, info.planes[0].ptr, info.size);
2107                 break;
2108         case TBM_FORMAT_YVU420:
2109         case TBM_FORMAT_YUV420:
2110                 snprintf(buf_info->name, sizeof(buf_info->name),
2111                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2112                                  _tbm_surface_internal_get_time(),
2113                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2114                                 info.height, FOURCC_STR(info.format), postfix);
2115                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2116                 bo_handle.ptr += info.planes[0].stride * info.height;
2117                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2118                 bo_handle.ptr += info.planes[1].stride * (info.height >> 1);
2119                 memcpy(bo_handle.ptr, info.planes[2].ptr, info.planes[2].stride * (info.height >> 1));
2120                 break;
2121         case TBM_FORMAT_NV12:
2122         case TBM_FORMAT_NV21:
2123                 snprintf(buf_info->name, sizeof(buf_info->name),
2124                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2125                                  _tbm_surface_internal_get_time(),
2126                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2127                                 info.height, FOURCC_STR(info.format), postfix);
2128                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2129                 bo_handle.ptr += info.planes[0].stride * info.height;
2130                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2131                 break;
2132         case TBM_FORMAT_YUYV:
2133         case TBM_FORMAT_UYVY:
2134                 snprintf(buf_info->name, sizeof(buf_info->name),
2135                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2136                                  _tbm_surface_internal_get_time(),
2137                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2138                                 info.height, FOURCC_STR(info.format), postfix);
2139                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2140                 break;
2141         default:
2142                 TBM_LOG_E("can't copy %c%c%c%c buffer", FOURCC_STR(info.format));
2143                 tbm_bo_unmap(buf_info->bo);
2144                 _tbm_surface_internal_put_keys(keys);
2145                 tbm_surface_unmap(surface);
2146                 return;
2147         }
2148
2149         tbm_bo_unmap(buf_info->bo);
2150
2151         _tbm_surface_internal_put_keys(keys);
2152
2153         tbm_surface_unmap(surface);
2154
2155         buf_info->dirty = 1;
2156         buf_info->dirty_shm = 0;
2157
2158         if (g_dump_info->count == 1000)
2159                 g_dump_info->count = 0;
2160
2161         g_dump_info->link = next_link;
2162
2163         TBM_LOG_I("Dump %s \n", buf_info->name);
2164 }
2165
2166 void tbm_surface_internal_dump_shm_buffer(void *ptr, int w, int h, int stride,
2167                                                 const char *type)
2168 {
2169         TBM_RETURN_IF_FAIL(ptr != NULL);
2170         TBM_RETURN_IF_FAIL(w > 0);
2171         TBM_RETURN_IF_FAIL(h > 0);
2172         TBM_RETURN_IF_FAIL(stride > 0);
2173         TBM_RETURN_IF_FAIL(type != NULL);
2174
2175         tbm_surface_dump_buf_info *buf_info;
2176         struct list_head *next_link;
2177         tbm_bo_handle bo_handle;
2178         int ret, size, dw = 0, dh = 0, dstride = 0;
2179
2180         if (!g_dump_info)
2181                 return;
2182
2183         next_link = g_dump_info->link->next;
2184         TBM_RETURN_IF_FAIL(next_link != NULL);
2185
2186         if (next_link == &g_dump_info->surface_list) {
2187                 next_link = next_link->next;
2188                 TBM_RETURN_IF_FAIL(next_link != NULL);
2189         }
2190
2191         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
2192         TBM_RETURN_IF_FAIL(buf_info != NULL);
2193
2194         if (scale_factor > 0.0) {
2195                 const int bpp = 4;
2196
2197                 dw = w * scale_factor;
2198                 dh = h * scale_factor;
2199                 dstride = dw * bpp;
2200                 size = dstride * dh;
2201         } else
2202                 size = stride * h;
2203
2204         if (size > buf_info->size) {
2205                 TBM_LOG_W("Dump skip. shm buffer over created buffer size(%d, %d)\n",
2206                                 size, buf_info->size);
2207                 return;
2208         }
2209
2210         /* dump */
2211         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2212         TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL);
2213
2214         memset(bo_handle.ptr, 0x00, buf_info->size);
2215         memset(&buf_info->info, 0x00, sizeof(tbm_surface_info_s));
2216
2217         snprintf(buf_info->name, sizeof(buf_info->name), "%10.3f_%03d-%s.%s",
2218                          _tbm_surface_internal_get_time(),
2219                          g_dump_info->count++, type, dump_postfix[0]);
2220         if (scale_factor > 0.0) {
2221                 ret = _tbm_surface_internal_buffer_scale(ptr, bo_handle.ptr,
2222                                                                                                  TBM_FORMAT_ARGB8888, stride,
2223                                                                                                  w, h, dstride, dw, dh);
2224                 if (ret != TBM_SURFACE_ERROR_NONE) {
2225                         TBM_LOG_E("fail to scale buffer");
2226                         tbm_bo_unmap(buf_info->bo);
2227                         return;
2228                 }
2229                 buf_info->shm_stride = dstride;
2230                 buf_info->shm_h = dh;
2231         } else {
2232                 memcpy(bo_handle.ptr, ptr, size);
2233                 buf_info->shm_stride = stride;
2234                 buf_info->shm_h = h;
2235         }
2236
2237         tbm_bo_unmap(buf_info->bo);
2238
2239         buf_info->dirty = 0;
2240         buf_info->dirty_shm = 1;
2241
2242         if (g_dump_info->count == 1000)
2243                 g_dump_info->count = 0;
2244
2245         g_dump_info->link = next_link;
2246
2247         TBM_LOG_I("Dump %s \n", buf_info->name);
2248 }
2249
2250 int
2251 tbm_surface_internal_capture_buffer(tbm_surface_h surface, const char *path, const char *name, const char *type)
2252 {
2253         TBM_RETURN_VAL_IF_FAIL(surface != NULL, 0);
2254         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2255         TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2256
2257         tbm_surface_info_s info;
2258         const char *postfix;
2259         int ret;
2260         char file[1024];
2261
2262         ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
2263         TBM_RETURN_VAL_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE, 0);
2264
2265         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
2266                 postfix = dump_postfix[0];
2267         else
2268                 postfix = dump_postfix[1];
2269
2270         if (strcmp(postfix, type)) {
2271                 TBM_LOG_E("not support type(%s) %c%c%c%c buffer", type, FOURCC_STR(info.format));
2272                 tbm_surface_unmap(surface);
2273                 return 0;
2274         }
2275
2276         snprintf(file, sizeof(file), "%s/%s.%s", path , name, postfix);
2277
2278         if (!access(file, 0)) {
2279                 TBM_LOG_E("can't capture  buffer, exist file %s", file);
2280                 tbm_surface_unmap(surface);
2281                 return 0;
2282         }
2283
2284         switch (info.format) {
2285         case TBM_FORMAT_ARGB8888:
2286                 _tbm_surface_internal_dump_file_png(file, info.planes[0].ptr,
2287                                                         info.planes[0].stride >> 2,
2288                                                         info.height, TBM_FORMAT_ARGB8888);
2289                 break;
2290         case TBM_FORMAT_XRGB8888:
2291                 _tbm_surface_internal_dump_file_png(file, info.planes[0].ptr,
2292                                                         info.planes[0].stride >> 2,
2293                                                         info.height, TBM_FORMAT_XRGB8888);
2294                 break;
2295         case TBM_FORMAT_YVU420:
2296         case TBM_FORMAT_YUV420:
2297                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2298                                 info.planes[0].stride * info.height,
2299                                 info.planes[1].ptr,
2300                                 info.planes[1].stride * (info.height >> 1),
2301                                 info.planes[2].ptr,
2302                                 info.planes[2].stride * (info.height >> 1));
2303                 break;
2304         case TBM_FORMAT_NV12:
2305         case TBM_FORMAT_NV21:
2306                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2307                                         info.planes[0].stride * info.height,
2308                                         info.planes[1].ptr,
2309                                         info.planes[1].stride * (info.height >> 1),
2310                                         NULL, 0);
2311                 break;
2312         case TBM_FORMAT_YUYV:
2313         case TBM_FORMAT_UYVY:
2314                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2315                                         info.planes[0].stride * info.height,
2316                                         NULL, 0, NULL, 0);
2317                 break;
2318         default:
2319                 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
2320                 tbm_surface_unmap(surface);
2321                 return 0;
2322         }
2323
2324         tbm_surface_unmap(surface);
2325
2326         TBM_TRACE("Capture %s \n", file);
2327
2328         return 1;
2329 }
2330
2331 int
2332 tbm_surface_internal_capture_shm_buffer(void *ptr, int w, int h, int stride,
2333                                                 const char *path, const char *name, const char *type)
2334 {
2335         TBM_RETURN_VAL_IF_FAIL(ptr != NULL, 0);
2336         TBM_RETURN_VAL_IF_FAIL(w > 0, 0);
2337         TBM_RETURN_VAL_IF_FAIL(h > 0, 0);
2338         TBM_RETURN_VAL_IF_FAIL(stride > 0, 0);
2339         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2340         TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2341
2342         char file[1024];
2343
2344         if (strcmp(dump_postfix[0], type)) {
2345                 TBM_LOG_E("Not supported type:%s'", type);
2346                 return 0;
2347         }
2348
2349         snprintf(file, sizeof(file), "%s/%s.%s", path , name, dump_postfix[0]);
2350
2351         if (!access(file, 0)) {
2352                 TBM_LOG_E("can't capture buffer, exist file %sTBM_FORMAT_XRGB8888", file);
2353                 return 0;
2354         }
2355
2356         _tbm_surface_internal_dump_file_png(file, ptr, w, h, 0);
2357
2358         TBM_TRACE("Capture %s \n", file);
2359
2360         return 1;
2361 }
2362 /*LCOV_EXCL_STOP*/