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