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 */
92 tbm_data_free free_func;
94 /* link of user_data */
95 struct list_head item_link;
98 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
99 tbm_bufmgr gBufMgr = NULL;
101 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
103 static void _tbm_set_last_result(tbm_error_e err)
105 tbm_last_error = err;
108 static void _tbm_util_get_appname_brief(char *brief)
112 char temp[255] = {0,};
113 char *saveptr = NULL;
115 token = strtok_r(brief, delim, &saveptr);
117 while (token != NULL) {
118 memset(temp, 0x00, 255*sizeof(char));
119 strncpy(temp, token, 254*sizeof(char));
120 token = strtok_r(NULL, delim, &saveptr);
123 snprintf(brief, sizeof(temp), "%s", temp);
126 static void _tbm_util_get_appname_from_pid(long pid, char *str)
131 char fn_cmdline[255] = {0,};
132 char cmdline[255] = {0,};
134 snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
136 fp = fopen(fn_cmdline, "r");
138 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
142 if (!fgets(cmdline, 255, fp)) {
143 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
149 len = strlen(cmdline);
151 memset(cmdline, 0x00, 255);
155 snprintf(str, sizeof(cmdline), "%s", cmdline);
158 static inline int _tgl_init(int fd, unsigned int key)
160 struct tgl_attribute attr;
164 attr.timeout_ms = 1000;
166 err = ioctl(fd, TGL_IOC_INIT_LOCK, &attr);
168 TBM_LOG("[libtbm:%d] "
169 "error(%s) %s:%d key:%d\n",
170 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
177 static inline int _tgl_destroy(int fd, unsigned int key)
180 err = ioctl(fd, TGL_IOC_DESTROY_LOCK, key);
182 TBM_LOG("[libtbm:%d] "
183 "error(%s) %s:%d key:%d\n",
184 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
191 static inline int _tgl_lock(int fd, unsigned int key)
194 err = ioctl(fd, TGL_IOC_LOCK_LOCK, key);
196 TBM_LOG("[libtbm:%d] "
197 "error(%s) %s:%d key:%d\n",
198 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
205 static inline int _tgl_unlock(int fd, unsigned int key)
208 err = ioctl(fd, TGL_IOC_UNLOCK_LOCK, key);
210 TBM_LOG("[libtbm:%d] "
211 "error(%s) %s:%d key:%d\n",
212 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
219 static inline int _tgl_set_data(int fd, unsigned int key, unsigned int val)
222 struct tgl_user_data arg;
226 err = ioctl(fd, TGL_IOC_SET_DATA, &arg);
228 TBM_LOG("[libtbm:%d] "
229 "error(%s) %s:%d key:%d\n",
230 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
237 static inline unsigned int _tgl_get_data(int fd, unsigned int key, unsigned int *locked)
240 struct tgl_user_data arg = { 0, };
243 err = ioctl(fd, TGL_IOC_GET_DATA, &arg);
245 TBM_LOG("[libtbm:%d] "
246 "error(%s) %s:%d key:%d\n",
247 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
252 *locked = arg.locked;
257 static tbm_user_data *_user_data_lookup(struct list_head *user_data_list, unsigned long key)
259 tbm_user_data *user_data = NULL;
260 tbm_user_data *old_data = NULL, *tmp = NULL;
262 if (!LIST_IS_EMPTY(user_data_list)) {
263 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
264 if (old_data->key == key) {
265 user_data = old_data;
274 static tbm_user_data *_user_data_create(unsigned long key, tbm_data_free data_free_func)
276 tbm_user_data *user_data = NULL;
278 user_data = calloc(1, sizeof(tbm_user_data));
282 user_data->key = key;
283 user_data->free_func = data_free_func;
284 user_data->data = (void *)0;
289 static void _user_data_delete(tbm_user_data * user_data)
291 if (user_data->data && user_data->free_func)
292 user_data->free_func(user_data->data);
294 LIST_DEL(&user_data->item_link);
299 static int _bo_lock(tbm_bo bo, int device, int opt)
301 tbm_bufmgr bufmgr = bo->bufmgr;
304 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
305 if (bufmgr->backend->bo_lock2) {
306 /* use bo_lock2 backend lock */
307 ret = bufmgr->backend->bo_lock2(bo, device, opt);
308 } else if (bufmgr->backend->bo_lock) {
309 /* use bo_lock backend lock */
310 ret = bufmgr->backend->bo_lock(bo);
312 TBM_LOG("[libtbm:%d] "
313 "error %s:%d no backend lock functions\n",
314 getpid(), __FUNCTION__, __LINE__);
317 /* use tizen global lock */
318 ret = _tgl_lock(bufmgr->lock_fd, bo->tgl_key);
324 static void _bo_unlock(tbm_bo bo)
326 tbm_bufmgr bufmgr = bo->bufmgr;
328 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
329 if (bufmgr->backend->bo_unlock) {
330 /* use backend unlock */
331 bufmgr->backend->bo_unlock(bo);
333 TBM_LOG("[libtbm:%d] "
334 "error %s:%d no backend unlock functions\n",
335 getpid(), __FUNCTION__, __LINE__);
338 /* use tizen global unlock */
339 _tgl_unlock(bufmgr->lock_fd, bo->tgl_key);
343 static int _tbm_bo_init_state(tbm_bo bo, int opt)
345 tbm_bufmgr bufmgr = bo->bufmgr;
346 tbm_bo_cache_state cache_state;
348 if (bo->tgl_key == INITIAL_KEY)
349 bo->tgl_key = bufmgr->backend->bo_get_global_key(bo);
351 if (!bo->default_handle.u32)
352 bo->default_handle = bufmgr->backend->bo_get_handle(bo, TBM_DEVICE_DEFAULT);
354 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
358 case CACHE_OP_CREATE: /*Create */
360 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
362 cache_state.data.isCacheable = BO_IS_CACHEABLE(bo);
363 cache_state.data.isDirtied = DEVICE_NONE;
364 cache_state.data.isCached = 0;
365 cache_state.data.cntFlush = 0;
367 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, cache_state.val);
369 case CACHE_OP_IMPORT: /*Import */
371 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
380 static void _tbm_bo_destroy_state(tbm_bo bo)
382 tbm_bufmgr bufmgr = bo->bufmgr;
384 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
386 _tgl_destroy(bufmgr->lock_fd, bo->tgl_key);
389 static int _tbm_bo_set_state(tbm_bo bo, int device, int opt)
391 tbm_bufmgr bufmgr = bo->bufmgr;
393 unsigned short cntFlush = 0;
394 unsigned int is_locked;
396 RETURN_VAL_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
398 /* get cache state of a bo */
399 bo->cache_state.val = _tgl_get_data(bufmgr->lock_fd, bo->tgl_key, &is_locked);
401 if (!bo->cache_state.data.isCacheable)
404 /* get global cache flush count */
405 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
407 if (DEVICE_IS_CACHE_AWARE(device)) {
408 if (bo->cache_state.data.isDirtied == DEVICE_CO &&
409 bo->cache_state.data.isCached)
410 need_flush = TBM_CACHE_INV;
412 bo->cache_state.data.isCached = 1;
413 if (opt & TBM_OPTION_WRITE)
414 bo->cache_state.data.isDirtied = DEVICE_CA;
416 if (bo->cache_state.data.isDirtied != DEVICE_CA)
417 bo->cache_state.data.isDirtied = DEVICE_NONE;
420 if (bo->cache_state.data.isDirtied == DEVICE_CA &&
421 bo->cache_state.data.isCached &&
422 bo->cache_state.data.cntFlush == cntFlush)
423 need_flush = TBM_CACHE_CLN | TBM_CACHE_ALL;
425 if (opt & TBM_OPTION_WRITE)
426 bo->cache_state.data.isDirtied = DEVICE_CO;
428 if (bo->cache_state.data.isDirtied != DEVICE_CO)
429 bo->cache_state.data.isDirtied = DEVICE_NONE;
434 /* set global cache flush count */
435 if (need_flush & TBM_CACHE_ALL)
436 _tgl_set_data(bufmgr->lock_fd, GLOBAL_KEY, (unsigned int)(++cntFlush));
438 /* call backend cache flush */
439 bufmgr->backend->bo_cache_flush(bo, need_flush);
441 DBG("[libtbm:%d] \tcache(%d,%d,%d)....flush:0x%x, cntFlush(%d)\n",
443 bo->cache_state.data.isCacheable,
444 bo->cache_state.data.isCached,
445 bo->cache_state.data.isDirtied,
453 static void _tbm_bo_save_state(tbm_bo bo)
455 tbm_bufmgr bufmgr = bo->bufmgr;
456 unsigned short cntFlush = 0;
458 RETURN_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags));
460 /* get global cache flush count */
461 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
463 /* save global cache flush count */
464 bo->cache_state.data.cntFlush = cntFlush;
465 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, bo->cache_state.val);
468 static int _tbm_bo_lock(tbm_bo bo, int device, int opt)
470 tbm_bufmgr bufmgr = NULL;
479 /* do not try to lock the bo */
480 if (bufmgr->lock_type == LOCK_TRY_NEVER)
483 if (bo->lock_cnt < 0) {
484 TBM_LOG("[libtbm:%d] "
485 "error %s:%d bo:%p(%d) LOCK_CNT=%d\n",
486 getpid(), __FUNCTION__, __LINE__, bo, bo->tgl_key, bo->lock_cnt);
490 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
491 if (bo->lock_cnt == 0) {
492 pthread_mutex_unlock(&bufmgr->lock);
493 ret = _bo_lock(bo, device, opt);
494 pthread_mutex_lock(&bufmgr->lock);
499 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
500 pthread_mutex_unlock(&bufmgr->lock);
501 ret = _bo_lock(bo, device, opt);
502 pthread_mutex_lock(&bufmgr->lock);
506 TBM_LOG("[libtbm:%d] "
507 "error %s:%d bo:%p lock_type is wrong.\n",
508 getpid(), __FUNCTION__, __LINE__, bo);
511 DBG_LOCK("[libtbm:%d] >> LOCK bo:%p(%d, %d->%d)\n", getpid(),
512 bo, bo->tgl_key, old, bo->lock_cnt);
517 static void _tbm_bo_unlock(tbm_bo bo)
519 tbm_bufmgr bufmgr = NULL;
528 /* do not try to unlock the bo */
529 if (bufmgr->lock_type == LOCK_TRY_NEVER)
533 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
534 if (bo->lock_cnt > 0) {
536 if (bo->lock_cnt == 0)
539 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
540 if (bo->lock_cnt > 0) {
545 TBM_LOG("[libtbm:%d] "
546 "error %s:%d bo:%p lock_type is wrong.\n",
547 getpid(), __FUNCTION__, __LINE__, bo);
550 if (bo->lock_cnt < 0)
553 DBG_LOCK("[libtbm:%d] << unlock bo:%p(%d, %d->%d)\n", getpid(),
554 bo, bo->tgl_key, old, bo->lock_cnt);
557 static int _tbm_bo_is_valid(tbm_bo bo)
559 tbm_bo old_data = NULL, tmp = NULL;;
564 if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
565 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
574 static void _tbm_bo_ref(tbm_bo bo)
579 static void _tbm_bo_unref(tbm_bo bo)
581 tbm_bufmgr bufmgr = bo->bufmgr;
582 tbm_user_data *old_data = NULL, *tmp = NULL;
584 if (bo->ref_cnt <= 0)
588 if (bo->ref_cnt == 0) {
589 /* destory the user_data_list */
590 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
591 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
592 DBG("[libtbm:%d] free user_data \n",
594 _user_data_delete(old_data);
598 if (bo->lock_cnt > 0) {
599 TBM_LOG("[libtbm:%d] "
600 "error %s:%d lock_cnt:%d\n",
601 getpid(), __FUNCTION__, __LINE__, bo->lock_cnt);
605 /* Destroy Global Lock */
606 _tbm_bo_destroy_state(bo);
608 /* call the bo_free */
609 bufmgr->backend->bo_free(bo);
612 LIST_DEL(&bo->item_link);
619 static int _tbm_bufmgr_init_state(tbm_bufmgr bufmgr)
621 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
623 bufmgr->lock_fd = open(tgl_devfile, O_RDWR);
625 if (bufmgr->lock_fd < 0) {
626 bufmgr->lock_fd = open(tgl_devfile1, O_RDWR);
627 if (bufmgr->lock_fd < 0) {
629 TBM_LOG("[libtbm:%d] "
630 "error: Fail to open global_lock:%s\n",
631 getpid(), tgl_devfile);
636 if (!_tgl_init(bufmgr->lock_fd, GLOBAL_KEY)) {
637 TBM_LOG("[libtbm:%d] "
638 "error: Fail to initialize the tgl\n",
646 static void _tbm_bufmgr_destroy_state(tbm_bufmgr bufmgr)
648 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
650 close(bufmgr->lock_fd);
653 static int _check_version(TBMModuleVersionInfo * data)
658 abimaj = GET_ABI_MAJOR(data->abiversion);
659 abimin = GET_ABI_MINOR(data->abiversion);
662 "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
663 getpid(), data->modname ? data->modname : "UNKNOWN!",
664 data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
666 vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
667 vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
670 "TBM ABI version %d.%d\n",
671 getpid(), vermaj, vermin);
673 if (abimaj != vermaj) {
674 TBM_LOG("[libtbm:%d] "
675 "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
676 getpid(), abimaj, vermaj);
678 } else if (abimin > vermin) {
679 TBM_LOG("[libtbm:%d] "
680 "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
681 getpid(), abimin, vermin);
687 static int _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
689 char path[PATH_MAX] = { 0, };
690 TBMModuleData *initdata = NULL;
693 snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
695 module_data = dlopen(path, RTLD_LAZY);
697 TBM_LOG("[libtbm:%d] "
698 "failed to load module: %s(%s)\n",
699 getpid(), dlerror(), file);
703 initdata = dlsym(module_data, "tbmModuleData");
706 TBMModuleVersionInfo *vers;
708 vers = initdata->vers;
709 init = initdata->init;
712 if (!_check_version(vers)) {
713 dlclose(module_data);
717 TBM_LOG("[libtbm:%d] "
718 "Error: module does not supply version information.\n",
721 dlclose(module_data);
726 if (!init(bufmgr, fd)) {
727 TBM_LOG("[libtbm:%d] "
728 "Fail to init module(%s)\n",
730 dlclose(module_data);
734 if (!bufmgr->backend || !bufmgr->backend->priv) {
735 TBM_LOG("[libtbm:%d] "
736 "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
738 dlclose(module_data);
742 TBM_LOG("[libtbm:%d] "
743 "Error: module does not supply init symbol.\n",
745 dlclose(module_data);
749 TBM_LOG("[libtbm:%d] "
750 "Error: module does not have data object.\n",
752 dlclose(module_data);
756 bufmgr->module_data = module_data;
759 "Success to load module(%s)\n",
765 static int _tbm_load_module(tbm_bufmgr bufmgr, int fd)
767 struct dirent **namelist;
768 const char *p = NULL;
772 /* load bufmgr priv from default lib */
773 ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
775 /* load bufmgr priv from configured path */
777 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
779 TBM_LOG("[libtbm:%d] "
781 getpid(), BUFMGR_MODULE_DIR);
784 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
785 p = strstr(namelist[n]->d_name, SUFFIX_LIB);
787 if (!strcmp(p, SUFFIX_LIB))
788 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
800 tbm_bufmgr tbm_bufmgr_init(int fd)
804 int backend_flag = 0;
806 pthread_mutex_lock(&gLock);
809 env = getenv("GEM_DEBUG");
812 TBM_LOG("GEM_DEBUG=%s\n", env);
817 /* initialize buffer manager */
819 DBG("[libtbm:%d] use previous gBufMgr\n", getpid());
820 if (!gBufMgr->fd_flag) {
822 if (dup2(gBufMgr->fd, fd) < 0) {
823 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
824 TBM_LOG("[libtbm:%d] Fail to duplicate(dup2) the drm fd\n",
826 pthread_mutex_unlock(&gLock);
829 DBG("[libtbm:%d] duplicate the drm_fd(%d), new drm_fd(%d).\n",
830 getpid(), gBufMgr->fd, fd);
833 gBufMgr->ref_count++;
835 DBG("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
836 getpid(), gBufMgr->fd, gBufMgr->ref_count);
837 pthread_mutex_unlock(&gLock);
845 DBG("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
847 /* allocate bufmgr */
848 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
850 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
851 pthread_mutex_unlock(&gLock);
855 gBufMgr->fd_flag = fd_flag;
860 gBufMgr->fd = dup(fd);
861 if (gBufMgr->fd < 0) {
862 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
863 TBM_LOG("[libtbm:%d] Fail to duplicate(dup) the drm fd\n",
867 pthread_mutex_unlock(&gLock);
870 DBG("[libtbm:%d] duplicate the drm_fd(%d), bufmgr use fd(%d).\n",
871 getpid(), fd, gBufMgr->fd);
874 /* load bufmgr priv from env */
875 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
876 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
877 TBM_LOG("[libtbm:%d] " "error : Fail to load bufmgr backend\n", getpid());
884 pthread_mutex_unlock(&gLock);
887 backend_flag = gBufMgr->backend->flags;
888 /* log for tbm backend_flag */
889 DBG("[libtbm:%d] ", getpid());
891 if (backend_flag & TBM_CACHE_CTRL_BACKEND) {
898 if (backend_flag & TBM_LOCK_CTRL_BACKEND) {
907 gBufMgr->ref_count = 1;
909 DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
910 getpid(), gBufMgr->ref_count);
912 if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
913 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
914 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
915 tbm_backend_free(gBufMgr->backend);
916 dlclose(gBufMgr->module_data);
923 pthread_mutex_unlock(&gLock);
927 /* intialize the tizen global status */
928 if (!_tbm_bufmgr_init_state(gBufMgr)) {
929 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
930 TBM_LOG("[libtbm:%d] " "error: Fail to init state\n", getpid());
931 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
932 tbm_backend_free(gBufMgr->backend);
933 pthread_mutex_destroy(&gBufMgr->lock);
934 dlclose(gBufMgr->module_data);
941 pthread_mutex_unlock(&gLock);
945 /* setup the lock_type */
946 env = getenv("BUFMGR_LOCK_TYPE");
947 if (env && !strcmp(env, "always"))
948 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
949 else if (env && !strcmp(env, "none"))
950 gBufMgr->lock_type = LOCK_TRY_NEVER;
951 else if (env && !strcmp(env, "once"))
952 gBufMgr->lock_type = LOCK_TRY_ONCE;
954 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
956 DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
957 getpid(), env ? env : "default:once");
959 /* setup the map_cache */
960 env = getenv("BUFMGR_MAP_CACHE");
961 if (env && !strcmp(env, "false"))
962 gBufMgr->use_map_cache = 0;
964 gBufMgr->use_map_cache = 1;
965 DBG("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n",
966 getpid(), env ? env : "default:true");
968 /* intialize bo_list */
969 LIST_INITHEAD(&gBufMgr->bo_list);
971 /* intialize surf_list */
972 LIST_INITHEAD(&gBufMgr->surf_list);
974 pthread_mutex_unlock(&gLock);
978 void tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
980 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
985 tbm_surface_h surf = NULL;
986 tbm_surface_h tmp_surf = NULL;
988 pthread_mutex_lock(&gLock);
991 if (bufmgr->ref_count > 0) {
992 TBM_LOG("[libtbm:%d] "
993 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
994 getpid(), bufmgr, bufmgr->ref_count);
995 pthread_mutex_unlock(&gLock);
999 /* destroy bo_list */
1000 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1001 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
1002 TBM_LOG("[libtbm:%d] "
1003 "Un-freed bo(%p, ref:%d) \n",
1004 getpid(), bo, bo->ref_cnt);
1010 /* destroy surf_list */
1011 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1012 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1013 TBM_LOG("[libtbm:%d] "
1014 "Destroy surf(%p) \n",
1016 tbm_surface_destroy(surf);
1020 /* destroy the tizen global status */
1021 _tbm_bufmgr_destroy_state(bufmgr);
1023 /* destroy bufmgr priv */
1024 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
1025 bufmgr->backend->priv = NULL;
1026 tbm_backend_free(bufmgr->backend);
1027 bufmgr->backend = NULL;
1029 pthread_mutex_destroy(&bufmgr->lock);
1032 "tizen bufmgr destroy: bufmgr:%p\n",
1035 dlclose(bufmgr->module_data);
1044 pthread_mutex_unlock(&gLock);
1047 int tbm_bo_size(tbm_bo bo)
1049 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1051 tbm_bufmgr bufmgr = bo->bufmgr;
1054 pthread_mutex_lock(&bufmgr->lock);
1056 size = bufmgr->backend->bo_size(bo);
1058 pthread_mutex_unlock(&bufmgr->lock);
1063 tbm_bo tbm_bo_ref(tbm_bo bo)
1065 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1067 tbm_bufmgr bufmgr = bo->bufmgr;
1069 pthread_mutex_lock(&bufmgr->lock);
1073 pthread_mutex_unlock(&bufmgr->lock);
1078 void tbm_bo_unref(tbm_bo bo)
1080 TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1082 tbm_bufmgr bufmgr = bo->bufmgr;
1084 pthread_mutex_lock(&bufmgr->lock);
1088 pthread_mutex_unlock(&bufmgr->lock);
1091 tbm_bo tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
1093 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1096 void *bo_priv = NULL;
1098 bo = calloc(1, sizeof(struct _tbm_bo));
1100 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
1104 bo->bufmgr = bufmgr;
1106 pthread_mutex_lock(&bufmgr->lock);
1108 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
1110 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
1112 pthread_mutex_unlock(&bufmgr->lock);
1118 bo->tgl_key = INITIAL_KEY;
1120 bo->default_handle.u32 = 0;
1123 if (!_tbm_bo_init_state(bo, CACHE_OP_CREATE)) {
1124 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1126 pthread_mutex_unlock(&bufmgr->lock);
1130 LIST_INITHEAD(&bo->user_data_list);
1132 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1134 pthread_mutex_unlock(&bufmgr->lock);
1139 tbm_bo tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
1141 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1146 void *bo_priv = NULL;
1148 pthread_mutex_lock(&bufmgr->lock);
1150 /* find bo in list */
1151 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1152 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1153 if (bo2->tgl_key == key) {
1155 "find bo(%p, ref:%d key:%d) in list \n",
1156 getpid(), bo2, bo2->ref_cnt, bo2->tgl_key);
1159 pthread_mutex_unlock(&bufmgr->lock);
1165 bo = calloc(1, sizeof(struct _tbm_bo));
1167 pthread_mutex_unlock(&bufmgr->lock);
1171 bo->bufmgr = bufmgr;
1173 bo_priv = bufmgr->backend->bo_import(bo, key);
1175 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
1177 pthread_mutex_unlock(&bufmgr->lock);
1182 bo->tgl_key = INITIAL_KEY;
1184 bo->default_handle.u32 = 0;
1186 if (bufmgr->backend->bo_get_flags)
1187 bo->flags = bufmgr->backend->bo_get_flags(bo);
1189 bo->flags = TBM_BO_DEFAULT;
1192 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1193 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1195 pthread_mutex_unlock(&bufmgr->lock);
1199 LIST_INITHEAD(&bo->user_data_list);
1201 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1203 pthread_mutex_unlock(&bufmgr->lock);
1208 tbm_bo tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1210 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1215 void *bo_priv = NULL;
1216 tbm_bo_handle default_handle;
1218 pthread_mutex_lock(&bufmgr->lock);
1220 default_handle = bufmgr->backend->fd_to_handle(bufmgr, fd, TBM_DEVICE_DEFAULT);
1222 /* find bo in list */
1223 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1224 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1225 if (bo2->default_handle.u32 == default_handle.u32) {
1227 "find bo(%p, ref:%d handle:%d) in list \n",
1228 getpid(), bo2, bo2->ref_cnt, bo2->default_handle.u32);
1231 pthread_mutex_unlock(&bufmgr->lock);
1237 bo = calloc(1, sizeof(struct _tbm_bo));
1239 pthread_mutex_unlock(&bufmgr->lock);
1243 bo->bufmgr = bufmgr;
1245 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1247 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1249 pthread_mutex_unlock(&bufmgr->lock);
1254 bo->tgl_key = INITIAL_KEY;
1256 bo->default_handle.u32 = 0;
1258 if (bufmgr->backend->bo_get_flags)
1259 bo->flags = bufmgr->backend->bo_get_flags(bo);
1261 bo->flags = TBM_BO_DEFAULT;
1264 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1265 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1267 pthread_mutex_unlock(&bufmgr->lock);
1271 LIST_INITHEAD(&bo->user_data_list);
1273 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1275 pthread_mutex_unlock(&bufmgr->lock);
1280 tbm_key tbm_bo_export(tbm_bo bo)
1282 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1287 bufmgr = bo->bufmgr;
1289 pthread_mutex_lock(&bufmgr->lock);
1290 ret = bufmgr->backend->bo_export(bo);
1292 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1293 pthread_mutex_unlock(&bufmgr->lock);
1296 pthread_mutex_unlock(&bufmgr->lock);
1301 tbm_fd tbm_bo_export_fd(tbm_bo bo)
1303 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1308 bufmgr = bo->bufmgr;
1310 pthread_mutex_lock(&bufmgr->lock);
1311 ret = bufmgr->backend->bo_export_fd(bo);
1313 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1314 pthread_mutex_unlock(&bufmgr->lock);
1317 pthread_mutex_unlock(&bufmgr->lock);
1322 tbm_bo_handle tbm_bo_get_handle(tbm_bo bo, int device)
1324 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1327 tbm_bo_handle bo_handle;
1329 bufmgr = bo->bufmgr;
1331 pthread_mutex_lock(&bufmgr->lock);
1332 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1333 if (bo_handle.ptr == NULL) {
1334 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1335 pthread_mutex_unlock(&bufmgr->lock);
1336 return (tbm_bo_handle) NULL;
1338 pthread_mutex_unlock(&bufmgr->lock);
1343 tbm_bo_handle tbm_bo_map(tbm_bo bo, int device, int opt)
1345 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1348 tbm_bo_handle bo_handle;
1350 bufmgr = bo->bufmgr;
1352 pthread_mutex_lock(&bufmgr->lock);
1354 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1356 if (!_tbm_bo_lock(bo, device, opt)) {
1357 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1358 TBM_LOG("[libtbm:%d] "
1359 "error %s:%d fail to lock bo:%p)\n",
1360 getpid(), __FUNCTION__, __LINE__, bo);
1361 pthread_mutex_unlock(&bufmgr->lock);
1362 return (tbm_bo_handle) NULL;
1365 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1366 if (bo_handle.ptr == NULL) {
1367 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1368 TBM_LOG("[libtbm:%d] "
1369 "error %s:%d fail to map bo:%p\n",
1370 getpid(), __FUNCTION__, __LINE__, bo);
1373 pthread_mutex_unlock(&bufmgr->lock);
1374 return (tbm_bo_handle) NULL;
1377 if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1378 _tbm_bo_set_state(bo, device, opt);
1380 /* increase the map_count */
1383 pthread_mutex_unlock(&bufmgr->lock);
1388 int tbm_bo_unmap(tbm_bo bo)
1390 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1395 bufmgr = bo->bufmgr;
1397 pthread_mutex_lock(&bufmgr->lock);
1399 ret = bufmgr->backend->bo_unmap(bo);
1402 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1403 pthread_mutex_unlock(&bufmgr->lock);
1407 /* decrease the map_count */
1410 if (bo->map_cnt == 0)
1411 _tbm_bo_save_state(bo);
1415 pthread_mutex_unlock(&bufmgr->lock);
1420 int tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1422 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1423 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1426 unsigned int tmp_key;
1427 tbm_bo_handle tmp_defualt_handle;
1429 pthread_mutex_lock(&bo1->bufmgr->lock);
1431 if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1432 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1433 pthread_mutex_unlock(&bo1->bufmgr->lock);
1437 tmp_key = bo1->tgl_key;
1438 bo1->tgl_key = bo2->tgl_key;
1439 bo2->tgl_key = tmp_key;
1441 tmp_defualt_handle = bo1->default_handle;
1442 bo1->default_handle = bo2->default_handle;
1443 bo2->default_handle = tmp_defualt_handle;
1446 bo1->priv = bo2->priv;
1449 pthread_mutex_unlock(&bo1->bufmgr->lock);
1454 int tbm_bo_locked(tbm_bo bo)
1456 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1460 bufmgr = bo->bufmgr;
1462 if (bufmgr->lock_type == LOCK_TRY_NEVER)
1465 pthread_mutex_lock(&bufmgr->lock);
1467 if (bo->lock_cnt > 0) {
1468 pthread_mutex_unlock(&bufmgr->lock);
1472 pthread_mutex_unlock(&bufmgr->lock);
1477 int tbm_bo_add_user_data(tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1479 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1481 tbm_user_data *data;
1483 /* check if the data according to the key exist if so, return false. */
1484 data = _user_data_lookup(&bo->user_data_list, key);
1486 TBM_LOG("[libtbm:%d] "
1487 "waring: %s:%d user data already exist. key:%ld\n",
1488 getpid(), __FUNCTION__, __LINE__, key);
1492 data = _user_data_create(key, data_free_func);
1496 LIST_ADD(&data->item_link, &bo->user_data_list);
1501 int tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1503 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1505 tbm_user_data *old_data;
1507 if (LIST_IS_EMPTY(&bo->user_data_list))
1510 old_data = _user_data_lookup(&bo->user_data_list, key);
1514 if (old_data->data && old_data->free_func)
1515 old_data->free_func(old_data->data);
1517 old_data->data = data;
1522 int tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1524 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1526 tbm_user_data *old_data;
1528 if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1531 old_data = _user_data_lookup(&bo->user_data_list, key);
1537 *data = old_data->data;
1542 int tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1544 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1546 tbm_user_data *old_data = (void *)0;
1548 if (LIST_IS_EMPTY(&bo->user_data_list))
1551 old_data = _user_data_lookup(&bo->user_data_list, key);
1555 _user_data_delete(old_data);
1560 tbm_error_e tbm_get_last_error(void)
1562 return tbm_last_error;
1565 unsigned int tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1567 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1569 unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1571 if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1572 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1574 if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1575 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1580 int tbm_bo_get_flags(tbm_bo bo)
1582 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1587 void tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1589 TBM_RETURN_IF_FAIL(bufmgr != NULL);
1590 tbm_bo bo = NULL, tmp_bo = NULL;
1593 tbm_surface_h surf = NULL, tmp_surf = NULL;
1596 char app_name[255] = {0,};
1597 unsigned int pid = 0;
1599 pthread_mutex_lock(&gLock);
1602 _tbm_util_get_appname_from_pid(getpid(), app_name);
1603 _tbm_util_get_appname_brief(app_name);
1604 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n", app_name, getpid());
1605 memset(app_name, 0x0, 255*sizeof(char));
1607 TBM_DEBUG("[tbm_surface information]\n");
1608 TBM_DEBUG("no surface refcnt width height bpp size num_bos num_planes flags format app_name\n");
1609 /* show the tbm_surface information in surf_list */
1610 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1611 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1612 pid = _tbm_surface_internal_get_debug_pid(surf);
1614 /* if pid is null, set the self_pid */
1618 _tbm_util_get_appname_from_pid(pid, app_name);
1619 _tbm_util_get_appname_brief(app_name);
1621 TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1628 surf->info.size/1024,
1632 _tbm_surface_internal_format_to_str(surf->info.format),
1635 for (i = 0; i < surf->num_bos; i++) {
1636 TBM_DEBUG(" bo:%-12p(key:%2d) %-26d%-10d\n",
1638 surf->bos[i]->tgl_key,
1639 surf->bos[i]->ref_cnt,
1640 tbm_bo_size(surf->bos[i])/1024);
1643 memset(app_name, 0x0, 255*sizeof(char));
1646 TBM_DEBUG("no tbm_surfaces.\n");
1650 TBM_DEBUG("[tbm_bo information]\n");
1651 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt cache_state flags surface\n");
1653 /* show the tbm_bo information in bo_list */
1654 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1655 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1656 TBM_DEBUG("%-4d%-11p(key:%2d) %-6d%-12d%-9d%-9d%-10d%-4d%-11p\n",
1661 tbm_bo_size(bo)/1024,
1664 bo->cache_state.val,
1669 TBM_DEBUG("no tbm_bos.\n");
1673 TBM_DEBUG("===============================================================\n");
1675 pthread_mutex_unlock(&gLock);
1679 void tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1681 TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1682 TBM_LOG("Not implemented yet.\n");
1685 /* internal function */
1686 int _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1688 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1690 bo->surface = surface;