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());
822 if (dup2(gBufMgr->fd, fd) < 0) {
823 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
824 DBG("[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);
832 gBufMgr->ref_count++;
834 DBG("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
835 getpid(), gBufMgr->fd, gBufMgr->ref_count);
836 pthread_mutex_unlock(&gLock);
844 DBG("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
846 /* allocate bufmgr */
847 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
849 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
850 pthread_mutex_unlock(&gLock);
854 gBufMgr->fd_flag = fd_flag;
859 gBufMgr->fd = dup(fd);
860 if (gBufMgr->fd < 0) {
861 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
862 TBM_LOG("[libtbm:%d] Fail to duplicate(dup) the drm fd\n",
866 pthread_mutex_unlock(&gLock);
869 DBG("[libtbm:%d] duplicate the drm_fd(%d), bufmgr use fd(%d).\n",
870 getpid(), fd, gBufMgr->fd);
873 /* load bufmgr priv from env */
874 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
875 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
876 TBM_LOG("[libtbm:%d] " "error : Fail to load bufmgr backend\n", getpid());
883 pthread_mutex_unlock(&gLock);
886 backend_flag = gBufMgr->backend->flags;
887 /* log for tbm backend_flag */
888 DBG("[libtbm:%d] ", getpid());
890 if (backend_flag & TBM_CACHE_CTRL_BACKEND) {
897 if (backend_flag & TBM_LOCK_CTRL_BACKEND) {
906 gBufMgr->ref_count = 1;
908 DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
909 getpid(), gBufMgr->ref_count);
911 if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
912 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
913 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
914 tbm_backend_free(gBufMgr->backend);
915 dlclose(gBufMgr->module_data);
922 pthread_mutex_unlock(&gLock);
926 /* intialize the tizen global status */
927 if (!_tbm_bufmgr_init_state(gBufMgr)) {
928 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
929 TBM_LOG("[libtbm:%d] " "error: Fail to init state\n", getpid());
930 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
931 tbm_backend_free(gBufMgr->backend);
932 pthread_mutex_destroy(&gBufMgr->lock);
933 dlclose(gBufMgr->module_data);
940 pthread_mutex_unlock(&gLock);
944 /* setup the lock_type */
945 env = getenv("BUFMGR_LOCK_TYPE");
946 if (env && !strcmp(env, "always"))
947 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
948 else if (env && !strcmp(env, "none"))
949 gBufMgr->lock_type = LOCK_TRY_NEVER;
950 else if (env && !strcmp(env, "once"))
951 gBufMgr->lock_type = LOCK_TRY_ONCE;
953 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
955 DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
956 getpid(), env ? env : "default:once");
958 /* setup the map_cache */
959 env = getenv("BUFMGR_MAP_CACHE");
960 if (env && !strcmp(env, "false"))
961 gBufMgr->use_map_cache = 0;
963 gBufMgr->use_map_cache = 1;
964 DBG("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n",
965 getpid(), env ? env : "default:true");
967 /* intialize bo_list */
968 LIST_INITHEAD(&gBufMgr->bo_list);
970 /* intialize surf_list */
971 LIST_INITHEAD(&gBufMgr->surf_list);
973 pthread_mutex_unlock(&gLock);
977 void tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
979 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
984 tbm_surface_h surf = NULL;
985 tbm_surface_h tmp_surf = NULL;
987 pthread_mutex_lock(&gLock);
990 if (bufmgr->ref_count > 0) {
991 TBM_LOG("[libtbm:%d] "
992 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
993 getpid(), bufmgr, bufmgr->ref_count);
994 pthread_mutex_unlock(&gLock);
998 /* destroy bo_list */
999 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1000 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
1001 TBM_LOG("[libtbm:%d] "
1002 "Un-freed bo(%p, ref:%d) \n",
1003 getpid(), bo, bo->ref_cnt);
1009 /* destroy surf_list */
1010 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1011 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1012 TBM_LOG("[libtbm:%d] "
1013 "Destroy surf(%p) \n",
1015 tbm_surface_destroy(surf);
1019 /* destroy the tizen global status */
1020 _tbm_bufmgr_destroy_state(bufmgr);
1022 /* destroy bufmgr priv */
1023 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
1024 bufmgr->backend->priv = NULL;
1025 tbm_backend_free(bufmgr->backend);
1026 bufmgr->backend = NULL;
1028 pthread_mutex_destroy(&bufmgr->lock);
1031 "tizen bufmgr destroy: bufmgr:%p\n",
1034 dlclose(bufmgr->module_data);
1043 pthread_mutex_unlock(&gLock);
1046 int tbm_bo_size(tbm_bo bo)
1048 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1050 tbm_bufmgr bufmgr = bo->bufmgr;
1053 pthread_mutex_lock(&bufmgr->lock);
1055 size = bufmgr->backend->bo_size(bo);
1057 pthread_mutex_unlock(&bufmgr->lock);
1062 tbm_bo tbm_bo_ref(tbm_bo bo)
1064 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1066 tbm_bufmgr bufmgr = bo->bufmgr;
1068 pthread_mutex_lock(&bufmgr->lock);
1072 pthread_mutex_unlock(&bufmgr->lock);
1077 void tbm_bo_unref(tbm_bo bo)
1079 TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1081 tbm_bufmgr bufmgr = bo->bufmgr;
1083 pthread_mutex_lock(&bufmgr->lock);
1087 pthread_mutex_unlock(&bufmgr->lock);
1090 tbm_bo tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
1092 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1095 void *bo_priv = NULL;
1097 bo = calloc(1, sizeof(struct _tbm_bo));
1099 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
1103 bo->bufmgr = bufmgr;
1105 pthread_mutex_lock(&bufmgr->lock);
1107 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
1109 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
1111 pthread_mutex_unlock(&bufmgr->lock);
1117 bo->tgl_key = INITIAL_KEY;
1119 bo->default_handle.u32 = 0;
1122 if (!_tbm_bo_init_state(bo, CACHE_OP_CREATE)) {
1123 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1125 pthread_mutex_unlock(&bufmgr->lock);
1129 LIST_INITHEAD(&bo->user_data_list);
1131 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1133 pthread_mutex_unlock(&bufmgr->lock);
1138 tbm_bo tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
1140 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1145 void *bo_priv = NULL;
1147 pthread_mutex_lock(&bufmgr->lock);
1149 /* find bo in list */
1150 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1151 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1152 if (bo2->tgl_key == key) {
1154 "find bo(%p, ref:%d key:%d) in list \n",
1155 getpid(), bo2, bo2->ref_cnt, bo2->tgl_key);
1158 pthread_mutex_unlock(&bufmgr->lock);
1164 bo = calloc(1, sizeof(struct _tbm_bo));
1166 pthread_mutex_unlock(&bufmgr->lock);
1170 bo->bufmgr = bufmgr;
1172 bo_priv = bufmgr->backend->bo_import(bo, key);
1174 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
1176 pthread_mutex_unlock(&bufmgr->lock);
1181 bo->tgl_key = INITIAL_KEY;
1183 bo->default_handle.u32 = 0;
1185 if (bufmgr->backend->bo_get_flags)
1186 bo->flags = bufmgr->backend->bo_get_flags(bo);
1188 bo->flags = TBM_BO_DEFAULT;
1191 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1192 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1194 pthread_mutex_unlock(&bufmgr->lock);
1198 LIST_INITHEAD(&bo->user_data_list);
1200 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1202 pthread_mutex_unlock(&bufmgr->lock);
1207 tbm_bo tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1209 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1214 void *bo_priv = NULL;
1215 tbm_bo_handle default_handle;
1217 pthread_mutex_lock(&bufmgr->lock);
1219 default_handle = bufmgr->backend->fd_to_handle(bufmgr, fd, TBM_DEVICE_DEFAULT);
1221 /* find bo in list */
1222 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1223 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1224 if (bo2->default_handle.u32 == default_handle.u32) {
1226 "find bo(%p, ref:%d handle:%d) in list \n",
1227 getpid(), bo2, bo2->ref_cnt, bo2->default_handle.u32);
1230 pthread_mutex_unlock(&bufmgr->lock);
1236 bo = calloc(1, sizeof(struct _tbm_bo));
1238 pthread_mutex_unlock(&bufmgr->lock);
1242 bo->bufmgr = bufmgr;
1244 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1246 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1248 pthread_mutex_unlock(&bufmgr->lock);
1253 bo->tgl_key = INITIAL_KEY;
1255 bo->default_handle.u32 = 0;
1257 if (bufmgr->backend->bo_get_flags)
1258 bo->flags = bufmgr->backend->bo_get_flags(bo);
1260 bo->flags = TBM_BO_DEFAULT;
1263 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1264 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1266 pthread_mutex_unlock(&bufmgr->lock);
1270 LIST_INITHEAD(&bo->user_data_list);
1272 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1274 pthread_mutex_unlock(&bufmgr->lock);
1279 tbm_key tbm_bo_export(tbm_bo bo)
1281 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1286 bufmgr = bo->bufmgr;
1288 pthread_mutex_lock(&bufmgr->lock);
1289 ret = bufmgr->backend->bo_export(bo);
1291 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1292 pthread_mutex_unlock(&bufmgr->lock);
1295 pthread_mutex_unlock(&bufmgr->lock);
1300 tbm_fd tbm_bo_export_fd(tbm_bo bo)
1302 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1307 bufmgr = bo->bufmgr;
1309 pthread_mutex_lock(&bufmgr->lock);
1310 ret = bufmgr->backend->bo_export_fd(bo);
1312 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1313 pthread_mutex_unlock(&bufmgr->lock);
1316 pthread_mutex_unlock(&bufmgr->lock);
1321 tbm_bo_handle tbm_bo_get_handle(tbm_bo bo, int device)
1323 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1326 tbm_bo_handle bo_handle;
1328 bufmgr = bo->bufmgr;
1330 pthread_mutex_lock(&bufmgr->lock);
1331 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1332 if (bo_handle.ptr == NULL) {
1333 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1334 pthread_mutex_unlock(&bufmgr->lock);
1335 return (tbm_bo_handle) NULL;
1337 pthread_mutex_unlock(&bufmgr->lock);
1342 tbm_bo_handle tbm_bo_map(tbm_bo bo, int device, int opt)
1344 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1347 tbm_bo_handle bo_handle;
1349 bufmgr = bo->bufmgr;
1351 pthread_mutex_lock(&bufmgr->lock);
1353 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1355 if (!_tbm_bo_lock(bo, device, opt)) {
1356 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1357 TBM_LOG("[libtbm:%d] "
1358 "error %s:%d fail to lock bo:%p)\n",
1359 getpid(), __FUNCTION__, __LINE__, bo);
1360 pthread_mutex_unlock(&bufmgr->lock);
1361 return (tbm_bo_handle) NULL;
1364 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1365 if (bo_handle.ptr == NULL) {
1366 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1367 TBM_LOG("[libtbm:%d] "
1368 "error %s:%d fail to map bo:%p\n",
1369 getpid(), __FUNCTION__, __LINE__, bo);
1372 pthread_mutex_unlock(&bufmgr->lock);
1373 return (tbm_bo_handle) NULL;
1376 if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1377 _tbm_bo_set_state(bo, device, opt);
1379 /* increase the map_count */
1382 pthread_mutex_unlock(&bufmgr->lock);
1387 int tbm_bo_unmap(tbm_bo bo)
1389 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1394 bufmgr = bo->bufmgr;
1396 pthread_mutex_lock(&bufmgr->lock);
1398 ret = bufmgr->backend->bo_unmap(bo);
1401 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1402 pthread_mutex_unlock(&bufmgr->lock);
1406 /* decrease the map_count */
1409 if (bo->map_cnt == 0)
1410 _tbm_bo_save_state(bo);
1414 pthread_mutex_unlock(&bufmgr->lock);
1419 int tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1421 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1422 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1425 unsigned int tmp_key;
1426 tbm_bo_handle tmp_defualt_handle;
1428 pthread_mutex_lock(&bo1->bufmgr->lock);
1430 if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1431 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1432 pthread_mutex_unlock(&bo1->bufmgr->lock);
1436 tmp_key = bo1->tgl_key;
1437 bo1->tgl_key = bo2->tgl_key;
1438 bo2->tgl_key = tmp_key;
1440 tmp_defualt_handle = bo1->default_handle;
1441 bo1->default_handle = bo2->default_handle;
1442 bo2->default_handle = tmp_defualt_handle;
1445 bo1->priv = bo2->priv;
1448 pthread_mutex_unlock(&bo1->bufmgr->lock);
1453 int tbm_bo_locked(tbm_bo bo)
1455 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1459 bufmgr = bo->bufmgr;
1461 if (bufmgr->lock_type == LOCK_TRY_NEVER)
1464 pthread_mutex_lock(&bufmgr->lock);
1466 if (bo->lock_cnt > 0) {
1467 pthread_mutex_unlock(&bufmgr->lock);
1471 pthread_mutex_unlock(&bufmgr->lock);
1476 int tbm_bo_add_user_data(tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1478 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1480 tbm_user_data *data;
1482 /* check if the data according to the key exist if so, return false. */
1483 data = _user_data_lookup(&bo->user_data_list, key);
1485 TBM_LOG("[libtbm:%d] "
1486 "waring: %s:%d user data already exist. key:%ld\n",
1487 getpid(), __FUNCTION__, __LINE__, key);
1491 data = _user_data_create(key, data_free_func);
1495 LIST_ADD(&data->item_link, &bo->user_data_list);
1500 int tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1502 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1504 tbm_user_data *old_data;
1506 if (LIST_IS_EMPTY(&bo->user_data_list))
1509 old_data = _user_data_lookup(&bo->user_data_list, key);
1513 if (old_data->data && old_data->free_func)
1514 old_data->free_func(old_data->data);
1516 old_data->data = data;
1521 int tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1523 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1525 tbm_user_data *old_data;
1527 if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1530 old_data = _user_data_lookup(&bo->user_data_list, key);
1536 *data = old_data->data;
1541 int tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1543 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1545 tbm_user_data *old_data = (void *)0;
1547 if (LIST_IS_EMPTY(&bo->user_data_list))
1550 old_data = _user_data_lookup(&bo->user_data_list, key);
1554 _user_data_delete(old_data);
1559 tbm_error_e tbm_get_last_error(void)
1561 return tbm_last_error;
1564 unsigned int tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1566 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1568 unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1570 if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1571 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1573 if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1574 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1579 int tbm_bo_get_flags(tbm_bo bo)
1581 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1586 void tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1588 TBM_RETURN_IF_FAIL(bufmgr != NULL);
1589 tbm_bo bo = NULL, tmp_bo = NULL;
1592 tbm_surface_h surf = NULL, tmp_surf = NULL;
1595 char app_name[255] = {0,};
1596 unsigned int pid = 0;
1598 pthread_mutex_lock(&gLock);
1601 _tbm_util_get_appname_from_pid(getpid(), app_name);
1602 _tbm_util_get_appname_brief(app_name);
1603 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n", app_name, getpid());
1604 memset(app_name, 0x0, 255*sizeof(char));
1606 TBM_DEBUG("[tbm_surface information]\n");
1607 TBM_DEBUG("no surface refcnt width height bpp size num_bos num_planes flags format app_name\n");
1608 /* show the tbm_surface information in surf_list */
1609 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1610 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1611 pid = _tbm_surface_internal_get_debug_pid(surf);
1613 /* if pid is null, set the self_pid */
1617 _tbm_util_get_appname_from_pid(pid, app_name);
1618 _tbm_util_get_appname_brief(app_name);
1620 TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1627 surf->info.size/1024,
1631 _tbm_surface_internal_format_to_str(surf->info.format),
1634 for (i = 0; i < surf->num_bos; i++) {
1635 TBM_DEBUG(" bo:%-12p(key:%2d) %-26d%-10d\n",
1637 surf->bos[i]->tgl_key,
1638 surf->bos[i]->ref_cnt,
1639 tbm_bo_size(surf->bos[i])/1024);
1642 memset(app_name, 0x0, 255*sizeof(char));
1645 TBM_DEBUG("no tbm_surfaces.\n");
1649 TBM_DEBUG("[tbm_bo information]\n");
1650 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt cache_state flags surface\n");
1652 /* show the tbm_bo information in bo_list */
1653 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1654 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1655 TBM_DEBUG("%-4d%-11p(key:%2d) %-6d%-12d%-9d%-9d%-10d%-4d%-11p\n",
1660 tbm_bo_size(bo)/1024,
1663 bo->cache_state.val,
1668 TBM_DEBUG("no tbm_bos.\n");
1672 TBM_DEBUG("===============================================================\n");
1674 pthread_mutex_unlock(&gLock);
1678 void tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1680 TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1681 TBM_LOG("Not implemented yet.\n");
1684 /* internal function */
1685 int _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1687 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1689 bo->surface = surface;