1 /**************************************************************************
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
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.
30 **************************************************************************/
37 #include "tbm_bufmgr.h"
38 #include "tbm_bufmgr_int.h"
39 #include "tbm_surface_internal.h"
44 static tbm_bufmgr g_surface_bufmgr;
45 static pthread_mutex_t tbm_surface_lock;
46 void _tbm_surface_mutex_unlock(void);
48 #define C(b, m) (((b) >> (m)) & 0xFF)
49 #define B(c, s) ((((unsigned int)(c)) & 0xff) << (s))
50 #define FOURCC(a, b, c, d) (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0))
51 #define FOURCC_STR(id) C(id, 0), C(id, 8), C(id, 16), C(id, 24)
52 #define FOURCC_ID(str) FOURCC(((char*)str)[0], ((char*)str)[1], ((char*)str)[2], ((char*)str)[3])
55 #define TBM_SURFACE_RETURN_IF_FAIL(cond) {\
57 TBM_LOG_E("'%s' failed.\n", #cond);\
58 _tbm_surface_mutex_unlock();\
63 #define TBM_SURFACE_RETURN_VAL_IF_FAIL(cond, val) {\
65 TBM_LOG_E("'%s' failed.\n", #cond);\
66 _tbm_surface_mutex_unlock();\
73 _tbm_surface_internal_get_time(void)
78 clock_gettime(CLOCK_MONOTONIC, &tp);
79 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
85 _tbm_surface_internal_debug_data_delete(tbm_surface_debug_data *debug_data)
87 LIST_DEL(&debug_data->item_link);
89 if (debug_data->key) free(debug_data->key);
90 if (debug_data->value) free(debug_data->value);
95 _tbm_surface_internal_format_to_str(tbm_format format)
99 return "TBM_FORMAT_C8";
100 case TBM_FORMAT_RGB332:
101 return "TBM_FORMAT_RGB332";
102 case TBM_FORMAT_BGR233:
103 return "TBM_FORMAT_BGR233";
104 case TBM_FORMAT_XRGB4444:
105 return "TBM_FORMAT_XRGB4444";
106 case TBM_FORMAT_XBGR4444:
107 return "TBM_FORMAT_XBGR4444";
108 case TBM_FORMAT_RGBX4444:
109 return "TBM_FORMAT_RGBX4444";
110 case TBM_FORMAT_BGRX4444:
111 return "TBM_FORMAT_BGRX4444";
112 case TBM_FORMAT_ARGB4444:
113 return "TBM_FORMAT_ARGB4444";
114 case TBM_FORMAT_ABGR4444:
115 return "TBM_FORMAT_ABGR4444";
116 case TBM_FORMAT_RGBA4444:
117 return "TBM_FORMAT_RGBA4444";
118 case TBM_FORMAT_BGRA4444:
119 return "TBM_FORMAT_BGRA4444";
120 case TBM_FORMAT_XRGB1555:
121 return "TBM_FORMAT_XRGB1555";
122 case TBM_FORMAT_XBGR1555:
123 return "TBM_FORMAT_XBGR1555";
124 case TBM_FORMAT_RGBX5551:
125 return "TBM_FORMAT_RGBX5551";
126 case TBM_FORMAT_BGRX5551:
127 return "TBM_FORMAT_BGRX5551";
128 case TBM_FORMAT_ARGB1555:
129 return "TBM_FORMAT_ARGB1555";
130 case TBM_FORMAT_ABGR1555:
131 return "TBM_FORMAT_ABGR1555";
132 case TBM_FORMAT_RGBA5551:
133 return "TBM_FORMAT_RGBA5551";
134 case TBM_FORMAT_BGRA5551:
135 return "TBM_FORMAT_BGRA5551";
136 case TBM_FORMAT_RGB565:
137 return "TBM_FORMAT_RGB565";
138 case TBM_FORMAT_BGR565:
139 return "TBM_FORMAT_BGR565";
140 case TBM_FORMAT_RGB888:
141 return "TBM_FORMAT_RGB888";
142 case TBM_FORMAT_BGR888:
143 return "TBM_FORMAT_BGR888";
144 case TBM_FORMAT_XRGB8888:
145 return "TBM_FORMAT_XRGB8888";
146 case TBM_FORMAT_XBGR8888:
147 return "TBM_FORMAT_XBGR8888";
148 case TBM_FORMAT_RGBX8888:
149 return "TBM_FORMAT_RGBX8888";
150 case TBM_FORMAT_BGRX8888:
151 return "TBM_FORMAT_BGRX8888";
152 case TBM_FORMAT_ARGB8888:
153 return "TBM_FORMAT_ARGB8888";
154 case TBM_FORMAT_ABGR8888:
155 return "TBM_FORMAT_ABGR8888";
156 case TBM_FORMAT_RGBA8888:
157 return "TBM_FORMAT_RGBA8888";
158 case TBM_FORMAT_BGRA8888:
159 return "TBM_FORMAT_BGRA8888";
160 case TBM_FORMAT_XRGB2101010:
161 return "TBM_FORMAT_XRGB2101010";
162 case TBM_FORMAT_XBGR2101010:
163 return "TBM_FORMAT_XBGR2101010";
164 case TBM_FORMAT_RGBX1010102:
165 return "TBM_FORMAT_RGBX1010102";
166 case TBM_FORMAT_BGRX1010102:
167 return "TBM_FORMAT_BGRX1010102";
168 case TBM_FORMAT_ARGB2101010:
169 return "TBM_FORMAT_ARGB2101010";
170 case TBM_FORMAT_ABGR2101010:
171 return "TBM_FORMAT_ABGR2101010";
172 case TBM_FORMAT_RGBA1010102:
173 return "TBM_FORMAT_RGBA1010102";
174 case TBM_FORMAT_BGRA1010102:
175 return "TBM_FORMAT_BGRA1010102";
176 case TBM_FORMAT_YUYV:
177 return "TBM_FORMAT_YUYV";
178 case TBM_FORMAT_YVYU:
179 return "TBM_FORMAT_YVYU";
180 case TBM_FORMAT_UYVY:
181 return "TBM_FORMAT_UYVY";
182 case TBM_FORMAT_VYUY:
183 return "TBM_FORMAT_VYUY";
184 case TBM_FORMAT_AYUV:
185 return "TBM_FORMAT_AYUV";
186 case TBM_FORMAT_NV12:
187 return "TBM_FORMAT_NV12";
188 case TBM_FORMAT_NV21:
189 return "TBM_FORMAT_NV21";
190 case TBM_FORMAT_NV16:
191 return "TBM_FORMAT_NV16";
192 case TBM_FORMAT_NV61:
193 return "TBM_FORMAT_NV61";
194 case TBM_FORMAT_YUV410:
195 return "TBM_FORMAT_YUV410";
196 case TBM_FORMAT_YVU410:
197 return "TBM_FORMAT_YVU410";
198 case TBM_FORMAT_YUV411:
199 return "TBM_FORMAT_YUV411";
200 case TBM_FORMAT_YVU411:
201 return "TBM_FORMAT_YVU411";
202 case TBM_FORMAT_YUV420:
203 return "TBM_FORMAT_YUV420";
204 case TBM_FORMAT_YVU420:
205 return "TBM_FORMAT_YVU420";
206 case TBM_FORMAT_YUV422:
207 return "TBM_FORMAT_YUV422";
208 case TBM_FORMAT_YVU422:
209 return "TBM_FORMAT_YVU422";
210 case TBM_FORMAT_YUV444:
211 return "TBM_FORMAT_YUV444";
212 case TBM_FORMAT_YVU444:
213 return "TBM_FORMAT_YVU444";
214 case TBM_FORMAT_NV12MT:
215 return "TBM_FORMAT_NV12MT";
222 _tbm_surface_mutex_init(void)
224 static bool tbm_surface_mutex_init = false;
226 if (tbm_surface_mutex_init)
229 if (pthread_mutex_init(&tbm_surface_lock, NULL)) {
230 TBM_LOG_E("fail: pthread_mutex_init for tbm_surface_lock.\n");
234 tbm_surface_mutex_init = true;
240 _tbm_surface_mutex_lock(void)
242 if (!_tbm_surface_mutex_init()) {
243 TBM_LOG_E("fail: _tbm_surface_mutex_init.\n");
247 pthread_mutex_lock(&tbm_surface_lock);
251 _tbm_surface_mutex_unlock(void)
253 pthread_mutex_unlock(&tbm_surface_lock);
257 _init_surface_bufmgr(void)
259 g_surface_bufmgr = tbm_bufmgr_init(-1);
263 _deinit_surface_bufmgr(void)
265 if (!g_surface_bufmgr)
268 tbm_bufmgr_deinit(g_surface_bufmgr);
269 g_surface_bufmgr = NULL;
274 _tbm_surface_internal_is_valid(tbm_surface_h surface)
276 tbm_surface_h old_data = NULL;
278 TBM_RETURN_VAL_IF_FAIL(g_surface_bufmgr, 0);
279 TBM_RETURN_VAL_IF_FAIL(surface, 0);
281 if (!LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
282 LIST_FOR_EACH_ENTRY(old_data, &g_surface_bufmgr->surf_list, item_link) {
283 if (old_data == surface) {
284 TBM_TRACE("tbm_surface(%p)\n", surface);
290 TBM_LOG_E("error: No valid tbm_surface(%p)\n", surface);
296 _tbm_surface_internal_query_plane_data(tbm_surface_h surface,
297 int plane_idx, uint32_t *size, uint32_t *offset, uint32_t *pitch, int *bo_idx)
299 TBM_RETURN_VAL_IF_FAIL(surface, 0);
300 TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
302 struct _tbm_surface *surf = (struct _tbm_surface *)surface;
303 struct _tbm_bufmgr *mgr = surf->bufmgr;
306 TBM_RETURN_VAL_IF_FAIL(mgr != NULL, 0);
307 TBM_RETURN_VAL_IF_FAIL(surf->info.width > 0, 0);
308 TBM_RETURN_VAL_IF_FAIL(surf->info.height > 0, 0);
309 TBM_RETURN_VAL_IF_FAIL(surf->info.format > 0, 0);
311 if (!mgr->backend->surface_get_plane_data)
314 ret = mgr->backend->surface_get_plane_data(surf->info.width,
315 surf->info.height, surf->info.format, plane_idx, size, offset, pitch, bo_idx);
317 /* LCOV_EXCL_START */
318 TBM_LOG_E("Fail to surface_get_plane_data. surface(%p)\n", surface);
327 _tbm_surface_internal_destroy(tbm_surface_h surface)
330 tbm_bufmgr bufmgr = surface->bufmgr;
331 tbm_user_data *old_data = NULL, *tmp = NULL;
332 tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
334 /* destory the user_data_list */
335 if (!LIST_IS_EMPTY(&surface->user_data_list)) {
336 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &surface->user_data_list, item_link) {
337 TBM_DBG("free user_data\n");
338 user_data_delete(old_data);
342 for (i = 0; i < surface->num_bos; i++) {
343 surface->bos[i]->surface = NULL;
345 tbm_bo_unref(surface->bos[i]);
346 surface->bos[i] = NULL;
349 if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
350 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &surface->debug_data_list, item_link)
351 _tbm_surface_internal_debug_data_delete(debug_old_data);
354 LIST_DEL(&surface->item_link);
359 if (LIST_IS_EMPTY(&bufmgr->surf_list)) {
360 LIST_DELINIT(&bufmgr->surf_list);
362 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
363 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
364 _tbm_surface_internal_debug_data_delete(debug_old_data);
368 _deinit_surface_bufmgr();
373 tbm_surface_internal_is_valid(tbm_surface_h surface)
377 _tbm_surface_mutex_lock();
379 /* Return silently if surface is null. */
381 _tbm_surface_mutex_unlock();
385 ret = _tbm_surface_internal_is_valid(surface);
387 _tbm_surface_mutex_unlock();
393 tbm_surface_internal_query_supported_formats(uint32_t **formats,
396 struct _tbm_bufmgr *mgr;
398 bool bufmgr_initialized = false;
400 _tbm_surface_mutex_lock();
402 if (!g_surface_bufmgr) {
403 _init_surface_bufmgr();
404 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
405 bufmgr_initialized = true;
408 mgr = g_surface_bufmgr;
410 if (!mgr->backend->surface_supported_format)
413 ret = mgr->backend->surface_supported_format(formats, num);
415 /* LCOV_EXCL_START */
416 TBM_LOG_E("Fail to surface_supported_format.\n");
418 /* LCOV_EXCL_START */
421 TBM_TRACE("tbm_bufmgr(%p) format num(%u)\n", g_surface_bufmgr, *num);
423 _tbm_surface_mutex_unlock();
427 /* LCOV_EXCL_START */
429 if (bufmgr_initialized) {
430 LIST_DELINIT(&g_surface_bufmgr->surf_list);
431 _deinit_surface_bufmgr();
433 _tbm_surface_mutex_unlock();
435 TBM_LOG_E("error: tbm_bufmgr(%p)\n", g_surface_bufmgr);
442 tbm_surface_internal_get_num_planes(tbm_format format)
448 case TBM_FORMAT_RGB332:
449 case TBM_FORMAT_BGR233:
450 case TBM_FORMAT_XRGB4444:
451 case TBM_FORMAT_XBGR4444:
452 case TBM_FORMAT_RGBX4444:
453 case TBM_FORMAT_BGRX4444:
454 case TBM_FORMAT_ARGB4444:
455 case TBM_FORMAT_ABGR4444:
456 case TBM_FORMAT_RGBA4444:
457 case TBM_FORMAT_BGRA4444:
458 case TBM_FORMAT_XRGB1555:
459 case TBM_FORMAT_XBGR1555:
460 case TBM_FORMAT_RGBX5551:
461 case TBM_FORMAT_BGRX5551:
462 case TBM_FORMAT_ARGB1555:
463 case TBM_FORMAT_ABGR1555:
464 case TBM_FORMAT_RGBA5551:
465 case TBM_FORMAT_BGRA5551:
466 case TBM_FORMAT_RGB565:
467 case TBM_FORMAT_BGR565:
468 case TBM_FORMAT_RGB888:
469 case TBM_FORMAT_BGR888:
470 case TBM_FORMAT_XRGB8888:
471 case TBM_FORMAT_XBGR8888:
472 case TBM_FORMAT_RGBX8888:
473 case TBM_FORMAT_BGRX8888:
474 case TBM_FORMAT_ARGB8888:
475 case TBM_FORMAT_ABGR8888:
476 case TBM_FORMAT_RGBA8888:
477 case TBM_FORMAT_BGRA8888:
478 case TBM_FORMAT_XRGB2101010:
479 case TBM_FORMAT_XBGR2101010:
480 case TBM_FORMAT_RGBX1010102:
481 case TBM_FORMAT_BGRX1010102:
482 case TBM_FORMAT_ARGB2101010:
483 case TBM_FORMAT_ABGR2101010:
484 case TBM_FORMAT_RGBA1010102:
485 case TBM_FORMAT_BGRA1010102:
486 case TBM_FORMAT_YUYV:
487 case TBM_FORMAT_YVYU:
488 case TBM_FORMAT_UYVY:
489 case TBM_FORMAT_VYUY:
490 case TBM_FORMAT_AYUV:
493 case TBM_FORMAT_NV12:
494 case TBM_FORMAT_NV12MT:
495 case TBM_FORMAT_NV21:
496 case TBM_FORMAT_NV16:
497 case TBM_FORMAT_NV61:
500 case TBM_FORMAT_YUV410:
501 case TBM_FORMAT_YVU410:
502 case TBM_FORMAT_YUV411:
503 case TBM_FORMAT_YVU411:
504 case TBM_FORMAT_YUV420:
505 case TBM_FORMAT_YVU420:
506 case TBM_FORMAT_YUV422:
507 case TBM_FORMAT_YVU422:
508 case TBM_FORMAT_YUV444:
509 case TBM_FORMAT_YVU444:
517 TBM_TRACE("tbm_format(%s) num_planes(%d)\n", _tbm_surface_internal_format_to_str(format), num_planes);
523 tbm_surface_internal_get_bpp(tbm_format format)
530 case TBM_FORMAT_RGB332:
531 case TBM_FORMAT_BGR233:
534 case TBM_FORMAT_XRGB4444:
535 case TBM_FORMAT_XBGR4444:
536 case TBM_FORMAT_RGBX4444:
537 case TBM_FORMAT_BGRX4444:
538 case TBM_FORMAT_ARGB4444:
539 case TBM_FORMAT_ABGR4444:
540 case TBM_FORMAT_RGBA4444:
541 case TBM_FORMAT_BGRA4444:
542 case TBM_FORMAT_XRGB1555:
543 case TBM_FORMAT_XBGR1555:
544 case TBM_FORMAT_RGBX5551:
545 case TBM_FORMAT_BGRX5551:
546 case TBM_FORMAT_ARGB1555:
547 case TBM_FORMAT_ABGR1555:
548 case TBM_FORMAT_RGBA5551:
549 case TBM_FORMAT_BGRA5551:
550 case TBM_FORMAT_RGB565:
551 case TBM_FORMAT_BGR565:
554 case TBM_FORMAT_RGB888:
555 case TBM_FORMAT_BGR888:
558 case TBM_FORMAT_XRGB8888:
559 case TBM_FORMAT_XBGR8888:
560 case TBM_FORMAT_RGBX8888:
561 case TBM_FORMAT_BGRX8888:
562 case TBM_FORMAT_ARGB8888:
563 case TBM_FORMAT_ABGR8888:
564 case TBM_FORMAT_RGBA8888:
565 case TBM_FORMAT_BGRA8888:
566 case TBM_FORMAT_XRGB2101010:
567 case TBM_FORMAT_XBGR2101010:
568 case TBM_FORMAT_RGBX1010102:
569 case TBM_FORMAT_BGRX1010102:
570 case TBM_FORMAT_ARGB2101010:
571 case TBM_FORMAT_ABGR2101010:
572 case TBM_FORMAT_RGBA1010102:
573 case TBM_FORMAT_BGRA1010102:
574 case TBM_FORMAT_YUYV:
575 case TBM_FORMAT_YVYU:
576 case TBM_FORMAT_UYVY:
577 case TBM_FORMAT_VYUY:
578 case TBM_FORMAT_AYUV:
581 case TBM_FORMAT_NV12:
582 case TBM_FORMAT_NV12MT:
583 case TBM_FORMAT_NV21:
586 case TBM_FORMAT_NV16:
587 case TBM_FORMAT_NV61:
590 case TBM_FORMAT_YUV410:
591 case TBM_FORMAT_YVU410:
594 case TBM_FORMAT_YUV411:
595 case TBM_FORMAT_YVU411:
596 case TBM_FORMAT_YUV420:
597 case TBM_FORMAT_YVU420:
600 case TBM_FORMAT_YUV422:
601 case TBM_FORMAT_YVU422:
604 case TBM_FORMAT_YUV444:
605 case TBM_FORMAT_YVU444:
612 TBM_TRACE("tbm_format(%s) bpp(%d)\n", _tbm_surface_internal_format_to_str(format), bpp);
618 tbm_surface_internal_create_with_flags(int width, int height,
619 int format, int flags)
621 TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
622 TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
624 struct _tbm_bufmgr *mgr;
625 struct _tbm_surface *surf = NULL;
629 uint32_t bo_size = 0;
632 bool bufmgr_initialized = false;
634 _tbm_surface_mutex_lock();
636 if (!g_surface_bufmgr) {
637 _init_surface_bufmgr();
638 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
639 bufmgr_initialized = true;
642 mgr = g_surface_bufmgr;
643 if (!TBM_BUFMGR_IS_VALID(mgr)) {
644 TBM_LOG_E("The bufmgr is invalid\n");
645 goto check_valid_fail;
648 surf = calloc(1, sizeof(struct _tbm_surface));
650 /* LCOV_EXCL_START */
651 TBM_LOG_E("fail to alloc surf\n");
652 goto alloc_surf_fail;
657 surf->info.width = width;
658 surf->info.height = height;
659 surf->info.format = format;
660 surf->info.bpp = tbm_surface_internal_get_bpp(format);
661 surf->info.num_planes = tbm_surface_internal_get_num_planes(format);
664 /* get size, stride and offset bo_idx */
665 for (i = 0; i < surf->info.num_planes; i++) {
666 if (!_tbm_surface_internal_query_plane_data(surf, i, &size,
667 &offset, &stride, &bo_idx)) {
668 TBM_LOG_E("fail to query plane data\n");
669 goto query_plane_data_fail;
672 surf->info.planes[i].size = size;
673 surf->info.planes[i].offset = offset;
674 surf->info.planes[i].stride = stride;
675 surf->planes_bo_idx[i] = bo_idx;
680 for (i = 0; i < surf->info.num_planes; i++) {
681 surf->info.size += surf->info.planes[i].size;
683 if (surf->num_bos < surf->planes_bo_idx[i] + 1)
684 surf->num_bos = surf->planes_bo_idx[i] + 1;
689 for (i = 0; i < surf->num_bos; i++) {
691 for (j = 0; j < surf->info.num_planes; j++) {
692 if (surf->planes_bo_idx[j] == i)
693 bo_size += surf->info.planes[j].size;
696 if (mgr->backend->surface_bo_alloc) {
697 /* LCOV_EXCL_START */
699 void *bo_priv = NULL;
701 bo = calloc(1, sizeof(struct _tbm_bo));
703 TBM_LOG_E("fail to alloc bo struct\n");
707 bo->bufmgr = surf->bufmgr;
709 pthread_mutex_lock(&surf->bufmgr->lock);
711 bo_priv = mgr->backend->surface_bo_alloc(bo, width, height, format, flags, i);
713 TBM_LOG_E("fail to alloc bo priv\n");
715 pthread_mutex_unlock(&surf->bufmgr->lock);
723 LIST_INITHEAD(&bo->user_data_list);
725 LIST_ADD(&bo->item_link, &surf->bufmgr->bo_list);
727 pthread_mutex_unlock(&surf->bufmgr->lock);
732 surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
734 TBM_LOG_E("fail to alloc bo idx:%d\n", i);
739 _tbm_bo_set_surface(surf->bos[i], surf);
742 TBM_TRACE("width(%d) height(%d) format(%s) flags(%d) tbm_surface(%p)\n", width, height,
743 _tbm_surface_internal_format_to_str(format), flags, surf);
745 LIST_INITHEAD(&surf->user_data_list);
746 LIST_INITHEAD(&surf->debug_data_list);
748 LIST_ADD(&surf->item_link, &mgr->surf_list);
750 _tbm_surface_mutex_unlock();
754 /* LCOV_EXCL_START */
756 for (j = 0; j < i; j++) {
758 tbm_bo_unref(surf->bos[j]);
760 query_plane_data_fail:
764 if (bufmgr_initialized && mgr) {
765 LIST_DELINIT(&mgr->surf_list);
766 _deinit_surface_bufmgr();
768 _tbm_surface_mutex_unlock();
770 TBM_LOG_E("error: width(%d) height(%d) format(%s) flags(%d)\n",
772 _tbm_surface_internal_format_to_str(format), flags);
779 tbm_surface_internal_create_with_bos(tbm_surface_info_s *info,
780 tbm_bo *bos, int num)
782 TBM_RETURN_VAL_IF_FAIL(bos, NULL);
783 TBM_RETURN_VAL_IF_FAIL(info, NULL);
784 TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
786 struct _tbm_bufmgr *mgr;
787 struct _tbm_surface *surf = NULL;
789 bool bufmgr_initialized = false;
791 _tbm_surface_mutex_lock();
793 if (!g_surface_bufmgr) {
794 _init_surface_bufmgr();
795 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
796 bufmgr_initialized = true;
799 mgr = g_surface_bufmgr;
800 if (!TBM_BUFMGR_IS_VALID(mgr)) {
801 TBM_LOG_E("fail to validate the Bufmgr.\n");
802 goto check_valid_fail;
805 surf = calloc(1, sizeof(struct _tbm_surface));
807 /* LCOV_EXCL_START */
808 TBM_LOG_E("fail to allocate struct _tbm_surface.\n");
809 goto alloc_surf_fail;
814 surf->info.width = info->width;
815 surf->info.height = info->height;
816 surf->info.format = info->format;
818 surf->info.bpp = info->bpp;
820 surf->info.bpp = tbm_surface_internal_get_bpp(info->format);
821 surf->info.num_planes = info->num_planes;
824 /* get size, stride and offset */
825 for (i = 0; i < info->num_planes; i++) {
826 surf->info.planes[i].offset = info->planes[i].offset;
827 surf->info.planes[i].stride = info->planes[i].stride;
829 if (info->planes[i].size > 0)
830 surf->info.planes[i].size = info->planes[i].size;
832 uint32_t size = 0, offset = 0, stride = 0;
835 _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride, &bo_idx);
836 surf->info.planes[i].size = size;
840 surf->planes_bo_idx[i] = 0;
842 surf->planes_bo_idx[i] = i;
845 if (info->size > 0) {
846 surf->info.size = info->size;
849 for (i = 0; i < info->num_planes; i++)
850 surf->info.size += surf->info.planes[i].size;
853 surf->flags = TBM_BO_DEFAULT;
855 /* create only one bo */
857 for (i = 0; i < num; i++) {
858 if (bos[i] == NULL) {
859 TBM_LOG_E("bos[%d] is null.\n", i);
863 surf->bos[i] = tbm_bo_ref(bos[i]);
864 _tbm_bo_set_surface(bos[i], surf);
867 TBM_TRACE("tbm_surface(%p) width(%u) height(%u) format(%s) bo_num(%d)\n", surf,
868 info->width, info->height, _tbm_surface_internal_format_to_str(info->format), num);
870 LIST_INITHEAD(&surf->user_data_list);
871 LIST_INITHEAD(&surf->debug_data_list);
873 LIST_ADD(&surf->item_link, &mgr->surf_list);
875 _tbm_surface_mutex_unlock();
879 /* LCOV_EXCL_START */
881 for (i = 0; i < num; i++) {
883 tbm_bo_unref(surf->bos[i]);
888 if (bufmgr_initialized && mgr) {
889 LIST_DELINIT(&mgr->surf_list);
890 _deinit_surface_bufmgr();
892 _tbm_surface_mutex_unlock();
894 TBM_LOG_E("error: width(%u) height(%u) format(%s) bo_num(%d)\n",
895 info->width, info->height,
896 _tbm_surface_internal_format_to_str(info->format), num);
903 tbm_surface_internal_destroy(tbm_surface_h surface)
905 _tbm_surface_mutex_lock();
907 TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
911 if (surface->refcnt > 0) {
912 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
913 _tbm_surface_mutex_unlock();
917 TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
919 if (surface->refcnt == 0)
920 _tbm_surface_internal_destroy(surface);
922 _tbm_surface_mutex_unlock();
926 tbm_surface_internal_ref(tbm_surface_h surface)
928 _tbm_surface_mutex_lock();
930 TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
934 TBM_TRACE("tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
936 _tbm_surface_mutex_unlock();
940 tbm_surface_internal_unref(tbm_surface_h surface)
942 _tbm_surface_mutex_lock();
944 TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
948 if (surface->refcnt > 0) {
949 TBM_TRACE("reduce a refcnt(%d) of tbm_surface(%p)\n", surface->refcnt, surface);
950 _tbm_surface_mutex_unlock();
954 TBM_TRACE("destroy tbm_surface(%p) refcnt(%d)\n", surface, surface->refcnt);
956 if (surface->refcnt == 0)
957 _tbm_surface_internal_destroy(surface);
959 _tbm_surface_mutex_unlock();
963 tbm_surface_internal_get_num_bos(tbm_surface_h surface)
965 struct _tbm_surface *surf;
968 _tbm_surface_mutex_lock();
970 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
972 surf = (struct _tbm_surface *)surface;
975 TBM_TRACE("tbm_surface(%p) num_bos(%d)\n", surface, num);
977 _tbm_surface_mutex_unlock();
983 tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
985 struct _tbm_surface *surf;
988 _tbm_surface_mutex_lock();
990 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
991 TBM_SURFACE_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
993 surf = (struct _tbm_surface *)surface;
994 bo = surf->bos[bo_idx];
996 TBM_TRACE("tbm_surface(%p) bo_idx(%d) tbm_bo(%p)\n", surface, bo_idx, bo);
998 _tbm_surface_mutex_unlock();
1004 tbm_surface_internal_get_size(tbm_surface_h surface)
1006 struct _tbm_surface *surf;
1009 _tbm_surface_mutex_lock();
1011 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1013 surf = (struct _tbm_surface *)surface;
1014 size = surf->info.size;
1016 TBM_TRACE("tbm_surface(%p) size(%u)\n", surface, size);
1018 _tbm_surface_mutex_unlock();
1024 tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx,
1025 uint32_t *size, uint32_t *offset, uint32_t *pitch)
1027 struct _tbm_surface *surf;
1029 _tbm_surface_mutex_lock();
1031 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1032 TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1034 surf = (struct _tbm_surface *)surface;
1036 if (plane_idx >= surf->info.num_planes) {
1037 TBM_TRACE("error: tbm_surface(%p) plane_idx(%d)\n", surface, plane_idx);
1038 _tbm_surface_mutex_unlock();
1043 *size = surf->info.planes[plane_idx].size;
1046 *offset = surf->info.planes[plane_idx].offset;
1049 *pitch = surf->info.planes[plane_idx].stride;
1051 TBM_TRACE("tbm_surface(%p) plane_idx(%d) size(%u) offset(%u) pitch(%u)\n", surface, plane_idx,
1052 surf->info.planes[plane_idx].size, surf->info.planes[plane_idx].offset,
1053 surf->info.planes[plane_idx].stride);
1055 _tbm_surface_mutex_unlock();
1061 tbm_surface_internal_get_info(tbm_surface_h surface, int opt,
1062 tbm_surface_info_s *info, int map)
1064 struct _tbm_surface *surf;
1065 tbm_bo_handle bo_handles[4];
1068 _tbm_surface_mutex_lock();
1070 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1072 memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
1074 surf = (struct _tbm_surface *)surface;
1076 memset(info, 0x00, sizeof(tbm_surface_info_s));
1077 info->width = surf->info.width;
1078 info->height = surf->info.height;
1079 info->format = surf->info.format;
1080 info->bpp = surf->info.bpp;
1081 info->size = surf->info.size;
1082 info->num_planes = surf->info.num_planes;
1085 for (i = 0; i < surf->num_bos; i++) {
1086 _tbm_surface_mutex_unlock();
1087 bo_handles[i] = tbm_bo_map(surf->bos[i], TBM_DEVICE_CPU, opt);
1088 _tbm_surface_mutex_lock();
1089 if (bo_handles[i].ptr == NULL) {
1090 for (j = 0; j < i; j++)
1091 tbm_bo_unmap(surf->bos[j]);
1093 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1094 _tbm_surface_mutex_unlock();
1099 for (i = 0; i < surf->num_bos; i++) {
1100 bo_handles[i] = tbm_bo_get_handle(surf->bos[i], TBM_DEVICE_CPU);
1101 if (bo_handles[i].ptr == NULL) {
1102 TBM_LOG_E("error: tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1103 _tbm_surface_mutex_unlock();
1109 for (i = 0; i < surf->info.num_planes; i++) {
1110 info->planes[i].size = surf->info.planes[i].size;
1111 info->planes[i].offset = surf->info.planes[i].offset;
1112 info->planes[i].stride = surf->info.planes[i].stride;
1114 if (bo_handles[surf->planes_bo_idx[i]].ptr)
1115 info->planes[i].ptr = bo_handles[surf->planes_bo_idx[i]].ptr +
1116 surf->info.planes[i].offset;
1119 TBM_TRACE("tbm_surface(%p) opt(%d) map(%d)\n", surface, opt, map);
1121 _tbm_surface_mutex_unlock();
1127 tbm_surface_internal_unmap(tbm_surface_h surface)
1129 struct _tbm_surface *surf;
1132 _tbm_surface_mutex_lock();
1134 TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1136 surf = (struct _tbm_surface *)surface;
1138 for (i = 0; i < surf->num_bos; i++)
1139 tbm_bo_unmap(surf->bos[i]);
1141 TBM_TRACE("tbm_surface(%p)\n", surface);
1143 _tbm_surface_mutex_unlock();
1147 tbm_surface_internal_get_width(tbm_surface_h surface)
1149 struct _tbm_surface *surf;
1152 _tbm_surface_mutex_lock();
1154 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1156 surf = (struct _tbm_surface *)surface;
1157 width = surf->info.width;
1159 TBM_TRACE("tbm_surface(%p) width(%u)\n", surface, width);
1161 _tbm_surface_mutex_unlock();
1167 tbm_surface_internal_get_height(tbm_surface_h surface)
1169 struct _tbm_surface *surf;
1170 unsigned int height;
1172 _tbm_surface_mutex_lock();
1174 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1176 surf = (struct _tbm_surface *)surface;
1177 height = surf->info.height;
1179 TBM_TRACE("tbm_surface(%p) height(%u)\n", surface, height);
1181 _tbm_surface_mutex_unlock();
1188 tbm_surface_internal_get_format(tbm_surface_h surface)
1190 struct _tbm_surface *surf;
1193 _tbm_surface_mutex_lock();
1195 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1197 surf = (struct _tbm_surface *)surface;
1198 format = surf->info.format;
1200 TBM_TRACE("tbm_surface(%p) format(%s)\n", surface, _tbm_surface_internal_format_to_str(format));
1202 _tbm_surface_mutex_unlock();
1208 tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
1210 struct _tbm_surface *surf;
1213 _tbm_surface_mutex_lock();
1215 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1216 TBM_SURFACE_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1218 surf = (struct _tbm_surface *)surface;
1219 bo_idx = surf->planes_bo_idx[plane_idx];
1221 TBM_TRACE("tbm_surface(%p) plane_idx(%d) bo_idx(%d)\n", surface, plane_idx, bo_idx);
1223 _tbm_surface_mutex_unlock();
1229 tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key,
1230 tbm_data_free data_free_func)
1232 tbm_user_data *data;
1234 _tbm_surface_mutex_lock();
1236 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1238 /* check if the data according to the key exist if so, return false. */
1239 data = user_data_lookup(&surface->user_data_list, key);
1241 TBM_TRACE("warning: user data already exist tbm_surface(%p) key(%lu)\n", surface, key);
1242 _tbm_surface_mutex_unlock();
1246 data = user_data_create(key, data_free_func);
1248 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1249 _tbm_surface_mutex_unlock();
1253 TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, data);
1255 LIST_ADD(&data->item_link, &surface->user_data_list);
1257 _tbm_surface_mutex_unlock();
1263 tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key,
1266 tbm_user_data *old_data;
1268 _tbm_surface_mutex_lock();
1270 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1272 old_data = user_data_lookup(&surface->user_data_list, key);
1274 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1275 _tbm_surface_mutex_unlock();
1279 if (old_data->data && old_data->free_func)
1280 old_data->free_func(old_data->data);
1282 old_data->data = data;
1284 TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1286 _tbm_surface_mutex_unlock();
1292 tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key,
1295 tbm_user_data *old_data;
1297 _tbm_surface_mutex_lock();
1299 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1302 TBM_LOG_E("error: tbm_surface(%p) key(%lu)\n", surface, key);
1303 _tbm_surface_mutex_unlock();
1308 old_data = user_data_lookup(&surface->user_data_list, key);
1310 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1311 _tbm_surface_mutex_unlock();
1315 *data = old_data->data;
1317 TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1319 _tbm_surface_mutex_unlock();
1325 tbm_surface_internal_delete_user_data(tbm_surface_h surface,
1328 tbm_user_data *old_data = (void *)0;
1330 _tbm_surface_mutex_lock();
1332 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1334 old_data = user_data_lookup(&surface->user_data_list, key);
1336 TBM_TRACE("error: tbm_surface(%p) key(%lu)\n", surface, key);
1337 _tbm_surface_mutex_unlock();
1341 TBM_TRACE("tbm_surface(%p) key(%lu) data(%p)\n", surface, key, old_data->data);
1343 user_data_delete(old_data);
1345 _tbm_surface_mutex_unlock();
1350 /* LCOV_EXCL_START */
1352 _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
1354 TBM_RETURN_VAL_IF_FAIL(surface, 0);
1356 return surface->debug_pid;
1360 tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
1362 _tbm_surface_mutex_lock();
1364 TBM_SURFACE_RETURN_IF_FAIL(_tbm_surface_internal_is_valid(surface));
1366 surface->debug_pid = pid;
1368 _tbm_surface_mutex_unlock();
1371 static tbm_surface_debug_data *
1372 _tbm_surface_internal_debug_data_create(char *key, char *value)
1374 tbm_surface_debug_data *debug_data = NULL;
1376 debug_data = calloc(1, sizeof(tbm_surface_debug_data));
1380 if (key) debug_data->key = strdup(key);
1381 if (value) debug_data->value = strdup(value);
1387 tbm_surface_internal_set_debug_data(tbm_surface_h surface, char *key, char *value)
1389 tbm_surface_debug_data *debug_data = NULL;
1390 tbm_surface_debug_data *old_data = NULL, *tmp = NULL;
1391 tbm_bufmgr bufmgr = NULL;
1393 _tbm_surface_mutex_lock();
1395 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), 0);
1396 TBM_SURFACE_RETURN_VAL_IF_FAIL(key, 0);
1398 bufmgr = surface->bufmgr;
1400 TBM_SURFACE_RETURN_VAL_IF_FAIL(bufmgr, 0);
1402 if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1403 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1405 if (!strcmp(old_data->key, key)) {
1406 if (old_data->value && value && !strncmp(old_data->value, value, strlen(old_data->value))) {
1407 TBM_TRACE("tbm_surface(%p) Already exist key(%s) and value(%s)!\n", surface, key, value);
1408 goto add_debug_key_list;
1411 if (old_data->value)
1412 free(old_data->value);
1415 old_data->value = strdup(value);
1417 old_data->value = NULL;
1419 goto add_debug_key_list;
1425 debug_data = _tbm_surface_internal_debug_data_create(key, value);
1427 TBM_LOG_E("error: tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1428 _tbm_surface_mutex_unlock();
1432 TBM_TRACE("tbm_surface(%p) key(%s) value(%s)\n", surface, key, value);
1434 LIST_ADD(&debug_data->item_link, &surface->debug_data_list);
1437 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1438 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bufmgr->debug_key_list, item_link) {
1439 if (!strcmp(old_data->key, key)) {
1440 _tbm_surface_mutex_unlock();
1446 debug_data = _tbm_surface_internal_debug_data_create(key, NULL);
1447 LIST_ADD(&debug_data->item_link, &bufmgr->debug_key_list);
1449 _tbm_surface_mutex_unlock();
1455 _tbm_surface_internal_get_debug_data(tbm_surface_h surface, char *key)
1457 tbm_surface_debug_data *old_data = NULL;
1459 TBM_SURFACE_RETURN_VAL_IF_FAIL(surface, NULL);
1461 if (!LIST_IS_EMPTY(&surface->debug_data_list)) {
1462 LIST_FOR_EACH_ENTRY(old_data, &surface->debug_data_list, item_link) {
1463 if (!strcmp(old_data->key, key))
1464 return old_data->value;
1471 typedef struct _tbm_surface_dump_info tbm_surface_dump_info;
1472 typedef struct _tbm_surface_dump_buf_info tbm_surface_dump_buf_info;
1474 struct _tbm_surface_dump_buf_info {
1484 tbm_surface_info_s info;
1486 struct list_head link;
1489 struct _tbm_surface_dump_info {
1490 char *path; // copy???
1493 struct list_head *link;
1494 struct list_head surface_list; /* link of surface */
1497 static tbm_surface_dump_info *g_dump_info = NULL;
1498 static const char *dump_postfix[2] = {"png", "yuv"};
1499 static double scale_factor;
1502 _tbm_surface_internal_dump_file_raw(const char *file, void *data1, int size1,
1503 void *data2, int size2, void *data3, int size3)
1505 FILE *fp = fopen(file, "w+");
1506 TBM_RETURN_IF_FAIL(fp != NULL);
1507 unsigned int *blocks;
1509 blocks = (unsigned int *)data1;
1510 fwrite(blocks, 1, size1, fp);
1513 blocks = (unsigned int *)data2;
1514 fwrite(blocks, 1, size2, fp);
1518 blocks = (unsigned int *)data3;
1519 fwrite(blocks, 1, size3, fp);
1526 _tbm_surface_internal_dump_file_png(const char *file, const void *data, int width, int height)
1528 unsigned int *blocks = (unsigned int *)data;
1529 FILE *fp = fopen(file, "wb");
1530 TBM_RETURN_IF_FAIL(fp != NULL);
1531 const int pixel_size = 4; // RGBA
1532 png_bytep *row_pointers;
1535 png_structp pPngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1538 TBM_LOG_E("fail to create a png write structure.\n");
1543 png_infop pPngInfo = png_create_info_struct(pPngStruct);
1545 TBM_LOG_E("fail to create a png info structure.\n");
1546 png_destroy_write_struct(&pPngStruct, NULL);
1551 png_init_io(pPngStruct, fp);
1552 png_set_IHDR(pPngStruct,
1557 PNG_COLOR_TYPE_RGBA,
1559 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1561 png_set_bgr(pPngStruct);
1562 png_write_info(pPngStruct, pPngInfo);
1564 row_pointers = png_malloc(pPngStruct, height * sizeof(png_byte *));
1565 if (!row_pointers) {
1566 TBM_LOG_E("fail to allocate the png row_pointers.\n");
1567 png_destroy_write_struct(&pPngStruct, &pPngInfo);
1572 for (y = 0; y < height; ++y) {
1576 row = png_malloc(pPngStruct, sizeof(png_byte) * width * pixel_size);
1578 TBM_LOG_E("fail to allocate the png row.\n");
1579 for (x = 0; x < y; x++)
1580 png_free(pPngStruct, row_pointers[x]);
1581 png_free(pPngStruct, row_pointers);
1582 png_destroy_write_struct(&pPngStruct, &pPngInfo);
1586 row_pointers[y] = (png_bytep)row;
1588 for (x = 0; x < width; ++x) {
1589 unsigned int curBlock = blocks[y * width + x];
1591 row[x * pixel_size] = (curBlock & 0xFF);
1592 row[1 + x * pixel_size] = (curBlock >> 8) & 0xFF;
1593 row[2 + x * pixel_size] = (curBlock >> 16) & 0xFF;
1594 row[3 + x * pixel_size] = (curBlock >> 24) & 0xFF;
1598 png_write_image(pPngStruct, row_pointers);
1599 png_write_end(pPngStruct, pPngInfo);
1601 for (y = 0; y < height; y++)
1602 png_free(pPngStruct, row_pointers[y]);
1603 png_free(pPngStruct, row_pointers);
1605 png_destroy_write_struct(&pPngStruct, &pPngInfo);
1611 tbm_surface_internal_dump_start(char *path, int w, int h, int count)
1613 TBM_RETURN_IF_FAIL(path != NULL);
1614 TBM_RETURN_IF_FAIL(w > 0);
1615 TBM_RETURN_IF_FAIL(h > 0);
1616 TBM_RETURN_IF_FAIL(count > 0);
1618 tbm_surface_dump_buf_info *buf_info = NULL;
1619 tbm_surface_h tbm_surface;
1620 tbm_surface_info_s info;
1625 TBM_LOG_W("waring already running the tbm_surface_internal_dump.\n");
1629 g_dump_info = calloc(1, sizeof(struct _tbm_surface_dump_info));
1630 TBM_RETURN_IF_FAIL(g_dump_info);
1632 LIST_INITHEAD(&g_dump_info->surface_list);
1633 g_dump_info->count = 0;
1634 g_dump_info->dump_max = count;
1636 /* get buffer size */
1637 tbm_surface = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
1638 if (tbm_surface == NULL) {
1639 TBM_LOG_E("tbm_surface_create fail\n");
1645 if (TBM_SURFACE_ERROR_NONE != tbm_surface_map(tbm_surface,
1646 TBM_SURF_OPTION_READ, &info)) {
1647 TBM_LOG_E("tbm_surface_map fail\n");
1648 tbm_surface_destroy(tbm_surface);
1653 buffer_size = info.planes[0].stride * h;
1655 tbm_surface_unmap(tbm_surface);
1656 tbm_surface_destroy(tbm_surface);
1658 /* create dump lists */
1659 for (i = 0; i < count; i++) {
1662 buf_info = calloc(1, sizeof(tbm_surface_dump_buf_info));
1663 TBM_GOTO_VAL_IF_FAIL(buf_info, fail);
1665 bo = tbm_bo_alloc(g_surface_bufmgr, buffer_size, TBM_BO_DEFAULT);
1667 TBM_LOG_E("fail to allocate the tbm_bo[%d]\n", i);
1672 buf_info->index = i;
1674 buf_info->size = buffer_size;
1676 LIST_ADDTAIL(&buf_info->link, &g_dump_info->surface_list);
1679 g_dump_info->path = path;
1680 g_dump_info->link = &g_dump_info->surface_list;
1684 TBM_LOG_I("Dump Start.. path:%s, count:%d\n", g_dump_info->path, count);
1689 /* free resources */
1690 if (!LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1691 tbm_surface_dump_buf_info *tmp;
1693 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1694 tbm_bo_unref(buf_info->bo);
1695 LIST_DEL(&buf_info->link);
1700 TBM_LOG_E("Dump Start fail.. path:%s\n", g_dump_info->path);
1709 tbm_surface_internal_dump_with_scale_start(char *path, int w, int h, int count, double scale)
1716 tbm_surface_internal_dump_start(path, w, h, count);
1717 scale_factor = scale;
1721 tbm_surface_internal_dump_end(void)
1723 tbm_surface_dump_buf_info *buf_info = NULL, *tmp = NULL;
1724 tbm_bo_handle bo_handle;
1729 if (LIST_IS_EMPTY(&g_dump_info->surface_list)) {
1736 LIST_FOR_EACH_ENTRY_SAFE(buf_info, tmp, &g_dump_info->surface_list, link) {
1739 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_READ);
1740 if (bo_handle.ptr == NULL) {
1741 tbm_bo_unref(buf_info->bo);
1742 LIST_DEL(&buf_info->link);
1747 snprintf(file, sizeof(file), "%s/%s", g_dump_info->path, buf_info->name);
1748 TBM_LOG_I("Dump File.. %s generated.\n", file);
1750 if (buf_info->dirty) {
1751 void *ptr1 = NULL, *ptr2 = NULL;
1753 switch (buf_info->info.format) {
1754 case TBM_FORMAT_ARGB8888:
1755 case TBM_FORMAT_XRGB8888:
1756 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1757 buf_info->info.planes[0].stride >> 2,
1758 buf_info->info.height);
1760 case TBM_FORMAT_YVU420:
1761 case TBM_FORMAT_YUV420:
1762 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1763 ptr2 = ptr1 + buf_info->info.planes[1].stride * (buf_info->info.height >> 1);
1764 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1765 buf_info->info.planes[0].stride * buf_info->info.height,
1767 buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1769 buf_info->info.planes[2].stride * (buf_info->info.height >> 1));
1771 case TBM_FORMAT_NV12:
1772 case TBM_FORMAT_NV21:
1773 ptr1 = bo_handle.ptr + buf_info->info.planes[0].stride * buf_info->info.height;
1774 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1775 buf_info->info.planes[0].stride * buf_info->info.height,
1777 buf_info->info.planes[1].stride * (buf_info->info.height >> 1),
1780 case TBM_FORMAT_YUYV:
1781 case TBM_FORMAT_UYVY:
1782 _tbm_surface_internal_dump_file_raw(file, bo_handle.ptr,
1783 buf_info->info.planes[0].stride * buf_info->info.height,
1787 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(buf_info->info.format));
1790 } else if (buf_info->dirty_shm)
1791 _tbm_surface_internal_dump_file_png(file, bo_handle.ptr,
1792 buf_info->shm_stride >> 2,
1795 tbm_bo_unmap(buf_info->bo);
1796 tbm_bo_unref(buf_info->bo);
1797 LIST_DEL(&buf_info->link);
1804 TBM_LOG_I("Dump End..\n");
1807 static pixman_format_code_t
1808 _tbm_surface_internal_pixman_format_get(tbm_format format)
1811 case TBM_FORMAT_ARGB8888:
1812 return PIXMAN_a8r8g8b8;
1813 case TBM_FORMAT_XRGB8888:
1814 return PIXMAN_x8r8g8b8;
1823 * This function supports only if a buffer has below formats.
1824 * - TBM_FORMAT_ARGB8888
1825 * - TBM_FORMAT_XRGB8888
1827 static tbm_surface_error_e
1828 _tbm_surface_internal_buffer_scale(void *src_ptr, void *dst_ptr,
1829 int format, int src_stride, int src_w, int src_h,
1830 int dst_stride, int dst_w, int dst_h)
1832 pixman_image_t *src_img = NULL, *dst_img = NULL;
1833 pixman_format_code_t pixman_format;
1834 pixman_transform_t t;
1835 struct pixman_f_transform ft;
1836 double scale_x, scale_y;
1838 TBM_RETURN_VAL_IF_FAIL(src_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1839 TBM_RETURN_VAL_IF_FAIL(dst_ptr != NULL, TBM_SURFACE_ERROR_INVALID_OPERATION);
1841 pixman_format = _tbm_surface_internal_pixman_format_get(format);
1842 TBM_RETURN_VAL_IF_FAIL(pixman_format > 0, TBM_SURFACE_ERROR_INVALID_OPERATION);
1845 src_img = pixman_image_create_bits(pixman_format, src_w, src_h,
1846 (uint32_t*)src_ptr, src_stride);
1847 TBM_GOTO_VAL_IF_FAIL(src_img != NULL, cant_convert);
1850 dst_img = pixman_image_create_bits(pixman_format, dst_w, dst_h,
1851 (uint32_t*)dst_ptr, dst_stride);
1852 TBM_GOTO_VAL_IF_FAIL(dst_img != NULL, cant_convert);
1854 pixman_f_transform_init_identity(&ft);
1856 scale_x = (double)src_w / dst_w;
1857 scale_y = (double)src_h / dst_h;
1859 pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
1860 pixman_f_transform_translate(&ft, NULL, 0, 0);
1861 pixman_transform_from_pixman_f_transform(&t, &ft);
1862 pixman_image_set_transform(src_img, &t);
1864 pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img,
1865 0, 0, 0, 0, 0, 0, dst_w, dst_h);
1867 pixman_image_unref(src_img);
1868 pixman_image_unref(dst_img);
1870 return TBM_SURFACE_ERROR_NONE;
1874 pixman_image_unref(src_img);
1876 return TBM_SURFACE_ERROR_INVALID_OPERATION;
1879 #define MAX_BOS 4 // This value is came from bos[4] in struct _tbm_surface
1880 #define KEY_LEN 5 // "_XXXX"
1881 #define KEYS_LEN KEY_LEN * MAX_BOS
1883 static char *_tbm_surface_internal_get_keys(tbm_surface_h surface)
1885 char *keys, temp_key[KEY_LEN + 1];
1886 struct _tbm_surface *surf;
1890 _tbm_surface_mutex_lock();
1892 TBM_SURFACE_RETURN_VAL_IF_FAIL(_tbm_surface_internal_is_valid(surface), NULL);
1894 surf = (struct _tbm_surface *)surface;
1896 num_bos = surf->num_bos;
1897 if (num_bos > MAX_BOS)
1900 keys = calloc(KEYS_LEN + 1, sizeof(char));
1902 TBM_LOG_E("Failed to alloc memory");
1903 _tbm_surface_mutex_unlock();
1907 for (i = 0; i < num_bos; i++) {
1908 memset(temp_key, 0x00, KEY_LEN + 1);
1910 snprintf(temp_key, KEY_LEN, "_%d", tbm_bo_export(bo));
1911 strncat(keys, temp_key, KEY_LEN);
1914 _tbm_surface_mutex_unlock();
1919 static void _tbm_surface_internal_put_keys(char *keys)
1926 tbm_surface_internal_dump_buffer(tbm_surface_h surface, const char *type)
1928 TBM_RETURN_IF_FAIL(surface != NULL);
1929 TBM_RETURN_IF_FAIL(type != NULL);
1931 tbm_surface_dump_buf_info *buf_info;
1932 struct list_head *next_link;
1933 tbm_surface_info_s info;
1934 tbm_bo_handle bo_handle;
1935 const char *postfix;
1942 next_link = g_dump_info->link->next;
1943 TBM_RETURN_IF_FAIL(next_link != NULL);
1945 if (next_link == &g_dump_info->surface_list) {
1946 next_link = next_link->next;
1947 TBM_RETURN_IF_FAIL(next_link != NULL);
1950 buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
1951 TBM_RETURN_IF_FAIL(buf_info != NULL);
1953 ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
1954 TBM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
1956 if (scale_factor > 0.0) {
1959 if (info.format != TBM_FORMAT_ARGB8888 && info.format != TBM_FORMAT_XRGB8888) {
1960 TBM_LOG_W("Dump with scale skip. unsupported format(%s)\n",
1961 _tbm_surface_internal_format_to_str(info.format));
1962 tbm_surface_unmap(surface);
1966 memset(&buf_info->info, 0, sizeof(tbm_surface_info_s));
1968 buf_info->info.width = info.width * scale_factor;
1969 buf_info->info.height = info.height * scale_factor;
1970 buf_info->info.format = info.format;
1971 buf_info->info.bpp = tbm_surface_internal_get_bpp(buf_info->info.format);
1972 buf_info->info.num_planes = 1;
1973 buf_info->info.planes[0].stride = buf_info->info.width * bpp;
1974 buf_info->info.size = buf_info->info.width * buf_info->info.height * bpp;
1976 if (buf_info->info.size > buf_info->size) {
1977 TBM_LOG_W("Dump with scale skip. surface over created buffer size(%u, %d)\n",
1978 buf_info->info.size, buf_info->size);
1979 tbm_surface_unmap(surface);
1983 if (info.size > buf_info->size) {
1984 TBM_LOG_W("Dump skip. surface over created buffer size(%u, %d)\n",
1985 info.size, buf_info->size);
1986 tbm_surface_unmap(surface);
1990 /* make the file information */
1991 memcpy(&buf_info->info, &info, sizeof(tbm_surface_info_s));
1994 if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
1995 postfix = dump_postfix[0];
1997 postfix = dump_postfix[1];
1999 keys = _tbm_surface_internal_get_keys(surface);
2001 TBM_LOG_E("fail to get keys");
2002 tbm_surface_unmap(surface);
2007 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2008 if (!bo_handle.ptr) {
2009 TBM_LOG_E("fail to map bo");
2010 _tbm_surface_internal_put_keys(keys);
2011 tbm_surface_unmap(surface);
2014 memset(bo_handle.ptr, 0x00, buf_info->size);
2016 switch (info.format) {
2017 case TBM_FORMAT_ARGB8888:
2018 case TBM_FORMAT_XRGB8888:
2019 snprintf(buf_info->name, sizeof(buf_info->name),
2020 "%10.3f_%03d%s_%p-%s.%s",
2021 _tbm_surface_internal_get_time(),
2022 g_dump_info->count++, keys, surface, type, postfix);
2024 if (scale_factor > 0.0) {
2025 ret = _tbm_surface_internal_buffer_scale(info.planes[0].ptr,
2027 buf_info->info.format,
2028 info.planes[0].stride,
2029 info.width, info.height,
2030 buf_info->info.planes[0].stride,
2031 buf_info->info.width,
2032 buf_info->info.height);
2033 if (ret != TBM_SURFACE_ERROR_NONE) {
2034 TBM_LOG_E("fail to scale buffer");
2035 tbm_bo_unmap(buf_info->bo);
2036 _tbm_surface_internal_put_keys(keys);
2037 tbm_surface_unmap(surface);
2041 memcpy(bo_handle.ptr, info.planes[0].ptr, info.size);
2043 case TBM_FORMAT_YVU420:
2044 case TBM_FORMAT_YUV420:
2045 snprintf(buf_info->name, sizeof(buf_info->name),
2046 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2047 _tbm_surface_internal_get_time(),
2048 g_dump_info->count++, keys, type, info.planes[0].stride,
2049 info.height, FOURCC_STR(info.format), postfix);
2050 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2051 bo_handle.ptr += info.planes[0].stride * info.height;
2052 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2053 bo_handle.ptr += info.planes[1].stride * (info.height >> 1);
2054 memcpy(bo_handle.ptr, info.planes[2].ptr, info.planes[2].stride * (info.height >> 1));
2056 case TBM_FORMAT_NV12:
2057 case TBM_FORMAT_NV21:
2058 snprintf(buf_info->name, sizeof(buf_info->name),
2059 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2060 _tbm_surface_internal_get_time(),
2061 g_dump_info->count++, keys, type, info.planes[0].stride,
2062 info.height, FOURCC_STR(info.format), postfix);
2063 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2064 bo_handle.ptr += info.planes[0].stride * info.height;
2065 memcpy(bo_handle.ptr, info.planes[1].ptr, info.planes[1].stride * (info.height >> 1));
2067 case TBM_FORMAT_YUYV:
2068 case TBM_FORMAT_UYVY:
2069 snprintf(buf_info->name, sizeof(buf_info->name),
2070 "%10.3f_%03d%s-%s_%dx%d_%c%c%c%c.%s",
2071 _tbm_surface_internal_get_time(),
2072 g_dump_info->count++, keys, type, info.planes[0].stride,
2073 info.height, FOURCC_STR(info.format), postfix);
2074 memcpy(bo_handle.ptr, info.planes[0].ptr, info.planes[0].stride * info.height);
2077 TBM_LOG_E("can't copy %c%c%c%c buffer", FOURCC_STR(info.format));
2078 tbm_bo_unmap(buf_info->bo);
2079 _tbm_surface_internal_put_keys(keys);
2080 tbm_surface_unmap(surface);
2084 tbm_bo_unmap(buf_info->bo);
2086 _tbm_surface_internal_put_keys(keys);
2088 tbm_surface_unmap(surface);
2090 buf_info->dirty = 1;
2091 buf_info->dirty_shm = 0;
2093 if (g_dump_info->count == 1000)
2094 g_dump_info->count = 0;
2096 g_dump_info->link = next_link;
2098 TBM_LOG_I("Dump %s \n", buf_info->name);
2101 void tbm_surface_internal_dump_shm_buffer(void *ptr, int w, int h, int stride,
2104 TBM_RETURN_IF_FAIL(ptr != NULL);
2105 TBM_RETURN_IF_FAIL(w > 0);
2106 TBM_RETURN_IF_FAIL(h > 0);
2107 TBM_RETURN_IF_FAIL(stride > 0);
2108 TBM_RETURN_IF_FAIL(type != NULL);
2110 tbm_surface_dump_buf_info *buf_info;
2111 struct list_head *next_link;
2112 tbm_bo_handle bo_handle;
2113 int ret, size, dw = 0, dh = 0, dstride = 0;
2118 next_link = g_dump_info->link->next;
2119 TBM_RETURN_IF_FAIL(next_link != NULL);
2121 if (next_link == &g_dump_info->surface_list) {
2122 next_link = next_link->next;
2123 TBM_RETURN_IF_FAIL(next_link != NULL);
2126 buf_info = LIST_ENTRY(tbm_surface_dump_buf_info, next_link, link);
2127 TBM_RETURN_IF_FAIL(buf_info != NULL);
2129 if (scale_factor > 0.0) {
2132 dw = w * scale_factor;
2133 dh = h * scale_factor;
2135 size = dstride * dh;
2139 if (size > buf_info->size) {
2140 TBM_LOG_W("Dump skip. shm buffer over created buffer size(%d, %d)\n",
2141 size, buf_info->size);
2146 bo_handle = tbm_bo_map(buf_info->bo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
2147 TBM_RETURN_IF_FAIL(bo_handle.ptr != NULL);
2149 memset(bo_handle.ptr, 0x00, buf_info->size);
2150 memset(&buf_info->info, 0x00, sizeof(tbm_surface_info_s));
2152 snprintf(buf_info->name, sizeof(buf_info->name), "%10.3f_%03d-%s.%s",
2153 _tbm_surface_internal_get_time(),
2154 g_dump_info->count++, type, dump_postfix[0]);
2155 if (scale_factor > 0.0) {
2156 ret = _tbm_surface_internal_buffer_scale(ptr, bo_handle.ptr,
2157 TBM_FORMAT_ARGB8888, stride,
2158 w, h, dstride, dw, dh);
2159 if (ret != TBM_SURFACE_ERROR_NONE) {
2160 TBM_LOG_E("fail to scale buffer");
2161 tbm_bo_unmap(buf_info->bo);
2164 buf_info->shm_stride = dstride;
2165 buf_info->shm_h = dh;
2167 memcpy(bo_handle.ptr, ptr, size);
2168 buf_info->shm_stride = stride;
2169 buf_info->shm_h = h;
2172 tbm_bo_unmap(buf_info->bo);
2174 buf_info->dirty = 0;
2175 buf_info->dirty_shm = 1;
2177 if (g_dump_info->count == 1000)
2178 g_dump_info->count = 0;
2180 g_dump_info->link = next_link;
2182 TBM_LOG_I("Dump %s \n", buf_info->name);
2186 tbm_surface_internal_capture_buffer(tbm_surface_h surface, const char *path, const char *name, const char *type)
2188 TBM_RETURN_VAL_IF_FAIL(surface != NULL, 0);
2189 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2190 TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2192 tbm_surface_info_s info;
2193 const char *postfix;
2197 ret = tbm_surface_map(surface, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info);
2198 TBM_RETURN_VAL_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE, 0);
2200 if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
2201 postfix = dump_postfix[0];
2203 postfix = dump_postfix[1];
2205 if (strcmp(postfix, type)) {
2206 TBM_LOG_E("not support type(%s) %c%c%c%c buffer", type, FOURCC_STR(info.format));
2207 tbm_surface_unmap(surface);
2211 snprintf(file, sizeof(file), "%s/%s.%s", path , name, postfix);
2213 if (!access(file, 0)) {
2214 TBM_LOG_E("can't capture buffer, exist file %s", file);
2215 tbm_surface_unmap(surface);
2219 switch (info.format) {
2220 case TBM_FORMAT_ARGB8888:
2221 case TBM_FORMAT_XRGB8888:
2222 _tbm_surface_internal_dump_file_png(file, info.planes[0].ptr,
2223 info.planes[0].stride >> 2,
2226 case TBM_FORMAT_YVU420:
2227 case TBM_FORMAT_YUV420:
2228 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2229 info.planes[0].stride * info.height,
2231 info.planes[1].stride * (info.height >> 1),
2233 info.planes[2].stride * (info.height >> 1));
2235 case TBM_FORMAT_NV12:
2236 case TBM_FORMAT_NV21:
2237 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2238 info.planes[0].stride * info.height,
2240 info.planes[1].stride * (info.height >> 1),
2243 case TBM_FORMAT_YUYV:
2244 case TBM_FORMAT_UYVY:
2245 _tbm_surface_internal_dump_file_raw(file, info.planes[0].ptr,
2246 info.planes[0].stride * info.height,
2250 TBM_LOG_E("can't dump %c%c%c%c buffer", FOURCC_STR(info.format));
2251 tbm_surface_unmap(surface);
2255 tbm_surface_unmap(surface);
2257 TBM_TRACE("Capture %s \n", file);
2263 tbm_surface_internal_capture_shm_buffer(void *ptr, int w, int h, int stride,
2264 const char *path, const char *name, const char *type)
2266 TBM_RETURN_VAL_IF_FAIL(ptr != NULL, 0);
2267 TBM_RETURN_VAL_IF_FAIL(w > 0, 0);
2268 TBM_RETURN_VAL_IF_FAIL(h > 0, 0);
2269 TBM_RETURN_VAL_IF_FAIL(stride > 0, 0);
2270 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
2271 TBM_RETURN_VAL_IF_FAIL(name != NULL, 0);
2275 if (strcmp(dump_postfix[0], type)) {
2276 TBM_LOG_E("Not supported type:%s'", type);
2280 if (!access(file, 0)) {
2281 TBM_LOG_E("can't capture buffer, exist file %s", file);
2285 snprintf(file, sizeof(file), "%s/%s.%s", path , name, dump_postfix[0]);
2287 _tbm_surface_internal_dump_file_png(file, ptr, stride, h);
2289 TBM_TRACE("Capture %s \n", file);