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