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