use dlog default
[platform/core/uifw/libtbm.git] / src / tbm_bufmgr.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
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>
9
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:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
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.
29
30 **************************************************************************/
31
32 #include "config.h"
33
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_bufmgr_backend.h"
37 #include "list.h"
38
39 #include <sys/resource.h>
40
41 int trace_mask = 0;
42
43 #ifdef HAVE_DLOG
44 int bDlog;
45 #endif
46
47 tbm_bufmgr gBufMgr;
48 int b_dump_queue;
49
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 void _tbm_bufmgr_mutex_unlock(void);
54
55 //#define TBM_BUFMGR_INIT_TIME
56
57 #define PREFIX_LIB    "libtbm_"
58 #define SUFFIX_LIB    ".so"
59 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
60
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
66
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)
72
73 #define MAX_SIZE_N(dest)        (sizeof(dest) - strlen(dest) - 1)
74
75 /* check condition */
76 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
77         if (!(cond)) {\
78                 TBM_ERR("'%s' failed.\n", #cond);\
79                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
80                 _tbm_bufmgr_mutex_unlock();\
81                 return;\
82         } \
83 }
84
85 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
86         if (!(cond)) {\
87                 TBM_ERR("'%s' failed.\n", #cond);\
88                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
89                 _tbm_bufmgr_mutex_unlock();\
90                 return val;\
91         } \
92 }
93
94 /* LCOV_EXCL_START */
95
96 void
97 _tbm_bufmgr_mutex_lock(void)
98 {
99         pthread_mutex_lock(&tbm_bufmgr_lock);
100 }
101
102 void
103 _tbm_bufmgr_mutex_unlock(void)
104 {
105         pthread_mutex_unlock(&tbm_bufmgr_lock);
106 }
107
108 static int
109 _tbm_util_get_max_surface_size(int *w, int *h)
110 {
111         tbm_surface_info_s info;
112         tbm_surface_h surface = NULL;
113         int count = 0;
114
115         *w = 0;
116         *h = 0;
117
118         if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
119                 return count;
120
121         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
122                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
123                         count++;
124                         if (*w < info.width)
125                                 *w = info.width;
126                         if (*h < info.height)
127                                 *h = info.height;
128                 }
129         }
130
131         return count;
132 }
133
134 static void
135 _tbm_util_get_appname_brief(char *brief)
136 {
137         char delim[] = "/";
138         char *token = NULL;
139         char temp[255] = {0,};
140         char *saveptr = NULL;
141
142         token = strtok_r(brief, delim, &saveptr);
143
144         while (token != NULL) {
145                 memset(temp, 0x00, 255 * sizeof(char));
146                 strncpy(temp, token, 254 * sizeof(char));
147                 token = strtok_r(NULL, delim, &saveptr);
148         }
149
150         snprintf(brief, sizeof(temp), "%s", temp);
151 }
152
153 static void
154 _tbm_util_get_appname_from_pid(long pid, char *str)
155 {
156         char fn_cmdline[255] = {0, }, cmdline[255];
157         FILE *fp;
158         int len;
159
160         if (pid <= 0) return;
161
162         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
163
164         fp = fopen(fn_cmdline, "r");
165         if (fp == 0) {
166                 TBM_ERR("cannot file open %s\n", fn_cmdline);
167                 return;
168         }
169
170         if (!fgets(cmdline, 255, fp)) {
171                 TBM_ERR("fail to get appname for pid(%ld)\n", pid);
172                 fclose(fp);
173                 return;
174         }
175
176         fclose(fp);
177
178         len = strlen(cmdline);
179         if (len < 1)
180                 memset(cmdline, 0x00, 255);
181         else
182                 cmdline[len] = 0;
183
184         snprintf(str, sizeof(cmdline), "%s", cmdline);
185 }
186
187 static int
188 _check_version(TBMModuleVersionInfo *data)
189 {
190         int backend_module_major, backend_module_minor;
191         int tbm_backend_major, tbm_backend_minor;
192
193         backend_module_major = GET_ABI_MAJOR(data->abiversion);
194         backend_module_minor = GET_ABI_MINOR(data->abiversion);
195
196         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
197             data->modname ? data->modname : "UNKNOWN!",
198             data->vendor ? data->vendor : "UNKNOWN!", backend_module_major, backend_module_minor);
199
200         tbm_backend_major = GET_ABI_MAJOR(TBM_ABI_VERSION);
201         tbm_backend_minor = GET_ABI_MINOR(TBM_ABI_VERSION);
202
203         TBM_DBG("TBM ABI version %d.%d\n",
204             tbm_backend_major, tbm_backend_minor);
205
206         if (backend_module_major != tbm_backend_major) {
207                 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
208                         backend_module_major, tbm_backend_major);
209                 return 0;
210         } else if (backend_module_minor > tbm_backend_minor) {
211                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
212                         backend_module_minor, tbm_backend_minor);
213                 return 0;
214         }
215
216         return 1;
217 }
218
219 static int
220 _tbm_backend_check_bufmgr_func(tbm_backend_bufmgr_func *bufmgr_func)
221 {
222         TBM_RETURN_VAL_IF_FAIL(bufmgr_func, 0); /* mandatory symbol */
223         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_capabilities, 0); /* mandatory symbol */
224         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_bind_native_display, 0); /* mandatory symbol */
225         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_supported_formats, 0); /* mandatory symbol */
226         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_plane_data, 0); /* mandatory symbol */
227         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_alloc_bo, 0); /* mandatory symbol */
228         if (!bufmgr_func->bufmgr_alloc_bo_with_format)
229                 TBM_DBG("No bufmgr_func->bufmgr_alloc_bo_with_format.");
230         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_import_fd, 0); /* mandatory symbol */
231         if (!bufmgr_func->bufmgr_import_key)
232                 TBM_DBG("No bufmgr_func->bo_export_key.");
233
234         return 1;
235 }
236
237 static int
238 _tbm_backend_check_bufmgr_bo(tbm_backend_bo_func *bo_func)
239 {
240         TBM_RETURN_VAL_IF_FAIL(bo_func, 0); /* mandatory symbol */
241         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_free, 0); /* mandatory symbol */
242         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_size, 0); /* mandatory symbol */
243         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_memory_types, 0); /* mandatory symbol */
244         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_handle, 0); /* mandatory symbol */
245         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_map, 0); /* mandatory symbol */
246         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_unmap, 0); /* mandatory symbol */
247         if (!bo_func->bo_lock)
248                 TBM_DBG("No bo_func->bo_lock.");
249         if (!bo_func->bo_unlock)
250                 TBM_DBG("No bo_func->bo_unlock.");
251         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_export_fd, 0); /* mandatory symbol */
252         if (!bo_func->bo_export_key)
253                 TBM_INFO("No bo_func->bo_export_key.");
254
255         return 1;
256 }
257
258 static int
259 _tbm_backend_load_module(tbm_bufmgr bufmgr, const char *file)
260 {
261         char path[PATH_MAX] = {0, };
262         void *module_data = NULL;
263         tbm_backend_module *backend_module_data = NULL;
264         tbm_backend_bufmgr_data *bufmgr_data = NULL;
265         int backend_module_major, backend_module_minor;
266         int tbm_backend_major, tbm_backend_minor;
267         tbm_error_e error;
268
269         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
270
271         module_data = dlopen(path, RTLD_LAZY);
272         if (!module_data) {
273                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
274                 return 0;
275         }
276
277         backend_module_data = dlsym(module_data, "tbm_backend_module_data");
278         if (!backend_module_data) {
279                 TBM_ERR("Error: module does not have data object.\n");
280                 goto err;
281         }
282
283         tbm_backend_major = GET_ABI_MAJOR(TBM_BACKEND_ABI_LATEST_VERSION);
284         tbm_backend_minor = GET_ABI_MINOR(TBM_BACKEND_ABI_LATEST_VERSION);
285         TBM_INFO("TBM Backend ABI version %d.%d\n", tbm_backend_major, tbm_backend_minor);
286
287         backend_module_major = GET_ABI_MAJOR(backend_module_data->abi_version);
288         backend_module_minor = GET_ABI_MINOR(backend_module_data->abi_version);
289
290         TBM_INFO("TBM module %s: vendor=\"%s\" Backend ABI version=%d.%d\n",
291             backend_module_data->name ? backend_module_data->name : "UNKNOWN!",
292             backend_module_data->vendor ? backend_module_data->vendor : "UNKNOWN!",
293                 backend_module_major, backend_module_minor);
294
295         if (backend_module_major > tbm_backend_major) {
296                 TBM_ERR("TBM module ABI major ver(%d) is newer than the TBM's ver(%d)\n",
297                         backend_module_major, tbm_backend_major);
298                 goto err;
299         } else if (backend_module_minor > tbm_backend_minor) {
300                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
301                         backend_module_minor, tbm_backend_minor);
302                 goto err;
303         }
304
305         if (!backend_module_data->init) {
306                 TBM_ERR("Error: module does not supply init symbol.\n");
307                 goto err;
308         }
309
310         if (!backend_module_data->deinit)       {
311                 TBM_ERR("Error: module does not supply deinit symbol.\n");
312                 goto err;
313         }
314
315         bufmgr_data = backend_module_data->init(bufmgr, &error);
316         if (!bufmgr_data) {
317                 TBM_ERR("Fail to init module(%s)\n", file);
318                 goto err;
319         }
320
321         /* check the mandatory symbols of the backend module */
322         if (!_tbm_backend_check_bufmgr_func(bufmgr->bufmgr_func)) {
323                 TBM_ERR("Fail to check the bufmgr_func symboles.");
324                 goto err;
325         }
326
327         if (!_tbm_backend_check_bufmgr_bo(bufmgr->bo_func)) {
328                 TBM_ERR("Fail to check the bufmgr_bo symboles.");
329                 goto err;
330         }
331
332         /* get the capability */
333         bufmgr->capabilities = bufmgr->bufmgr_func->bufmgr_get_capabilities(bufmgr_data, &error);
334         if (bufmgr->capabilities == TBM_BUFMGR_CAPABILITY_NONE) {
335                 TBM_ERR("The capabilities of the backend module is TBM_BUFMGR_CAPABILITY_NONE.");
336                 TBM_ERR("TBM_BUFMGR_CAPABILITY_SHARE_FD is the essential capability.");
337                 goto err;
338         }
339
340         if (!(bufmgr->capabilities & TBM_BUFMGR_CAPABILITY_SHARE_FD)) {
341                 TBM_ERR("The capabilities of the backend module had no TBM_BUFMGR_CAPABILITY_SHARE_FD.");
342                 TBM_ERR("The tbm backend has to get TBM_BUFMGR_CAPABILITY_SHARE_FD. ");
343                 goto err;
344         }
345
346         bufmgr->module_data = module_data;
347         bufmgr->backend_module_data = backend_module_data;
348         bufmgr->bufmgr_data = bufmgr_data;
349
350         TBM_DBG("Success to load module(%s)\n", file);
351         TBM_STDOUT_INFO("Success to load module(%s)", file);
352
353         return 1;
354
355 err:
356         if (bufmgr_data)
357                 bufmgr->backend_module_data->deinit(bufmgr_data);
358         if (module_data)
359                 dlclose(module_data);
360
361         return 0;
362 }
363
364 static int
365 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
366 {
367         char path[PATH_MAX] = {0, };
368         TBMModuleVersionInfo *vers;
369         TBMModuleData *initdata;
370         ModuleInitProc init;
371         void *module_data;
372
373         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
374
375         module_data = dlopen(path, RTLD_LAZY);
376         if (!module_data) {
377                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
378                 return 0;
379         }
380
381         initdata = dlsym(module_data, "tbmModuleData");
382         if (!initdata) {
383                 TBM_ERR("Error: module does not have data object.\n");
384                 goto err;
385         }
386
387         vers = initdata->vers;
388         if (!vers) {
389                 TBM_ERR("Error: module does not supply version information.\n");
390                 goto err;
391         }
392
393         init = initdata->init;
394         if (!init) {
395                 TBM_ERR("Error: module does not supply init symbol.\n");
396                 goto err;
397         }
398
399         if (!_check_version(vers)) {
400                 TBM_ERR("Fail to check version.\n");
401                 goto err;
402         }
403
404         if (!init(bufmgr, fd)) {
405                 TBM_ERR("Fail to init module(%s)\n", file);
406                 goto err;
407         }
408
409         if (!bufmgr->backend || !bufmgr->backend->priv) {
410                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
411                 goto err;
412         }
413
414         bufmgr->module_data = module_data;
415
416         TBM_DBG("Success to load module(%s)\n", file);
417
418         return 1;
419
420 err:
421         dlclose(module_data);
422         return 0;
423 }
424
425 static int
426 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
427 {
428         struct dirent **namelist;
429         int ret = 0, n;
430
431         /* try to load the new backend module */
432         ret = _tbm_backend_load_module(bufmgr, DEFAULT_LIB);
433         if (ret)
434                 return 1;
435
436         /* try to load the old(deprecated) backend mdoule */
437         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
438         if (ret)
439                 return 1;
440
441         /* load bufmgr priv from configured path */
442         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
443         if (n < 0) {
444                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
445                 return 0;
446         }
447
448         while (n--) {
449                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
450                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
451
452                         if (p && !strcmp(p, SUFFIX_LIB)) {
453                                 ret = _tbm_backend_load_module(bufmgr, namelist[n]->d_name);
454                                 if (!ret)
455                                         ret = _tbm_bufmgr_load_module(bufmgr, fd,
456                                                                         namelist[n]->d_name);
457                         }
458                 }
459
460                 free(namelist[n]);
461         }
462
463         free(namelist);
464
465         return ret;
466 }
467 /* LCOV_EXCL_STOP */
468
469 static tbm_bufmgr
470 _tbm_bufmgr_init(int fd, int server)
471 {
472 #ifdef TBM_BUFMGR_INIT_TIME
473         struct timeval start_tv, end_tv;
474 #endif
475         char *env;
476
477 #ifdef TBM_BUFMGR_INIT_TIME
478         /* get the start tv */
479         gettimeofday(&start_tv, NULL);
480 #endif
481
482         bDlog = 1;
483
484         /* LCOV_EXCL_START */
485 #ifdef TRACE
486         env = getenv("TBM_TRACE");
487         if (env) {
488                 trace_mask = atoi(env);
489                 TBM_DBG("TBM_TRACE=%s\n", env);
490         } else
491                 trace_mask = 0;
492 #endif
493
494         pthread_mutex_lock(&gLock);
495
496         _tbm_set_last_result(TBM_ERROR_NONE);
497
498         if (fd >= 0) {
499                 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
500                 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
501         }
502
503
504         /* initialize buffer manager */
505         if (gBufMgr) {
506                 gBufMgr->ref_count++;
507                 TBM_DBG("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
508                 pthread_mutex_unlock(&gLock);
509                 return gBufMgr;
510         }
511
512         TBM_DBG("bufmgr init\n");
513
514         /* allocate bufmgr */
515         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
516         if (!gBufMgr) {
517                 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
518                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
519                 pthread_mutex_unlock(&gLock);
520                 return NULL;
521         }
522
523         gBufMgr->fd = fd;
524
525         /* set the display_server flag before loading the backend module */
526         if (server) {
527                 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
528                 gBufMgr->display_server = 1;
529         }
530
531         /* load bufmgr priv from env */
532         TBM_STDOUT_INFO("loading backend module");
533         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
534                 TBM_ERR("error : Fail to load bufmgr backend\n");
535                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
536                 free(gBufMgr);
537                 gBufMgr = NULL;
538                 pthread_mutex_unlock(&gLock);
539                 return NULL;
540
541         }
542         TBM_STDOUT_INFO("loading backend module done");
543         /* LCOV_EXCL_STOP */
544
545         gBufMgr->ref_count = 1;
546
547         TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
548             gBufMgr, gBufMgr->ref_count);
549
550         /* setup the bo_lock_type */
551         env = getenv("BUFMGR_LOCK_TYPE");
552         if (env && !strcmp(env, "always"))
553                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
554         else if (env && !strcmp(env, "none"))
555                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
556         else if (env && !strcmp(env, "once"))
557                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
558         else
559                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
560
561         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
562
563         /* intialize bo_list */
564         LIST_INITHEAD(&gBufMgr->bo_list);
565
566         /* intialize surf_list */
567         LIST_INITHEAD(&gBufMgr->surf_list);
568
569         /* intialize surf_queue_list */
570         LIST_INITHEAD(&gBufMgr->surf_queue_list);
571
572         /* intialize debug_key_list */
573         LIST_INITHEAD(&gBufMgr->debug_key_list);
574
575 #ifdef TBM_BUFMGR_INIT_TIME
576         /* get the end tv */
577         gettimeofday(&end_tv, NULL);
578         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)));
579 #endif
580
581         pthread_mutex_unlock(&gLock);
582
583         return gBufMgr;
584 }
585
586 tbm_bufmgr
587 tbm_bufmgr_init(int fd)
588 {
589         tbm_bufmgr bufmgr;
590
591         bufmgr = _tbm_bufmgr_init(fd, 0);
592
593         return bufmgr;
594 }
595
596 void
597 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
598 {
599         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
600
601         _tbm_bufmgr_mutex_lock();
602         pthread_mutex_lock(&gLock);
603         _tbm_set_last_result(TBM_ERROR_NONE);
604
605         if (!gBufMgr) {
606                 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
607                 pthread_mutex_unlock(&gLock);
608                 _tbm_bufmgr_mutex_unlock();
609                 return;
610         }
611
612         bufmgr->ref_count--;
613         if (bufmgr->ref_count > 0) {
614                 TBM_DBG("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
615                 pthread_mutex_unlock(&gLock);
616                 _tbm_bufmgr_mutex_unlock();
617                 return;
618         }
619
620         /* destroy bo_list */
621         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
622                 tbm_bo bo = NULL, tmp;
623
624                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
625                         TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
626                         _tbm_bo_free(bo);
627                 }
628                 LIST_DELINIT(&bufmgr->bo_list);
629         }
630
631         /* destroy surf_list */
632         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
633                 tbm_surface_h surf = NULL, tmp;
634
635                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
636                         TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
637                         tbm_surface_destroy(surf);
638                 }
639                 LIST_DELINIT(&bufmgr->surf_list);
640         }
641
642         if (bufmgr->backend_module_data) {
643                 /* deinit and backend destroys the backend func and data */
644                 bufmgr->backend_module_data->deinit(bufmgr->bufmgr_data);
645                 bufmgr->bo_func = NULL;
646                 bufmgr->bufmgr_func = NULL;
647                 bufmgr->bufmgr_data = NULL;
648                 bufmgr->backend_module_data = NULL;
649         } else {
650                 /* destroy bufmgr priv */
651                 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
652                 bufmgr->backend->priv = NULL;
653                 tbm_backend_free(bufmgr->backend);
654                 bufmgr->backend = NULL;
655         }
656
657         TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
658
659         dlclose(bufmgr->module_data);
660
661         if (bufmgr->fd > 0)
662                 close(bufmgr->fd);
663
664         free(bufmgr);
665         gBufMgr = NULL;
666
667         pthread_mutex_unlock(&gLock);
668         _tbm_bufmgr_mutex_unlock();
669 }
670
671 unsigned int
672 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
673 {
674         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
675
676         _tbm_bufmgr_mutex_lock();
677         _tbm_set_last_result(TBM_ERROR_NONE);
678
679         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
680         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
681
682         capabilities = bufmgr->capabilities;
683
684         _tbm_bufmgr_mutex_unlock();
685
686         return capabilities;
687 }
688
689 /* LCOV_EXCL_START */
690 char *
691 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
692 {
693         char app_name[255] = {0,}, title[512] = {0,};
694         tbm_surface_debug_data *debug_old_data = NULL;
695         char *str;
696         int len = 1024*4;
697         int c = 0;
698         int size;
699         tbm_error_e error;
700         long pid = 0;
701
702         pthread_mutex_lock(&gLock);
703         _tbm_set_last_result(TBM_ERROR_NONE);
704
705         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
706                 TBM_ERR("invalid bufmgr\n");
707                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
708                 pthread_mutex_unlock(&gLock);
709                 return NULL;
710         }
711
712         str = malloc(len);
713         if (!str) {
714                 TBM_ERR("Fail to allocate the string.\n");
715                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
716                 pthread_mutex_unlock(&gLock);
717                 return NULL;
718         }
719
720         TBM_SNRPRINTF(str, len, c, "\n");
721         pid = syscall(SYS_getpid);
722         _tbm_util_get_appname_from_pid(pid, app_name);
723         _tbm_util_get_appname_brief(app_name);
724         TBM_SNRPRINTF(str, len, c, "============TBM DEBUG: %s(%ld)===========================\n",
725                   app_name, pid);
726
727         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
728
729         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
730                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
731                         strncat(title, "  ", MAX_SIZE_N(title));
732                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
733                 }
734         }
735
736         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
737         TBM_SNRPRINTF(str, len, c, "%s\n", title);
738
739         /* show the tbm_surface information in surf_list */
740         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
741                 tbm_surface_h surf = NULL;
742                 int surf_cnt = 0;
743
744                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
745                         char data[512] = {0,};
746                         unsigned int surf_pid = 0;
747                         int i;
748
749                         surf_pid = _tbm_surface_internal_get_debug_pid(surf);
750                         if (!surf_pid) {
751                                 /* if pid is null, set the self_pid */
752                                 surf_pid = syscall(SYS_getpid);;
753                         }
754
755                         memset(app_name, 0x0, 255 * sizeof(char));
756                         if (geteuid() == 0) {
757                                 _tbm_util_get_appname_from_pid(surf_pid, app_name);
758                                 _tbm_util_get_appname_brief(app_name);
759                         } else {
760                                 snprintf(app_name, sizeof(app_name), "%d", surf_pid);
761                         }
762
763                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5u  %-6u  %-3u  %-6u   %-2d   %-2d    %-3d  %-8s  %-15s",
764                                   ++surf_cnt,
765                                   surf,
766                                   surf->refcnt,
767                                   surf->info.width,
768                                   surf->info.height,
769                                   surf->info.bpp,
770                                   surf->info.size / 1024,
771                                   surf->num_bos,
772                                   surf->num_planes,
773                                   surf->flags,
774                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
775                                   app_name);
776
777                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
778                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
779                                         char *value;
780
781                                         strncat(data, "  ", MAX_SIZE_N(title));
782
783                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
784                                         if (value)
785                                                 strncat(data, value, MAX_SIZE_N(title));
786                                         else
787                                                 strncat(data, "none", MAX_SIZE_N(title));
788                                 }
789                         }
790                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
791
792                         for (i = 0; i < surf->num_bos; i++) {
793                                 if (bufmgr->backend_module_data) {
794                                         size = bufmgr->bo_func->bo_get_size(surf->bos[i]->bo_data, &error);
795                                         if (error != TBM_ERROR_NONE)
796                                                 TBM_WRN("fail to get the size of bo.");
797                                 } else
798                                         size = bufmgr->backend->bo_size(surf->bos[i]);
799                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
800                                           surf->bos[i],
801                                           surf->bos[i]->ref_cnt,
802                                           size / 1024);
803                         }
804                 }
805         } else
806                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
807         TBM_SNRPRINTF(str, len, c, "\n");
808
809         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
810         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface     name\n");
811
812         /* show the tbm_bo information in bo_list */
813         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
814                 int bo_cnt = 0;
815                 tbm_bo bo = NULL;
816                 tbm_key key = 0;
817
818                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
819                         if (bufmgr->backend_module_data) {
820                                 size = bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
821                                 if (error != TBM_ERROR_NONE)
822                                         TBM_WRN("fail to get the size of bo.");
823                                 key = bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
824                                 if (error != TBM_ERROR_NONE)
825                                         TBM_WRN("fail to get the tdm_key of bo.");
826                         } else {
827                                 size = bufmgr->backend->bo_size(bo);
828                                 key = bufmgr->backend->bo_export(bo);
829                         }
830                         TBM_SNRPRINTF(str, len, c, "%-4d%-11p   %-4d  %-6d     %-5d     %-4u    %-3d  %-11p  %-4d\n",
831                                   ++bo_cnt,
832                                   bo,
833                                   bo->ref_cnt,
834                                   size / 1024,
835                                   bo->lock_cnt,
836                                   bo->map_cnt,
837                                   bo->flags,
838                                   bo->surface,
839                                   key);
840                 }
841         } else
842                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
843         TBM_SNRPRINTF(str, len, c, "\n");
844
845         TBM_SNRPRINTF(str, len, c, "===============================================================\n");
846
847         pthread_mutex_unlock(&gLock);
848
849         return str;
850 }
851
852 void
853 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
854 {
855         char * str;
856         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
857         if (str) {
858                 TBM_DBG("       %s", str);
859                 free(str);
860         }
861 }
862
863 void
864 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
865 {
866         _tbm_bufmgr_mutex_lock();
867         _tbm_set_last_result(TBM_ERROR_NONE);
868
869         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
870         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
871
872 #ifdef TRACE
873         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
874         bTrace = onoff;
875 #endif
876
877         _tbm_bufmgr_mutex_unlock();
878 }
879
880 void
881 tbm_bufmgr_debug_set_trace_mask(tbm_bufmgr bufmgr, tbm_bufmgr_debug_trace_mask mask, int set)
882 {
883         _tbm_bufmgr_mutex_lock();
884         _tbm_set_last_result(TBM_ERROR_NONE);
885
886         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
887         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
888
889         if (set == 1) {
890                 trace_mask |= mask;
891
892                 TBM_INFO("bufmgr=%p sets the trace_mask=%d\n", bufmgr, mask);
893                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
894                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
895                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
896                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
897                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
898                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
899                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
900                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
901         } else if (set == 0) {
902                 trace_mask &= ~mask;
903
904                 TBM_INFO("bufmgr=%p unsets the trace_mask=%d\n", bufmgr, mask);
905                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
906                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
907                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
908                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
909                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
910                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
911                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
912                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
913         } else {
914                 TBM_WRN("set value is wrong.(set=%d)", set);
915         }
916
917         _tbm_bufmgr_mutex_unlock();
918 }
919
920 void
921 tbm_bufmgr_debug_dump_set_scale(double scale)
922 {
923         pthread_mutex_lock(&gLock);
924         _tbm_set_last_result(TBM_ERROR_NONE);
925         scale_factor = scale;
926         pthread_mutex_unlock(&gLock);
927 }
928
929 int
930 tbm_bufmgr_debug_get_ref_count(void)
931 {
932         int refcnt;
933
934         pthread_mutex_lock(&gLock);
935
936         _tbm_set_last_result(TBM_ERROR_NONE);
937
938         refcnt = (gBufMgr) ? gBufMgr->ref_count : 0;
939
940         pthread_mutex_unlock(&gLock);
941
942         return refcnt;
943 }
944
945 int
946 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
947 {
948         pthread_mutex_lock(&gLock);
949         _tbm_set_last_result(TBM_ERROR_NONE);
950
951         if (onoff == 0) {
952                 TBM_DBG("count=%d onoff=%d\n", count, onoff);
953                 b_dump_queue = 0;
954                 tbm_surface_internal_dump_end();
955         } else {
956                 int w, h;
957
958                 if (path == NULL) {
959                         TBM_ERR("path is null");
960                         pthread_mutex_unlock(&gLock);
961                         return 0;
962                 }
963                 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
964
965                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
966                         TBM_ERR("Fail to get tbm_surface size.\n");
967                         pthread_mutex_unlock(&gLock);
968                         return 0;
969                 }
970
971                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
972                 scale_factor = 0;
973
974                 b_dump_queue = 1;
975         }
976
977         pthread_mutex_unlock(&gLock);
978
979         return 1;
980 }
981
982 int
983 tbm_bufmgr_debug_dump_all(char *path)
984 {
985         int w, h, count = 0;
986         tbm_surface_h surface = NULL;
987
988         pthread_mutex_lock(&gLock);
989         _tbm_set_last_result(TBM_ERROR_NONE);
990
991         if (!path) {
992                 TBM_ERR("path is null.\n");
993                 pthread_mutex_unlock(&gLock);
994                 return 0;
995         }
996
997         TBM_DBG("path=%s\n", path);
998
999         count = _tbm_util_get_max_surface_size(&w, &h);
1000         if (count == 0) {
1001                 TBM_ERR("No tbm_surface.\n");
1002                 pthread_mutex_unlock(&gLock);
1003                 return 0;
1004         }
1005
1006         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1007         scale_factor = 0;
1008
1009         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1010                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1011
1012         tbm_surface_internal_dump_end();
1013
1014         pthread_mutex_unlock(&gLock);
1015
1016         return 1;
1017 }
1018
1019 /* internal function */
1020 tbm_bufmgr
1021 _tbm_bufmgr_get_bufmgr(void)
1022 {
1023         return gBufMgr;
1024 }
1025
1026 int
1027 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1028 {
1029         int ret;
1030         tbm_error_e error;
1031
1032         _tbm_bufmgr_mutex_lock();
1033         _tbm_set_last_result(TBM_ERROR_NONE);
1034
1035         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1036
1037         if (bufmgr->backend_module_data) {
1038                 if (!bufmgr->bufmgr_func->bufmgr_bind_native_display) {
1039                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1040                                         bufmgr, native_display);
1041                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1042                         _tbm_bufmgr_mutex_unlock();
1043                         return 1;
1044                 }
1045
1046                 error = bufmgr->bufmgr_func->bufmgr_bind_native_display(bufmgr->bufmgr_data, (tbm_native_display *)native_display);
1047                 if (error != TBM_ERROR_NONE) {
1048                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p) error(%d)\n",
1049                                         bufmgr, native_display, error);
1050                         _tbm_set_last_result(error);
1051                         _tbm_bufmgr_mutex_unlock();
1052                         return 0;
1053                 }
1054                 ret = 1;
1055         } else {
1056                 if (!bufmgr->backend->bufmgr_bind_native_display) {
1057                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1058                                         bufmgr, native_display);
1059                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1060                         _tbm_bufmgr_mutex_unlock();
1061                         return 1;
1062                 }
1063
1064                 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
1065                 if (!ret) {
1066                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p)\n",
1067                                         bufmgr, native_display);
1068                         _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
1069                         _tbm_bufmgr_mutex_unlock();
1070                         return 0;
1071                 }
1072         }
1073
1074         TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
1075
1076         _tbm_bufmgr_mutex_unlock();
1077
1078         return 1;
1079 }
1080
1081 tbm_bufmgr
1082 tbm_bufmgr_server_init(void)
1083 {
1084         tbm_bufmgr bufmgr;
1085
1086         bufmgr = _tbm_bufmgr_init(-1, 1);
1087
1088         return bufmgr;
1089 }
1090
1091 int
1092 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
1093 {
1094         _tbm_bufmgr_mutex_lock();
1095         _tbm_set_last_result(TBM_ERROR_NONE);
1096
1097         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1098         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
1099
1100         pthread_mutex_lock(&gLock);
1101         gBufMgr->bo_lock_type = bo_lock_type;
1102         pthread_mutex_unlock(&gLock);
1103
1104         TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
1105
1106         _tbm_bufmgr_mutex_unlock();
1107
1108         return 1;
1109 }
1110
1111
1112 int tbm_bufmgr_get_fd_limit(void)
1113 {
1114         struct rlimit lim;
1115
1116         if (getrlimit(RLIMIT_NOFILE, &lim))
1117                 return 1024;
1118
1119         return (int)lim.rlim_cur;
1120 }
1121
1122 tbm_bufmgr tbm_bufmgr_get(void)
1123 {
1124         return gBufMgr;
1125 }
1126 /* LCOV_EXCL_STOP */