bufmgr: do not print backend information on stdout
[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_INFO("Success to load module(%s)\n", file);
351
352         return 1;
353
354 err:
355         if (bufmgr_data)
356                 bufmgr->backend_module_data->deinit(bufmgr_data);
357         if (module_data)
358                 dlclose(module_data);
359
360         return 0;
361 }
362
363 static int
364 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
365 {
366         char path[PATH_MAX] = {0, };
367         TBMModuleVersionInfo *vers;
368         TBMModuleData *initdata;
369         ModuleInitProc init;
370         void *module_data;
371
372         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
373
374         module_data = dlopen(path, RTLD_LAZY);
375         if (!module_data) {
376                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
377                 return 0;
378         }
379
380         initdata = dlsym(module_data, "tbmModuleData");
381         if (!initdata) {
382                 TBM_ERR("Error: module does not have data object.\n");
383                 goto err;
384         }
385
386         vers = initdata->vers;
387         if (!vers) {
388                 TBM_ERR("Error: module does not supply version information.\n");
389                 goto err;
390         }
391
392         init = initdata->init;
393         if (!init) {
394                 TBM_ERR("Error: module does not supply init symbol.\n");
395                 goto err;
396         }
397
398         if (!_check_version(vers)) {
399                 TBM_ERR("Fail to check version.\n");
400                 goto err;
401         }
402
403         if (!init(bufmgr, fd)) {
404                 TBM_ERR("Fail to init module(%s)\n", file);
405                 goto err;
406         }
407
408         if (!bufmgr->backend || !bufmgr->backend->priv) {
409                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
410                 goto err;
411         }
412
413         bufmgr->module_data = module_data;
414
415         TBM_DBG("Success to load module(%s)\n", file);
416
417         return 1;
418
419 err:
420         dlclose(module_data);
421         return 0;
422 }
423
424 static int
425 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
426 {
427         struct dirent **namelist;
428         int ret = 0, n;
429
430         /* try to load the new backend module */
431         ret = _tbm_backend_load_module(bufmgr, DEFAULT_LIB);
432         if (ret)
433                 return 1;
434
435         /* try to load the old(deprecated) backend mdoule */
436         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
437         if (ret)
438                 return 1;
439
440         /* load bufmgr priv from configured path */
441         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
442         if (n < 0) {
443                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
444                 return 0;
445         }
446
447         while (n--) {
448                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
449                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
450
451                         if (p && !strcmp(p, SUFFIX_LIB)) {
452                                 ret = _tbm_backend_load_module(bufmgr, namelist[n]->d_name);
453                                 if (!ret)
454                                         ret = _tbm_bufmgr_load_module(bufmgr, fd,
455                                                                         namelist[n]->d_name);
456                         }
457                 }
458
459                 free(namelist[n]);
460         }
461
462         free(namelist);
463
464         return ret;
465 }
466 /* LCOV_EXCL_STOP */
467
468 static tbm_bufmgr
469 _tbm_bufmgr_init(int fd, int server)
470 {
471 #ifdef TBM_BUFMGR_INIT_TIME
472         struct timeval start_tv, end_tv;
473 #endif
474         char *env;
475
476 #ifdef TBM_BUFMGR_INIT_TIME
477         /* get the start tv */
478         gettimeofday(&start_tv, NULL);
479 #endif
480
481         bDlog = 1;
482
483         /* LCOV_EXCL_START */
484 #ifdef TRACE
485         env = getenv("TBM_TRACE");
486         if (env) {
487                 trace_mask = atoi(env);
488                 TBM_DBG("TBM_TRACE=%s\n", env);
489         } else
490                 trace_mask = 0;
491 #endif
492
493         pthread_mutex_lock(&gLock);
494
495         _tbm_set_last_result(TBM_ERROR_NONE);
496
497         if (fd >= 0) {
498                 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
499                 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
500         }
501
502
503         /* initialize buffer manager */
504         if (gBufMgr) {
505                 gBufMgr->ref_count++;
506                 TBM_DBG("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
507                 pthread_mutex_unlock(&gLock);
508                 return gBufMgr;
509         }
510
511         TBM_DBG("bufmgr init\n");
512
513         /* allocate bufmgr */
514         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
515         if (!gBufMgr) {
516                 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
517                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
518                 pthread_mutex_unlock(&gLock);
519                 return NULL;
520         }
521
522         gBufMgr->fd = fd;
523
524         /* set the display_server flag before loading the backend module */
525         if (server) {
526                 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
527                 gBufMgr->display_server = 1;
528         }
529
530         /* load bufmgr priv from env */
531         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
532                 TBM_ERR("error : Fail to load bufmgr backend\n");
533                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
534                 free(gBufMgr);
535                 gBufMgr = NULL;
536                 pthread_mutex_unlock(&gLock);
537                 return NULL;
538
539         }
540         /* LCOV_EXCL_STOP */
541
542         gBufMgr->ref_count = 1;
543
544         TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
545             gBufMgr, gBufMgr->ref_count);
546
547         /* setup the bo_lock_type */
548         env = getenv("BUFMGR_LOCK_TYPE");
549         if (env && !strcmp(env, "always"))
550                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
551         else if (env && !strcmp(env, "none"))
552                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
553         else if (env && !strcmp(env, "once"))
554                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
555         else
556                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
557
558         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
559
560         /* intialize bo_list */
561         LIST_INITHEAD(&gBufMgr->bo_list);
562
563         /* intialize surf_list */
564         LIST_INITHEAD(&gBufMgr->surf_list);
565
566         /* intialize surf_queue_list */
567         LIST_INITHEAD(&gBufMgr->surf_queue_list);
568
569         /* intialize debug_key_list */
570         LIST_INITHEAD(&gBufMgr->debug_key_list);
571
572 #ifdef TBM_BUFMGR_INIT_TIME
573         /* get the end tv */
574         gettimeofday(&end_tv, NULL);
575         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)));
576 #endif
577
578         pthread_mutex_unlock(&gLock);
579
580         return gBufMgr;
581 }
582
583 tbm_bufmgr
584 tbm_bufmgr_init(int fd)
585 {
586         tbm_bufmgr bufmgr;
587
588         bufmgr = _tbm_bufmgr_init(fd, 0);
589
590         return bufmgr;
591 }
592
593 void
594 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
595 {
596         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
597
598         _tbm_bufmgr_mutex_lock();
599         pthread_mutex_lock(&gLock);
600         _tbm_set_last_result(TBM_ERROR_NONE);
601
602         if (!gBufMgr) {
603                 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
604                 pthread_mutex_unlock(&gLock);
605                 _tbm_bufmgr_mutex_unlock();
606                 return;
607         }
608
609         bufmgr->ref_count--;
610         if (bufmgr->ref_count > 0) {
611                 TBM_DBG("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
612                 pthread_mutex_unlock(&gLock);
613                 _tbm_bufmgr_mutex_unlock();
614                 return;
615         }
616
617         /* destroy bo_list */
618         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
619                 tbm_bo bo = NULL, tmp;
620
621                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
622                         TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
623                         _tbm_bo_free(bo);
624                 }
625                 LIST_DELINIT(&bufmgr->bo_list);
626         }
627
628         /* destroy surf_list */
629         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
630                 tbm_surface_h surf = NULL, tmp;
631
632                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
633                         TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
634                         tbm_surface_destroy(surf);
635                 }
636                 LIST_DELINIT(&bufmgr->surf_list);
637         }
638
639         if (bufmgr->backend_module_data) {
640                 /* deinit and backend destroys the backend func and data */
641                 bufmgr->backend_module_data->deinit(bufmgr->bufmgr_data);
642                 bufmgr->bo_func = NULL;
643                 bufmgr->bufmgr_func = NULL;
644                 bufmgr->bufmgr_data = NULL;
645                 bufmgr->backend_module_data = NULL;
646         } else {
647                 /* destroy bufmgr priv */
648                 bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
649                 bufmgr->backend->priv = NULL;
650                 tbm_backend_free(bufmgr->backend);
651                 bufmgr->backend = NULL;
652         }
653
654         TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
655
656         dlclose(bufmgr->module_data);
657
658         if (bufmgr->fd > 0)
659                 close(bufmgr->fd);
660
661         free(bufmgr);
662         gBufMgr = NULL;
663
664         pthread_mutex_unlock(&gLock);
665         _tbm_bufmgr_mutex_unlock();
666 }
667
668 unsigned int
669 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
670 {
671         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
672
673         _tbm_bufmgr_mutex_lock();
674         _tbm_set_last_result(TBM_ERROR_NONE);
675
676         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
677         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
678
679         capabilities = bufmgr->capabilities;
680
681         _tbm_bufmgr_mutex_unlock();
682
683         return capabilities;
684 }
685
686 /* LCOV_EXCL_START */
687 char *
688 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
689 {
690         char app_name[255] = {0,}, title[512] = {0,};
691         tbm_surface_debug_data *debug_old_data = NULL;
692         char *str;
693         int len = 1024*4;
694         int c = 0;
695         int size;
696         tbm_error_e error;
697         long pid = 0;
698
699         pthread_mutex_lock(&gLock);
700         _tbm_set_last_result(TBM_ERROR_NONE);
701
702         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
703                 TBM_ERR("invalid bufmgr\n");
704                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
705                 pthread_mutex_unlock(&gLock);
706                 return NULL;
707         }
708
709         str = malloc(len);
710         if (!str) {
711                 TBM_ERR("Fail to allocate the string.\n");
712                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
713                 pthread_mutex_unlock(&gLock);
714                 return NULL;
715         }
716
717         TBM_SNRPRINTF(str, len, c, "\n");
718         pid = syscall(SYS_getpid);
719         _tbm_util_get_appname_from_pid(pid, app_name);
720         _tbm_util_get_appname_brief(app_name);
721         TBM_SNRPRINTF(str, len, c, "===========================================TBM DEBUG: %s(%ld)===========================================\n",
722                   app_name, pid);
723
724         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags    format    app_name              ");
725
726         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
727                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
728                         strncat(title, "  ", MAX_SIZE_N(title));
729                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
730                 }
731         }
732
733         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
734         TBM_SNRPRINTF(str, len, c, "%s\n", title);
735
736         /* show the tbm_surface information in surf_list */
737         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
738                 tbm_surface_h surf = NULL;
739                 int surf_cnt = 0;
740
741                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
742                         char data[512] = {0,};
743                         unsigned int surf_pid = 0;
744                         int i;
745
746                         surf_pid = _tbm_surface_internal_get_debug_pid(surf);
747                         if (!surf_pid) {
748                                 /* if pid is null, set the self_pid */
749                                 surf_pid = syscall(SYS_getpid);;
750                         }
751
752                         memset(app_name, 0x0, 255 * sizeof(char));
753                         if (geteuid() == 0) {
754                                 _tbm_util_get_appname_from_pid(surf_pid, app_name);
755                                 _tbm_util_get_appname_brief(app_name);
756                         } else {
757                                 snprintf(app_name, sizeof(app_name), "%d", surf_pid);
758                         }
759
760                         snprintf(data, 255, "%-3d %-11p   %-5d %-6u %-7u %-4u %-7u  %-3d  %-3d %-8d %-9s %-22s",
761                                   ++surf_cnt,
762                                   surf,
763                                   surf->refcnt,
764                                   surf->info.width,
765                                   surf->info.height,
766                                   surf->info.bpp,
767                                   surf->info.size / 1024,
768                                   surf->num_bos,
769                                   surf->num_planes,
770                                   surf->flags,
771                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
772                                   app_name);
773
774                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
775                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
776                                         char *value;
777
778                                         strncat(data, "  ", MAX_SIZE_N(title));
779
780                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
781                                         if (value)
782                                                 strncat(data, value, MAX_SIZE_N(title));
783                                         else
784                                                 strncat(data, "none", MAX_SIZE_N(title));
785                                 }
786                         }
787                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
788
789                         for (i = 0; i < surf->num_bos; i++) {
790                                 if (bufmgr->backend_module_data) {
791                                         size = bufmgr->bo_func->bo_get_size(surf->bos[i]->bo_data, &error);
792                                         if (error != TBM_ERROR_NONE)
793                                                 TBM_WRN("fail to get the size of bo.");
794                                 } else
795                                         size = bufmgr->backend->bo_size(surf->bos[i]);
796                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
797                                           surf->bos[i],
798                                           surf->bos[i]->ref_cnt,
799                                           size / 1024);
800                         }
801                 }
802         } else
803                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
804         TBM_SNRPRINTF(str, len, c, "\n");
805
806         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
807         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags   surface     name\n");
808
809         /* show the tbm_bo information in bo_list */
810         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
811                 int bo_cnt = 0;
812                 tbm_bo bo = NULL;
813                 tbm_key key = 0;
814
815                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
816                         if (bufmgr->backend_module_data) {
817                                 size = bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
818                                 if (error != TBM_ERROR_NONE)
819                                         TBM_WRN("fail to get the size of bo.");
820                                 key = bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
821                                 if (error != TBM_ERROR_NONE)
822                                         TBM_WRN("fail to get the tdm_key of bo.");
823                         } else {
824                                 size = bufmgr->backend->bo_size(bo);
825                                 key = bufmgr->backend->bo_export(bo);
826                         }
827                         TBM_SNRPRINTF(str, len, c, "%-3d %-11p   %-5d %-7d    %-6d    %-5u %-7d %-11p  %-4d\n",
828                                   ++bo_cnt,
829                                   bo,
830                                   bo->ref_cnt,
831                                   size / 1024,
832                                   bo->lock_cnt,
833                                   bo->map_cnt,
834                                   bo->flags,
835                                   bo->surface,
836                                   key);
837                 }
838         } else
839                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
840         TBM_SNRPRINTF(str, len, c, "\n");
841
842         TBM_SNRPRINTF(str, len, c, "========================================================================================================\n");
843
844         pthread_mutex_unlock(&gLock);
845
846         return str;
847 }
848
849 void
850 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
851 {
852         char * str;
853         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
854         if (str) {
855                 TBM_DBG("       %s", str);
856                 free(str);
857         }
858 }
859
860 void
861 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
862 {
863         _tbm_bufmgr_mutex_lock();
864         _tbm_set_last_result(TBM_ERROR_NONE);
865
866         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
867         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
868
869 #ifdef TRACE
870         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
871         bTrace = onoff;
872 #endif
873
874         _tbm_bufmgr_mutex_unlock();
875 }
876
877 void
878 tbm_bufmgr_debug_set_trace_mask(tbm_bufmgr bufmgr, tbm_bufmgr_debug_trace_mask mask, int set)
879 {
880         _tbm_bufmgr_mutex_lock();
881         _tbm_set_last_result(TBM_ERROR_NONE);
882
883         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
884         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
885
886         if (set == 1) {
887                 trace_mask |= mask;
888
889                 TBM_INFO("bufmgr=%p sets 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 if (set == 0) {
899                 trace_mask &= ~mask;
900
901                 TBM_INFO("bufmgr=%p unsets the trace_mask=%d\n", bufmgr, mask);
902                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
903                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
904                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
905                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
906                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
907                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
908                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
909                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
910         } else {
911                 TBM_WRN("set value is wrong.(set=%d)", set);
912         }
913
914         _tbm_bufmgr_mutex_unlock();
915 }
916
917 void
918 tbm_bufmgr_debug_dump_set_scale(double scale)
919 {
920         pthread_mutex_lock(&gLock);
921         _tbm_set_last_result(TBM_ERROR_NONE);
922         scale_factor = scale;
923         pthread_mutex_unlock(&gLock);
924 }
925
926 int
927 tbm_bufmgr_debug_get_ref_count(void)
928 {
929         int refcnt;
930
931         pthread_mutex_lock(&gLock);
932
933         _tbm_set_last_result(TBM_ERROR_NONE);
934
935         refcnt = (gBufMgr) ? gBufMgr->ref_count : 0;
936
937         pthread_mutex_unlock(&gLock);
938
939         return refcnt;
940 }
941
942 int
943 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
944 {
945         pthread_mutex_lock(&gLock);
946         _tbm_set_last_result(TBM_ERROR_NONE);
947
948         if (onoff == 0) {
949                 TBM_DBG("count=%d onoff=%d\n", count, onoff);
950                 b_dump_queue = 0;
951                 tbm_surface_internal_dump_end();
952         } else {
953                 int w, h;
954
955                 if (path == NULL) {
956                         TBM_ERR("path is null");
957                         pthread_mutex_unlock(&gLock);
958                         return 0;
959                 }
960                 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
961
962                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
963                         TBM_ERR("Fail to get tbm_surface size.\n");
964                         pthread_mutex_unlock(&gLock);
965                         return 0;
966                 }
967
968                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
969                 scale_factor = 0;
970
971                 b_dump_queue = 1;
972         }
973
974         pthread_mutex_unlock(&gLock);
975
976         return 1;
977 }
978
979 int
980 tbm_bufmgr_debug_dump_all(char *path)
981 {
982         int w, h, count = 0;
983         tbm_surface_h surface = NULL;
984
985         pthread_mutex_lock(&gLock);
986         _tbm_set_last_result(TBM_ERROR_NONE);
987
988         if (!path) {
989                 TBM_ERR("path is null.\n");
990                 pthread_mutex_unlock(&gLock);
991                 return 0;
992         }
993
994         TBM_DBG("path=%s\n", path);
995
996         count = _tbm_util_get_max_surface_size(&w, &h);
997         if (count == 0) {
998                 TBM_ERR("No tbm_surface.\n");
999                 pthread_mutex_unlock(&gLock);
1000                 return 0;
1001         }
1002
1003         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1004         scale_factor = 0;
1005
1006         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1007                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1008
1009         tbm_surface_internal_dump_end();
1010
1011         pthread_mutex_unlock(&gLock);
1012
1013         return 1;
1014 }
1015
1016 /* internal function */
1017 tbm_bufmgr
1018 _tbm_bufmgr_get_bufmgr(void)
1019 {
1020         return gBufMgr;
1021 }
1022
1023 int
1024 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
1025 {
1026         int ret;
1027         tbm_error_e error;
1028
1029         _tbm_bufmgr_mutex_lock();
1030         _tbm_set_last_result(TBM_ERROR_NONE);
1031
1032         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1033
1034         if (bufmgr->backend_module_data) {
1035                 if (!bufmgr->bufmgr_func->bufmgr_bind_native_display) {
1036                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1037                                         bufmgr, native_display);
1038                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1039                         _tbm_bufmgr_mutex_unlock();
1040                         return 1;
1041                 }
1042
1043                 error = bufmgr->bufmgr_func->bufmgr_bind_native_display(bufmgr->bufmgr_data, (tbm_native_display *)native_display);
1044                 if (error != TBM_ERROR_NONE) {
1045                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p) error(%d)\n",
1046                                         bufmgr, native_display, error);
1047                         _tbm_set_last_result(error);
1048                         _tbm_bufmgr_mutex_unlock();
1049                         return 0;
1050                 }
1051                 ret = 1;
1052         } else {
1053                 if (!bufmgr->backend->bufmgr_bind_native_display) {
1054                         TBM_WRN("skip: tbm_bufmgr(%p) native_display(%p)\n",
1055                                         bufmgr, native_display);
1056                         _tbm_set_last_result(TBM_ERROR_NOT_SUPPORTED);
1057                         _tbm_bufmgr_mutex_unlock();
1058                         return 1;
1059                 }
1060
1061                 ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, native_display);
1062                 if (!ret) {
1063                         TBM_ERR("error: tbm_bufmgr(%p) native_display(%p)\n",
1064                                         bufmgr, native_display);
1065                         _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
1066                         _tbm_bufmgr_mutex_unlock();
1067                         return 0;
1068                 }
1069         }
1070
1071         TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
1072
1073         _tbm_bufmgr_mutex_unlock();
1074
1075         return 1;
1076 }
1077
1078 tbm_bufmgr
1079 tbm_bufmgr_server_init(void)
1080 {
1081         tbm_bufmgr bufmgr;
1082
1083         bufmgr = _tbm_bufmgr_init(-1, 1);
1084
1085         return bufmgr;
1086 }
1087
1088 int
1089 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
1090 {
1091         _tbm_bufmgr_mutex_lock();
1092         _tbm_set_last_result(TBM_ERROR_NONE);
1093
1094         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1095         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
1096
1097         pthread_mutex_lock(&gLock);
1098         gBufMgr->bo_lock_type = bo_lock_type;
1099         pthread_mutex_unlock(&gLock);
1100
1101         TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
1102
1103         _tbm_bufmgr_mutex_unlock();
1104
1105         return 1;
1106 }
1107
1108
1109 int tbm_bufmgr_get_fd_limit(void)
1110 {
1111         struct rlimit lim;
1112
1113         if (getrlimit(RLIMIT_NOFILE, &lim))
1114                 return 1024;
1115
1116         return (int)lim.rlim_cur;
1117 }
1118
1119 tbm_bufmgr tbm_bufmgr_get(void)
1120 {
1121         return gBufMgr;
1122 }
1123 /* LCOV_EXCL_STOP */