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"
39 #include <sys/resource.h>
50 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
51 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
52 static double scale_factor = 0;
53 static void _tbm_bufmgr_mutex_unlock(void);
55 //#define TBM_BUFMGR_INIT_TIME
57 #define PREFIX_LIB "libtbm_"
58 #define SUFFIX_LIB ".so"
59 #define DEFAULT_LIB PREFIX_LIB"default"SUFFIX_LIB
61 /* values to indicate unspecified fields in XF86ModReqInfo. */
62 #define MAJOR_UNSPEC 0xFF
63 #define MINOR_UNSPEC 0xFF
64 #define PATCH_UNSPEC 0xFFFF
65 #define ABI_VERS_UNSPEC 0xFFFFFFFF
67 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
68 ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
69 #define GET_MODULE_MAJOR_VERSION(vers) (((vers) >> 24) & 0xFF)
70 #define GET_MODULE_MINOR_VERSION(vers) (((vers) >> 16) & 0xFF)
71 #define GET_MODULE_PATCHLEVEL(vers) ((vers) & 0xFFFF)
73 #define MAX_SIZE_N(dest) (sizeof(dest) - strlen(dest) - 1)
76 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
78 TBM_ERR("'%s' failed.\n", #cond);\
79 _tbm_bufmgr_mutex_unlock();\
84 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
86 TBM_ERR("'%s' failed.\n", #cond);\
87 _tbm_bufmgr_mutex_unlock();\
94 _tbm_bufmgr_mutex_init(void)
96 static bool tbm_bufmgr_mutex_init = false;
98 if (tbm_bufmgr_mutex_init)
101 if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
102 TBM_ERR("fail: Cannot pthread_mutex_init for tbm_bufmgr_lock.\n");
106 tbm_bufmgr_mutex_init = true;
112 _tbm_bufmgr_mutex_lock(void)
114 if (!_tbm_bufmgr_mutex_init()) {
115 TBM_ERR("fail: _tbm_bufmgr_mutex_init()\n");
119 pthread_mutex_lock(&tbm_bufmgr_lock);
123 _tbm_bufmgr_mutex_unlock(void)
125 pthread_mutex_unlock(&tbm_bufmgr_lock);
129 _tbm_util_get_max_surface_size(int *w, int *h)
131 tbm_surface_info_s info;
132 tbm_surface_h surface = NULL;
138 if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
141 LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
142 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
146 if (*h < info.height)
155 _tbm_util_get_appname_brief(char *brief)
159 char temp[255] = {0,};
160 char *saveptr = NULL;
162 token = strtok_r(brief, delim, &saveptr);
164 while (token != NULL) {
165 memset(temp, 0x00, 255 * sizeof(char));
166 strncpy(temp, token, 254 * sizeof(char));
167 token = strtok_r(NULL, delim, &saveptr);
170 snprintf(brief, sizeof(temp), "%s", temp);
174 _tbm_util_get_appname_from_pid(long pid, char *str)
176 char fn_cmdline[255] = {0, }, cmdline[255];
180 snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
182 fp = fopen(fn_cmdline, "r");
184 TBM_ERR("cannot file open %s\n", fn_cmdline);
188 if (!fgets(cmdline, 255, fp)) {
189 TBM_ERR("fail to get appname for pid(%ld)\n", pid);
196 len = strlen(cmdline);
198 memset(cmdline, 0x00, 255);
202 snprintf(str, sizeof(cmdline), "%s", cmdline);
206 _check_version(TBMModuleVersionInfo *data)
211 abimaj = GET_ABI_MAJOR(data->abiversion);
212 abimin = GET_ABI_MINOR(data->abiversion);
214 TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
215 data->modname ? data->modname : "UNKNOWN!",
216 data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
218 vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
219 vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
221 TBM_DBG("TBM ABI version %d.%d\n",
224 if (abimaj != vermaj) {
225 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
228 } else if (abimin > vermin) {
229 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
238 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
240 char path[PATH_MAX] = {0, };
241 TBMModuleVersionInfo *vers;
242 TBMModuleData *initdata;
246 snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
248 module_data = dlopen(path, RTLD_LAZY);
250 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
254 initdata = dlsym(module_data, "tbmModuleData");
256 TBM_ERR("Error: module does not have data object.\n");
260 vers = initdata->vers;
262 TBM_ERR("Error: module does not supply version information.\n");
266 init = initdata->init;
268 TBM_ERR("Error: module does not supply init symbol.\n");
272 if (!_check_version(vers)) {
273 TBM_ERR("Fail to check version.\n");
277 if (!init(bufmgr, fd)) {
278 TBM_ERR("Fail to init module(%s)\n", file);
282 if (!bufmgr->backend || !bufmgr->backend->priv) {
283 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
287 bufmgr->module_data = module_data;
289 TBM_DBG("Success to load module(%s)\n", file);
294 dlclose(module_data);
299 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
301 struct dirent **namelist;
304 /* load bufmgr priv from default lib */
305 if (_tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB))
308 /* load bufmgr priv from configured path */
309 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
311 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
316 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
317 const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
319 if (p && !strcmp(p, SUFFIX_LIB))
320 ret = _tbm_bufmgr_load_module(bufmgr, fd,
321 namelist[n]->d_name);
334 _tbm_bufmgr_init(int fd, int server)
336 #ifdef TBM_BUFMGR_INIT_TIME
337 struct timeval start_tv, end_tv;
341 #ifdef TBM_BUFMGR_INIT_TIME
342 /* get the start tv */
343 gettimeofday(&start_tv, NULL);
346 /* LCOV_EXCL_START */
348 env = getenv("TBM_DLOG");
351 TBM_DBG("TBM_DLOG=%s\n", env);
357 env = getenv("TBM_TRACE");
359 trace_mask = atoi(env);
360 TBM_DBG("TBM_TRACE=%s\n", env);
365 pthread_mutex_lock(&gLock);
368 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
369 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
373 /* initialize buffer manager */
375 gBufMgr->ref_count++;
376 TBM_INFO("reuse tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
377 pthread_mutex_unlock(&gLock);
381 TBM_DBG("bufmgr init\n");
383 /* allocate bufmgr */
384 gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
386 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
387 pthread_mutex_unlock(&gLock);
393 /* set the display_server flag before loading the backend module */
395 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
396 gBufMgr->display_server = 1;
399 /* load bufmgr priv from env */
400 if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
401 TBM_ERR("error : Fail to load bufmgr backend\n");
404 pthread_mutex_unlock(&gLock);
410 gBufMgr->ref_count = 1;
412 TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
413 gBufMgr, gBufMgr->ref_count);
415 /* setup the bo_lock_type */
416 env = getenv("BUFMGR_LOCK_TYPE");
417 if (env && !strcmp(env, "always"))
418 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
419 else if (env && !strcmp(env, "none"))
420 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
421 else if (env && !strcmp(env, "once"))
422 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
424 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
426 TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
428 /* intialize bo_list */
429 LIST_INITHEAD(&gBufMgr->bo_list);
431 /* intialize surf_list */
432 LIST_INITHEAD(&gBufMgr->surf_list);
434 /* intialize surf_queue_list */
435 LIST_INITHEAD(&gBufMgr->surf_queue_list);
437 /* intialize debug_key_list */
438 LIST_INITHEAD(&gBufMgr->debug_key_list);
440 #ifdef TBM_BUFMGR_INIT_TIME
442 gettimeofday(&end_tv, NULL);
443 TBM_INFO("tbm_bufmgr_init time: %ld ms", ((end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000) - (start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000)));
446 pthread_mutex_unlock(&gLock);
452 tbm_bufmgr_init(int fd)
456 bufmgr = _tbm_bufmgr_init(fd, 0);
462 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
464 TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
466 _tbm_bufmgr_mutex_lock();
467 pthread_mutex_lock(&gLock);
470 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
471 pthread_mutex_unlock(&gLock);
472 _tbm_bufmgr_mutex_unlock();
477 if (bufmgr->ref_count > 0) {
478 TBM_INFO("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
479 pthread_mutex_unlock(&gLock);
480 _tbm_bufmgr_mutex_unlock();
484 /* destroy bo_list */
485 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
486 tbm_bo bo = NULL, tmp;
488 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
489 TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
492 LIST_DELINIT(&bufmgr->bo_list);
495 /* destroy surf_list */
496 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
497 tbm_surface_h surf = NULL, tmp;
499 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
500 TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
501 tbm_surface_destroy(surf);
503 LIST_DELINIT(&bufmgr->surf_list);
506 /* destroy bufmgr priv */
507 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
508 bufmgr->backend->priv = NULL;
509 tbm_backend_free(bufmgr->backend);
510 bufmgr->backend = NULL;
512 TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
514 dlclose(bufmgr->module_data);
522 pthread_mutex_unlock(&gLock);
523 _tbm_bufmgr_mutex_unlock();
527 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
529 unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
531 _tbm_bufmgr_mutex_lock();
533 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
534 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
536 capabilities = bufmgr->capabilities;
538 _tbm_bufmgr_mutex_unlock();
543 /* LCOV_EXCL_START */
545 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
547 char app_name[255] = {0,}, title[512] = {0,};
548 tbm_surface_debug_data *debug_old_data = NULL;
553 pthread_mutex_lock(&gLock);
555 if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
556 TBM_ERR("invalid bufmgr\n");
557 pthread_mutex_unlock(&gLock);
563 TBM_ERR("Fail to allocate the string.\n");
564 pthread_mutex_unlock(&gLock);
568 TBM_SNRPRINTF(str, len, c, "\n");
569 _tbm_util_get_appname_from_pid(getpid(), app_name);
570 _tbm_util_get_appname_brief(app_name);
571 TBM_SNRPRINTF(str, len, c, "============TBM DEBUG: %s(%d)===========================\n",
574 snprintf(title, 255, "%s", "no surface refcnt width height bpp size n_b n_p flags format app_name ");
576 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
577 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
578 strncat(title, " ", MAX_SIZE_N(title));
579 strncat(title, debug_old_data->key, MAX_SIZE_N(title));
583 TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
584 TBM_SNRPRINTF(str, len, c, "%s\n", title);
586 /* show the tbm_surface information in surf_list */
587 if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
588 tbm_surface_h surf = NULL;
591 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
592 char data[512] = {0,};
596 pid = _tbm_surface_internal_get_debug_pid(surf);
598 /* if pid is null, set the self_pid */
602 memset(app_name, 0x0, 255 * sizeof(char));
603 _tbm_util_get_appname_from_pid(pid, app_name);
604 _tbm_util_get_appname_brief(app_name);
606 snprintf(data, 255, "%-2d %-9p %-4d %-5u %-6u %-3u %-6u %-2d %-2d %-3d %-8s %-15s",
613 surf->info.size / 1024,
617 _tbm_surface_internal_format_to_str(surf->info.format) + 11,
620 if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
621 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
624 strncat(data, " ", MAX_SIZE_N(title));
626 value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
628 strncat(data, value, MAX_SIZE_N(title));
630 strncat(data, "none", MAX_SIZE_N(title));
633 TBM_SNRPRINTF(str, len, c, "%s\n", data);
635 for (i = 0; i < surf->num_bos; i++) {
636 TBM_SNRPRINTF(str, len, c, " bo:%-12p %-26d%-10d\n",
638 surf->bos[i]->ref_cnt,
639 bufmgr->backend->bo_size(surf->bos[i]) / 1024);
643 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
644 TBM_SNRPRINTF(str, len, c, "\n");
646 TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
647 TBM_SNRPRINTF(str, len, c, "no bo refcnt size lock_cnt map_cnt flags surface name\n");
649 /* show the tbm_bo information in bo_list */
650 if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
654 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
655 TBM_SNRPRINTF(str, len, c, "%-4d%-11p %-4d %-6d %-5d %-4u %-3d %-11p %-4d\n",
659 bufmgr->backend->bo_size(bo) / 1024,
664 bufmgr->backend->bo_export(bo));
667 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
668 TBM_SNRPRINTF(str, len, c, "\n");
670 TBM_SNRPRINTF(str, len, c, "===============================================================\n");
672 pthread_mutex_unlock(&gLock);
678 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
681 str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
689 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
691 _tbm_bufmgr_mutex_lock();
693 TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
694 TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
697 TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
701 _tbm_bufmgr_mutex_unlock();
705 tbm_bufmgr_debug_dump_set_scale(double scale)
707 pthread_mutex_lock(&gLock);
708 scale_factor = scale;
709 pthread_mutex_unlock(&gLock);
713 tbm_bufmgr_debug_get_ref_count(void)
715 return (gBufMgr) ? gBufMgr->ref_count : 0;
719 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
721 pthread_mutex_lock(&gLock);
724 TBM_DBG("count=%d onoff=%d\n", count, onoff);
726 tbm_surface_internal_dump_end();
731 TBM_ERR("path is null");
732 pthread_mutex_unlock(&gLock);
735 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
737 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
738 TBM_ERR("Fail to get tbm_surface size.\n");
739 pthread_mutex_unlock(&gLock);
743 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
749 pthread_mutex_unlock(&gLock);
754 tbm_bufmgr_debug_dump_all(char *path)
757 tbm_surface_h surface = NULL;
759 TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
760 TBM_DBG("path=%s\n", path);
762 pthread_mutex_lock(&gLock);
764 count = _tbm_util_get_max_surface_size(&w, &h);
766 TBM_ERR("No tbm_surface.\n");
767 pthread_mutex_unlock(&gLock);
771 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
774 LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
775 tbm_surface_internal_dump_buffer(surface, "dump_all");
777 tbm_surface_internal_dump_end();
779 pthread_mutex_unlock(&gLock);
784 /* internal function */
786 _tbm_bufmgr_get_bufmgr(void)
792 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
796 _tbm_bufmgr_mutex_lock();
798 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
800 if (!bufmgr->backend->bufmgr_bind_native_display) {
801 TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
802 bufmgr, native_display);
803 _tbm_bufmgr_mutex_unlock();
807 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
809 TBM_ERR("error: tbm_bufmgr(%p) native_display(%p)\n",
810 bufmgr, native_display);
811 _tbm_bufmgr_mutex_unlock();
815 TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
817 _tbm_bufmgr_mutex_unlock();
823 tbm_bufmgr_server_init(void)
827 bufmgr = _tbm_bufmgr_init(-1, 1);
833 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
835 TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
836 TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
838 gBufMgr->bo_lock_type = bo_lock_type;
840 TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
846 int tbm_bufmgr_get_fd_limit(void)
850 if (getrlimit(RLIMIT_NOFILE, &lim))
853 return (int)lim.rlim_cur;
856 tbm_bufmgr tbm_bufmgr_get(void)