tbm_surface: added checking num and num_planes
[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(info->num_planes > 0, NULL);
813         TBM_RETURN_VAL_IF_FAIL(num > 0, NULL);
814         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
815
816         struct _tbm_bufmgr *mgr;
817         struct _tbm_surface *surf = NULL;
818         int i;
819         bool bufmgr_initialized = false;
820
821         _tbm_surface_mutex_lock();
822
823         if (!g_surface_bufmgr) {
824                 _init_surface_bufmgr();
825                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
826                 bufmgr_initialized = true;
827         }
828
829         mgr = g_surface_bufmgr;
830         if (!TBM_BUFMGR_IS_VALID(mgr)) {
831                 TBM_LOG_E("fail to validate the Bufmgr.\n");
832                 goto check_valid_fail;
833         }
834
835         surf = calloc(1, sizeof(struct _tbm_surface));
836         if (!surf) {
837                 /* LCOV_EXCL_START */
838                 TBM_LOG_E("fail to allocate struct _tbm_surface.\n");
839                 goto alloc_surf_fail;
840                 /* LCOV_EXCL_STOP */
841         }
842
843         surf->bufmgr = mgr;
844         surf->info.width = info->width;
845         surf->info.height = info->height;
846         surf->info.format = info->format;
847         if (info->bpp > 0)
848                 surf->info.bpp = info->bpp;
849         else
850                 surf->info.bpp = tbm_surface_internal_get_bpp(info->format);
851         surf->info.num_planes = info->num_planes;
852         surf->refcnt = 1;
853
854         /* get size, stride and offset */
855         for (i = 0; i < info->num_planes; i++) {
856                 surf->info.planes[i].offset = info->planes[i].offset;
857                 surf->info.planes[i].stride = info->planes[i].stride;
858
859                 if (info->planes[i].size > 0)
860                         surf->info.planes[i].size = info->planes[i].size;
861                 else {
862                         uint32_t size = 0, offset = 0, stride = 0;
863                         int32_t bo_idx = 0;
864
865                         _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride, &bo_idx);
866                         surf->info.planes[i].size = size;
867                 }
868
869                 if (num == 1)
870                         surf->planes_bo_idx[i] = 0;
871                 else
872                         surf->planes_bo_idx[i] = i;
873         }
874
875         if (info->size > 0) {
876                 surf->info.size = info->size;
877         } else {
878                 surf->info.size = 0;
879                 for (i = 0; i < info->num_planes; i++)
880                         surf->info.size += surf->info.planes[i].size;
881         }
882
883         surf->flags = TBM_BO_DEFAULT;
884
885         /* create only one bo */
886         surf->num_bos = num;
887         for (i = 0; i < num; i++) {
888                 if (bos[i] == NULL) {
889                         TBM_LOG_E("bos[%d] is null.\n", i);
890                         goto check_bo_fail;
891                 }
892
893                 surf->bos[i] = tbm_bo_ref(bos[i]);
894                 _tbm_bo_set_surface(bos[i], surf);
895         }
896
897         TBM_TRACE("tbm_surface(%p) width(%u) height(%u) format(%s) bo_num(%d)\n", surf,
898                         info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
899
900         LIST_INITHEAD(&surf->user_data_list);
901         LIST_INITHEAD(&surf->debug_data_list);
902
903         LIST_ADD(&surf->item_link, &mgr->surf_list);
904
905         _tbm_surface_mutex_unlock();
906
907         return surf;
908
909 /* LCOV_EXCL_START */
910 check_bo_fail:
911         for (i = 0; i < num; i++) {
912                 if (surf->bos[i])
913                         tbm_bo_unref(surf->bos[i]);
914         }
915         free(surf);
916 alloc_surf_fail:
917 check_valid_fail:
918         if (bufmgr_initialized && mgr) {
919                 LIST_DELINIT(&mgr->surf_list);
920                 _deinit_surface_bufmgr();
921         }
922         _tbm_surface_mutex_unlock();
923
924         TBM_LOG_E("error: width(%u) height(%u) format(%s) bo_num(%d)\n",
925                         info->width, info->height,
926                         _tbm_surface_internal_format_to_str(info->format), num);
927 /* LCOV_EXCL_STOP */
928
929         return NULL;
930 }
931
932 void
933 tbm_surface_internal_destroy(tbm_surface_h surface)
934 {
935         _tbm_surface_mutex_lock();
936
937         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
938
939         surface->refcnt--;
940
941         if (surface->refcnt > 0) {
942                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
943                 _tbm_surface_mutex_unlock();
944                 return;
945         }
946
947         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
948
949         if (surface->refcnt == 0)
950                 _tbm_surface_internal_destroy(surface);
951
952         _tbm_surface_mutex_unlock();
953 }
954
955 void
956 tbm_surface_internal_ref(tbm_surface_h surface)
957 {
958         _tbm_surface_mutex_lock();
959
960         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
961
962         surface->refcnt++;
963
964         TBM_TRACE("tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
965
966         _tbm_surface_mutex_unlock();
967 }
968
969 void
970 tbm_surface_internal_unref(tbm_surface_h surface)
971 {
972         _tbm_surface_mutex_lock();
973
974         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
975
976         surface->refcnt--;
977
978         if (surface->refcnt > 0) {
979                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
980                 _tbm_surface_mutex_unlock();
981                 return;
982         }
983
984         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
985
986         if (surface->refcnt == 0)
987                 _tbm_surface_internal_destroy(surface);
988
989         _tbm_surface_mutex_unlock();
990 }
991
992 int
993 tbm_surface_internal_get_num_bos(tbm_surface_h surface)
994 {
995         struct _tbm_surface *surf;
996         int num;
997
998         _tbm_surface_mutex_lock();
999
1000         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1001
1002         surf = (struct _tbm_surface *)surface;
1003         num = surf->num_bos;
1004
1005         TBM_TRACE("tbm_surface(%p) num_bos(%d)\n", surface, num);
1006
1007         _tbm_surface_mutex_unlock();
1008
1009         return num;
1010 }
1011
1012 tbm_bo
1013 tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
1014 {
1015         struct _tbm_surface *surf;
1016         tbm_bo bo;
1017
1018         _tbm_surface_mutex_lock();
1019
1020         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
1021         TBM_SURFACE_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
1022
1023         surf = (struct _tbm_surface *)surface;
1024         bo = surf->bos[bo_idx];
1025
1026         TBM_TRACE("tbm_surface(%p) bo_idx(%d) tbm_bo(%p)\n", surface, bo_idx, bo);
1027
1028         _tbm_surface_mutex_unlock();
1029
1030         return bo;
1031 }
1032
1033 unsigned int
1034 tbm_surface_internal_get_size(tbm_surface_h surface)
1035 {
1036         struct _tbm_surface *surf;
1037         unsigned int size;
1038
1039         _tbm_surface_mutex_lock();
1040
1041         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1042
1043         surf = (struct _tbm_surface *)surface;
1044         size = surf->info.size;
1045
1046         TBM_TRACE("tbm_surface(%p) size(%u)\n", surface, size);
1047
1048         _tbm_surface_mutex_unlock();
1049
1050         return size;
1051 }
1052
1053 int
1054 tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx,
1055                                     uint32_t *size, uint32_t *offset, uint32_t *pitch)
1056 {
1057         struct _tbm_surface *surf;
1058
1059         _tbm_surface_mutex_lock();
1060
1061         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1062         TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1063
1064         surf = (struct _tbm_surface *)surface;
1065
1066         if (plane_idx >= surf->info.num_planes) {
1067                 TBM_TRACE("error: tbm_surface(%p) plane_idx(%d)\n", surface, plane_idx);
1068                 _tbm_surface_mutex_unlock();
1069                 return 0;
1070         }
1071
1072         if (size)
1073                 *size = surf->info.planes[plane_idx].size;
1074
1075         if (offset)
1076                 *offset = surf->info.planes[plane_idx].offset;
1077
1078         if (pitch)
1079                 *pitch = surf->info.planes[plane_idx].stride;
1080
1081         TBM_TRACE("tbm_surface(%p) plane_idx(%d) size(%u) offset(%u) pitch(%u)\n", surface, plane_idx,
1082                                 surf->info.planes[plane_idx].size, surf->info.planes[plane_idx].offset,
1083                                 surf->info.planes[plane_idx].stride);
1084
1085         _tbm_surface_mutex_unlock();
1086
1087         return 1;
1088 }
1089
1090 int
1091 tbm_surface_internal_get_info(tbm_surface_h surface, int opt,
1092                               tbm_surface_info_s *info, int map)
1093 {
1094         struct _tbm_surface *surf;
1095         tbm_bo_handle bo_handles[4];
1096         int num_bos = 0;
1097         tbm_bo bos[4];
1098         int planes_bo_idx[TBM_SURF_PLANE_MAX];
1099         int i, j;
1100
1101         _tbm_surface_mutex_lock();
1102
1103         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1104
1105         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
1106
1107         surf = (struct _tbm_surface *)surface;
1108
1109         memset(info, 0x00, sizeof(tbm_surface_info_s));
1110         info->width = surf->info.width;
1111         info->height = surf->info.height;
1112         info->format = surf->info.format;
1113         info->bpp = surf->info.bpp;
1114         info->size = surf->info.size;
1115         info->num_planes = surf->info.num_planes;
1116
1117         for (i = 0; i < surf->info.num_planes; i++) {
1118                 info->planes[i].size = surf->info.planes[i].size;
1119                 info->planes[i].offset = surf->info.planes[i].offset;
1120                 info->planes[i].stride = surf->info.planes[i].stride;
1121                 planes_bo_idx[i] = surf->planes_bo_idx[i];
1122         }
1123
1124         for (i = 0; i < surf->num_bos; i++)
1125                 bos[i] = surf->bos[i];
1126
1127         num_bos = surf->num_bos;
1128
1129         if (map == 1) {
1130                 _tbm_surface_mutex_unlock();
1131                 for (i = 0; i < num_bos; i++) {
1132                         bo_handles[i] = tbm_bo_map(bos[i], TBM_DEVICE_CPU, opt);
1133                         if (bo_handles[i].ptr == NULL) {
1134                                 for (j = 0; j < i; j++)
1135                                         tbm_bo_unmap(bos[j]);
1136
1137                                 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1138                                 return 0;
1139                         }
1140                 }
1141                 _tbm_surface_mutex_lock();
1142         } else {
1143                 for (i = 0; i < num_bos; i++) {
1144                         bo_handles[i] = tbm_bo_get_handle(bos[i], TBM_DEVICE_CPU);
1145                         if (bo_handles[i].ptr == NULL) {
1146                                 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1147                                 _tbm_surface_mutex_unlock();
1148                                 return 0;
1149                         }
1150                 }
1151         }
1152
1153         for (i = 0; i < info->num_planes; i++) {
1154                 if (bo_handles[planes_bo_idx[i]].ptr)
1155                         info->planes[i].ptr = bo_handles[planes_bo_idx[i]].ptr + info->planes[i].offset;
1156         }
1157
1158         TBM_TRACE("tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1159
1160         _tbm_surface_mutex_unlock();
1161
1162         return 1;
1163 }
1164
1165 void
1166 tbm_surface_internal_unmap(tbm_surface_h surface)
1167 {
1168         struct _tbm_surface *surf;
1169         int i;
1170
1171         _tbm_surface_mutex_lock();
1172
1173         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1174
1175         surf = (struct _tbm_surface *)surface;
1176
1177         for (i = 0; i < surf->num_bos; i++)
1178                 tbm_bo_unmap(surf->bos[i]);
1179
1180         TBM_TRACE("tbm_surface(%p)\n", surface);
1181
1182         _tbm_surface_mutex_unlock();
1183 }
1184
1185 unsigned int
1186 tbm_surface_internal_get_width(tbm_surface_h surface)
1187 {
1188         struct _tbm_surface *surf;
1189         unsigned int width;
1190
1191         _tbm_surface_mutex_lock();
1192
1193         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1194
1195         surf = (struct _tbm_surface *)surface;
1196         width = surf->info.width;
1197
1198         TBM_TRACE("tbm_surface(%p) width(%u)\n", surface, width);
1199
1200         _tbm_surface_mutex_unlock();
1201
1202         return width;
1203 }
1204
1205 unsigned int
1206 tbm_surface_internal_get_height(tbm_surface_h surface)
1207 {
1208         struct _tbm_surface *surf;
1209         unsigned int height;
1210
1211         _tbm_surface_mutex_lock();
1212
1213         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1214
1215         surf = (struct _tbm_surface *)surface;
1216         height = surf->info.height;
1217
1218         TBM_TRACE("tbm_surface(%p) height(%u)\n", surface, height);
1219
1220         _tbm_surface_mutex_unlock();
1221
1222         return height;
1223
1224 }
1225
1226 tbm_format
1227 tbm_surface_internal_get_format(tbm_surface_h surface)
1228 {
1229         struct _tbm_surface *surf;
1230         tbm_format format;
1231
1232         _tbm_surface_mutex_lock();
1233
1234         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1235
1236         surf = (struct _tbm_surface *)surface;
1237         format = surf->info.format;
1238
1239         TBM_TRACE("tbm_surface(%p) format(%s)\n", surface, _tbm_surface_internal_format_to_str(format));
1240
1241         _tbm_surface_mutex_unlock();
1242
1243         return format;
1244 }
1245
1246 int
1247 tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
1248 {
1249         struct _tbm_surface *surf;
1250         int bo_idx;
1251
1252         _tbm_surface_mutex_lock();
1253
1254         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1255         TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1256
1257         surf = (struct _tbm_surface *)surface;
1258         bo_idx = surf->planes_bo_idx[plane_idx];
1259
1260         TBM_TRACE("tbm_surface(%p) plane_idx(%d) bo_idx(%d)\n", surface, plane_idx, bo_idx);
1261
1262         _tbm_surface_mutex_unlock();
1263
1264         return bo_idx;
1265 }
1266
1267 int
1268 tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key,
1269                                    tbm_data_free data_free_func)
1270 {
1271         tbm_user_data *data;
1272
1273         _tbm_surface_mutex_lock();
1274
1275         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1276
1277         /* check if the data according to the key exist if so, return false. */
1278         data = user_data_lookup(&surface->user_data_list, key);
1279         if (data) {
1280                 TBM_TRACE("warning: user data already exist tbm_surface(%p) key(%lu)\n", surface, key);
1281                 _tbm_surface_mutex_unlock();
1282                 return 0;
1283         }
1284
1285         data = user_data_create(key, data_free_func);
1286         if (!data) {
1287                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1288                 _tbm_surface_mutex_unlock();
1289                 return 0;
1290         }
1291
1292         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, data);
1293
1294         LIST_ADD(&data->item_link, &surface->user_data_list);
1295
1296         _tbm_surface_mutex_unlock();
1297
1298         return 1;
1299 }
1300
1301 int
1302 tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key,
1303                                    void *data)
1304 {
1305         tbm_user_data *old_data;
1306
1307         _tbm_surface_mutex_lock();
1308
1309         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1310
1311         old_data = user_data_lookup(&surface->user_data_list, key);
1312         if (!old_data) {
1313                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1314                 _tbm_surface_mutex_unlock();
1315                 return 0;
1316         }
1317
1318         if (old_data->data && old_data->free_func)
1319                 old_data->free_func(old_data->data);
1320
1321         old_data->data = data;
1322
1323         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1324
1325         _tbm_surface_mutex_unlock();
1326
1327         return 1;
1328 }
1329
1330 int
1331 tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key,
1332                                    void **data)
1333 {
1334         tbm_user_data *old_data;
1335
1336         _tbm_surface_mutex_lock();
1337
1338         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1339
1340         if (!data) {
1341                 TBM_LOG_E("error: tbm_surface(%p) key(%lu)\n", surface, key);
1342                 _tbm_surface_mutex_unlock();
1343                 return 0;
1344         }
1345         *data = NULL;
1346
1347         old_data = user_data_lookup(&surface->user_data_list, key);
1348         if (!old_data) {
1349                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1350                 _tbm_surface_mutex_unlock();
1351                 return 0;
1352         }
1353
1354         *data = old_data->data;
1355
1356         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1357
1358         _tbm_surface_mutex_unlock();
1359
1360         return 1;
1361 }
1362
1363 int
1364 tbm_surface_internal_delete_user_data(tbm_surface_h surface,
1365                                       unsigned long key)
1366 {
1367         tbm_user_data *old_data = (void *)0;
1368
1369         _tbm_surface_mutex_lock();
1370
1371         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1372
1373         old_data = user_data_lookup(&surface->user_data_list, key);
1374         if (!old_data) {
1375                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1376                 _tbm_surface_mutex_unlock();
1377                 return 0;
1378         }
1379
1380         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1381
1382         user_data_delete(old_data);
1383
1384         _tbm_surface_mutex_unlock();
1385
1386         return 1;
1387 }
1388
1389 /* LCOV_EXCL_START */
1390 unsigned int
1391 _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
1392 {
1393         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1394
1395         return surface->debug_pid;
1396 }
1397
1398 void
1399 tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
1400 {
1401         _tbm_surface_mutex_lock();
1402
1403         TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1404
1405         surface->debug_pid = pid;
1406
1407         _tbm_surface_mutex_unlock();
1408 }
1409
1410 static tbm_surface_debug_data *
1411 _tbm_surface_internal_debug_data_create(char *key, char *value)
1412 {
1413         tbm_surface_debug_data *debug_data = NULL;
1414
1415         debug_data = calloc(1, sizeof(tbm_surface_debug_data));
1416         if (!debug_data)
1417                 return NULL;
1418
1419         if (key) debug_data->key = strdup(key);
1420         if (value) debug_data->value = strdup(value);
1421
1422         return debug_data;
1423 }
1424
1425 int
1426 tbm_surface_internal_set_debug_data(tbm_surface_h surface, char *key, char *value)
1427 {
1428         tbm_surface_debug_data *debug_data = NULL;
1429         tbm_surface_debug_data *old_data = NULL, *tmp = NULL;
1430         tbm_bufmgr bufmgr = NULL;
1431
1432         _tbm_surface_mutex_lock();
1433
1434         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1435         TBM_SURFACE_RETURN_VAL_IF_FAIL(key, 0);
1436
1437         bufmgr = surface->bufmgr;
1438
1439         TBM_SURFACE_RETURN_VAL_IF_FAIL(bufmgr, 0);
1440
1441         if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1442                 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1443                         if (old_data) {
1444                                 if (!strcmp(old_data->key, key)) {
1445                                         if (old_data->value && value && !strncmp(old_data->value, value, strlen(old_data->value))) {
1446                                                 TBM_TRACE("tbm_surface(%p) Already exist key(%s) and value(%s)!\n", surface, key, value);
1447                                                 goto add_debug_key_list;
1448                                         }
1449
1450                                         if (old_data->value)
1451                                                 free(old_data->value);
1452
1453                                         if (value)
1454                                                 old_data->value = strdup(value);
1455                                         else
1456                                                 old_data->value = NULL;
1457
1458                                         goto add_debug_key_list;
1459                                 }
1460                         }
1461                 }
1462         }
1463
1464         debug_data = _tbm_surface_internal_debug_data_create(key, value);
1465         if (!debug_data) {
1466                 TBM_LOG_E("error: tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1467                 _tbm_surface_mutex_unlock();
1468                 return 0;
1469         }
1470
1471         TBM_TRACE("tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1472
1473         LIST_ADD(&debug_data->item_link, &surface->debug_data_list);
1474
1475 add_debug_key_list:
1476         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1477                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bufmgr->debug_key_list, item_link) {
1478                         if (!strcmp(old_data->key, key)) {
1479                                 _tbm_surface_mutex_unlock();
1480                                 return 1;
1481                         }
1482                 }
1483         }
1484
1485         debug_data = _tbm_surface_internal_debug_data_create(key, NULL);
1486         LIST_ADD(&debug_data->item_link, &bufmgr->debug_key_list);
1487
1488         _tbm_surface_mutex_unlock();
1489
1490         return 1;
1491 }
1492
1493 char *
1494 _tbm_surface_internal_get_debug_data(tbm_surface_h surface, char *key)
1495 {
1496         tbm_surface_debug_data *old_data = NULL;
1497
1498         TBM_SURFACE_RETURN_VAL_IF_FAIL(surface, NULL);
1499
1500         if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1501                 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1502                         if (!strcmp(old_data->key, key))
1503                                 return old_data->value;
1504                 }
1505         }
1506
1507         return NULL;
1508 }
1509
1510 typedef struct _tbm_surface_dump_info tbm_surface_dump_info;
1511 typedef struct _tbm_surface_dump_buf_info tbm_surface_dump_buf_info;
1512
1513 struct _tbm_surface_dump_buf_info {
1514         int index;
1515         tbm_bo bo;
1516         int size;
1517         int dirty;
1518         int dirty_shm;
1519         int shm_stride;
1520         int shm_h;
1521         char name[1024];
1522
1523         tbm_surface_info_s info;
1524
1525         struct list_head link;
1526 };
1527
1528 struct _tbm_surface_dump_info {
1529         char *path;  // copy???
1530         int dump_max;
1531         int count;
1532         struct list_head *link;
1533         struct list_head surface_list; /* link of surface */
1534 };
1535
1536 static tbm_surface_dump_info *g_dump_info = NULL;
1537 static const char *dump_postfix[2] = {"png", "yuv"};
1538 static double scale_factor;
1539
1540 static void
1541 _tbm_surface_internal_dump_file_raw(const char *file, void *data1, int size1,
1542                                 void *data2, int size2, void *data3, int size3)
1543 {
1544         FILE *fp;
1545         unsigned int *blocks;
1546
1547         if (!_tbm_surface_check_file_is_valid(file, 1))
1548                 TBM_LOG_E("%s is symbolic link\n", file);
1549
1550         fp = fopen(file, "w+");
1551         TBM_RETURN_IF_FAIL(fp != NULL);
1552
1553         blocks = (unsigned int *)data1;
1554         fwrite(blocks, 1, size1, fp);
1555
1556         if (size2 > 0) {
1557                 blocks = (unsigned int *)data2;
1558                 fwrite(blocks, 1, size2, fp);
1559         }
1560
1561         if (size3 > 0) {
1562                 blocks = (unsigned int *)data3;
1563                 fwrite(blocks, 1, size3, fp);
1564         }
1565
1566         fclose(fp);
1567 }
1568
1569 static void
1570 _tbm_surface_internal_dump_file_png(const char *file, const void *data, int width, int height, int format)
1571 {
1572         unsigned int *blocks = (unsigned int *)data;
1573         FILE *fp;
1574         int pixel_size;
1575         png_bytep *row_pointers;
1576         int depth = 8, y;
1577
1578         if (!_tbm_surface_check_file_is_valid(file, 1))
1579                 TBM_LOG_E("%s is symbolic link\n", file);
1580
1581         fp = fopen(file, "wb");
1582         TBM_RETURN_IF_FAIL(fp != NULL);
1583
1584         png_structp pPngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1585                                                         NULL, NULL, NULL);
1586         if (!pPngStruct) {
1587                 TBM_LOG_E("fail to create a png write structure.\n");
1588                 fclose(fp);
1589                 return;
1590         }
1591
1592         png_infop pPngInfo = png_create_info_struct(pPngStruct);
1593         if (!pPngInfo) {
1594                 TBM_LOG_E("fail to create a png info structure.\n");
1595                 png_destroy_write_struct(&pPngStruct, NULL);
1596                 fclose(fp);
1597                 return;
1598         }
1599
1600         png_init_io(pPngStruct, fp);
1601         if (format == TBM_FORMAT_XRGB8888) {
1602                 pixel_size = 3;
1603                 png_set_IHDR(pPngStruct,
1604                                 pPngInfo,
1605                                 width,
1606                                 height,
1607                                 depth,
1608                                 PNG_COLOR_TYPE_RGB,
1609                                 PNG_INTERLACE_NONE,
1610                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1611         } else {
1612                 pixel_size = 4;
1613                 png_set_IHDR(pPngStruct,
1614                                 pPngInfo,
1615                                 width,
1616                                 height,
1617                                 depth,
1618                                 PNG_COLOR_TYPE_RGBA,
1619                                 PNG_INTERLACE_NONE,
1620                                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1621         }
1622
1623         png_set_bgr(pPngStruct);
1624         png_write_info(pPngStruct, pPngInfo);
1625
1626         row_pointers = png_malloc(pPngStruct, height * sizeof(png_byte *));
1627         if (!row_pointers) {
1628                 TBM_LOG_E("fail to allocate the png row_pointers.\n");
1629                 png_destroy_write_struct(&pPngStruct, &pPngInfo);
1630                 fclose(fp);
1631                 return;
1632         }
1633
1634         for (y = 0; y < height; ++y) {
1635                 png_bytep row;
1636                 int x = 0;
1637
1638                 row = png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
1639                 if (!row) {
1640                         TBM_LOG_E("fail to allocate the png row.\n");
1641                         for (x = 0; x < y; x++)
1642                                 png_free(pPngStruct, row_pointers[x]);
1643                         png_free(pPngStruct, row_pointers);
1644                         png_destroy_write_struct(&pPngStruct, &pPngInfo);
1645                         fclose(fp);
1646                         return;
1647                 }
1648                 row_pointers[y] = (png_bytep)row;
1649
1650                 for (x = 0; x < width; ++x) {
1651                         unsigned int curBlock = blocks[y * width + x];
1652
1653                         if (pixel_size == 3) { // XRGB8888
1654                                 row[x * pixel_size] = (curBlock & 0xFF);
1655                                 row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1656                                 row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1657                         } else { // ARGB8888
1658                                 row[x * pixel_size] = (curBlock & 0xFF);
1659                                 row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1660                                 row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1661                                 row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
1662                         }
1663                 }
1664         }
1665
1666         png_write_image(pPngStruct, row_pointers);
1667         png_write_end(pPngStruct, pPngInfo);
1668
1669         for (y = 0; y < height; y++)
1670                 png_free(pPngStruct, row_pointers[y]);
1671         png_free(pPngStruct, row_pointers);
1672
1673         png_destroy_write_struct(&pPngStruct, &pPngInfo);
1674
1675         fclose(fp);
1676 }
1677
1678 void
1679 tbm_surface_internal_dump_start(char *path, int w, int h, int count)
1680 {
1681         TBM_RETURN_IF_FAIL(path != NULL);
1682         TBM_RETURN_IF_FAIL(w > 0);
1683         TBM_RETURN_IF_FAIL(h > 0);
1684         TBM_RETURN_IF_FAIL(count > 0);
1685
1686         tbm_surface_dump_buf_info *buf_info = NULL;
1687         tbm_surface_h tbm_surface;
1688         tbm_surface_info_s info;
1689         int buffer_size, i;
1690
1691         /* check running */
1692         if (g_dump_info) {
1693                 TBM_LOG_W("waring already running the tbm_surface_internal_dump.\n");
1694                 return;
1695         }
1696
1697         g_dump_info = calloc(1, sizeof(struct _tbm_surface_dump_info));
1698         TBM_RETURN_IF_FAIL(g_dump_info);
1699
1700         LIST_INITHEAD(&g_dump_info->surface_list);
1701         g_dump_info->count = 0;
1702         g_dump_info->dump_max = count;
1703
1704         /* get buffer size */
1705         tbm_surface = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
1706         if (tbm_surface == NULL) {
1707                 TBM_LOG_E("tbm_surface_create fail\n");
1708                 free(g_dump_info);
1709                 g_dump_info = NULL;
1710                 return;
1711         }
1712
1713         if (TBM_SURFACE_ERROR_NONE != tbm_surface_get_info(tbm_surface, &info)) {
1714                 TBM_LOG_E("tbm_surface_get_info fail\n");
1715                 tbm_surface_destroy(tbm_surface);
1716                 free(g_dump_info);
1717                 g_dump_info = NULL;
1718                 return;
1719         }
1720         buffer_size = info.size;
1721         tbm_surface_destroy(tbm_surface);
1722
1723         /* create dump lists */
1724         for (i = 0; i < count; i++) {
1725                 tbm_bo bo = NULL;
1726
1727                 buf_info = calloc(1, sizeof(tbm_surface_dump_buf_info));
1728                 TBM_GOTO_VAL_IF_FAIL(buf_info, fail);
1729
1730                 bo = tbm_bo_alloc(g_surface_bufmgr, buffer_size, TBM_BO_DEFAULT);
1731                 if (bo == NULL) {
1732                         TBM_LOG_E("fail to allocate the tbm_bo[%d]\n", i);
1733                         free(buf_info);
1734                         goto fail;
1735                 }
1736
1737                 buf_info->index = i;
1738                 buf_info->bo = bo;
1739                 buf_info->size = buffer_size;
1740
1741                 LIST_ADDTAIL(&buf_info->link, &g_dump_info->surface_list);
1742         }
1743
1744         g_dump_info->path = path;
1745         g_dump_info->link = &g_dump_info->surface_list;
1746
1747         scale_factor = 0.0;
1748
1749         TBM_LOG_I("Dump Start.. path:%s, count:%d\n", g_dump_info->path, count);
1750
1751         return;
1752
1753 fail:
1754         /* free resources */
1755         if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1756                 tbm_surface_dump_buf_info *tmp;
1757
1758                 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1759                         tbm_bo_unref(buf_info->bo);
1760                         LIST_DEL(&buf_info->link);
1761                         free(buf_info);
1762                 }
1763         }
1764
1765         TBM_LOG_E("Dump Start fail.. path:%s\n", g_dump_info->path);
1766
1767         free(g_dump_info);
1768         g_dump_info = NULL;
1769
1770         return;
1771 }
1772
1773 void
1774 tbm_surface_internal_dump_with_scale_start(char *path, int w, int h, int count, double scale)
1775 {
1776         if (scale > 0.0) {
1777                 w *= scale;
1778                 h *= scale;
1779         }
1780
1781         tbm_surface_internal_dump_start(path, w, h, count);
1782         scale_factor = scale;
1783 }
1784
1785 void
1786 tbm_surface_internal_dump_end(void)
1787 {
1788         tbm_surface_dump_buf_info *buf_info = NULL, *tmp = NULL;
1789         tbm_bo_handle bo_handle;
1790
1791         if (!g_dump_info)
1792                 return;
1793
1794         if (LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1795                 free(g_dump_info);
1796                 g_dump_info = NULL;
1797                 return;
1798         }
1799
1800         /* make files */
1801         LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1802                 char file[2048];
1803
1804                 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
1805                 if (bo_handle.ptr == NULL) {
1806                         tbm_bo_unref(buf_info->bo);
1807                         LIST_DEL(&buf_info->link);
1808                         free(buf_info);
1809                         continue;
1810                 }
1811
1812                 snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name);
1813                 TBM_LOG_I("Dump File.. %s generated.\n", file);
1814
1815                 if (buf_info->dirty) {
1816                         void *ptr1 = NULL, *ptr2 = NULL;
1817
1818                         switch (buf_info->info.format) {
1819                         case TBM_FORMAT_ARGB8888:
1820                                 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1821                                                         buf_info->info.planes[0].stride >> 2,
1822                                                         buf_info->info.height, TBM_FORMAT_ARGB8888);
1823                                 break;
1824                         case TBM_FORMAT_XRGB8888:
1825                                 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1826                                                         buf_info->info.planes[0].stride >> 2,
1827                                                         buf_info->info.height, TBM_FORMAT_XRGB8888);
1828                                 break;
1829                         case TBM_FORMAT_YVU420:
1830                         case TBM_FORMAT_YUV420:
1831                                 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1832                                 ptr2 = ptr1 + buf_info->info.planes[1].stride * (buf_info->info.height >> 1);
1833                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1834                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1835                                                         ptr1,
1836                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1837                                                         ptr2,
1838                                                         buf_info->info.planes[2].stride * (buf_info->info.height >> 1));
1839                                 break;
1840                         case TBM_FORMAT_NV12:
1841                         case TBM_FORMAT_NV21:
1842                                 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1843                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1844                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1845                                                         ptr1,
1846                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1847                                                         NULL, 0);
1848                                 break;
1849                         case TBM_FORMAT_YUYV:
1850                         case TBM_FORMAT_UYVY:
1851                                 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1852                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1853                                                         NULL, 0, NULL, 0);
1854                                 break;
1855                         default:
1856                                 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(buf_info->info.format));
1857                                 break;
1858                         }
1859                 } else if (buf_info->dirty_shm)
1860                         _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1861                                                         buf_info->shm_stride >> 2,
1862                                                         buf_info->shm_h, 0);
1863
1864                 tbm_bo_unmap(buf_info->bo);
1865                 tbm_bo_unref(buf_info->bo);
1866                 LIST_DEL(&buf_info->link);
1867                 free(buf_info);
1868         }
1869
1870         free(g_dump_info);
1871         g_dump_info = NULL;
1872
1873         TBM_LOG_I("Dump End..\n");
1874 }
1875
1876 static pixman_format_code_t
1877 _tbm_surface_internal_pixman_format_get(tbm_format format)
1878 {
1879         switch (format) {
1880         case TBM_FORMAT_ARGB8888:
1881                 return PIXMAN_a8r8g8b8;
1882         case TBM_FORMAT_XRGB8888:
1883                 return PIXMAN_x8r8g8b8;
1884         default:
1885                 return 0;
1886         }
1887
1888         return 0;
1889 }
1890
1891 /**
1892  * This function supports only if a buffer has below formats.
1893  * - TBM_FORMAT_ARGB8888
1894  * - TBM_FORMAT_XRGB8888
1895  */
1896 static tbm_surface_error_e
1897 _tbm_surface_internal_buffer_scale(void *src_ptr, void *dst_ptr,
1898                                                                    int format, int src_stride, int src_w, int src_h,
1899                                                                    int dst_stride, int dst_w, int dst_h)
1900 {
1901         pixman_image_t *src_img = NULL, *dst_img = NULL;
1902         pixman_format_code_t pixman_format;
1903         pixman_transform_t t;
1904         struct pixman_f_transform ft;
1905         double scale_x, scale_y;
1906
1907         TBM_RETURN_VAL_IF_FAIL(src_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1908         TBM_RETURN_VAL_IF_FAIL(dst_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1909
1910         pixman_format = _tbm_surface_internal_pixman_format_get(format);
1911         TBM_RETURN_VAL_IF_FAIL(pixman_format > 0, TBM_SURFACE_ERROR_INVALID_OPERATION);
1912
1913         /* src */
1914         src_img = pixman_image_create_bits(pixman_format, src_w, src_h,
1915                                                                            (uint32_t*)src_ptr, src_stride);
1916         TBM_GOTO_VAL_IF_FAIL(src_img != NULL, cant_convert);
1917
1918         /* dst */
1919         dst_img = pixman_image_create_bits(pixman_format, dst_w, dst_h,
1920                                                                            (uint32_t*)dst_ptr, dst_stride);
1921         TBM_GOTO_VAL_IF_FAIL(dst_img != NULL, cant_convert);
1922
1923         pixman_f_transform_init_identity(&ft);
1924
1925         scale_x = (double)src_w / dst_w;
1926         scale_y = (double)src_h / dst_h;
1927
1928         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
1929         pixman_f_transform_translate(&ft, NULL, 0, 0);
1930         pixman_transform_from_pixman_f_transform(&t, &ft);
1931         pixman_image_set_transform(src_img, &t);
1932
1933         pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img,
1934                                                    0, 0, 0, 0, 0, 0, dst_w, dst_h);
1935
1936         pixman_image_unref(src_img);
1937         pixman_image_unref(dst_img);
1938
1939         return TBM_SURFACE_ERROR_NONE;
1940
1941 cant_convert:
1942         if (src_img)
1943                 pixman_image_unref(src_img);
1944
1945         return TBM_SURFACE_ERROR_INVALID_OPERATION;
1946 }
1947
1948 #define MAX_BOS         4       // This value is came from bos[4] in struct _tbm_surface
1949 #define KEY_LEN         5       // "_XXXX"
1950 #define KEYS_LEN        KEY_LEN * MAX_BOS
1951
1952 static char *_tbm_surface_internal_get_keys(tbm_surface_h surface)
1953 {
1954         char *keys, temp_key[KEY_LEN + 1];
1955         struct _tbm_surface *surf;
1956         int i, num_bos;
1957         tbm_bo bo;
1958
1959         _tbm_surface_mutex_lock();
1960
1961         TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
1962
1963         surf = (struct _tbm_surface *)surface;
1964
1965         num_bos = surf->num_bos;
1966         if (num_bos > MAX_BOS)
1967                 num_bos = MAX_BOS;
1968
1969         keys = calloc(KEYS_LEN + 1, sizeof(char));
1970         if (!keys) {
1971                 TBM_LOG_E("Failed to alloc memory");
1972                 _tbm_surface_mutex_unlock();
1973                 return NULL;
1974         }
1975
1976         for (i = 0; i < num_bos; i++) {
1977                 memset(temp_key, 0x00, KEY_LEN + 1);
1978                 bo = surf->bos[i];
1979                 snprintf(temp_key, KEY_LEN, "_%d", tbm_bo_export(bo));
1980                 strncat(keys, temp_key, KEY_LEN);
1981         }
1982
1983         _tbm_surface_mutex_unlock();
1984
1985         return keys;
1986 }
1987
1988 static void _tbm_surface_internal_put_keys(char *keys)
1989 {
1990         if (keys)
1991                 free(keys);
1992 }
1993
1994 void
1995 tbm_surface_internal_dump_buffer(tbm_surface_h surface, const char *type)
1996 {
1997         TBM_RETURN_IF_FAIL(surface != NULL);
1998         TBM_RETURN_IF_FAIL(type != NULL);
1999
2000         tbm_surface_dump_buf_info *buf_info;
2001         struct list_head *next_link;
2002         tbm_surface_info_s info;
2003         tbm_bo_handle bo_handle;
2004         const char *postfix;
2005         const char *format = NULL;
2006         char *keys;
2007         int ret;
2008
2009         if (!g_dump_info)
2010                 return;
2011
2012         next_link = g_dump_info->link->next;
2013         TBM_RETURN_IF_FAIL(next_link != NULL);
2014
2015         if (next_link == &g_dump_info->surface_list) {
2016                 next_link = next_link->next;
2017                 TBM_RETURN_IF_FAIL(next_link != NULL);
2018         }
2019
2020         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
2021         TBM_RETURN_IF_FAIL(buf_info != NULL);
2022
2023         ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
2024         TBM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
2025
2026         if (scale_factor > 0.0) {
2027                 const int bpp = 4;
2028
2029                 if (info.format != TBM_FORMAT_ARGB8888 && info.format != TBM_FORMAT_XRGB8888) {
2030                         TBM_LOG_W("Dump with scale skip. unsupported format(%s)\n",
2031                                           _tbm_surface_internal_format_to_str(info.format));
2032                         tbm_surface_unmap(surface);
2033                         return;
2034                 }
2035
2036                 memset(&buf_info->info, 0, sizeof(tbm_surface_info_s));
2037
2038                 buf_info->info.width = info.width * scale_factor;
2039                 buf_info->info.height = info.height * scale_factor;
2040                 buf_info->info.format = info.format;
2041                 buf_info->info.bpp = tbm_surface_internal_get_bpp(buf_info->info.format);
2042                 buf_info->info.num_planes = 1;
2043                 buf_info->info.planes[0].stride = buf_info->info.width * bpp;
2044                 buf_info->info.size = buf_info->info.width * buf_info->info.height * bpp;
2045
2046                 if (buf_info->info.size > buf_info->size) {
2047                         TBM_LOG_W("Dump with scale skip. surface over created buffer size(%u, %d)\n",
2048                                         buf_info->info.size, buf_info->size);
2049                         tbm_surface_unmap(surface);
2050                         return;
2051                 }
2052         } else {
2053                 if (info.size > buf_info->size) {
2054                         TBM_LOG_W("Dump skip. surface over created buffer size(%u, %d)\n",
2055                                         info.size, buf_info->size);
2056                         tbm_surface_unmap(surface);
2057                         return;
2058                 }
2059
2060                 /* make the file information */
2061                 memcpy(&buf_info->info, &info, sizeof(tbm_surface_info_s));
2062         }
2063
2064         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) {
2065                 postfix = dump_postfix[0];
2066                 format = _tbm_surface_internal_format_to_str(info.format);
2067         } else
2068                 postfix = dump_postfix[1];
2069
2070         keys = _tbm_surface_internal_get_keys(surface);
2071         if (!keys) {
2072                 TBM_LOG_E("fail to get keys");
2073                 tbm_surface_unmap(surface);
2074                 return;
2075         }
2076
2077         /* dump */
2078         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2079         if (!bo_handle.ptr) {
2080                 TBM_LOG_E("fail to map bo");
2081                 _tbm_surface_internal_put_keys(keys);
2082                 tbm_surface_unmap(surface);
2083                 return;
2084         }
2085         memset(bo_handle.ptr, 0x00, buf_info->size);
2086
2087         switch (info.format) {
2088         case TBM_FORMAT_ARGB8888:
2089         case TBM_FORMAT_XRGB8888:
2090                 snprintf(buf_info->name, sizeof(buf_info->name),
2091                                 "%10.3f_%03d%s_%p_%s-%s.%s",
2092                                  _tbm_surface_internal_get_time(),
2093                                  g_dump_info->count++, keys, surface, format, type, postfix);
2094
2095                 if (scale_factor > 0.0) {
2096                         ret = _tbm_surface_internal_buffer_scale(info.planes[0].ptr,
2097                                                                                                          bo_handle.ptr,
2098                                                                                                          buf_info->info.format,
2099                                                                                                          info.planes[0].stride,
2100                                                                                                          info.width, info.height,
2101                                                                                                          buf_info->info.planes[0].stride,
2102                                                                                                          buf_info->info.width,
2103                                                                                                          buf_info->info.height);
2104                         if (ret != TBM_SURFACE_ERROR_NONE) {
2105                                 TBM_LOG_E("fail to scale buffer");
2106                                 tbm_bo_unmap(buf_info->bo);
2107                                 _tbm_surface_internal_put_keys(keys);
2108                                 tbm_surface_unmap(surface);
2109                                 return;
2110                         }
2111                 } else
2112                         memcpy(bo_handle.ptr, info.planes[0].ptr, info.size);
2113                 break;
2114         case TBM_FORMAT_YVU420:
2115         case TBM_FORMAT_YUV420:
2116                 snprintf(buf_info->name, sizeof(buf_info->name),
2117                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2118                                  _tbm_surface_internal_get_time(),
2119                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2120                                 info.height, FOURCC_STR(info.format), postfix);
2121                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2122                 bo_handle.ptr += info.planes[0].stride * info.height;
2123                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2124                 bo_handle.ptr += info.planes[1].stride * (info.height >> 1);
2125                 memcpy(bo_handle.ptr, info.planes[2].ptr, info.planes[2].stride * (info.height >> 1));
2126                 break;
2127         case TBM_FORMAT_NV12:
2128         case TBM_FORMAT_NV21:
2129                 snprintf(buf_info->name, sizeof(buf_info->name),
2130                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2131                                  _tbm_surface_internal_get_time(),
2132                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2133                                 info.height, FOURCC_STR(info.format), postfix);
2134                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2135                 bo_handle.ptr += info.planes[0].stride * info.height;
2136                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2137                 break;
2138         case TBM_FORMAT_YUYV:
2139         case TBM_FORMAT_UYVY:
2140                 snprintf(buf_info->name, sizeof(buf_info->name),
2141                                 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2142                                  _tbm_surface_internal_get_time(),
2143                                  g_dump_info->count++, keys, type, info.planes[0].stride,
2144                                 info.height, FOURCC_STR(info.format), postfix);
2145                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2146                 break;
2147         default:
2148                 TBM_LOG_E("can't copy %c%c%c%c buffer", FOURCC_STR(info.format));
2149                 tbm_bo_unmap(buf_info->bo);
2150                 _tbm_surface_internal_put_keys(keys);
2151                 tbm_surface_unmap(surface);
2152                 return;
2153         }
2154
2155         tbm_bo_unmap(buf_info->bo);
2156
2157         _tbm_surface_internal_put_keys(keys);
2158
2159         tbm_surface_unmap(surface);
2160
2161         buf_info->dirty = 1;
2162         buf_info->dirty_shm = 0;
2163
2164         if (g_dump_info->count == 1000)
2165                 g_dump_info->count = 0;
2166
2167         g_dump_info->link = next_link;
2168
2169         TBM_LOG_I("Dump %s \n", buf_info->name);
2170 }
2171
2172 void tbm_surface_internal_dump_shm_buffer(void *ptr, int w, int h, int stride,
2173                                                 const char *type)
2174 {
2175         TBM_RETURN_IF_FAIL(ptr != NULL);
2176         TBM_RETURN_IF_FAIL(w > 0);
2177         TBM_RETURN_IF_FAIL(h > 0);
2178         TBM_RETURN_IF_FAIL(stride > 0);
2179         TBM_RETURN_IF_FAIL(type != NULL);
2180
2181         tbm_surface_dump_buf_info *buf_info;
2182         struct list_head *next_link;
2183         tbm_bo_handle bo_handle;
2184         int ret, size, dw = 0, dh = 0, dstride = 0;
2185
2186         if (!g_dump_info)
2187                 return;
2188
2189         next_link = g_dump_info->link->next;
2190         TBM_RETURN_IF_FAIL(next_link != NULL);
2191
2192         if (next_link == &g_dump_info->surface_list) {
2193                 next_link = next_link->next;
2194                 TBM_RETURN_IF_FAIL(next_link != NULL);
2195         }
2196
2197         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
2198         TBM_RETURN_IF_FAIL(buf_info != NULL);
2199
2200         if (scale_factor > 0.0) {
2201                 const int bpp = 4;
2202
2203                 dw = w * scale_factor;
2204                 dh = h * scale_factor;
2205                 dstride = dw * bpp;
2206                 size = dstride * dh;
2207         } else
2208                 size = stride * h;
2209
2210         if (size > buf_info->size) {
2211                 TBM_LOG_W("Dump skip. shm buffer over created buffer size(%d, %d)\n",
2212                                 size, buf_info->size);
2213                 return;
2214         }
2215
2216         /* dump */
2217         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2218         TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL);
2219
2220         memset(bo_handle.ptr, 0x00, buf_info->size);
2221         memset(&buf_info->info, 0x00, sizeof(tbm_surface_info_s));
2222
2223         snprintf(buf_info->name, sizeof(buf_info->name), "%10.3f_%03d-%s.%s",
2224                          _tbm_surface_internal_get_time(),
2225                          g_dump_info->count++, type, dump_postfix[0]);
2226         if (scale_factor > 0.0) {
2227                 ret = _tbm_surface_internal_buffer_scale(ptr, bo_handle.ptr,
2228                                                                                                  TBM_FORMAT_ARGB8888, stride,
2229                                                                                                  w, h, dstride, dw, dh);
2230                 if (ret != TBM_SURFACE_ERROR_NONE) {
2231                         TBM_LOG_E("fail to scale buffer");
2232                         tbm_bo_unmap(buf_info->bo);
2233                         return;
2234                 }
2235                 buf_info->shm_stride = dstride;
2236                 buf_info->shm_h = dh;
2237         } else {
2238                 memcpy(bo_handle.ptr, ptr, size);
2239                 buf_info->shm_stride = stride;
2240                 buf_info->shm_h = h;
2241         }
2242
2243         tbm_bo_unmap(buf_info->bo);
2244
2245         buf_info->dirty = 0;
2246         buf_info->dirty_shm = 1;
2247
2248         if (g_dump_info->count == 1000)
2249                 g_dump_info->count = 0;
2250
2251         g_dump_info->link = next_link;
2252
2253         TBM_LOG_I("Dump %s \n", buf_info->name);
2254 }
2255
2256 int
2257 tbm_surface_internal_capture_buffer(tbm_surface_h surface, const char *path, const char *name, const char *type)
2258 {
2259         TBM_RETURN_VAL_IF_FAIL(surface != NULL, 0);
2260         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2261         TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2262
2263         tbm_surface_info_s info;
2264         const char *postfix;
2265         int ret;
2266         char file[1024];
2267
2268         ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
2269         TBM_RETURN_VAL_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE, 0);
2270
2271         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
2272                 postfix = dump_postfix[0];
2273         else
2274                 postfix = dump_postfix[1];
2275
2276         if (strcmp(postfix, type)) {
2277                 TBM_LOG_E("not support type(%s) %c%c%c%c buffer", type, FOURCC_STR(info.format));
2278                 tbm_surface_unmap(surface);
2279                 return 0;
2280         }
2281
2282         snprintf(file, sizeof(file), "%s/%s.%s", path , name, postfix);
2283
2284         if (!access(file, 0)) {
2285                 TBM_LOG_E("can't capture  buffer, exist file %s", file);
2286                 tbm_surface_unmap(surface);
2287                 return 0;
2288         }
2289
2290         switch (info.format) {
2291         case TBM_FORMAT_ARGB8888:
2292                 _tbm_surface_internal_dump_file_png(file, info.planes[0].ptr,
2293                                                         info.planes[0].stride >> 2,
2294                                                         info.height, TBM_FORMAT_ARGB8888);
2295                 break;
2296         case TBM_FORMAT_XRGB8888:
2297                 _tbm_surface_internal_dump_file_png(file, info.planes[0].ptr,
2298                                                         info.planes[0].stride >> 2,
2299                                                         info.height, TBM_FORMAT_XRGB8888);
2300                 break;
2301         case TBM_FORMAT_YVU420:
2302         case TBM_FORMAT_YUV420:
2303                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2304                                 info.planes[0].stride * info.height,
2305                                 info.planes[1].ptr,
2306                                 info.planes[1].stride * (info.height >> 1),
2307                                 info.planes[2].ptr,
2308                                 info.planes[2].stride * (info.height >> 1));
2309                 break;
2310         case TBM_FORMAT_NV12:
2311         case TBM_FORMAT_NV21:
2312                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2313                                         info.planes[0].stride * info.height,
2314                                         info.planes[1].ptr,
2315                                         info.planes[1].stride * (info.height >> 1),
2316                                         NULL, 0);
2317                 break;
2318         case TBM_FORMAT_YUYV:
2319         case TBM_FORMAT_UYVY:
2320                 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2321                                         info.planes[0].stride * info.height,
2322                                         NULL, 0, NULL, 0);
2323                 break;
2324         default:
2325                 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
2326                 tbm_surface_unmap(surface);
2327                 return 0;
2328         }
2329
2330         tbm_surface_unmap(surface);
2331
2332         TBM_TRACE("Capture %s \n", file);
2333
2334         return 1;
2335 }
2336
2337 int
2338 tbm_surface_internal_capture_shm_buffer(void *ptr, int w, int h, int stride,
2339                                                 const char *path, const char *name, const char *type)
2340 {
2341         TBM_RETURN_VAL_IF_FAIL(ptr != NULL, 0);
2342         TBM_RETURN_VAL_IF_FAIL(w > 0, 0);
2343         TBM_RETURN_VAL_IF_FAIL(h > 0, 0);
2344         TBM_RETURN_VAL_IF_FAIL(stride > 0, 0);
2345         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2346         TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2347
2348         char file[1024];
2349
2350         if (strcmp(dump_postfix[0], type)) {
2351                 TBM_LOG_E("Not supported type:%s'", type);
2352                 return 0;
2353         }
2354
2355         snprintf(file, sizeof(file), "%s/%s.%s", path , name, dump_postfix[0]);
2356
2357         if (!access(file, 0)) {
2358                 TBM_LOG_E("can't capture buffer, exist file %sTBM_FORMAT_XRGB8888", file);
2359                 return 0;
2360         }
2361
2362         _tbm_surface_internal_dump_file_png(file, ptr, w, h, 0);
2363
2364         TBM_TRACE("Capture %s \n", file);
2365
2366         return 1;
2367 }
2368 /*LCOV_EXCL_STOP*/