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