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