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