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