add trace messages for debugging
[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 #include <stdio.h>
34 #include <time.h>
35 #include <sys/time.h>
36 #include "tbm_bufmgr.h"
37 #include "tbm_bufmgr_int.h"
38 #include "tbm_surface_internal.h"
39 #include "list.h"
40 #include <png.h>
41
42 #define C(b, m)              (((b) >> (m)) & 0xFF)
43 #define B(c, s)              ((((unsigned int)(c)) & 0xff) << (s))
44 #define FOURCC(a, b, c, d)     (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0))
45 #define FOURCC_STR(id)      C(id, 0), C(id, 8), C(id, 16), C(id, 24)
46 #define FOURCC_ID(str)      FOURCC(((char*)str)[0], ((char*)str)[1], ((char*)str)[2], ((char*)str)[3])
47
48 static tbm_bufmgr g_surface_bufmgr;
49 static pthread_mutex_t tbm_surface_lock;
50
51 /* LCOV_EXCL_START */
52
53 static unsigned long
54 _get_time_in_millis(void)
55 {
56         struct timeval tv;
57
58         gettimeofday(&tv, NULL);
59
60         return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
61 }
62
63 char *
64 _tbm_surface_internal_format_to_str(tbm_format format)
65 {
66         switch (format) {
67         case TBM_FORMAT_C8:
68                 return "TBM_FORMAT_C8";
69         case TBM_FORMAT_RGB332:
70                 return "TBM_FORMAT_RGB332";
71         case TBM_FORMAT_BGR233:
72                 return "TBM_FORMAT_BGR233";
73         case TBM_FORMAT_XRGB4444:
74                 return "TBM_FORMAT_XRGB4444";
75         case TBM_FORMAT_XBGR4444:
76                 return "TBM_FORMAT_XBGR4444";
77         case TBM_FORMAT_RGBX4444:
78                 return "TBM_FORMAT_RGBX4444";
79         case TBM_FORMAT_BGRX4444:
80                 return "TBM_FORMAT_BGRX4444";
81         case TBM_FORMAT_ARGB4444:
82                 return "TBM_FORMAT_ARGB4444";
83         case TBM_FORMAT_ABGR4444:
84                 return "TBM_FORMAT_ABGR4444";
85         case TBM_FORMAT_RGBA4444:
86                 return "TBM_FORMAT_RGBA4444";
87         case TBM_FORMAT_BGRA4444:
88                 return "TBM_FORMAT_BGRA4444";
89         case TBM_FORMAT_XRGB1555:
90                 return "TBM_FORMAT_XRGB1555";
91         case TBM_FORMAT_XBGR1555:
92                 return "TBM_FORMAT_XBGR1555";
93         case TBM_FORMAT_RGBX5551:
94                 return "TBM_FORMAT_RGBX5551";
95         case TBM_FORMAT_BGRX5551:
96                 return "TBM_FORMAT_BGRX5551";
97         case TBM_FORMAT_ARGB1555:
98                 return "TBM_FORMAT_ARGB1555";
99         case TBM_FORMAT_ABGR1555:
100                 return "TBM_FORMAT_ABGR1555";
101         case TBM_FORMAT_RGBA5551:
102                 return "TBM_FORMAT_RGBA5551";
103         case TBM_FORMAT_BGRA5551:
104                 return "TBM_FORMAT_BGRA5551";
105         case TBM_FORMAT_RGB565:
106                 return "TBM_FORMAT_RGB565";
107         case TBM_FORMAT_BGR565:
108                 return "TBM_FORMAT_BGR565";
109         case TBM_FORMAT_RGB888:
110                 return "TBM_FORMAT_RGB888";
111         case TBM_FORMAT_BGR888:
112                 return "TBM_FORMAT_BGR888";
113         case TBM_FORMAT_XRGB8888:
114                 return "TBM_FORMAT_XRGB8888";
115         case TBM_FORMAT_XBGR8888:
116                 return "TBM_FORMAT_XBGR8888";
117         case TBM_FORMAT_RGBX8888:
118                 return "TBM_FORMAT_RGBX8888";
119         case TBM_FORMAT_BGRX8888:
120                 return "TBM_FORMAT_BGRX8888";
121         case TBM_FORMAT_ARGB8888:
122                 return "TBM_FORMAT_ARGB8888";
123         case TBM_FORMAT_ABGR8888:
124                 return "TBM_FORMAT_ABGR8888";
125         case TBM_FORMAT_RGBA8888:
126                 return "TBM_FORMAT_RGBA8888";
127         case TBM_FORMAT_BGRA8888:
128                 return "TBM_FORMAT_BGRA8888";
129         case TBM_FORMAT_XRGB2101010:
130                 return "TBM_FORMAT_XRGB2101010";
131         case TBM_FORMAT_XBGR2101010:
132                 return "TBM_FORMAT_XBGR2101010";
133         case TBM_FORMAT_RGBX1010102:
134                 return "TBM_FORMAT_RGBX1010102";
135         case TBM_FORMAT_BGRX1010102:
136                 return "TBM_FORMAT_BGRX1010102";
137         case TBM_FORMAT_ARGB2101010:
138                 return "TBM_FORMAT_ARGB2101010";
139         case TBM_FORMAT_ABGR2101010:
140                 return "TBM_FORMAT_ABGR2101010";
141         case TBM_FORMAT_RGBA1010102:
142                 return "TBM_FORMAT_RGBA1010102";
143         case TBM_FORMAT_BGRA1010102:
144                 return "TBM_FORMAT_BGRA1010102";
145         case TBM_FORMAT_YUYV:
146                 return "TBM_FORMAT_YUYV";
147         case TBM_FORMAT_YVYU:
148                 return "TBM_FORMAT_YVYU";
149         case TBM_FORMAT_UYVY:
150                 return "TBM_FORMAT_UYVY";
151         case TBM_FORMAT_VYUY:
152                 return "TBM_FORMAT_VYUY";
153         case TBM_FORMAT_AYUV:
154                 return "TBM_FORMAT_AYUV";
155         case TBM_FORMAT_NV12:
156                 return "TBM_FORMAT_NV12";
157         case TBM_FORMAT_NV21:
158                 return "TBM_FORMAT_NV21";
159         case TBM_FORMAT_NV16:
160                 return "TBM_FORMAT_NV16";
161         case TBM_FORMAT_NV61:
162                 return "TBM_FORMAT_NV61";
163         case TBM_FORMAT_YUV410:
164                 return "TBM_FORMAT_YUV410";
165         case TBM_FORMAT_YVU410:
166                 return "TBM_FORMAT_YVU410";
167         case TBM_FORMAT_YUV411:
168                 return "TBM_FORMAT_YUV411";
169         case TBM_FORMAT_YVU411:
170                 return "TBM_FORMAT_YVU411";
171         case TBM_FORMAT_YUV420:
172                 return "TBM_FORMAT_YUV420";
173         case TBM_FORMAT_YVU420:
174                 return "TBM_FORMAT_YVU420";
175         case TBM_FORMAT_YUV422:
176                 return "TBM_FORMAT_YUV422";
177         case TBM_FORMAT_YVU422:
178                 return "TBM_FORMAT_YVU422";
179         case TBM_FORMAT_YUV444:
180                 return "TBM_FORMAT_YUV444";
181         case TBM_FORMAT_YVU444:
182                 return "TBM_FORMAT_YVU444";
183         case TBM_FORMAT_NV12MT:
184                 return "TBM_FORMAT_NV12MT";
185         default:
186                 return "unknwon";
187         }
188 }
189 /* LCOV_EXCL_STOP */
190
191 static bool
192 _tbm_surface_mutex_init(void)
193 {
194         static bool tbm_surface_mutex_init = false;
195
196         if (tbm_surface_mutex_init)
197                 return true;
198
199         if (pthread_mutex_init(&tbm_surface_lock, NULL)) {
200                 TBM_LOG_E("fail: tbm_surface mutex init\n");
201                 return false;
202         }
203
204         tbm_surface_mutex_init = true;
205
206         return true;
207 }
208
209 void
210 _tbm_surface_mutex_lock(void)
211 {
212         if (!_tbm_surface_mutex_init())
213                 return;
214
215         pthread_mutex_lock(&tbm_surface_lock);
216 }
217
218 void
219 _tbm_surface_mutex_unlock(void)
220 {
221         pthread_mutex_unlock(&tbm_surface_lock);
222 }
223
224 static void
225 _init_surface_bufmgr(void)
226 {
227         g_surface_bufmgr = tbm_bufmgr_init(-1);
228 }
229
230 static void
231 _deinit_surface_bufmgr(void)
232 {
233         if (!g_surface_bufmgr)
234                 return;
235
236         tbm_bufmgr_deinit(g_surface_bufmgr);
237         g_surface_bufmgr = NULL;
238 }
239
240 static int
241 _tbm_surface_internal_query_plane_data(tbm_surface_h surface,
242                                        int plane_idx, uint32_t *size, uint32_t *offset, uint32_t *pitch, int *bo_idx)
243 {
244         TBM_RETURN_VAL_IF_FAIL(surface, 0);
245         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
246
247         struct _tbm_surface *surf = (struct _tbm_surface *)surface;
248         struct _tbm_bufmgr *mgr = surf->bufmgr;
249         int ret = 0;
250
251         TBM_RETURN_VAL_IF_FAIL(mgr != NULL, 0);
252         TBM_RETURN_VAL_IF_FAIL(surf->info.width > 0, 0);
253         TBM_RETURN_VAL_IF_FAIL(surf->info.height > 0, 0);
254         TBM_RETURN_VAL_IF_FAIL(surf->info.format > 0, 0);
255
256         if (!mgr->backend->surface_get_plane_data)
257                 return 0;
258
259         ret = mgr->backend->surface_get_plane_data(surf->info.width,
260                         surf->info.height, surf->info.format, plane_idx, size, offset, pitch, bo_idx);
261         if (!ret)
262                 return 0;
263
264         return 1;
265 }
266
267 static void
268 _tbm_surface_internal_destroy(tbm_surface_h surface)
269 {
270         int i;
271         tbm_bufmgr bufmgr = surface->bufmgr;
272         tbm_user_data *old_data = NULL, *tmp = NULL;
273
274         for (i = 0; i < surface->num_bos; i++) {
275                 surface->bos[i]->surface = NULL;
276
277                 tbm_bo_unref(surface->bos[i]);
278                 surface->bos[i] = NULL;
279         }
280
281         /* destory the user_data_list */
282         if (!LIST_IS_EMPTY(&surface->user_data_list)) {
283                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &surface->user_data_list, item_link) {
284                         DBG("free user_data\n");
285                         user_data_delete(old_data);
286                 }
287         }
288
289         LIST_DEL(&surface->item_link);
290
291         free(surface);
292         surface = NULL;
293
294         if (LIST_IS_EMPTY(&bufmgr->surf_list)) {
295                 LIST_DELINIT(&bufmgr->surf_list);
296                 _deinit_surface_bufmgr();
297         }
298 }
299
300 int
301 tbm_surface_internal_is_valid(tbm_surface_h surface)
302 {
303         tbm_surface_h old_data = NULL, tmp = NULL;
304
305         if (surface == NULL || g_surface_bufmgr == NULL) {
306                 TBM_TRACE("error: tbm_surface(%p)\n", surface);
307                 return 0;
308         }
309
310         if (!LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
311                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &g_surface_bufmgr->surf_list, item_link) {
312                         if (old_data == surface) {
313                                 TBM_TRACE("tbm_surface(%p)\n", surface);
314                                 return 1;
315                         }
316                 }
317         }
318         TBM_TRACE("error: tbm_surface(%p)\n", surface);
319         return 0;
320 }
321
322 int
323 tbm_surface_internal_query_supported_formats(uint32_t **formats,
324                 uint32_t *num)
325 {
326         struct _tbm_bufmgr *mgr;
327         int ret = 0;
328
329         _tbm_surface_mutex_lock();
330
331         if (!g_surface_bufmgr) {
332                 _init_surface_bufmgr();
333                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
334         }
335
336         mgr = g_surface_bufmgr;
337
338         if (!mgr->backend->surface_supported_format) {
339                 TBM_TRACE("error: tbm_bufmgr(%p)\n", g_surface_bufmgr);
340                 _tbm_surface_mutex_unlock();
341                 return 0;
342         }
343
344         ret = mgr->backend->surface_supported_format(formats, num);
345
346         TBM_TRACE("tbm_bufmgr(%p) format num(%d)\n", g_surface_bufmgr, *num);
347
348         _tbm_surface_mutex_unlock();
349
350         return ret;
351 }
352
353 int
354 tbm_surface_internal_get_num_planes(tbm_format format)
355 {
356         int num_planes = 0;
357
358         switch (format) {
359         case TBM_FORMAT_C8:
360         case TBM_FORMAT_RGB332:
361         case TBM_FORMAT_BGR233:
362         case TBM_FORMAT_XRGB4444:
363         case TBM_FORMAT_XBGR4444:
364         case TBM_FORMAT_RGBX4444:
365         case TBM_FORMAT_BGRX4444:
366         case TBM_FORMAT_ARGB4444:
367         case TBM_FORMAT_ABGR4444:
368         case TBM_FORMAT_RGBA4444:
369         case TBM_FORMAT_BGRA4444:
370         case TBM_FORMAT_XRGB1555:
371         case TBM_FORMAT_XBGR1555:
372         case TBM_FORMAT_RGBX5551:
373         case TBM_FORMAT_BGRX5551:
374         case TBM_FORMAT_ARGB1555:
375         case TBM_FORMAT_ABGR1555:
376         case TBM_FORMAT_RGBA5551:
377         case TBM_FORMAT_BGRA5551:
378         case TBM_FORMAT_RGB565:
379         case TBM_FORMAT_BGR565:
380         case TBM_FORMAT_RGB888:
381         case TBM_FORMAT_BGR888:
382         case TBM_FORMAT_XRGB8888:
383         case TBM_FORMAT_XBGR8888:
384         case TBM_FORMAT_RGBX8888:
385         case TBM_FORMAT_BGRX8888:
386         case TBM_FORMAT_ARGB8888:
387         case TBM_FORMAT_ABGR8888:
388         case TBM_FORMAT_RGBA8888:
389         case TBM_FORMAT_BGRA8888:
390         case TBM_FORMAT_XRGB2101010:
391         case TBM_FORMAT_XBGR2101010:
392         case TBM_FORMAT_RGBX1010102:
393         case TBM_FORMAT_BGRX1010102:
394         case TBM_FORMAT_ARGB2101010:
395         case TBM_FORMAT_ABGR2101010:
396         case TBM_FORMAT_RGBA1010102:
397         case TBM_FORMAT_BGRA1010102:
398         case TBM_FORMAT_YUYV:
399         case TBM_FORMAT_YVYU:
400         case TBM_FORMAT_UYVY:
401         case TBM_FORMAT_VYUY:
402         case TBM_FORMAT_AYUV:
403                 num_planes = 1;
404                 break;
405         case TBM_FORMAT_NV12:
406         case TBM_FORMAT_NV12MT:
407         case TBM_FORMAT_NV21:
408         case TBM_FORMAT_NV16:
409         case TBM_FORMAT_NV61:
410                 num_planes = 2;
411                 break;
412         case TBM_FORMAT_YUV410:
413         case TBM_FORMAT_YVU410:
414         case TBM_FORMAT_YUV411:
415         case TBM_FORMAT_YVU411:
416         case TBM_FORMAT_YUV420:
417         case TBM_FORMAT_YVU420:
418         case TBM_FORMAT_YUV422:
419         case TBM_FORMAT_YVU422:
420         case TBM_FORMAT_YUV444:
421         case TBM_FORMAT_YVU444:
422                 num_planes = 3;
423                 break;
424
425         default:
426                 break;
427         }
428
429         TBM_TRACE("tbm_format(%s) num_planes(%d)\n", _tbm_surface_internal_format_to_str(format), num_planes);
430
431         return num_planes;
432 }
433
434 int
435 tbm_surface_internal_get_bpp(tbm_format format)
436 {
437
438         int bpp = 0;
439
440         switch (format) {
441         case TBM_FORMAT_C8:
442         case TBM_FORMAT_RGB332:
443         case TBM_FORMAT_BGR233:
444                 bpp = 8;
445                 break;
446         case TBM_FORMAT_XRGB4444:
447         case TBM_FORMAT_XBGR4444:
448         case TBM_FORMAT_RGBX4444:
449         case TBM_FORMAT_BGRX4444:
450         case TBM_FORMAT_ARGB4444:
451         case TBM_FORMAT_ABGR4444:
452         case TBM_FORMAT_RGBA4444:
453         case TBM_FORMAT_BGRA4444:
454         case TBM_FORMAT_XRGB1555:
455         case TBM_FORMAT_XBGR1555:
456         case TBM_FORMAT_RGBX5551:
457         case TBM_FORMAT_BGRX5551:
458         case TBM_FORMAT_ARGB1555:
459         case TBM_FORMAT_ABGR1555:
460         case TBM_FORMAT_RGBA5551:
461         case TBM_FORMAT_BGRA5551:
462         case TBM_FORMAT_RGB565:
463         case TBM_FORMAT_BGR565:
464                 bpp = 16;
465                 break;
466         case TBM_FORMAT_RGB888:
467         case TBM_FORMAT_BGR888:
468                 bpp = 24;
469                 break;
470         case TBM_FORMAT_XRGB8888:
471         case TBM_FORMAT_XBGR8888:
472         case TBM_FORMAT_RGBX8888:
473         case TBM_FORMAT_BGRX8888:
474         case TBM_FORMAT_ARGB8888:
475         case TBM_FORMAT_ABGR8888:
476         case TBM_FORMAT_RGBA8888:
477         case TBM_FORMAT_BGRA8888:
478         case TBM_FORMAT_XRGB2101010:
479         case TBM_FORMAT_XBGR2101010:
480         case TBM_FORMAT_RGBX1010102:
481         case TBM_FORMAT_BGRX1010102:
482         case TBM_FORMAT_ARGB2101010:
483         case TBM_FORMAT_ABGR2101010:
484         case TBM_FORMAT_RGBA1010102:
485         case TBM_FORMAT_BGRA1010102:
486         case TBM_FORMAT_YUYV:
487         case TBM_FORMAT_YVYU:
488         case TBM_FORMAT_UYVY:
489         case TBM_FORMAT_VYUY:
490         case TBM_FORMAT_AYUV:
491                 bpp = 32;
492                 break;
493         case TBM_FORMAT_NV12:
494         case TBM_FORMAT_NV12MT:
495         case TBM_FORMAT_NV21:
496                 bpp = 12;
497                 break;
498         case TBM_FORMAT_NV16:
499         case TBM_FORMAT_NV61:
500                 bpp = 16;
501                 break;
502         case TBM_FORMAT_YUV410:
503         case TBM_FORMAT_YVU410:
504                 bpp = 9;
505                 break;
506         case TBM_FORMAT_YUV411:
507         case TBM_FORMAT_YVU411:
508         case TBM_FORMAT_YUV420:
509         case TBM_FORMAT_YVU420:
510                 bpp = 12;
511                 break;
512         case TBM_FORMAT_YUV422:
513         case TBM_FORMAT_YVU422:
514                 bpp = 16;
515                 break;
516         case TBM_FORMAT_YUV444:
517         case TBM_FORMAT_YVU444:
518                 bpp = 24;
519                 break;
520         default:
521                 break;
522         }
523
524         TBM_TRACE("tbm_format(%s) bpp(%d)\n", _tbm_surface_internal_format_to_str(format), bpp);
525
526         return bpp;
527 }
528
529 tbm_surface_h
530 tbm_surface_internal_create_with_flags(int width, int height,
531                                        int format, int flags)
532 {
533         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
534         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
535
536         struct _tbm_bufmgr *mgr;
537         struct _tbm_surface *surf = NULL;
538         uint32_t size = 0;
539         uint32_t offset = 0;
540         uint32_t stride = 0;
541         uint32_t bo_size = 0;
542         int bo_idx;
543         int i, j;
544
545         _tbm_surface_mutex_lock();
546
547         if (!g_surface_bufmgr) {
548                 _init_surface_bufmgr();
549                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
550         }
551
552         mgr = g_surface_bufmgr;
553         if (!TBM_BUFMGR_IS_VALID(mgr)) {
554                 TBM_TRACE("error: width(%d) height(%d) format(%s) flags(%d)\n",
555                                 width, height, _tbm_surface_internal_format_to_str(format), flags);
556                 _tbm_surface_mutex_unlock();
557                 return NULL;
558         }
559         surf = calloc(1, sizeof(struct _tbm_surface));
560         if (!surf) {
561                 TBM_TRACE("error: width(%d) height(%d) format(%s) flags(%d)\n",
562                                 width, height, _tbm_surface_internal_format_to_str(format), flags);
563                 _tbm_surface_mutex_unlock();
564                 return NULL;
565         }
566
567         surf->bufmgr = mgr;
568         surf->info.width = width;
569         surf->info.height = height;
570         surf->info.format = format;
571         surf->info.bpp = tbm_surface_internal_get_bpp(format);
572         surf->info.num_planes = tbm_surface_internal_get_num_planes(format);
573         surf->refcnt = 1;
574
575         /* get size, stride and offset bo_idx */
576         for (i = 0; i < surf->info.num_planes; i++) {
577                 _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride,
578                                                        &bo_idx);
579                 surf->info.planes[i].size = size;
580                 surf->info.planes[i].offset = offset;
581                 surf->info.planes[i].stride = stride;
582                 surf->planes_bo_idx[i] = bo_idx;
583         }
584
585         surf->num_bos = 1;
586
587         for (i = 0; i < surf->info.num_planes; i++) {
588                 surf->info.size += surf->info.planes[i].size;
589
590                 if (surf->num_bos < surf->planes_bo_idx[i] + 1)
591                         surf->num_bos = surf->planes_bo_idx[i] + 1;
592         }
593
594         surf->flags = flags;
595
596         for (i = 0; i < surf->num_bos; i++) {
597                 bo_size = 0;
598                 for (j = 0; j < surf->info.num_planes; j++) {
599                         if (surf->planes_bo_idx[j] == i)
600                                 bo_size += surf->info.planes[j].size;
601                 }
602
603                 if (mgr->backend->surface_bo_alloc) {
604                         /* LCOV_EXCL_START */
605                         tbm_bo bo = NULL;
606                         void *bo_priv = NULL;
607
608                         bo = calloc(1, sizeof(struct _tbm_bo));
609                         if (!bo) {
610                                 TBM_LOG_E("fail to alloc bo struct\n");
611                                 goto alloc_fail;
612                         }
613
614                         bo->bufmgr = surf->bufmgr;
615
616                         pthread_mutex_lock(&surf->bufmgr->lock);
617
618                         bo_priv = mgr->backend->surface_bo_alloc(bo, width, height, format, flags, i);
619                         if (!bo_priv) {
620                                 TBM_LOG_E("fail to alloc bo priv\n");
621                                 free(bo);
622                                 pthread_mutex_unlock(&surf->bufmgr->lock);
623                                 goto alloc_fail;
624                         }
625
626                         bo->ref_cnt = 1;
627                         bo->flags = flags;
628                         bo->priv = bo_priv;
629
630                         LIST_INITHEAD(&bo->user_data_list);
631
632                         LIST_ADD(&bo->item_link, &surf->bufmgr->bo_list);
633
634                         pthread_mutex_unlock(&surf->bufmgr->lock);
635
636                         surf->bos[i] = bo;
637                         /* LCOV_EXCL_STOP */
638                 } else {
639                         surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
640                 }
641
642                 if (!surf->bos[i]) {
643                         TBM_LOG_E("fail to alloc bo idx:%d\n", i);
644                         goto alloc_fail;
645                 }
646
647                 _tbm_bo_set_surface(surf->bos[i], surf);
648
649         }
650
651         TBM_TRACE("width(%d) height(%d) format(%s) flags(%d) tbm_surface(%p)\n", width, height,
652                         _tbm_surface_internal_format_to_str(format), flags, surf);
653
654         LIST_INITHEAD(&surf->user_data_list);
655
656         LIST_ADD(&surf->item_link, &mgr->surf_list);
657
658         _tbm_surface_mutex_unlock();
659
660         return surf;
661
662 alloc_fail:
663
664         TBM_TRACE("error: width(%d) height(%d) format(%s) flags(%d)\n",
665                         width, height, _tbm_surface_internal_format_to_str(format), flags);
666
667         for (j = 0; j < i; j++) {
668                 if (surf->bos[j])
669                         tbm_bo_unref(surf->bos[j]);
670         }
671
672         free(surf);
673         surf = NULL;
674
675         if (LIST_IS_EMPTY(&mgr->surf_list)) {
676                 LIST_DELINIT(&mgr->surf_list);
677                 _deinit_surface_bufmgr();
678         }
679
680         _tbm_surface_mutex_unlock();
681         return NULL;
682 }
683
684 tbm_surface_h
685 tbm_surface_internal_create_with_bos(tbm_surface_info_s *info,
686                                      tbm_bo *bos, int num)
687 {
688         TBM_RETURN_VAL_IF_FAIL(bos, NULL);
689         TBM_RETURN_VAL_IF_FAIL(info, NULL);
690         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
691
692         struct _tbm_bufmgr *mgr;
693         struct _tbm_surface *surf = NULL;
694         int i;
695
696         _tbm_surface_mutex_lock();
697
698         if (!g_surface_bufmgr) {
699                 _init_surface_bufmgr();
700                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
701         }
702
703         mgr = g_surface_bufmgr;
704         if (!TBM_BUFMGR_IS_VALID(mgr)) {
705                 TBM_TRACE("error: width(%d) height(%d) format(%s) bo_num(%d)\n",
706                                 info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
707                 _tbm_surface_mutex_unlock();
708                 return NULL;
709         }
710
711         surf = calloc(1, sizeof(struct _tbm_surface));
712         if (!surf) {
713                 TBM_TRACE("error: width(%d) height(%d) format(%s) bo_num(%d)\n",
714                                 info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
715                 _tbm_surface_mutex_unlock();
716                 return NULL;
717         }
718
719         surf->bufmgr = mgr;
720         surf->info.width = info->width;
721         surf->info.height = info->height;
722         surf->info.format = info->format;
723         surf->info.bpp = info->bpp;
724         surf->info.num_planes = info->num_planes;
725         surf->refcnt = 1;
726
727         /* get size, stride and offset */
728         for (i = 0; i < info->num_planes; i++) {
729                 surf->info.planes[i].offset = info->planes[i].offset;
730                 surf->info.planes[i].stride = info->planes[i].stride;
731
732                 if (info->planes[i].size > 0)
733                         surf->info.planes[i].size = info->planes[i].size;
734                 else
735                         surf->info.planes[i].size += surf->info.planes[i].stride * info->height;
736
737                 if (num == 1)
738                         surf->planes_bo_idx[i] = 0;
739                 else
740                         surf->planes_bo_idx[i] = i;
741         }
742
743         if (info->size > 0) {
744                 surf->info.size = info->size;
745         } else {
746                 surf->info.size = 0;
747                 for (i = 0; i < info->num_planes; i++)
748                         surf->info.size += surf->info.planes[i].size;
749         }
750
751         surf->flags = TBM_BO_DEFAULT;
752
753         /* create only one bo */
754         surf->num_bos = num;
755         for (i = 0; i < num; i++) {
756                 if (bos[i] == NULL)
757                         goto bail1;
758
759                 surf->bos[i] = tbm_bo_ref(bos[i]);
760                 _tbm_bo_set_surface(bos[i], surf);
761         }
762
763         TBM_TRACE("tbm_surface(%p) width(%d) height(%d) format(%s) bo_num(%d)\n", surf,
764                         info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
765
766         LIST_INITHEAD(&surf->user_data_list);
767
768         LIST_ADD(&surf->item_link, &mgr->surf_list);
769
770         _tbm_surface_mutex_unlock();
771
772         return surf;
773 bail1:
774         TBM_TRACE("error: width(%d) height(%d) format(%s) bo_num(%d)\n",
775                                 info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
776         for (i = 0; i < num; i++) {
777                 if (surf->bos[i]) {
778                         tbm_bo_unref(surf->bos[i]);
779                         surf->bos[i] = NULL;
780                 }
781         }
782
783         free(surf);
784         surf = NULL;
785
786         if (LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
787                 LIST_DELINIT(&g_surface_bufmgr->surf_list);
788                 _deinit_surface_bufmgr();
789         }
790
791         _tbm_surface_mutex_unlock();
792
793         return NULL;
794 }
795
796 void
797 tbm_surface_internal_destroy(tbm_surface_h surface)
798 {
799         if (!tbm_surface_internal_is_valid(surface))
800                 return;
801
802         _tbm_surface_mutex_lock();
803
804         surface->refcnt--;
805
806         if (surface->refcnt > 0) {
807                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
808                 _tbm_surface_mutex_unlock();
809                 return;
810         }
811
812         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
813
814         if (surface->refcnt == 0)
815                 _tbm_surface_internal_destroy(surface);
816
817         _tbm_surface_mutex_unlock();
818 }
819
820 void
821 tbm_surface_internal_ref(tbm_surface_h surface)
822 {
823         TBM_RETURN_IF_FAIL(tbm_surface_internal_is_valid(surface));
824
825         _tbm_surface_mutex_lock();
826
827         surface->refcnt++;
828
829         TBM_TRACE("tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
830
831         _tbm_surface_mutex_unlock();
832 }
833
834 void
835 tbm_surface_internal_unref(tbm_surface_h surface)
836 {
837         TBM_RETURN_IF_FAIL(tbm_surface_internal_is_valid(surface));
838
839         _tbm_surface_mutex_lock();
840
841         surface->refcnt--;
842
843         if (surface->refcnt > 0) {
844                 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
845                 _tbm_surface_mutex_unlock();
846                 return;
847         }
848
849         TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
850
851         if (surface->refcnt == 0)
852                 _tbm_surface_internal_destroy(surface);
853
854         _tbm_surface_mutex_unlock();
855 }
856
857 int
858 tbm_surface_internal_get_num_bos(tbm_surface_h surface)
859 {
860         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
861
862         struct _tbm_surface *surf;
863         int num;
864
865         _tbm_surface_mutex_lock();
866
867         surf = (struct _tbm_surface *)surface;
868         num = surf->num_bos;
869
870         TBM_TRACE("tbm_surface(%p) num_bos(%d)\n", surface, num);
871
872         _tbm_surface_mutex_unlock();
873
874         return num;
875 }
876
877 tbm_bo
878 tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
879 {
880         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), NULL);
881         TBM_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
882
883         struct _tbm_surface *surf;
884         tbm_bo bo;
885
886         _tbm_surface_mutex_lock();
887
888         surf = (struct _tbm_surface *)surface;
889         bo = surf->bos[bo_idx];
890
891         TBM_TRACE("tbm_surface(%p) bo_idx(%d) tbm_bo(%p)\n", surface, bo_idx, bo);
892
893         _tbm_surface_mutex_unlock();
894
895         return bo;
896 }
897
898 int
899 tbm_surface_internal_get_size(tbm_surface_h surface)
900 {
901         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
902
903         struct _tbm_surface *surf;
904         unsigned int size;
905
906         _tbm_surface_mutex_lock();
907
908         surf = (struct _tbm_surface *)surface;
909         size = surf->info.size;
910
911         TBM_TRACE("tbm_surface(%p) size(%d)\n", surface, size);
912
913         _tbm_surface_mutex_unlock();
914
915         return size;
916 }
917
918 int
919 tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx,
920                                     uint32_t *size, uint32_t *offset, uint32_t *pitch)
921 {
922         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
923         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
924
925         struct _tbm_surface *surf;
926
927         _tbm_surface_mutex_lock();
928
929         surf = (struct _tbm_surface *)surface;
930
931         if (plane_idx >= surf->info.num_planes) {
932                 TBM_TRACE("error: tbm_surface(%p) plane_idx(%d)\n", surface, plane_idx);
933                 _tbm_surface_mutex_unlock();
934                 return 0;
935         }
936
937         if (size)
938                 *size = surf->info.planes[plane_idx].size;
939
940         if (offset)
941                 *offset = surf->info.planes[plane_idx].offset;
942
943         if (pitch)
944                 *pitch = surf->info.planes[plane_idx].stride;
945
946         TBM_TRACE("tbm_surface(%p) plane_idx(%d) size(%d) offset(%d) pitch(%d)\n", surface, plane_idx,
947                                 surf->info.planes[plane_idx].size, surf->info.planes[plane_idx].offset,
948                                 surf->info.planes[plane_idx].stride);
949
950         _tbm_surface_mutex_unlock();
951
952         return 1;
953 }
954
955 int
956 tbm_surface_internal_get_info(tbm_surface_h surface, int opt,
957                               tbm_surface_info_s *info, int map)
958 {
959         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
960
961         struct _tbm_surface *surf;
962         tbm_bo_handle bo_handles[4];
963         int i, j;
964
965         _tbm_surface_mutex_lock();
966
967         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
968
969         surf = (struct _tbm_surface *)surface;
970
971         memset(info, 0x00, sizeof(tbm_surface_info_s));
972         info->width = surf->info.width;
973         info->height = surf->info.height;
974         info->format = surf->info.format;
975         info->bpp = surf->info.bpp;
976         info->size = surf->info.size;
977         info->num_planes = surf->info.num_planes;
978
979         if (map == 1) {
980                 for (i = 0; i < surf->num_bos; i++) {
981                         bo_handles[i] = tbm_bo_map(surf->bos[i], TBM_DEVICE_CPU, opt);
982                         if (bo_handles[i].ptr == NULL) {
983                                 for (j = 0; j < i; j++)
984                                         tbm_bo_unmap(surf->bos[j]);
985
986                                 TBM_TRACE("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
987                                 _tbm_surface_mutex_unlock();
988                                 return 0;
989                         }
990                 }
991         } else {
992                 for (i = 0; i < surf->num_bos; i++)
993                         bo_handles[i] = tbm_bo_get_handle(surf->bos[i], TBM_DEVICE_CPU);
994         }
995
996         for (i = 0; i < surf->info.num_planes; i++) {
997                 info->planes[i].size = surf->info.planes[i].size;
998                 info->planes[i].offset = surf->info.planes[i].offset;
999                 info->planes[i].stride = surf->info.planes[i].stride;
1000
1001                 if (bo_handles[surf->planes_bo_idx[i]].ptr)
1002                         info->planes[i].ptr = bo_handles[surf->planes_bo_idx[i]].ptr +
1003                                               surf->info.planes[i].offset;
1004         }
1005
1006         TBM_TRACE("tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1007
1008         _tbm_surface_mutex_unlock();
1009
1010         return 1;
1011 }
1012
1013 void
1014 tbm_surface_internal_unmap(tbm_surface_h surface)
1015 {
1016         TBM_RETURN_IF_FAIL(tbm_surface_internal_is_valid(surface));
1017
1018         struct _tbm_surface *surf;
1019         int i;
1020
1021         _tbm_surface_mutex_lock();
1022
1023         surf = (struct _tbm_surface *)surface;
1024
1025         for (i = 0; i < surf->num_bos; i++)
1026                 tbm_bo_unmap(surf->bos[i]);
1027
1028         TBM_TRACE("tbm_surface(%p)\n", surface);
1029
1030         _tbm_surface_mutex_unlock();
1031 }
1032
1033 unsigned int
1034 tbm_surface_internal_get_width(tbm_surface_h surface)
1035 {
1036         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1037
1038         struct _tbm_surface *surf;
1039         unsigned int width;
1040
1041         _tbm_surface_mutex_lock();
1042
1043         surf = (struct _tbm_surface *)surface;
1044         width = surf->info.width;
1045
1046         TBM_TRACE("tbm_surface(%p) width(%d)\n", surface, width);
1047
1048         _tbm_surface_mutex_unlock();
1049
1050         return width;
1051 }
1052
1053 unsigned int
1054 tbm_surface_internal_get_height(tbm_surface_h surface)
1055 {
1056         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1057
1058         struct _tbm_surface *surf;
1059         unsigned int height;
1060
1061         _tbm_surface_mutex_lock();
1062
1063         surf = (struct _tbm_surface *)surface;
1064         height = surf->info.height;
1065
1066         TBM_TRACE("tbm_surface(%p) height(%d)\n", surface, height);
1067
1068         _tbm_surface_mutex_unlock();
1069
1070         return height;
1071
1072 }
1073
1074 tbm_format
1075 tbm_surface_internal_get_format(tbm_surface_h surface)
1076 {
1077         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1078
1079         struct _tbm_surface *surf;
1080         tbm_format format;
1081
1082         _tbm_surface_mutex_lock();
1083
1084         surf = (struct _tbm_surface *)surface;
1085         format = surf->info.format;
1086
1087         TBM_TRACE("tbm_surface(%p) format(%s)\n", surface, _tbm_surface_internal_format_to_str(format));
1088
1089         _tbm_surface_mutex_unlock();
1090
1091         return format;
1092 }
1093
1094 int
1095 tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
1096 {
1097         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1098         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1099         struct _tbm_surface *surf;
1100         int bo_idx;
1101
1102         _tbm_surface_mutex_lock();
1103
1104         surf = (struct _tbm_surface *)surface;
1105         bo_idx = surf->planes_bo_idx[plane_idx];
1106
1107         TBM_TRACE("tbm_surface(%p) plane_idx(%d) bo_idx(%d)\n", surface, plane_idx, bo_idx);
1108
1109         _tbm_surface_mutex_unlock();
1110
1111         return bo_idx;
1112 }
1113
1114 int
1115 tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key,
1116                                    tbm_data_free data_free_func)
1117 {
1118         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1119
1120         tbm_user_data *data;
1121
1122         /* check if the data according to the key exist if so, return false. */
1123         data = user_data_lookup(&surface->user_data_list, key);
1124         if (data) {
1125                 TBM_TRACE("warning: user data already exist tbm_surface(%p) key(%lu)\n", surface, key);
1126                 return 0;
1127         }
1128
1129         data = user_data_create(key, data_free_func);
1130         if (!data) {
1131                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1132                 return 0;
1133         }
1134
1135         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, data);
1136
1137         LIST_ADD(&data->item_link, &surface->user_data_list);
1138
1139         return 1;
1140 }
1141
1142 int
1143 tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key,
1144                                    void *data)
1145 {
1146         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1147
1148         tbm_user_data *old_data;
1149
1150         if (LIST_IS_EMPTY(&surface->user_data_list)) {
1151                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1152                 return 0;
1153         }
1154
1155         old_data = user_data_lookup(&surface->user_data_list, key);
1156         if (!old_data) {
1157                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1158                 return 0;
1159         }
1160
1161         if (old_data->data && old_data->free_func)
1162                 old_data->free_func(old_data->data);
1163
1164         old_data->data = data;
1165
1166         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1167
1168         return 1;
1169 }
1170
1171 int
1172 tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key,
1173                                    void **data)
1174 {
1175         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1176
1177         tbm_user_data *old_data;
1178
1179         if (!data || LIST_IS_EMPTY(&surface->user_data_list)) {
1180                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1181                 return 0;
1182         }
1183
1184         old_data = user_data_lookup(&surface->user_data_list, key);
1185         if (!old_data) {
1186                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1187                 *data = NULL;
1188                 return 0;
1189         }
1190
1191         *data = old_data->data;
1192
1193         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1194
1195         return 1;
1196 }
1197
1198 int
1199 tbm_surface_internal_delete_user_data(tbm_surface_h surface,
1200                                       unsigned long key)
1201 {
1202         TBM_RETURN_VAL_IF_FAIL(tbm_surface_internal_is_valid(surface), 0);
1203
1204         tbm_user_data *old_data = (void *)0;
1205
1206         if (LIST_IS_EMPTY(&surface->user_data_list)) {
1207                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1208                 return 0;
1209         }
1210
1211         old_data = user_data_lookup(&surface->user_data_list, key);
1212         if (!old_data) {
1213                 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1214                 return 0;
1215         }
1216
1217         TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1218
1219         user_data_delete(old_data);
1220
1221         return 1;
1222 }
1223
1224 /* LCOV_EXCL_START */
1225 unsigned int
1226 _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
1227 {
1228         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1229
1230         return surface->debug_pid;
1231 }
1232
1233 void
1234 tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
1235 {
1236         TBM_RETURN_IF_FAIL(tbm_surface_internal_is_valid(surface));
1237
1238         surface->debug_pid = pid;
1239 }
1240
1241 typedef struct _tbm_surface_dump_info tbm_surface_dump_info;
1242 typedef struct _tbm_surface_dump_buf_info tbm_surface_dump_buf_info;
1243
1244 struct _tbm_surface_dump_buf_info {
1245         int index;
1246         tbm_bo bo;
1247         int size;
1248         int dirty;
1249         int dirty_shm;
1250         int shm_stride;
1251         int shm_h;
1252         char name[1024];
1253
1254         tbm_surface_info_s info;
1255
1256         struct list_head link;
1257 };
1258
1259 struct _tbm_surface_dump_info {
1260         char *path;  // copy???
1261         int dump_max;
1262         int count;
1263         struct list_head *link;
1264         struct list_head surface_list; /* link of surface */
1265 };
1266
1267 static tbm_surface_dump_info *g_dump_info = NULL;
1268 static const char *dump_postfix[2] = {"png", "yuv"};
1269
1270 static void
1271 _tbm_surface_internal_dump_file_raw(const char *file, void *data1, int size1, void *data2,
1272                 int size2, void *data3, int size3)
1273 {
1274         unsigned int *blocks;
1275         FILE *fp = fopen(file, "w+");
1276         TBM_RETURN_IF_FAIL(fp != NULL);
1277
1278         blocks = (unsigned int *)data1;
1279         fwrite(blocks, 1, size1, fp);
1280
1281         if (size2 > 0) {
1282                 blocks = (unsigned int *)data2;
1283                 fwrite(blocks, 1, size2, fp);
1284         }
1285
1286         if (size3 > 0) {
1287                 blocks = (unsigned int *)data3;
1288                 fwrite(blocks, 1, size3, fp);
1289         }
1290
1291         fclose(fp);
1292 }
1293
1294 static void
1295 _tbm_surface_internal_dump_file_png(const char *file, const void *data, int width,
1296                 int height)
1297 {
1298         FILE *fp = fopen(file, "wb");
1299         TBM_RETURN_IF_FAIL(fp != NULL);
1300         int depth = 8;
1301
1302         png_structp pPngStruct =
1303                 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1304         if (!pPngStruct) {
1305                 fclose(fp);
1306                 return;
1307         }
1308
1309         png_infop pPngInfo = png_create_info_struct(pPngStruct);
1310         if (!pPngInfo) {
1311                 png_destroy_write_struct(&pPngStruct, NULL);
1312                 fclose(fp);
1313                 return;
1314         }
1315
1316         png_init_io(pPngStruct, fp);
1317         png_set_IHDR(pPngStruct,
1318                         pPngInfo,
1319                         width,
1320                         height,
1321                         depth,
1322                         PNG_COLOR_TYPE_RGBA,
1323                         PNG_INTERLACE_NONE,
1324                         PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1325
1326         png_set_bgr(pPngStruct);
1327         png_write_info(pPngStruct, pPngInfo);
1328
1329         const int pixel_size = 4;       // RGBA
1330         png_bytep *row_pointers =
1331                         png_malloc(pPngStruct, height * sizeof(png_byte *));
1332
1333         unsigned int *blocks = (unsigned int *)data;
1334         int y = 0;
1335         int x = 0;
1336
1337         for (; y < height; ++y) {
1338                 png_bytep row =
1339                         png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
1340                 row_pointers[y] = (png_bytep)row;
1341                 for (x = 0; x < width; ++x) {
1342                         unsigned int curBlock = blocks[y * width + x];
1343                         row[x * pixel_size] = (curBlock & 0xFF);
1344                         row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1345                         row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1346                         row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
1347                 }
1348         }
1349
1350         png_write_image(pPngStruct, row_pointers);
1351         png_write_end(pPngStruct, pPngInfo);
1352
1353         for (y = 0; y < height; y++)
1354                 png_free(pPngStruct, row_pointers[y]);
1355         png_free(pPngStruct, row_pointers);
1356
1357         png_destroy_write_struct(&pPngStruct, &pPngInfo);
1358
1359         fclose(fp);
1360 }
1361
1362 void
1363 tbm_surface_internal_dump_start(char *path, int w, int h, int count)
1364 {
1365         TBM_RETURN_IF_FAIL(path != NULL);
1366         TBM_RETURN_IF_FAIL(w > 0);
1367         TBM_RETURN_IF_FAIL(h > 0);
1368         TBM_RETURN_IF_FAIL(count > 0);
1369
1370         tbm_surface_dump_buf_info *buf_info = NULL;
1371         tbm_surface_dump_buf_info *tmp;
1372         tbm_bo bo = NULL;
1373         int i;
1374         int buffer_size;
1375         tbm_surface_h tbm_surface;
1376         tbm_surface_info_s info;
1377         tbm_surface_error_e err;
1378
1379         /* check running */
1380         if (g_dump_info) {
1381                 TBM_LOG_W("waring already running the tbm_surface_internal_dump.\n");
1382                 return;
1383         }
1384
1385         g_dump_info = calloc(1, sizeof(struct _tbm_surface_dump_info));
1386         TBM_RETURN_IF_FAIL(g_dump_info);
1387
1388         LIST_INITHEAD(&g_dump_info->surface_list);
1389         g_dump_info->count = 0;
1390         g_dump_info->dump_max = count;
1391
1392         /* get buffer size */
1393         tbm_surface = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
1394         if (tbm_surface == NULL) {
1395                 TBM_LOG_E("tbm_surface_create fail\n");
1396                 free(g_dump_info);
1397                 g_dump_info = NULL;
1398                 return;
1399         }
1400         err = tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &info);
1401         if (err != TBM_SURFACE_ERROR_NONE) {
1402                 TBM_LOG_E("tbm_surface_map fail\n");
1403                 tbm_surface_destroy(tbm_surface);
1404                 free(g_dump_info);
1405                 g_dump_info = NULL;
1406                 return;
1407         }
1408         buffer_size = info.planes[0].stride * h;
1409         tbm_surface_unmap(tbm_surface);
1410         tbm_surface_destroy(tbm_surface);
1411
1412         /* create dump lists */
1413         for (i = 0; i < count; i++)     {
1414                 buf_info = calloc(1, sizeof(tbm_surface_dump_buf_info));
1415                 TBM_GOTO_VAL_IF_FAIL(buf_info, fail);
1416                 bo = tbm_bo_alloc(g_surface_bufmgr, buffer_size, TBM_BO_DEFAULT);
1417                 if (bo == NULL) {
1418                         free(buf_info);
1419                         goto fail;
1420                 }
1421
1422                 buf_info->index = i;
1423                 buf_info->bo = bo;
1424                 buf_info->size = buffer_size;
1425
1426                 LIST_ADDTAIL(&buf_info->link, &g_dump_info->surface_list);
1427         }
1428
1429         g_dump_info->path = path;
1430         g_dump_info->link = &g_dump_info->surface_list;
1431
1432         TBM_LOG_I("Dump Start.. path:%s, count:%d\n", g_dump_info->path, count);
1433
1434         return;
1435 fail:
1436         /* free resources */
1437         if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1438                 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1439                         tbm_bo_unref(buf_info->bo);
1440                         free(buf_info);
1441                 }
1442         }
1443
1444         TBM_LOG_E("Dump Start fail.. path:%s\n", g_dump_info->path);
1445
1446         free(g_dump_info);
1447         g_dump_info = NULL;
1448
1449         return;
1450 }
1451
1452 void
1453 tbm_surface_internal_dump_end(void)
1454 {
1455         tbm_surface_dump_buf_info *buf_info = NULL, *tmp = NULL;
1456         tbm_bo_handle bo_handle;
1457
1458         if (!g_dump_info)
1459                 return;
1460
1461         /* make files */
1462         if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1463                 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1464                         char file[2048];
1465
1466                         if (buf_info->dirty) {
1467                                 void *ptr1 = NULL;
1468                                 void *ptr2 = NULL;
1469
1470                                 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
1471                                 if (bo_handle.ptr == NULL)
1472                                         continue;
1473
1474                                 snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name);
1475                                 TBM_LOG_I("Dump File.. %s generated.\n", file);
1476
1477                                 switch (buf_info->info.format) {
1478                                 case TBM_FORMAT_ARGB8888:
1479                                 case TBM_FORMAT_XRGB8888:
1480                                         _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1481                                                                         buf_info->info.planes[0].stride >> 2, buf_info->info.height);
1482                                         break;
1483                                 case TBM_FORMAT_YVU420:
1484                                 case TBM_FORMAT_YUV420:
1485                                         ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1486                                         ptr2 = ptr1 + buf_info->info.planes[1].stride * (buf_info->info.height >> 1);
1487                                         _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1488                                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1489                                                                         ptr1,
1490                                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1491                                                                         ptr2,
1492                                                                         buf_info->info.planes[2].stride * (buf_info->info.height >> 1));
1493                                         break;
1494                                 case TBM_FORMAT_NV12:
1495                                 case TBM_FORMAT_NV21:
1496                                         ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1497                                         _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1498                                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1499                                                                         ptr1,
1500                                                                         buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1501                                                                         NULL, 0);
1502                                         break;
1503                                 case TBM_FORMAT_YUYV:
1504                                 case TBM_FORMAT_UYVY:
1505                                         _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1506                                                                         buf_info->info.planes[0].stride * buf_info->info.height,
1507                                                                         NULL, 0, NULL, 0);
1508                                         break;
1509                                 default:
1510                                         TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(buf_info->info.format));
1511                                         tbm_bo_unmap(buf_info->bo);
1512                                         return;
1513                                 }
1514
1515                                 tbm_bo_unmap(buf_info->bo);
1516                         } else if (buf_info->dirty_shm) {
1517                                 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
1518                                 if (bo_handle.ptr == NULL)
1519                                         continue;
1520
1521                                 snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name);
1522                                 TBM_LOG_I("Dump File.. %s generated.\n", file);
1523
1524                                 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1525                                                                 buf_info->shm_stride >> 2, buf_info->shm_h);
1526
1527                                 tbm_bo_unmap(buf_info->bo);
1528                         }
1529                 }
1530         }
1531
1532
1533         /* free resources */
1534         if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1535                 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1536                         tbm_bo_unref(buf_info->bo);
1537                         free(buf_info);
1538                 }
1539         }
1540
1541         free(g_dump_info);
1542         g_dump_info = NULL;
1543
1544         TBM_LOG_I("Dump End..\n");
1545 }
1546
1547 void
1548 tbm_surface_internal_dump_buffer(tbm_surface_h surface, const char *type)
1549 {
1550         TBM_RETURN_IF_FAIL(surface != NULL);
1551         TBM_RETURN_IF_FAIL(type != NULL);
1552
1553         tbm_surface_dump_buf_info *buf_info;
1554         tbm_surface_info_s info;
1555         struct list_head *next_link;
1556         tbm_bo_handle bo_handle;
1557         int ret;
1558         const char *postfix;
1559
1560         if (!g_dump_info)
1561                 return;
1562
1563         next_link = g_dump_info->link->next;
1564         TBM_RETURN_IF_FAIL(next_link != NULL);
1565
1566         if (next_link == &g_dump_info->surface_list) {
1567                 next_link = next_link->next;
1568                 TBM_RETURN_IF_FAIL(next_link != NULL);
1569         }
1570
1571         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
1572         TBM_RETURN_IF_FAIL(buf_info != NULL);
1573
1574         ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
1575         TBM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
1576
1577         if (info.size > buf_info->size) {
1578                 TBM_LOG_W("Dump skip. surface over created buffer size(%d, %d)\n", info.size, buf_info->size);
1579                 tbm_surface_unmap(surface);
1580                 return;
1581         }
1582
1583         if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
1584                 postfix = dump_postfix[0];
1585         else
1586                 postfix = dump_postfix[1];
1587
1588         /* make the file information */
1589         memcpy(&buf_info->info, &info, sizeof(tbm_surface_info_s));
1590
1591         /* dump */
1592         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
1593         TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL);
1594         memset(bo_handle.ptr, 0x00, buf_info->size);
1595
1596         switch (info.format) {
1597         case TBM_FORMAT_ARGB8888:
1598         case TBM_FORMAT_XRGB8888:
1599                 snprintf(buf_info->name, sizeof(buf_info->name), "%.3f_%03d_%p-%s.%s", _get_time_in_millis() / 1000.0, g_dump_info->count++, surface, type, postfix);
1600                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.size);
1601                 break;
1602         case TBM_FORMAT_YVU420:
1603         case TBM_FORMAT_YUV420:
1604                 snprintf(buf_info->name, sizeof(buf_info->name), "%03d-%s_%dx%d_%c%c%c%c.%s",
1605                                 g_dump_info->count++, type, info.planes[0].stride, info.height, FOURCC_STR(info.format), postfix);
1606                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
1607                 bo_handle.ptr += info.planes[0].stride * info.height;
1608                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
1609                 bo_handle.ptr += info.planes[1].stride * (info.height >> 1);
1610                 memcpy(bo_handle.ptr, info.planes[2].ptr, info.planes[2].stride * (info.height >> 1));
1611                 break;
1612         case TBM_FORMAT_NV12:
1613         case TBM_FORMAT_NV21:
1614                 snprintf(buf_info->name, sizeof(buf_info->name), "%03d-%s_%dx%d_%c%c%c%c.%s",
1615                                 g_dump_info->count++, type, info.planes[0].stride, info.height, FOURCC_STR(info.format), postfix);
1616                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
1617                 bo_handle.ptr += info.planes[0].stride * info.height;
1618                 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
1619                 break;
1620         case TBM_FORMAT_YUYV:
1621         case TBM_FORMAT_UYVY:
1622                 snprintf(buf_info->name, sizeof(buf_info->name), "%03d-%s_%dx%d_%c%c%c%c.%s",
1623                                 g_dump_info->count++, type, info.planes[0].stride, info.height, FOURCC_STR(info.format), postfix);
1624                 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
1625                 break;
1626         default:
1627                 TBM_LOG_E("can't copy %c%c%c%c buffer", FOURCC_STR(info.format));
1628                 tbm_bo_unmap(buf_info->bo);
1629                 return;
1630         }
1631
1632         tbm_bo_unmap(buf_info->bo);
1633
1634         tbm_surface_unmap(surface);
1635
1636         buf_info->dirty = 1;
1637         buf_info->dirty_shm = 0;
1638
1639         if (g_dump_info->count == 1000)
1640                 g_dump_info->count = 0;
1641
1642         g_dump_info->link = next_link;
1643
1644         TBM_LOG_I("Dump %s \n", buf_info->name);
1645 }
1646
1647 void tbm_surface_internal_dump_shm_buffer(void *ptr, int w, int h, int  stride, const char *type)
1648 {
1649         TBM_RETURN_IF_FAIL(ptr != NULL);
1650         TBM_RETURN_IF_FAIL(w > 0);
1651         TBM_RETURN_IF_FAIL(h > 0);
1652         TBM_RETURN_IF_FAIL(stride > 0);
1653         TBM_RETURN_IF_FAIL(type != NULL);
1654
1655         tbm_surface_dump_buf_info *buf_info;
1656         struct list_head *next_link;
1657         tbm_bo_handle bo_handle;
1658
1659         if (!g_dump_info)
1660                 return;
1661
1662         next_link = g_dump_info->link->next;
1663         TBM_RETURN_IF_FAIL(next_link != NULL);
1664
1665         if (next_link == &g_dump_info->surface_list) {
1666                 next_link = next_link->next;
1667                 TBM_RETURN_IF_FAIL(next_link != NULL);
1668         }
1669
1670         buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
1671         TBM_RETURN_IF_FAIL(buf_info != NULL);
1672
1673         if (stride * h > buf_info->size) {
1674                 TBM_LOG_W("Dump skip. shm buffer over created buffer size(%d, %d)\n", stride * h, buf_info->size);
1675                 return;
1676         }
1677
1678         /* dump */
1679         bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
1680         TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL);
1681         memset(bo_handle.ptr, 0x00, buf_info->size);
1682         memset(&buf_info->info, 0x00, sizeof(tbm_surface_info_s));
1683
1684
1685         snprintf(buf_info->name, sizeof(buf_info->name), "%03d-%s.%s", g_dump_info->count++, type, dump_postfix[0]);
1686         memcpy(bo_handle.ptr, ptr, stride * h);
1687
1688         tbm_bo_unmap(buf_info->bo);
1689
1690         buf_info->dirty = 0;
1691         buf_info->dirty_shm = 1;
1692         buf_info->shm_stride = stride;
1693         buf_info->shm_h = h;
1694
1695         if (g_dump_info->count == 1000)
1696                 g_dump_info->count = 0;
1697
1698         g_dump_info->link = next_link;
1699
1700         TBM_LOG_I("Dump %s \n", buf_info->name);
1701 }
1702 /*LCOV_EXCL_STOP*/