7fb555750304f816af8dc679fd1a5f5e0043bd63
[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         TBMModuleVersionInfo *vers;
482         TBMModuleData *initdata;
483         ModuleInitProc init;
484         void *module_data;
485
486         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
487
488         module_data = dlopen(path, RTLD_LAZY);
489         if (!module_data) {
490                 TBM_LOG_E("failed to load module: %s(%s)\n", dlerror(), file);
491                 return 0;
492         }
493
494         initdata = dlsym(module_data, "tbmModuleData");
495         if (!initdata) {
496                 TBM_LOG_E("Error: module does not have data object.\n");
497                 goto err;
498         }
499
500         vers = initdata->vers;
501         if (!vers) {
502                 TBM_LOG_E("Error: module does not supply version information.\n");
503                 goto err;
504         }
505
506         init = initdata->init;
507         if (!init) {
508                 TBM_LOG_E("Error: module does not supply init symbol.\n");
509                 goto err;
510         }
511
512         if (!_check_version(vers)) {
513                 TBM_LOG_E("Fail to check version.\n");
514                 goto err;
515         }
516
517         if (!init(bufmgr, fd)) {
518                 TBM_LOG_E("Fail to init module(%s)\n", file);
519                 goto err;
520         }
521
522         if (!bufmgr->backend || !bufmgr->backend->priv) {
523                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
524                 goto err;
525         }
526
527         bufmgr->module_data = module_data;
528
529         TBM_DBG("Success to load module(%s)\n", file);
530
531         return 1;
532
533 err:
534         dlclose(module_data);
535         return 0;
536 }
537
538 static int
539 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
540 {
541         struct dirent **namelist;
542         int ret = 0, n;
543
544         /* load bufmgr priv from default lib */
545         if (_tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB))
546                 return 1;
547
548         /* load bufmgr priv from configured path */
549         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
550         if (n < 0) {
551                 TBM_LOG_E("no files : %s\n", BUFMGR_MODULE_DIR);
552                 return 0;
553         }
554
555         while (n--) {
556                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
557                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
558
559                         if (p && !strcmp(p, SUFFIX_LIB))
560                                 ret = _tbm_bufmgr_load_module(bufmgr, fd,
561                                                         namelist[n]->d_name);
562                 }
563
564                 free(namelist[n]);
565         }
566
567         free(namelist);
568
569         return ret;
570 }
571 /* LCOV_EXCL_STOP */
572
573 tbm_bufmgr
574 tbm_bufmgr_init(int fd)
575 {
576 #ifdef TBM_BUFMGR_INIT_TIME
577         struct timeval start_tv, end_tv;
578 #endif
579         char *env;
580
581 #ifdef TBM_BUFMGR_INIT_TIME
582         /* get the start tv */
583         gettimeofday(&start_tv, NULL);
584 #endif
585
586         /* LCOV_EXCL_START */
587 #ifdef HAVE_DLOG
588         env = getenv("TBM_DLOG");
589         if (env) {
590                 bDlog = atoi(env);
591                 TBM_LOG_D("TBM_DLOG=%s\n", env);
592         } else
593                 bDlog = 1;
594 #endif
595
596 #ifdef DEBUG
597         env = getenv("TBM_DEBUG");
598         if (env) {
599                 bDebug = atoi(env);
600                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
601         } else
602                 bDebug = 0;
603 #endif
604
605 #ifdef TRACE
606         env = getenv("TBM_TRACE");
607         if (env) {
608                 bTrace = atoi(env);
609                 TBM_LOG_D("TBM_TRACE=%s\n", env);
610         } else
611                 bTrace = 0;
612 #endif
613         /* LCOV_EXCL_STOP */
614
615         pthread_mutex_lock(&gLock);
616
617         /* initialize buffer manager */
618         if (gBufMgr) {
619                 gBufMgr->ref_count++;
620                 TBM_TRACE("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
621                 pthread_mutex_unlock(&gLock);
622                 return gBufMgr;
623         }
624
625         TBM_DBG("bufmgr init\n");
626
627         /* allocate bufmgr */
628         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
629         if (!gBufMgr) {
630                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
631                 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
632                 pthread_mutex_unlock(&gLock);
633                 return NULL;
634         }
635
636         gBufMgr->fd = fd;
637
638         /* load bufmgr priv from env */
639         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
640                 /* LCOV_EXCL_START */
641                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
642                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
643                 free(gBufMgr);
644                 gBufMgr = NULL;
645                 pthread_mutex_unlock(&gLock);
646                 return NULL;
647                 /* LCOV_EXCL_STOP */
648         }
649
650         /* log for tbm backend_flag */
651         TBM_DBG("backend flag:%x:", gBufMgr->backend->flags);
652         TBM_DBG("\n");
653
654         gBufMgr->ref_count = 1;
655
656         TBM_DBG("create tizen bufmgr:%p ref_count:%d\n",
657             gBufMgr, gBufMgr->ref_count);
658
659         /* setup the lock_type */
660         env = getenv("BUFMGR_LOCK_TYPE");
661         if (env && !strcmp(env, "always"))
662                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
663         else if (env && !strcmp(env, "none"))
664                 gBufMgr->lock_type = LOCK_TRY_NEVER;
665         else if (env && !strcmp(env, "once"))
666                 gBufMgr->lock_type = LOCK_TRY_ONCE;
667         else
668                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
669
670         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
671
672         TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
673
674         /* intialize bo_list */
675         LIST_INITHEAD(&gBufMgr->bo_list);
676
677         /* intialize surf_list */
678         LIST_INITHEAD(&gBufMgr->surf_list);
679
680         /* intialize surf_queue_list */
681         LIST_INITHEAD(&gBufMgr->surf_queue_list);
682
683         /* intialize debug_key_list */
684         LIST_INITHEAD(&gBufMgr->debug_key_list);
685
686 #ifdef TBM_BUFMGR_INIT_TIME
687         /* get the end tv */
688         gettimeofday(&end_tv, NULL);
689         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)));
690 #endif
691
692         pthread_mutex_unlock(&gLock);
693
694         return gBufMgr;
695 }
696
697 void
698 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
699 {
700         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
701
702         pthread_mutex_lock(&gLock);
703
704         if (!gBufMgr) {
705                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
706                 pthread_mutex_unlock(&gLock);
707                 return;
708         }
709
710         bufmgr->ref_count--;
711         if (bufmgr->ref_count > 0) {
712                 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
713                 pthread_mutex_unlock(&gLock);
714                 return;
715         }
716
717         /* destroy bo_list */
718         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
719                 tbm_bo bo = NULL, tmp;
720
721                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
722                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
723                         bo->ref_cnt = 1;
724                         tbm_bo_unref(bo);
725                 }
726         }
727
728         /* destroy surf_list */
729         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
730                 tbm_surface_h surf = NULL, tmp;
731
732                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
733                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
734                         tbm_surface_destroy(surf);
735                 }
736         }
737
738         /* destroy bufmgr priv */
739         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
740         bufmgr->backend->priv = NULL;
741         tbm_backend_free(bufmgr->backend);
742         bufmgr->backend = NULL;
743
744         TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
745
746         dlclose(bufmgr->module_data);
747
748         if (bufmgr->fd > 0)
749                 close(bufmgr->fd);
750
751         free(bufmgr);
752         gBufMgr = NULL;
753
754         pthread_mutex_unlock(&gLock);
755 }
756
757 int
758 tbm_bo_size(tbm_bo bo)
759 {
760         tbm_bufmgr bufmgr = NULL;
761         int size;
762
763         _tbm_bufmgr_mutex_lock();
764
765         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
766         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
767
768         bufmgr = gBufMgr;
769
770         size = bufmgr->backend->bo_size(bo);
771
772         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
773
774         _tbm_bufmgr_mutex_unlock();
775
776         return size;
777 }
778
779 tbm_bo
780 tbm_bo_ref(tbm_bo bo)
781 {
782         _tbm_bufmgr_mutex_lock();
783
784         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
785         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
786
787         bo->ref_cnt++;
788
789         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
790
791         _tbm_bufmgr_mutex_unlock();
792
793         return bo;
794 }
795
796 void
797 tbm_bo_unref(tbm_bo bo)
798 {
799         tbm_bufmgr bufmgr = NULL;
800         tbm_user_data *old_data = NULL, *tmp = NULL;
801
802         _tbm_bufmgr_mutex_lock();
803
804         TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
805         TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
806
807         bufmgr = gBufMgr;
808
809         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
810
811         if (bo->ref_cnt <= 0) {
812                 _tbm_bufmgr_mutex_unlock();
813                 return;
814         }
815
816         bo->ref_cnt--;
817         if (bo->ref_cnt == 0) {
818                 /* destory the user_data_list */
819                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
820                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
821                                 TBM_DBG("free user_data\n");
822                                 user_data_delete(old_data);
823                         }
824                 }
825
826                 while (bo->lock_cnt > 0) {
827                         TBM_LOG_E("error lock_cnt:%d\n",
828                                 bo->lock_cnt);
829                         _bo_unlock(bo);
830                         bo->lock_cnt--;
831                 }
832
833                 /* call the bo_free */
834                 bufmgr->backend->bo_free(bo);
835                 bo->priv = NULL;
836
837                 LIST_DEL(&bo->item_link);
838                 free(bo);
839
840                 bufmgr->bo_cnt--;
841         }
842
843         _tbm_bufmgr_mutex_unlock();
844 }
845
846 tbm_bo
847 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
848 {
849         tbm_bo bo = NULL;
850         void *bo_priv = NULL;
851
852         _tbm_bufmgr_mutex_lock();
853
854         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
855         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
856         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
857
858         bo = calloc(1, sizeof(struct _tbm_bo));
859         if (!bo) {
860                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n",
861                                 size, _tbm_flag_to_str(flags));
862                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
863                 _tbm_bufmgr_mutex_unlock();
864                 return NULL;
865         }
866
867         _tbm_util_check_bo_cnt(bufmgr);
868         bufmgr->bo_cnt++;
869
870         bo->bufmgr = bufmgr;
871
872         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
873         if (!bo_priv) {
874                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n",
875                                 size, _tbm_flag_to_str(flags));
876                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
877                 free(bo);
878                 _tbm_bufmgr_mutex_unlock();
879                 return NULL;
880         }
881
882         bo->ref_cnt = 1;
883         bo->flags = flags;
884         bo->priv = bo_priv;
885
886         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
887                         _tbm_flag_to_str(bo->flags));
888
889         LIST_INITHEAD(&bo->user_data_list);
890
891         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
892
893         _tbm_bufmgr_mutex_unlock();
894
895         return bo;
896 }
897
898 tbm_bo
899 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
900 {
901         tbm_bo bo = NULL;
902         tbm_bo bo2 = NULL;
903         tbm_bo tmp = NULL;
904         void *bo_priv = NULL;
905
906         _tbm_bufmgr_mutex_lock();
907
908         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
909         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
910
911         if (!bufmgr->backend->bo_import) {
912                 _tbm_bufmgr_mutex_unlock();
913                 return NULL;
914         }
915
916         _tbm_util_check_bo_cnt(bufmgr);
917
918         bo = calloc(1, sizeof(struct _tbm_bo));
919         if (!bo) {
920                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
921                 _tbm_bufmgr_mutex_unlock();
922                 return NULL;
923         }
924
925         bo->bufmgr = bufmgr;
926
927         bo_priv = bufmgr->backend->bo_import(bo, key);
928         if (!bo_priv) {
929                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
930                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
931                 free(bo);
932                 _tbm_bufmgr_mutex_unlock();
933                 return NULL;
934         }
935
936         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
937                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
938                         if (bo2->priv == bo_priv) {
939                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
940                                                 bo2, bo2->ref_cnt, key,
941                                                 _tbm_flag_to_str(bo2->flags));
942                                 bo2->ref_cnt++;
943                                 free(bo);
944                                 _tbm_bufmgr_mutex_unlock();
945                                 return bo2;
946                         }
947                 }
948         }
949
950         bufmgr->bo_cnt++;
951
952         bo->ref_cnt = 1;
953         bo->priv = bo_priv;
954
955         if (bufmgr->backend->bo_get_flags)
956                 bo->flags = bufmgr->backend->bo_get_flags(bo);
957         else
958                 bo->flags = TBM_BO_DEFAULT;
959
960         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
961                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
962
963         LIST_INITHEAD(&bo->user_data_list);
964
965         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
966
967         _tbm_bufmgr_mutex_unlock();
968
969         return bo;
970 }
971
972 tbm_bo
973 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
974 {
975         tbm_bo bo = NULL;
976         tbm_bo bo2 = NULL;
977         tbm_bo tmp = NULL;
978         void *bo_priv = NULL;
979
980         _tbm_bufmgr_mutex_lock();
981
982         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
983         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
984
985         if (!bufmgr->backend->bo_import_fd) {
986                 _tbm_bufmgr_mutex_unlock();
987                 return NULL;
988         }
989
990         _tbm_util_check_bo_cnt(bufmgr);
991
992         bo = calloc(1, sizeof(struct _tbm_bo));
993         if (!bo) {
994                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
995                 _tbm_bufmgr_mutex_unlock();
996                 return NULL;
997         }
998
999         bo->bufmgr = bufmgr;
1000
1001         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1002         if (!bo_priv) {
1003                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1004                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1005                 free(bo);
1006                 _tbm_bufmgr_mutex_unlock();
1007                 return NULL;
1008         }
1009
1010         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1011                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1012                         if (bo2->priv == bo_priv) {
1013                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1014                                                 bo2, bo2->ref_cnt, fd,
1015                                                 _tbm_flag_to_str(bo2->flags));
1016                                 bo2->ref_cnt++;
1017                                 free(bo);
1018                                 _tbm_bufmgr_mutex_unlock();
1019                                 return bo2;
1020                         }
1021                 }
1022         }
1023
1024         bufmgr->bo_cnt++;
1025
1026         bo->ref_cnt = 1;
1027         bo->priv = bo_priv;
1028
1029         if (bufmgr->backend->bo_get_flags)
1030                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1031         else
1032                 bo->flags = TBM_BO_DEFAULT;
1033
1034         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
1035                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
1036
1037         LIST_INITHEAD(&bo->user_data_list);
1038
1039         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1040
1041         _tbm_bufmgr_mutex_unlock();
1042
1043         return bo;
1044 }
1045
1046 tbm_key
1047 tbm_bo_export(tbm_bo bo)
1048 {
1049         tbm_bufmgr bufmgr = NULL;
1050         tbm_key ret;
1051
1052         _tbm_bufmgr_mutex_lock();
1053
1054         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1055         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1056
1057         bufmgr = gBufMgr;
1058
1059         if (!bufmgr->backend->bo_export) {
1060                 _tbm_bufmgr_mutex_unlock();
1061                 return 0;
1062         }
1063
1064         ret = bufmgr->backend->bo_export(bo);
1065         if (!ret) {
1066                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1067                 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
1068                 _tbm_bufmgr_mutex_unlock();
1069                 return ret;
1070         }
1071
1072         TBM_TRACE("bo(%p) tbm_key(%d)\n", bo, ret);
1073
1074         _tbm_bufmgr_mutex_unlock();
1075
1076         return ret;
1077 }
1078
1079 tbm_fd
1080 tbm_bo_export_fd(tbm_bo bo)
1081 {
1082         tbm_bufmgr bufmgr = NULL;
1083         int ret;
1084
1085         _tbm_bufmgr_mutex_lock();
1086
1087         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1088         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1089
1090         bufmgr = gBufMgr;
1091
1092         if (!bufmgr->backend->bo_export_fd) {
1093                 _tbm_bufmgr_mutex_unlock();
1094                 return -1;
1095         }
1096
1097         ret = bufmgr->backend->bo_export_fd(bo);
1098         if (ret < 0) {
1099                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1100                 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1101                 _tbm_bufmgr_mutex_unlock();
1102                 return ret;
1103         }
1104
1105         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1106
1107         _tbm_bufmgr_mutex_unlock();
1108
1109         return ret;
1110 }
1111
1112 tbm_bo_handle
1113 tbm_bo_get_handle(tbm_bo bo, int device)
1114 {
1115         tbm_bufmgr bufmgr = NULL;
1116         tbm_bo_handle bo_handle;
1117
1118         _tbm_bufmgr_mutex_lock();
1119
1120         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1121         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1122
1123         bufmgr = gBufMgr;
1124
1125         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1126         if (bo_handle.ptr == NULL) {
1127                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1128                 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1129                 _tbm_bufmgr_mutex_unlock();
1130                 return (tbm_bo_handle) NULL;
1131         }
1132
1133         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1134
1135         _tbm_bufmgr_mutex_unlock();
1136
1137         return bo_handle;
1138 }
1139
1140 tbm_bo_handle
1141 tbm_bo_map(tbm_bo bo, int device, int opt)
1142 {
1143         tbm_bufmgr bufmgr = NULL;
1144         tbm_bo_handle bo_handle;
1145
1146         _tbm_bufmgr_mutex_lock();
1147
1148         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1149         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1150
1151         bufmgr = gBufMgr;
1152
1153         if (!_tbm_bo_lock(bo, device, opt)) {
1154                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1155                 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1156                 _tbm_bufmgr_mutex_unlock();
1157                 return (tbm_bo_handle) NULL;
1158         }
1159
1160         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1161         if (bo_handle.ptr == NULL) {
1162                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1163                 TBM_TRACE("error: fail to map bo:%p\n", bo);
1164                 _tbm_bo_unlock(bo);
1165                 _tbm_bufmgr_mutex_unlock();
1166                 return (tbm_bo_handle) NULL;
1167         }
1168
1169         /* increase the map_count */
1170         bo->map_cnt++;
1171
1172         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1173
1174         _tbm_bufmgr_mutex_unlock();
1175
1176         return bo_handle;
1177 }
1178
1179 int
1180 tbm_bo_unmap(tbm_bo bo)
1181 {
1182         tbm_bufmgr bufmgr = NULL;
1183         int ret;
1184
1185         _tbm_bufmgr_mutex_lock();
1186
1187         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1188         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1189
1190         bufmgr = gBufMgr;
1191
1192         ret = bufmgr->backend->bo_unmap(bo);
1193         if (!ret) {
1194                 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1195                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1196                 _tbm_bufmgr_mutex_unlock();
1197                 return ret;
1198         }
1199
1200         /* decrease the map_count */
1201         bo->map_cnt--;
1202
1203         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1204
1205         _tbm_bo_unlock(bo);
1206
1207         _tbm_bufmgr_mutex_unlock();
1208
1209         return ret;
1210 }
1211
1212 int
1213 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1214 {
1215         tbm_bufmgr bufmgr = NULL;
1216         void *temp;
1217
1218         _tbm_bufmgr_mutex_lock();
1219
1220         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1221         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1222         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1223
1224         bufmgr = gBufMgr;
1225
1226         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1227
1228         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1229                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1230                 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1231                 _tbm_bufmgr_mutex_unlock();
1232                 return 0;
1233         }
1234
1235         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1236
1237         temp = bo1->priv;
1238         bo1->priv = bo2->priv;
1239         bo2->priv = temp;
1240
1241         _tbm_bufmgr_mutex_unlock();
1242
1243         return 1;
1244 }
1245
1246 int
1247 tbm_bo_locked(tbm_bo bo)
1248 {
1249         tbm_bufmgr bufmgr = NULL;
1250
1251         _tbm_bufmgr_mutex_lock();
1252
1253         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1254         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1255
1256         bufmgr = gBufMgr;
1257
1258         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1259                 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1260                 _tbm_bufmgr_mutex_unlock();
1261                 return 0;
1262         }
1263
1264         if (bo->lock_cnt > 0) {
1265                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1266                 _tbm_bufmgr_mutex_unlock();
1267                 return 1;
1268         }
1269
1270         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1271         _tbm_bufmgr_mutex_unlock();
1272
1273         return 0;
1274 }
1275
1276 int
1277 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1278                      tbm_data_free data_free_func)
1279 {
1280         tbm_user_data *data;
1281
1282         _tbm_bufmgr_mutex_lock();
1283
1284         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1285         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1286
1287         /* check if the data according to the key exist if so, return false. */
1288         data = user_data_lookup(&bo->user_data_list, key);
1289         if (data) {
1290                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1291                 _tbm_bufmgr_mutex_unlock();
1292                 return 0;
1293         }
1294
1295         data = user_data_create(key, data_free_func);
1296         if (!data) {
1297                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1298                 _tbm_bufmgr_mutex_unlock();
1299                 return 0;
1300         }
1301
1302         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1303
1304         LIST_ADD(&data->item_link, &bo->user_data_list);
1305
1306         _tbm_bufmgr_mutex_unlock();
1307
1308         return 1;
1309 }
1310
1311 int
1312 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1313 {
1314         tbm_user_data *old_data;
1315
1316         _tbm_bufmgr_mutex_lock();
1317
1318         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1319         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1320
1321         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1322                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1323                 _tbm_bufmgr_mutex_unlock();
1324                 return 0;
1325         }
1326
1327         old_data = user_data_lookup(&bo->user_data_list, key);
1328         if (!old_data) {
1329                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1330                 _tbm_bufmgr_mutex_unlock();
1331                 return 0;
1332         }
1333
1334         if (old_data->data && old_data->free_func)
1335                 old_data->free_func(old_data->data);
1336
1337         old_data->data = data;
1338
1339         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1340
1341         _tbm_bufmgr_mutex_unlock();
1342
1343         return 1;
1344 }
1345
1346 int
1347 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1348 {
1349         tbm_user_data *old_data;
1350
1351         _tbm_bufmgr_mutex_lock();
1352
1353         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1354         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1355
1356         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1357                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1358                 _tbm_bufmgr_mutex_unlock();
1359                 return 0;
1360         }
1361
1362         old_data = user_data_lookup(&bo->user_data_list, key);
1363         if (!old_data) {
1364                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1365                 *data = NULL;
1366                 _tbm_bufmgr_mutex_unlock();
1367                 return 0;
1368         }
1369
1370         *data = old_data->data;
1371
1372         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1373
1374         _tbm_bufmgr_mutex_unlock();
1375
1376         return 1;
1377 }
1378
1379 int
1380 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1381 {
1382         tbm_user_data *old_data = (void *)0;
1383
1384         _tbm_bufmgr_mutex_lock();
1385
1386         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1387         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1388
1389         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1390                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1391                 _tbm_bufmgr_mutex_unlock();
1392                 return 0;
1393         }
1394
1395         old_data = user_data_lookup(&bo->user_data_list, key);
1396         if (!old_data) {
1397                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1398                 _tbm_bufmgr_mutex_unlock();
1399                 return 0;
1400         }
1401
1402         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1403
1404         user_data_delete(old_data);
1405
1406         _tbm_bufmgr_mutex_unlock();
1407
1408         return 1;
1409 }
1410
1411 unsigned int
1412 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1413 {
1414         int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1415
1416         _tbm_bufmgr_mutex_lock();
1417
1418         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1419         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1420
1421         TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1422
1423         capabilities = bufmgr->capabilities;
1424
1425         _tbm_bufmgr_mutex_unlock();
1426
1427         return capabilities;
1428 }
1429
1430 int
1431 tbm_bo_get_flags(tbm_bo bo)
1432 {
1433         int flags;
1434
1435         _tbm_bufmgr_mutex_lock();
1436
1437         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1438         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1439
1440         flags = bo->flags;
1441
1442         TBM_TRACE("bo(%p)\n", bo);
1443
1444         _tbm_bufmgr_mutex_unlock();
1445
1446         return flags;
1447 }
1448
1449 /* LCOV_EXCL_START */
1450 tbm_error_e
1451 tbm_get_last_error(void)
1452 {
1453         return tbm_last_error;
1454 }
1455
1456 void
1457 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1458 {
1459         tbm_bo bo = NULL, tmp_bo = NULL;
1460         int bo_cnt = 0;
1461         tbm_surface_h surf = NULL, tmp_surf = NULL;
1462         int surf_cnt = 0;
1463         int i;
1464         char app_name[255] = {0,};
1465         unsigned int pid = 0;
1466         char title[255] = {0,};
1467         char data[255] = {0,};
1468         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1469
1470         pthread_mutex_lock(&gLock);
1471
1472         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1473                 TBM_LOG_E("invalid bufmgr\n");
1474                 pthread_mutex_unlock(&gLock);
1475                 return;
1476         }
1477
1478         TBM_DEBUG("\n");
1479         _tbm_util_get_appname_from_pid(getpid(), app_name);
1480         _tbm_util_get_appname_brief(app_name);
1481         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1482                   app_name, getpid());
1483         memset(app_name, 0x0, 255 * sizeof(char));
1484         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1485         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1486                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1487                         strncat(title, "  ", 3);
1488                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1489                 }
1490         }
1491
1492         TBM_DEBUG("[tbm_surface information]\n");
1493         TBM_DEBUG("%s\n", title);
1494         /* show the tbm_surface information in surf_list */
1495         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1496                 char *value = NULL;
1497
1498                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1499                         pid = _tbm_surface_internal_get_debug_pid(surf);
1500                         if (!pid) {
1501                                 /* if pid is null, set the self_pid */
1502                                 pid = getpid();
1503                         }
1504
1505                         _tbm_util_get_appname_from_pid(pid, app_name);
1506                         _tbm_util_get_appname_brief(app_name);
1507
1508                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5d  %-6d  %-3d  %-6d   %-2d   %-2d    %-3d  %-8s  %-15s",
1509                                   ++surf_cnt,
1510                                   surf,
1511                                   surf->refcnt,
1512                                   surf->info.width,
1513                                   surf->info.height,
1514                                   surf->info.bpp,
1515                                   surf->info.size / 1024,
1516                                   surf->num_bos,
1517                                   surf->num_planes,
1518                                   surf->flags,
1519                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1520                                   app_name);
1521
1522                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1523                                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1524                                         strncat(data, "  ", 3);
1525
1526                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1527                                         if (value)
1528                                                 strncat(data, value, strlen(value) + 1);
1529                                         else
1530                                                 strncat(data, "none", 5);
1531                                 }
1532                         }
1533                         TBM_DEBUG("%s\n", data);
1534
1535                         for (i = 0; i < surf->num_bos; i++) {
1536                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1537                                           surf->bos[i],
1538                                           surf->bos[i]->ref_cnt,
1539                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1540                         }
1541
1542                         memset(app_name, 0x0, 255 * sizeof(char));
1543                 }
1544         } else {
1545                 TBM_DEBUG("no tbm_surfaces.\n");
1546         }
1547         TBM_DEBUG("\n");
1548
1549         TBM_DEBUG("[tbm_bo information]\n");
1550         TBM_DEBUG("no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1551
1552         /* show the tbm_bo information in bo_list */
1553         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1554                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1555                         TBM_DEBUG("%-4d%-11p   %-4d  %-6d     %-5d     %-4d    %-3d  %-11p\n",
1556                                   ++bo_cnt,
1557                                   bo,
1558                                   bo->ref_cnt,
1559                                   bufmgr->backend->bo_size(bo) / 1024,
1560                                   bo->lock_cnt,
1561                                   bo->map_cnt,
1562                                   bo->flags,
1563                                   bo->surface);
1564                 }
1565         } else {
1566                 TBM_DEBUG("no tbm_bos.\n");
1567         }
1568         TBM_DEBUG("\n");
1569
1570         TBM_DEBUG("===============================================================\n");
1571
1572         pthread_mutex_unlock(&gLock);
1573 }
1574
1575 void
1576 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1577 {
1578         _tbm_bufmgr_mutex_lock();
1579
1580         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1581         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1582
1583 #ifdef TRACE
1584         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1585         bTrace = onoff;
1586 #endif
1587
1588         _tbm_bufmgr_mutex_unlock();
1589 }
1590
1591 int
1592 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1593 {
1594         int w = 0, h = 0;
1595
1596         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1597         TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1598
1599         pthread_mutex_lock(&gLock);
1600
1601         if (onoff == 1) {
1602                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1603                         TBM_LOG_I("No tbm_surface.\n");
1604                         pthread_mutex_unlock(&gLock);
1605                         return 0;
1606                 }
1607
1608                 tbm_surface_internal_dump_start(path, w, h, count);
1609                 b_dump_queue = 1;
1610         } else if (onoff == 0) {
1611                 tbm_surface_internal_dump_end();
1612                 b_dump_queue = 0;
1613         } else {
1614                 pthread_mutex_unlock(&gLock);
1615                 return 0;
1616         }
1617
1618         pthread_mutex_unlock(&gLock);
1619         return 1;
1620 }
1621
1622 int
1623 tbm_bufmgr_debug_dump_all(char *path)
1624 {
1625         int w = 0, h = 0, count = 0;
1626         tbm_surface_h surface = NULL, tmp = NULL;
1627
1628         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1629         TBM_LOG_D("path=%s\n", path);
1630
1631         pthread_mutex_lock(&gLock);
1632
1633         count = _tbm_util_get_max_surface_size(&w, &h);
1634         if (count == 0) {
1635                 TBM_LOG_I("No tbm_surface.\n");
1636                 pthread_mutex_unlock(&gLock);
1637                 return 1;
1638         }
1639
1640         tbm_surface_internal_dump_start(path, w, h, count);
1641
1642         LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1643                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1644         }
1645
1646         tbm_surface_internal_dump_end();
1647
1648         pthread_mutex_unlock(&gLock);
1649
1650         return 1;
1651 }
1652
1653 /* internal function */
1654 tbm_bufmgr
1655 _tbm_bufmgr_get_bufmgr(void)
1656 {
1657         return gBufMgr;
1658 }
1659
1660 int
1661 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1662 {
1663         _tbm_bufmgr_mutex_lock();
1664
1665         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1666         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1667
1668         bo->surface = surface;
1669
1670         _tbm_bufmgr_mutex_unlock();
1671
1672         return 1;
1673 }
1674
1675 int
1676 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1677 {
1678         int ret;
1679
1680         _tbm_bufmgr_mutex_lock();
1681
1682         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1683
1684         if (!bufmgr->backend->bufmgr_bind_native_display) {
1685                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1686                 _tbm_bufmgr_mutex_unlock();
1687                 return 1;
1688         }
1689
1690         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1691         if (!ret) {
1692                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1693                 _tbm_bufmgr_mutex_unlock();
1694                 return 0;
1695         }
1696
1697         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1698
1699         _tbm_bufmgr_mutex_unlock();
1700
1701         return 1;
1702 }
1703 /* LCOV_EXCL_STOP */