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);
842 fd = tbm_bufmgr_get_drm_fd_x11();
844 fd = tbm_bufmgr_get_drm_fd_wayland();
847 _tbm_set_last_result(TBM_BO_ERROR_GET_FD_FAILED);
848 TBM_LOG("[libtbm:%d] Fail get drm fd\n",
850 pthread_mutex_unlock(&gLock);
856 DBG("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
858 /* allocate bufmgr */
859 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
861 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
865 pthread_mutex_unlock(&gLock);
869 gBufMgr->fd_flag = fd_flag;
874 gBufMgr->fd = dup(fd);
875 if (gBufMgr->fd < 0) {
876 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
877 TBM_LOG("[libtbm:%d] Fail to duplicate(dup) the drm fd\n",
881 pthread_mutex_unlock(&gLock);
884 DBG("[libtbm:%d] duplicate the drm_fd(%d), bufmgr use fd(%d).\n",
885 getpid(), fd, gBufMgr->fd);
888 /* load bufmgr priv from env */
889 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
890 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
891 TBM_LOG("[libtbm:%d] " "error : Fail to load bufmgr backend\n", getpid());
895 pthread_mutex_unlock(&gLock);
898 backend_flag = gBufMgr->backend->flags;
899 /* log for tbm backend_flag */
900 DBG("[libtbm:%d] ", getpid());
902 if (backend_flag & TBM_CACHE_CTRL_BACKEND) {
909 if (backend_flag & TBM_LOCK_CTRL_BACKEND) {
918 gBufMgr->ref_count = 1;
920 DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
921 getpid(), gBufMgr->ref_count);
923 if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
924 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
925 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
926 tbm_backend_free(gBufMgr->backend);
927 dlclose(gBufMgr->module_data);
931 pthread_mutex_unlock(&gLock);
935 /* intialize the tizen global status */
936 if (!_tbm_bufmgr_init_state(gBufMgr)) {
937 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
938 TBM_LOG("[libtbm:%d] " "error: Fail to init state\n", getpid());
939 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
940 tbm_backend_free(gBufMgr->backend);
941 pthread_mutex_destroy(&gBufMgr->lock);
942 dlclose(gBufMgr->module_data);
946 pthread_mutex_unlock(&gLock);
950 /* setup the lock_type */
951 env = getenv("BUFMGR_LOCK_TYPE");
952 if (env && !strcmp(env, "always"))
953 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
954 else if (env && !strcmp(env, "none"))
955 gBufMgr->lock_type = LOCK_TRY_NEVER;
956 else if (env && !strcmp(env, "once"))
957 gBufMgr->lock_type = LOCK_TRY_ONCE;
959 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
961 DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
962 getpid(), env ? env : "default:once");
964 /* setup the map_cache */
965 env = getenv("BUFMGR_MAP_CACHE");
966 if (env && !strcmp(env, "false"))
967 gBufMgr->use_map_cache = 0;
969 gBufMgr->use_map_cache = 1;
970 DBG("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n",
971 getpid(), env ? env : "default:true");
973 /* intialize bo_list */
974 LIST_INITHEAD(&gBufMgr->bo_list);
976 /* intialize surf_list */
977 LIST_INITHEAD(&gBufMgr->surf_list);
979 pthread_mutex_unlock(&gLock);
983 void tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
985 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
990 tbm_surface_h surf = NULL;
991 tbm_surface_h tmp_surf = NULL;
993 pthread_mutex_lock(&gLock);
996 if (bufmgr->ref_count > 0) {
997 TBM_LOG("[libtbm:%d] "
998 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
999 getpid(), bufmgr, bufmgr->ref_count);
1000 pthread_mutex_unlock(&gLock);
1004 /* destroy bo_list */
1005 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1006 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
1007 TBM_LOG("[libtbm:%d] "
1008 "Un-freed bo(%p, ref:%d) \n",
1009 getpid(), bo, bo->ref_cnt);
1015 /* destroy surf_list */
1016 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1017 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1018 TBM_LOG("[libtbm:%d] "
1019 "Destroy surf(%p) \n",
1021 tbm_surface_destroy(surf);
1025 /* destroy the tizen global status */
1026 _tbm_bufmgr_destroy_state(bufmgr);
1028 /* destroy bufmgr priv */
1029 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
1030 bufmgr->backend->priv = NULL;
1031 tbm_backend_free(bufmgr->backend);
1032 bufmgr->backend = NULL;
1034 pthread_mutex_destroy(&bufmgr->lock);
1037 "tizen bufmgr destroy: bufmgr:%p\n",
1040 dlclose(bufmgr->module_data);
1048 pthread_mutex_unlock(&gLock);
1051 int tbm_bo_size(tbm_bo bo)
1053 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1055 tbm_bufmgr bufmgr = bo->bufmgr;
1058 pthread_mutex_lock(&bufmgr->lock);
1060 size = bufmgr->backend->bo_size(bo);
1062 pthread_mutex_unlock(&bufmgr->lock);
1067 tbm_bo tbm_bo_ref(tbm_bo bo)
1069 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1071 tbm_bufmgr bufmgr = bo->bufmgr;
1073 pthread_mutex_lock(&bufmgr->lock);
1077 pthread_mutex_unlock(&bufmgr->lock);
1082 void tbm_bo_unref(tbm_bo bo)
1084 TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1086 tbm_bufmgr bufmgr = bo->bufmgr;
1088 pthread_mutex_lock(&bufmgr->lock);
1092 pthread_mutex_unlock(&bufmgr->lock);
1095 tbm_bo tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
1097 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1100 void *bo_priv = NULL;
1102 bo = calloc(1, sizeof(struct _tbm_bo));
1104 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
1108 bo->bufmgr = bufmgr;
1110 pthread_mutex_lock(&bufmgr->lock);
1112 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
1114 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
1116 pthread_mutex_unlock(&bufmgr->lock);
1122 bo->tgl_key = INITIAL_KEY;
1124 bo->default_handle.u32 = 0;
1127 if (!_tbm_bo_init_state(bo, CACHE_OP_CREATE)) {
1128 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1130 pthread_mutex_unlock(&bufmgr->lock);
1134 LIST_INITHEAD(&bo->user_data_list);
1136 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1138 pthread_mutex_unlock(&bufmgr->lock);
1143 tbm_bo tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
1145 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1150 void *bo_priv = NULL;
1152 pthread_mutex_lock(&bufmgr->lock);
1154 /* find bo in list */
1155 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1156 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1157 if (bo2->tgl_key == key) {
1159 "find bo(%p, ref:%d key:%d) in list \n",
1160 getpid(), bo2, bo2->ref_cnt, bo2->tgl_key);
1163 pthread_mutex_unlock(&bufmgr->lock);
1169 bo = calloc(1, sizeof(struct _tbm_bo));
1171 pthread_mutex_unlock(&bufmgr->lock);
1175 bo->bufmgr = bufmgr;
1177 bo_priv = bufmgr->backend->bo_import(bo, key);
1179 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
1181 pthread_mutex_unlock(&bufmgr->lock);
1186 bo->tgl_key = INITIAL_KEY;
1188 bo->default_handle.u32 = 0;
1190 if (bufmgr->backend->bo_get_flags)
1191 bo->flags = bufmgr->backend->bo_get_flags(bo);
1193 bo->flags = TBM_BO_DEFAULT;
1196 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1197 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1199 pthread_mutex_unlock(&bufmgr->lock);
1203 LIST_INITHEAD(&bo->user_data_list);
1205 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1207 pthread_mutex_unlock(&bufmgr->lock);
1212 tbm_bo tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1214 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1219 void *bo_priv = NULL;
1220 tbm_bo_handle default_handle;
1222 pthread_mutex_lock(&bufmgr->lock);
1224 default_handle = bufmgr->backend->fd_to_handle(bufmgr, fd, TBM_DEVICE_DEFAULT);
1226 /* find bo in list */
1227 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1228 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1229 if (bo2->default_handle.u32 == default_handle.u32) {
1231 "find bo(%p, ref:%d handle:%d) in list \n",
1232 getpid(), bo2, bo2->ref_cnt, bo2->default_handle.u32);
1235 pthread_mutex_unlock(&bufmgr->lock);
1241 bo = calloc(1, sizeof(struct _tbm_bo));
1243 pthread_mutex_unlock(&bufmgr->lock);
1247 bo->bufmgr = bufmgr;
1249 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1251 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1253 pthread_mutex_unlock(&bufmgr->lock);
1258 bo->tgl_key = INITIAL_KEY;
1260 bo->default_handle.u32 = 0;
1262 if (bufmgr->backend->bo_get_flags)
1263 bo->flags = bufmgr->backend->bo_get_flags(bo);
1265 bo->flags = TBM_BO_DEFAULT;
1268 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1269 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1271 pthread_mutex_unlock(&bufmgr->lock);
1275 LIST_INITHEAD(&bo->user_data_list);
1277 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1279 pthread_mutex_unlock(&bufmgr->lock);
1284 tbm_key tbm_bo_export(tbm_bo bo)
1286 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1291 bufmgr = bo->bufmgr;
1293 pthread_mutex_lock(&bufmgr->lock);
1294 ret = bufmgr->backend->bo_export(bo);
1296 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1297 pthread_mutex_unlock(&bufmgr->lock);
1300 pthread_mutex_unlock(&bufmgr->lock);
1305 tbm_fd tbm_bo_export_fd(tbm_bo bo)
1307 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1312 bufmgr = bo->bufmgr;
1314 pthread_mutex_lock(&bufmgr->lock);
1315 ret = bufmgr->backend->bo_export_fd(bo);
1317 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1318 pthread_mutex_unlock(&bufmgr->lock);
1321 pthread_mutex_unlock(&bufmgr->lock);
1326 tbm_bo_handle tbm_bo_get_handle(tbm_bo bo, int device)
1328 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1331 tbm_bo_handle bo_handle;
1333 bufmgr = bo->bufmgr;
1335 pthread_mutex_lock(&bufmgr->lock);
1336 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1337 if (bo_handle.ptr == NULL) {
1338 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1339 pthread_mutex_unlock(&bufmgr->lock);
1340 return (tbm_bo_handle) NULL;
1342 pthread_mutex_unlock(&bufmgr->lock);
1347 tbm_bo_handle tbm_bo_map(tbm_bo bo, int device, int opt)
1349 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1352 tbm_bo_handle bo_handle;
1354 bufmgr = bo->bufmgr;
1356 pthread_mutex_lock(&bufmgr->lock);
1358 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1360 if (!_tbm_bo_lock(bo, device, opt)) {
1361 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1362 TBM_LOG("[libtbm:%d] "
1363 "error %s:%d fail to lock bo:%p)\n",
1364 getpid(), __FUNCTION__, __LINE__, bo);
1365 pthread_mutex_unlock(&bufmgr->lock);
1366 return (tbm_bo_handle) NULL;
1369 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1370 if (bo_handle.ptr == NULL) {
1371 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1372 TBM_LOG("[libtbm:%d] "
1373 "error %s:%d fail to map bo:%p\n",
1374 getpid(), __FUNCTION__, __LINE__, bo);
1377 pthread_mutex_unlock(&bufmgr->lock);
1378 return (tbm_bo_handle) NULL;
1381 if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1382 _tbm_bo_set_state(bo, device, opt);
1384 /* increase the map_count */
1387 pthread_mutex_unlock(&bufmgr->lock);
1392 int tbm_bo_unmap(tbm_bo bo)
1394 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1399 bufmgr = bo->bufmgr;
1401 pthread_mutex_lock(&bufmgr->lock);
1403 ret = bufmgr->backend->bo_unmap(bo);
1406 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1407 pthread_mutex_unlock(&bufmgr->lock);
1411 /* decrease the map_count */
1414 if (bo->map_cnt == 0)
1415 _tbm_bo_save_state(bo);
1419 pthread_mutex_unlock(&bufmgr->lock);
1424 int tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1426 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1427 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1430 unsigned int tmp_key;
1431 tbm_bo_handle tmp_defualt_handle;
1433 pthread_mutex_lock(&bo1->bufmgr->lock);
1435 if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1436 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1437 pthread_mutex_unlock(&bo1->bufmgr->lock);
1441 tmp_key = bo1->tgl_key;
1442 bo1->tgl_key = bo2->tgl_key;
1443 bo2->tgl_key = tmp_key;
1445 tmp_defualt_handle = bo1->default_handle;
1446 bo1->default_handle = bo2->default_handle;
1447 bo2->default_handle = tmp_defualt_handle;
1450 bo1->priv = bo2->priv;
1453 pthread_mutex_unlock(&bo1->bufmgr->lock);
1458 int tbm_bo_locked(tbm_bo bo)
1460 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1464 bufmgr = bo->bufmgr;
1466 if (bufmgr->lock_type == LOCK_TRY_NEVER)
1469 pthread_mutex_lock(&bufmgr->lock);
1471 if (bo->lock_cnt > 0) {
1472 pthread_mutex_unlock(&bufmgr->lock);
1476 pthread_mutex_unlock(&bufmgr->lock);
1481 int tbm_bo_add_user_data(tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1483 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1485 tbm_user_data *data;
1487 /* check if the data according to the key exist if so, return false. */
1488 data = _user_data_lookup(&bo->user_data_list, key);
1490 TBM_LOG("[libtbm:%d] "
1491 "waring: %s:%d user data already exist. key:%ld\n",
1492 getpid(), __FUNCTION__, __LINE__, key);
1496 data = _user_data_create(key, data_free_func);
1500 LIST_ADD(&data->item_link, &bo->user_data_list);
1505 int tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1507 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1509 tbm_user_data *old_data;
1511 if (LIST_IS_EMPTY(&bo->user_data_list))
1514 old_data = _user_data_lookup(&bo->user_data_list, key);
1518 if (old_data->data && old_data->free_func)
1519 old_data->free_func(old_data->data);
1521 old_data->data = data;
1526 int tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1528 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1530 tbm_user_data *old_data;
1532 if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1535 old_data = _user_data_lookup(&bo->user_data_list, key);
1541 *data = old_data->data;
1546 int tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1548 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1550 tbm_user_data *old_data = (void *)0;
1552 if (LIST_IS_EMPTY(&bo->user_data_list))
1555 old_data = _user_data_lookup(&bo->user_data_list, key);
1559 _user_data_delete(old_data);
1564 tbm_error_e tbm_get_last_error(void)
1566 return tbm_last_error;
1569 unsigned int tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1571 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1573 unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1575 if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1576 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1578 if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1579 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1584 int tbm_bo_get_flags(tbm_bo bo)
1586 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1591 void tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1593 TBM_RETURN_IF_FAIL(bufmgr != NULL);
1594 tbm_bo bo = NULL, tmp_bo = NULL;
1597 tbm_surface_h surf = NULL, tmp_surf = NULL;
1600 char app_name[255] = {0,};
1601 unsigned int pid = 0;
1603 pthread_mutex_lock(&gLock);
1606 _tbm_util_get_appname_from_pid(getpid(), app_name);
1607 _tbm_util_get_appname_brief(app_name);
1608 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n", app_name, getpid());
1609 memset(app_name, 0x0, 255*sizeof(char));
1611 TBM_DEBUG("[tbm_surface information]\n");
1612 TBM_DEBUG("no surface refcnt width height bpp size num_bos num_planes flags format app_name\n");
1613 /* show the tbm_surface information in surf_list */
1614 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1615 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1616 pid = _tbm_surface_internal_get_debug_pid(surf);
1618 /* if pid is null, set the self_pid */
1622 _tbm_util_get_appname_from_pid(pid, app_name);
1623 _tbm_util_get_appname_brief(app_name);
1625 TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1632 surf->info.size/1024,
1636 _tbm_surface_internal_format_to_str(surf->info.format),
1639 for (i = 0; i < surf->num_bos; i++) {
1640 TBM_DEBUG(" bo:%-12p(key:%2d) %-26d%-10d\n",
1642 surf->bos[i]->tgl_key,
1643 surf->bos[i]->ref_cnt,
1644 tbm_bo_size(surf->bos[i])/1024);
1647 memset(app_name, 0x0, 255*sizeof(char));
1650 TBM_DEBUG("no tbm_surfaces.\n");
1654 TBM_DEBUG("[tbm_bo information]\n");
1655 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt cache_state flags surface\n");
1657 /* show the tbm_bo information in bo_list */
1658 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1659 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1660 TBM_DEBUG("%-4d%-11p(key:%2d) %-6d%-12d%-9d%-9d%-10d%-4d%-11p\n",
1665 tbm_bo_size(bo)/1024,
1668 bo->cache_state.val,
1673 TBM_DEBUG("no tbm_bos.\n");
1677 TBM_DEBUG("===============================================================\n");
1679 pthread_mutex_unlock(&gLock);
1683 void tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1685 TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1686 TBM_LOG("Not implemented yet.\n");
1689 /* internal function */
1690 int _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1692 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1694 bo->surface = surface;