1 /**************************************************************************
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
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.
30 **************************************************************************/
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
37 #include "tbm_bufmgr_tgl.h"
43 #define DBG(...) if (bDebug&0x1) TBM_LOG(__VA_ARGS__)
44 #define DBG_LOCK(...) if (bDebug&0x2) TBM_LOG(__VA_ARGS__)
50 #define PREFIX_LIB "libtbm_"
51 #define SUFFIX_LIB ".so"
52 #define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB
54 #define BO_IS_CACHEABLE(bo) ((bo->flags & TBM_BO_NONCACHABLE) ? 0 : 1)
55 #define DEVICE_IS_CACHE_AWARE(device) ((device == TBM_DEVICE_CPU) ? (1) : (0))
58 #define GLOBAL_KEY ((unsigned int)(-1))
59 #define INITIAL_KEY ((unsigned int)(-2))
61 #define CACHE_OP_CREATE (-1)
62 #define CACHE_OP_ATTACH (-2)
63 #define CACHE_OP_IMPORT (-3)
65 /* values to indicate unspecified fields in XF86ModReqInfo. */
66 #define MAJOR_UNSPEC 0xFF
67 #define MINOR_UNSPEC 0xFF
68 #define PATCH_UNSPEC 0xFFFF
69 #define ABI_VERS_UNSPEC 0xFFFFFFFF
71 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
72 ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
73 #define GET_MODULE_MAJOR_VERSION(vers) (((vers) >> 24) & 0xFF)
74 #define GET_MODULE_MINOR_VERSION(vers) (((vers) >> 16) & 0xFF)
75 #define GET_MODULE_PATCHLEVEL(vers) ((vers) & 0xFFFF)
85 DEVICE_CA, /* cache aware device */
86 DEVICE_CO /* cache oblivious device */
89 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
90 tbm_bufmgr gBufMgr = NULL;
92 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
94 static void _tbm_set_last_result(tbm_error_e err)
99 static void _tbm_util_get_appname_brief(char *brief)
103 char temp[255] = {0,};
104 char *saveptr = NULL;
106 token = strtok_r(brief, delim, &saveptr);
108 while (token != NULL) {
109 memset(temp, 0x00, 255*sizeof(char));
110 strncpy(temp, token, 254*sizeof(char));
111 token = strtok_r(NULL, delim, &saveptr);
114 snprintf(brief, sizeof(temp), "%s", temp);
117 static void _tbm_util_get_appname_from_pid(long pid, char *str)
122 char fn_cmdline[255] = {0,};
123 char cmdline[255] = {0,};
125 snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
127 fp = fopen(fn_cmdline, "r");
129 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
133 if (!fgets(cmdline, 255, fp)) {
134 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
140 len = strlen(cmdline);
142 memset(cmdline, 0x00, 255);
146 snprintf(str, sizeof(cmdline), "%s", cmdline);
149 static inline int _tgl_init(int fd, unsigned int key)
151 struct tgl_attribute attr;
155 attr.timeout_ms = 1000;
157 err = ioctl(fd, TGL_IOC_INIT_LOCK, &attr);
159 TBM_LOG("[libtbm:%d] "
160 "error(%s) %s:%d key:%d\n",
161 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
168 static inline int _tgl_destroy(int fd, unsigned int key)
171 err = ioctl(fd, TGL_IOC_DESTROY_LOCK, key);
173 TBM_LOG("[libtbm:%d] "
174 "error(%s) %s:%d key:%d\n",
175 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
182 static inline int _tgl_lock(int fd, unsigned int key)
185 err = ioctl(fd, TGL_IOC_LOCK_LOCK, key);
187 TBM_LOG("[libtbm:%d] "
188 "error(%s) %s:%d key:%d\n",
189 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
196 static inline int _tgl_unlock(int fd, unsigned int key)
199 err = ioctl(fd, TGL_IOC_UNLOCK_LOCK, key);
201 TBM_LOG("[libtbm:%d] "
202 "error(%s) %s:%d key:%d\n",
203 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
210 static inline int _tgl_set_data(int fd, unsigned int key, unsigned int val)
213 struct tgl_user_data arg;
217 err = ioctl(fd, TGL_IOC_SET_DATA, &arg);
219 TBM_LOG("[libtbm:%d] "
220 "error(%s) %s:%d key:%d\n",
221 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
228 static inline unsigned int _tgl_get_data(int fd, unsigned int key, unsigned int *locked)
231 struct tgl_user_data arg = { 0, };
234 err = ioctl(fd, TGL_IOC_GET_DATA, &arg);
236 TBM_LOG("[libtbm:%d] "
237 "error(%s) %s:%d key:%d\n",
238 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
243 *locked = arg.locked;
248 tbm_user_data *user_data_lookup(struct list_head *user_data_list, unsigned long key)
250 tbm_user_data *user_data = NULL;
251 tbm_user_data *old_data = NULL, *tmp = NULL;
253 if (!LIST_IS_EMPTY(user_data_list)) {
254 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
255 if (old_data->key == key) {
256 user_data = old_data;
265 tbm_user_data *user_data_create(unsigned long key, tbm_data_free data_free_func)
267 tbm_user_data *user_data = NULL;
269 user_data = calloc(1, sizeof(tbm_user_data));
273 user_data->key = key;
274 user_data->free_func = data_free_func;
275 user_data->data = (void *)0;
280 void user_data_delete(tbm_user_data * user_data)
282 if (user_data->data && user_data->free_func)
283 user_data->free_func(user_data->data);
285 LIST_DEL(&user_data->item_link);
290 static int _bo_lock(tbm_bo bo, int device, int opt)
292 tbm_bufmgr bufmgr = bo->bufmgr;
295 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
296 if (bufmgr->backend->bo_lock2) {
297 /* use bo_lock2 backend lock */
298 ret = bufmgr->backend->bo_lock2(bo, device, opt);
299 } else if (bufmgr->backend->bo_lock) {
300 /* use bo_lock backend lock */
301 ret = bufmgr->backend->bo_lock(bo);
303 TBM_LOG("[libtbm:%d] "
304 "error %s:%d no backend lock functions\n",
305 getpid(), __FUNCTION__, __LINE__);
308 /* use tizen global lock */
309 ret = _tgl_lock(bufmgr->lock_fd, bo->tgl_key);
315 static void _bo_unlock(tbm_bo bo)
317 tbm_bufmgr bufmgr = bo->bufmgr;
319 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
320 if (bufmgr->backend->bo_unlock) {
321 /* use backend unlock */
322 bufmgr->backend->bo_unlock(bo);
324 TBM_LOG("[libtbm:%d] "
325 "error %s:%d no backend unlock functions\n",
326 getpid(), __FUNCTION__, __LINE__);
329 /* use tizen global unlock */
330 _tgl_unlock(bufmgr->lock_fd, bo->tgl_key);
334 static int _tbm_bo_init_state(tbm_bo bo, int opt)
336 tbm_bufmgr bufmgr = bo->bufmgr;
337 tbm_bo_cache_state cache_state;
339 if (bo->tgl_key == INITIAL_KEY)
340 bo->tgl_key = bufmgr->backend->bo_get_global_key(bo);
342 if (!bo->default_handle.u32)
343 bo->default_handle = bufmgr->backend->bo_get_handle(bo, TBM_DEVICE_DEFAULT);
345 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
349 case CACHE_OP_CREATE: /*Create */
351 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
353 cache_state.data.isCacheable = BO_IS_CACHEABLE(bo);
354 cache_state.data.isDirtied = DEVICE_NONE;
355 cache_state.data.isCached = 0;
356 cache_state.data.cntFlush = 0;
358 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, cache_state.val);
360 case CACHE_OP_IMPORT: /*Import */
362 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
371 static void _tbm_bo_destroy_state(tbm_bo bo)
373 tbm_bufmgr bufmgr = bo->bufmgr;
375 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
377 _tgl_destroy(bufmgr->lock_fd, bo->tgl_key);
380 static int _tbm_bo_set_state(tbm_bo bo, int device, int opt)
382 tbm_bufmgr bufmgr = bo->bufmgr;
384 unsigned short cntFlush = 0;
385 unsigned int is_locked;
387 RETURN_VAL_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
389 /* get cache state of a bo */
390 bo->cache_state.val = _tgl_get_data(bufmgr->lock_fd, bo->tgl_key, &is_locked);
392 if (!bo->cache_state.data.isCacheable)
395 /* get global cache flush count */
396 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
398 if (DEVICE_IS_CACHE_AWARE(device)) {
399 if (bo->cache_state.data.isDirtied == DEVICE_CO &&
400 bo->cache_state.data.isCached)
401 need_flush = TBM_CACHE_INV;
403 bo->cache_state.data.isCached = 1;
404 if (opt & TBM_OPTION_WRITE)
405 bo->cache_state.data.isDirtied = DEVICE_CA;
407 if (bo->cache_state.data.isDirtied != DEVICE_CA)
408 bo->cache_state.data.isDirtied = DEVICE_NONE;
411 if (bo->cache_state.data.isDirtied == DEVICE_CA &&
412 bo->cache_state.data.isCached &&
413 bo->cache_state.data.cntFlush == cntFlush)
414 need_flush = TBM_CACHE_CLN | TBM_CACHE_ALL;
416 if (opt & TBM_OPTION_WRITE)
417 bo->cache_state.data.isDirtied = DEVICE_CO;
419 if (bo->cache_state.data.isDirtied != DEVICE_CO)
420 bo->cache_state.data.isDirtied = DEVICE_NONE;
425 /* set global cache flush count */
426 if (need_flush & TBM_CACHE_ALL)
427 _tgl_set_data(bufmgr->lock_fd, GLOBAL_KEY, (unsigned int)(++cntFlush));
429 /* call backend cache flush */
430 bufmgr->backend->bo_cache_flush(bo, need_flush);
432 DBG("[libtbm:%d] \tcache(%d,%d,%d)....flush:0x%x, cntFlush(%d)\n",
434 bo->cache_state.data.isCacheable,
435 bo->cache_state.data.isCached,
436 bo->cache_state.data.isDirtied,
444 static void _tbm_bo_save_state(tbm_bo bo)
446 tbm_bufmgr bufmgr = bo->bufmgr;
447 unsigned short cntFlush = 0;
449 RETURN_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags));
451 /* get global cache flush count */
452 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
454 /* save global cache flush count */
455 bo->cache_state.data.cntFlush = cntFlush;
456 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, bo->cache_state.val);
459 static int _tbm_bo_lock(tbm_bo bo, int device, int opt)
461 tbm_bufmgr bufmgr = NULL;
470 /* do not try to lock the bo */
471 if (bufmgr->lock_type == LOCK_TRY_NEVER)
474 if (bo->lock_cnt < 0) {
475 TBM_LOG("[libtbm:%d] "
476 "error %s:%d bo:%p(%d) LOCK_CNT=%d\n",
477 getpid(), __FUNCTION__, __LINE__, bo, bo->tgl_key, bo->lock_cnt);
481 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
482 if (bo->lock_cnt == 0) {
483 pthread_mutex_unlock(&bufmgr->lock);
484 ret = _bo_lock(bo, device, opt);
485 pthread_mutex_lock(&bufmgr->lock);
490 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
491 pthread_mutex_unlock(&bufmgr->lock);
492 ret = _bo_lock(bo, device, opt);
493 pthread_mutex_lock(&bufmgr->lock);
497 TBM_LOG("[libtbm:%d] "
498 "error %s:%d bo:%p lock_type is wrong.\n",
499 getpid(), __FUNCTION__, __LINE__, bo);
502 DBG_LOCK("[libtbm:%d] >> LOCK bo:%p(%d, %d->%d)\n", getpid(),
503 bo, bo->tgl_key, old, bo->lock_cnt);
508 static void _tbm_bo_unlock(tbm_bo bo)
510 tbm_bufmgr bufmgr = NULL;
519 /* do not try to unlock the bo */
520 if (bufmgr->lock_type == LOCK_TRY_NEVER)
524 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
525 if (bo->lock_cnt > 0) {
527 if (bo->lock_cnt == 0)
530 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
531 if (bo->lock_cnt > 0) {
536 TBM_LOG("[libtbm:%d] "
537 "error %s:%d bo:%p lock_type is wrong.\n",
538 getpid(), __FUNCTION__, __LINE__, bo);
541 if (bo->lock_cnt < 0)
544 DBG_LOCK("[libtbm:%d] << unlock bo:%p(%d, %d->%d)\n", getpid(),
545 bo, bo->tgl_key, old, bo->lock_cnt);
548 static int _tbm_bo_is_valid(tbm_bo bo)
550 tbm_bo old_data = NULL, tmp = NULL;;
555 if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
556 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
565 static void _tbm_bo_ref(tbm_bo bo)
570 static void _tbm_bo_unref(tbm_bo bo)
572 tbm_bufmgr bufmgr = bo->bufmgr;
573 tbm_user_data *old_data = NULL, *tmp = NULL;
575 if (bo->ref_cnt <= 0)
579 if (bo->ref_cnt == 0) {
580 /* destory the user_data_list */
581 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
582 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
583 DBG("[libtbm:%d] free user_data \n",
585 user_data_delete(old_data);
589 if (bo->lock_cnt > 0) {
590 TBM_LOG("[libtbm:%d] "
591 "error %s:%d lock_cnt:%d\n",
592 getpid(), __FUNCTION__, __LINE__, bo->lock_cnt);
596 /* Destroy Global Lock */
597 _tbm_bo_destroy_state(bo);
599 /* call the bo_free */
600 bufmgr->backend->bo_free(bo);
603 LIST_DEL(&bo->item_link);
610 static int _tbm_bufmgr_init_state(tbm_bufmgr bufmgr)
612 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
614 bufmgr->lock_fd = open(tgl_devfile, O_RDWR);
616 if (bufmgr->lock_fd < 0) {
617 bufmgr->lock_fd = open(tgl_devfile1, O_RDWR);
618 if (bufmgr->lock_fd < 0) {
620 TBM_LOG("[libtbm:%d] "
621 "error: Fail to open global_lock:%s\n",
622 getpid(), tgl_devfile);
627 if (!_tgl_init(bufmgr->lock_fd, GLOBAL_KEY)) {
628 TBM_LOG("[libtbm:%d] "
629 "error: Fail to initialize the tgl\n",
637 static void _tbm_bufmgr_destroy_state(tbm_bufmgr bufmgr)
639 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
641 close(bufmgr->lock_fd);
644 static int _check_version(TBMModuleVersionInfo * data)
649 abimaj = GET_ABI_MAJOR(data->abiversion);
650 abimin = GET_ABI_MINOR(data->abiversion);
653 "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
654 getpid(), data->modname ? data->modname : "UNKNOWN!",
655 data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
657 vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
658 vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
661 "TBM ABI version %d.%d\n",
662 getpid(), vermaj, vermin);
664 if (abimaj != vermaj) {
665 TBM_LOG("[libtbm:%d] "
666 "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
667 getpid(), abimaj, vermaj);
669 } else if (abimin > vermin) {
670 TBM_LOG("[libtbm:%d] "
671 "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
672 getpid(), abimin, vermin);
678 static int _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
680 char path[PATH_MAX] = { 0, };
681 TBMModuleData *initdata = NULL;
684 snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
686 module_data = dlopen(path, RTLD_LAZY);
688 TBM_LOG("[libtbm:%d] "
689 "failed to load module: %s(%s)\n",
690 getpid(), dlerror(), file);
694 initdata = dlsym(module_data, "tbmModuleData");
697 TBMModuleVersionInfo *vers;
699 vers = initdata->vers;
700 init = initdata->init;
703 if (!_check_version(vers)) {
704 dlclose(module_data);
708 TBM_LOG("[libtbm:%d] "
709 "Error: module does not supply version information.\n",
712 dlclose(module_data);
717 if (!init(bufmgr, fd)) {
718 TBM_LOG("[libtbm:%d] "
719 "Fail to init module(%s)\n",
721 dlclose(module_data);
725 if (!bufmgr->backend || !bufmgr->backend->priv) {
726 TBM_LOG("[libtbm:%d] "
727 "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
729 dlclose(module_data);
733 TBM_LOG("[libtbm:%d] "
734 "Error: module does not supply init symbol.\n",
736 dlclose(module_data);
740 TBM_LOG("[libtbm:%d] "
741 "Error: module does not have data object.\n",
743 dlclose(module_data);
747 bufmgr->module_data = module_data;
750 "Success to load module(%s)\n",
756 static int _tbm_load_module(tbm_bufmgr bufmgr, int fd)
758 struct dirent **namelist;
759 const char *p = NULL;
763 /* load bufmgr priv from default lib */
764 ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
766 /* load bufmgr priv from configured path */
768 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
770 TBM_LOG("[libtbm:%d] "
772 getpid(), BUFMGR_MODULE_DIR);
775 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
776 p = strstr(namelist[n]->d_name, SUFFIX_LIB);
778 if (!strcmp(p, SUFFIX_LIB))
779 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
791 tbm_bufmgr tbm_bufmgr_init(int fd)
795 int backend_flag = 0;
797 pthread_mutex_lock(&gLock);
800 env = getenv("GEM_DEBUG");
803 TBM_LOG("GEM_DEBUG=%s\n", env);
808 /* initialize buffer manager */
810 DBG("[libtbm:%d] use previous gBufMgr\n", getpid());
811 if (!gBufMgr->fd_flag) {
813 if (dup2(gBufMgr->fd, fd) < 0) {
814 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
815 TBM_LOG("[libtbm:%d] Fail to duplicate(dup2) the drm fd\n",
817 pthread_mutex_unlock(&gLock);
820 DBG("[libtbm:%d] duplicate the drm_fd(%d), new drm_fd(%d).\n",
821 getpid(), gBufMgr->fd, fd);
824 gBufMgr->ref_count++;
826 DBG("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
827 getpid(), gBufMgr->fd, gBufMgr->ref_count);
828 pthread_mutex_unlock(&gLock);
836 DBG("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
838 /* allocate bufmgr */
839 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
841 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
842 pthread_mutex_unlock(&gLock);
846 gBufMgr->fd_flag = fd_flag;
851 gBufMgr->fd = dup(fd);
852 if (gBufMgr->fd < 0) {
853 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
854 TBM_LOG("[libtbm:%d] Fail to duplicate(dup) the drm fd\n",
858 pthread_mutex_unlock(&gLock);
861 DBG("[libtbm:%d] duplicate the drm_fd(%d), bufmgr use fd(%d).\n",
862 getpid(), fd, gBufMgr->fd);
865 /* load bufmgr priv from env */
866 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
867 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
868 TBM_LOG("[libtbm:%d] " "error : Fail to load bufmgr backend\n", getpid());
875 pthread_mutex_unlock(&gLock);
878 backend_flag = gBufMgr->backend->flags;
879 /* log for tbm backend_flag */
880 DBG("[libtbm:%d] ", getpid());
882 if (backend_flag & TBM_CACHE_CTRL_BACKEND) {
889 if (backend_flag & TBM_LOCK_CTRL_BACKEND) {
898 gBufMgr->ref_count = 1;
900 DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
901 getpid(), gBufMgr->ref_count);
903 if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
904 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
905 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
906 tbm_backend_free(gBufMgr->backend);
907 dlclose(gBufMgr->module_data);
914 pthread_mutex_unlock(&gLock);
918 /* intialize the tizen global status */
919 if (!_tbm_bufmgr_init_state(gBufMgr)) {
920 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
921 TBM_LOG("[libtbm:%d] " "error: Fail to init state\n", getpid());
922 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
923 tbm_backend_free(gBufMgr->backend);
924 pthread_mutex_destroy(&gBufMgr->lock);
925 dlclose(gBufMgr->module_data);
932 pthread_mutex_unlock(&gLock);
936 /* setup the lock_type */
937 env = getenv("BUFMGR_LOCK_TYPE");
938 if (env && !strcmp(env, "always"))
939 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
940 else if (env && !strcmp(env, "none"))
941 gBufMgr->lock_type = LOCK_TRY_NEVER;
942 else if (env && !strcmp(env, "once"))
943 gBufMgr->lock_type = LOCK_TRY_ONCE;
945 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
947 DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
948 getpid(), env ? env : "default:once");
950 /* setup the map_cache */
951 env = getenv("BUFMGR_MAP_CACHE");
952 if (env && !strcmp(env, "false"))
953 gBufMgr->use_map_cache = 0;
955 gBufMgr->use_map_cache = 1;
956 DBG("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n",
957 getpid(), env ? env : "default:true");
959 /* intialize bo_list */
960 LIST_INITHEAD(&gBufMgr->bo_list);
962 /* intialize surf_list */
963 LIST_INITHEAD(&gBufMgr->surf_list);
965 pthread_mutex_unlock(&gLock);
969 void tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
971 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
976 tbm_surface_h surf = NULL;
977 tbm_surface_h tmp_surf = NULL;
979 pthread_mutex_lock(&gLock);
982 if (bufmgr->ref_count > 0) {
983 TBM_LOG("[libtbm:%d] "
984 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
985 getpid(), bufmgr, bufmgr->ref_count);
986 pthread_mutex_unlock(&gLock);
990 /* destroy bo_list */
991 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
992 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
993 TBM_LOG("[libtbm:%d] "
994 "Un-freed bo(%p, ref:%d) \n",
995 getpid(), bo, bo->ref_cnt);
1001 /* destroy surf_list */
1002 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1003 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1004 TBM_LOG("[libtbm:%d] "
1005 "Destroy surf(%p) \n",
1007 tbm_surface_destroy(surf);
1011 /* destroy the tizen global status */
1012 _tbm_bufmgr_destroy_state(bufmgr);
1014 /* destroy bufmgr priv */
1015 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
1016 bufmgr->backend->priv = NULL;
1017 tbm_backend_free(bufmgr->backend);
1018 bufmgr->backend = NULL;
1020 pthread_mutex_destroy(&bufmgr->lock);
1023 "tizen bufmgr destroy: bufmgr:%p\n",
1026 dlclose(bufmgr->module_data);
1035 pthread_mutex_unlock(&gLock);
1038 int tbm_bo_size(tbm_bo bo)
1040 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1042 tbm_bufmgr bufmgr = bo->bufmgr;
1045 pthread_mutex_lock(&bufmgr->lock);
1047 size = bufmgr->backend->bo_size(bo);
1049 pthread_mutex_unlock(&bufmgr->lock);
1054 tbm_bo tbm_bo_ref(tbm_bo bo)
1056 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1058 tbm_bufmgr bufmgr = bo->bufmgr;
1060 pthread_mutex_lock(&bufmgr->lock);
1064 pthread_mutex_unlock(&bufmgr->lock);
1069 void tbm_bo_unref(tbm_bo bo)
1071 TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1073 tbm_bufmgr bufmgr = bo->bufmgr;
1075 pthread_mutex_lock(&bufmgr->lock);
1079 pthread_mutex_unlock(&bufmgr->lock);
1082 tbm_bo tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
1084 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1087 void *bo_priv = NULL;
1089 bo = calloc(1, sizeof(struct _tbm_bo));
1091 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
1095 bo->bufmgr = bufmgr;
1097 pthread_mutex_lock(&bufmgr->lock);
1099 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
1101 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
1103 pthread_mutex_unlock(&bufmgr->lock);
1109 bo->tgl_key = INITIAL_KEY;
1111 bo->default_handle.u32 = 0;
1114 if (!_tbm_bo_init_state(bo, CACHE_OP_CREATE)) {
1115 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1117 pthread_mutex_unlock(&bufmgr->lock);
1121 LIST_INITHEAD(&bo->user_data_list);
1123 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1125 pthread_mutex_unlock(&bufmgr->lock);
1130 tbm_bo tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
1132 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1137 void *bo_priv = NULL;
1139 pthread_mutex_lock(&bufmgr->lock);
1141 /* find bo in list */
1142 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1143 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1144 if (bo2->tgl_key == key) {
1146 "find bo(%p, ref:%d key:%d) in list \n",
1147 getpid(), bo2, bo2->ref_cnt, bo2->tgl_key);
1150 pthread_mutex_unlock(&bufmgr->lock);
1156 bo = calloc(1, sizeof(struct _tbm_bo));
1158 pthread_mutex_unlock(&bufmgr->lock);
1162 bo->bufmgr = bufmgr;
1164 bo_priv = bufmgr->backend->bo_import(bo, key);
1166 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
1168 pthread_mutex_unlock(&bufmgr->lock);
1173 bo->tgl_key = INITIAL_KEY;
1175 bo->default_handle.u32 = 0;
1177 if (bufmgr->backend->bo_get_flags)
1178 bo->flags = bufmgr->backend->bo_get_flags(bo);
1180 bo->flags = TBM_BO_DEFAULT;
1183 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1184 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1186 pthread_mutex_unlock(&bufmgr->lock);
1190 LIST_INITHEAD(&bo->user_data_list);
1192 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1194 pthread_mutex_unlock(&bufmgr->lock);
1199 tbm_bo tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1201 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1206 void *bo_priv = NULL;
1207 tbm_bo_handle default_handle;
1209 pthread_mutex_lock(&bufmgr->lock);
1211 default_handle = bufmgr->backend->fd_to_handle(bufmgr, fd, TBM_DEVICE_DEFAULT);
1213 /* find bo in list */
1214 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1215 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1216 if (bo2->default_handle.u32 == default_handle.u32) {
1218 "find bo(%p, ref:%d handle:%d) in list \n",
1219 getpid(), bo2, bo2->ref_cnt, bo2->default_handle.u32);
1222 pthread_mutex_unlock(&bufmgr->lock);
1228 bo = calloc(1, sizeof(struct _tbm_bo));
1230 pthread_mutex_unlock(&bufmgr->lock);
1234 bo->bufmgr = bufmgr;
1236 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1238 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1240 pthread_mutex_unlock(&bufmgr->lock);
1245 bo->tgl_key = INITIAL_KEY;
1247 bo->default_handle.u32 = 0;
1249 if (bufmgr->backend->bo_get_flags)
1250 bo->flags = bufmgr->backend->bo_get_flags(bo);
1252 bo->flags = TBM_BO_DEFAULT;
1255 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1256 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1258 pthread_mutex_unlock(&bufmgr->lock);
1262 LIST_INITHEAD(&bo->user_data_list);
1264 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1266 pthread_mutex_unlock(&bufmgr->lock);
1271 tbm_key tbm_bo_export(tbm_bo bo)
1273 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1278 bufmgr = bo->bufmgr;
1280 pthread_mutex_lock(&bufmgr->lock);
1281 ret = bufmgr->backend->bo_export(bo);
1283 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1284 pthread_mutex_unlock(&bufmgr->lock);
1287 pthread_mutex_unlock(&bufmgr->lock);
1292 tbm_fd tbm_bo_export_fd(tbm_bo bo)
1294 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1299 bufmgr = bo->bufmgr;
1301 pthread_mutex_lock(&bufmgr->lock);
1302 ret = bufmgr->backend->bo_export_fd(bo);
1304 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1305 pthread_mutex_unlock(&bufmgr->lock);
1308 pthread_mutex_unlock(&bufmgr->lock);
1313 tbm_bo_handle tbm_bo_get_handle(tbm_bo bo, int device)
1315 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1318 tbm_bo_handle bo_handle;
1320 bufmgr = bo->bufmgr;
1322 pthread_mutex_lock(&bufmgr->lock);
1323 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1324 if (bo_handle.ptr == NULL) {
1325 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1326 pthread_mutex_unlock(&bufmgr->lock);
1327 return (tbm_bo_handle) NULL;
1329 pthread_mutex_unlock(&bufmgr->lock);
1334 tbm_bo_handle tbm_bo_map(tbm_bo bo, int device, int opt)
1336 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1339 tbm_bo_handle bo_handle;
1341 bufmgr = bo->bufmgr;
1343 pthread_mutex_lock(&bufmgr->lock);
1345 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1347 if (!_tbm_bo_lock(bo, device, opt)) {
1348 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1349 TBM_LOG("[libtbm:%d] "
1350 "error %s:%d fail to lock bo:%p)\n",
1351 getpid(), __FUNCTION__, __LINE__, bo);
1352 pthread_mutex_unlock(&bufmgr->lock);
1353 return (tbm_bo_handle) NULL;
1356 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1357 if (bo_handle.ptr == NULL) {
1358 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1359 TBM_LOG("[libtbm:%d] "
1360 "error %s:%d fail to map bo:%p\n",
1361 getpid(), __FUNCTION__, __LINE__, bo);
1364 pthread_mutex_unlock(&bufmgr->lock);
1365 return (tbm_bo_handle) NULL;
1368 if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1369 _tbm_bo_set_state(bo, device, opt);
1371 /* increase the map_count */
1374 pthread_mutex_unlock(&bufmgr->lock);
1379 int tbm_bo_unmap(tbm_bo bo)
1381 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1386 bufmgr = bo->bufmgr;
1388 pthread_mutex_lock(&bufmgr->lock);
1390 ret = bufmgr->backend->bo_unmap(bo);
1393 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1394 pthread_mutex_unlock(&bufmgr->lock);
1398 /* decrease the map_count */
1401 if (bo->map_cnt == 0)
1402 _tbm_bo_save_state(bo);
1406 pthread_mutex_unlock(&bufmgr->lock);
1411 int tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1413 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1414 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1417 unsigned int tmp_key;
1418 tbm_bo_handle tmp_defualt_handle;
1420 pthread_mutex_lock(&bo1->bufmgr->lock);
1422 if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1423 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1424 pthread_mutex_unlock(&bo1->bufmgr->lock);
1428 tmp_key = bo1->tgl_key;
1429 bo1->tgl_key = bo2->tgl_key;
1430 bo2->tgl_key = tmp_key;
1432 tmp_defualt_handle = bo1->default_handle;
1433 bo1->default_handle = bo2->default_handle;
1434 bo2->default_handle = tmp_defualt_handle;
1437 bo1->priv = bo2->priv;
1440 pthread_mutex_unlock(&bo1->bufmgr->lock);
1445 int tbm_bo_locked(tbm_bo bo)
1447 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1451 bufmgr = bo->bufmgr;
1453 if (bufmgr->lock_type == LOCK_TRY_NEVER)
1456 pthread_mutex_lock(&bufmgr->lock);
1458 if (bo->lock_cnt > 0) {
1459 pthread_mutex_unlock(&bufmgr->lock);
1463 pthread_mutex_unlock(&bufmgr->lock);
1468 int tbm_bo_add_user_data(tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1470 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1472 tbm_user_data *data;
1474 /* check if the data according to the key exist if so, return false. */
1475 data = user_data_lookup(&bo->user_data_list, key);
1477 TBM_LOG("[libtbm:%d] "
1478 "waring: %s:%d user data already exist. key:%ld\n",
1479 getpid(), __FUNCTION__, __LINE__, key);
1483 data = user_data_create(key, data_free_func);
1487 LIST_ADD(&data->item_link, &bo->user_data_list);
1492 int tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1494 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1496 tbm_user_data *old_data;
1498 if (LIST_IS_EMPTY(&bo->user_data_list))
1501 old_data = user_data_lookup(&bo->user_data_list, key);
1505 if (old_data->data && old_data->free_func)
1506 old_data->free_func(old_data->data);
1508 old_data->data = data;
1513 int tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1515 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1517 tbm_user_data *old_data;
1519 if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1522 old_data = user_data_lookup(&bo->user_data_list, key);
1528 *data = old_data->data;
1533 int tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1535 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1537 tbm_user_data *old_data = (void *)0;
1539 if (LIST_IS_EMPTY(&bo->user_data_list))
1542 old_data = user_data_lookup(&bo->user_data_list, key);
1546 user_data_delete(old_data);
1551 tbm_error_e tbm_get_last_error(void)
1553 return tbm_last_error;
1556 unsigned int tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1558 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1560 unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1562 if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1563 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1565 if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1566 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1571 int tbm_bo_get_flags(tbm_bo bo)
1573 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1578 void tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1580 TBM_RETURN_IF_FAIL(bufmgr != NULL);
1581 tbm_bo bo = NULL, tmp_bo = NULL;
1584 tbm_surface_h surf = NULL, tmp_surf = NULL;
1587 char app_name[255] = {0,};
1588 unsigned int pid = 0;
1590 pthread_mutex_lock(&gLock);
1593 _tbm_util_get_appname_from_pid(getpid(), app_name);
1594 _tbm_util_get_appname_brief(app_name);
1595 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n", app_name, getpid());
1596 memset(app_name, 0x0, 255*sizeof(char));
1598 TBM_DEBUG("[tbm_surface information]\n");
1599 TBM_DEBUG("no surface refcnt width height bpp size num_bos num_planes flags format app_name\n");
1600 /* show the tbm_surface information in surf_list */
1601 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1602 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1603 pid = _tbm_surface_internal_get_debug_pid(surf);
1605 /* if pid is null, set the self_pid */
1609 _tbm_util_get_appname_from_pid(pid, app_name);
1610 _tbm_util_get_appname_brief(app_name);
1612 TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1619 surf->info.size/1024,
1623 _tbm_surface_internal_format_to_str(surf->info.format),
1626 for (i = 0; i < surf->num_bos; i++) {
1627 TBM_DEBUG(" bo:%-12p(key:%2d) %-26d%-10d\n",
1629 surf->bos[i]->tgl_key,
1630 surf->bos[i]->ref_cnt,
1631 tbm_bo_size(surf->bos[i])/1024);
1634 memset(app_name, 0x0, 255*sizeof(char));
1637 TBM_DEBUG("no tbm_surfaces.\n");
1641 TBM_DEBUG("[tbm_bo information]\n");
1642 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt cache_state flags surface\n");
1644 /* show the tbm_bo information in bo_list */
1645 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1646 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1647 TBM_DEBUG("%-4d%-11p(key:%2d) %-6d%-12d%-9d%-9d%-10d%-4d%-11p\n",
1652 tbm_bo_size(bo)/1024,
1655 bo->cache_state.val,
1660 TBM_DEBUG("no tbm_bos.\n");
1664 TBM_DEBUG("===============================================================\n");
1666 pthread_mutex_unlock(&gLock);
1670 void tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1672 TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1673 TBM_LOG("Not implemented yet.\n");
1676 /* internal function */
1677 int _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1679 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1681 bo->surface = surface;