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