494c07a0d10be293cf01e0fc08c67f89e8173123
[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 #ifdef DEBUG
40 int bDebug;
41 #endif
42
43 #ifdef HAVE_DLOG
44 int bDlog;
45 #endif
46
47 #define PREFIX_LIB    "libtbm_"
48 #define SUFFIX_LIB    ".so"
49 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
50
51 /* values to indicate unspecified fields in XF86ModReqInfo. */
52 #define MAJOR_UNSPEC        0xFF
53 #define MINOR_UNSPEC        0xFF
54 #define PATCH_UNSPEC        0xFFFF
55 #define ABI_VERS_UNSPEC   0xFFFFFFFF
56
57 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
58                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
59 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
60 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
61 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
62
63 enum {
64         LOCK_TRY_ONCE,
65         LOCK_TRY_ALWAYS,
66         LOCK_TRY_NEVER
67 };
68
69 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
70 tbm_bufmgr gBufMgr;
71
72 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
73
74 static void
75 _tbm_set_last_result(tbm_error_e err)
76 {
77         tbm_last_error = err;
78 }
79
80 /* LCOV_EXCL_START */
81 static int last_chk_bo_cnt = 0;
82 static void
83 _tbm_util_check_bo_cnt(tbm_bufmgr bufmgr)
84 {
85         if (bufmgr->bo_cnt >= 500 && ((bufmgr->bo_cnt % 20) == 0)) {
86                 if (bufmgr->bo_cnt > last_chk_bo_cnt) {
87                         TBM_DEBUG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
88                         tbm_bufmgr_debug_show(bufmgr);
89                         last_chk_bo_cnt = bufmgr->bo_cnt;
90                 }
91         }
92 }
93
94 static void
95 _tbm_util_get_appname_brief(char *brief)
96 {
97         char delim[] = "/";
98         char *token = NULL;
99         char temp[255] = {0,};
100         char *saveptr = NULL;
101
102         token = strtok_r(brief, delim, &saveptr);
103
104         while (token != NULL) {
105                 memset(temp, 0x00, 255 * sizeof(char));
106                 strncpy(temp, token, 254 * sizeof(char));
107                 token = strtok_r(NULL, delim, &saveptr);
108         }
109
110         snprintf(brief, sizeof(temp), "%s", temp);
111 }
112
113 static void
114 _tbm_util_get_appname_from_pid(long pid, char *str)
115 {
116         FILE *fp;
117         int len;
118         long app_pid = pid;
119         char fn_cmdline[255] = {0,};
120         char cmdline[255] = {0,};
121
122         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
123
124         fp = fopen(fn_cmdline, "r");
125         if (fp == 0) {
126                 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
127                 return;
128         }
129
130         if (!fgets(cmdline, 255, fp)) {
131                 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
132                 fclose(fp);
133                 return;
134         }
135         fclose(fp);
136
137         len = strlen(cmdline);
138         if (len < 1)
139                 memset(cmdline, 0x00, 255);
140         else
141                 cmdline[len] = 0;
142
143         snprintf(str, sizeof(cmdline), "%s", cmdline);
144 }
145 /* LCOV_EXCL_STOP */
146
147 tbm_user_data
148 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
149 {
150         tbm_user_data *user_data = NULL;
151         tbm_user_data *old_data = NULL, *tmp = NULL;
152
153         if (!LIST_IS_EMPTY(user_data_list)) {
154                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
155                         if (old_data->key == key) {
156                                 user_data = old_data;
157                                 return user_data;
158                         }
159                 }
160         }
161
162         return user_data;
163 }
164
165 tbm_user_data
166 *user_data_create(unsigned long key, tbm_data_free data_free_func)
167 {
168         tbm_user_data *user_data = NULL;
169
170         user_data = calloc(1, sizeof(tbm_user_data));
171         if (!user_data)
172                 return NULL;
173
174         user_data->key = key;
175         user_data->free_func = data_free_func;
176         user_data->data = (void *)0;
177
178         return user_data;
179 }
180
181 void
182 user_data_delete(tbm_user_data *user_data)
183 {
184         if (user_data->data && user_data->free_func)
185                 user_data->free_func(user_data->data);
186
187         LIST_DEL(&user_data->item_link);
188
189         free(user_data);
190 }
191
192 static int
193 _bo_lock(tbm_bo bo, int device, int opt)
194 {
195         tbm_bufmgr bufmgr = bo->bufmgr;
196         int ret = 0;
197
198         if (bufmgr->backend->bo_lock)
199                 ret = bufmgr->backend->bo_lock(bo, device, opt);
200         else
201                 ret = 1;
202
203         return ret;
204 }
205
206 static void
207 _bo_unlock(tbm_bo bo)
208 {
209         tbm_bufmgr bufmgr = bo->bufmgr;
210
211         if (bufmgr->backend->bo_unlock)
212                 bufmgr->backend->bo_unlock(bo);
213 }
214
215 static int
216 _tbm_bo_lock(tbm_bo bo, int device, int opt)
217 {
218         tbm_bufmgr bufmgr = NULL;
219         int old;
220         int ret = 0;
221
222         if (!bo)
223                 return 0;
224
225         bufmgr = bo->bufmgr;
226
227         /* do not try to lock the bo */
228         if (bufmgr->lock_type == LOCK_TRY_NEVER)
229                 return 1;
230
231         if (bo->lock_cnt < 0) {
232                 TBM_LOG_E("error bo:%p LOCK_CNT=%d\n",
233                         bo, bo->lock_cnt);
234         }
235
236         old = bo->lock_cnt;
237         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
238                 if (bo->lock_cnt == 0) {
239                         pthread_mutex_unlock(&bufmgr->lock);
240                         ret = _bo_lock(bo, device, opt);
241                         pthread_mutex_lock(&bufmgr->lock);
242                         if (ret)
243                                 bo->lock_cnt++;
244                 } else
245                         ret = 1;
246         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
247                 pthread_mutex_unlock(&bufmgr->lock);
248                 ret = _bo_lock(bo, device, opt);
249                 pthread_mutex_lock(&bufmgr->lock);
250                 if (ret)
251                         bo->lock_cnt++;
252         } else {
253                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
254                         bo);
255         }
256
257         DBG_LOCK(">> LOCK bo:%p(%d->%d)\n",
258                  bo, old, bo->lock_cnt);
259
260         return ret;
261 }
262
263 static void
264 _tbm_bo_unlock(tbm_bo bo)
265 {
266         tbm_bufmgr bufmgr = NULL;
267
268         int old;
269
270         if (!bo)
271                 return;
272
273         bufmgr = bo->bufmgr;
274
275         /* do not try to unlock the bo */
276         if (bufmgr->lock_type == LOCK_TRY_NEVER)
277                 return;
278
279         old = bo->lock_cnt;
280         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
281                 if (bo->lock_cnt > 0) {
282                         bo->lock_cnt--;
283                         if (bo->lock_cnt == 0)
284                                 _bo_unlock(bo);
285                 }
286         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
287                 if (bo->lock_cnt > 0) {
288                         bo->lock_cnt--;
289                         _bo_unlock(bo);
290                 }
291         } else {
292                 TBM_LOG_E("error bo:%p lock_type is wrong.\n",
293                         bo);
294         }
295
296         if (bo->lock_cnt < 0)
297                 bo->lock_cnt = 0;
298
299         DBG_LOCK(">> UNLOCK bo:%p(%d->%d)\n",
300                  bo, old, bo->lock_cnt);
301 }
302
303 static int
304 _tbm_bo_is_valid(tbm_bo bo)
305 {
306         tbm_bo old_data = NULL, tmp = NULL;
307
308         if (bo == NULL)
309                 return 0;
310
311         if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
312                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
313                         if (old_data == bo)
314                                 return 1;
315                 }
316
317         }
318         return 0;
319 }
320
321 static void
322 _tbm_bo_ref(tbm_bo bo)
323 {
324         bo->ref_cnt++;
325 }
326
327 static void
328 _tbm_bo_unref(tbm_bo bo)
329 {
330         tbm_bufmgr bufmgr = bo->bufmgr;
331         tbm_user_data *old_data = NULL, *tmp = NULL;
332
333         if (bo->ref_cnt <= 0)
334                 return;
335
336         bo->ref_cnt--;
337         if (bo->ref_cnt == 0) {
338                 /* destory the user_data_list */
339                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
340                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
341                                 DBG("free user_data\n");
342                                 user_data_delete(old_data);
343                         }
344                 }
345
346                 if (bo->lock_cnt > 0) {
347                         TBM_LOG_E("error lock_cnt:%d\n",
348                                 bo->lock_cnt);
349                         _bo_unlock(bo);
350                 }
351
352                 /* call the bo_free */
353                 bufmgr->backend->bo_free(bo);
354                 bo->priv = NULL;
355
356                 LIST_DEL(&bo->item_link);
357                 free(bo);
358                 bo = NULL;
359
360                 bufmgr->bo_cnt--;
361         }
362
363 }
364
365 /* LCOV_EXCL_START */
366 static int
367 _check_version(TBMModuleVersionInfo *data)
368 {
369         int abimaj, abimin;
370         int vermaj, vermin;
371
372         abimaj = GET_ABI_MAJOR(data->abiversion);
373         abimin = GET_ABI_MINOR(data->abiversion);
374
375         DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
376             data->modname ? data->modname : "UNKNOWN!",
377             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
378
379         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
380         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
381
382         DBG("TBM ABI version %d.%d\n",
383             vermaj, vermin);
384
385         if (abimaj != vermaj) {
386                 TBM_LOG_E("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
387                         abimaj, vermaj);
388                 return 0;
389         } else if (abimin > vermin) {
390                 TBM_LOG_E("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
391                         abimin, vermin);
392                 return 0;
393         }
394         return 1;
395 }
396
397 static int
398 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
399 {
400         char path[PATH_MAX] = { 0, };
401         TBMModuleData *initdata = NULL;
402         void *module_data;
403
404         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
405
406         module_data = dlopen(path, RTLD_LAZY);
407         if (!module_data) {
408                 TBM_LOG_E("failed to load module: %s(%s)\n",
409                         dlerror(), file);
410                 return 0;
411         }
412
413         initdata = dlsym(module_data, "tbmModuleData");
414         if (initdata) {
415                 ModuleInitProc init;
416                 TBMModuleVersionInfo *vers;
417
418                 vers = initdata->vers;
419                 init = initdata->init;
420
421                 if (vers) {
422                         if (!_check_version(vers)) {
423                                 dlclose(module_data);
424                                 return 0;
425                         }
426                 } else {
427                         TBM_LOG_E("Error: module does not supply version information.\n");
428
429                         dlclose(module_data);
430                         return 0;
431                 }
432
433                 if (init) {
434                         if (!init(bufmgr, fd)) {
435                                 TBM_LOG_E("Fail to init module(%s)\n",
436                                         file);
437                                 dlclose(module_data);
438                                 return 0;
439                         }
440
441                         if (!bufmgr->backend || !bufmgr->backend->priv) {
442                                 TBM_LOG_E("Error: module(%s) wrong operation. Check backend or backend's priv.\n",
443                                         file);
444                                 dlclose(module_data);
445                                 return 0;
446                         }
447                 } else {
448                         TBM_LOG_E("Error: module does not supply init symbol.\n");
449                         dlclose(module_data);
450                         return 0;
451                 }
452         } else {
453                 TBM_LOG_E("Error: module does not have data object.\n");
454                 dlclose(module_data);
455                 return 0;
456         }
457
458         bufmgr->module_data = module_data;
459
460         DBG("Success to load module(%s)\n",
461             file);
462
463         return 1;
464 }
465
466 static int
467 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
468 {
469         struct dirent **namelist;
470         const char *p = NULL;
471         int n;
472         int ret = 0;
473
474         /* load bufmgr priv from default lib */
475         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
476
477         /* load bufmgr priv from configured path */
478         if (!ret) {
479                 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
480                 if (n < 0) {
481                         TBM_LOG_E("no files : %s\n",
482                                 BUFMGR_MODULE_DIR);
483                 } else {
484                         while (n--) {
485                                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
486                                         p = strstr(namelist[n]->d_name, SUFFIX_LIB);
487                                         if (p && !strcmp(p, SUFFIX_LIB))
488                                                 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
489                                 }
490                                 free(namelist[n]);
491                         }
492                         free(namelist);
493                 }
494         }
495
496         return ret;
497 }
498 /* LCOV_EXCL_STOP */
499
500 tbm_bufmgr
501 tbm_bufmgr_init(int fd)
502 {
503         char *env;
504
505         pthread_mutex_lock(&gLock);
506
507         /* LCOV_EXCL_START */
508 #ifdef HAVE_DLOG
509         env = getenv("TBM_DLOG");
510         if (env) {
511                 bDlog = atoi(env);
512                 TBM_LOG_D("TBM_DLOG=%s\n", env);
513         } else {
514                 bDlog = 1;
515         }
516 #endif
517
518 #ifdef DEBUG
519         env = getenv("TBM_DEBUG");
520         if (env) {
521                 bDebug = atoi(env);
522                 TBM_LOG_D("TBM_DEBUG=%s\n", env);
523         } else {
524                 bDebug = 0;
525         }
526 #endif
527         /* LCOV_EXCL_STOP */
528
529         /* initialize buffer manager */
530         if (gBufMgr) {
531                 gBufMgr->ref_count++;
532
533                 DBG("bufmgr:%p ref: fd=%d, ref_count:%d\n",
534                     gBufMgr, gBufMgr->fd, gBufMgr->ref_count);
535                 pthread_mutex_unlock(&gLock);
536                 return gBufMgr;
537         }
538
539         DBG("bufmgr init\n");
540
541         /* allocate bufmgr */
542         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
543         if (!gBufMgr) {
544                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
545                 pthread_mutex_unlock(&gLock);
546                 return NULL;
547         }
548
549         gBufMgr->fd = fd;
550
551         /* load bufmgr priv from env */
552         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
553                 /* LCOV_EXCL_START */
554                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
555                 TBM_LOG_E("error : Fail to load bufmgr backend\n");
556
557                 free(gBufMgr);
558                 gBufMgr = NULL;
559                 pthread_mutex_unlock(&gLock);
560                 return NULL;
561                 /* LCOV_EXCL_STOP */
562         }
563
564         /* log for tbm backend_flag */
565         DBG("backend flag:%x:", gBufMgr->backend->flags);
566         DBG("\n");
567
568         gBufMgr->ref_count = 1;
569
570         DBG("create tizen bufmgr:%p ref_count:%d\n",
571             gBufMgr, gBufMgr->ref_count);
572
573         if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
574                 /* LCOV_EXCL_START */
575                 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
576                 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
577                 tbm_backend_free(gBufMgr->backend);
578                 dlclose(gBufMgr->module_data);
579                 free(gBufMgr);
580                 gBufMgr = NULL;
581                 pthread_mutex_unlock(&gLock);
582                 return NULL;
583                 /* LCOV_EXCL_STOP */
584         }
585
586         /* setup the lock_type */
587         env = getenv("BUFMGR_LOCK_TYPE");
588         if (env && !strcmp(env, "always"))
589                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
590         else if (env && !strcmp(env, "none"))
591                 gBufMgr->lock_type = LOCK_TRY_NEVER;
592         else if (env && !strcmp(env, "once"))
593                 gBufMgr->lock_type = LOCK_TRY_ONCE;
594         else
595                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
596
597         DBG("BUFMGR_LOCK_TYPE=%s\n",
598             env ? env : "default:once");
599
600         /* intialize bo_list */
601         LIST_INITHEAD(&gBufMgr->bo_list);
602
603         /* intialize surf_list */
604         LIST_INITHEAD(&gBufMgr->surf_list);
605
606         pthread_mutex_unlock(&gLock);
607         return gBufMgr;
608 }
609
610 void
611 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
612 {
613         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
614
615         tbm_bo bo = NULL;
616         tbm_bo tmp = NULL;
617
618         tbm_surface_h surf = NULL;
619         tbm_surface_h tmp_surf = NULL;
620
621         pthread_mutex_lock(&gLock);
622
623         if (!gBufMgr) {
624                 TBM_LOG_E("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
625                 pthread_mutex_unlock(&gLock);
626                 return;
627         }
628
629         bufmgr->ref_count--;
630         if (bufmgr->ref_count > 0) {
631                 DBG("tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
632                         bufmgr, bufmgr->ref_count);
633                 pthread_mutex_unlock(&gLock);
634                 return;
635         }
636
637         /* destroy bo_list */
638         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
639                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
640                         TBM_LOG_E("Un-freed bo(%p, ref:%d)\n",
641                                 bo, bo->ref_cnt);
642                         bo->ref_cnt = 1;
643                         tbm_bo_unref(bo);
644                 }
645         }
646
647         /* destroy surf_list */
648         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
649                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
650                         TBM_LOG_E("Un-freed surf(%p, ref:%d)\n",
651                                 surf, surf->refcnt);
652                         tbm_surface_destroy(surf);
653                 }
654         }
655
656         /* destroy bufmgr priv */
657         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
658         bufmgr->backend->priv = NULL;
659         tbm_backend_free(bufmgr->backend);
660         bufmgr->backend = NULL;
661
662         pthread_mutex_destroy(&bufmgr->lock);
663
664         DBG("tizen bufmgr destroy: bufmgr:%p\n",
665             bufmgr);
666
667         dlclose(bufmgr->module_data);
668
669         if (bufmgr->fd > 0)
670                 close(bufmgr->fd);
671
672         free(bufmgr);
673         bufmgr = NULL;
674         gBufMgr = NULL;
675
676         pthread_mutex_unlock(&gLock);
677 }
678
679 int
680 tbm_bo_size(tbm_bo bo)
681 {
682         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
683
684         tbm_bufmgr bufmgr = bo->bufmgr;
685         int size;
686
687         pthread_mutex_lock(&bufmgr->lock);
688
689         size = bufmgr->backend->bo_size(bo);
690
691         pthread_mutex_unlock(&bufmgr->lock);
692
693         return size;
694 }
695
696 tbm_bo
697 tbm_bo_ref(tbm_bo bo)
698 {
699         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
700
701         tbm_bufmgr bufmgr = bo->bufmgr;
702
703         pthread_mutex_lock(&bufmgr->lock);
704
705         _tbm_bo_ref(bo);
706
707         pthread_mutex_unlock(&bufmgr->lock);
708
709         return bo;
710 }
711
712 void
713 tbm_bo_unref(tbm_bo bo)
714 {
715         TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
716
717         tbm_bufmgr bufmgr = bo->bufmgr;
718
719         pthread_mutex_lock(&bufmgr->lock);
720
721         _tbm_bo_unref(bo);
722
723         pthread_mutex_unlock(&bufmgr->lock);
724 }
725
726 tbm_bo
727 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
728 {
729         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
730
731         tbm_bo bo = NULL;
732         void *bo_priv = NULL;
733
734         bo = calloc(1, sizeof(struct _tbm_bo));
735         if (!bo) {
736                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
737                 return NULL;
738         }
739
740         _tbm_util_check_bo_cnt(bufmgr);
741         bufmgr->bo_cnt++;
742
743         bo->bufmgr = bufmgr;
744
745         pthread_mutex_lock(&bufmgr->lock);
746
747         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
748         if (!bo_priv) {
749                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
750                 free(bo);
751                 pthread_mutex_unlock(&bufmgr->lock);
752                 return NULL;
753         }
754
755         bo->ref_cnt = 1;
756         bo->flags = flags;
757         bo->priv = bo_priv;
758
759         LIST_INITHEAD(&bo->user_data_list);
760
761         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
762
763         pthread_mutex_unlock(&bufmgr->lock);
764
765         return bo;
766 }
767
768 tbm_bo
769 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
770 {
771         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
772
773         tbm_bo bo = NULL;
774         tbm_bo bo2 = NULL;
775         tbm_bo tmp = NULL;
776         void *bo_priv = NULL;
777
778         _tbm_util_check_bo_cnt(bufmgr);
779
780         pthread_mutex_lock(&bufmgr->lock);
781
782         bo = calloc(1, sizeof(struct _tbm_bo));
783         if (!bo) {
784                 pthread_mutex_unlock(&bufmgr->lock);
785                 return NULL;
786         }
787
788         bufmgr->bo_cnt++;
789
790         bo->bufmgr = bufmgr;
791
792         bo_priv = bufmgr->backend->bo_import(bo, key);
793         if (!bo_priv) {
794                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
795                 free(bo);
796                 pthread_mutex_unlock(&bufmgr->lock);
797                 return NULL;
798         }
799
800         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
801                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
802                         if (bo2->priv == bo_priv) {
803                                 DBG("find bo(%p, ref:%d key:%d) in list\n",
804                                     bo2, bo2->ref_cnt, key);
805
806                                 bo2->ref_cnt++;
807                                 free(bo);
808                                 pthread_mutex_unlock(&bufmgr->lock);
809                                 return bo2;
810                         }
811                 }
812         }
813
814         bo->ref_cnt = 1;
815         bo->priv = bo_priv;
816
817         if (bufmgr->backend->bo_get_flags)
818                 bo->flags = bufmgr->backend->bo_get_flags(bo);
819         else
820                 bo->flags = TBM_BO_DEFAULT;
821
822         LIST_INITHEAD(&bo->user_data_list);
823
824         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
825
826         pthread_mutex_unlock(&bufmgr->lock);
827
828         return bo;
829 }
830
831 tbm_bo
832 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
833 {
834         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
835
836         tbm_bo bo = NULL;
837         tbm_bo bo2 = NULL;
838         tbm_bo tmp = NULL;
839         void *bo_priv = NULL;
840
841         _tbm_util_check_bo_cnt(bufmgr);
842
843         pthread_mutex_lock(&bufmgr->lock);
844
845         bo = calloc(1, sizeof(struct _tbm_bo));
846         if (!bo) {
847                 pthread_mutex_unlock(&bufmgr->lock);
848                 return NULL;
849         }
850
851         bufmgr->bo_cnt++;
852
853         bo->bufmgr = bufmgr;
854
855         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
856         if (!bo_priv) {
857                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
858                 free(bo);
859                 pthread_mutex_unlock(&bufmgr->lock);
860                 return NULL;
861         }
862
863         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
864                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
865                         if (bo2->priv == bo_priv) {
866                                 DBG("find bo(%p, ref:%d, fd:%d) in list\n",
867                                     bo2, bo2->ref_cnt, fd);
868
869                                 bo2->ref_cnt++;
870                                 free(bo);
871                                 pthread_mutex_unlock(&bufmgr->lock);
872                                 return bo2;
873                         }
874                 }
875         }
876
877         bo->ref_cnt = 1;
878         bo->priv = bo_priv;
879
880         if (bufmgr->backend->bo_get_flags)
881                 bo->flags = bufmgr->backend->bo_get_flags(bo);
882         else
883                 bo->flags = TBM_BO_DEFAULT;
884
885         LIST_INITHEAD(&bo->user_data_list);
886
887         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
888
889         pthread_mutex_unlock(&bufmgr->lock);
890
891         return bo;
892 }
893
894 tbm_key
895 tbm_bo_export(tbm_bo bo)
896 {
897         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
898
899         tbm_bufmgr bufmgr;
900         tbm_key ret;
901
902         bufmgr = bo->bufmgr;
903
904         pthread_mutex_lock(&bufmgr->lock);
905         ret = bufmgr->backend->bo_export(bo);
906         if (!ret) {
907                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
908                 pthread_mutex_unlock(&bufmgr->lock);
909                 return ret;
910         }
911         pthread_mutex_unlock(&bufmgr->lock);
912
913         return ret;
914 }
915
916 tbm_fd
917 tbm_bo_export_fd(tbm_bo bo)
918 {
919         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
920
921         tbm_bufmgr bufmgr;
922         int ret;
923
924         bufmgr = bo->bufmgr;
925
926         pthread_mutex_lock(&bufmgr->lock);
927         ret = bufmgr->backend->bo_export_fd(bo);
928         if (ret < 0) {
929                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
930                 pthread_mutex_unlock(&bufmgr->lock);
931                 return ret;
932         }
933         pthread_mutex_unlock(&bufmgr->lock);
934
935         return ret;
936 }
937
938 tbm_bo_handle
939 tbm_bo_get_handle(tbm_bo bo, int device)
940 {
941         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
942
943         tbm_bufmgr bufmgr;
944         tbm_bo_handle bo_handle;
945
946         bufmgr = bo->bufmgr;
947
948         pthread_mutex_lock(&bufmgr->lock);
949         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
950         if (bo_handle.ptr == NULL) {
951                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
952                 pthread_mutex_unlock(&bufmgr->lock);
953                 return (tbm_bo_handle) NULL;
954         }
955         pthread_mutex_unlock(&bufmgr->lock);
956
957         return bo_handle;
958 }
959
960 tbm_bo_handle
961 tbm_bo_map(tbm_bo bo, int device, int opt)
962 {
963         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
964
965         tbm_bufmgr bufmgr;
966         tbm_bo_handle bo_handle;
967
968         bufmgr = bo->bufmgr;
969
970         pthread_mutex_lock(&bufmgr->lock);
971
972         if (!_tbm_bo_lock(bo, device, opt)) {
973                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
974                 TBM_LOG_E("error fail to lock bo:%p)\n",
975                         bo);
976                 pthread_mutex_unlock(&bufmgr->lock);
977                 return (tbm_bo_handle) NULL;
978         }
979
980         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
981         if (bo_handle.ptr == NULL) {
982                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
983                 TBM_LOG_E("error fail to map bo:%p\n",
984                         bo);
985
986                 _tbm_bo_unlock(bo);
987                 pthread_mutex_unlock(&bufmgr->lock);
988                 return (tbm_bo_handle) NULL;
989         }
990
991         /* increase the map_count */
992         bo->map_cnt++;
993
994         pthread_mutex_unlock(&bufmgr->lock);
995
996         return bo_handle;
997 }
998
999 int
1000 tbm_bo_unmap(tbm_bo bo)
1001 {
1002         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1003
1004         tbm_bufmgr bufmgr;
1005         int ret;
1006
1007         bufmgr = bo->bufmgr;
1008
1009         pthread_mutex_lock(&bufmgr->lock);
1010
1011         ret = bufmgr->backend->bo_unmap(bo);
1012         if (!ret) {
1013
1014                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
1015                 pthread_mutex_unlock(&bufmgr->lock);
1016                 return ret;
1017         }
1018
1019         /* decrease the map_count */
1020         bo->map_cnt--;
1021
1022         _tbm_bo_unlock(bo);
1023
1024         pthread_mutex_unlock(&bufmgr->lock);
1025
1026         return ret;
1027 }
1028
1029 int
1030 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1031 {
1032         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1033         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1034
1035         void *temp;
1036
1037         pthread_mutex_lock(&bo1->bufmgr->lock);
1038
1039         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1040                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1041                 pthread_mutex_unlock(&bo1->bufmgr->lock);
1042                 return 0;
1043         }
1044
1045         temp = bo1->priv;
1046         bo1->priv = bo2->priv;
1047         bo2->priv = temp;
1048
1049         pthread_mutex_unlock(&bo1->bufmgr->lock);
1050
1051         return 1;
1052 }
1053
1054 int
1055 tbm_bo_locked(tbm_bo bo)
1056 {
1057         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1058
1059         tbm_bufmgr bufmgr;
1060
1061         bufmgr = bo->bufmgr;
1062
1063         if (bufmgr->lock_type == LOCK_TRY_NEVER)
1064                 return 0;
1065
1066         pthread_mutex_lock(&bufmgr->lock);
1067
1068         if (bo->lock_cnt > 0) {
1069                 pthread_mutex_unlock(&bufmgr->lock);
1070                 return 1;
1071         }
1072
1073         pthread_mutex_unlock(&bufmgr->lock);
1074
1075         return 0;
1076 }
1077
1078 int
1079 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1080                      tbm_data_free data_free_func)
1081 {
1082         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1083
1084         tbm_user_data *data;
1085
1086         /* check if the data according to the key exist if so, return false. */
1087         data = user_data_lookup(&bo->user_data_list, key);
1088         if (data) {
1089                 TBM_LOG_W("waring user data already exist. key:%ld\n",
1090                         key);
1091                 return 0;
1092         }
1093
1094         data = user_data_create(key, data_free_func);
1095         if (!data)
1096                 return 0;
1097
1098         LIST_ADD(&data->item_link, &bo->user_data_list);
1099
1100         return 1;
1101 }
1102
1103 int
1104 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1105 {
1106         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1107
1108         tbm_user_data *old_data;
1109
1110         if (LIST_IS_EMPTY(&bo->user_data_list))
1111                 return 0;
1112
1113         old_data = user_data_lookup(&bo->user_data_list, key);
1114         if (!old_data)
1115                 return 0;
1116
1117         if (old_data->data && old_data->free_func)
1118                 old_data->free_func(old_data->data);
1119
1120         old_data->data = data;
1121
1122         return 1;
1123 }
1124
1125 int
1126 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1127 {
1128         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1129
1130         tbm_user_data *old_data;
1131
1132         if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1133                 return 0;
1134
1135         old_data = user_data_lookup(&bo->user_data_list, key);
1136         if (!old_data) {
1137                 *data = NULL;
1138                 return 0;
1139         }
1140
1141         *data = old_data->data;
1142
1143         return 1;
1144 }
1145
1146 int
1147 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1148 {
1149         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1150
1151         tbm_user_data *old_data = (void *)0;
1152
1153         if (LIST_IS_EMPTY(&bo->user_data_list))
1154                 return 0;
1155
1156         old_data = user_data_lookup(&bo->user_data_list, key);
1157         if (!old_data)
1158                 return 0;
1159
1160         user_data_delete(old_data);
1161
1162         return 1;
1163 }
1164
1165 unsigned int
1166 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1167 {
1168         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1169
1170         unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1171
1172         if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1173                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1174
1175         if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1176                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1177
1178         return capability;
1179 }
1180
1181 int
1182 tbm_bo_get_flags(tbm_bo bo)
1183 {
1184         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1185
1186         return bo->flags;
1187 }
1188
1189 /* LCOV_EXCL_START */
1190 tbm_error_e
1191 tbm_get_last_error(void)
1192 {
1193         return tbm_last_error;
1194 }
1195
1196 void
1197 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1198 {
1199         TBM_RETURN_IF_FAIL(bufmgr != NULL);
1200         tbm_bo bo = NULL, tmp_bo = NULL;
1201         int bo_cnt = 0;
1202
1203         tbm_surface_h surf = NULL, tmp_surf = NULL;
1204         int surf_cnt = 0;
1205         int i;
1206         char app_name[255] = {0,};
1207         unsigned int pid = 0;
1208
1209         pthread_mutex_lock(&gLock);
1210
1211         TBM_DEBUG("\n");
1212         _tbm_util_get_appname_from_pid(getpid(), app_name);
1213         _tbm_util_get_appname_brief(app_name);
1214         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1215                   app_name, getpid());
1216         memset(app_name, 0x0, 255 * sizeof(char));
1217
1218         TBM_DEBUG("[tbm_surface information]\n");
1219         TBM_DEBUG("no  surface              refcnt  width  height  bpp  size      num_bos num_planes flags format              app_name\n");
1220         /* show the tbm_surface information in surf_list */
1221         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1222                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1223                         pid = _tbm_surface_internal_get_debug_pid(surf);
1224                         if (!pid) {
1225                                 /* if pid is null, set the self_pid */
1226                                 pid = getpid();
1227                         }
1228
1229                         _tbm_util_get_appname_from_pid(pid, app_name);
1230                         _tbm_util_get_appname_brief(app_name);
1231
1232                         TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1233                                   ++surf_cnt,
1234                                   surf,
1235                                   surf->refcnt,
1236                                   surf->info.width,
1237                                   surf->info.height,
1238                                   surf->info.bpp,
1239                                   surf->info.size / 1024,
1240                                   surf->num_bos,
1241                                   surf->num_planes,
1242                                   surf->flags,
1243                                   _tbm_surface_internal_format_to_str(surf->info.format),
1244                                   app_name);
1245
1246                         for (i = 0; i < surf->num_bos; i++) {
1247                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1248                                           surf->bos[i],
1249                                           surf->bos[i]->ref_cnt,
1250                                           tbm_bo_size(surf->bos[i]) / 1024);
1251                         }
1252
1253                         memset(app_name, 0x0, 255 * sizeof(char));
1254                 }
1255         } else {
1256                 TBM_DEBUG("no tbm_surfaces.\n");
1257         }
1258         TBM_DEBUG("\n");
1259
1260         TBM_DEBUG("[tbm_bo information]\n");
1261         TBM_DEBUG("no  bo                   refcnt  size     lock_cnt map_cnt flags surface\n");
1262
1263         /* show the tbm_bo information in bo_list */
1264         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1265                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1266                         TBM_DEBUG("%-4d%-11p   %-6d%-12d%-9d%-9d%-4d%-11p\n",
1267                                   ++bo_cnt,
1268                                   bo,
1269                                   bo->ref_cnt,
1270                                   tbm_bo_size(bo) / 1024,
1271                                   bo->lock_cnt,
1272                                   bo->map_cnt,
1273                                   bo->flags,
1274                                   bo->surface);
1275                 }
1276         } else {
1277                 TBM_DEBUG("no tbm_bos.\n");
1278         }
1279         TBM_DEBUG("\n");
1280
1281         TBM_DEBUG("===============================================================\n");
1282
1283         pthread_mutex_unlock(&gLock);
1284
1285 }
1286
1287 void
1288 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1289 {
1290         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1291         TBM_LOG_D("Not implemented yet.\n");
1292 }
1293
1294 /* internal function */
1295 int
1296 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1297 {
1298         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1299
1300         bo->surface = surface;
1301
1302         return 1;
1303 }
1304
1305 int
1306 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1307 {
1308         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1309
1310         int ret;
1311
1312         pthread_mutex_lock(&bufmgr->lock);
1313
1314         if (!bufmgr->backend->bufmgr_bind_native_display) {
1315                 pthread_mutex_unlock(&bufmgr->lock);
1316                 return 1;
1317         }
1318
1319         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1320         if (!ret) {
1321                 pthread_mutex_unlock(&bufmgr->lock);
1322                 return 0;
1323         }
1324
1325         pthread_mutex_unlock(&bufmgr->lock);
1326
1327         return 1;
1328 }
1329 /* LCOV_EXCL_STOP */