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