Remove code for 1.0 version backend
[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 "list.h"
38
39 #define DEBUG
40 #ifdef DEBUG
41 int bDebug;
42 #define DBG(...) {if (bDebug&0x1) TBM_LOG(__VA_ARGS__);}
43 #define DBG_LOCK(...) {if (bDebug&0x2) TBM_LOG(__VA_ARGS__);}
44 #else
45 #define DBG(...)
46 #define DBG_LOCK(...)
47 #endif
48
49 #define PREFIX_LIB    "libtbm_"
50 #define SUFFIX_LIB    ".so"
51 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
52
53 /* values to indicate unspecified fields in XF86ModReqInfo. */
54 #define MAJOR_UNSPEC        0xFF
55 #define MINOR_UNSPEC        0xFF
56 #define PATCH_UNSPEC        0xFFFF
57 #define ABI_VERS_UNSPEC   0xFFFFFFFF
58
59 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
60                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
61 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
62 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
63 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
64
65 enum {
66         LOCK_TRY_ONCE,
67         LOCK_TRY_ALWAYS,
68         LOCK_TRY_NEVER
69 };
70
71 pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
72 tbm_bufmgr gBufMgr;
73
74 static __thread tbm_error_e tbm_last_error = TBM_ERROR_NONE;
75
76 static void
77 _tbm_set_last_result(tbm_error_e err)
78 {
79         tbm_last_error = err;
80 }
81
82 static void
83 _tbm_util_get_appname_brief(char *brief)
84 {
85         char delim[] = "/";
86         char *token = NULL;
87         char temp[255] = {0,};
88         char *saveptr = NULL;
89
90         token = strtok_r(brief, delim, &saveptr);
91
92         while (token != NULL) {
93                 memset(temp, 0x00, 255 * sizeof(char));
94                 strncpy(temp, token, 254 * sizeof(char));
95                 token = strtok_r(NULL, delim, &saveptr);
96         }
97
98         snprintf(brief, sizeof(temp), "%s", temp);
99 }
100
101 static void
102 _tbm_util_get_appname_from_pid(long pid, char *str)
103 {
104         FILE *fp;
105         int len;
106         long app_pid = pid;
107         char fn_cmdline[255] = {0,};
108         char cmdline[255] = {0,};
109
110         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", app_pid);
111
112         fp = fopen(fn_cmdline, "r");
113         if (fp == 0) {
114                 fprintf(stderr, "cannot file open /proc/%ld/cmdline", app_pid);
115                 return;
116         }
117
118         if (!fgets(cmdline, 255, fp)) {
119                 fprintf(stderr, "fail to get appname for pid(%ld)\n", app_pid);
120                 fclose(fp);
121                 return;
122         }
123         fclose(fp);
124
125         len = strlen(cmdline);
126         if (len < 1)
127                 memset(cmdline, 0x00, 255);
128         else
129                 cmdline[len] = 0;
130
131         snprintf(str, sizeof(cmdline), "%s", cmdline);
132 }
133
134 tbm_user_data
135 *user_data_lookup(struct list_head *user_data_list, unsigned long key)
136 {
137         tbm_user_data *user_data = NULL;
138         tbm_user_data *old_data = NULL, *tmp = NULL;
139
140         if (!LIST_IS_EMPTY(user_data_list)) {
141                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, user_data_list, item_link) {
142                         if (old_data->key == key) {
143                                 user_data = old_data;
144                                 return user_data;
145                         }
146                 }
147         }
148
149         return user_data;
150 }
151
152 tbm_user_data
153 *user_data_create(unsigned long key, tbm_data_free data_free_func)
154 {
155         tbm_user_data *user_data = NULL;
156
157         user_data = calloc(1, sizeof(tbm_user_data));
158         if (!user_data)
159                 return NULL;
160
161         user_data->key = key;
162         user_data->free_func = data_free_func;
163         user_data->data = (void *)0;
164
165         return user_data;
166 }
167
168 void
169 user_data_delete(tbm_user_data *user_data)
170 {
171         if (user_data->data && user_data->free_func)
172                 user_data->free_func(user_data->data);
173
174         LIST_DEL(&user_data->item_link);
175
176         free(user_data);
177 }
178
179 static int
180 _bo_lock(tbm_bo bo, int device, int opt)
181 {
182         tbm_bufmgr bufmgr = bo->bufmgr;
183         int ret = 0;
184
185         if (bufmgr->backend->bo_lock) {
186                 ret = bufmgr->backend->bo_lock(bo, device, opt);
187         } else {
188                 ret = 1;
189         }
190
191         return ret;
192 }
193
194 static void
195 _bo_unlock(tbm_bo bo)
196 {
197         tbm_bufmgr bufmgr = bo->bufmgr;
198
199         if (bufmgr->backend->bo_unlock) {
200                 bufmgr->backend->bo_unlock(bo);
201         }
202 }
203
204 static int
205 _tbm_bo_lock(tbm_bo bo, int device, int opt)
206 {
207         tbm_bufmgr bufmgr = NULL;
208         int old;
209         int ret = 0;
210
211         if (!bo)
212                 return 0;
213
214         bufmgr = bo->bufmgr;
215
216         /* do not try to lock the bo */
217         if (bufmgr->lock_type == LOCK_TRY_NEVER)
218                 return 1;
219
220         if (bo->lock_cnt < 0) {
221                 TBM_LOG("[libtbm:%d] "
222                         "error %s:%d bo:%p LOCK_CNT=%d\n",
223                         getpid(), __func__, __LINE__, bo, bo->lock_cnt);
224         }
225
226         old = bo->lock_cnt;
227         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
228                 if (bo->lock_cnt == 0) {
229                         pthread_mutex_unlock(&bufmgr->lock);
230                         ret = _bo_lock(bo, device, opt);
231                         pthread_mutex_lock(&bufmgr->lock);
232                         if (ret)
233                                 bo->lock_cnt++;
234                 } else
235                         ret = 1;
236         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
237                 pthread_mutex_unlock(&bufmgr->lock);
238                 ret = _bo_lock(bo, device, opt);
239                 pthread_mutex_lock(&bufmgr->lock);
240                 if (ret)
241                         bo->lock_cnt++;
242         } else {
243                 TBM_LOG("[libtbm:%d] "
244                         "error %s:%d bo:%p lock_type is wrong.\n",
245                         getpid(), __func__, __LINE__, bo);
246         }
247
248         DBG_LOCK("[libtbm:%d] >> LOCK bo:%p(%d->%d)\n", getpid(),
249                  bo, old, bo->lock_cnt);
250
251         return ret;
252 }
253
254 static void
255 _tbm_bo_unlock(tbm_bo bo)
256 {
257         tbm_bufmgr bufmgr = NULL;
258
259         int old;
260
261         if (!bo)
262                 return;
263
264         bufmgr = bo->bufmgr;
265
266         /* do not try to unlock the bo */
267         if (bufmgr->lock_type == LOCK_TRY_NEVER)
268                 return;
269
270         old = bo->lock_cnt;
271         if (bufmgr->lock_type == LOCK_TRY_ONCE) {
272                 if (bo->lock_cnt > 0) {
273                         bo->lock_cnt--;
274                         if (bo->lock_cnt == 0)
275                                 _bo_unlock(bo);
276                 }
277         } else if (bufmgr->lock_type == LOCK_TRY_ALWAYS) {
278                 if (bo->lock_cnt > 0) {
279                         bo->lock_cnt--;
280                         _bo_unlock(bo);
281                 }
282         } else {
283                 TBM_LOG("[libtbm:%d] "
284                         "error %s:%d bo:%p lock_type is wrong.\n",
285                         getpid(), __func__, __LINE__, bo);
286         }
287
288         if (bo->lock_cnt < 0)
289                 bo->lock_cnt = 0;
290
291         DBG_LOCK("[libtbm:%d] << unlock bo:%p(%d->%d)\n", getpid(),
292                  bo, old, bo->lock_cnt);
293 }
294
295 static int
296 _tbm_bo_is_valid(tbm_bo bo)
297 {
298         tbm_bo old_data = NULL, tmp = NULL;
299
300         if (bo == NULL)
301                 return 0;
302
303         if (!LIST_IS_EMPTY(&gBufMgr->bo_list)) {
304                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &gBufMgr->bo_list, item_link) {
305                         if (old_data == bo)
306                                 return 1;
307                 }
308
309         }
310         return 0;
311 }
312
313 static void
314 _tbm_bo_ref(tbm_bo bo)
315 {
316         bo->ref_cnt++;
317 }
318
319 static void
320 _tbm_bo_unref(tbm_bo bo)
321 {
322         tbm_bufmgr bufmgr = bo->bufmgr;
323         tbm_user_data *old_data = NULL, *tmp = NULL;
324
325         if (bo->ref_cnt <= 0)
326                 return;
327
328         bo->ref_cnt--;
329         if (bo->ref_cnt == 0) {
330                 /* destory the user_data_list */
331                 if (!LIST_IS_EMPTY(&bo->user_data_list)) {
332                         LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &bo->user_data_list, item_link) {
333                                 DBG("[libtbm:%d] free user_data\n",
334                                     getpid());
335                                 user_data_delete(old_data);
336                         }
337                 }
338
339                 if (bo->lock_cnt > 0) {
340                         TBM_LOG("[libtbm:%d] "
341                                 "error %s:%d lock_cnt:%d\n",
342                                 getpid(), __func__, __LINE__, bo->lock_cnt);
343                         _bo_unlock(bo);
344                 }
345
346                 /* call the bo_free */
347                 bufmgr->backend->bo_free(bo);
348                 bo->priv = NULL;
349
350                 LIST_DEL(&bo->item_link);
351                 free(bo);
352                 bo = NULL;
353         }
354
355 }
356
357 static int
358 _check_version(TBMModuleVersionInfo *data)
359 {
360         int abimaj, abimin;
361         int vermaj, vermin;
362
363         abimaj = GET_ABI_MAJOR(data->abiversion);
364         abimin = GET_ABI_MINOR(data->abiversion);
365
366         DBG("[libtbm:%d] "
367             "TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
368             getpid(), data->modname ? data->modname : "UNKNOWN!",
369             data->vendor ? data->vendor : "UNKNOWN!", abimaj, abimin);
370
371         vermaj = GET_ABI_MAJOR(TBM_ABI_VERSION);
372         vermin = GET_ABI_MINOR(TBM_ABI_VERSION);
373
374         DBG("[libtbm:%d] "
375             "TBM ABI version %d.%d\n",
376             getpid(), vermaj, vermin);
377
378         if (abimaj != vermaj) {
379                 TBM_LOG("[libtbm:%d] "
380                         "TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
381                         getpid(), abimaj, vermaj);
382                 return 0;
383         } else if (abimin > vermin) {
384                 TBM_LOG("[libtbm:%d] "
385                         "TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
386                         getpid(), abimin, vermin);
387                 return 0;
388         }
389         return 1;
390 }
391
392 static int
393 _tbm_bufmgr_load_module(tbm_bufmgr bufmgr, int fd, const char *file)
394 {
395         char path[PATH_MAX] = { 0, };
396         TBMModuleData *initdata = NULL;
397         void *module_data;
398
399         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
400
401         module_data = dlopen(path, RTLD_LAZY);
402         if (!module_data) {
403                 TBM_LOG("[libtbm:%d] "
404                         "failed to load module: %s(%s)\n",
405                         getpid(), dlerror(), file);
406                 return 0;
407         }
408
409         initdata = dlsym(module_data, "tbmModuleData");
410         if (initdata) {
411                 ModuleInitProc init;
412                 TBMModuleVersionInfo *vers;
413
414                 vers = initdata->vers;
415                 init = initdata->init;
416
417                 if (vers) {
418                         if (!_check_version(vers)) {
419                                 dlclose(module_data);
420                                 return 0;
421                         }
422                 } else {
423                         TBM_LOG("[libtbm:%d] "
424                                 "Error: module does not supply version information.\n",
425                                 getpid());
426
427                         dlclose(module_data);
428                         return 0;
429                 }
430
431                 if (init) {
432                         if (!init(bufmgr, fd)) {
433                                 TBM_LOG("[libtbm:%d] "
434                                         "Fail to init module(%s)\n",
435                                         getpid(), file);
436                                 dlclose(module_data);
437                                 return 0;
438                         }
439
440                         if (!bufmgr->backend || !bufmgr->backend->priv) {
441                                 TBM_LOG("[libtbm:%d] "
442                                         "Error: module(%s) wrong operation. Check backend or backend's priv.\n",
443                                         getpid(), file);
444                                 dlclose(module_data);
445                                 return 0;
446                         }
447                 } else {
448                         TBM_LOG("[libtbm:%d] "
449                                 "Error: module does not supply init symbol.\n",
450                                 getpid());
451                         dlclose(module_data);
452                         return 0;
453                 }
454         } else {
455                 TBM_LOG("[libtbm:%d] "
456                         "Error: module does not have data object.\n",
457                         getpid());
458                 dlclose(module_data);
459                 return 0;
460         }
461
462         bufmgr->module_data = module_data;
463
464         DBG("[libtbm:%d] "
465             "Success to load module(%s)\n",
466             getpid(), file);
467
468         return 1;
469 }
470
471 static int
472 _tbm_load_module(tbm_bufmgr bufmgr, int fd)
473 {
474         struct dirent **namelist;
475         const char *p = NULL;
476         int n;
477         int ret = 0;
478
479         /* load bufmgr priv from default lib */
480         ret = _tbm_bufmgr_load_module(bufmgr, fd, DEFAULT_LIB);
481
482         /* load bufmgr priv from configured path */
483         if (!ret) {
484                 n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
485                 if (n < 0) {
486                         TBM_LOG("[libtbm:%d] "
487                                 "no files : %s\n",
488                                 getpid(), BUFMGR_MODULE_DIR);
489                 } else {
490                         while (n--) {
491                                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
492                                         p = strstr(namelist[n]->d_name, SUFFIX_LIB);
493                                         if (p && !strcmp(p, SUFFIX_LIB))
494                                                 ret = _tbm_bufmgr_load_module(bufmgr, fd, namelist[n]->d_name);
495                                 }
496                                 free(namelist[n]);
497                         }
498                         free(namelist);
499                 }
500         }
501
502         return ret;
503 }
504
505 tbm_bufmgr
506 tbm_bufmgr_init(int fd)
507 {
508         char *env;
509
510         pthread_mutex_lock(&gLock);
511
512 #ifdef DEBUG
513         env = getenv("GEM_DEBUG");
514         if (env) {
515                 bDebug = atoi(env);
516                 TBM_LOG("GEM_DEBUG=%s\n", env);
517         } else {
518                 bDebug = 0;
519         }
520 #endif
521
522         /* initialize buffer manager */
523         if (gBufMgr) {
524                 gBufMgr->ref_count++;
525
526                 DBG("[libtbm:%d] bufmgr ref: fd=%d, ref_count:%d\n",
527                     getpid(), gBufMgr->fd, gBufMgr->ref_count);
528                 pthread_mutex_unlock(&gLock);
529                 return gBufMgr;
530         }
531
532         DBG("[libtbm:%d] bufmgr init\n", getpid());
533
534         /* allocate bufmgr */
535         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
536         if (!gBufMgr) {
537                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
538                 pthread_mutex_unlock(&gLock);
539                 return NULL;
540         }
541
542         gBufMgr->fd = fd;
543
544         /* load bufmgr priv from env */
545         if (!_tbm_load_module(gBufMgr, gBufMgr->fd)) {
546                 _tbm_set_last_result(TBM_BO_ERROR_LOAD_MODULE_FAILED);
547                 TBM_LOG("[libtbm:%d] error : Fail to load bufmgr backend\n", getpid());
548
549                 free(gBufMgr);
550                 gBufMgr = NULL;
551                 pthread_mutex_unlock(&gLock);
552                 return NULL;
553         }
554
555         /* log for tbm backend_flag */
556         DBG("[libtbm:%d] ", getpid());
557         DBG("backend flag:%x:", gBufMgr->backend->flags);
558         DBG("\n");
559
560         gBufMgr->ref_count = 1;
561
562         DBG("[libtbm:%d] create tizen bufmgr: ref_count:%d\n",
563             getpid(), gBufMgr->ref_count);
564
565         if (pthread_mutex_init(&gBufMgr->lock, NULL) != 0) {
566                 _tbm_set_last_result(TBM_BO_ERROR_THREAD_INIT_FAILED);
567                 gBufMgr->backend->bufmgr_deinit(gBufMgr->backend->priv);
568                 tbm_backend_free(gBufMgr->backend);
569                 dlclose(gBufMgr->module_data);
570                 free(gBufMgr);
571                 gBufMgr = NULL;
572                 pthread_mutex_unlock(&gLock);
573                 return NULL;
574         }
575
576         /* setup the lock_type */
577         env = getenv("BUFMGR_LOCK_TYPE");
578         if (env && !strcmp(env, "always"))
579                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
580         else if (env && !strcmp(env, "none"))
581                 gBufMgr->lock_type = LOCK_TRY_NEVER;
582         else if (env && !strcmp(env, "once"))
583                 gBufMgr->lock_type = LOCK_TRY_ONCE;
584         else
585                 gBufMgr->lock_type = LOCK_TRY_ALWAYS;
586
587         DBG("[libtbm:%d] BUFMGR_LOCK_TYPE=%s\n",
588             getpid(), env ? env : "default:once");
589
590         /* intialize bo_list */
591         LIST_INITHEAD(&gBufMgr->bo_list);
592
593         /* intialize surf_list */
594         LIST_INITHEAD(&gBufMgr->surf_list);
595
596         pthread_mutex_unlock(&gLock);
597         return gBufMgr;
598 }
599
600 void
601 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
602 {
603         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
604
605         tbm_bo bo = NULL;
606         tbm_bo tmp = NULL;
607
608         tbm_surface_h surf = NULL;
609         tbm_surface_h tmp_surf = NULL;
610
611         pthread_mutex_lock(&gLock);
612
613         bufmgr->ref_count--;
614         if (bufmgr->ref_count > 0) {
615                 TBM_LOG("[libtbm:%d] "
616                         "tizen bufmgr destroy: bufmgr:%p, ref_count:%d\n",
617                         getpid(), bufmgr, bufmgr->ref_count);
618                 pthread_mutex_unlock(&gLock);
619                 return;
620         }
621
622         /* destroy bo_list */
623         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
624                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
625                         TBM_LOG("[libtbm:%d] "
626                                 "Un-freed bo(%p, ref:%d)\n",
627                                 getpid(), bo, bo->ref_cnt);
628                         bo->ref_cnt = 1;
629                         tbm_bo_unref(bo);
630                 }
631         }
632
633         /* destroy surf_list */
634         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
635                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
636                         TBM_LOG("[libtbm:%d] "
637                                 "Destroy surf(%p)\n",
638                                 getpid(), surf);
639                         tbm_surface_destroy(surf);
640                 }
641         }
642
643         /* destroy bufmgr priv */
644         bufmgr->backend->bufmgr_deinit(bufmgr->backend->priv);
645         bufmgr->backend->priv = NULL;
646         tbm_backend_free(bufmgr->backend);
647         bufmgr->backend = NULL;
648
649         pthread_mutex_destroy(&bufmgr->lock);
650
651         DBG("[libtbm:%d] "
652             "tizen bufmgr destroy: bufmgr:%p\n",
653             getpid(), bufmgr);
654
655         dlclose(bufmgr->module_data);
656
657         if (bufmgr->fd > 0)
658                 close(bufmgr->fd);
659
660         free(bufmgr);
661         bufmgr = NULL;
662         gBufMgr = NULL;
663
664         pthread_mutex_unlock(&gLock);
665 }
666
667 int
668 tbm_bo_size(tbm_bo bo)
669 {
670         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
671
672         tbm_bufmgr bufmgr = bo->bufmgr;
673         int size;
674
675         pthread_mutex_lock(&bufmgr->lock);
676
677         size = bufmgr->backend->bo_size(bo);
678
679         pthread_mutex_unlock(&bufmgr->lock);
680
681         return size;
682 }
683
684 tbm_bo
685 tbm_bo_ref(tbm_bo bo)
686 {
687         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), NULL);
688
689         tbm_bufmgr bufmgr = bo->bufmgr;
690
691         pthread_mutex_lock(&bufmgr->lock);
692
693         _tbm_bo_ref(bo);
694
695         pthread_mutex_unlock(&bufmgr->lock);
696
697         return bo;
698 }
699
700 void
701 tbm_bo_unref(tbm_bo bo)
702 {
703         TBM_RETURN_IF_FAIL(_tbm_bo_is_valid(bo));
704
705         tbm_bufmgr bufmgr = bo->bufmgr;
706
707         pthread_mutex_lock(&bufmgr->lock);
708
709         _tbm_bo_unref(bo);
710
711         pthread_mutex_unlock(&bufmgr->lock);
712 }
713
714 tbm_bo
715 tbm_bo_alloc(tbm_bufmgr bufmgr, int size, int flags)
716 {
717         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr) && (size > 0), NULL);
718
719         tbm_bo bo = NULL;
720         void *bo_priv = NULL;
721
722         bo = calloc(1, sizeof(struct _tbm_bo));
723         if (!bo) {
724                 _tbm_set_last_result(TBM_BO_ERROR_HEAP_ALLOC_FAILED);
725                 return NULL;
726         }
727
728         bo->bufmgr = bufmgr;
729
730         pthread_mutex_lock(&bufmgr->lock);
731
732         bo_priv = bufmgr->backend->bo_alloc(bo, size, flags);
733         if (!bo_priv) {
734                 _tbm_set_last_result(TBM_BO_ERROR_BO_ALLOC_FAILED);
735                 free(bo);
736                 pthread_mutex_unlock(&bufmgr->lock);
737                 return NULL;
738         }
739
740         bo->ref_cnt = 1;
741         bo->flags = flags;
742         bo->priv = bo_priv;
743
744         LIST_INITHEAD(&bo->user_data_list);
745
746         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
747
748         pthread_mutex_unlock(&bufmgr->lock);
749
750         return bo;
751 }
752
753 tbm_bo
754 tbm_bo_import(tbm_bufmgr bufmgr, unsigned int key)
755 {
756         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
757
758         tbm_bo bo = NULL;
759         tbm_bo bo2 = NULL;
760         tbm_bo tmp = NULL;
761         void *bo_priv = NULL;
762
763         pthread_mutex_lock(&bufmgr->lock);
764
765         bo = calloc(1, sizeof(struct _tbm_bo));
766         if (!bo) {
767                 pthread_mutex_unlock(&bufmgr->lock);
768                 return NULL;
769         }
770
771         bo->bufmgr = bufmgr;
772
773         bo_priv = bufmgr->backend->bo_import(bo, key);
774         if (!bo_priv) {
775                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FAILED);
776                 free(bo);
777                 pthread_mutex_unlock(&bufmgr->lock);
778                 return NULL;
779         }
780
781         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
782                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
783                         if (bo2->priv == bo_priv) {
784                                 DBG("[libtbm:%d] "
785                                     "find bo(%p, ref:%d key:%d) in list\n",
786                                     getpid(), bo2, bo2->ref_cnt, key);
787
788                                 bo2->ref_cnt++;
789                                 free(bo);
790                                 pthread_mutex_unlock(&bufmgr->lock);
791                                 return bo2;
792                         }
793                 }
794         }
795
796         bo->ref_cnt = 1;
797         bo->priv = bo_priv;
798
799         if (bufmgr->backend->bo_get_flags)
800                 bo->flags = bufmgr->backend->bo_get_flags(bo);
801         else
802                 bo->flags = TBM_BO_DEFAULT;
803
804         LIST_INITHEAD(&bo->user_data_list);
805
806         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
807
808         pthread_mutex_unlock(&bufmgr->lock);
809
810         return bo;
811 }
812
813 tbm_bo
814 tbm_bo_import_fd(tbm_bufmgr bufmgr, tbm_fd fd)
815 {
816         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
817
818         tbm_bo bo = NULL;
819         tbm_bo bo2 = NULL;
820         tbm_bo tmp = NULL;
821         void *bo_priv = NULL;
822
823         pthread_mutex_lock(&bufmgr->lock);
824
825         bo = calloc(1, sizeof(struct _tbm_bo));
826         if (!bo) {
827                 pthread_mutex_unlock(&bufmgr->lock);
828                 return NULL;
829         }
830
831         bo->bufmgr = bufmgr;
832
833         bo_priv = bufmgr->backend->bo_import_fd(bo, fd);
834         if (!bo_priv) {
835                 _tbm_set_last_result(TBM_BO_ERROR_IMPORT_FD_FAILED);
836                 free(bo);
837                 pthread_mutex_unlock(&bufmgr->lock);
838                 return NULL;
839         }
840
841         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
842                 LIST_FOR_EACH_ENTRY_SAFE(bo2, tmp, &bufmgr->bo_list, item_link) {
843                         if (bo2->priv == bo_priv) {
844                                 DBG("[libtbm:%d] "
845                                     "find bo(%p, ref:%d, fd:%d) in list\n",
846                                     getpid(), bo2, bo2->ref_cnt, fd);
847
848                                 bo2->ref_cnt++;
849                                 free(bo);
850                                 pthread_mutex_unlock(&bufmgr->lock);
851                                 return bo2;
852                         }
853                 }
854         }
855
856         bo->ref_cnt = 1;
857         bo->priv = bo_priv;
858
859         if (bufmgr->backend->bo_get_flags)
860                 bo->flags = bufmgr->backend->bo_get_flags(bo);
861         else
862                 bo->flags = TBM_BO_DEFAULT;
863
864         LIST_INITHEAD(&bo->user_data_list);
865
866         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
867
868         pthread_mutex_unlock(&bufmgr->lock);
869
870         return bo;
871 }
872
873 tbm_key
874 tbm_bo_export(tbm_bo bo)
875 {
876         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
877
878         tbm_bufmgr bufmgr;
879         tbm_key ret;
880
881         bufmgr = bo->bufmgr;
882
883         pthread_mutex_lock(&bufmgr->lock);
884         ret = bufmgr->backend->bo_export(bo);
885         if (!ret) {
886                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FAILED);
887                 pthread_mutex_unlock(&bufmgr->lock);
888                 return ret;
889         }
890         pthread_mutex_unlock(&bufmgr->lock);
891
892         return ret;
893 }
894
895 tbm_fd
896 tbm_bo_export_fd(tbm_bo bo)
897 {
898         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), -1);
899
900         tbm_bufmgr bufmgr;
901         int ret;
902
903         bufmgr = bo->bufmgr;
904
905         pthread_mutex_lock(&bufmgr->lock);
906         ret = bufmgr->backend->bo_export_fd(bo);
907         if (ret < 0) {
908                 _tbm_set_last_result(TBM_BO_ERROR_EXPORT_FD_FAILED);
909                 pthread_mutex_unlock(&bufmgr->lock);
910                 return ret;
911         }
912         pthread_mutex_unlock(&bufmgr->lock);
913
914         return ret;
915 }
916
917 tbm_bo_handle
918 tbm_bo_get_handle(tbm_bo bo, int device)
919 {
920         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
921
922         tbm_bufmgr bufmgr;
923         tbm_bo_handle bo_handle;
924
925         bufmgr = bo->bufmgr;
926
927         pthread_mutex_lock(&bufmgr->lock);
928         bo_handle = bufmgr->backend->bo_get_handle(bo, device);
929         if (bo_handle.ptr == NULL) {
930                 _tbm_set_last_result(TBM_BO_ERROR_GET_HANDLE_FAILED);
931                 pthread_mutex_unlock(&bufmgr->lock);
932                 return (tbm_bo_handle) NULL;
933         }
934         pthread_mutex_unlock(&bufmgr->lock);
935
936         return bo_handle;
937 }
938
939 tbm_bo_handle
940 tbm_bo_map(tbm_bo bo, int device, int opt)
941 {
942         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), (tbm_bo_handle) 0);
943
944         tbm_bufmgr bufmgr;
945         tbm_bo_handle bo_handle;
946
947         bufmgr = bo->bufmgr;
948
949         pthread_mutex_lock(&bufmgr->lock);
950
951         if (!_tbm_bo_lock(bo, device, opt)) {
952                 _tbm_set_last_result(TBM_BO_ERROR_LOCK_FAILED);
953                 TBM_LOG("[libtbm:%d] "
954                         "error %s:%d fail to lock bo:%p)\n",
955                         getpid(), __func__, __LINE__, bo);
956                 pthread_mutex_unlock(&bufmgr->lock);
957                 return (tbm_bo_handle) NULL;
958         }
959
960         bo_handle = bufmgr->backend->bo_map(bo, device, opt);
961         if (bo_handle.ptr == NULL) {
962                 _tbm_set_last_result(TBM_BO_ERROR_MAP_FAILED);
963                 TBM_LOG("[libtbm:%d] "
964                         "error %s:%d fail to map bo:%p\n",
965                         getpid(), __func__, __LINE__, bo);
966
967                 _tbm_bo_unlock(bo);
968                 pthread_mutex_unlock(&bufmgr->lock);
969                 return (tbm_bo_handle) NULL;
970         }
971
972         /* increase the map_count */
973         bo->map_cnt++;
974
975         pthread_mutex_unlock(&bufmgr->lock);
976
977         return bo_handle;
978 }
979
980 int
981 tbm_bo_unmap(tbm_bo bo)
982 {
983         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
984
985         tbm_bufmgr bufmgr;
986         int ret;
987
988         bufmgr = bo->bufmgr;
989
990         pthread_mutex_lock(&bufmgr->lock);
991
992         ret = bufmgr->backend->bo_unmap(bo);
993         if (!ret) {
994
995                 _tbm_set_last_result(TBM_BO_ERROR_UNMAP_FAILED);
996                 pthread_mutex_unlock(&bufmgr->lock);
997                 return ret;
998         }
999
1000         /* decrease the map_count */
1001         bo->map_cnt--;
1002
1003         _tbm_bo_unlock(bo);
1004
1005         pthread_mutex_unlock(&bufmgr->lock);
1006
1007         return ret;
1008 }
1009
1010 int
1011 tbm_bo_swap(tbm_bo bo1, tbm_bo bo2)
1012 {
1013         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo1), 0);
1014         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo2), 0);
1015
1016         void *temp;
1017
1018         pthread_mutex_lock(&bo1->bufmgr->lock);
1019
1020         if (bo1->bufmgr->backend->bo_size(bo1) != bo2->bufmgr->backend->bo_size(bo2)) {
1021                 _tbm_set_last_result(TBM_BO_ERROR_SWAP_FAILED);
1022                 pthread_mutex_unlock(&bo1->bufmgr->lock);
1023                 return 0;
1024         }
1025
1026         temp = bo1->priv;
1027         bo1->priv = bo2->priv;
1028         bo2->priv = temp;
1029
1030         pthread_mutex_unlock(&bo1->bufmgr->lock);
1031
1032         return 1;
1033 }
1034
1035 int
1036 tbm_bo_locked(tbm_bo bo)
1037 {
1038         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1039
1040         tbm_bufmgr bufmgr;
1041
1042         bufmgr = bo->bufmgr;
1043
1044         if (bufmgr->lock_type == LOCK_TRY_NEVER)
1045                 return 0;
1046
1047         pthread_mutex_lock(&bufmgr->lock);
1048
1049         if (bo->lock_cnt > 0) {
1050                 pthread_mutex_unlock(&bufmgr->lock);
1051                 return 1;
1052         }
1053
1054         pthread_mutex_unlock(&bufmgr->lock);
1055
1056         return 0;
1057 }
1058
1059 int
1060 tbm_bo_add_user_data(tbm_bo bo, unsigned long key,
1061                      tbm_data_free data_free_func)
1062 {
1063         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1064
1065         tbm_user_data *data;
1066
1067         /* check if the data according to the key exist if so, return false. */
1068         data = user_data_lookup(&bo->user_data_list, key);
1069         if (data) {
1070                 TBM_LOG("[libtbm:%d] "
1071                         "waring: %s:%d user data already exist. key:%ld\n",
1072                         getpid(), __func__, __LINE__, key);
1073                 return 0;
1074         }
1075
1076         data = user_data_create(key, data_free_func);
1077         if (!data)
1078                 return 0;
1079
1080         LIST_ADD(&data->item_link, &bo->user_data_list);
1081
1082         return 1;
1083 }
1084
1085 int
1086 tbm_bo_set_user_data(tbm_bo bo, unsigned long key, void *data)
1087 {
1088         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1089
1090         tbm_user_data *old_data;
1091
1092         if (LIST_IS_EMPTY(&bo->user_data_list))
1093                 return 0;
1094
1095         old_data = user_data_lookup(&bo->user_data_list, key);
1096         if (!old_data)
1097                 return 0;
1098
1099         if (old_data->data && old_data->free_func)
1100                 old_data->free_func(old_data->data);
1101
1102         old_data->data = data;
1103
1104         return 1;
1105 }
1106
1107 int
1108 tbm_bo_get_user_data(tbm_bo bo, unsigned long key, void **data)
1109 {
1110         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1111
1112         tbm_user_data *old_data;
1113
1114         if (!data || LIST_IS_EMPTY(&bo->user_data_list))
1115                 return 0;
1116
1117         old_data = user_data_lookup(&bo->user_data_list, key);
1118         if (!old_data) {
1119                 *data = NULL;
1120                 return 0;
1121         }
1122
1123         *data = old_data->data;
1124
1125         return 1;
1126 }
1127
1128 int
1129 tbm_bo_delete_user_data(tbm_bo bo, unsigned long key)
1130 {
1131         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1132
1133         tbm_user_data *old_data = (void *)0;
1134
1135         if (LIST_IS_EMPTY(&bo->user_data_list))
1136                 return 0;
1137
1138         old_data = user_data_lookup(&bo->user_data_list, key);
1139         if (!old_data)
1140                 return 0;
1141
1142         user_data_delete(old_data);
1143
1144         return 1;
1145 }
1146
1147 tbm_error_e
1148 tbm_get_last_error(void)
1149 {
1150         return tbm_last_error;
1151 }
1152
1153 unsigned int
1154 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
1155 {
1156         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1157
1158         unsigned int capability = TBM_BUFMGR_CAPABILITY_NONE;
1159
1160         if (bufmgr->backend->bo_import && bufmgr->backend->bo_export)
1161                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_KEY;
1162
1163         if (bufmgr->backend->bo_import_fd && bufmgr->backend->bo_export_fd)
1164                 capability |= TBM_BUFMGR_CAPABILITY_SHARE_FD;
1165
1166         return capability;
1167 }
1168
1169 int
1170 tbm_bo_get_flags(tbm_bo bo)
1171 {
1172         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1173
1174         return bo->flags;
1175 }
1176
1177 void
1178 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
1179 {
1180         TBM_RETURN_IF_FAIL(bufmgr != NULL);
1181         tbm_bo bo = NULL, tmp_bo = NULL;
1182         int bo_cnt = 0;
1183
1184         tbm_surface_h surf = NULL, tmp_surf = NULL;
1185         int surf_cnt = 0;
1186         int i;
1187         char app_name[255] = {0,};
1188         unsigned int pid = 0;
1189
1190         pthread_mutex_lock(&gLock);
1191
1192         TBM_DEBUG("\n");
1193         _tbm_util_get_appname_from_pid(getpid(), app_name);
1194         _tbm_util_get_appname_brief(app_name);
1195         TBM_DEBUG("============TBM DEBUG: %s(%d)===========================\n",
1196                   app_name, getpid());
1197         memset(app_name, 0x0, 255 * sizeof(char));
1198
1199         TBM_DEBUG("[tbm_surface information]\n");
1200         TBM_DEBUG("no  surface              refcnt  width  height  bpp  size      num_bos num_planes flags format              app_name\n");
1201         /* show the tbm_surface information in surf_list */
1202         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
1203                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp_surf, &bufmgr->surf_list, item_link) {
1204                         pid = _tbm_surface_internal_get_debug_pid(surf);
1205                         if (!pid) {
1206                                 /* if pid is null, set the self_pid */
1207                                 pid = getpid();
1208                         }
1209
1210                         _tbm_util_get_appname_from_pid(pid, app_name);
1211                         _tbm_util_get_appname_brief(app_name);
1212
1213                         TBM_DEBUG("%-4d%-23p%-6d%-7d%-8d%-5d%-12d%-10d%-9d%-4d%-20s%s\n",
1214                                   ++surf_cnt,
1215                                   surf,
1216                                   surf->refcnt,
1217                                   surf->info.width,
1218                                   surf->info.height,
1219                                   surf->info.bpp,
1220                                   surf->info.size / 1024,
1221                                   surf->num_bos,
1222                                   surf->num_planes,
1223                                   surf->flags,
1224                                   _tbm_surface_internal_format_to_str(surf->info.format),
1225                                   app_name);
1226
1227                         for (i = 0; i < surf->num_bos; i++) {
1228                                 TBM_DEBUG(" bo:%-12p  %-26d%-10d\n",
1229                                           surf->bos[i],
1230                                           surf->bos[i]->ref_cnt,
1231                                           tbm_bo_size(surf->bos[i]) / 1024);
1232                         }
1233
1234                         memset(app_name, 0x0, 255 * sizeof(char));
1235                 }
1236         } else {
1237                 TBM_DEBUG("no tbm_surfaces.\n");
1238         }
1239         TBM_DEBUG("\n");
1240
1241         TBM_DEBUG("[tbm_bo information]\n");
1242         TBM_DEBUG("no  bo                   refcnt  size     lock_cnt map_cnt flags surface\n");
1243
1244         /* show the tbm_bo information in bo_list */
1245         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
1246                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp_bo, &bufmgr->bo_list, item_link) {
1247                         TBM_DEBUG("%-4d%-11p   %-6d%-12d%-9d%-9d%-4d%-11p\n",
1248                                   ++bo_cnt,
1249                                   bo,
1250                                   bo->ref_cnt,
1251                                   tbm_bo_size(bo) / 1024,
1252                                   bo->lock_cnt,
1253                                   bo->map_cnt,
1254                                   bo->flags,
1255                                   bo->surface);
1256                 }
1257         } else {
1258                 TBM_DEBUG("no tbm_bos.\n");
1259         }
1260         TBM_DEBUG("\n");
1261
1262         TBM_DEBUG("===============================================================\n");
1263
1264         pthread_mutex_unlock(&gLock);
1265
1266 }
1267
1268 void
1269 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
1270 {
1271         TBM_LOG("bufmgr=%p onoff=%d\n", bufmgr, onoff);
1272         TBM_LOG("Not implemented yet.\n");
1273 }
1274
1275 /* internal function */
1276 int
1277 _tbm_bo_set_surface(tbm_bo bo, tbm_surface_h surface)
1278 {
1279         TBM_RETURN_VAL_IF_FAIL(_tbm_bo_is_valid(bo), 0);
1280
1281         bo->surface = surface;
1282
1283         return 1;
1284 }
1285
1286 int
1287 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *NativeDisplay)
1288 {
1289         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
1290
1291         int ret;
1292
1293         pthread_mutex_lock(&bufmgr->lock);
1294
1295         if (!bufmgr->backend->bufmgr_bind_native_display) {
1296                 pthread_mutex_unlock(&bufmgr->lock);
1297                 return 1;
1298         }
1299
1300         ret = bufmgr->backend->bufmgr_bind_native_display(bufmgr, NativeDisplay);
1301         if (!ret) {
1302                 pthread_mutex_unlock(&bufmgr->lock);
1303                 return 0;
1304         }
1305
1306         pthread_mutex_unlock(&bufmgr->lock);
1307
1308         return 1;
1309 }
1310