remove the function which tbm does not support.
[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 {
91     unsigned long key;
92     void *data;
93     tbm_data_free free_func ;
94
95     /* link of user_data */
96     struct list_head item_link;
97 } tbm_user_data;
98
99 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
100 tbm_bufmgr gBufMgr = NULL;
101
102 static inline int
103 _tgl_init (int fd, unsigned int key)
104 {
105     struct tgl_attribute attr;
106     int err;
107
108     attr.key = key;
109     attr.timeout_ms = 1000;
110
111     err = ioctl (fd, TGL_IOC_INIT_LOCK, &attr);
112     if (err)
113     {
114         TBM_LOG ( "[libtbm:%d] "
115                 "error(%s) %s:%d key:%d\n",
116                 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
117         return 0;
118     }
119
120     return 1;
121 }
122
123 static inline int
124 _tgl_destroy (int fd, unsigned int key)
125 {
126     int err;
127     err = ioctl (fd, TGL_IOC_DESTROY_LOCK, key);
128     if (err)
129     {
130         TBM_LOG ( "[libtbm:%d] "
131                 "error(%s) %s:%d key:%d\n",
132                 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
133         return 0;
134     }
135
136     return 1;
137 }
138
139 static inline int
140 _tgl_lock (int fd, unsigned int key)
141 {
142     int err;
143     err = ioctl (fd, TGL_IOC_LOCK_LOCK, key);
144     if (err)
145     {
146         TBM_LOG ("[libtbm:%d] "
147                 "error(%s) %s:%d key:%d\n",
148                 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
149         return 0;
150     }
151
152     return 1;
153 }
154
155 static inline int
156 _tgl_unlock (int fd, unsigned int key)
157 {
158     int err;
159     err = ioctl (fd, TGL_IOC_UNLOCK_LOCK, key);
160     if (err)
161     {
162         TBM_LOG ("[libtbm:%d] "
163                 "error(%s) %s:%d key:%d\n",
164                 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
165         return 0;
166     }
167
168     return 1;
169 }
170
171 static inline int
172 _tgl_set_data (int fd, unsigned int key, unsigned int val)
173 {
174     int err;
175     struct tgl_user_data arg;
176
177     arg.key = key;
178     arg.data1 = val;
179     err = ioctl (fd, TGL_IOC_SET_DATA, &arg);
180     if (err)
181     {
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 unsigned int
192 _tgl_get_data (int fd, unsigned int key, unsigned int *locked)
193 {
194     int err;
195     struct tgl_user_data arg = {0,};
196
197     arg.key = key;
198     err = ioctl (fd, TGL_IOC_GET_DATA, &arg);
199     if (err)
200     {
201         TBM_LOG ("[libtbm:%d] "
202                 "error(%s) %s:%d key:%d\n",
203                 getpid(), strerror(errno), __FUNCTION__, __LINE__, key);
204         return 0;
205     }
206
207     if (locked)
208         *locked = arg.locked;
209
210     return arg.data1;
211 }
212
213 static tbm_user_data *
214 _user_data_lookup (struct list_head *user_data_list, unsigned long key)
215 {
216     tbm_user_data *user_data = NULL;
217     tbm_user_data *old_data = NULL, *tmp = NULL;
218
219     if (!LIST_IS_EMPTY (user_data_list))
220     {
221         LIST_FOR_EACH_ENTRY_SAFE (old_data, tmp, user_data_list, item_link)
222         {
223             if (old_data->key == key)
224             {
225                 user_data = old_data;
226                 return user_data;
227             }
228         }
229     }
230
231     return user_data;
232 }
233
234 static tbm_user_data *
235 _user_data_create (unsigned long key, tbm_data_free data_free_func)
236 {
237     tbm_user_data * user_data = NULL;
238
239     user_data = calloc (1, sizeof (tbm_user_data));
240     if (!user_data)
241         return NULL;
242
243     user_data->key = key;
244     user_data->free_func = data_free_func;
245     user_data->data = (void *)0;
246
247     return user_data;
248 }
249
250 static void
251 _user_data_delete (tbm_user_data *user_data)
252 {
253     if (user_data->data && user_data->free_func)
254         user_data->free_func(user_data->data);
255
256     LIST_DEL (&user_data->item_link);
257
258     free(user_data);
259 }
260
261 static int
262 _bo_lock (tbm_bo bo, int device, int opt)
263 {
264     tbm_bufmgr bufmgr = bo->bufmgr;
265     int ret = 0;
266
267     if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags))
268     {
269         if (bufmgr->backend->bo_lock2)
270         {
271             /* use bo_lock2 backend lock */
272             ret = bufmgr->backend->bo_lock2 (bo, device, opt);
273         }
274         else if (bufmgr->backend->bo_lock)
275         {
276             /* use bo_lock backend lock */
277             ret = bufmgr->backend->bo_lock (bo);
278         }
279         else
280             TBM_LOG ("[libtbm:%d] "
281                 "error %s:%d no backend lock functions\n",
282                 getpid(), __FUNCTION__, __LINE__);
283     }
284     else
285     {
286         /* use tizen global lock */
287         ret = _tgl_lock (bufmgr->lock_fd, bo->tgl_key);
288     }
289
290     return ret;
291 }
292
293 static void
294 _bo_unlock (tbm_bo bo)
295 {
296     tbm_bufmgr bufmgr = bo->bufmgr;
297
298     if (TBM_LOCK_CTRL_BACKEND_VALID(bufmgr->backend->flags))
299     {
300         if (bufmgr->backend->bo_unlock)
301         {
302             /* use backend unlock */
303             bufmgr->backend->bo_unlock (bo);
304         }
305         else
306             TBM_LOG ("[libtbm:%d] "
307                 "error %s:%d no backend unlock functions\n",
308                 getpid(), __FUNCTION__, __LINE__);
309     }
310     else
311     {
312         /* use tizen global unlock */
313         _tgl_unlock (bufmgr->lock_fd, bo->tgl_key);
314     }
315 }
316
317 static int
318 _tbm_bo_init_state (tbm_bo bo, int opt)
319 {
320     tbm_bufmgr bufmgr = bo->bufmgr;
321     tbm_bo_cache_state cache_state;
322
323     RETURN_VAL_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
324
325     cache_state.val = 0;
326     switch (opt)
327     {
328     case CACHE_OP_CREATE:    /*Create*/
329         if (bo->tgl_key == INITIAL_KEY)
330            bo->tgl_key = bufmgr->backend->bo_get_global_key (bo);
331
332         _tgl_init (bufmgr->lock_fd, bo->tgl_key);
333
334         cache_state.data.isCacheable = BO_IS_CACHEABLE(bo);
335         cache_state.data.isDirtied = DEVICE_NONE;
336         cache_state.data.isCached = 0;
337         cache_state.data.cntFlush = 0;
338
339         _tgl_set_data (bufmgr->lock_fd, bo->tgl_key, cache_state.val);
340         break;
341     case CACHE_OP_IMPORT:    /*Import*/
342         if (bo->tgl_key == INITIAL_KEY)
343            bo->tgl_key = bufmgr->backend->bo_get_global_key (bo);
344
345         _tgl_init (bufmgr->lock_fd, bo->tgl_key);
346         break;
347     default:
348         break;
349     }
350
351     return 1;
352 }
353
354 static void
355 _tbm_bo_destroy_state (tbm_bo bo)
356 {
357     tbm_bufmgr bufmgr = bo->bufmgr;
358
359     RETURN_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
360
361     _tgl_destroy (bufmgr->lock_fd, bo->tgl_key);
362 }
363
364 static int
365 _tbm_bo_set_state (tbm_bo bo, int device, int opt)
366 {
367     tbm_bufmgr bufmgr = bo->bufmgr;
368     char need_flush = 0;
369     unsigned short cntFlush = 0;
370     unsigned int is_locked;
371
372     RETURN_VAL_CHECK_FLAG (TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
373
374     /* get cache state of a bo */
375     bo->cache_state.val = _tgl_get_data (bufmgr->lock_fd, bo->tgl_key, &is_locked);
376
377     if (!bo->cache_state.data.isCacheable)
378         return 1;
379
380     /* get global cache flush count */
381     cntFlush = (unsigned short)_tgl_get_data (bufmgr->lock_fd, GLOBAL_KEY, NULL);
382
383     if (DEVICE_IS_CACHE_AWARE (device))
384     {
385         if (bo->cache_state.data.isDirtied == DEVICE_CO &&
386             bo->cache_state.data.isCached)
387         {
388             need_flush = TBM_CACHE_INV;
389         }
390
391         bo->cache_state.data.isCached = 1;
392         if (opt & TBM_OPTION_WRITE)
393             bo->cache_state.data.isDirtied = DEVICE_CA;
394         else
395         {
396             if( bo->cache_state.data.isDirtied != DEVICE_CA )
397                 bo->cache_state.data.isDirtied = DEVICE_NONE;
398         }
399     }
400     else
401     {
402         if (bo->cache_state.data.isDirtied == DEVICE_CA &&
403             bo->cache_state.data.isCached &&
404             bo->cache_state.data.cntFlush == cntFlush)
405         {
406             need_flush = TBM_CACHE_CLN | TBM_CACHE_ALL;
407         }
408
409         if (opt & TBM_OPTION_WRITE)
410             bo->cache_state.data.isDirtied = DEVICE_CO;
411         else
412         {
413             if( bo->cache_state.data.isDirtied != DEVICE_CO )
414                 bo->cache_state.data.isDirtied = DEVICE_NONE;
415         }
416     }
417
418     if (need_flush)
419     {
420         /* set global cache flush count */
421         if (need_flush & TBM_CACHE_ALL)
422             _tgl_set_data (bufmgr->lock_fd, GLOBAL_KEY, (unsigned int)(++cntFlush));
423
424         /* call backend cache flush */
425         bufmgr->backend->bo_cache_flush (bo, need_flush);
426
427         DBG ("[libtbm:%d] \tcache(%d,%d,%d)....flush:0x%x, cntFlush(%d)\n", getpid(),
428              bo->cache_state.data.isCacheable,
429              bo->cache_state.data.isCached,
430              bo->cache_state.data.isDirtied,
431              need_flush, cntFlush);
432     }
433
434     return 1;
435 }
436
437 static void
438 _tbm_bo_save_state (tbm_bo bo)
439 {
440     tbm_bufmgr bufmgr = bo->bufmgr;
441     unsigned short cntFlush = 0;
442
443     RETURN_CHECK_FLAG (TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags));
444
445     /* get global cache flush count */
446     cntFlush = (unsigned short)_tgl_get_data (bufmgr->lock_fd, GLOBAL_KEY, NULL);
447
448     /* save global cache flush count */
449     bo->cache_state.data.cntFlush = cntFlush;
450     _tgl_set_data(bufmgr->lock_fd, bo->tgl_key, bo->cache_state.val);
451 }
452
453
454 static int
455 _tbm_bo_lock (tbm_bo bo, int device, int opt)
456 {
457     tbm_bufmgr bufmgr = NULL;
458     int old;
459     int ret = 0;
460
461     if (!bo)
462         return 0;
463
464     bufmgr = bo->bufmgr;
465
466     /* do not try to lock the bo */
467     if (bufmgr->lock_type == LOCK_TRY_NEVER)
468         return 1;
469
470     if (bo->lock_cnt < 0)
471     {
472         TBM_LOG ("[libtbm:%d] "
473                 "error %s:%d bo:%p(%d) LOCK_CNT=%d\n",
474                 getpid(), __FUNCTION__, __LINE__, bo, bo->tgl_key, bo->lock_cnt);
475     }
476
477     old = bo->lock_cnt;
478     if (bufmgr->lock_type == LOCK_TRY_ONCE)
479     {
480         if (bo->lock_cnt == 0)
481         {
482             pthread_mutex_unlock (&bufmgr->lock);
483             ret = _bo_lock (bo, device, opt);
484             pthread_mutex_lock (&bufmgr->lock);
485             if (ret)
486                 bo->lock_cnt++;
487         }
488     }
489     else if (bufmgr->lock_type == LOCK_TRY_ALWAYS)
490     {
491         pthread_mutex_unlock (&bufmgr->lock);
492         ret = _bo_lock (bo, device, opt);
493         pthread_mutex_lock (&bufmgr->lock);
494         if(ret)
495             bo->lock_cnt++;
496     }
497     else
498         TBM_LOG ("[libtbm:%d] "
499                 "error %s:%d bo:%p lock_type is wrong.\n",
500                 getpid(), __FUNCTION__, __LINE__, bo);
501
502     DBG_LOCK ("[libtbm:%d] >> LOCK bo:%p(%d, %d->%d)\n", getpid(),
503             bo, bo->tgl_key, old, bo->lock_cnt);
504
505     return 1;
506 }
507
508 static void
509 _tbm_bo_unlock (tbm_bo bo)
510 {
511     tbm_bufmgr bufmgr = NULL;
512
513     int old;
514
515     if (!bo)
516         return;
517
518     bufmgr = bo->bufmgr;
519
520     /* do not try to unlock the bo */
521     if (bufmgr->lock_type == LOCK_TRY_NEVER)
522         return;
523
524     old = bo->lock_cnt;
525     if (bufmgr->lock_type == LOCK_TRY_ONCE)
526     {
527         if (bo->lock_cnt > 0)
528         {
529             bo->lock_cnt--;
530             if (bo->lock_cnt == 0)
531                _bo_unlock (bo);
532         }
533     }
534     else if (bufmgr->lock_type == LOCK_TRY_ALWAYS)
535     {
536         if (bo->lock_cnt > 0)
537         {
538             bo->lock_cnt--;
539             _bo_unlock (bo);
540         }
541     }
542     else
543         TBM_LOG ("[libtbm:%d] "
544                 "error %s:%d bo:%p lock_type is wrong.\n",
545                 getpid(), __FUNCTION__, __LINE__, bo);
546
547     if (bo->lock_cnt < 0)
548         bo->lock_cnt = 0;
549
550     DBG_LOCK ("[libtbm:%d] << unlock bo:%p(%d, %d->%d)\n", getpid(),
551              bo, bo->tgl_key, old, bo->lock_cnt);
552 }
553
554
555 static void
556 _tbm_bo_ref (tbm_bo bo)
557 {
558     bo->ref_cnt++;
559 }
560
561 static void
562 _tbm_bo_unref (tbm_bo bo)
563 {
564     tbm_bufmgr bufmgr = bo->bufmgr;
565     tbm_user_data *old_data = NULL, *tmp = NULL;
566
567     if (bo->ref_cnt <= 0)
568         return;
569
570     bo->ref_cnt--;
571     if (bo->ref_cnt == 0)
572     {
573         /* destory the user_data_list */
574         if (!LIST_IS_EMPTY (&bo->user_data_list))
575         {
576             LIST_FOR_EACH_ENTRY_SAFE (old_data, tmp, &bo->user_data_list, item_link)
577             {
578                 DBG ("[libtbm:%d] free user_data \n", getpid());
579                 _user_data_delete (old_data);
580             }
581         }
582
583         if (bo->lock_cnt > 0)
584         {
585             TBM_LOG ("[libtbm:%d] "
586                     "error %s:%d lock_cnt:%d\n",
587                     getpid(), __FUNCTION__, __LINE__, bo->lock_cnt);
588             _bo_unlock (bo);
589         }
590
591         /* Destroy Global Lock */
592         _tbm_bo_destroy_state (bo);
593
594         /* call the bo_free */
595         bufmgr->backend->bo_free (bo);
596         bo->priv = NULL;
597
598         LIST_DEL (&bo->item_link);
599         free(bo);
600         bo = NULL;
601     }
602
603 }
604
605 static int
606 _tbm_bufmgr_init_state (tbm_bufmgr bufmgr)
607 {
608     RETURN_VAL_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
609
610     bufmgr->lock_fd = open (tgl_devfile, O_RDWR);
611
612     if(bufmgr->lock_fd < 0)
613     {
614         bufmgr->lock_fd = open (tgl_devfile1, O_RDWR);
615         if(bufmgr->lock_fd < 0)
616         {
617
618             TBM_LOG ("[libtbm:%d] "
619                     "error: Fail to open global_lock:%s\n",
620                     getpid(), tgl_devfile);
621             return 0;
622         }
623     }
624
625    if (!_tgl_init(bufmgr->lock_fd, GLOBAL_KEY))
626    {
627         TBM_LOG ("[libtbm:%d] "
628                 "error: Fail to initialize the tgl\n",
629                 getpid());
630         return 0;
631    }
632
633    return 1;
634 }
635
636 static void
637 _tbm_bufmgr_destroy_state (tbm_bufmgr bufmgr)
638 {
639     RETURN_CHECK_FLAG (TBM_ALL_CTRL_BACKEND_VALID(bufmgr->backend->flags));
640
641     close (bufmgr->lock_fd);
642 }
643
644 static int
645 _check_version (TBMModuleVersionInfo *data)
646 {
647     int abimaj, abimin;
648     int vermaj, vermin;
649
650     abimaj = GET_ABI_MAJOR (data->abiversion);
651     abimin = GET_ABI_MINOR (data->abiversion);
652
653     TBM_LOG ("[libtbm:%d] "
654             "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
655             getpid(), data->modname ? data->modname : "UNKNOWN!",
656             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
657
658     vermaj = GET_ABI_MAJOR (TBM_ABI_VERSION);
659     vermin = GET_ABI_MINOR (TBM_ABI_VERSION);
660
661     DBG ("[libtbm:%d] " "TBM ABI version %d.%d\n", getpid(), vermaj, vermin);
662
663     if (abimaj != vermaj)
664     {
665         TBM_LOG ("[libtbm:%d] "
666                 "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
667                 getpid(), abimaj, vermaj);
668         return 0;
669     }
670     else if (abimin > vermin)
671     {
672         TBM_LOG ("[libtbm:%d] "
673                 "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
674                 getpid(), abimin, vermin);
675         return 0;
676     }
677     return 1;
678 }
679
680 static int
681 _tbm_bufmgr_load_module (tbm_bufmgr bufmgr, int fd, const char *file)
682 {
683     char path[PATH_MAX] = {0,};
684     TBMModuleData *initdata = NULL;
685     void * module_data;
686
687     snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
688
689     module_data = dlopen (path, RTLD_LAZY);
690     if (!module_data)
691     {
692         TBM_LOG ("[libtbm:%d] "
693                 "failed to load module: %s(%s)\n",
694                 getpid(), dlerror(), file);
695         return 0;
696     }
697
698     initdata = dlsym (module_data, "tbmModuleData");
699     if (initdata)
700     {
701         ModuleInitProc init;
702         TBMModuleVersionInfo *vers;
703
704         vers = initdata->vers;
705         init = initdata->init;
706
707         if (vers)
708         {
709             if (!_check_version (vers))
710             {
711                 dlclose (module_data);
712                 return 0;
713             }
714         }
715         else
716         {
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         {
727             if(!init (bufmgr, fd))
728             {
729                 TBM_LOG ("[libtbm:%d] "
730                         "Fail to init module(%s)\n",
731                         getpid(), file);
732                 dlclose (module_data);
733                 return 0;
734             }
735
736             if (!bufmgr->backend || !bufmgr->backend->priv)
737             {
738                 TBM_LOG ("[libtbm:%d] "
739                         "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
740                         getpid(), file);
741                 dlclose (module_data);
742                 return 0;
743             }
744         }
745         else
746         {
747             TBM_LOG ("[libtbm:%d] "
748                     "Error: module does not supply init symbol.\n", getpid());
749             dlclose (module_data);
750             return 0;
751         }
752     }
753     else
754     {
755         TBM_LOG ("[libtbm:%d] "
756                 "Error: module does not have data object.\n", getpid());
757         dlclose (module_data);
758         return 0;
759     }
760
761     bufmgr->module_data = module_data;
762
763     TBM_LOG ("[libtbm:%d] "
764             "Success to load module(%s)\n", getpid(), file);
765
766     return 1;
767 }
768
769 static int _tbm_load_module (tbm_bufmgr bufmgr, int fd)
770 {
771     struct dirent **namelist;
772     const char *p = NULL;
773     int n;
774     int ret = 0;
775
776     /* load bufmgr priv from default lib */
777     ret = _tbm_bufmgr_load_module (bufmgr, fd, DEFAULT_LIB);
778
779     /* load bufmgr priv from configured path */
780     if (!ret)
781     {
782         n = scandir (BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
783         if (n < 0)
784             TBM_LOG ("[libtbm:%d] "
785                     "no files : %s\n", getpid(), BUFMGR_MODULE_DIR);
786         else
787         {
788             while(n--)
789             {
790                 if (!ret && strstr (namelist[n]->d_name, PREFIX_LIB))
791                 {
792                     p = strstr (namelist[n]->d_name, SUFFIX_LIB);
793                     if (!strcmp (p, SUFFIX_LIB))
794                     {
795                         ret = _tbm_bufmgr_load_module (bufmgr, fd, namelist[n]->d_name);
796                     }
797                 }
798                 free(namelist[n]);
799             }
800             free(namelist);
801         }
802     }
803
804     return ret;
805 }
806
807 tbm_bufmgr
808 tbm_bufmgr_init (int fd)
809 {
810     char *env;
811     int fd_flag = 0;
812
813     pthread_mutex_lock (&gLock);
814
815 #ifdef DEBUG
816     env = getenv("GEM_DEBUG");
817     if(env)
818     {
819         bDebug = atoi(env);
820         TBM_LOG ("GEM_DEBUG=%s\n", env);
821     }
822     else
823         bDebug = 0;
824 #endif
825
826     /* initialize buffer manager */
827     if (gBufMgr)
828     {
829         TBM_LOG ("[libtbm:%d] use previous gBufMgr\n", getpid());
830         gBufMgr->ref_count++;
831         TBM_LOG ("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
832                     getpid(), gBufMgr->fd, gBufMgr->ref_count);
833         pthread_mutex_unlock (&gLock);
834         return gBufMgr;
835     }
836
837     if (fd < 0)
838     {
839 #ifdef HAVE_X11
840         fd = tbm_bufmgr_get_drm_fd_x11();
841 #elif HAVE_WAYLAND
842         fd = tbm_bufmgr_get_drm_fd_wayland();
843 #endif
844         if (fd < 0)
845         {
846             TBM_LOG ("[libtbm:%d] Fail get drm fd\n", getpid());
847             pthread_mutex_unlock (&gLock);
848             return NULL;
849         }
850         fd_flag = 1;
851     }
852
853     TBM_LOG ("[libtbm:%d] bufmgr init: fd=%d\n", getpid(), fd);
854
855     /* allocate bufmgr */
856     gBufMgr = calloc (1, sizeof(struct _tbm_bufmgr));
857     if (!gBufMgr)
858     {
859         pthread_mutex_unlock (&gLock);
860         return NULL;
861     }
862
863     /* load bufmgr priv from env */
864     if (!_tbm_load_module(gBufMgr, fd))
865     {
866         TBM_LOG ("[libtbm:%d] "
867                 "error : Fail to load bufmgr backend\n",
868                 getpid());
869         free (gBufMgr);
870         gBufMgr = NULL;
871         pthread_mutex_unlock (&gLock);
872         return NULL;
873     }
874
875     gBufMgr->fd_flag = fd_flag;
876     gBufMgr->fd = fd;
877     gBufMgr->ref_count = 1;
878
879     TBM_LOG ("[libtbm:%d] create tizen bufmgr: ref_count:%d\n", getpid(), gBufMgr->ref_count);
880
881     if (pthread_mutex_init (&gBufMgr->lock, NULL) != 0)
882     {
883         gBufMgr->backend->bufmgr_deinit (gBufMgr->backend->priv);
884         tbm_backend_free (gBufMgr->backend);
885         dlclose (gBufMgr->module_data);
886         free (gBufMgr);
887         gBufMgr = NULL;
888         pthread_mutex_unlock (&gLock);
889         return NULL;
890     }
891
892     /* intialize the tizen global status */
893     if (!_tbm_bufmgr_init_state (gBufMgr))
894     {
895         TBM_LOG ("[libtbm:%d] "
896                 "error: Fail to init state\n",
897                 getpid());
898         gBufMgr->backend->bufmgr_deinit (gBufMgr->backend->priv);
899         tbm_backend_free (gBufMgr->backend);
900         pthread_mutex_destroy (&gBufMgr->lock);
901         dlclose (gBufMgr->module_data);
902         free (gBufMgr);
903         gBufMgr = NULL;
904         pthread_mutex_unlock (&gLock);
905         return NULL;
906     }
907
908     /* setup the lock_type */
909     env = getenv ("BUFMGR_LOCK_TYPE");
910     if (env && !strcmp (env, "always"))
911         gBufMgr->lock_type = LOCK_TRY_ALWAYS;
912     else if(env && !strcmp(env, "none"))
913         gBufMgr->lock_type = LOCK_TRY_NEVER;
914     else if(env && !strcmp(env, "once"))
915          gBufMgr->lock_type = LOCK_TRY_ONCE;
916     else
917         gBufMgr->lock_type = LOCK_TRY_ALWAYS;
918
919     DBG ("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n", getpid(), env?env:"default:once");
920
921     /* setup the map_cache */
922     env = getenv ("BUFMGR_MAP_CACHE");
923     if (env && !strcmp (env, "false"))
924         gBufMgr->use_map_cache = 0;
925     else
926         gBufMgr->use_map_cache = 1;
927     DBG ("[libtbm:%d] BUFMGR_MAP_CACHE=%s\n", getpid(), env?env:"default:true");
928
929     /* intialize bo_list */
930     LIST_INITHEAD (&gBufMgr->bo_list);
931
932     /* intialize surf_list */
933     LIST_INITHEAD (&gBufMgr->surf_list);
934
935     pthread_mutex_unlock (&gLock);
936     return gBufMgr;
937 }
938
939 void
940 tbm_bufmgr_deinit (tbm_bufmgr bufmgr)
941 {
942     TBM_RETURN_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr));
943
944     tbm_bo bo = NULL;
945     tbm_bo tmp = NULL;
946
947     tbm_surface_h surf = NULL;
948     tbm_surface_h tmp_surf = NULL;
949
950     pthread_mutex_lock (&gLock);
951
952     bufmgr->ref_count--;
953     if (bufmgr->ref_count > 0)
954     {
955         TBM_LOG ("[libtbm:%d] "
956                 "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
957                 getpid(), bufmgr, bufmgr->ref_count);
958         pthread_mutex_unlock (&gLock);
959         return;
960     }
961
962     /* destroy bo_list */
963     if(!LIST_IS_EMPTY (&bufmgr->bo_list))
964     {
965         LIST_FOR_EACH_ENTRY_SAFE (bo, tmp, &bufmgr->bo_list, item_link)
966         {
967             TBM_LOG ("[libtbm:%d] "
968                     "Un-freed bo(%p, ref:%d) \n",
969                     getpid(), bo, bo->ref_cnt);
970             bo->ref_cnt = 1;
971             tbm_bo_unref(bo);
972         }
973     }
974
975     /* destroy surf_list */
976     if(!LIST_IS_EMPTY (&bufmgr->surf_list))
977     {
978         LIST_FOR_EACH_ENTRY_SAFE (surf, tmp_surf, &bufmgr->surf_list, item_link)
979         {
980             TBM_LOG ("[libtbm:%d] "
981                     "Destroy surf(%p) \n",
982                     getpid(), surf);
983             tbm_surface_destroy(surf);
984         }
985     }
986
987     /* destroy the tizen global status */
988     _tbm_bufmgr_destroy_state (bufmgr);
989
990     /* destroy bufmgr priv */
991     bufmgr->backend->bufmgr_deinit (bufmgr->backend->priv);
992     bufmgr->backend->priv = NULL;
993     tbm_backend_free (bufmgr->backend);
994     bufmgr->backend = NULL;
995
996     pthread_mutex_destroy (&bufmgr->lock);
997
998     TBM_LOG ("[libtbm:%d] "
999             "tizen bufmgr destroy: bufmgr:%p\n",
1000             getpid(), bufmgr);
1001
1002     dlclose (bufmgr->module_data);
1003
1004     if(bufmgr->fd_flag)
1005         close(bufmgr->fd);
1006
1007     free (bufmgr);
1008     bufmgr = NULL;
1009     gBufMgr = NULL;
1010
1011     pthread_mutex_unlock (&gLock);
1012 }
1013
1014 int
1015 tbm_bo_size (tbm_bo bo)
1016 {
1017     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1018
1019     tbm_bufmgr bufmgr = bo->bufmgr;
1020     int size;
1021
1022     pthread_mutex_lock(&bufmgr->lock);
1023
1024     size = bufmgr->backend->bo_size(bo);
1025
1026     pthread_mutex_unlock(&bufmgr->lock);
1027
1028     return size;
1029 }
1030
1031 tbm_bo
1032 tbm_bo_ref (tbm_bo bo)
1033 {
1034     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), NULL);
1035
1036     tbm_bufmgr bufmgr = bo->bufmgr;
1037
1038     pthread_mutex_lock(&bufmgr->lock);
1039
1040     _tbm_bo_ref (bo);
1041
1042     pthread_mutex_unlock(&bufmgr->lock);
1043
1044     return bo;
1045 }
1046
1047 void
1048 tbm_bo_unref (tbm_bo bo)
1049 {
1050     TBM_RETURN_IF_FAIL(TBM_BO_IS_VALID(bo));
1051
1052     tbm_bufmgr bufmgr = bo->bufmgr;
1053
1054     pthread_mutex_lock (&bufmgr->lock);
1055
1056     _tbm_bo_unref (bo);
1057
1058     pthread_mutex_unlock(&bufmgr->lock);
1059 }
1060
1061 tbm_bo
1062 tbm_bo_alloc (tbm_bufmgr bufmgr, int size, int flags)
1063 {
1064     TBM_RETURN_VAL_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1065
1066     tbm_bo bo = NULL;
1067     void * bo_priv = NULL;
1068
1069     bo = calloc (1, sizeof(struct _tbm_bo));
1070     if(!bo)
1071         return NULL;
1072
1073     bo->bufmgr = bufmgr;
1074
1075     pthread_mutex_lock (&bufmgr->lock);
1076
1077     bo_priv = bufmgr->backend->bo_alloc (bo, size, flags);
1078     if (!bo_priv)
1079     {
1080         free (bo);
1081         pthread_mutex_unlock (&bufmgr->lock);
1082         return NULL;
1083     }
1084
1085     bo->ref_cnt = 1;
1086     bo->flags = flags;
1087     bo->tgl_key = INITIAL_KEY;
1088     bo->priv = bo_priv;
1089
1090     /* init bo state */
1091     if (!_tbm_bo_init_state (bo, CACHE_OP_CREATE))
1092     {
1093         _tbm_bo_unref (bo);
1094         pthread_mutex_unlock (&bufmgr->lock);
1095         return NULL;
1096     }
1097
1098     LIST_INITHEAD (&bo->user_data_list);
1099
1100     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1101
1102     pthread_mutex_unlock(&bufmgr->lock);
1103
1104     return bo;
1105 }
1106
1107 tbm_bo
1108 tbm_bo_import (tbm_bufmgr bufmgr, unsigned int key)
1109 {
1110     TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1111
1112     tbm_bo bo = NULL;
1113     void * bo_priv = NULL;
1114
1115     bo = calloc (1, sizeof(struct _tbm_bo));
1116     if(!bo)
1117         return NULL;
1118
1119     bo->bufmgr = bufmgr;
1120
1121     pthread_mutex_lock (&bufmgr->lock);
1122
1123     bo_priv = bufmgr->backend->bo_import (bo, key);
1124     if (!bo_priv)
1125     {
1126         free (bo);
1127         pthread_mutex_unlock (&bufmgr->lock);
1128         return NULL;
1129     }
1130
1131     bo->ref_cnt = 1;
1132     bo->tgl_key = INITIAL_KEY;
1133     bo->priv = bo_priv;
1134
1135     /* init bo state */
1136     if (!_tbm_bo_init_state (bo, CACHE_OP_IMPORT))
1137     {
1138         _tbm_bo_unref (bo);
1139         pthread_mutex_unlock (&bufmgr->lock);
1140         return NULL;
1141     }
1142
1143     LIST_INITHEAD (&bo->user_data_list);
1144
1145     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1146
1147     pthread_mutex_unlock (&bufmgr->lock);
1148
1149     return bo;
1150 }
1151
1152 tbm_bo
1153 tbm_bo_import_fd  (tbm_bufmgr bufmgr, tbm_fd fd)
1154 {
1155     tbm_bo bo = NULL;
1156
1157     return bo;
1158 }
1159
1160 unsigned int
1161 tbm_bo_export (tbm_bo bo)
1162 {
1163     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1164
1165     tbm_bufmgr bufmgr;
1166     int ret;
1167
1168     bufmgr = bo->bufmgr;
1169
1170     pthread_mutex_lock (&bufmgr->lock);
1171     ret = bufmgr->backend->bo_export (bo);
1172     pthread_mutex_unlock (&bufmgr->lock);
1173
1174     return ret;
1175 }
1176
1177 tbm_fd
1178 tbm_bo_export_fd (tbm_bo bo)
1179 {
1180     tbm_fd fd = 0;
1181
1182     return fd;
1183 }
1184
1185
1186 tbm_bo_handle
1187 tbm_bo_get_handle (tbm_bo bo, int device)
1188 {
1189     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1190
1191     tbm_bufmgr bufmgr;
1192     tbm_bo_handle bo_handle;
1193
1194     bufmgr = bo->bufmgr;
1195
1196     pthread_mutex_lock (&bufmgr->lock);
1197     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1198     pthread_mutex_unlock (&bufmgr->lock);
1199
1200     return bo_handle;
1201 }
1202
1203 tbm_bo_handle
1204 tbm_bo_map (tbm_bo bo, int device, int opt)
1205 {
1206     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1207
1208     tbm_bufmgr bufmgr;
1209     tbm_bo_handle bo_handle;
1210
1211     bufmgr = bo->bufmgr;
1212
1213     pthread_mutex_lock (&bufmgr->lock);
1214
1215     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1216
1217     _tbm_bo_lock (bo, device, opt);
1218
1219     bo_handle = bufmgr->backend->bo_map (bo, device, opt);
1220
1221     if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1222         _tbm_bo_set_state (bo, device, opt);
1223
1224     /* increase the map_count */
1225     bo->map_cnt++;
1226
1227     pthread_mutex_unlock (&bufmgr->lock);
1228
1229     return bo_handle;
1230 }
1231
1232 int
1233 tbm_bo_unmap (tbm_bo bo)
1234 {
1235     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1236
1237     tbm_bufmgr bufmgr;
1238     int ret;
1239
1240     bufmgr = bo->bufmgr;
1241
1242     pthread_mutex_lock (&bufmgr->lock);
1243
1244
1245     ret = bufmgr->backend->bo_unmap (bo);
1246
1247     /* decrease the map_count */
1248     bo->map_cnt--;
1249
1250     if (bo->map_cnt == 0)
1251         _tbm_bo_save_state (bo);
1252
1253      _tbm_bo_unlock (bo);
1254
1255     pthread_mutex_unlock (&bufmgr->lock);
1256
1257     return ret;
1258 }
1259
1260 int
1261 tbm_bo_swap (tbm_bo bo1, tbm_bo bo2)
1262 {
1263     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo1), 0);
1264     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo2), 0);
1265
1266     void* temp;
1267     unsigned int tmp_key;
1268
1269     if (bo1->bufmgr->backend->bo_size (bo1) != bo2->bufmgr->backend->bo_size (bo2))
1270         return 0;
1271
1272     pthread_mutex_lock (&bo1->bufmgr->lock);
1273
1274     tmp_key = bo1->tgl_key;
1275     bo1->tgl_key = bo2->tgl_key;
1276     bo2->tgl_key = tmp_key;
1277
1278     temp = bo1->priv;
1279     bo1->priv = bo2->priv;
1280     bo2->priv = temp;
1281
1282     pthread_mutex_unlock (&bo1->bufmgr->lock);
1283
1284     return 1;
1285 }
1286
1287 int
1288 tbm_bo_locked (tbm_bo bo)
1289 {
1290     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1291
1292     tbm_bufmgr bufmgr;
1293
1294     bufmgr = bo->bufmgr;
1295
1296     if (bufmgr->lock_type == LOCK_TRY_NEVER)
1297         return 0;
1298
1299     pthread_mutex_lock (&bufmgr->lock);
1300
1301     if (bo->lock_cnt > 0)
1302     {
1303         pthread_mutex_unlock (&bufmgr->lock);
1304         return 1;
1305     }
1306
1307     pthread_mutex_unlock (&bufmgr->lock);
1308
1309     return 0;
1310 }
1311
1312
1313 int
1314 tbm_bo_add_user_data (tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1315 {
1316     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1317
1318     tbm_user_data *data;
1319
1320     /* check if the data according to the key exist if so, return false.*/
1321     data = _user_data_lookup (&bo->user_data_list, key);
1322     if (data)
1323     {
1324         TBM_LOG ("[libtbm:%d] "
1325                 "waring: %s:%d user data already exist. key:%ld\n",
1326                 getpid(), __FUNCTION__, __LINE__, key);
1327         return 0;
1328     }
1329
1330     data = _user_data_create (key, data_free_func);
1331     if (!data)
1332         return 0;
1333
1334     LIST_ADD (&data->item_link, &bo->user_data_list);
1335
1336     return 1;
1337 }
1338
1339 int
1340 tbm_bo_set_user_data (tbm_bo bo, unsigned long key, void* data)
1341 {
1342     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1343
1344     tbm_user_data *old_data;
1345
1346     if (LIST_IS_EMPTY (&bo->user_data_list))
1347         return 0;
1348
1349     old_data = _user_data_lookup (&bo->user_data_list, key);
1350     if (!old_data)
1351         return 0;
1352
1353     if (old_data->data && old_data->free_func)
1354         old_data->free_func(old_data->data);
1355
1356     old_data->data = data;
1357
1358     return 1;
1359 }
1360
1361 int
1362 tbm_bo_get_user_data (tbm_bo bo, unsigned long key, void** data)
1363 {
1364     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1365
1366     tbm_user_data* old_data;
1367
1368     if (!data || LIST_IS_EMPTY (&bo->user_data_list))
1369         return 0;
1370
1371     old_data = _user_data_lookup (&bo->user_data_list, key);
1372     if (!old_data)
1373     {
1374         *data = NULL;
1375         return 0;
1376     }
1377
1378     *data = old_data->data;
1379
1380     return 1;
1381 }
1382
1383 int
1384 tbm_bo_delete_user_data (tbm_bo bo, unsigned long key)
1385 {
1386     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1387
1388     tbm_user_data *old_data = (void *)0;
1389
1390     if (LIST_IS_EMPTY (&bo->user_data_list))
1391         return 0;
1392
1393     old_data = _user_data_lookup (&bo->user_data_list, key);
1394     if (!old_data)
1395         return 0;
1396
1397     _user_data_delete (old_data);
1398
1399     return 1;
1400 }
1401