remove unused valiable
[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 #ifdef DEBUG
42 int bDebug;
43 #endif
44
45 #ifdef TRACE
46 int bTrace;
47 #endif
48
49 #ifdef HAVE_DLOG
50 int bDlog;
51 #endif
52
53 tbm_bufmgr gBufMgr;
54 int b_dump_queue;
55
56 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
57 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
58 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
59 static double scale_factor = 0;
60 static void _tbm_bufmgr_mutex_unlock(void);
61
62 //#define TBM_BUFMGR_INIT_TIME
63
64 #define PREFIX_LIB    "libtbm_"
65 #define SUFFIX_LIB    ".so"
66 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
67
68 /* values to indicate unspecified fields in XF86ModReqInfo. */
69 #define MAJOR_UNSPEC        0xFF
70 #define MINOR_UNSPEC        0xFF
71 #define PATCH_UNSPEC        0xFFFF
72 #define ABI_VERS_UNSPEC   0xFFFFFFFF
73
74 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
75                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
76 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
77 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
78 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
79
80 /* check condition */
81 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
82         if (!(cond)) {\
83                 TBM_LOG_E("'%s' failed.\n", #cond);\
84                 _tbm_bufmgr_mutex_unlock();\
85                 return;\
86         } \
87 }
88
89 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
90         if (!(cond)) {\
91                 TBM_LOG_E("'%s' failed.\n", #cond);\
92                 _tbm_bufmgr_mutex_unlock();\
93                 return val;\
94         } \
95 }
96
97 enum {
98         LOCK_TRY_ONCE,
99         LOCK_TRY_ALWAYS,
100         LOCK_TRY_NEVER
101 };
102
103 static void
104 _tbm_set_last_result(tbm_error_e err)
105 {
106         tbm_last_error = err;
107 }
108
109 /* LCOV_EXCL_START */
110 static bool
111 _tbm_bufmgr_mutex_init(void)
112 {
113         static bool tbm_bufmgr_mutex_init = false;
114
115         if (tbm_bufmgr_mutex_init)
116                 return true;
117
118         if (pthread_mutex_init(&tbm_bufmgr_lock, NULL)) {
119                 TBM_LOG_E("fail: Cannot pthread_mutex_init for tbm_bufmgr_lock.\n");
120                 return false;
121         }
122
123         tbm_bufmgr_mutex_init = true;
124
125         return true;
126 }
127
128 static void
129 _tbm_bufmgr_mutex_lock(void)
130 {
131         if (!_tbm_bufmgr_mutex_init()) {
132                 TBM_LOG_E("fail: _tbm_bufmgr_mutex_init()\n");
133                 return;
134         }
135
136         pthread_mutex_lock(&tbm_bufmgr_lock);
137 }
138
139 static void
140 _tbm_bufmgr_mutex_unlock(void)
141 {
142         pthread_mutex_unlock(&tbm_bufmgr_lock);
143 }
144
145 static char *
146 _tbm_flag_to_str(int f)
147 {
148         static char str[255];
149
150         if (f == TBM_BO_DEFAULT)
151                  snprintf(str, 255, "DEFAULT");
152         else {
153                 int c = 0;
154
155                 if (f & TBM_BO_SCANOUT)
156                         c = snprintf(&str[c], 255, "SCANOUT");
157
158                 if (f & TBM_BO_NONCACHABLE) {
159                         if (c)
160                                 c = snprintf(&str[c], 255, ", ");
161                         c = snprintf(&str[c], 255, "NONCACHABLE,");
162                 }
163
164                 if (f & TBM_BO_WC) {
165                         if (c)
166                                 c = snprintf(&str[c], 255, ", ");
167                         c = snprintf(&str[c], 255, "WC");
168                 }
169         }
170
171         return str;
172 }
173
174 static void
175 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
176 {
177         static int last_chk_bo_cnt = 0;
178
179         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
180                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
181                 TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n",
182                                 bufmgr->bo_cnt);
183
184                 tbm_bufmgr_debug_show(bufmgr);
185
186                 last_chk_bo_cnt = bufmgr->bo_cnt;
187         }
188 }
189
190 static int
191 _tbm_util_get_max_surface_size(int *w, int *h)
192 {
193         tbm_surface_info_s info;
194         tbm_surface_h surface = NULL;
195         int count = 0;
196
197         *w = 0;
198         *h = 0;
199
200         if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
201                 return count;
202
203         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
204                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
205                         count++;
206                         if (*w < info.width)
207                                 *w = info.width;
208                         if (*h < info.height)
209                                 *h = info.height;
210                 }
211         }
212
213         return count;
214 }
215
216 static void
217 _tbm_util_get_appname_brief(char *brief)
218 {
219         char delim[] = "/";
220         char *token = NULL;
221         char temp[255] = {0,};
222         char *saveptr = NULL;
223
224         token = strtok_r(brief, delim, &saveptr);
225
226         while (token != NULL) {
227                 memset(temp, 0x00, 255 * sizeof(char));
228                 strncpy(temp, token, 254 * sizeof(char));
229                 token = strtok_r(NULL, delim, &saveptr);
230         }
231
232         snprintf(brief, sizeof(temp), "%s", temp);
233 }
234
235 static void
236 _tbm_util_get_appname_from_pid(long pid, char *str)
237 {
238         char fn_cmdline[255] = {0, }, cmdline[255];
239         FILE *fp;
240         int len;
241
242         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
243
244         fp = fopen(fn_cmdline, "r");
245         if (fp == 0) {
246                 TBM_LOG_E("cannot file open %s\n", fn_cmdline);
247                 return;
248         }
249
250         if (!fgets(cmdline, 255, fp)) {
251                 TBM_LOG_E("fail to get appname for pid(%ld)\n", pid);
252                 fclose(fp);
253                 return;
254         }
255
256         fclose(fp);
257
258         len = strlen(cmdline);
259         if (len < 1)
260                 memset(cmdline, 0x00, 255);
261         else
262                 cmdline[len] = 0;
263
264         snprintf(str, sizeof(cmdline), "%s", cmdline);
265 }
266 /* LCOV_EXCL_STOP */
267
268 tbm_user_data
269 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
270 {
271         tbm_user_data *old_data = NULL;
272
273         if (LIST_IS_EMPTY(user_data_list))
274                 return NULL;
275
276         LIST_FOR_EACH_ENTRY(old_data, user_data_list, item_link) {
277                 if (old_data->key == key)
278                         return old_data;
279         }
280
281         return NULL;
282 }
283
284 tbm_user_data
285 *user_data_create(unsigned long key, tbm_data_free data_free_func)
286 {
287         tbm_user_data *user_data;
288
289         user_data = calloc(1, sizeof(tbm_user_data));
290         if (!user_data) {
291                 /* LCOV_EXCL_START */
292                 TBM_LOG_E("fail to allocate an user_date\n");
293                 return NULL;
294                 /* LCOV_EXCL_STOP */
295         }
296
297         user_data->key = key;
298         user_data->free_func = data_free_func;
299
300         return user_data;
301 }
302
303 void
304 user_data_delete(tbm_user_data *user_data)
305 {
306         if (user_data->data && user_data->free_func)
307                 user_data->free_func(user_data->data);
308
309         LIST_DEL(&user_data->item_link);
310
311         free(user_data);
312 }
313
314 static int
315 _bo_lock(tbm_bo bo, int device, int opt)
316 {
317         tbm_bufmgr bufmgr = bo->bufmgr;
318         int ret = 1;
319
320         if (bufmgr->backend->bo_lock)
321                 ret = bufmgr->backend->bo_lock(bo, device, opt);
322
323         return ret;
324 }
325
326 static void
327 _bo_unlock(tbm_bo bo)
328 {
329         tbm_bufmgr bufmgr = bo->bufmgr;
330
331         if (bufmgr->backend->bo_unlock)
332                 bufmgr->backend->bo_unlock(bo);
333 }
334
335 static int
336 _tbm_bo_lock(tbm_bo bo, int device, int opt)
337 {
338         tbm_bufmgr bufmgr;
339         int old, ret;
340
341         if (!bo)
342                 return 0;
343
344         bufmgr = bo->bufmgr;
345
346         /* do not try to lock the bo */
347         if (bufmgr->lock_type == LOCK_TRY_NEVER)
348                 return 1;
349
350         if (bo->lock_cnt < 0) {
351                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
352                         bo, bo->lock_cnt);
353                 return 0;
354         }
355
356         old = bo->lock_cnt;
357
358         switch (bufmgr->lock_type) {
359         case LOCK_TRY_ONCE:
360                 if (bo->lock_cnt == 0) {
361                         _tbm_bufmgr_mutex_unlock();
362                         ret = _bo_lock(bo, device, opt);
363                         _tbm_bufmgr_mutex_lock();
364                         if (ret)
365                                 bo->lock_cnt++;
366                 } else
367                         ret = 1;
368                 break;
369         case LOCK_TRY_ALWAYS:
370                 _tbm_bufmgr_mutex_unlock();
371                 ret = _bo_lock(bo, device, opt);
372                 _tbm_bufmgr_mutex_lock();
373                 if (ret)
374                         bo->lock_cnt++;
375                 break;
376         default:
377                 TBM_LOG_E("error bo:%p lock_type[%d] is wrong.\n",
378                                 bo, bufmgr->lock_type);
379                 ret = 0;
380                 break;
381         }
382
383         TBM_DBG_LOCK(">> LOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
384
385         return ret;
386 }
387
388 static void
389 _tbm_bo_unlock(tbm_bo bo)
390 {
391         tbm_bufmgr bufmgr;
392         int old;
393
394         if (!bo)
395                 return;
396
397         bufmgr = bo->bufmgr;
398
399         /* do not try to unlock the bo */
400         if (bufmgr->lock_type == LOCK_TRY_NEVER)
401                 return;
402
403         old = bo->lock_cnt;
404
405         switch (bufmgr->lock_type) {
406         case LOCK_TRY_ONCE:
407                 if (bo->lock_cnt > 0) {
408                         bo->lock_cnt--;
409                         if (bo->lock_cnt == 0)
410                                 _bo_unlock(bo);
411                 }
412                 break;
413         case LOCK_TRY_ALWAYS:
414                 if (bo->lock_cnt > 0) {
415                         bo->lock_cnt--;
416                         _bo_unlock(bo);
417                 }
418                 break;
419         default:
420                 TBM_LOG_E("error bo:%p lock_type[%d] is wrong.\n",
421                                 bo, bufmgr->lock_type);
422                 break;
423         }
424
425         if (bo->lock_cnt < 0)
426                 bo->lock_cnt = 0;
427
428         TBM_DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n", bo, old, bo->lock_cnt);
429 }
430
431 static int
432 _tbm_bo_is_valid(tbm_bo bo)
433 {
434         tbm_bo old_data = NULL;
435
436         if (bo == NULL || gBufMgr == NULL) {
437                 TBM_LOG_E("error: bo is NULL or tbm_bufmgr was deinited\n");
438                 return 0;
439         }
440
441         if (LIST_IS_EMPTY(&gBufMgr->bo_list)) {
442                 TBM_LOG_E("error: gBufMgr->bo_list is EMPTY.\n");
443                 return 0;
444         }
445
446         LIST_FOR_EACH_ENTRY(old_data, &gBufMgr->bo_list, item_link) {
447                 if (old_data == bo)
448                         return 1;
449         }
450
451         TBM_LOG_E("error: No valid bo(%p).\n", bo);
452
453         return 0;
454 }
455
456 static void
457 _tbm_bo_free(tbm_bo bo)
458 {
459         tbm_bufmgr bufmgr = bo->bufmgr;
460
461         /* destory the user_data_list */
462         if (!LIST_IS_EMPTY(&bo->user_data_list)) {
463                 tbm_user_data *old_data = NULL, *tmp;
464
465                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp,
466                                 &bo->user_data_list, item_link) {
467                         TBM_DBG("free user_data\n");
468                         user_data_delete(old_data);
469                 }
470         }
471
472         while (bo->lock_cnt > 0) {
473                 TBM_LOG_E("error lock_cnt:%d\n", bo->lock_cnt);
474                 _bo_unlock(bo);
475                 bo->lock_cnt--;
476         }
477
478         /* call the bo_free */
479         bufmgr->backend->bo_free(bo);
480         bo->priv = NULL;
481
482         LIST_DEL(&bo->item_link);
483         free(bo);
484
485         bufmgr->bo_cnt--;
486 }
487
488 /* LCOV_EXCL_START */
489 static int
490 _check_version(TBMModuleVersionInfo *data)
491 {
492         int abimaj, abimin;
493         int vermaj, vermin;
494
495         abimaj = GET_ABI_MAJOR(data->abiversion);
496         abimin = GET_ABI_MINOR(data->abiversion);
497
498         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
499             data->modname ? data->modname : "UNKNOWN!",
500             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
501
502         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
503         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
504
505         TBM_DBG("TBM ABI version %d.%d\n",
506             vermaj, vermin);
507
508         if (abimaj != vermaj) {
509                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
510                         abimaj, vermaj);
511                 return 0;
512         } else if (abimin > vermin) {
513                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
514                         abimin, vermin);
515                 return 0;
516         }
517
518         return 1;
519 }
520
521 static int
522 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
523 {
524         char path[PATH_MAX] = {0, };
525         TBMModuleVersionInfo *vers;
526         TBMModuleData *initdata;
527         ModuleInitProc init;
528         void *module_data;
529
530         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
531
532         module_data = dlopen(path, RTLD_LAZY);
533         if (!module_data) {
534                 TBM_LOG_E("failed to load module: %s(%s)\n", dlerror(), file);
535                 return 0;
536         }
537
538         initdata = dlsym(module_data, "tbmModuleData");
539         if (!initdata) {
540                 TBM_LOG_E("Error: module does not have data object.\n");
541                 goto err;
542         }
543
544         vers = initdata->vers;
545         if (!vers) {
546                 TBM_LOG_E("Error: module does not supply version information.\n");
547                 goto err;
548         }
549
550         init = initdata->init;
551         if (!init) {
552                 TBM_LOG_E("Error: module does not supply init symbol.\n");
553                 goto err;
554         }
555
556         if (!_check_version(vers)) {
557                 TBM_LOG_E("Fail to check version.\n");
558                 goto err;
559         }
560
561         if (!init(bufmgr, fd)) {
562                 TBM_LOG_E("Fail to init module(%s)\n", file);
563                 goto err;
564         }
565
566         if (!bufmgr->backend || !bufmgr->backend->priv) {
567                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
568                 goto err;
569         }
570
571         bufmgr->module_data = module_data;
572
573         TBM_DBG("Success to load module(%s)\n", file);
574
575         return 1;
576
577 err:
578         dlclose(module_data);
579         return 0;
580 }
581
582 static int
583 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
584 {
585         struct dirent **namelist;
586         int ret = 0, n;
587
588         /* load bufmgr priv from default lib */
589         if (_tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB))
590                 return 1;
591
592         /* load bufmgr priv from configured path */
593         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
594         if (n < 0) {
595                 TBM_LOG_E("no files : %s\n", BUFMGR_MODULE_DIR);
596                 return 0;
597         }
598
599         while (n--) {
600                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
601                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
602
603                         if (p && !strcmp(p, SUFFIX_LIB))
604                                 ret = _tbm_bufmgr_load_module(bufmgr, fd,
605                                                         namelist[n]->d_name);
606                 }
607
608                 free(namelist[n]);
609         }
610
611         free(namelist);
612
613         return ret;
614 }
615 /* LCOV_EXCL_STOP */
616
617 tbm_bufmgr
618 tbm_bufmgr_init(int fd)
619 {
620 #ifdef TBM_BUFMGR_INIT_TIME
621         struct timeval start_tv, end_tv;
622 #endif
623         char *env;
624
625 #ifdef TBM_BUFMGR_INIT_TIME
626         /* get the start tv */
627         gettimeofday(&start_tv, NULL);
628 #endif
629
630         /* LCOV_EXCL_START */
631 #ifdef HAVE_DLOG
632         env = getenv("TBM_DLOG");
633         if (env) {
634                 bDlog = atoi(env);
635                 TBM_LOG_D("TBM_DLOG=%s\n", env);
636         } else
637                 bDlog = 1;
638 #endif
639
640 #ifdef DEBUG
641         env = getenv("TBM_DEBUG");
642         if (env) {
643                 bDebug = atoi(env);
644                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
645         } else
646                 bDebug = 0;
647 #endif
648
649 #ifdef TRACE
650         env = getenv("TBM_TRACE");
651         if (env) {
652                 bTrace = atoi(env);
653                 TBM_LOG_D("TBM_TRACE=%s\n", env);
654         } else
655                 bTrace = 0;
656 #endif
657
658         pthread_mutex_lock(&gLock);
659
660         if (fd >= 0) {
661                 TBM_LOG_W("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
662                 TBM_LOG_W("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
663         }
664
665
666         /* initialize buffer manager */
667         if (gBufMgr) {
668                 gBufMgr->ref_count++;
669                 TBM_TRACE("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
670                 pthread_mutex_unlock(&gLock);
671                 return gBufMgr;
672         }
673
674         TBM_DBG("bufmgr init\n");
675
676         /* allocate bufmgr */
677         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
678         if (!gBufMgr) {
679                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
680                 TBM_TRACE("error: fail to alloc bufmgr fd(%d)\n", fd);
681                 pthread_mutex_unlock(&gLock);
682                 return NULL;
683         }
684
685         gBufMgr->fd = fd;
686
687         /* load bufmgr priv from env */
688         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
689                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
690                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
691                 free(gBufMgr);
692                 gBufMgr = NULL;
693                 pthread_mutex_unlock(&gLock);
694                 return NULL;
695
696         }
697         /* LCOV_EXCL_STOP */
698
699         /* log for tbm backend_flag */
700         TBM_DBG("backend flag:%x:", gBufMgr->backend->flags);
701         TBM_DBG("\n");
702
703         gBufMgr->ref_count = 1;
704
705         TBM_DBG("create tizen bufmgr:%p ref_count:%d\n",
706             gBufMgr, gBufMgr->ref_count);
707
708         /* setup the lock_type */
709         env = getenv("BUFMGR_LOCK_TYPE");
710         if (env && !strcmp(env, "always"))
711                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
712         else if (env && !strcmp(env, "none"))
713                 gBufMgr->lock_type = LOCK_TRY_NEVER;
714         else if (env && !strcmp(env, "once"))
715                 gBufMgr->lock_type = LOCK_TRY_ONCE;
716         else
717                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
718
719         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
720
721         TBM_TRACE("create tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, fd);
722
723         /* intialize bo_list */
724         LIST_INITHEAD(&gBufMgr->bo_list);
725
726         /* intialize surf_list */
727         LIST_INITHEAD(&gBufMgr->surf_list);
728
729         /* intialize surf_queue_list */
730         LIST_INITHEAD(&gBufMgr->surf_queue_list);
731
732         /* intialize debug_key_list */
733         LIST_INITHEAD(&gBufMgr->debug_key_list);
734
735 #ifdef TBM_BUFMGR_INIT_TIME
736         /* get the end tv */
737         gettimeofday(&end_tv, NULL);
738         TBM_LOG_I("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)));
739 #endif
740
741         pthread_mutex_unlock(&gLock);
742
743         return gBufMgr;
744 }
745
746 void
747 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
748 {
749         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
750
751         _tbm_bufmgr_mutex_lock();
752         pthread_mutex_lock(&gLock);
753
754         if (!gBufMgr) {
755                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
756                 pthread_mutex_unlock(&gLock);
757                 _tbm_bufmgr_mutex_unlock();
758                 return;
759         }
760
761         bufmgr->ref_count--;
762         if (bufmgr->ref_count > 0) {
763                 TBM_TRACE("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
764                 pthread_mutex_unlock(&gLock);
765                 _tbm_bufmgr_mutex_unlock();
766                 return;
767         }
768
769         /* destroy bo_list */
770         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
771                 tbm_bo bo = NULL, tmp;
772
773                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
774                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
775                         _tbm_bo_free(bo);
776                 }
777         }
778
779         /* destroy surf_list */
780         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
781                 tbm_surface_h surf = NULL, tmp;
782
783                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
784                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
785                         tbm_surface_destroy(surf);
786                 }
787         }
788
789         /* destroy bufmgr priv */
790         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
791         bufmgr->backend->priv = NULL;
792         tbm_backend_free(bufmgr->backend);
793         bufmgr->backend = NULL;
794
795         TBM_TRACE("destroy tbm_bufmgr(%p)\n", bufmgr);
796
797         dlclose(bufmgr->module_data);
798
799         if (bufmgr->fd > 0)
800                 close(bufmgr->fd);
801
802         free(bufmgr);
803         gBufMgr = NULL;
804
805         pthread_mutex_unlock(&gLock);
806         _tbm_bufmgr_mutex_unlock();
807 }
808
809 int
810 tbm_bo_size(tbm_bo bo)
811 {
812         tbm_bufmgr bufmgr = gBufMgr;
813         int size;
814
815         _tbm_bufmgr_mutex_lock();
816
817         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
818         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
819
820         size = bufmgr->backend->bo_size(bo);
821
822         TBM_TRACE("bo(%p) size(%d)\n", bo, size);
823
824         _tbm_bufmgr_mutex_unlock();
825
826         return size;
827 }
828
829 tbm_bo
830 tbm_bo_ref(tbm_bo bo)
831 {
832         _tbm_bufmgr_mutex_lock();
833
834         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
835         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
836
837         bo->ref_cnt++;
838
839         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt);
840
841         _tbm_bufmgr_mutex_unlock();
842
843         return bo;
844 }
845
846 void
847 tbm_bo_unref(tbm_bo bo)
848 {
849         _tbm_bufmgr_mutex_lock();
850
851         TBM_BUFMGR_RETURN_IF_FAIL(gBufMgr);
852         TBM_BUFMGR_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
853
854         TBM_TRACE("bo(%p) ref_cnt(%d)\n", bo, bo->ref_cnt - 1);
855
856         if (bo->ref_cnt <= 0) {
857                 _tbm_bufmgr_mutex_unlock();
858                 return;
859         }
860
861         bo->ref_cnt--;
862         if (bo->ref_cnt == 0)
863                 _tbm_bo_free(bo);
864
865         _tbm_bufmgr_mutex_unlock();
866 }
867
868 tbm_bo
869 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
870 {
871         void *bo_priv;
872         tbm_bo bo;
873
874         _tbm_bufmgr_mutex_lock();
875
876         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
877         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
878         TBM_BUFMGR_RETURN_VAL_IF_FAIL(size > 0, NULL);
879
880         bo = calloc(1, sizeof(struct _tbm_bo));
881         if (!bo) {
882                 /* LCOV_EXCL_START */
883                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
884                                 size, _tbm_flag_to_str(flags));
885                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
886                 _tbm_bufmgr_mutex_unlock();
887                 return NULL;
888                 /* LCOV_EXCL_STOP */
889         }
890
891         _tbm_util_check_bo_cnt(bufmgr);
892
893         bo->bufmgr = bufmgr;
894
895         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
896         if (!bo_priv) {
897                 /* LCOV_EXCL_START */
898                 TBM_LOG_E("error: fail to create of tbm_bo size(%d) flag(%s)\n",
899                                 size, _tbm_flag_to_str(flags));
900                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
901                 free(bo);
902                 _tbm_bufmgr_mutex_unlock();
903                 return NULL;
904                 /* LCOV_EXCL_STOP */
905         }
906
907         bufmgr->bo_cnt++;
908
909         bo->ref_cnt = 1;
910         bo->flags = flags;
911         bo->priv = bo_priv;
912
913         TBM_TRACE("bo(%p) size(%d) refcnt(%d), flag(%s)\n", bo, size, bo->ref_cnt,
914                         _tbm_flag_to_str(bo->flags));
915
916         LIST_INITHEAD(&bo->user_data_list);
917
918         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
919
920         _tbm_bufmgr_mutex_unlock();
921
922         return bo;
923 }
924
925 tbm_bo
926 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
927 {
928         void *bo_priv;
929         tbm_bo bo;
930
931         _tbm_bufmgr_mutex_lock();
932
933         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
934         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
935
936         if (!bufmgr->backend->bo_import) {
937                 /* LCOV_EXCL_START */
938                 _tbm_bufmgr_mutex_unlock();
939                 return NULL;
940                 /* LCOV_EXCL_STOP */
941         }
942
943         _tbm_util_check_bo_cnt(bufmgr);
944
945         bo = calloc(1, sizeof(struct _tbm_bo));
946         if (!bo) {
947                 /* LCOV_EXCL_START */
948                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
949                 _tbm_bufmgr_mutex_unlock();
950                 return NULL;
951                 /* LCOV_EXCL_STOP */
952         }
953
954         bo->bufmgr = bufmgr;
955
956         bo_priv = bufmgr->backend->bo_import(bo, key);
957         if (!bo_priv) {
958                 /* LCOV_EXCL_START */
959                 TBM_LOG_E("error: fail to import of tbm_bo by key(%d)\n", key);
960                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
961                 free(bo);
962                 _tbm_bufmgr_mutex_unlock();
963                 return NULL;
964                 /* LCOV_EXCL_STOP */
965         }
966
967         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
968                 tbm_bo bo2 = NULL;
969
970                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
971                         if (bo2->priv == bo_priv) {
972                                 TBM_TRACE("find bo(%p) ref(%d) key(%d) flag(%s) in list\n",
973                                                 bo2, bo2->ref_cnt, key,
974                                                 _tbm_flag_to_str(bo2->flags));
975                                 bo2->ref_cnt++;
976                                 free(bo);
977                                 _tbm_bufmgr_mutex_unlock();
978                                 return bo2;
979                         }
980                 }
981         }
982
983         bufmgr->bo_cnt++;
984
985         bo->ref_cnt = 1;
986         bo->priv = bo_priv;
987
988         if (bufmgr->backend->bo_get_flags)
989                 bo->flags = bufmgr->backend->bo_get_flags(bo);
990         else
991                 bo->flags = TBM_BO_DEFAULT;
992
993         TBM_TRACE("import new bo(%p) ref(%d) key(%d) flag(%s) in list\n",
994                           bo, bo->ref_cnt, key, _tbm_flag_to_str(bo->flags));
995
996         LIST_INITHEAD(&bo->user_data_list);
997
998         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
999
1000         _tbm_bufmgr_mutex_unlock();
1001
1002         return bo;
1003 }
1004
1005 tbm_bo
1006 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
1007 {
1008         void *bo_priv;
1009         tbm_bo bo;
1010
1011         _tbm_bufmgr_mutex_lock();
1012
1013         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1014         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
1015
1016         if (!bufmgr->backend->bo_import_fd) {
1017                 /* LCOV_EXCL_START */
1018                 _tbm_bufmgr_mutex_unlock();
1019                 return NULL;
1020                 /* LCOV_EXCL_STOP */
1021         }
1022
1023         _tbm_util_check_bo_cnt(bufmgr);
1024
1025         bo = calloc(1, sizeof(struct _tbm_bo));
1026         if (!bo) {
1027                 /* LCOV_EXCL_START */
1028                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1029                 _tbm_bufmgr_mutex_unlock();
1030                 return NULL;
1031                 /* LCOV_EXCL_STOP */
1032         }
1033
1034         bo->bufmgr = bufmgr;
1035
1036         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
1037         if (!bo_priv) {
1038                 /* LCOV_EXCL_START */
1039                 TBM_LOG_E("error: fail to import tbm_bo by tbm_fd(%d)\n", fd);
1040                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
1041                 free(bo);
1042                 _tbm_bufmgr_mutex_unlock();
1043                 return NULL;
1044                 /* LCOV_EXCL_STOP */
1045         }
1046
1047         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1048                 tbm_bo bo2 = NULL;
1049
1050                 LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
1051                         if (bo2->priv == bo_priv) {
1052                                 TBM_TRACE("find bo(%p) ref(%d) fd(%d) flag(%s) in list\n",
1053                                                 bo2, bo2->ref_cnt, fd,
1054                                                 _tbm_flag_to_str(bo2->flags));
1055                                 bo2->ref_cnt++;
1056                                 free(bo);
1057                                 _tbm_bufmgr_mutex_unlock();
1058                                 return bo2;
1059                         }
1060                 }
1061         }
1062
1063         bufmgr->bo_cnt++;
1064
1065         bo->ref_cnt = 1;
1066         bo->priv = bo_priv;
1067
1068         if (bufmgr->backend->bo_get_flags)
1069                 bo->flags = bufmgr->backend->bo_get_flags(bo);
1070         else
1071                 bo->flags = TBM_BO_DEFAULT;
1072
1073         TBM_TRACE("import bo(%p) ref(%d) fd(%d) flag(%s)\n",
1074                         bo, bo->ref_cnt, fd, _tbm_flag_to_str(bo->flags));
1075
1076         LIST_INITHEAD(&bo->user_data_list);
1077
1078         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
1079
1080         _tbm_bufmgr_mutex_unlock();
1081
1082         return bo;
1083 }
1084
1085 tbm_key
1086 tbm_bo_export(tbm_bo bo)
1087 {
1088         tbm_bufmgr bufmgr = gBufMgr;
1089         tbm_key ret;
1090
1091         _tbm_bufmgr_mutex_lock();
1092
1093         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1094         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1095
1096         if (!bufmgr->backend->bo_export) {
1097                 /* LCOV_EXCL_START */
1098                 _tbm_bufmgr_mutex_unlock();
1099                 return 0;
1100                 /* LCOV_EXCL_STOP */
1101         }
1102
1103         ret = bufmgr->backend->bo_export(bo);
1104         if (!ret) {
1105                 /* LCOV_EXCL_START */
1106                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
1107                 TBM_LOG_E("error: bo(%p) tbm_key(%d)\n", bo, ret);
1108                 _tbm_bufmgr_mutex_unlock();
1109                 return ret;
1110                 /* LCOV_EXCL_STOP */
1111         }
1112
1113         TBM_TRACE("bo(%p) tbm_key(%u)\n", bo, ret);
1114
1115         _tbm_bufmgr_mutex_unlock();
1116
1117         return ret;
1118 }
1119
1120 tbm_fd
1121 tbm_bo_export_fd(tbm_bo bo)
1122 {
1123         tbm_bufmgr bufmgr = gBufMgr;
1124         tbm_fd ret;
1125
1126         _tbm_bufmgr_mutex_lock();
1127
1128         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), -1);
1129         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
1130
1131         if (!bufmgr->backend->bo_export_fd) {
1132                 /* LCOV_EXCL_START */
1133                 _tbm_bufmgr_mutex_unlock();
1134                 return -1;
1135                 /* LCOV_EXCL_STOP */
1136         }
1137
1138         ret = bufmgr->backend->bo_export_fd(bo);
1139         if (ret < 0) {
1140                 /* LCOV_EXCL_START */
1141                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
1142                 TBM_LOG_E("error: bo(%p) tbm_fd(%d)\n", bo, ret);
1143                 _tbm_bufmgr_mutex_unlock();
1144                 return ret;
1145                 /* LCOV_EXCL_STOP */
1146         }
1147
1148         TBM_TRACE("bo(%p) tbm_fd(%d)\n", bo, ret);
1149
1150         _tbm_bufmgr_mutex_unlock();
1151
1152         return ret;
1153 }
1154
1155 tbm_bo_handle
1156 tbm_bo_get_handle(tbm_bo bo, int device)
1157 {
1158         tbm_bufmgr bufmgr = gBufMgr;
1159         tbm_bo_handle bo_handle;
1160
1161         _tbm_bufmgr_mutex_lock();
1162
1163         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1164         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1165
1166         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
1167         if (bo_handle.ptr == NULL) {
1168                 /* LCOV_EXCL_START */
1169                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
1170                 TBM_LOG_E("error: bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1171                 _tbm_bufmgr_mutex_unlock();
1172                 return (tbm_bo_handle) NULL;
1173                 /* LCOV_EXCL_STOP */
1174         }
1175
1176         TBM_TRACE("bo(%p) bo_handle(%p)\n", bo, bo_handle.ptr);
1177
1178         _tbm_bufmgr_mutex_unlock();
1179
1180         return bo_handle;
1181 }
1182
1183 tbm_bo_handle
1184 tbm_bo_map(tbm_bo bo, int device, int opt)
1185 {
1186         tbm_bufmgr bufmgr = gBufMgr;
1187         tbm_bo_handle bo_handle;
1188
1189         _tbm_bufmgr_mutex_lock();
1190
1191         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), (tbm_bo_handle) NULL);
1192         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) NULL);
1193
1194         if (!_tbm_bo_lock(bo, device, opt)) {
1195                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
1196                 TBM_LOG_E("error: fail to lock bo:%p)\n", bo);
1197                 _tbm_bufmgr_mutex_unlock();
1198                 return (tbm_bo_handle) NULL;
1199         }
1200
1201         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
1202         if (bo_handle.ptr == NULL) {
1203                 /* LCOV_EXCL_START */
1204                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
1205                 TBM_LOG_E("error: fail to map bo:%p\n", bo);
1206                 _tbm_bo_unlock(bo);
1207                 _tbm_bufmgr_mutex_unlock();
1208                 return (tbm_bo_handle) NULL;
1209                 /* LCOV_EXCL_STOP */
1210         }
1211
1212         /* increase the map_count */
1213         bo->map_cnt++;
1214
1215         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1216
1217         _tbm_bufmgr_mutex_unlock();
1218
1219         return bo_handle;
1220 }
1221
1222 int
1223 tbm_bo_unmap(tbm_bo bo)
1224 {
1225         tbm_bufmgr bufmgr = gBufMgr;
1226         int ret;
1227
1228         _tbm_bufmgr_mutex_lock();
1229
1230         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1231         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1232
1233         ret = bufmgr->backend->bo_unmap(bo);
1234         if (!ret) {
1235                 /* LCOV_EXCL_START */
1236                 TBM_LOG_E("error: bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1237                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1238                 _tbm_bufmgr_mutex_unlock();
1239                 return ret;
1240                 /* LCOV_EXCL_STOP */
1241         }
1242
1243         /* decrease the map_count */
1244         bo->map_cnt--;
1245
1246         TBM_TRACE("bo(%p) map_cnt(%d)\n", bo, bo->map_cnt);
1247
1248         _tbm_bo_unlock(bo);
1249
1250         _tbm_bufmgr_mutex_unlock();
1251
1252         return ret;
1253 }
1254
1255 int
1256 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1257 {
1258         tbm_bufmgr bufmgr = gBufMgr;
1259         void *temp;
1260
1261         _tbm_bufmgr_mutex_lock();
1262
1263         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1264         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1265         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1266
1267         TBM_TRACE("before: bo1(%p) bo2(%p)\n", bo1, bo2);
1268
1269         if (bufmgr->backend->bo_size(bo1) != bufmgr->backend->bo_size(bo2)) {
1270                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1271                 TBM_LOG_E("error: bo1(%p) bo2(%p)\n", bo1, bo2);
1272                 _tbm_bufmgr_mutex_unlock();
1273                 return 0;
1274         }
1275
1276         TBM_TRACE("after: bo1(%p) bo2(%p)\n", bo1, bo2);
1277
1278         temp = bo1->priv;
1279         bo1->priv = bo2->priv;
1280         bo2->priv = temp;
1281
1282         _tbm_bufmgr_mutex_unlock();
1283
1284         return 1;
1285 }
1286
1287 int
1288 tbm_bo_locked(tbm_bo bo)
1289 {
1290         tbm_bufmgr bufmgr = gBufMgr;
1291
1292         _tbm_bufmgr_mutex_lock();
1293
1294         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1295         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1296
1297         if (bufmgr->lock_type == LOCK_TRY_NEVER) {
1298                 TBM_LOG_E("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1299                 _tbm_bufmgr_mutex_unlock();
1300                 return 0;
1301         }
1302
1303         if (bo->lock_cnt > 0) {
1304                 TBM_TRACE("error: bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1305                 _tbm_bufmgr_mutex_unlock();
1306                 return 1;
1307         }
1308
1309         TBM_TRACE("bo(%p) lock_cnt(%d)\n", bo, bo->lock_cnt);
1310         _tbm_bufmgr_mutex_unlock();
1311
1312         return 0;
1313 }
1314
1315 int
1316 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1317                      tbm_data_free data_free_func)
1318 {
1319         tbm_user_data *data;
1320
1321         _tbm_bufmgr_mutex_lock();
1322
1323         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1324         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1325
1326         /* check if the data according to the key exist if so, return false. */
1327         data = user_data_lookup(&bo->user_data_list, key);
1328         if (data) {
1329                 TBM_TRACE("warning: user data already exist key(%ld)\n", key);
1330                 _tbm_bufmgr_mutex_unlock();
1331                 return 0;
1332         }
1333
1334         data = user_data_create(key, data_free_func);
1335         if (!data) {
1336                 TBM_LOG_E("error: bo(%p) key(%lu)\n", bo, key);
1337                 _tbm_bufmgr_mutex_unlock();
1338                 return 0;
1339         }
1340
1341         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, data->data);
1342
1343         LIST_ADD(&data->item_link, &bo->user_data_list);
1344
1345         _tbm_bufmgr_mutex_unlock();
1346
1347         return 1;
1348 }
1349
1350 int
1351 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1352 {
1353         tbm_user_data *old_data;
1354
1355         _tbm_bufmgr_mutex_lock();
1356
1357         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1358         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1359
1360         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1361                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1362                 _tbm_bufmgr_mutex_unlock();
1363                 return 0;
1364         }
1365
1366         old_data = user_data_lookup(&bo->user_data_list, key);
1367         if (!old_data) {
1368                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1369                 _tbm_bufmgr_mutex_unlock();
1370                 return 0;
1371         }
1372
1373         if (old_data->data && old_data->free_func)
1374                 old_data->free_func(old_data->data);
1375         old_data->data = data;
1376
1377         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1378
1379         _tbm_bufmgr_mutex_unlock();
1380
1381         return 1;
1382 }
1383
1384 int
1385 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1386 {
1387         tbm_user_data *old_data;
1388
1389         _tbm_bufmgr_mutex_lock();
1390
1391         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1392         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1393
1394         if (!data || LIST_IS_EMPTY(&bo->user_data_list)) {
1395                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1396                 _tbm_bufmgr_mutex_unlock();
1397                 return 0;
1398         }
1399
1400         old_data = user_data_lookup(&bo->user_data_list, key);
1401         if (!old_data) {
1402                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1403                 *data = NULL;
1404                 _tbm_bufmgr_mutex_unlock();
1405                 return 0;
1406         }
1407
1408         *data = old_data->data;
1409
1410         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1411
1412         _tbm_bufmgr_mutex_unlock();
1413
1414         return 1;
1415 }
1416
1417 int
1418 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1419 {
1420         tbm_user_data *old_data;
1421
1422         _tbm_bufmgr_mutex_lock();
1423
1424         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1425         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1426
1427         if (LIST_IS_EMPTY(&bo->user_data_list)) {
1428                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1429                 _tbm_bufmgr_mutex_unlock();
1430                 return 0;
1431         }
1432
1433         old_data = user_data_lookup(&bo->user_data_list, key);
1434         if (!old_data) {
1435                 TBM_TRACE("error: bo(%p) key(%lu)\n", bo, key);
1436                 _tbm_bufmgr_mutex_unlock();
1437                 return 0;
1438         }
1439
1440         TBM_TRACE("bo(%p) key(%lu) data(%p)\n", bo, key, old_data->data);
1441
1442         user_data_delete(old_data);
1443
1444         _tbm_bufmgr_mutex_unlock();
1445
1446         return 1;
1447 }
1448
1449 unsigned int
1450 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1451 {
1452         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
1453
1454         _tbm_bufmgr_mutex_lock();
1455
1456         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
1457         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
1458
1459         TBM_TRACE("tbm_bufmgr(%p) capability(%u)\n", bufmgr, bufmgr->capabilities);
1460
1461         capabilities = bufmgr->capabilities;
1462
1463         _tbm_bufmgr_mutex_unlock();
1464
1465         return capabilities;
1466 }
1467
1468 int
1469 tbm_bo_get_flags(tbm_bo bo)
1470 {
1471         int flags;
1472
1473         _tbm_bufmgr_mutex_lock();
1474
1475         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1476         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1477
1478         flags = bo->flags;
1479
1480         TBM_TRACE("bo(%p)\n", bo);
1481
1482         _tbm_bufmgr_mutex_unlock();
1483
1484         return flags;
1485 }
1486
1487 /* LCOV_EXCL_START */
1488 tbm_error_e
1489 tbm_get_last_error(void)
1490 {
1491         return tbm_last_error;
1492 }
1493
1494 void
1495 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr, char *str, int *len)
1496 {
1497         char app_name[255] = {0,}, title[512] = {0,};
1498         tbm_surface_debug_data *debug_old_data = NULL;
1499
1500         pthread_mutex_lock(&gLock);
1501
1502         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
1503                 TBM_LOG_E("invalid bufmgr\n");
1504                 pthread_mutex_unlock(&gLock);
1505                 return;
1506         }
1507
1508         TBM_SNPRINTF(str, len, "\n");
1509         _tbm_util_get_appname_from_pid(getpid(), app_name);
1510         _tbm_util_get_appname_brief(app_name);
1511         TBM_SNPRINTF(str, len, "============TBM DEBUG: %s(%d)===========================\n",
1512                   app_name, getpid());
1513
1514         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags  format    app_name       ");
1515
1516         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1517                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1518                         strncat(title, "  ", 3);
1519                         strncat(title, debug_old_data->key, strlen(debug_old_data->key) + 1);
1520                 }
1521         }
1522
1523         TBM_SNPRINTF(str, len, "[tbm_surface information]\n");
1524         TBM_SNPRINTF(str, len, "%s\n", title);
1525
1526         /* show the tbm_surface information in surf_list */
1527         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1528                 tbm_surface_h surf = NULL;
1529                 int surf_cnt = 0;
1530
1531                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
1532                         char data[512] = {0,};
1533                         unsigned int pid;
1534                         int i;
1535
1536                         pid = _tbm_surface_internal_get_debug_pid(surf);
1537                         if (!pid) {
1538                                 /* if pid is null, set the self_pid */
1539                                 pid = getpid();
1540                         }
1541
1542                         memset(app_name, 0x0, 255 * sizeof(char));
1543                         _tbm_util_get_appname_from_pid(pid, app_name);
1544                         _tbm_util_get_appname_brief(app_name);
1545
1546                         snprintf(data, 255, "%-2d  %-9p    %-4d  %-5u  %-6u  %-3u  %-6u   %-2d   %-2d    %-3d  %-8s  %-15s",
1547                                   ++surf_cnt,
1548                                   surf,
1549                                   surf->refcnt,
1550                                   surf->info.width,
1551                                   surf->info.height,
1552                                   surf->info.bpp,
1553                                   surf->info.size / 1024,
1554                                   surf->num_bos,
1555                                   surf->num_planes,
1556                                   surf->flags,
1557                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
1558                                   app_name);
1559
1560                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
1561                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
1562                                         char *value;
1563
1564                                         strncat(data, "  ", 3);
1565
1566                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
1567                                         if (value)
1568                                                 strncat(data, value, strlen(value) + 1);
1569                                         else
1570                                                 strncat(data, "none", 5);
1571                                 }
1572                         }
1573                         TBM_SNPRINTF(str, len, "%s\n", data);
1574
1575                         for (i = 0; i < surf->num_bos; i++) {
1576                                 TBM_SNPRINTF(str, len, " bo:%-12p  %-26d%-10d\n",
1577                                           surf->bos[i],
1578                                           surf->bos[i]->ref_cnt,
1579                                           bufmgr->backend->bo_size(surf->bos[i]) / 1024);
1580                         }
1581                 }
1582         } else
1583                 TBM_SNPRINTF(str, len, " no tbm_surfaces.\n");
1584         TBM_SNPRINTF(str, len, "\n");
1585
1586         TBM_SNPRINTF(str, len, "[tbm_bo information]\n");
1587         TBM_SNPRINTF(str, len, "no  bo          refcnt  size    lock_cnt  map_cnt  flags  surface\n");
1588
1589         /* show the tbm_bo information in bo_list */
1590         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1591                 int bo_cnt = 0;
1592                 tbm_bo bo = NULL;
1593
1594                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
1595                         TBM_SNPRINTF(str, len, "%-4d%-11p   %-4d  %-6d     %-5d     %-4u    %-3d  %-11p\n",
1596                                   ++bo_cnt,
1597                                   bo,
1598                                   bo->ref_cnt,
1599                                   bufmgr->backend->bo_size(bo) / 1024,
1600                                   bo->lock_cnt,
1601                                   bo->map_cnt,
1602                                   bo->flags,
1603                                   bo->surface);
1604                 }
1605         } else
1606                 TBM_SNPRINTF(str, len, "no tbm_bos.\n");
1607         TBM_SNPRINTF(str, len, "\n");
1608
1609         TBM_SNPRINTF(str, len, "===============================================================\n");
1610
1611         pthread_mutex_unlock(&gLock);
1612 }
1613
1614 void
1615 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1616 {
1617         char str[1024*4];
1618         int len = sizeof(str);
1619         tbm_bufmgr_debug_tbm_info_get(bufmgr, str, &len);
1620         TBM_DEBUG("     %s", str);
1621 }
1622
1623 void
1624 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1625 {
1626         _tbm_bufmgr_mutex_lock();
1627
1628         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
1629         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
1630
1631 #ifdef TRACE
1632         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1633         bTrace = onoff;
1634 #endif
1635
1636         _tbm_bufmgr_mutex_unlock();
1637 }
1638
1639 void
1640 tbm_bufmgr_debug_dump_set_scale(double scale)
1641 {
1642         pthread_mutex_lock(&gLock);
1643         scale_factor = scale;
1644         pthread_mutex_unlock(&gLock);
1645 }
1646
1647 int
1648 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
1649 {
1650         pthread_mutex_lock(&gLock);
1651
1652         if (onoff == 0) {
1653                 TBM_LOG_D("count=%d onoff=%d\n", count, onoff);
1654                 b_dump_queue = 0;
1655                 tbm_surface_internal_dump_end();
1656         } else {
1657                 int w, h;
1658
1659                 if (path == NULL) {
1660                         TBM_LOG_E("path is null");
1661                         pthread_mutex_unlock(&gLock);
1662                         return 0;
1663                 }
1664                 TBM_LOG_D("path=%s count=%d onoff=%d\n", path, count, onoff);
1665
1666                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
1667                         TBM_LOG_E("Fail to get tbm_surface size.\n");
1668                         pthread_mutex_unlock(&gLock);
1669                         return 0;
1670                 }
1671
1672                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1673                 scale_factor = 0;
1674
1675                 b_dump_queue = 1;
1676         }
1677
1678         pthread_mutex_unlock(&gLock);
1679         return 1;
1680 }
1681
1682 int
1683 tbm_bufmgr_debug_dump_all(char *path)
1684 {
1685         int w, h, count = 0;
1686         tbm_surface_h surface = NULL;
1687
1688         TBM_RETURN_VAL_IF_FAIL(path != NULL, 0);
1689         TBM_LOG_D("path=%s\n", path);
1690
1691         pthread_mutex_lock(&gLock);
1692
1693         count = _tbm_util_get_max_surface_size(&w, &h);
1694         if (count == 0) {
1695                 TBM_LOG_E("No tbm_surface.\n");
1696                 pthread_mutex_unlock(&gLock);
1697                 return 1;
1698         }
1699
1700         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
1701         scale_factor = 0;
1702
1703         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
1704                 tbm_surface_internal_dump_buffer(surface, "dump_all");
1705
1706         tbm_surface_internal_dump_end();
1707
1708         pthread_mutex_unlock(&gLock);
1709
1710         return 1;
1711 }
1712
1713 /* internal function */
1714 tbm_bufmgr
1715 _tbm_bufmgr_get_bufmgr(void)
1716 {
1717         return gBufMgr;
1718 }
1719
1720 int
1721 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1722 {
1723         _tbm_bufmgr_mutex_lock();
1724
1725         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1726         TBM_BUFMGR_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1727
1728         bo->surface = surface;
1729
1730         _tbm_bufmgr_mutex_unlock();
1731
1732         return 1;
1733 }
1734
1735 int
1736 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1737 {
1738         int ret;
1739
1740         _tbm_bufmgr_mutex_lock();
1741
1742         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
1743
1744         if (!bufmgr->backend->bufmgr_bind_native_display) {
1745                 TBM_TRACE("skip: tbm_bufmgr(%p) NativeDisplay(%p)\n",
1746                                 bufmgr, NativeDisplay);
1747                 _tbm_bufmgr_mutex_unlock();
1748                 return 1;
1749         }
1750
1751         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1752         if (!ret) {
1753                 TBM_LOG_E("error: tbm_bufmgr(%p) NativeDisplay(%p)\n",
1754                                 bufmgr, NativeDisplay);
1755                 _tbm_bufmgr_mutex_unlock();
1756                 return 0;
1757         }
1758
1759         TBM_TRACE("tbm_bufmgr(%p) NativeDisplay(%p)\n", bufmgr, NativeDisplay);
1760
1761         _tbm_bufmgr_mutex_unlock();
1762
1763         return 1;
1764 }
1765
1766 int tbm_bufmgr_get_fd_limit(void)
1767 {
1768         struct rlimit lim;
1769
1770         if (getrlimit(RLIMIT_NOFILE, &lim))
1771                 return 1024;
1772
1773         return (int)lim.rlim_cur;
1774 }
1775 /* LCOV_EXCL_STOP */