remove bufmgr parameter at the tbm_surface_internal APIs
[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
1096     pthread_mutex_unlock (&gLock);
1097 }
1098
1099 int
1100 tbm_bo_size (tbm_bo bo)
1101 {
1102     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1103
1104     tbm_bufmgr bufmgr = bo->bufmgr;
1105     int size;
1106
1107     pthread_mutex_lock(&bufmgr->lock);
1108
1109     size = bufmgr->backend->bo_size(bo);
1110
1111     pthread_mutex_unlock(&bufmgr->lock);
1112
1113     return size;
1114 }
1115
1116 tbm_bo
1117 tbm_bo_ref (tbm_bo bo)
1118 {
1119     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), NULL);
1120
1121     tbm_bufmgr bufmgr = bo->bufmgr;
1122
1123     pthread_mutex_lock(&bufmgr->lock);
1124
1125     _tbm_bo_ref (bo);
1126
1127     pthread_mutex_unlock(&bufmgr->lock);
1128
1129     return bo;
1130 }
1131
1132 void
1133 tbm_bo_unref (tbm_bo bo)
1134 {
1135     TBM_RETURN_IF_FAIL(TBM_BO_IS_VALID(bo));
1136
1137     tbm_bufmgr bufmgr = bo->bufmgr;
1138
1139     pthread_mutex_lock (&bufmgr->lock);
1140
1141     _tbm_bo_unref (bo);
1142
1143     pthread_mutex_unlock(&bufmgr->lock);
1144 }
1145
1146 tbm_bo
1147 tbm_bo_alloc (tbm_bufmgr bufmgr, int size, int flags)
1148 {
1149     TBM_RETURN_VAL_IF_FAIL (TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
1150
1151     tbm_bo bo = NULL;
1152     void * bo_priv = NULL;
1153
1154     bo = calloc (1, sizeof(struct _tbm_bo));
1155     if(!bo)
1156         return NULL;
1157
1158     bo->bufmgr = bufmgr;
1159
1160     pthread_mutex_lock (&bufmgr->lock);
1161
1162     bo_priv = bufmgr->backend->bo_alloc (bo, size, flags);
1163     if (!bo_priv)
1164     {
1165         free (bo);
1166         pthread_mutex_unlock (&bufmgr->lock);
1167         return NULL;
1168     }
1169
1170     bo->ref_cnt = 1;
1171     bo->flags = flags;
1172     bo->tgl_key = INITIAL_KEY;
1173     bo->priv = bo_priv;
1174
1175     /* init bo state */
1176     if (!_tbm_bo_init_state (bo, CACHE_OP_CREATE))
1177     {
1178         _tbm_bo_unref (bo);
1179         pthread_mutex_unlock (&bufmgr->lock);
1180         return NULL;
1181     }
1182
1183     LIST_INITHEAD (&bo->user_data_list);
1184
1185     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1186
1187     pthread_mutex_unlock(&bufmgr->lock);
1188
1189     return bo;
1190 }
1191
1192 tbm_bo
1193 tbm_bo_import (tbm_bufmgr bufmgr, unsigned int key)
1194 {
1195     TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1196
1197     tbm_bo bo = NULL;
1198     void * bo_priv = NULL;
1199
1200     bo = calloc (1, sizeof(struct _tbm_bo));
1201     if(!bo)
1202         return NULL;
1203
1204     bo->bufmgr = bufmgr;
1205
1206     pthread_mutex_lock (&bufmgr->lock);
1207
1208     bo_priv = bufmgr->backend->bo_import (bo, key);
1209     if (!bo_priv)
1210     {
1211         free (bo);
1212         pthread_mutex_unlock (&bufmgr->lock);
1213         return NULL;
1214     }
1215
1216     bo->ref_cnt = 1;
1217     bo->tgl_key = INITIAL_KEY;
1218     bo->priv = bo_priv;
1219
1220     /* init bo state */
1221     if (!_tbm_bo_init_state (bo, CACHE_OP_IMPORT))
1222     {
1223         _tbm_bo_unref (bo);
1224         pthread_mutex_unlock (&bufmgr->lock);
1225         return NULL;
1226     }
1227
1228     LIST_INITHEAD (&bo->user_data_list);
1229
1230     LIST_ADD (&bo->item_link, &bufmgr->bo_list);
1231
1232     pthread_mutex_unlock (&bufmgr->lock);
1233
1234     return bo;
1235 }
1236
1237 tbm_bo
1238 tbm_bo_import_fd  (tbm_bufmgr bufmgr, tbm_fd fd)
1239 {
1240     tbm_bo bo = NULL;
1241
1242     return bo;
1243 }
1244
1245 unsigned int
1246 tbm_bo_export (tbm_bo bo)
1247 {
1248     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1249
1250     tbm_bufmgr bufmgr;
1251     int ret;
1252
1253     bufmgr = bo->bufmgr;
1254
1255     pthread_mutex_lock (&bufmgr->lock);
1256     ret = bufmgr->backend->bo_export (bo);
1257     pthread_mutex_unlock (&bufmgr->lock);
1258
1259     return ret;
1260 }
1261
1262 tbm_fd
1263 tbm_bo_export_fd (tbm_bo bo)
1264 {
1265     tbm_fd fd = 0;
1266
1267     return fd;
1268 }
1269
1270
1271 tbm_bo_handle
1272 tbm_bo_get_handle (tbm_bo bo, int device)
1273 {
1274     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1275
1276     tbm_bufmgr bufmgr;
1277     tbm_bo_handle bo_handle;
1278
1279     bufmgr = bo->bufmgr;
1280
1281     pthread_mutex_lock (&bufmgr->lock);
1282     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1283     pthread_mutex_unlock (&bufmgr->lock);
1284
1285     return bo_handle;
1286 }
1287
1288 tbm_bo_handle
1289 tbm_bo_map (tbm_bo bo, int device, int opt)
1290 {
1291     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), (tbm_bo_handle)0);
1292
1293     tbm_bufmgr bufmgr;
1294     tbm_bo_handle bo_handle;
1295
1296     bufmgr = bo->bufmgr;
1297
1298     pthread_mutex_lock (&bufmgr->lock);
1299
1300     bo_handle = bufmgr->backend->bo_get_handle (bo, device);
1301
1302     _tbm_bo_lock (bo, device, opt);
1303
1304     bo_handle = bufmgr->backend->bo_map (bo, device, opt);
1305
1306     if (bufmgr->use_map_cache == 1 && bo->map_cnt == 0)
1307         _tbm_bo_set_state (bo, device, opt);
1308
1309     /* increase the map_count */
1310     bo->map_cnt++;
1311
1312     pthread_mutex_unlock (&bufmgr->lock);
1313
1314     return bo_handle;
1315 }
1316
1317 int
1318 tbm_bo_unmap (tbm_bo bo)
1319 {
1320     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1321
1322     tbm_bufmgr bufmgr;
1323     int ret;
1324
1325     bufmgr = bo->bufmgr;
1326
1327     pthread_mutex_lock (&bufmgr->lock);
1328
1329
1330     ret = bufmgr->backend->bo_unmap (bo);
1331
1332     /* decrease the map_count */
1333     bo->map_cnt--;
1334
1335     if (bo->map_cnt == 0)
1336         _tbm_bo_save_state (bo);
1337
1338      _tbm_bo_unlock (bo);
1339
1340     pthread_mutex_unlock (&bufmgr->lock);
1341
1342     return ret;
1343 }
1344
1345 int
1346 tbm_bo_swap (tbm_bo bo1, tbm_bo bo2)
1347 {
1348     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo1), 0);
1349     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo2), 0);
1350
1351     void* temp;
1352     unsigned int tmp_key;
1353
1354     if (bo1->bufmgr->backend->bo_size (bo1) != bo2->bufmgr->backend->bo_size (bo2))
1355         return 0;
1356
1357     pthread_mutex_lock (&bo1->bufmgr->lock);
1358
1359     tmp_key = bo1->tgl_key;
1360     bo1->tgl_key = bo2->tgl_key;
1361     bo2->tgl_key = tmp_key;
1362
1363     temp = bo1->priv;
1364     bo1->priv = bo2->priv;
1365     bo2->priv = temp;
1366
1367     pthread_mutex_unlock (&bo1->bufmgr->lock);
1368
1369     return 1;
1370 }
1371
1372 int
1373 tbm_bo_locked (tbm_bo bo)
1374 {
1375     TBM_RETURN_VAL_IF_FAIL (TBM_BO_IS_VALID(bo), 0);
1376
1377     tbm_bufmgr bufmgr;
1378
1379     bufmgr = bo->bufmgr;
1380
1381     if (bufmgr->lock_type == LOCK_TRY_NEVER)
1382         return 0;
1383
1384     pthread_mutex_lock (&bufmgr->lock);
1385
1386     if (bo->lock_cnt > 0)
1387     {
1388         pthread_mutex_unlock (&bufmgr->lock);
1389         return 1;
1390     }
1391
1392     pthread_mutex_unlock (&bufmgr->lock);
1393
1394     return 0;
1395 }
1396
1397
1398 int
1399 tbm_bo_add_user_data (tbm_bo bo, unsigned long key, tbm_data_free data_free_func)
1400 {
1401     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1402
1403     tbm_user_data *data;
1404
1405     /* check if the data according to the key exist if so, return false.*/
1406     data = _user_data_lookup (&bo->user_data_list, key);
1407     if (data)
1408     {
1409         TBM_LOG ("[libtbm:%d] "
1410                 "waring: %s:%d user data already exist. key:%ld\n",
1411                 getpid(), __FUNCTION__, __LINE__, key);
1412         return 0;
1413     }
1414
1415     data = _user_data_create (key, data_free_func);
1416     if (!data)
1417         return 0;
1418
1419     LIST_ADD (&data->item_link, &bo->user_data_list);
1420
1421     return 1;
1422 }
1423
1424 int
1425 tbm_bo_set_user_data (tbm_bo bo, unsigned long key, void* data)
1426 {
1427     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1428
1429     tbm_user_data *old_data;
1430
1431     if (LIST_IS_EMPTY (&bo->user_data_list))
1432         return 0;
1433
1434     old_data = _user_data_lookup (&bo->user_data_list, key);
1435     if (!old_data)
1436         return 0;
1437
1438     if (old_data->data && old_data->free_func)
1439         old_data->free_func(old_data->data);
1440
1441     old_data->data = data;
1442
1443     return 1;
1444 }
1445
1446 int
1447 tbm_bo_get_user_data (tbm_bo bo, unsigned long key, void** data)
1448 {
1449     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1450
1451     tbm_user_data* old_data;
1452
1453     if (!data || LIST_IS_EMPTY (&bo->user_data_list))
1454         return 0;
1455
1456     old_data = _user_data_lookup (&bo->user_data_list, key);
1457     if (!old_data)
1458     {
1459         *data = NULL;
1460         return 0;
1461     }
1462
1463     *data = old_data->data;
1464
1465     return 1;
1466 }
1467
1468 int
1469 tbm_bo_delete_user_data (tbm_bo bo, unsigned long key)
1470 {
1471     TBM_RETURN_VAL_IF_FAIL(TBM_BO_IS_VALID(bo), 0);
1472
1473     tbm_user_data *old_data = (void *)0;
1474
1475     if (LIST_IS_EMPTY (&bo->user_data_list))
1476         return 0;
1477
1478     old_data = _user_data_lookup (&bo->user_data_list, key);
1479     if (!old_data)
1480         return 0;
1481
1482     _user_data_delete (old_data);
1483
1484     return 1;
1485 }
1486
1487 int
1488 tbm_bo_cache_flush(tbm_bo bo, int flags)
1489 {
1490     tbm_bufmgr bufmgr = bo->bufmgr;
1491
1492     bufmgr->backend->bo_cache_flush (bo, flags);
1493
1494     RETURN_VAL_CHECK_FLAG (TBM_CACHE_CTRL_BACKEND_VALID(bufmgr->backend->flags), 1);
1495
1496     unsigned short cntFlush = 0;
1497     unsigned int is_locked;
1498
1499     /* get cache state of a bo */
1500     bo->cache_state.val = _tgl_get_data (bufmgr->lock_fd, bo->tgl_key, &is_locked);
1501
1502     if (!bo->cache_state.data.isCacheable)
1503         return 1;
1504
1505     /* get global cache flush count */
1506     cntFlush = (unsigned short)_tgl_get_data (bufmgr->lock_fd, GLOBAL_KEY, NULL);
1507
1508     bo->cache_state.data.isDirtied = DEVICE_NONE;
1509     bo->cache_state.data.isCached = 0;
1510
1511     /* set global cache flush count */
1512     _tgl_set_data (bufmgr->lock_fd, GLOBAL_KEY, (unsigned int)(++cntFlush));
1513
1514     DBG ("[libtbm:%d] \tcache(%d,%d,%d)....  cntFlush(%d)\n", getpid(),
1515              bo->cache_state.data.isCacheable,
1516              bo->cache_state.data.isCached,
1517              bo->cache_state.data.isDirtied,
1518              cntFlush);
1519
1520     return 1;
1521 }