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"
39 #include "tbm_user_data.h"
44 #define DBG(...) if (bDebug&0x1) TBM_LOG(__VA_ARGS__)
45 #define DBG_LOCK(...) if (bDebug&0x2) TBM_LOG(__VA_ARGS__)
51 #define PREFIX_LIB "libtbm_"
52 #define SUFFIX_LIB ".so"
53 #define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB
55 #define BO_IS_CACHEABLE(bo) ((bo->flags & TBM_BO_NONCACHABLE) ? 0 : 1)
56 #define DEVICE_IS_CACHE_AWARE(device) ((device == TBM_DEVICE_CPU) ? (1) : (0))
59 #define GLOBAL_KEY ((unsigned int)(-1))
60 #define INITIAL_KEY ((unsigned int)(-2))
62 #define CACHE_OP_CREATE (-1)
63 #define CACHE_OP_ATTACH (-2)
64 #define CACHE_OP_IMPORT (-3)
66 /* values to indicate unspecified fields in XF86ModReqInfo. */
67 #define MAJOR_UNSPEC 0xFF
68 #define MINOR_UNSPEC 0xFF
69 #define PATCH_UNSPEC 0xFFFF
70 #define ABI_VERS_UNSPEC 0xFFFFFFFF
72 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
73 ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
74 #define GET_MODULE_MAJOR_VERSION(vers) (((vers) >> 24) & 0xFF)
75 #define GET_MODULE_MINOR_VERSION(vers) (((vers) >> 16) & 0xFF)
76 #define GET_MODULE_PATCHLEVEL(vers) ((vers) & 0xFFFF)
86 DEVICE_CA, /* cache aware device */
87 DEVICE_CO /* cache oblivious device */
90 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
91 tbm_bufmgr gBufMgr = NULL;
93 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
95 static void _tbm_set_last_result(tbm_error_e err)
100 static void _tbm_util_get_appname_brief(char *brief)
104 char temp[255] = {0,};
105 char *saveptr = NULL;
107 token = strtok_r(brief, delim, &saveptr);
109 while (token != NULL) {
110 memset(temp, 0x00, 255*sizeof(char));
111 strncpy(temp, token, 254*sizeof(char));
112 token = strtok_r(NULL, delim, &saveptr);
115 snprintf(brief, sizeof(temp), "%s", temp);
118 static void _tbm_util_get_appname_from_pid(long pid, char *str)
123 char fn_cmdline[255] = {0,};
124 char cmdline[255] = {0,};
126 snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
128 fp = fopen(fn_cmdline, "r");
130 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
134 if (!fgets(cmdline, 255, fp)) {
135 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
141 len = strlen(cmdline);
143 memset(cmdline, 0x00, 255);
147 snprintf(str, sizeof(cmdline), "%s", cmdline);
150 static inline int _tgl_init(int fd, unsigned int key)
152 struct tgl_attribute attr;
156 attr.timeout_ms = 1000;
158 err = ioctl(fd, TGL_IOC_INIT_LOCK, &attr);
160 TBM_LOG("[libtbm:%d] "
161 "error(%s) %s:%d key:%d\n",
162 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
169 static inline int _tgl_destroy(int fd, unsigned int key)
172 err = ioctl(fd, TGL_IOC_DESTROY_LOCK, key);
174 TBM_LOG("[libtbm:%d] "
175 "error(%s) %s:%d key:%d\n",
176 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
183 static inline int _tgl_lock(int fd, unsigned int key)
186 err = ioctl(fd, TGL_IOC_LOCK_LOCK, key);
188 TBM_LOG("[libtbm:%d] "
189 "error(%s) %s:%d key:%d\n",
190 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
197 static inline int _tgl_unlock(int fd, unsigned int key)
200 err = ioctl(fd, TGL_IOC_UNLOCK_LOCK, key);
202 TBM_LOG("[libtbm:%d] "
203 "error(%s) %s:%d key:%d\n",
204 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
211 static inline int _tgl_set_data(int fd, unsigned int key, unsigned int val)
214 struct tgl_user_data arg;
218 err = ioctl(fd, TGL_IOC_SET_DATA, &arg);
220 TBM_LOG("[libtbm:%d] "
221 "error(%s) %s:%d key:%d\n",
222 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
229 static inline unsigned int _tgl_get_data(int fd, unsigned int key, unsigned int *locked)
232 struct tgl_user_data arg = { 0, };
235 err = ioctl(fd, TGL_IOC_GET_DATA, &arg);
237 TBM_LOG("[libtbm:%d] "
238 "error(%s) %s:%d key:%d\n",
239 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
244 *locked = arg.locked;
248 static int _bo_lock(tbm_bo bo, int device, int opt)
250 tbm_bufmgr bufmgr = bo->bufmgr;
253 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
254 if (bufmgr->backend->bo_lock2) {
255 /* use bo_lock2 backend lock */
256 ret = bufmgr->backend->bo_lock2(bo, device, opt);
257 } else if (bufmgr->backend->bo_lock) {
258 /* use bo_lock backend lock */
259 ret = bufmgr->backend->bo_lock(bo);
261 TBM_LOG("[libtbm:%d] "
262 "error %s:%d no backend lock functions\n",
263 getpid(), __FUNCTION__, __LINE__);
266 /* use tizen global lock */
267 ret = _tgl_lock(bufmgr->lock_fd, bo->tgl_key);
273 static void _bo_unlock(tbm_bo bo)
275 tbm_bufmgr bufmgr = bo->bufmgr;
277 if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags)) {
278 if (bufmgr->backend->bo_unlock) {
279 /* use backend unlock */
280 bufmgr->backend->bo_unlock(bo);
282 TBM_LOG("[libtbm:%d] "
283 "error %s:%d no backend unlock functions\n",
284 getpid(), __FUNCTION__, __LINE__);
287 /* use tizen global unlock */
288 _tgl_unlock(bufmgr->lock_fd, bo->tgl_key);
292 static int _tbm_bo_init_state(tbm_bo bo, int opt)
294 tbm_bufmgr bufmgr = bo->bufmgr;
295 tbm_bo_cache_state cache_state;
297 if (bo->tgl_key == INITIAL_KEY)
298 bo->tgl_key = bufmgr->backend->bo_get_global_key(bo);
300 if (!bo->default_handle.u32)
301 bo->default_handle = bufmgr->backend->bo_get_handle(bo, TBM_DEVICE_DEFAULT);
303 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
307 case CACHE_OP_CREATE: /*Create */
309 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
311 cache_state.data.isCacheable = BO_IS_CACHEABLE(bo);
312 cache_state.data.isDirtied = DEVICE_NONE;
313 cache_state.data.isCached = 0;
314 cache_state.data.cntFlush = 0;
316 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, cache_state.val);
318 case CACHE_OP_IMPORT: /*Import */
320 _tgl_init(bufmgr->lock_fd, bo->tgl_key);
329 static void _tbm_bo_destroy_state(tbm_bo bo)
331 tbm_bufmgr bufmgr = bo->bufmgr;
333 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
335 _tgl_destroy(bufmgr->lock_fd, bo->tgl_key);
338 static int _tbm_bo_set_state(tbm_bo bo, int device, int opt)
340 tbm_bufmgr bufmgr = bo->bufmgr;
342 unsigned short cntFlush = 0;
343 unsigned int is_locked;
345 RETURN_VAL_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
347 /* get cache state of a bo */
348 bo->cache_state.val = _tgl_get_data(bufmgr->lock_fd, bo->tgl_key, &is_locked);
350 if (!bo->cache_state.data.isCacheable)
353 /* get global cache flush count */
354 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
356 if (DEVICE_IS_CACHE_AWARE(device)) {
357 if (bo->cache_state.data.isDirtied == DEVICE_CO &&
358 bo->cache_state.data.isCached)
359 need_flush = TBM_CACHE_INV;
361 bo->cache_state.data.isCached = 1;
362 if (opt & TBM_OPTION_WRITE)
363 bo->cache_state.data.isDirtied = DEVICE_CA;
365 if (bo->cache_state.data.isDirtied != DEVICE_CA)
366 bo->cache_state.data.isDirtied = DEVICE_NONE;
369 if (bo->cache_state.data.isDirtied == DEVICE_CA &&
370 bo->cache_state.data.isCached &&
371 bo->cache_state.data.cntFlush == cntFlush)
372 need_flush = TBM_CACHE_CLN | TBM_CACHE_ALL;
374 if (opt & TBM_OPTION_WRITE)
375 bo->cache_state.data.isDirtied = DEVICE_CO;
377 if (bo->cache_state.data.isDirtied != DEVICE_CO)
378 bo->cache_state.data.isDirtied = DEVICE_NONE;
383 /* set global cache flush count */
384 if (need_flush & TBM_CACHE_ALL)
385 _tgl_set_data(bufmgr->lock_fd, GLOBAL_KEY, (unsigned int)(++cntFlush));
387 /* call backend cache flush */
388 bufmgr->backend->bo_cache_flush(bo, need_flush);
390 DBG("[libtbm:%d] \tcache(%d,%d,%d)....flush:0x%x, cntFlush(%d)\n",
392 bo->cache_state.data.isCacheable,
393 bo->cache_state.data.isCached,
394 bo->cache_state.data.isDirtied,
402 static void _tbm_bo_save_state(tbm_bo bo)
404 tbm_bufmgr bufmgr = bo->bufmgr;
405 unsigned short cntFlush = 0;
407 RETURN_CHECK_FLAG(TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags));
409 /* get global cache flush count */
410 cntFlush = (unsigned short)_tgl_get_data(bufmgr->lock_fd, GLOBAL_KEY, NULL);
412 /* save global cache flush count */
413 bo->cache_state.data.cntFlush = cntFlush;
414 _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, bo->cache_state.val);
417 static int _tbm_bo_lock(tbm_bo bo, int device, int opt)
419 tbm_bufmgr bufmgr = NULL;
428 /* do not try to lock the bo */
429 if (bufmgr->lock_type == LOCK_TRY_NEVER)
432 if (bo->lock_cnt < 0) {
433 TBM_LOG("[libtbm:%d] "
434 "error %s:%d bo:%p(%d) LOCK_CNT=%d\n",
435 getpid(), __FUNCTION__, __LINE__, bo, bo->tgl_key, bo->lock_cnt);
439 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
440 if (bo->lock_cnt == 0) {
441 pthread_mutex_unlock(&bufmgr->lock);
442 ret = _bo_lock(bo, device, opt);
443 pthread_mutex_lock(&bufmgr->lock);
448 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
449 pthread_mutex_unlock(&bufmgr->lock);
450 ret = _bo_lock(bo, device, opt);
451 pthread_mutex_lock(&bufmgr->lock);
455 TBM_LOG("[libtbm:%d] "
456 "error %s:%d bo:%p lock_type is wrong.\n",
457 getpid(), __FUNCTION__, __LINE__, bo);
460 DBG_LOCK("[libtbm:%d] >> LOCK bo:%p(%d, %d->%d)\n", getpid(),
461 bo, bo->tgl_key, old, bo->lock_cnt);
466 static void _tbm_bo_unlock(tbm_bo bo)
468 tbm_bufmgr bufmgr = NULL;
477 /* do not try to unlock the bo */
478 if (bufmgr->lock_type == LOCK_TRY_NEVER)
482 if (bufmgr->lock_type == LOCK_TRY_ONCE) {
483 if (bo->lock_cnt > 0) {
485 if (bo->lock_cnt == 0)
488 } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
489 if (bo->lock_cnt > 0) {
494 TBM_LOG("[libtbm:%d] "
495 "error %s:%d bo:%p lock_type is wrong.\n",
496 getpid(), __FUNCTION__, __LINE__, bo);
499 if (bo->lock_cnt < 0)
502 DBG_LOCK("[libtbm:%d] << unlock bo:%p(%d, %d->%d)\n", getpid(),
503 bo, bo->tgl_key, old, bo->lock_cnt);
506 static int _tbm_bo_is_valid(tbm_bo bo)
508 tbm_bo old_data = NULL, tmp = NULL;;
513 if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
514 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
523 static void _tbm_bo_ref(tbm_bo bo)
528 static void _tbm_bo_unref(tbm_bo bo)
530 tbm_bufmgr bufmgr = bo->bufmgr;
531 tbm_user_data *old_data = NULL, *tmp = NULL;
533 if (bo->ref_cnt <= 0)
537 if (bo->ref_cnt == 0) {
538 /* destory the user_data_list */
539 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
540 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
541 DBG("[libtbm:%d] free user_data \n",
543 user_data_delete(old_data);
547 if (bo->lock_cnt > 0) {
548 TBM_LOG("[libtbm:%d] "
549 "error %s:%d lock_cnt:%d\n",
550 getpid(), __FUNCTION__, __LINE__, bo->lock_cnt);
554 /* Destroy Global Lock */
555 _tbm_bo_destroy_state(bo);
557 /* call the bo_free */
558 bufmgr->backend->bo_free(bo);
561 LIST_DEL(&bo->item_link);
568 static int _tbm_bufmgr_init_state(tbm_bufmgr bufmgr)
570 RETURN_VAL_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
572 bufmgr->lock_fd = open(tgl_devfile, O_RDWR);
574 if (bufmgr->lock_fd < 0) {
575 bufmgr->lock_fd = open(tgl_devfile1, O_RDWR);
576 if (bufmgr->lock_fd < 0) {
578 TBM_LOG("[libtbm:%d] "
579 "error: Fail to open global_lock:%s\n",
580 getpid(), tgl_devfile);
585 if (!_tgl_init(bufmgr->lock_fd, GLOBAL_KEY)) {
586 TBM_LOG("[libtbm:%d] "
587 "error: Fail to initialize the tgl\n",
595 static void _tbm_bufmgr_destroy_state(tbm_bufmgr bufmgr)
597 RETURN_CHECK_FLAG(TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
599 close(bufmgr->lock_fd);
602 static int _check_version(TBMModuleVersionInfo * data)
607 abimaj = GET_ABI_MAJOR(data->abiversion);
608 abimin = GET_ABI_MINOR(data->abiversion);
611 "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
612 getpid(), data->modname ? data->modname : "UNKNOWN!",
613 data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
615 vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
616 vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
619 "TBM ABI version %d.%d\n",
620 getpid(), vermaj, vermin);
622 if (abimaj != vermaj) {
623 TBM_LOG("[libtbm:%d] "
624 "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
625 getpid(), abimaj, vermaj);
627 } else if (abimin > vermin) {
628 TBM_LOG("[libtbm:%d] "
629 "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
630 getpid(), abimin, vermin);
636 static int _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
638 char path[PATH_MAX] = { 0, };
639 TBMModuleData *initdata = NULL;
642 snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
644 module_data = dlopen(path, RTLD_LAZY);
646 TBM_LOG("[libtbm:%d] "
647 "failed to load module: %s(%s)\n",
648 getpid(), dlerror(), file);
652 initdata = dlsym(module_data, "tbmModuleData");
655 TBMModuleVersionInfo *vers;
657 vers = initdata->vers;
658 init = initdata->init;
661 if (!_check_version(vers)) {
662 dlclose(module_data);
666 TBM_LOG("[libtbm:%d] "
667 "Error: module does not supply version information.\n",
670 dlclose(module_data);
675 if (!init(bufmgr, fd)) {
676 TBM_LOG("[libtbm:%d] "
677 "Fail to init module(%s)\n",
679 dlclose(module_data);
683 if (!bufmgr->backend || !bufmgr->backend->priv) {
684 TBM_LOG("[libtbm:%d] "
685 "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
687 dlclose(module_data);
691 TBM_LOG("[libtbm:%d] "
692 "Error: module does not supply init symbol.\n",
694 dlclose(module_data);
698 TBM_LOG("[libtbm:%d] "
699 "Error: module does not have data object.\n",
701 dlclose(module_data);
705 bufmgr->module_data = module_data;
708 "Success to load module(%s)\n",
714 static int _tbm_load_module(tbm_bufmgr bufmgr, int fd)
716 struct dirent **namelist;
717 const char *p = NULL;
721 /* load bufmgr priv from default lib */
722 ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
724 /* load bufmgr priv from configured path */
726 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
728 TBM_LOG("[libtbm:%d] "
730 getpid(), BUFMGR_MODULE_DIR);
733 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
734 p = strstr(namelist[n]->d_name, SUFFIX_LIB);
736 if (!strcmp(p, SUFFIX_LIB))
737 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
749 tbm_bufmgr tbm_bufmgr_init(int fd)
753 int backend_flag = 0;
755 pthread_mutex_lock(&gLock);
758 env = getenv("GEM_DEBUG");
761 TBM_LOG("GEM_DEBUG=%s\n", env);
766 /* initialize buffer manager */
768 DBG("[libtbm:%d] use previous gBufMgr\n", getpid());
769 if (!gBufMgr->fd_flag) {
771 if (dup2(gBufMgr->fd, fd) < 0) {
772 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
773 TBM_LOG("[libtbm:%d] Fail to duplicate(dup2) the drm fd\n",
775 pthread_mutex_unlock(&gLock);
778 DBG("[libtbm:%d] duplicate the drm_fd(%d), new drm_fd(%d).\n",
779 getpid(), gBufMgr->fd, fd);
782 gBufMgr->ref_count++;
784 DBG("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
785 getpid(), gBufMgr->fd, gBufMgr->ref_count);
786 pthread_mutex_unlock(&gLock);
794 DBG("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
796 /* allocate bufmgr */
797 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
799 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
800 pthread_mutex_unlock(&gLock);
804 gBufMgr->fd_flag = fd_flag;
809 gBufMgr->fd = dup(fd);
810 if (gBufMgr->fd < 0) {
811 _tbm_set_last_result(TBM_BO_ERROR_DUP_FD_FAILED);
812 TBM_LOG("[libtbm:%d] Fail to duplicate(dup) the drm fd\n",
816 pthread_mutex_unlock(&gLock);
819 DBG("[libtbm:%d] duplicate the drm_fd(%d), bufmgr use fd(%d).\n",
820 getpid(), fd, gBufMgr->fd);
823 /* load bufmgr priv from env */
824 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
825 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
826 TBM_LOG("[libtbm:%d] " "error : Fail to load bufmgr backend\n", getpid());
833 pthread_mutex_unlock(&gLock);
836 backend_flag = gBufMgr->backend->flags;
837 /* log for tbm backend_flag */
838 DBG("[libtbm:%d] ", getpid());
840 if (backend_flag & TBM_CACHE_CTRL_BACKEND) {
847 if (backend_flag & TBM_LOCK_CTRL_BACKEND) {
856 gBufMgr->ref_count = 1;
858 DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
859 getpid(), gBufMgr->ref_count);
861 if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
862 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
863 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
864 tbm_backend_free(gBufMgr->backend);
865 dlclose(gBufMgr->module_data);
872 pthread_mutex_unlock(&gLock);
876 /* intialize the tizen global status */
877 if (!_tbm_bufmgr_init_state(gBufMgr)) {
878 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
879 TBM_LOG("[libtbm:%d] " "error: Fail to init state\n", getpid());
880 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
881 tbm_backend_free(gBufMgr->backend);
882 pthread_mutex_destroy(&gBufMgr->lock);
883 dlclose(gBufMgr->module_data);
890 pthread_mutex_unlock(&gLock);
894 /* setup the lock_type */
895 env = getenv("BUFMGR_LOCK_TYPE");
896 if (env && !strcmp(env, "always"))
897 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
898 else if (env && !strcmp(env, "none"))
899 gBufMgr->lock_type = LOCK_TRY_NEVER;
900 else if (env && !strcmp(env, "once"))
901 gBufMgr->lock_type = LOCK_TRY_ONCE;
903 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
905 DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
906 getpid(), env ? env : "default:once");
908 /* setup the map_cache */
909 env = getenv("BUFMGR_MAP_CACHE");
910 if (env && !strcmp(env, "false"))
911 gBufMgr->use_map_cache = 0;
913 gBufMgr->use_map_cache = 1;
914 DBG("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n",
915 getpid(), env ? env : "default:true");
917 /* intialize bo_list */
918 LIST_INITHEAD(&gBufMgr->bo_list);
920 /* intialize surf_list */
921 LIST_INITHEAD(&gBufMgr->surf_list);
923 pthread_mutex_unlock(&gLock);
927 void tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
929 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
934 tbm_surface_h surf = NULL;
935 tbm_surface_h tmp_surf = NULL;
937 pthread_mutex_lock(&gLock);
940 if (bufmgr->ref_count > 0) {
941 TBM_LOG("[libtbm:%d] "
942 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
943 getpid(), bufmgr, bufmgr->ref_count);
944 pthread_mutex_unlock(&gLock);
948 /* destroy bo_list */
949 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
950 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
951 TBM_LOG("[libtbm:%d] "
952 "Un-freed bo(%p, ref:%d) \n",
953 getpid(), bo, bo->ref_cnt);
959 /* destroy surf_list */
960 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
961 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
962 TBM_LOG("[libtbm:%d] "
963 "Destroy surf(%p) \n",
965 tbm_surface_destroy(surf);
969 /* destroy the tizen global status */
970 _tbm_bufmgr_destroy_state(bufmgr);
972 /* destroy bufmgr priv */
973 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
974 bufmgr->backend->priv = NULL;
975 tbm_backend_free(bufmgr->backend);
976 bufmgr->backend = NULL;
978 pthread_mutex_destroy(&bufmgr->lock);
981 "tizen bufmgr destroy: bufmgr:%p\n",
984 dlclose(bufmgr->module_data);
993 pthread_mutex_unlock(&gLock);
996 int tbm_bo_size(tbm_bo bo)
998 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1000 tbm_bufmgr bufmgr = bo->bufmgr;
1003 pthread_mutex_lock(&bufmgr->lock);
1005 size = bufmgr->backend->bo_size(bo);
1007 pthread_mutex_unlock(&bufmgr->lock);
1012 tbm_bo tbm_bo_ref(tbm_bo bo)
1014 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
1016 tbm_bufmgr bufmgr = bo->bufmgr;
1018 pthread_mutex_lock(&bufmgr->lock);
1022 pthread_mutex_unlock(&bufmgr->lock);
1027 void tbm_bo_unref(tbm_bo bo)
1029 TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
1031 tbm_bufmgr bufmgr = bo->bufmgr;
1033 pthread_mutex_lock(&bufmgr->lock);
1037 pthread_mutex_unlock(&bufmgr->lock);
1040 tbm_bo tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
1042 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1045 void *bo_priv = NULL;
1047 bo = calloc(1, sizeof(struct _tbm_bo));
1049 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
1053 bo->bufmgr = bufmgr;
1055 pthread_mutex_lock(&bufmgr->lock);
1057 bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
1059 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
1061 pthread_mutex_unlock(&bufmgr->lock);
1067 bo->tgl_key = INITIAL_KEY;
1069 bo->default_handle.u32 = 0;
1072 if (!_tbm_bo_init_state(bo, CACHE_OP_CREATE)) {
1073 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1075 pthread_mutex_unlock(&bufmgr->lock);
1079 LIST_INITHEAD(&bo->user_data_list);
1081 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1083 pthread_mutex_unlock(&bufmgr->lock);
1088 tbm_bo tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
1090 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1095 void *bo_priv = NULL;
1097 pthread_mutex_lock(&bufmgr->lock);
1099 /* find bo in list */
1100 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1101 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1102 if (bo2->tgl_key == key) {
1104 "find bo(%p, ref:%d key:%d) in list \n",
1105 getpid(), bo2, bo2->ref_cnt, bo2->tgl_key);
1108 pthread_mutex_unlock(&bufmgr->lock);
1114 bo = calloc(1, sizeof(struct _tbm_bo));
1116 pthread_mutex_unlock(&bufmgr->lock);
1120 bo->bufmgr = bufmgr;
1122 bo_priv = bufmgr->backend->bo_import(bo, key);
1124 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
1126 pthread_mutex_unlock(&bufmgr->lock);
1131 bo->tgl_key = INITIAL_KEY;
1133 bo->default_handle.u32 = 0;
1135 if (bufmgr->backend->bo_get_flags)
1136 bo->flags = bufmgr->backend->bo_get_flags(bo);
1138 bo->flags = TBM_BO_DEFAULT;
1141 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1142 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1144 pthread_mutex_unlock(&bufmgr->lock);
1148 LIST_INITHEAD(&bo->user_data_list);
1150 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1152 pthread_mutex_unlock(&bufmgr->lock);
1157 tbm_bo tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1159 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1164 void *bo_priv = NULL;
1165 tbm_bo_handle default_handle;
1167 pthread_mutex_lock(&bufmgr->lock);
1169 default_handle = bufmgr->backend->fd_to_handle(bufmgr, fd, TBM_DEVICE_DEFAULT);
1171 /* find bo in list */
1172 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1173 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
1174 if (bo2->default_handle.u32 == default_handle.u32) {
1176 "find bo(%p, ref:%d handle:%d) in list \n",
1177 getpid(), bo2, bo2->ref_cnt, bo2->default_handle.u32);
1180 pthread_mutex_unlock(&bufmgr->lock);
1186 bo = calloc(1, sizeof(struct _tbm_bo));
1188 pthread_mutex_unlock(&bufmgr->lock);
1192 bo->bufmgr = bufmgr;
1194 bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1196 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1198 pthread_mutex_unlock(&bufmgr->lock);
1203 bo->tgl_key = INITIAL_KEY;
1205 bo->default_handle.u32 = 0;
1207 if (bufmgr->backend->bo_get_flags)
1208 bo->flags = bufmgr->backend->bo_get_flags(bo);
1210 bo->flags = TBM_BO_DEFAULT;
1213 if (!_tbm_bo_init_state(bo, CACHE_OP_IMPORT)) {
1214 _tbm_set_last_result(TBM_BO_ERROR_INIT_STATE_FAILED);
1216 pthread_mutex_unlock(&bufmgr->lock);
1220 LIST_INITHEAD(&bo->user_data_list);
1222 LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1224 pthread_mutex_unlock(&bufmgr->lock);
1229 tbm_key tbm_bo_export(tbm_bo bo)
1231 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1236 bufmgr = bo->bufmgr;
1238 pthread_mutex_lock(&bufmgr->lock);
1239 ret = bufmgr->backend->bo_export(bo);
1241 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1242 pthread_mutex_unlock(&bufmgr->lock);
1245 pthread_mutex_unlock(&bufmgr->lock);
1250 tbm_fd tbm_bo_export_fd(tbm_bo bo)
1252 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1257 bufmgr = bo->bufmgr;
1259 pthread_mutex_lock(&bufmgr->lock);
1260 ret = bufmgr->backend->bo_export_fd(bo);
1262 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1263 pthread_mutex_unlock(&bufmgr->lock);
1266 pthread_mutex_unlock(&bufmgr->lock);
1271 tbm_bo_handle tbm_bo_get_handle(tbm_bo bo, int device)
1273 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1276 tbm_bo_handle bo_handle;
1278 bufmgr = bo->bufmgr;
1280 pthread_mutex_lock(&bufmgr->lock);
1281 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1282 if (bo_handle.ptr == NULL) {
1283 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1284 pthread_mutex_unlock(&bufmgr->lock);
1285 return (tbm_bo_handle) NULL;
1287 pthread_mutex_unlock(&bufmgr->lock);
1292 tbm_bo_handle tbm_bo_map(tbm_bo bo, int device, int opt)
1294 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
1297 tbm_bo_handle bo_handle;
1299 bufmgr = bo->bufmgr;
1301 pthread_mutex_lock(&bufmgr->lock);
1303 bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1305 if (!_tbm_bo_lock(bo, device, opt)) {
1306 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1307 TBM_LOG("[libtbm:%d] "
1308 "error %s:%d fail to lock bo:%p)\n",
1309 getpid(), __FUNCTION__, __LINE__, bo);
1310 pthread_mutex_unlock(&bufmgr->lock);
1311 return (tbm_bo_handle) NULL;
1314 bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1315 if (bo_handle.ptr == NULL) {
1316 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1317 TBM_LOG("[libtbm:%d] "
1318 "error %s:%d fail to map bo:%p\n",
1319 getpid(), __FUNCTION__, __LINE__, bo);
1322 pthread_mutex_unlock(&bufmgr->lock);
1323 return (tbm_bo_handle) NULL;
1326 if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1327 _tbm_bo_set_state(bo, device, opt);
1329 /* increase the map_count */
1332 pthread_mutex_unlock(&bufmgr->lock);
1337 int tbm_bo_unmap(tbm_bo bo)
1339 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1344 bufmgr = bo->bufmgr;
1346 pthread_mutex_lock(&bufmgr->lock);
1348 ret = bufmgr->backend->bo_unmap(bo);
1351 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1352 pthread_mutex_unlock(&bufmgr->lock);
1356 /* decrease the map_count */
1359 if (bo->map_cnt == 0)
1360 _tbm_bo_save_state(bo);
1364 pthread_mutex_unlock(&bufmgr->lock);
1369 int tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1371 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1372 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1375 unsigned int tmp_key;
1376 tbm_bo_handle tmp_defualt_handle;
1378 pthread_mutex_lock(&bo1->bufmgr->lock);
1380 if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1381 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1382 pthread_mutex_unlock(&bo1->bufmgr->lock);
1386 tmp_key = bo1->tgl_key;
1387 bo1->tgl_key = bo2->tgl_key;
1388 bo2->tgl_key = tmp_key;
1390 tmp_defualt_handle = bo1->default_handle;
1391 bo1->default_handle = bo2->default_handle;
1392 bo2->default_handle = tmp_defualt_handle;
1395 bo1->priv = bo2->priv;
1398 pthread_mutex_unlock(&bo1->bufmgr->lock);
1403 int tbm_bo_locked(tbm_bo bo)
1405 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1409 bufmgr = bo->bufmgr;
1411 if (bufmgr->lock_type == LOCK_TRY_NEVER)
1414 pthread_mutex_lock(&bufmgr->lock);
1416 if (bo->lock_cnt > 0) {
1417 pthread_mutex_unlock(&bufmgr->lock);
1421 pthread_mutex_unlock(&bufmgr->lock);
1426 int tbm_bo_add_user_data(tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1428 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1430 tbm_user_data *data;
1432 /* check if the data according to the key exist if so, return false. */
1433 data = user_data_lookup(&bo->user_data_list, key);
1435 TBM_LOG("[libtbm:%d] "
1436 "waring: %s:%d user data already exist. key:%ld\n",
1437 getpid(), __FUNCTION__, __LINE__, key);
1441 data = user_data_create(key, data_free_func);
1445 LIST_ADD(&data->item_link, &bo->user_data_list);
1450 int tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1452 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1454 tbm_user_data *old_data;
1456 if (LIST_IS_EMPTY(&bo->user_data_list))
1459 old_data = user_data_lookup(&bo->user_data_list, key);
1463 if (old_data->data && old_data->free_func)
1464 old_data->free_func(old_data->data);
1466 old_data->data = data;
1471 int tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1473 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1475 tbm_user_data *old_data;
1477 if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1480 old_data = user_data_lookup(&bo->user_data_list, key);
1486 *data = old_data->data;
1491 int tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1493 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1495 tbm_user_data *old_data = (void *)0;
1497 if (LIST_IS_EMPTY(&bo->user_data_list))
1500 old_data = user_data_lookup(&bo->user_data_list, key);
1504 user_data_delete(old_data);
1509 tbm_error_e tbm_get_last_error(void)
1511 return tbm_last_error;
1514 unsigned int tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1516 TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1518 unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1520 if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1521 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1523 if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1524 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1529 int tbm_bo_get_flags(tbm_bo bo)
1531 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1536 void tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1538 TBM_RETURN_IF_FAIL(bufmgr != NULL);
1539 tbm_bo bo = NULL, tmp_bo = NULL;
1542 tbm_surface_h surf = NULL, tmp_surf = NULL;
1545 char app_name[255] = {0,};
1546 unsigned int pid = 0;
1548 pthread_mutex_lock(&gLock);
1551 _tbm_util_get_appname_from_pid(getpid(), app_name);
1552 _tbm_util_get_appname_brief(app_name);
1553 TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n", app_name, getpid());
1554 memset(app_name, 0x0, 255*sizeof(char));
1556 TBM_DEBUG("[tbm_surface information]\n");
1557 TBM_DEBUG("no surface refcnt width height bpp size num_bos num_planes flags format app_name\n");
1558 /* show the tbm_surface information in surf_list */
1559 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1560 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1561 pid = _tbm_surface_internal_get_debug_pid(surf);
1563 /* if pid is null, set the self_pid */
1567 _tbm_util_get_appname_from_pid(pid, app_name);
1568 _tbm_util_get_appname_brief(app_name);
1570 TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1577 surf->info.size/1024,
1581 _tbm_surface_internal_format_to_str(surf->info.format),
1584 for (i = 0; i < surf->num_bos; i++) {
1585 TBM_DEBUG(" bo:%-12p(key:%2d) %-26d%-10d\n",
1587 surf->bos[i]->tgl_key,
1588 surf->bos[i]->ref_cnt,
1589 tbm_bo_size(surf->bos[i])/1024);
1592 memset(app_name, 0x0, 255*sizeof(char));
1595 TBM_DEBUG("no tbm_surfaces.\n");
1599 TBM_DEBUG("[tbm_bo information]\n");
1600 TBM_DEBUG("no bo refcnt size lock_cnt map_cnt cache_state flags surface\n");
1602 /* show the tbm_bo information in bo_list */
1603 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1604 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1605 TBM_DEBUG("%-4d%-11p(key:%2d) %-6d%-12d%-9d%-9d%-10d%-4d%-11p\n",
1610 tbm_bo_size(bo)/1024,
1613 bo->cache_state.val,
1618 TBM_DEBUG("no tbm_bos.\n");
1622 TBM_DEBUG("===============================================================\n");
1624 pthread_mutex_unlock(&gLock);
1628 void tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1630 TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1631 TBM_LOG("Not implemented yet.\n");
1634 /* internal function */
1635 int _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1637 TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1639 bo->surface = surface;