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