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