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