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