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