65c3ba60d782590730f067cc87fe9c4fc845a2e1
[platform/core/uifw/libtbm.git] / src / tbm_bufmgr.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 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
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
37 #include "list.h"
38
39 #ifdef DEBUG
40 int bDebug;
41 #endif
42
43 #ifdef TRACE
44 int bTrace;
45 #endif
46
47 #ifdef HAVE_DLOG
48 int bDlog;
49 #endif
50
51 int b_dump_queue;
52
53 #define PREFIX_LIB    "libtbm_"
54 #define SUFFIX_LIB    ".so"
55 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
56
57 /* values to indicate unspecified fields in XF86ModReqInfo. */
58 #define MAJOR_UNSPEC        0xFF
59 #define MINOR_UNSPEC        0xFF
60 #define PATCH_UNSPEC        0xFFFF
61 #define ABI_VERS_UNSPEC   0xFFFFFFFF
62
63 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
64                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
65 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
66 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
67 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
68
69 enum {
70         LOCK_TRY_ONCE,
71         LOCK_TRY_ALWAYS,
72         LOCK_TRY_NEVER
73 };
74
75 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
76 tbm_bufmgr gBufMgr;
77
78 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
79
80 static void
81 _tbm_set_last_result(tbm_error_e err)
82 {
83         tbm_last_error = err;
84 }
85
86 char * tbm_flag_to_str(int f)
87 {
88         static char str[255];
89         int c = 0;
90         if (f == TBM_BO_DEFAULT)
91                  snprintf(str, 255, "DEFAULT\n");
92         else {
93                 if (f & TBM_BO_SCANOUT)
94                         c = snprintf(&str[c], 255, "SCANOUT,");
95                 if (f & TBM_BO_NONCACHABLE)
96                         c = snprintf(&str[c], 255, "NONCACHABLE,");
97                 if (f & TBM_BO_WC)
98                         c = snprintf(&str[c], 255, "WC");
99         }
100         return str;
101 }
102
103 /* LCOV_EXCL_START */
104 static int last_chk_bo_cnt = 0;
105 static void
106 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
107 {
108         if (bufmgr->bo_cnt >= 500 && ((bufmgr->bo_cnt % 20) == 0)) {
109                 if (bufmgr->bo_cnt > last_chk_bo_cnt) {
110                         TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
111                         tbm_bufmgr_debug_show(bufmgr);
112                         last_chk_bo_cnt = bufmgr->bo_cnt;
113                 }
114         }
115 }
116
117 static int
118 _tbm_util_get_max_surface_size(int * w, int * h)
119 {
120         int count = 0;
121         tbm_surface_h surface = NULL, tmp = NULL;
122         tbm_surface_info_s info;
123
124         *w = 0;
125         *h = 0;
126
127         if (gBufMgr == NULL)
128                 return count;
129
130         if (!LIST_IS_EMPTY(&gBufMgr->surf_list)) {
131                 LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
132                         if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
133                                 count++;
134                                 if (*w < info.width) *w = info.width;
135                                 if (*h < info.height) *h = info.height;
136                         }
137                 }
138         }
139
140         return count;
141 }
142
143 static void
144 _tbm_util_get_appname_brief(char *brief)
145 {
146         char delim[] = "/";
147         char *token = NULL;
148         char temp[255] = {0,};
149         char *saveptr = NULL;
150
151         token = strtok_r(brief, delim, &saveptr);
152
153         while (token != NULL) {
154                 memset(temp, 0x00, 255 * sizeof(char));
155                 strncpy(temp, token, 254 * sizeof(char));
156                 token = strtok_r(NULL, delim, &saveptr);
157         }
158
159         snprintf(brief, sizeof(temp), "%s", temp);
160 }
161
162 static void
163 _tbm_util_get_appname_from_pid(long pid, char *str)
164 {
165         FILE *fp;
166         int len;
167         long app_pid = pid;
168         char fn_cmdline[255] = {0,};
169         char cmdline[255] = {0,};
170
171         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
172
173         fp = fopen(fn_cmdline, "r");
174         if (fp == 0) {
175                 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
176                 return;
177         }
178
179         if (!fgets(cmdline, 255, fp)) {
180                 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
181                 fclose(fp);
182                 return;
183         }
184         fclose(fp);
185
186         len = strlen(cmdline);
187         if (len < 1)
188                 memset(cmdline, 0x00, 255);
189         else
190                 cmdline[len] = 0;
191
192         snprintf(str, sizeof(cmdline), "%s", cmdline);
193 }
194 /* LCOV_EXCL_STOP */
195
196 tbm_user_data
197 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
198 {
199         tbm_user_data *user_data = NULL;
200         tbm_user_data *old_data = NULL, *tmp = NULL;
201
202         if (!LIST_IS_EMPTY(user_data_list)) {
203                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
204                         if (old_data->key == key) {
205                                 user_data = old_data;
206                                 return user_data;
207                         }
208                 }
209         }
210
211         return user_data;
212 }
213
214 tbm_user_data
215 *user_data_create(unsigned long key, tbm_data_free data_free_func)
216 {
217         tbm_user_data *user_data = NULL;
218
219         user_data = calloc(1, sizeof(tbm_user_data));
220         if (!user_data)
221                 return NULL;
222
223         user_data->key = key;
224         user_data->free_func = data_free_func;
225         user_data->data = (void *)0;
226
227         return user_data;
228 }
229
230 void
231 user_data_delete(tbm_user_data *user_data)
232 {
233         if (user_data->data && user_data->free_func)
234                 user_data->free_func(user_data->data);
235
236         LIST_DEL(&user_data->item_link);
237
238         free(user_data);
239 }
240
241 static int
242 _bo_lock(tbm_bo bo, int device, int opt)
243 {
244         tbm_bufmgr bufmgr = bo->bufmgr;
245         int ret = 0;
246
247         if (bufmgr->backend->bo_lock)
248                 ret = bufmgr->backend->bo_lock(bo, device, opt);
249         else
250                 ret = 1;
251
252         return ret;
253 }
254
255 static void
256 _bo_unlock(tbm_bo bo)
257 {
258         tbm_bufmgr bufmgr = bo->bufmgr;
259
260         if (bufmgr->backend->bo_unlock)
261                 bufmgr->backend->bo_unlock(bo);
262 }
263
264 static int
265 _tbm_bo_lock(tbm_bo bo, int device, int opt)
266 {
267         tbm_bufmgr bufmgr = NULL;
268         int old;
269         int ret = 0;
270
271         if (!bo)
272                 return 0;
273
274         bufmgr = bo->bufmgr;
275
276         /* do not try to lock the bo */
277         if (bufmgr->lock_type == LOCK_TRY_NEVER)
278                 return 1;
279
280         if (bo->lock_cnt < 0) {
281                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
282                         bo, bo->lock_cnt);
283         }
284
285         old = bo->lock_cnt;
286         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
287                 if (bo->lock_cnt == 0) {
288                         pthread_mutex_unlock(&bufmgr->lock);
289                         ret = _bo_lock(bo, device, opt);
290                         pthread_mutex_lock(&bufmgr->lock);
291                         if (ret)
292                                 bo->lock_cnt++;
293                 } else
294                         ret = 1;
295         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
296                 pthread_mutex_unlock(&bufmgr->lock);
297                 ret = _bo_lock(bo, device, opt);
298                 pthread_mutex_lock(&bufmgr->lock);
299                 if (ret)
300                         bo->lock_cnt++;
301         } else {
302                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
303                         bo);
304         }
305
306         DBG_LOCK(">> LOCK bo:%p(%d->%d)\n",
307                  bo, old, bo->lock_cnt);
308
309         return ret;
310 }
311
312 static void
313 _tbm_bo_unlock(tbm_bo bo)
314 {
315         tbm_bufmgr bufmgr = NULL;
316
317         int old;
318
319         if (!bo)
320                 return;
321
322         bufmgr = bo->bufmgr;
323
324         /* do not try to unlock the bo */
325         if (bufmgr->lock_type == LOCK_TRY_NEVER)
326                 return;
327
328         old = bo->lock_cnt;
329         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
330                 if (bo->lock_cnt > 0) {
331                         bo->lock_cnt--;
332                         if (bo->lock_cnt == 0)
333                                 _bo_unlock(bo);
334                 }
335         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
336                 if (bo->lock_cnt > 0) {
337                         bo->lock_cnt--;
338                         _bo_unlock(bo);
339                 }
340         } else {
341                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
342                         bo);
343         }
344
345         if (bo->lock_cnt < 0)
346                 bo->lock_cnt = 0;
347
348         DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n",
349                  bo, old, bo->lock_cnt);
350 }
351
352 static int
353 _tbm_bo_is_valid(tbm_bo bo)
354 {
355         tbm_bo old_data = NULL, tmp = NULL;
356
357         if (bo == NULL)
358                 return 0;
359
360         if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
361                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
362                         if (old_data == bo)
363                                 return 1;
364                 }
365
366         }
367         return 0;
368 }
369
370 static void
371 _tbm_bo_ref(tbm_bo bo)
372 {
373         bo->ref_cnt++;
374 }
375
376 static void
377 _tbm_bo_unref(tbm_bo bo)
378 {
379         tbm_bufmgr bufmgr = bo->bufmgr;
380         tbm_user_data *old_data = NULL, *tmp = NULL;
381
382         if (bo->ref_cnt <= 0)
383                 return;
384
385         bo->ref_cnt--;
386         if (bo->ref_cnt == 0) {
387                 /* destory the user_data_list */
388                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
389                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
390                                 DBG("free user_data\n");
391                                 user_data_delete(old_data);
392                         }
393                 }
394
395                 if (bo->lock_cnt > 0) {
396                         TBM_LOG_E("error lock_cnt:%d\n",
397                                 bo->lock_cnt);
398                         _bo_unlock(bo);
399                 }
400
401                 /* call the bo_free */
402                 bufmgr->backend->bo_free(bo);
403                 bo->priv = NULL;
404
405                 LIST_DEL(&bo->item_link);
406                 free(bo);
407                 bo = NULL;
408
409                 bufmgr->bo_cnt--;
410         }
411
412 }
413
414 /* LCOV_EXCL_START */
415 static int
416 _check_version(TBMModuleVersionInfo *data)
417 {
418         int abimaj, abimin;
419         int vermaj, vermin;
420
421         abimaj = GET_ABI_MAJOR(data->abiversion);
422         abimin = GET_ABI_MINOR(data->abiversion);
423
424         DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
425             data->modname ? data->modname : "UNKNOWN!",
426             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
427
428         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
429         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
430
431         DBG("TBM ABI version %d.%d\n",
432             vermaj, vermin);
433
434         if (abimaj != vermaj) {
435                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
436                         abimaj, vermaj);
437                 return 0;
438         } else if (abimin > vermin) {
439                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
440                         abimin, vermin);
441                 return 0;
442         }
443         return 1;
444 }
445
446 static int
447 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
448 {
449         char path[PATH_MAX] = { 0, };
450         TBMModuleData *initdata = NULL;
451         void *module_data;
452
453         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
454
455         module_data = dlopen(path, RTLD_LAZY);
456         if (!module_data) {
457                 TBM_LOG_E("failed to load module: %s(%s)\n",
458                         dlerror(), file);
459                 return 0;
460         }
461
462         initdata = dlsym(module_data, "tbmModuleData");
463         if (initdata) {
464                 ModuleInitProc init;
465                 TBMModuleVersionInfo *vers;
466
467                 vers = initdata->vers;
468                 init = initdata->init;
469
470                 if (vers) {
471                         if (!_check_version(vers)) {
472                                 dlclose(module_data);
473                                 return 0;
474                         }
475                 } else {
476                         TBM_LOG_E("Error: module does not supply version information.\n");
477
478                         dlclose(module_data);
479                         return 0;
480                 }
481
482                 if (init) {
483                         if (!init(bufmgr, fd)) {
484                                 TBM_LOG_E("Fail to init module(%s)\n",
485                                         file);
486                                 dlclose(module_data);
487                                 return 0;
488                         }
489
490                         if (!bufmgr->backend || !bufmgr->backend->priv) {
491                                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n",
492                                         file);
493                                 dlclose(module_data);
494                                 return 0;
495                         }
496                 } else {
497                         TBM_LOG_E("Error: module does not supply init symbol.\n");
498                         dlclose(module_data);
499                         return 0;
500                 }
501         } else {
502                 TBM_LOG_E("Error: module does not have data object.\n");
503                 dlclose(module_data);
504                 return 0;
505         }
506
507         bufmgr->module_data = module_data;
508
509         DBG("Success to load module(%s)\n",
510             file);
511
512         return 1;
513 }
514
515 static int
516 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
517 {
518         struct dirent **namelist;
519         const char *p = NULL;
520         int n;
521         int ret = 0;
522
523         /* load bufmgr priv from default lib */
524         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
525
526         /* load bufmgr priv from configured path */
527         if (!ret) {
528                 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
529                 if (n < 0) {
530                         TBM_LOG_E("no files : %s\n",
531                                 BUFMGR_MODULE_DIR);
532                 } else {
533                         while (n--) {
534                                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
535                                         p = strstr(namelist[n]->d_name, SUFFIX_LIB);
536                                         if (p && !strcmp(p, SUFFIX_LIB))
537                                                 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
538                                 }
539                                 free(namelist[n]);
540                         }
541                         free(namelist);
542                 }
543         }
544
545         return ret;
546 }
547 /* LCOV_EXCL_STOP */
548
549 tbm_bufmgr
550 tbm_bufmgr_init(int fd)
551 {
552         char *env;
553
554         pthread_mutex_lock(&gLock);
555
556         /* LCOV_EXCL_START */
557 #ifdef HAVE_DLOG
558         env = getenv("TBM_DLOG");
559         if (env) {
560                 bDlog = atoi(env);
561                 TBM_LOG_D("TBM_DLOG=%s\n", env);
562         } else {
563                 bDlog = 1;
564         }
565 #endif
566
567 #ifdef DEBUG
568         env = getenv("TBM_DEBUG");
569         if (env) {
570                 bDebug = atoi(env);
571                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
572         } else {
573                 bDebug = 0;
574         }
575 #endif
576
577 #ifdef TRACE
578         env = getenv("TBM_TRACE");
579         if (env) {
580                 bTrace = atoi(env);
581                 TBM_LOG_D("TBM_TRACE=%s\n", env);
582         } else {
583                 bTrace = 0;
584         }
585 #endif
586         /* LCOV_EXCL_STOP */
587
588         /* initialize buffer manager */
589         if (gBufMgr) {
590                 gBufMgr->ref_count++;
591                 TBM_TRACE("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
592                 pthread_mutex_unlock(&gLock);
593                 return gBufMgr;
594         }
595
596         DBG("bufmgr init\n");
597
598         /* allocate bufmgr */
599         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
600         if (!gBufMgr) {
601                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
602                 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
603                 pthread_mutex_unlock(&gLock);
604                 return NULL;
605         }
606
607         gBufMgr->fd = fd;
608
609         /* load bufmgr priv from env */
610         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
611                 /* LCOV_EXCL_START */
612                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
613                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
614                 free(gBufMgr);
615                 gBufMgr = NULL;
616                 pthread_mutex_unlock(&gLock);
617                 return NULL;
618                 /* LCOV_EXCL_STOP */
619         }
620
621         /* log for tbm backend_flag */
622         DBG("backend flag:%x:", gBufMgr->backend->flags);
623         DBG("\n");
624
625         gBufMgr->ref_count = 1;
626
627         DBG("create tizen bufmgr:%p ref_count:%d\n",
628             gBufMgr, gBufMgr->ref_count);
629
630         if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
631                 /* LCOV_EXCL_START */
632                 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
633                 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
634                 tbm_backend_free(gBufMgr->backend);
635                 dlclose(gBufMgr->module_data);
636                 free(gBufMgr);
637                 gBufMgr = NULL;
638                 pthread_mutex_unlock(&gLock);
639                 return NULL;
640                 /* LCOV_EXCL_STOP */
641         }
642
643         /* setup the lock_type */
644         env = getenv("BUFMGR_LOCK_TYPE");
645         if (env && !strcmp(env, "always"))
646                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
647         else if (env && !strcmp(env, "none"))
648                 gBufMgr->lock_type = LOCK_TRY_NEVER;
649         else if (env && !strcmp(env, "once"))
650                 gBufMgr->lock_type = LOCK_TRY_ONCE;
651         else
652                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
653
654         DBG("BUFMGR_LOCK_TYPE=%s\n",
655             env ? env : "default:once");
656
657         TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
658
659         /* intialize bo_list */
660         LIST_INITHEAD(&gBufMgr->bo_list);
661
662         /* intialize surf_list */
663         LIST_INITHEAD(&gBufMgr->surf_list);
664
665         /* intialize debug_key_list */
666         LIST_INITHEAD(&gBufMgr->debug_key_list);
667
668         pthread_mutex_unlock(&gLock);
669         return gBufMgr;
670 }
671
672 void
673 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
674 {
675         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
676
677         tbm_bo bo = NULL;
678         tbm_bo tmp = NULL;
679
680         tbm_surface_h surf = NULL;
681         tbm_surface_h tmp_surf = NULL;
682
683         pthread_mutex_lock(&gLock);
684
685         if (!gBufMgr) {
686                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
687                 pthread_mutex_unlock(&gLock);
688                 return;
689         }
690
691         bufmgr->ref_count--;
692         if (bufmgr->ref_count > 0) {
693                 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
694                 pthread_mutex_unlock(&gLock);
695                 return;
696         }
697
698         /* destroy bo_list */
699         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
700                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
701                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
702                                 bo, bo->ref_cnt);
703                         bo->ref_cnt = 1;
704                         tbm_bo_unref(bo);
705                 }
706         }
707
708         /* destroy surf_list */
709         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
710                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
711                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
712                                 surf, surf->refcnt);
713                         tbm_surface_destroy(surf);
714                 }
715         }
716
717         /* destroy bufmgr priv */
718         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
719         bufmgr->backend->priv = NULL;
720         tbm_backend_free(bufmgr->backend);
721         bufmgr->backend = NULL;
722
723         pthread_mutex_destroy(&bufmgr->lock);
724
725         TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
726
727         dlclose(bufmgr->module_data);
728
729         if (bufmgr->fd > 0)
730                 close(bufmgr->fd);
731
732         free(bufmgr);
733         bufmgr = NULL;
734         gBufMgr = NULL;
735
736         pthread_mutex_unlock(&gLock);
737 }
738
739 int
740 tbm_bo_size(tbm_bo bo)
741 {
742         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
743
744         tbm_bufmgr bufmgr = bo->bufmgr;
745         int size;
746
747         pthread_mutex_lock(&bufmgr->lock);
748
749         size = bufmgr->backend->bo_size(bo);
750
751         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
752
753         pthread_mutex_unlock(&bufmgr->lock);
754
755         return size;
756 }
757
758 tbm_bo
759 tbm_bo_ref(tbm_bo bo)
760 {
761         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
762
763         tbm_bufmgr bufmgr = bo->bufmgr;
764
765         pthread_mutex_lock(&bufmgr->lock);
766
767         _tbm_bo_ref(bo);
768
769         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
770
771         pthread_mutex_unlock(&bufmgr->lock);
772
773         return bo;
774 }
775
776 void
777 tbm_bo_unref(tbm_bo bo)
778 {
779         TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
780
781         tbm_bufmgr bufmgr = bo->bufmgr;
782
783         pthread_mutex_lock(&bufmgr->lock);
784
785         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
786
787         _tbm_bo_unref(bo);
788
789         pthread_mutex_unlock(&bufmgr->lock);
790 }
791
792 tbm_bo
793 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
794 {
795         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
796
797         tbm_bo bo = NULL;
798         void *bo_priv = NULL;
799
800         bo = calloc(1, sizeof(struct _tbm_bo));
801         if (!bo) {
802                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
803                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
804                 return NULL;
805         }
806
807         _tbm_util_check_bo_cnt(bufmgr);
808         bufmgr->bo_cnt++;
809
810         bo->bufmgr = bufmgr;
811
812         pthread_mutex_lock(&bufmgr->lock);
813
814         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
815         if (!bo_priv) {
816                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n", size, tbm_flag_to_str(flags));
817                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
818                 free(bo);
819                 pthread_mutex_unlock(&bufmgr->lock);
820                 return NULL;
821         }
822
823         bo->ref_cnt = 1;
824         bo->flags = flags;
825         bo->priv = bo_priv;
826
827         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt, tbm_flag_to_str(bo->flags));
828
829         LIST_INITHEAD(&bo->user_data_list);
830
831         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
832
833         pthread_mutex_unlock(&bufmgr->lock);
834
835         return bo;
836 }
837
838 tbm_bo
839 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
840 {
841         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
842
843         tbm_bo bo = NULL;
844         tbm_bo bo2 = NULL;
845         tbm_bo tmp = NULL;
846         void *bo_priv = NULL;
847
848         _tbm_util_check_bo_cnt(bufmgr);
849
850         pthread_mutex_lock(&bufmgr->lock);
851
852         bo = calloc(1, sizeof(struct _tbm_bo));
853         if (!bo) {
854                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
855                 pthread_mutex_unlock(&bufmgr->lock);
856                 return NULL;
857         }
858
859         bufmgr->bo_cnt++;
860
861         bo->bufmgr = bufmgr;
862
863         bo_priv = bufmgr->backend->bo_import(bo, key);
864         if (!bo_priv) {
865                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
866                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
867                 free(bo);
868                 pthread_mutex_unlock(&bufmgr->lock);
869                 return NULL;
870         }
871
872         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
873                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
874                         if (bo2->priv == bo_priv) {
875                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
876                                                         bo2, bo2->ref_cnt, key, tbm_flag_to_str(bo2->flags));
877                                 bo2->ref_cnt++;
878                                 free(bo);
879                                 pthread_mutex_unlock(&bufmgr->lock);
880                                 return bo2;
881                         }
882                 }
883         }
884
885         bo->ref_cnt = 1;
886         bo->priv = bo_priv;
887
888         if (bufmgr->backend->bo_get_flags)
889                 bo->flags = bufmgr->backend->bo_get_flags(bo);
890         else
891                 bo->flags = TBM_BO_DEFAULT;
892
893         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
894                           bo, bo->ref_cnt, key, tbm_flag_to_str(bo->flags));
895
896         LIST_INITHEAD(&bo->user_data_list);
897
898         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
899
900         pthread_mutex_unlock(&bufmgr->lock);
901
902         return bo;
903 }
904
905 tbm_bo
906 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
907 {
908         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
909
910         tbm_bo bo = NULL;
911         tbm_bo bo2 = NULL;
912         tbm_bo tmp = NULL;
913         void *bo_priv = NULL;
914
915         _tbm_util_check_bo_cnt(bufmgr);
916
917         pthread_mutex_lock(&bufmgr->lock);
918
919         bo = calloc(1, sizeof(struct _tbm_bo));
920         if (!bo) {
921                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
922                 pthread_mutex_unlock(&bufmgr->lock);
923                 return NULL;
924         }
925
926         bufmgr->bo_cnt++;
927
928         bo->bufmgr = bufmgr;
929
930         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
931         if (!bo_priv) {
932                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
933                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
934                 free(bo);
935                 pthread_mutex_unlock(&bufmgr->lock);
936                 return NULL;
937         }
938
939         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
940                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
941                         if (bo2->priv == bo_priv) {
942                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
943                                                         bo2, bo2->ref_cnt, fd, tbm_flag_to_str(bo2->flags));
944                                 bo2->ref_cnt++;
945                                 free(bo);
946                                 pthread_mutex_unlock(&bufmgr->lock);
947                                 return bo2;
948                         }
949                 }
950         }
951
952         bo->ref_cnt = 1;
953         bo->priv = bo_priv;
954
955         if (bufmgr->backend->bo_get_flags)
956                 bo->flags = bufmgr->backend->bo_get_flags(bo);
957         else
958                 bo->flags = TBM_BO_DEFAULT;
959
960         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
961                                 bo, bo->ref_cnt, fd, tbm_flag_to_str(bo->flags));
962
963         LIST_INITHEAD(&bo->user_data_list);
964
965         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
966
967         pthread_mutex_unlock(&bufmgr->lock);
968
969         return bo;
970 }
971
972 tbm_key
973 tbm_bo_export(tbm_bo bo)
974 {
975         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
976
977         tbm_bufmgr bufmgr;
978         tbm_key ret;
979
980         bufmgr = bo->bufmgr;
981
982         pthread_mutex_lock(&bufmgr->lock);
983
984         ret = bufmgr->backend->bo_export(bo);
985         if (!ret) {
986                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
987                 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
988                 pthread_mutex_unlock(&bufmgr->lock);
989                 return ret;
990         }
991
992         TBM_TRACE("bo(%p) tbm_key(%d)\n", bo, ret);
993
994         pthread_mutex_unlock(&bufmgr->lock);
995
996         return ret;
997 }
998
999 tbm_fd
1000 tbm_bo_export_fd(tbm_bo bo)
1001 {
1002         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1003
1004         tbm_bufmgr bufmgr;
1005         int ret;
1006
1007         bufmgr = bo->bufmgr;
1008
1009         pthread_mutex_lock(&bufmgr->lock);
1010
1011         ret = bufmgr->backend->bo_export_fd(bo);
1012         if (ret < 0) {
1013                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1014                 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1015                 pthread_mutex_unlock(&bufmgr->lock);
1016                 return ret;
1017         }
1018
1019         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1020
1021         pthread_mutex_unlock(&bufmgr->lock);
1022
1023         return ret;
1024 }
1025
1026 tbm_bo_handle
1027 tbm_bo_get_handle(tbm_bo bo, int device)
1028 {
1029         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1030
1031         tbm_bufmgr bufmgr;
1032         tbm_bo_handle bo_handle;
1033
1034         bufmgr = bo->bufmgr;
1035
1036         pthread_mutex_lock(&bufmgr->lock);
1037
1038         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1039         if (bo_handle.ptr == NULL) {
1040                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1041                 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1042                 pthread_mutex_unlock(&bufmgr->lock);
1043                 return (tbm_bo_handle) NULL;
1044         }
1045
1046         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1047
1048         pthread_mutex_unlock(&bufmgr->lock);
1049
1050         return bo_handle;
1051 }
1052
1053 tbm_bo_handle
1054 tbm_bo_map(tbm_bo bo, int device, int opt)
1055 {
1056         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1057
1058         tbm_bufmgr bufmgr;
1059         tbm_bo_handle bo_handle;
1060
1061         bufmgr = bo->bufmgr;
1062
1063         pthread_mutex_lock(&bufmgr->lock);
1064
1065         if (!_tbm_bo_lock(bo, device, opt)) {
1066                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1067                 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1068                 pthread_mutex_unlock(&bufmgr->lock);
1069                 return (tbm_bo_handle) NULL;
1070         }
1071
1072         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1073         if (bo_handle.ptr == NULL) {
1074                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1075                 TBM_TRACE("error: fail to map bo:%p\n", bo);
1076                 _tbm_bo_unlock(bo);
1077                 pthread_mutex_unlock(&bufmgr->lock);
1078                 return (tbm_bo_handle) NULL;
1079         }
1080
1081         /* increase the map_count */
1082         bo->map_cnt++;
1083
1084         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1085
1086         pthread_mutex_unlock(&bufmgr->lock);
1087
1088         return bo_handle;
1089 }
1090
1091 int
1092 tbm_bo_unmap(tbm_bo bo)
1093 {
1094         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1095
1096         tbm_bufmgr bufmgr;
1097         int ret;
1098
1099         bufmgr = bo->bufmgr;
1100
1101         pthread_mutex_lock(&bufmgr->lock);
1102
1103         ret = bufmgr->backend->bo_unmap(bo);
1104         if (!ret) {
1105                 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1106                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1107                 pthread_mutex_unlock(&bufmgr->lock);
1108                 return ret;
1109         }
1110
1111         /* decrease the map_count */
1112         bo->map_cnt--;
1113
1114         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1115
1116         _tbm_bo_unlock(bo);
1117
1118         pthread_mutex_unlock(&bufmgr->lock);
1119
1120         return ret;
1121 }
1122
1123 int
1124 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1125 {
1126         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1127         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1128
1129         void *temp;
1130
1131         pthread_mutex_lock(&bo1->bufmgr->lock);
1132
1133         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1134
1135         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1136                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1137                 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1138         pthread_mutex_unlock(&bo1->bufmgr->lock);
1139                 return 0;
1140         }
1141
1142         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1143
1144         temp = bo1->priv;
1145         bo1->priv = bo2->priv;
1146         bo2->priv = temp;
1147
1148         pthread_mutex_unlock(&bo1->bufmgr->lock);
1149
1150         return 1;
1151 }
1152
1153 int
1154 tbm_bo_locked(tbm_bo bo)
1155 {
1156         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1157
1158         tbm_bufmgr bufmgr;
1159
1160         bufmgr = bo->bufmgr;
1161
1162         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1163                 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1164                 return 0;
1165         }
1166
1167         pthread_mutex_lock(&bufmgr->lock);
1168
1169
1170         if (bo->lock_cnt > 0) {
1171                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1172                 pthread_mutex_unlock(&bufmgr->lock);
1173                 return 1;
1174         }
1175
1176         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1177         pthread_mutex_unlock(&bufmgr->lock);
1178
1179         return 0;
1180 }
1181
1182 int
1183 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1184                      tbm_data_free data_free_func)
1185 {
1186         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1187
1188         tbm_user_data *data;
1189
1190         /* check if the data according to the key exist if so, return false. */
1191         data = user_data_lookup(&bo->user_data_list, key);
1192         if (data) {
1193                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1194                 return 0;
1195         }
1196
1197         data = user_data_create(key, data_free_func);
1198         if (!data) {
1199                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1200                 return 0;
1201         }
1202
1203         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1204
1205         LIST_ADD(&data->item_link, &bo->user_data_list);
1206
1207         return 1;
1208 }
1209
1210 int
1211 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1212 {
1213         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1214
1215         tbm_user_data *old_data;
1216
1217         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1218                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1219                 return 0;
1220         }
1221
1222         old_data = user_data_lookup(&bo->user_data_list, key);
1223         if (!old_data) {
1224                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1225                 return 0;
1226         }
1227
1228         if (old_data->data && old_data->free_func)
1229                 old_data->free_func(old_data->data);
1230
1231         old_data->data = data;
1232
1233         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1234
1235         return 1;
1236 }
1237
1238 int
1239 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1240 {
1241         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1242
1243         tbm_user_data *old_data;
1244
1245         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1246                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1247                 return 0;
1248         }
1249
1250         old_data = user_data_lookup(&bo->user_data_list, key);
1251         if (!old_data) {
1252                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1253                 *data = NULL;
1254                 return 0;
1255         }
1256
1257         *data = old_data->data;
1258
1259         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1260
1261         return 1;
1262 }
1263
1264 int
1265 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1266 {
1267         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1268
1269         tbm_user_data *old_data = (void *)0;
1270
1271         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1272                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1273                 return 0;
1274         }
1275
1276         old_data = user_data_lookup(&bo->user_data_list, key);
1277         if (!old_data) {
1278                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1279                 return 0;
1280         }
1281
1282         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1283
1284         user_data_delete(old_data);
1285
1286         return 1;
1287 }
1288
1289 unsigned int
1290 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1291 {
1292         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1293
1294         TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1295
1296         return bufmgr->capabilities;
1297 }
1298
1299 int
1300 tbm_bo_get_flags(tbm_bo bo)
1301 {
1302         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1303
1304         TBM_TRACE("bo(%p)\n", bo);
1305
1306         return bo->flags;
1307 }
1308
1309 /* LCOV_EXCL_START */
1310 tbm_error_e
1311 tbm_get_last_error(void)
1312 {
1313         return tbm_last_error;
1314 }
1315
1316 void
1317 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1318 {
1319         TBM_RETURN_IF_FAIL(bufmgr != NULL);
1320         tbm_bo bo = NULL, tmp_bo = NULL;
1321         int bo_cnt = 0;
1322
1323         tbm_surface_h surf = NULL, tmp_surf = NULL;
1324         int surf_cnt = 0;
1325         int i;
1326         char app_name[255] = {0,};
1327         unsigned int pid = 0;
1328         char title[255] = {0,};
1329         char data[255] = {0,};
1330         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1331
1332         pthread_mutex_lock(&gLock);
1333
1334         TBM_DEBUG("\n");
1335         _tbm_util_get_appname_from_pid(getpid(), app_name);
1336         _tbm_util_get_appname_brief(app_name);
1337         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1338                   app_name, getpid());
1339         memset(app_name, 0x0, 255 * sizeof(char));
1340         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1341         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1342                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1343                         strncat(title, "  ", 2);
1344                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1345                 }
1346         }
1347
1348         TBM_DEBUG("[tbm_surface information]\n");
1349         TBM_DEBUG("%s\n", title);
1350         /* show the tbm_surface information in surf_list */
1351         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1352                 char *value = NULL;
1353
1354                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1355                         pid = _tbm_surface_internal_get_debug_pid(surf);
1356                         if (!pid) {
1357                                 /* if pid is null, set the self_pid */
1358                                 pid = getpid();
1359                         }
1360
1361                         _tbm_util_get_appname_from_pid(pid, app_name);
1362                         _tbm_util_get_appname_brief(app_name);
1363
1364                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5d  %-6d  %-3d  %-6d   %-2d   %-2d    %-3d  %-8s  %-15s",
1365                                   ++surf_cnt,
1366                                   surf,
1367                                   surf->refcnt,
1368                                   surf->info.width,
1369                                   surf->info.height,
1370                                   surf->info.bpp,
1371                                   surf->info.size / 1024,
1372                                   surf->num_bos,
1373                                   surf->num_planes,
1374                                   surf->flags,
1375                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1376                                   app_name);
1377
1378                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1379                                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1380                                         strncat(data, "  ", 2);
1381
1382                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1383                                         if (value)
1384                                                 strncat(data, value, strlen(value) + 1);
1385                                         else
1386                                                 strncat(data, "none", strlen("none") + 1);
1387                                 }
1388                         }
1389                         TBM_DEBUG("%s\n", data);
1390
1391                         for (i = 0; i < surf->num_bos; i++) {
1392                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1393                                           surf->bos[i],
1394                                           surf->bos[i]->ref_cnt,
1395                                           tbm_bo_size(surf->bos[i]) / 1024);
1396                         }
1397
1398                         memset(app_name, 0x0, 255 * sizeof(char));
1399                 }
1400         } else {
1401                 TBM_DEBUG("no tbm_surfaces.\n");
1402         }
1403         TBM_DEBUG("\n");
1404
1405         TBM_DEBUG("[tbm_bo information]\n");
1406         TBM_DEBUG("no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1407
1408         /* show the tbm_bo information in bo_list */
1409         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1410                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1411                         TBM_DEBUG("%-4d%-11p   %-4d  %-6d     %-5d     %-4d    %-3d  %-11p\n",
1412                                   ++bo_cnt,
1413                                   bo,
1414                                   bo->ref_cnt,
1415                                   tbm_bo_size(bo) / 1024,
1416                                   bo->lock_cnt,
1417                                   bo->map_cnt,
1418                                   bo->flags,
1419                                   bo->surface);
1420                 }
1421         } else {
1422                 TBM_DEBUG("no tbm_bos.\n");
1423         }
1424         TBM_DEBUG("\n");
1425
1426         TBM_DEBUG("===============================================================\n");
1427
1428         pthread_mutex_unlock(&gLock);
1429
1430 }
1431
1432 void
1433 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1434 {
1435 #ifdef TRACE
1436         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1437         bTrace = onoff;
1438 #endif
1439 }
1440
1441 int
1442 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1443 {
1444         TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1445
1446         if (onoff == 1) {
1447
1448                 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1449
1450                 int w = 0, h = 0;
1451                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1452                         TBM_LOG_I("No tbm_surface.\n");
1453                         return 0;
1454                 }
1455
1456                 tbm_surface_internal_dump_start(path, w, h, count);
1457                 b_dump_queue = 1;
1458
1459         } else if (onoff == 0) {
1460
1461                 tbm_surface_internal_dump_end();
1462                 b_dump_queue = 0;
1463
1464         } else {
1465                 return 0;
1466         }
1467
1468         return 1;
1469 }
1470
1471 int
1472 tbm_bufmgr_debug_dump_all(char *path)
1473 {
1474         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1475
1476         TBM_LOG_D("path=%s\n", path);
1477         int w = 0, h = 0, count = 0;
1478         tbm_surface_h surface = NULL, tmp = NULL;
1479
1480         count = _tbm_util_get_max_surface_size(&w, &h);
1481         if (count == 0) {
1482                 TBM_LOG_I("No tbm_surface.\n");
1483                 return 1;
1484         }
1485
1486         tbm_surface_internal_dump_start(path, w, h, count);
1487
1488         LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1489                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1490         }
1491
1492         tbm_surface_internal_dump_end();
1493
1494         return 1;
1495
1496 }
1497
1498 /* internal function */
1499 tbm_bufmgr
1500 _tbm_bufmgr_get_bufmgr(void)
1501 {
1502         return gBufMgr;
1503 }
1504
1505 int
1506 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1507 {
1508         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1509
1510         bo->surface = surface;
1511
1512         return 1;
1513 }
1514
1515 int
1516 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1517 {
1518         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1519
1520         int ret;
1521
1522         pthread_mutex_lock(&bufmgr->lock);
1523
1524         if (!bufmgr->backend->bufmgr_bind_native_display) {
1525                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1526                 pthread_mutex_unlock(&bufmgr->lock);
1527                 return 1;
1528         }
1529
1530         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1531         if (!ret) {
1532                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1533                 pthread_mutex_unlock(&bufmgr->lock);
1534                 return 0;
1535         }
1536
1537         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1538
1539         pthread_mutex_unlock(&bufmgr->lock);
1540
1541         return 1;
1542 }
1543 /* LCOV_EXCL_STOP */