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