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