tbm_bufmgr: clean up tbm_bo_***() functions
[platform/core/uifw/libtbm.git] / src / tbm_bufmgr.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
37 #include "list.h"
38
39 #ifdef DEBUG
40 int bDebug;
41 #endif
42
43 #ifdef TRACE
44 int bTrace;
45 #endif
46
47 #ifdef HAVE_DLOG
48 int bDlog;
49 #endif
50
51 tbm_bufmgr gBufMgr;
52 int b_dump_queue;
53
54 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
55 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
56 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
57
58 static void _tbm_bufmgr_mutex_unlock(void);
59
60 //#define TBM_BUFMGR_INIT_TIME
61
62 #define PREFIX_LIB    "libtbm_"
63 #define SUFFIX_LIB    ".so"
64 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
65
66 /* values to indicate unspecified fields in XF86ModReqInfo. */
67 #define MAJOR_UNSPEC        0xFF
68 #define MINOR_UNSPEC        0xFF
69 #define PATCH_UNSPEC        0xFFFF
70 #define ABI_VERS_UNSPEC   0xFFFFFFFF
71
72 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
73                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
74 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
75 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
76 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
77
78 /* check condition */
79 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
80         if (!(cond)) {\
81                 TBM_LOG_E("'%s' failed.\n", #cond);\
82                 _tbm_bufmgr_mutex_unlock();\
83                 return;\
84         } \
85 }
86
87 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
88         if (!(cond)) {\
89                 TBM_LOG_E("'%s' failed.\n", #cond);\
90                 _tbm_bufmgr_mutex_unlock();\
91                 return val;\
92         } \
93 }
94
95 enum {
96         LOCK_TRY_ONCE,
97         LOCK_TRY_ALWAYS,
98         LOCK_TRY_NEVER
99 };
100
101 static void
102 _tbm_set_last_result(tbm_error_e err)
103 {
104         tbm_last_error = err;
105 }
106
107 static bool
108 _tbm_bufmgr_mutex_init(void)
109 {
110         static bool tbm_bufmgr_mutex_init = false;
111
112         if (tbm_bufmgr_mutex_init)
113                 return true;
114
115         if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
116                 TBM_LOG_E("fail: tbm_bufmgr mutex init\n");
117                 return false;
118         }
119
120         tbm_bufmgr_mutex_init = true;
121
122         return true;
123 }
124
125 static void
126 _tbm_bufmgr_mutex_lock(void)
127 {
128         if (!_tbm_bufmgr_mutex_init())
129                 return;
130
131         pthread_mutex_lock(&tbm_bufmgr_lock);
132 }
133
134 static void
135 _tbm_bufmgr_mutex_unlock(void)
136 {
137         pthread_mutex_unlock(&tbm_bufmgr_lock);
138 }
139
140 static char *
141 _tbm_flag_to_str(int f)
142 {
143         static char str[255];
144
145         if (f == TBM_BO_DEFAULT)
146                  snprintf(str, 255, "DEFAULT");
147         else {
148                 int c = 0;
149
150                 if (f & TBM_BO_SCANOUT)
151                         c = snprintf(&str[c], 255, "SCANOUT");
152
153                 if (f & TBM_BO_NONCACHABLE) {
154                         if (c)
155                                 c = snprintf(&str[c], 255, ", ");
156                         c = snprintf(&str[c], 255, "NONCACHABLE,");
157                 }
158
159                 if (f & TBM_BO_WC) {
160                         if (c)
161                                 c = snprintf(&str[c], 255, ", ");
162                         c = snprintf(&str[c], 255, "WC");
163                 }
164         }
165
166         return str;
167 }
168
169 /* LCOV_EXCL_START */
170 static void
171 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
172 {
173         static int last_chk_bo_cnt = 0;
174
175         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
176                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
177                 TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n",
178                                 bufmgr->bo_cnt);
179
180                 tbm_bufmgr_debug_show(bufmgr);
181
182                 last_chk_bo_cnt = bufmgr->bo_cnt;
183         }
184 }
185
186 static int
187 _tbm_util_get_max_surface_size(int *w, int *h)
188 {
189         tbm_surface_info_s info;
190         tbm_surface_h surface = NULL;
191         int count = 0;
192
193         *w = 0;
194         *h = 0;
195
196         if (gBufMgr == NULL || !LIST_IS_EMPTY(&gBufMgr->surf_list))
197                 return count;
198
199         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
200                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
201                         count++;
202                         if (*w < info.width)
203                                 *w = info.width;
204                         if (*h < info.height)
205                                 *h = info.height;
206                 }
207         }
208
209         return count;
210 }
211
212 static void
213 _tbm_util_get_appname_brief(char *brief)
214 {
215         char delim[] = "/";
216         char *token = NULL;
217         char temp[255] = {0,};
218         char *saveptr = NULL;
219
220         token = strtok_r(brief, delim, &saveptr);
221
222         while (token != NULL) {
223                 memset(temp, 0x00, 255 * sizeof(char));
224                 strncpy(temp, token, 254 * sizeof(char));
225                 token = strtok_r(NULL, delim, &saveptr);
226         }
227
228         snprintf(brief, sizeof(temp), "%s", temp);
229 }
230
231 static void
232 _tbm_util_get_appname_from_pid(long pid, char *str)
233 {
234         char fn_cmdline[255] = {0, }, cmdline[255];
235         FILE *fp;
236         int len;
237
238         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
239
240         fp = fopen(fn_cmdline, "r");
241         if (fp == 0) {
242                 fprintf(stderr, "cannot file open %s\n", fn_cmdline);
243                 return;
244         }
245
246         if (!fgets(cmdline, 255, fp)) {
247                 fprintf(stderr, "fail to get appname for pid(%ld)\n", pid);
248                 fclose(fp);
249                 return;
250         }
251
252         fclose(fp);
253
254         len = strlen(cmdline);
255         if (len < 1)
256                 memset(cmdline, 0x00, 255);
257         else
258                 cmdline[len] = 0;
259
260         snprintf(str, sizeof(cmdline), "%s", cmdline);
261 }
262 /* LCOV_EXCL_STOP */
263
264 tbm_user_data
265 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
266 {
267         tbm_user_data *old_data = NULL;
268
269         if (LIST_IS_EMPTY(user_data_list))
270                 return NULL;
271
272         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
273                 if (old_data->key == key)
274                         return old_data;
275         }
276
277         return NULL;
278 }
279
280 tbm_user_data
281 *user_data_create(unsigned long key, tbm_data_free data_free_func)
282 {
283         tbm_user_data *user_data;
284
285         user_data = calloc(1, sizeof(tbm_user_data));
286         if (!user_data)
287                 return NULL;
288
289         user_data->key = key;
290         user_data->free_func = data_free_func;
291
292         return user_data;
293 }
294
295 void
296 user_data_delete(tbm_user_data *user_data)
297 {
298         if (user_data->data && user_data->free_func)
299                 user_data->free_func(user_data->data);
300
301         LIST_DEL(&user_data->item_link);
302
303         free(user_data);
304 }
305
306 static int
307 _bo_lock(tbm_bo bo, int device, int opt)
308 {
309         tbm_bufmgr bufmgr = bo->bufmgr;
310         int ret = 1;
311
312         if (bufmgr->backend->bo_lock)
313                 ret = bufmgr->backend->bo_lock(bo, device, opt);
314
315         return ret;
316 }
317
318 static void
319 _bo_unlock(tbm_bo bo)
320 {
321         tbm_bufmgr bufmgr = bo->bufmgr;
322
323         if (bufmgr->backend->bo_unlock)
324                 bufmgr->backend->bo_unlock(bo);
325 }
326
327 static int
328 _tbm_bo_lock(tbm_bo bo, int device, int opt)
329 {
330         tbm_bufmgr bufmgr;
331         int old, ret;
332
333         if (!bo)
334                 return 0;
335
336         bufmgr = bo->bufmgr;
337
338         /* do not try to lock the bo */
339         if (bufmgr->lock_type == LOCK_TRY_NEVER)
340                 return 1;
341
342         if (bo->lock_cnt < 0) {
343                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
344                         bo, bo->lock_cnt);
345                 return 0;
346         }
347
348         old = bo->lock_cnt;
349
350         switch (bufmgr->lock_type) {
351         case LOCK_TRY_ONCE:
352                 if (bo->lock_cnt == 0) {
353                         _tbm_bufmgr_mutex_unlock();
354                         ret = _bo_lock(bo, device, opt);
355                         _tbm_bufmgr_mutex_lock();
356                         if (ret)
357                                 bo->lock_cnt++;
358                 } else
359                         ret = 1;
360                 break;
361         case LOCK_TRY_ALWAYS:
362                 _tbm_bufmgr_mutex_unlock();
363                 ret = _bo_lock(bo, device, opt);
364                 _tbm_bufmgr_mutex_lock();
365                 if (ret)
366                         bo->lock_cnt++;
367                 break;
368         default:
369                 TBM_LOG_E("error bo:%p lock_type[%d] is wrong.\n",
370                                 bo, bufmgr->lock_type);
371                 ret = 0;
372                 break;
373         }
374
375         TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
376
377         return ret;
378 }
379
380 static void
381 _tbm_bo_unlock(tbm_bo bo)
382 {
383         tbm_bufmgr bufmgr;
384         int old;
385
386         if (!bo)
387                 return;
388
389         bufmgr = bo->bufmgr;
390
391         /* do not try to unlock the bo */
392         if (bufmgr->lock_type == LOCK_TRY_NEVER)
393                 return;
394
395         old = bo->lock_cnt;
396
397         switch (bufmgr->lock_type) {
398         case LOCK_TRY_ONCE:
399                 if (bo->lock_cnt > 0) {
400                         bo->lock_cnt--;
401                         if (bo->lock_cnt == 0)
402                                 _bo_unlock(bo);
403                 }
404                 break;
405         case LOCK_TRY_ALWAYS:
406                 if (bo->lock_cnt > 0) {
407                         bo->lock_cnt--;
408                         _bo_unlock(bo);
409                 }
410                 break;
411         default:
412                 TBM_LOG_E("error bo:%p lock_type[%d] is wrong.\n",
413                                 bo, bufmgr->lock_type);
414                 break;
415         }
416
417         if (bo->lock_cnt < 0)
418                 bo->lock_cnt = 0;
419
420         TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
421 }
422
423 static int
424 _tbm_bo_is_valid(tbm_bo bo)
425 {
426         tbm_bo old_data;
427
428         if (bo == NULL || gBufMgr == NULL) {
429                 TBM_LOG_E("error: bo is NULL or tbm_bufmgr was deinited\n");
430                 return 0;
431         }
432
433         if (LIST_IS_EMPTY(&gBufMgr->bo_list))
434                 return 0;
435
436         LIST_FOR_EACH_ENTRY(old_data, &gBufMgr->bo_list, item_link) {
437                 if (old_data == bo)
438                         return 1;
439         }
440
441         return 0;
442 }
443
444 /* LCOV_EXCL_START */
445 static int
446 _check_version(TBMModuleVersionInfo *data)
447 {
448         int abimaj, abimin;
449         int vermaj, vermin;
450
451         abimaj = GET_ABI_MAJOR(data->abiversion);
452         abimin = GET_ABI_MINOR(data->abiversion);
453
454         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
455             data->modname ? data->modname : "UNKNOWN!",
456             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
457
458         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
459         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
460
461         TBM_DBG("TBM ABI version %d.%d\n",
462             vermaj, vermin);
463
464         if (abimaj != vermaj) {
465                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
466                         abimaj, vermaj);
467                 return 0;
468         } else if (abimin > vermin) {
469                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
470                         abimin, vermin);
471                 return 0;
472         }
473
474         return 1;
475 }
476
477 static int
478 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
479 {
480         char path[PATH_MAX] = {0, };
481         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 = gBufMgr;
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         size = bufmgr->backend->bo_size(bo);
769
770         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
771
772         _tbm_bufmgr_mutex_unlock();
773
774         return size;
775 }
776
777 tbm_bo
778 tbm_bo_ref(tbm_bo bo)
779 {
780         _tbm_bufmgr_mutex_lock();
781
782         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
783         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
784
785         bo->ref_cnt++;
786
787         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
788
789         _tbm_bufmgr_mutex_unlock();
790
791         return bo;
792 }
793
794 void
795 tbm_bo_unref(tbm_bo bo)
796 {
797         tbm_bufmgr bufmgr = gBufMgr;
798
799         _tbm_bufmgr_mutex_lock();
800
801         TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
802         TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
803
804         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
805
806         if (bo->ref_cnt <= 0) {
807                 _tbm_bufmgr_mutex_unlock();
808                 return;
809         }
810
811         bo->ref_cnt--;
812         if (bo->ref_cnt == 0) {
813                 /* destory the user_data_list */
814                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
815                         tbm_user_data *old_data = NULL, *tmp;
816
817                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
818                                         &bo->user_data_list, item_link) {
819                                 TBM_DBG("free user_data\n");
820                                 user_data_delete(old_data);
821                         }
822                 }
823
824                 while (bo->lock_cnt > 0) {
825                         TBM_LOG_E("error lock_cnt:%d\n", bo->lock_cnt);
826                         _bo_unlock(bo);
827                         bo->lock_cnt--;
828                 }
829
830                 /* call the bo_free */
831                 bufmgr->backend->bo_free(bo);
832                 bo->priv = NULL;
833
834                 LIST_DEL(&bo->item_link);
835                 free(bo);
836
837                 bufmgr->bo_cnt--;
838         }
839
840         _tbm_bufmgr_mutex_unlock();
841 }
842
843 tbm_bo
844 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
845 {
846         void *bo_priv;
847         tbm_bo bo;
848
849         _tbm_bufmgr_mutex_lock();
850
851         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
852         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
853         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
854
855         bo = calloc(1, sizeof(struct _tbm_bo));
856         if (!bo) {
857                 TBM_TRACE("error: fail to create of tbm_bo size(%d) flag(%s)\n",
858                                 size, _tbm_flag_to_str(flags));
859                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
860                 _tbm_bufmgr_mutex_unlock();
861                 return NULL;
862         }
863
864         _tbm_util_check_bo_cnt(bufmgr);
865
866         bo->bufmgr = bufmgr;
867
868         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
869         if (!bo_priv) {
870                 TBM_TRACE("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_BO_ALLOC_FAILED);
873                 free(bo);
874                 _tbm_bufmgr_mutex_unlock();
875                 return NULL;
876         }
877
878         bufmgr->bo_cnt++;
879
880         bo->ref_cnt = 1;
881         bo->flags = flags;
882         bo->priv = bo_priv;
883
884         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
885                         _tbm_flag_to_str(bo->flags));
886
887         LIST_INITHEAD(&bo->user_data_list);
888
889         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
890
891         _tbm_bufmgr_mutex_unlock();
892
893         return bo;
894 }
895
896 tbm_bo
897 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
898 {
899         void *bo_priv;
900         tbm_bo bo;
901
902         _tbm_bufmgr_mutex_lock();
903
904         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
905         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
906
907         if (!bufmgr->backend->bo_import) {
908                 _tbm_bufmgr_mutex_unlock();
909                 return NULL;
910         }
911
912         _tbm_util_check_bo_cnt(bufmgr);
913
914         bo = calloc(1, sizeof(struct _tbm_bo));
915         if (!bo) {
916                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
917                 _tbm_bufmgr_mutex_unlock();
918                 return NULL;
919         }
920
921         bo->bufmgr = bufmgr;
922
923         bo_priv = bufmgr->backend->bo_import(bo, key);
924         if (!bo_priv) {
925                 TBM_TRACE("error: fail to import of tbm_bo by key(%d)\n", key);
926                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
927                 free(bo);
928                 _tbm_bufmgr_mutex_unlock();
929                 return NULL;
930         }
931
932         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
933                 tbm_bo bo2 = NULL;
934
935                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
936                         if (bo2->priv == bo_priv) {
937                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
938                                                 bo2, bo2->ref_cnt, key,
939                                                 _tbm_flag_to_str(bo2->flags));
940                                 bo2->ref_cnt++;
941                                 free(bo);
942                                 _tbm_bufmgr_mutex_unlock();
943                                 return bo2;
944                         }
945                 }
946         }
947
948         bufmgr->bo_cnt++;
949
950         bo->ref_cnt = 1;
951         bo->priv = bo_priv;
952
953         if (bufmgr->backend->bo_get_flags)
954                 bo->flags = bufmgr->backend->bo_get_flags(bo);
955         else
956                 bo->flags = TBM_BO_DEFAULT;
957
958         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
959                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
960
961         LIST_INITHEAD(&bo->user_data_list);
962
963         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
964
965         _tbm_bufmgr_mutex_unlock();
966
967         return bo;
968 }
969
970 tbm_bo
971 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
972 {
973         void *bo_priv;
974         tbm_bo bo;
975
976         _tbm_bufmgr_mutex_lock();
977
978         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
979         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
980
981         if (!bufmgr->backend->bo_import_fd) {
982                 _tbm_bufmgr_mutex_unlock();
983                 return NULL;
984         }
985
986         _tbm_util_check_bo_cnt(bufmgr);
987
988         bo = calloc(1, sizeof(struct _tbm_bo));
989         if (!bo) {
990                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
991                 _tbm_bufmgr_mutex_unlock();
992                 return NULL;
993         }
994
995         bo->bufmgr = bufmgr;
996
997         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
998         if (!bo_priv) {
999                 TBM_TRACE("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1000                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1001                 free(bo);
1002                 _tbm_bufmgr_mutex_unlock();
1003                 return NULL;
1004         }
1005
1006         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1007                 tbm_bo bo2 = NULL;
1008
1009                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
1010                         if (bo2->priv == bo_priv) {
1011                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1012                                                 bo2, bo2->ref_cnt, fd,
1013                                                 _tbm_flag_to_str(bo2->flags));
1014                                 bo2->ref_cnt++;
1015                                 free(bo);
1016                                 _tbm_bufmgr_mutex_unlock();
1017                                 return bo2;
1018                         }
1019                 }
1020         }
1021
1022         bufmgr->bo_cnt++;
1023
1024         bo->ref_cnt = 1;
1025         bo->priv = bo_priv;
1026
1027         if (bufmgr->backend->bo_get_flags)
1028                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1029         else
1030                 bo->flags = TBM_BO_DEFAULT;
1031
1032         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)in list\n",
1033                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
1034
1035         LIST_INITHEAD(&bo->user_data_list);
1036
1037         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1038
1039         _tbm_bufmgr_mutex_unlock();
1040
1041         return bo;
1042 }
1043
1044 tbm_key
1045 tbm_bo_export(tbm_bo bo)
1046 {
1047         tbm_bufmgr bufmgr = gBufMgr;
1048         tbm_key ret;
1049
1050         _tbm_bufmgr_mutex_lock();
1051
1052         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1053         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1054
1055         if (!bufmgr->backend->bo_export) {
1056                 _tbm_bufmgr_mutex_unlock();
1057                 return 0;
1058         }
1059
1060         ret = bufmgr->backend->bo_export(bo);
1061         if (!ret) {
1062                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1063                 TBM_TRACE("error: bo(%p) tbm_key(%d)\n", bo, ret);
1064                 _tbm_bufmgr_mutex_unlock();
1065                 return ret;
1066         }
1067
1068         TBM_TRACE("bo(%p) tbm_key(%u)\n", bo, ret);
1069
1070         _tbm_bufmgr_mutex_unlock();
1071
1072         return ret;
1073 }
1074
1075 tbm_fd
1076 tbm_bo_export_fd(tbm_bo bo)
1077 {
1078         tbm_bufmgr bufmgr = gBufMgr;
1079         tbm_fd ret;
1080
1081         _tbm_bufmgr_mutex_lock();
1082
1083         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1084         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1085
1086         if (!bufmgr->backend->bo_export_fd) {
1087                 _tbm_bufmgr_mutex_unlock();
1088                 return -1;
1089         }
1090
1091         ret = bufmgr->backend->bo_export_fd(bo);
1092         if (ret < 0) {
1093                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1094                 TBM_TRACE("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1095                 _tbm_bufmgr_mutex_unlock();
1096                 return ret;
1097         }
1098
1099         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1100
1101         _tbm_bufmgr_mutex_unlock();
1102
1103         return ret;
1104 }
1105
1106 tbm_bo_handle
1107 tbm_bo_get_handle(tbm_bo bo, int device)
1108 {
1109         tbm_bufmgr bufmgr = gBufMgr;
1110         tbm_bo_handle bo_handle;
1111
1112         _tbm_bufmgr_mutex_lock();
1113
1114         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1115         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1116
1117         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1118         if (bo_handle.ptr == NULL) {
1119                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1120                 TBM_TRACE("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1121                 _tbm_bufmgr_mutex_unlock();
1122                 return (tbm_bo_handle) NULL;
1123         }
1124
1125         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1126
1127         _tbm_bufmgr_mutex_unlock();
1128
1129         return bo_handle;
1130 }
1131
1132 tbm_bo_handle
1133 tbm_bo_map(tbm_bo bo, int device, int opt)
1134 {
1135         tbm_bufmgr bufmgr = gBufMgr;
1136         tbm_bo_handle bo_handle;
1137
1138         _tbm_bufmgr_mutex_lock();
1139
1140         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1141         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1142
1143         if (!_tbm_bo_lock(bo, device, opt)) {
1144                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1145                 TBM_TRACE("error: fail to lock bo:%p)\n", bo);
1146                 _tbm_bufmgr_mutex_unlock();
1147                 return (tbm_bo_handle) NULL;
1148         }
1149
1150         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1151         if (bo_handle.ptr == NULL) {
1152                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1153                 TBM_TRACE("error: fail to map bo:%p\n", bo);
1154                 _tbm_bo_unlock(bo);
1155                 _tbm_bufmgr_mutex_unlock();
1156                 return (tbm_bo_handle) NULL;
1157         }
1158
1159         /* increase the map_count */
1160         bo->map_cnt++;
1161
1162         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1163
1164         _tbm_bufmgr_mutex_unlock();
1165
1166         return bo_handle;
1167 }
1168
1169 int
1170 tbm_bo_unmap(tbm_bo bo)
1171 {
1172         tbm_bufmgr bufmgr = gBufMgr;
1173         int ret;
1174
1175         _tbm_bufmgr_mutex_lock();
1176
1177         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1178         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1179
1180         ret = bufmgr->backend->bo_unmap(bo);
1181         if (!ret) {
1182                 TBM_TRACE("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1183                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1184                 _tbm_bufmgr_mutex_unlock();
1185                 return ret;
1186         }
1187
1188         /* decrease the map_count */
1189         bo->map_cnt--;
1190
1191         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1192
1193         _tbm_bo_unlock(bo);
1194
1195         _tbm_bufmgr_mutex_unlock();
1196
1197         return ret;
1198 }
1199
1200 int
1201 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1202 {
1203         tbm_bufmgr bufmgr = gBufMgr;
1204         void *temp;
1205
1206         _tbm_bufmgr_mutex_lock();
1207
1208         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1209         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1210         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1211
1212         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1213
1214         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1215                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1216                 TBM_TRACE("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1217                 _tbm_bufmgr_mutex_unlock();
1218                 return 0;
1219         }
1220
1221         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1222
1223         temp = bo1->priv;
1224         bo1->priv = bo2->priv;
1225         bo2->priv = temp;
1226
1227         _tbm_bufmgr_mutex_unlock();
1228
1229         return 1;
1230 }
1231
1232 int
1233 tbm_bo_locked(tbm_bo bo)
1234 {
1235         tbm_bufmgr bufmgr = gBufMgr;
1236
1237         _tbm_bufmgr_mutex_lock();
1238
1239         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1240         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1241
1242         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1243                 TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1244                 _tbm_bufmgr_mutex_unlock();
1245                 return 0;
1246         }
1247
1248         if (bo->lock_cnt > 0) {
1249                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1250                 _tbm_bufmgr_mutex_unlock();
1251                 return 1;
1252         }
1253
1254         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1255         _tbm_bufmgr_mutex_unlock();
1256
1257         return 0;
1258 }
1259
1260 int
1261 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1262                      tbm_data_free data_free_func)
1263 {
1264         tbm_user_data *data;
1265
1266         _tbm_bufmgr_mutex_lock();
1267
1268         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1269         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1270
1271         /* check if the data according to the key exist if so, return false. */
1272         data = user_data_lookup(&bo->user_data_list, key);
1273         if (data) {
1274                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1275                 _tbm_bufmgr_mutex_unlock();
1276                 return 0;
1277         }
1278
1279         data = user_data_create(key, data_free_func);
1280         if (!data) {
1281                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1282                 _tbm_bufmgr_mutex_unlock();
1283                 return 0;
1284         }
1285
1286         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1287
1288         LIST_ADD(&data->item_link, &bo->user_data_list);
1289
1290         _tbm_bufmgr_mutex_unlock();
1291
1292         return 1;
1293 }
1294
1295 int
1296 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1297 {
1298         tbm_user_data *old_data;
1299
1300         _tbm_bufmgr_mutex_lock();
1301
1302         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1303         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1304
1305         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1306                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1307                 _tbm_bufmgr_mutex_unlock();
1308                 return 0;
1309         }
1310
1311         old_data = user_data_lookup(&bo->user_data_list, key);
1312         if (!old_data) {
1313                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1314                 _tbm_bufmgr_mutex_unlock();
1315                 return 0;
1316         }
1317
1318         if (old_data->data && old_data->free_func)
1319                 old_data->free_func(old_data->data);
1320         old_data->data = data;
1321
1322         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1323
1324         _tbm_bufmgr_mutex_unlock();
1325
1326         return 1;
1327 }
1328
1329 int
1330 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1331 {
1332         tbm_user_data *old_data;
1333
1334         _tbm_bufmgr_mutex_lock();
1335
1336         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1337         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1338
1339         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1340                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1341                 _tbm_bufmgr_mutex_unlock();
1342                 return 0;
1343         }
1344
1345         old_data = user_data_lookup(&bo->user_data_list, key);
1346         if (!old_data) {
1347                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1348                 *data = NULL;
1349                 _tbm_bufmgr_mutex_unlock();
1350                 return 0;
1351         }
1352
1353         *data = old_data->data;
1354
1355         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1356
1357         _tbm_bufmgr_mutex_unlock();
1358
1359         return 1;
1360 }
1361
1362 int
1363 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1364 {
1365         tbm_user_data *old_data;
1366
1367         _tbm_bufmgr_mutex_lock();
1368
1369         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1370         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1371
1372         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1373                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1374                 _tbm_bufmgr_mutex_unlock();
1375                 return 0;
1376         }
1377
1378         old_data = user_data_lookup(&bo->user_data_list, key);
1379         if (!old_data) {
1380                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1381                 _tbm_bufmgr_mutex_unlock();
1382                 return 0;
1383         }
1384
1385         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1386
1387         user_data_delete(old_data);
1388
1389         _tbm_bufmgr_mutex_unlock();
1390
1391         return 1;
1392 }
1393
1394 unsigned int
1395 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1396 {
1397         int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1398
1399         _tbm_bufmgr_mutex_lock();
1400
1401         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1402         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1403
1404         TBM_TRACE("tbm_bufmgr(%p) capability(%d)\n", bufmgr, bufmgr->capabilities);
1405
1406         capabilities = bufmgr->capabilities;
1407
1408         _tbm_bufmgr_mutex_unlock();
1409
1410         return capabilities;
1411 }
1412
1413 int
1414 tbm_bo_get_flags(tbm_bo bo)
1415 {
1416         int flags;
1417
1418         _tbm_bufmgr_mutex_lock();
1419
1420         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1421         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1422
1423         flags = bo->flags;
1424
1425         TBM_TRACE("bo(%p)\n", bo);
1426
1427         _tbm_bufmgr_mutex_unlock();
1428
1429         return flags;
1430 }
1431
1432 /* LCOV_EXCL_START */
1433 tbm_error_e
1434 tbm_get_last_error(void)
1435 {
1436         return tbm_last_error;
1437 }
1438
1439 void
1440 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1441 {
1442         tbm_bo bo = NULL, tmp_bo = NULL;
1443         int bo_cnt = 0;
1444         tbm_surface_h surf = NULL, tmp_surf = NULL;
1445         int surf_cnt = 0;
1446         int i;
1447         char app_name[255] = {0,};
1448         unsigned int pid = 0;
1449         char title[255] = {0,};
1450         char data[255] = {0,};
1451         tbm_surface_debug_data *debug_old_data = NULL, *debug_tmp = NULL;
1452
1453         pthread_mutex_lock(&gLock);
1454
1455         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1456                 TBM_LOG_E("invalid bufmgr\n");
1457                 pthread_mutex_unlock(&gLock);
1458                 return;
1459         }
1460
1461         TBM_DEBUG("\n");
1462         _tbm_util_get_appname_from_pid(getpid(), app_name);
1463         _tbm_util_get_appname_brief(app_name);
1464         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1465                   app_name, getpid());
1466         memset(app_name, 0x0, 255 * sizeof(char));
1467         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1468         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1469                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1470                         strncat(title, "  ", 3);
1471                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1472                 }
1473         }
1474
1475         TBM_DEBUG("[tbm_surface information]\n");
1476         TBM_DEBUG("%s\n", title);
1477         /* show the tbm_surface information in surf_list */
1478         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1479                 char *value = NULL;
1480
1481                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1482                         pid = _tbm_surface_internal_get_debug_pid(surf);
1483                         if (!pid) {
1484                                 /* if pid is null, set the self_pid */
1485                                 pid = getpid();
1486                         }
1487
1488                         _tbm_util_get_appname_from_pid(pid, app_name);
1489                         _tbm_util_get_appname_brief(app_name);
1490
1491                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5d  %-6d  %-3d  %-6d   %-2d   %-2d    %-3d  %-8s  %-15s",
1492                                   ++surf_cnt,
1493                                   surf,
1494                                   surf->refcnt,
1495                                   surf->info.width,
1496                                   surf->info.height,
1497                                   surf->info.bpp,
1498                                   surf->info.size / 1024,
1499                                   surf->num_bos,
1500                                   surf->num_planes,
1501                                   surf->flags,
1502                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1503                                   app_name);
1504
1505                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1506                                 LIST_FOR_EACH_ENTRY_SAFE(debug_old_data, debug_tmp, &bufmgr->debug_key_list, item_link) {
1507                                         strncat(data, "  ", 3);
1508
1509                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1510                                         if (value)
1511                                                 strncat(data, value, strlen(value) + 1);
1512                                         else
1513                                                 strncat(data, "none", 5);
1514                                 }
1515                         }
1516                         TBM_DEBUG("%s\n", data);
1517
1518                         for (i = 0; i < surf->num_bos; i++) {
1519                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1520                                           surf->bos[i],
1521                                           surf->bos[i]->ref_cnt,
1522                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1523                         }
1524
1525                         memset(app_name, 0x0, 255 * sizeof(char));
1526                 }
1527         } else {
1528                 TBM_DEBUG("no tbm_surfaces.\n");
1529         }
1530         TBM_DEBUG("\n");
1531
1532         TBM_DEBUG("[tbm_bo information]\n");
1533         TBM_DEBUG("no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1534
1535         /* show the tbm_bo information in bo_list */
1536         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1537                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1538                         TBM_DEBUG("%-4d%-11p   %-4d  %-6d     %-5d     %-4d    %-3d  %-11p\n",
1539                                   ++bo_cnt,
1540                                   bo,
1541                                   bo->ref_cnt,
1542                                   bufmgr->backend->bo_size(bo) / 1024,
1543                                   bo->lock_cnt,
1544                                   bo->map_cnt,
1545                                   bo->flags,
1546                                   bo->surface);
1547                 }
1548         } else {
1549                 TBM_DEBUG("no tbm_bos.\n");
1550         }
1551         TBM_DEBUG("\n");
1552
1553         TBM_DEBUG("===============================================================\n");
1554
1555         pthread_mutex_unlock(&gLock);
1556 }
1557
1558 void
1559 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1560 {
1561         _tbm_bufmgr_mutex_lock();
1562
1563         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1564         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1565
1566 #ifdef TRACE
1567         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1568         bTrace = onoff;
1569 #endif
1570
1571         _tbm_bufmgr_mutex_unlock();
1572 }
1573
1574 int
1575 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1576 {
1577         int w = 0, h = 0;
1578
1579         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1580         TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1581
1582         pthread_mutex_lock(&gLock);
1583
1584         if (onoff == 1) {
1585                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1586                         TBM_LOG_I("No tbm_surface.\n");
1587                         pthread_mutex_unlock(&gLock);
1588                         return 0;
1589                 }
1590
1591                 tbm_surface_internal_dump_start(path, w, h, count);
1592                 b_dump_queue = 1;
1593         } else if (onoff == 0) {
1594                 tbm_surface_internal_dump_end();
1595                 b_dump_queue = 0;
1596         } else {
1597                 pthread_mutex_unlock(&gLock);
1598                 return 0;
1599         }
1600
1601         pthread_mutex_unlock(&gLock);
1602         return 1;
1603 }
1604
1605 int
1606 tbm_bufmgr_debug_dump_all(char *path)
1607 {
1608         int w = 0, h = 0, count = 0;
1609         tbm_surface_h surface = NULL, tmp = NULL;
1610
1611         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1612         TBM_LOG_D("path=%s\n", path);
1613
1614         pthread_mutex_lock(&gLock);
1615
1616         count = _tbm_util_get_max_surface_size(&w, &h);
1617         if (count == 0) {
1618                 TBM_LOG_I("No tbm_surface.\n");
1619                 pthread_mutex_unlock(&gLock);
1620                 return 1;
1621         }
1622
1623         tbm_surface_internal_dump_start(path, w, h, count);
1624
1625         LIST_FOR_EACH_ENTRY_SAFE(surface, tmp, &gBufMgr->surf_list, item_link) {
1626                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1627         }
1628
1629         tbm_surface_internal_dump_end();
1630
1631         pthread_mutex_unlock(&gLock);
1632
1633         return 1;
1634 }
1635
1636 /* internal function */
1637 tbm_bufmgr
1638 _tbm_bufmgr_get_bufmgr(void)
1639 {
1640         return gBufMgr;
1641 }
1642
1643 int
1644 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1645 {
1646         _tbm_bufmgr_mutex_lock();
1647
1648         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1649         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1650
1651         bo->surface = surface;
1652
1653         _tbm_bufmgr_mutex_unlock();
1654
1655         return 1;
1656 }
1657
1658 int
1659 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1660 {
1661         int ret;
1662
1663         _tbm_bufmgr_mutex_lock();
1664
1665         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1666
1667         if (!bufmgr->backend->bufmgr_bind_native_display) {
1668                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1669                 _tbm_bufmgr_mutex_unlock();
1670                 return 1;
1671         }
1672
1673         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1674         if (!ret) {
1675                 TBM_TRACE("error: tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1676                 _tbm_bufmgr_mutex_unlock();
1677                 return 0;
1678         }
1679
1680         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1681
1682         _tbm_bufmgr_mutex_unlock();
1683
1684         return 1;
1685 }
1686 /* LCOV_EXCL_STOP */