tbm_bufmgr: add tbm_bufmgr_internal_import_bo_with_fd and use it
[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_drm_helper.h"
37 #include "list.h"
38
39 #include <sys/resource.h>
40
41 int trace_mask = 0;
42
43 #ifdef HAVE_DLOG
44 int bDlog;
45 #endif
46
47 tbm_bufmgr gBufMgr;
48 int b_dump_queue;
49
50 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
51 static pthread_mutex_t tbm_bufmgr_lock = PTHREAD_MUTEX_INITIALIZER;
52 static double scale_factor = 0;
53 void _tbm_bufmgr_mutex_unlock(void);
54
55 //#define TBM_BUFMGR_INIT_TIME
56
57 #define MAX_SIZE_N(dest)        (sizeof(dest) - strlen(dest) - 1)
58
59 /* check condition */
60 #define TBM_BUFMGR_RETURN_IF_FAIL(cond) {\
61         if (!(cond)) {\
62                 TBM_ERR("'%s' failed.\n", #cond);\
63                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
64                 _tbm_bufmgr_mutex_unlock();\
65                 return;\
66         } \
67 }
68
69 #define TBM_BUFMGR_RETURN_VAL_IF_FAIL(cond, val) {\
70         if (!(cond)) {\
71                 TBM_ERR("'%s' failed.\n", #cond);\
72                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);\
73                 _tbm_bufmgr_mutex_unlock();\
74                 return val;\
75         } \
76 }
77
78 /* LCOV_EXCL_START */
79
80 static void
81 _tbm_bufmgr_check_bo_cnt(tbm_bufmgr bufmgr)
82 {
83         static int last_chk_bo_cnt = 0;
84
85         if ((bufmgr->bo_cnt >= 500) && ((bufmgr->bo_cnt % 20) == 0) &&
86                 (bufmgr->bo_cnt > last_chk_bo_cnt)) {
87                 TBM_DBG("============TBM BO CNT DEBUG: bo_cnt=%d\n", bufmgr->bo_cnt);
88                 tbm_bufmgr_debug_show(bufmgr);
89                 last_chk_bo_cnt = bufmgr->bo_cnt;
90         }
91 }
92
93 static void
94 _tbm_bufmgr_initialize_bo(tbm_bufmgr bufmgr, tbm_bo bo, int flags)
95 {
96         bo->bufmgr = bufmgr;
97         bo->flags = flags;
98         bo->magic = TBM_BO_MAGIC;
99         bo->ref_cnt = 1;
100
101         LIST_INITHEAD(&bo->user_data_list);
102
103         bufmgr->bo_cnt++;
104         LIST_ADD(&bo->item_link, &bufmgr->bo_list);
105 }
106
107 void
108 _tbm_bufmgr_mutex_lock(void)
109 {
110         pthread_mutex_lock(&tbm_bufmgr_lock);
111 }
112
113 void
114 _tbm_bufmgr_mutex_unlock(void)
115 {
116         pthread_mutex_unlock(&tbm_bufmgr_lock);
117 }
118
119 static int
120 _tbm_util_get_max_surface_size(int *w, int *h)
121 {
122         tbm_surface_info_s info;
123         tbm_surface_h surface = NULL;
124         int count = 0;
125
126         *w = 0;
127         *h = 0;
128
129         if (gBufMgr == NULL || LIST_IS_EMPTY(&gBufMgr->surf_list))
130                 return count;
131
132         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link) {
133                 if (tbm_surface_get_info(surface, &info) == TBM_SURFACE_ERROR_NONE) {
134                         count++;
135                         if (*w < info.width)
136                                 *w = info.width;
137                         if (*h < info.height)
138                                 *h = info.height;
139                 }
140         }
141
142         return count;
143 }
144
145 static void
146 _tbm_util_get_appname_brief(char *brief)
147 {
148         char delim[] = "/";
149         char *token = NULL;
150         char temp[255] = {0,};
151         char *saveptr = NULL;
152
153         token = strtok_r(brief, delim, &saveptr);
154
155         while (token != NULL) {
156                 memset(temp, 0x00, 255 * sizeof(char));
157                 strncpy(temp, token, 254 * sizeof(char));
158                 token = strtok_r(NULL, delim, &saveptr);
159         }
160
161         snprintf(brief, sizeof(temp), "%s", temp);
162 }
163
164 static void
165 _tbm_util_get_appname_from_pid(long pid, char *str)
166 {
167         char fn_cmdline[255] = {0, }, cmdline[255];
168         FILE *fp;
169         int len;
170
171         if (pid <= 0) return;
172
173         snprintf(fn_cmdline, sizeof(fn_cmdline), "/proc/%ld/cmdline", pid);
174
175         fp = fopen(fn_cmdline, "r");
176         if (fp == 0) {
177                 TBM_ERR("cannot file open %s\n", fn_cmdline);
178                 return;
179         }
180
181         if (!fgets(cmdline, 255, fp)) {
182                 TBM_ERR("fail to get appname for pid(%ld)\n", pid);
183                 fclose(fp);
184                 return;
185         }
186
187         fclose(fp);
188
189         len = strlen(cmdline);
190         if (len < 1)
191                 memset(cmdline, 0x00, 255);
192         else
193                 cmdline[len] = 0;
194
195         snprintf(str, sizeof(cmdline), "%s", cmdline);
196 }
197
198 static void
199 _tbm_bufmgr_copy_module_data(tbm_bufmgr bufmgr, tbm_module *module, int reset)
200 {
201         if (!reset) {
202                 bufmgr->module_data = module->module_data;
203                 bufmgr->backend = module->backend;
204
205                 bufmgr->backend_module_data = module->backend_module_data;
206                 bufmgr->bufmgr_data = module->bufmgr_data;
207                 bufmgr->bufmgr_func = module->bufmgr_func;
208                 bufmgr->bo_func = module->bo_func;
209
210                 bufmgr->use_hal_tbm = module->use_hal_tbm;
211                 bufmgr->auth_wl_socket_created = module->auth_wl_socket_created;
212                 bufmgr->auth_fd = module->auth_fd;
213                 bufmgr->hal_backend = module->hal_backend;
214                 bufmgr->hal_bufmgr = module->hal_bufmgr;
215         } else {
216                 bufmgr->module_data = NULL;
217                 bufmgr->backend = NULL;
218
219                 bufmgr->backend_module_data = NULL;
220                 bufmgr->bufmgr_data = NULL;
221                 bufmgr->bufmgr_func = NULL;
222                 bufmgr->bo_func = NULL;
223
224                 bufmgr->use_hal_tbm = 0;
225                 bufmgr->auth_wl_socket_created = 0;
226                 bufmgr->auth_fd = -1;
227                 bufmgr->hal_backend = NULL;
228                 bufmgr->hal_bufmgr = NULL;
229         }
230 }
231
232
233 /* LCOV_EXCL_STOP */
234
235 static tbm_bufmgr
236 _tbm_bufmgr_init(int fd, int server)
237 {
238         tbm_error_e error = TBM_ERROR_NONE;
239
240 #ifdef TBM_BUFMGR_INIT_TIME
241         struct timeval start_tv, end_tv;
242 #endif
243         char *env;
244
245 #ifdef TBM_BUFMGR_INIT_TIME
246         /* get the start tv */
247         gettimeofday(&start_tv, NULL);
248 #endif
249
250         bDlog = 1;
251
252         /* LCOV_EXCL_START */
253 #ifdef TRACE
254         env = getenv("TBM_TRACE");
255         if (env) {
256                 trace_mask = atoi(env);
257                 TBM_DBG("TBM_TRACE=%s\n", env);
258         } else
259                 trace_mask = 0;
260 #endif
261
262         pthread_mutex_lock(&gLock);
263
264         _tbm_set_last_result(TBM_ERROR_NONE);
265
266         if (fd >= 0) {
267                 TBM_WRN("!!!!!WARNING:: The tbm_bufmgr_init DOSE NOT use argument fd ANYMORE.\n");
268                 TBM_WRN("!!!!!WARNING:: IT WILL BE CHANGED like tbm_bufmgr_init(int fd) --> tbm_bufmgr_init(void).\n");
269         }
270
271
272         /* initialize buffer manager */
273         if (gBufMgr) {
274                 gBufMgr->ref_count++;
275                 TBM_DBG("reuse  tbm_bufmgr(%p) ref_count(%d) fd(%d)\n", gBufMgr, gBufMgr->ref_count, gBufMgr->fd);
276                 pthread_mutex_unlock(&gLock);
277                 return gBufMgr;
278         }
279
280         TBM_DBG("bufmgr init\n");
281
282         /* allocate bufmgr */
283         gBufMgr = calloc(1, sizeof(struct _tbm_bufmgr));
284         if (!gBufMgr) {
285                 TBM_ERR("error: fail to alloc bufmgr fd(%d)\n", fd);
286                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
287                 pthread_mutex_unlock(&gLock);
288                 return NULL;
289         }
290
291         gBufMgr->fd = fd;
292
293         /* set the display_server flag before loading the backend module */
294         if (server) {
295                 TBM_INFO("The tbm_bufmgr(%p) is used by display server. Need to bind the native_display.\n", gBufMgr);
296                 gBufMgr->display_server = 1;
297         }
298
299         /* load bufmgr priv from env */
300         gBufMgr->module = tbm_module_load(gBufMgr->fd);
301         if (!gBufMgr->module) {
302                 TBM_ERR("error : Fail to load bufmgr backend\n");
303                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
304                 free(gBufMgr);
305                 gBufMgr = NULL;
306                 pthread_mutex_unlock(&gLock);
307                 return NULL;
308
309         }
310
311         // TODO: this is temporary. it will be removed after finishing refactoring the tbm_module.
312         _tbm_bufmgr_copy_module_data(gBufMgr, gBufMgr->module, 0);
313
314         /* check the essential capabilities of tbm_module */
315         gBufMgr->capabilities = tbm_module_bufmgr_get_capabilities(gBufMgr->module, &error);
316         if (gBufMgr->capabilities == TBM_BUFMGR_CAPABILITY_NONE) {
317                 TBM_ERR("The capabilities of the backend module is TBM_BUFMGR_CAPABILITY_NONE.");
318                 TBM_ERR("TBM_BUFMGR_CAPABILITY_SHARE_FD is the essential capability.");
319                 tbm_module_unload(gBufMgr->module);
320                 _tbm_set_last_result(error);
321                 free(gBufMgr);
322                 gBufMgr = NULL;
323                 pthread_mutex_unlock(&gLock);
324                 return NULL;
325         }
326
327         if (!(gBufMgr->capabilities & TBM_BUFMGR_CAPABILITY_SHARE_FD)) {
328                 TBM_ERR("The capabilities of the backend module had no TBM_BUFMGR_CAPABILITY_SHARE_FD.");
329                 TBM_ERR("The tbm backend has to get TBM_BUFMGR_CAPABILITY_SHARE_FD. ");
330                 tbm_module_unload(gBufMgr->module);
331                 _tbm_set_last_result(TBM_ERROR_INVALID_OPERATION);
332                 free(gBufMgr);
333                 gBufMgr = NULL;
334                 pthread_mutex_unlock(&gLock);
335                 return NULL;
336         }
337
338         /* LCOV_EXCL_STOP */
339
340         gBufMgr->ref_count = 1;
341
342         TBM_INFO("create tizen bufmgr:%p ref_count:%d\n",
343             gBufMgr, gBufMgr->ref_count);
344
345         /* setup the bo_lock_type */
346         env = getenv("BUFMGR_LOCK_TYPE");
347         if (env && !strcmp(env, "always"))
348                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
349         else if (env && !strcmp(env, "none"))
350                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_NEVER;
351         else if (env && !strcmp(env, "once"))
352                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ONCE;
353         else
354                 gBufMgr->bo_lock_type = TBM_BUFMGR_BO_LOCK_TYPE_ALWAYS;
355
356         TBM_DBG("BUFMGR_LOCK_TYPE=%s\n", env ? env : "default:once");
357
358         /* intialize bo_list */
359         LIST_INITHEAD(&gBufMgr->bo_list);
360
361         /* intialize surf_list */
362         LIST_INITHEAD(&gBufMgr->surf_list);
363
364         /* intialize surf_queue_list */
365         LIST_INITHEAD(&gBufMgr->surf_queue_list);
366
367         /* intialize debug_key_list */
368         LIST_INITHEAD(&gBufMgr->debug_key_list);
369
370 #ifdef TBM_BUFMGR_INIT_TIME
371         /* get the end tv */
372         gettimeofday(&end_tv, NULL);
373         TBM_INFO("tbm_bufmgr_init time: %ld ms", ((end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000) - (start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000)));
374 #endif
375
376         pthread_mutex_unlock(&gLock);
377
378         return gBufMgr;
379 }
380
381 tbm_bufmgr
382 tbm_bufmgr_init(int fd)
383 {
384         tbm_bufmgr bufmgr;
385
386         bufmgr = _tbm_bufmgr_init(fd, 0);
387
388         return bufmgr;
389 }
390
391 void
392 tbm_bufmgr_deinit(tbm_bufmgr bufmgr)
393 {
394         TBM_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
395
396         _tbm_bufmgr_mutex_lock();
397         pthread_mutex_lock(&gLock);
398         _tbm_set_last_result(TBM_ERROR_NONE);
399
400         if (!gBufMgr) {
401                 TBM_ERR("gBufmgr already destroy: bufmgr:%p\n", bufmgr);
402                 pthread_mutex_unlock(&gLock);
403                 _tbm_bufmgr_mutex_unlock();
404                 return;
405         }
406
407         bufmgr->ref_count--;
408         if (bufmgr->ref_count > 0) {
409                 TBM_DBG("reduce a ref_count(%d) of tbm_bufmgr(%p)\n", bufmgr->ref_count, bufmgr);
410                 pthread_mutex_unlock(&gLock);
411                 _tbm_bufmgr_mutex_unlock();
412                 return;
413         }
414
415         /* destroy bo_list */
416         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
417                 tbm_bo bo = NULL, tmp;
418
419                 LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bo_list, item_link) {
420                         TBM_ERR("Un-freed bo(%p, ref:%d)\n", bo, bo->ref_cnt);
421                         _tbm_bo_free(bo);
422                 }
423                 LIST_DELINIT(&bufmgr->bo_list);
424         }
425
426         /* destroy surf_list */
427         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
428                 tbm_surface_h surf = NULL, tmp;
429
430                 LIST_FOR_EACH_ENTRY_SAFE(surf, tmp, &bufmgr->surf_list, item_link) {
431                         TBM_ERR("Un-freed surf(%p, ref:%d)\n", surf, surf->refcnt);
432                         tbm_surface_destroy(surf);
433                 }
434                 LIST_DELINIT(&bufmgr->surf_list);
435         }
436
437         tbm_module_unload(bufmgr->module);
438
439         // TODO: this is temporary. it will be removed after finishing refactoring the tbm_module.
440         _tbm_bufmgr_copy_module_data(bufmgr, bufmgr->module, 1);
441
442         if (bufmgr->fd > 0)
443                 close(bufmgr->fd);
444
445         TBM_INFO("destroy tbm_bufmgr(%p)\n", bufmgr);
446
447         free(bufmgr);
448         gBufMgr = NULL;
449
450         pthread_mutex_unlock(&gLock);
451         _tbm_bufmgr_mutex_unlock();
452 }
453
454 unsigned int
455 tbm_bufmgr_get_capability(tbm_bufmgr bufmgr)
456 {
457         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
458
459         _tbm_bufmgr_mutex_lock();
460         _tbm_set_last_result(TBM_ERROR_NONE);
461
462         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), TBM_BUFMGR_CAPABILITY_NONE);
463         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, TBM_BUFMGR_CAPABILITY_NONE);
464
465         capabilities = bufmgr->capabilities;
466
467         _tbm_bufmgr_mutex_unlock();
468
469         return capabilities;
470 }
471
472 /* LCOV_EXCL_START */
473 char *
474 tbm_bufmgr_debug_tbm_info_get(tbm_bufmgr bufmgr)
475 {
476         char app_name[255] = {0,}, title[512] = {0,};
477         tbm_surface_debug_data *debug_old_data = NULL;
478         char *str;
479         int len = 1024*4;
480         int c = 0;
481         int size;
482         tbm_error_e error;
483         long pid = 0;
484
485         pthread_mutex_lock(&gLock);
486         _tbm_set_last_result(TBM_ERROR_NONE);
487
488         if (!TBM_BUFMGR_IS_VALID(bufmgr) || (bufmgr != gBufMgr)) {
489                 TBM_ERR("invalid bufmgr\n");
490                 _tbm_set_last_result(TBM_ERROR_INVALID_PARAMETER);
491                 pthread_mutex_unlock(&gLock);
492                 return NULL;
493         }
494
495         str = malloc(len);
496         if (!str) {
497                 TBM_ERR("Fail to allocate the string.\n");
498                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
499                 pthread_mutex_unlock(&gLock);
500                 return NULL;
501         }
502
503         TBM_SNRPRINTF(str, len, c, "\n");
504         pid = syscall(SYS_getpid);
505         _tbm_util_get_appname_from_pid(pid, app_name);
506         _tbm_util_get_appname_brief(app_name);
507         TBM_SNRPRINTF(str, len, c, "===========================================TBM DEBUG: %s(%ld)===========================================\n",
508                   app_name, pid);
509
510         snprintf(title, 255, "%s", "no  surface     refcnt  width  height  bpp  size    n_b  n_p  flags    format    app_name              ");
511
512         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
513                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
514                         strncat(title, "  ", MAX_SIZE_N(title));
515                         strncat(title, debug_old_data->key, MAX_SIZE_N(title));
516                 }
517         }
518
519         TBM_SNRPRINTF(str, len, c, "[tbm_surface information]\n");
520         TBM_SNRPRINTF(str, len, c, "%s\n", title);
521
522         /* show the tbm_surface information in surf_list */
523         if (!LIST_IS_EMPTY(&bufmgr->surf_list)) {
524                 tbm_surface_h surf = NULL;
525                 int surf_cnt = 0;
526
527                 LIST_FOR_EACH_ENTRY(surf, &bufmgr->surf_list, item_link) {
528                         char data[512] = {0,};
529                         unsigned int surf_pid = 0;
530                         int i;
531
532                         surf_pid = _tbm_surface_internal_get_debug_pid(surf);
533                         if (!surf_pid) {
534                                 /* if pid is null, set the self_pid */
535                                 surf_pid = syscall(SYS_getpid);;
536                         }
537
538                         memset(app_name, 0x0, 255 * sizeof(char));
539                         if (geteuid() == 0) {
540                                 _tbm_util_get_appname_from_pid(surf_pid, app_name);
541                                 _tbm_util_get_appname_brief(app_name);
542                         } else {
543                                 snprintf(app_name, sizeof(app_name), "%d", surf_pid);
544                         }
545
546                         snprintf(data, 255, "%-3d %-11p   %-5d %-6u %-7u %-4u %-7u  %-3d  %-3d %-8d %-9s %-22s",
547                                   ++surf_cnt,
548                                   surf,
549                                   surf->refcnt,
550                                   surf->info.width,
551                                   surf->info.height,
552                                   surf->info.bpp,
553                                   surf->info.size / 1024,
554                                   surf->num_bos,
555                                   surf->num_planes,
556                                   surf->flags,
557                                   _tbm_surface_internal_format_to_str(surf->info.format) + 11,
558                                   app_name);
559
560                         if (!LIST_IS_EMPTY(&bufmgr->debug_key_list)) {
561                                 LIST_FOR_EACH_ENTRY(debug_old_data, &bufmgr->debug_key_list, item_link) {
562                                         char *value;
563
564                                         strncat(data, "  ", MAX_SIZE_N(title));
565
566                                         value = _tbm_surface_internal_get_debug_data(surf, debug_old_data->key);
567                                         if (value)
568                                                 strncat(data, value, MAX_SIZE_N(title));
569                                         else
570                                                 strncat(data, "none", MAX_SIZE_N(title));
571                                 }
572                         }
573                         TBM_SNRPRINTF(str, len, c, "%s\n", data);
574
575                         for (i = 0; i < surf->num_bos; i++) {
576                                 if (bufmgr->use_hal_tbm) {
577                                         size = hal_tbm_bo_get_size((hal_tbm_bo *)surf->bos[i]->bo_data, (hal_tbm_error *)&error);
578                                         if (error != TBM_ERROR_NONE)
579                                                 TBM_WRN("fail to get the size of bo.");
580                                 } else if (bufmgr->backend_module_data) {
581                                         size = bufmgr->bo_func->bo_get_size(surf->bos[i]->bo_data, &error);
582                                         if (error != TBM_ERROR_NONE)
583                                                 TBM_WRN("fail to get the size of bo.");
584                                 } else
585                                         size = bufmgr->backend->bo_size(surf->bos[i]);
586                                 TBM_SNRPRINTF(str, len, c, " bo:%-12p  %-26d%-10d\n",
587                                           surf->bos[i],
588                                           surf->bos[i]->ref_cnt,
589                                           size / 1024);
590                         }
591                 }
592         } else
593                 TBM_SNRPRINTF(str, len, c, " no tbm_surfaces.\n");
594         TBM_SNRPRINTF(str, len, c, "\n");
595
596         TBM_SNRPRINTF(str, len, c, "[tbm_bo information]\n");
597         TBM_SNRPRINTF(str, len, c, "no  bo          refcnt  size    lock_cnt  map_cnt  flags   surface     name\n");
598
599         /* show the tbm_bo information in bo_list */
600         if (!LIST_IS_EMPTY(&bufmgr->bo_list)) {
601                 int bo_cnt = 0;
602                 tbm_bo bo = NULL;
603                 tbm_key key = 0;
604
605                 LIST_FOR_EACH_ENTRY(bo, &bufmgr->bo_list, item_link) {
606                         if (bo->bufmgr->use_hal_tbm) {
607                                 size = hal_tbm_bo_get_size((hal_tbm_bo *)bo->bo_data, (hal_tbm_error *)&error);
608                                 if (error != TBM_ERROR_NONE)
609                                         TBM_WRN("fail to get the size of bo.");
610                                 key = (tbm_key)hal_tbm_bo_export_key((hal_tbm_bo *)bo->bo_data, (hal_tbm_error *)&error);
611                         } else if (bufmgr->backend_module_data) {
612                                 size = bufmgr->bo_func->bo_get_size(bo->bo_data, &error);
613                                 if (error != TBM_ERROR_NONE)
614                                         TBM_WRN("fail to get the size of bo.");
615                                 key = bufmgr->bo_func->bo_export_key(bo->bo_data, &error);
616                                 if (error != TBM_ERROR_NONE)
617                                         TBM_WRN("fail to get the tdm_key of bo.");
618                         } else {
619                                 size = bufmgr->backend->bo_size(bo);
620                                 key = bufmgr->backend->bo_export(bo);
621                         }
622                         TBM_SNRPRINTF(str, len, c, "%-3d %-11p   %-5d %-7d    %-6d    %-5u %-7d %-11p  %-4d\n",
623                                   ++bo_cnt,
624                                   bo,
625                                   bo->ref_cnt,
626                                   size / 1024,
627                                   bo->lock_cnt,
628                                   bo->map_cnt,
629                                   bo->flags,
630                                   bo->surface,
631                                   key);
632                 }
633         } else
634                 TBM_SNRPRINTF(str, len, c, "no tbm_bos.\n");
635         TBM_SNRPRINTF(str, len, c, "\n");
636
637         TBM_SNRPRINTF(str, len, c, "========================================================================================================\n");
638
639         pthread_mutex_unlock(&gLock);
640
641         return str;
642 }
643
644 void
645 tbm_bufmgr_debug_show(tbm_bufmgr bufmgr)
646 {
647         char * str;
648         str = tbm_bufmgr_debug_tbm_info_get(bufmgr);
649         if (str) {
650                 TBM_DBG("       %s", str);
651                 free(str);
652         }
653 }
654
655 void
656 tbm_bufmgr_debug_trace(tbm_bufmgr bufmgr, int onoff)
657 {
658         _tbm_bufmgr_mutex_lock();
659         _tbm_set_last_result(TBM_ERROR_NONE);
660
661         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
662         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
663
664 #ifdef TRACE
665         TBM_LOG_D("bufmgr=%p onoff=%d\n", bufmgr, onoff);
666         bTrace = onoff;
667 #endif
668
669         _tbm_bufmgr_mutex_unlock();
670 }
671
672 void
673 tbm_bufmgr_debug_set_trace_mask(tbm_bufmgr bufmgr, tbm_bufmgr_debug_trace_mask mask, int set)
674 {
675         _tbm_bufmgr_mutex_lock();
676         _tbm_set_last_result(TBM_ERROR_NONE);
677
678         TBM_BUFMGR_RETURN_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr));
679         TBM_BUFMGR_RETURN_IF_FAIL(bufmgr == gBufMgr);
680
681         if (set == 1) {
682                 trace_mask |= mask;
683
684                 TBM_INFO("bufmgr=%p sets the trace_mask=%d\n", bufmgr, mask);
685                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
686                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
687                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
688                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
689                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
690                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
691                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
692                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
693         } else if (set == 0) {
694                 trace_mask &= ~mask;
695
696                 TBM_INFO("bufmgr=%p unsets the trace_mask=%d\n", bufmgr, mask);
697                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_BO)
698                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_BO");
699                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL)
700                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_INTERNAL");
701                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE)
702                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE");
703                 if (trace_mask&TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE)
704                         TBM_INFO("  TBM_BUFGMR_DEBUG_TRACE_SURFACE_QUEUE");
705         } else {
706                 TBM_WRN("set value is wrong.(set=%d)", set);
707         }
708
709         _tbm_bufmgr_mutex_unlock();
710 }
711
712 void
713 tbm_bufmgr_debug_dump_set_scale(double scale)
714 {
715         pthread_mutex_lock(&gLock);
716         _tbm_set_last_result(TBM_ERROR_NONE);
717         scale_factor = scale;
718         pthread_mutex_unlock(&gLock);
719 }
720
721 int
722 tbm_bufmgr_debug_get_ref_count(void)
723 {
724         int refcnt;
725
726         pthread_mutex_lock(&gLock);
727
728         _tbm_set_last_result(TBM_ERROR_NONE);
729
730         refcnt = (gBufMgr) ? gBufMgr->ref_count : 0;
731
732         pthread_mutex_unlock(&gLock);
733
734         return refcnt;
735 }
736
737 int
738 tbm_bufmgr_debug_queue_dump(char *path, int count, int onoff)
739 {
740         pthread_mutex_lock(&gLock);
741         _tbm_set_last_result(TBM_ERROR_NONE);
742
743         if (onoff == 0) {
744                 TBM_DBG("count=%d onoff=%d\n", count, onoff);
745                 b_dump_queue = 0;
746                 tbm_surface_internal_dump_end();
747         } else {
748                 int w, h;
749
750                 if (path == NULL) {
751                         TBM_ERR("path is null");
752                         pthread_mutex_unlock(&gLock);
753                         return 0;
754                 }
755                 TBM_DBG("path=%s count=%d onoff=%d\n", path, count, onoff);
756
757                 if (_tbm_util_get_max_surface_size(&w, &h) == 0) {
758                         TBM_ERR("Fail to get tbm_surface size.\n");
759                         pthread_mutex_unlock(&gLock);
760                         return 0;
761                 }
762
763                 tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
764                 scale_factor = 0;
765
766                 b_dump_queue = 1;
767         }
768
769         pthread_mutex_unlock(&gLock);
770
771         return 1;
772 }
773
774 int
775 tbm_bufmgr_debug_dump_all(char *path)
776 {
777         int w, h, count = 0;
778         tbm_surface_h surface = NULL;
779
780         pthread_mutex_lock(&gLock);
781         _tbm_set_last_result(TBM_ERROR_NONE);
782
783         if (!path) {
784                 TBM_ERR("path is null.\n");
785                 pthread_mutex_unlock(&gLock);
786                 return 0;
787         }
788
789         TBM_DBG("path=%s\n", path);
790
791         count = _tbm_util_get_max_surface_size(&w, &h);
792         if (count == 0) {
793                 TBM_ERR("No tbm_surface.\n");
794                 pthread_mutex_unlock(&gLock);
795                 return 0;
796         }
797
798         tbm_surface_internal_dump_with_scale_start(path, w, h, count, scale_factor);
799         scale_factor = 0;
800
801         LIST_FOR_EACH_ENTRY(surface, &gBufMgr->surf_list, item_link)
802                 tbm_surface_internal_dump_buffer(surface, "dump_all");
803
804         tbm_surface_internal_dump_end();
805
806         pthread_mutex_unlock(&gLock);
807
808         return 1;
809 }
810
811 /* internal function */
812 tbm_bufmgr
813 _tbm_bufmgr_get_bufmgr(void)
814 {
815         return gBufMgr;
816 }
817
818 int
819 tbm_bufmgr_bind_native_display(tbm_bufmgr bufmgr, void *native_display)
820 {
821         tbm_error_e error;
822
823         _tbm_bufmgr_mutex_lock();
824         _tbm_set_last_result(TBM_ERROR_NONE);
825
826         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), 0);
827
828         error = tbm_module_bufmgr_bind_native_display(bufmgr->module, native_display);
829         if (error != TBM_ERROR_NONE) {
830                 _tbm_set_last_result(error);
831                 _tbm_bufmgr_mutex_unlock();
832
833                 if (error == TBM_ERROR_NOT_SUPPORTED) {
834                         TBM_WRN("Not supported, so skip: tbm_bufmgr(%p) native_display(%p)", bufmgr, native_display);
835                         return 1;
836                 }
837
838                 return 0;
839         }
840
841         TBM_INFO("tbm_bufmgr(%p) native_display(%p)\n", bufmgr, native_display);
842
843         _tbm_bufmgr_mutex_unlock();
844
845         return 1;
846 }
847
848 tbm_bufmgr
849 tbm_bufmgr_server_init(void)
850 {
851         tbm_bufmgr bufmgr;
852
853         bufmgr = _tbm_bufmgr_init(-1, 1);
854
855         return bufmgr;
856 }
857
858 int
859 tbm_bufmgr_set_bo_lock_type(tbm_bufmgr bufmgr, tbm_bufmgr_bo_lock_type bo_lock_type)
860 {
861         _tbm_bufmgr_mutex_lock();
862         _tbm_set_last_result(TBM_ERROR_NONE);
863
864         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), 0);
865         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, 0);
866
867         pthread_mutex_lock(&gLock);
868         gBufMgr->bo_lock_type = bo_lock_type;
869         pthread_mutex_unlock(&gLock);
870
871         TBM_INFO("The bo_lock_type of the bo is %d\n", bo_lock_type);
872
873         _tbm_bufmgr_mutex_unlock();
874
875         return 1;
876 }
877
878
879 int tbm_bufmgr_get_fd_limit(void)
880 {
881         struct rlimit lim;
882
883         if (getrlimit(RLIMIT_NOFILE, &lim))
884                 return 1024;
885
886         return (int)lim.rlim_cur;
887 }
888
889 tbm_bufmgr tbm_bufmgr_get(void)
890 {
891         return gBufMgr;
892 }
893
894
895 tbm_bo
896 tbm_bufmgr_internal_find_bo(tbm_bufmgr bufmgr, tbm_bo bo)
897 {
898         tbm_bo bo2 = NULL;
899
900         TBM_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(gBufMgr), NULL);
901         TBM_RETURN_VAL_IF_FAIL(bufmgr == gBufMgr, NULL);
902
903         if (LIST_IS_EMPTY(&bufmgr->bo_list))
904                 return NULL;
905
906         LIST_FOR_EACH_ENTRY(bo2, &bufmgr->bo_list, item_link) {
907                 if (bo2->bo_data == bo->bo_data) {
908                         return bo2;
909                 }
910         }
911
912         return NULL;
913 }
914
915 tbm_bo
916 tbm_bufmgr_internal_alloc_bo(tbm_bufmgr bufmgr, int size, int flags, tbm_error_e *error)
917 {
918         tbm_bo bo;
919         tbm_backend_bo_data *bo_data;
920
921         _tbm_bufmgr_check_bo_cnt(bufmgr);
922
923         bo = calloc(1, sizeof(struct _tbm_bo));
924         if (!bo) {
925                 /* LCOV_EXCL_START */
926                 TBM_ERR("memory allocationc failed.");
927                 *error = TBM_ERROR_OUT_OF_MEMORY;
928                 return NULL;
929                 /* LCOV_EXCL_STOP */
930         }
931
932         bo_data = tbm_module_bufmgr_bo_alloc(bufmgr->module, bo, size, flags, error);
933         if (!bo_data) {
934                 /* LCOV_EXCL_START */
935                 TBM_ERR("tbm_module_bufmgr_bo_alloc failed. size:%d flags:%s error:%d", size, _tbm_flag_to_str(flags), *error);
936                 free(bo);
937                 return NULL;
938                 /* LCOV_EXCL_STOP */
939         }
940         bo->bo_data = bo_data;
941         bo->priv = (void *)bo_data; // TODO: this will be DEPRECATED.
942
943         _tbm_bufmgr_initialize_bo(bufmgr, bo, flags);
944
945         return bo;
946 }
947
948
949 /* LCOV_EXCL_START */
950
951 tbm_bo
952 tbm_bufmgr_internal_alloc_bo_with_format(tbm_bufmgr bufmgr, int format, int bo_idx, int width,
953                                                 int height, int bpp, tbm_bo_memory_type flags, tbm_error_e *error)
954 {
955         tbm_bo bo = NULL;
956
957         _tbm_bufmgr_mutex_lock();
958         _tbm_set_last_result(TBM_ERROR_NONE);
959
960         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
961
962         _tbm_bufmgr_check_bo_cnt(bufmgr);
963
964         bo = calloc(1, sizeof(struct _tbm_bo));
965         if (!bo) {
966                 /* LCOV_EXCL_START */
967                 TBM_ERR("memory allocationc failed.");
968                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
969                 /* LCOV_EXCL_STOP */
970                 goto fail;
971         }
972
973         bo->bo_data = tbm_module_bufmgr_bo_alloc_with_format(bufmgr->module, format, bo_idx, width, height, bpp, flags, error);
974         if (!bo->bo_data) {
975                 /* LCOV_EXCL_START */
976                 _tbm_set_last_result(*error);
977                 /* LCOV_EXCL_STOP */
978                 goto fail;
979         }
980
981         _tbm_bufmgr_initialize_bo(bufmgr, bo, flags);
982
983         _tbm_bufmgr_mutex_unlock();
984
985         return bo;
986
987 fail:
988         if (bo)
989                 free(bo);
990         _tbm_bufmgr_mutex_unlock();
991
992         return NULL;
993 }
994
995 tbm_bo
996 tbm_bufmgr_internal_alloc_bo_with_bo_data(tbm_bufmgr bufmgr, tbm_backend_bo_data *bo_data, int flags)
997 {
998         tbm_bo bo, bo2 = NULL;
999
1000         _tbm_bufmgr_mutex_lock();
1001         _tbm_set_last_result(TBM_ERROR_NONE);
1002
1003         TBM_BUFMGR_RETURN_VAL_IF_FAIL(TBM_BUFMGR_IS_VALID(bufmgr), NULL);
1004         TBM_BUFMGR_RETURN_VAL_IF_FAIL(bo_data, NULL);
1005
1006         _tbm_bufmgr_check_bo_cnt(bufmgr);
1007
1008         bo = calloc(1, sizeof(struct _tbm_bo));
1009         if (!bo) {
1010                 /* LCOV_EXCL_START */
1011                 TBM_ERR("memory allocationc failed.");
1012                 _tbm_set_last_result(TBM_ERROR_OUT_OF_MEMORY);
1013                 _tbm_bufmgr_mutex_unlock();
1014                 return NULL;
1015                 /* LCOV_EXCL_STOP */
1016         }
1017         bo->bo_data = bo_data;
1018         bo->get_from_hal_surface = 1;
1019
1020         // return an existed bo if the bo is already created with the same bo_data.
1021         bo2 = tbm_bufmgr_internal_find_bo(bufmgr, bo);
1022         if (bo2) {
1023                 bo2->ref_cnt++;
1024                 free(bo);
1025                 _tbm_bufmgr_mutex_unlock();
1026                 return bo2;
1027         }
1028
1029         _tbm_bufmgr_initialize_bo(bufmgr, bo, flags);
1030
1031         TBM_TRACE_BO("bo(%p) refcnt(%d), flag(%s)", bo, bo->ref_cnt, _tbm_flag_to_str(bo->flags));
1032
1033         _tbm_bufmgr_mutex_unlock();
1034
1035         return bo;
1036 }
1037
1038 tbm_bo
1039 tbm_bufmgr_internal_import_bo_with_key(tbm_bufmgr bufmgr, unsigned int key, tbm_error_e *error)
1040 {
1041         tbm_bo bo, bo2;
1042         int flags;
1043
1044         _tbm_bufmgr_check_bo_cnt(bufmgr);
1045
1046         bo = calloc(1, sizeof(struct _tbm_bo));
1047         if (!bo) {
1048                 /* LCOV_EXCL_START */
1049                 TBM_ERR("memory allocationc failed.");
1050                 *error = TBM_ERROR_OUT_OF_MEMORY;
1051                 return NULL;
1052                 /* LCOV_EXCL_STOP */
1053         }
1054
1055         bo->bo_data = tbm_module_bufmgr_bo_import_key(bufmgr->module, bo, key, error);
1056         if (!bo->bo_data) {
1057                 /* LCOV_EXCL_START */
1058                 TBM_ERR("tbm_module_bufmgr_bo_import_key failed. tbm_key:%d", key);
1059                 free(bo);
1060                 return NULL;
1061                 /* LCOV_EXCL_STOP */
1062         }
1063
1064         // return the existed bo2 if bo->bo_data and bo2->bo_data is the same
1065         bo2 = tbm_bufmgr_internal_find_bo(bufmgr, bo);
1066         if (bo2) {
1067                 TBM_TRACE_BO("find bo(%p) ref(%d) key(%d) flag(%s) in list",
1068                                         bo2, bo2->ref_cnt, key, _tbm_flag_to_str(bo2->flags));
1069                 bo2->ref_cnt++;
1070                 free(bo);
1071                 return bo2;
1072         }
1073
1074         // TODO: refactoring tbm_module_bo
1075         if (bufmgr->use_hal_tbm) {
1076                 flags = (tbm_bo_memory_type)hal_tbm_bo_get_memory_types((hal_tbm_bo *)bo->bo_data, (hal_tbm_error *)error);
1077                 if (*error != TBM_ERROR_NONE) {
1078                         TBM_ERR("fail to get the bo flags(memory_types)");
1079                         flags = TBM_BO_DEFAULT;
1080                 }
1081         } else if (bufmgr->backend_module_data) {
1082                 flags = bufmgr->bo_func->bo_get_memory_types(bo->bo_data, error);
1083                 if (error != TBM_ERROR_NONE) {
1084                         TBM_ERR("fail to get the bo flags(memory_types)");
1085                         flags = TBM_BO_DEFAULT;
1086                 }
1087         } else {
1088                 if (bufmgr->backend->bo_get_flags)
1089                         flags = bufmgr->backend->bo_get_flags(bo);
1090                 else
1091                         flags = TBM_BO_DEFAULT;
1092         }
1093
1094         _tbm_bufmgr_initialize_bo(bufmgr, bo, flags);
1095
1096         return bo;
1097 }
1098
1099 tbm_bo
1100 tbm_bufmgr_internal_import_bo_with_fd(tbm_bufmgr bufmgr, tbm_fd fd, tbm_error_e *error)
1101 {
1102         tbm_bo bo, bo2;
1103         int flags;
1104
1105         _tbm_bufmgr_check_bo_cnt(bufmgr);
1106
1107         bo = calloc(1, sizeof(struct _tbm_bo));
1108         if (!bo) {
1109                 /* LCOV_EXCL_START */
1110                 TBM_ERR("memory allocationc failed.");
1111                 *error = TBM_ERROR_OUT_OF_MEMORY;
1112                 return NULL;
1113                 /* LCOV_EXCL_STOP */
1114         }
1115
1116         bo->bo_data = tbm_module_bufmgr_bo_import_fd(bufmgr->module, bo, fd, error);
1117         if (!bo->bo_data) {
1118                 /* LCOV_EXCL_START */
1119                 TBM_ERR("tbm_module_bufmgr_bo_import_fd failed. tbm_fd:%d", fd);
1120                 free(bo);
1121                 return NULL;
1122                 /* LCOV_EXCL_STOP */
1123         }
1124
1125         // return the existed bo2 if bo->bo_data and bo2->bo_data is the same
1126         bo2 = tbm_bufmgr_internal_find_bo(bufmgr, bo);
1127         if (bo2) {
1128                 TBM_TRACE_BO("find bo(%p) ref(%d) fd(%d) flag(%s) in list",
1129                                         bo2, bo2->ref_cnt, fd, _tbm_flag_to_str(bo2->flags));
1130                 bo2->ref_cnt++;
1131                 free(bo);
1132                 return bo2;
1133         }
1134
1135         // TODO: refactoring tbm_module_bo
1136         if (bufmgr->use_hal_tbm) {
1137                 flags = (tbm_bo_memory_type)hal_tbm_bo_get_memory_types((hal_tbm_bo *)bo->bo_data, (hal_tbm_error *)error);
1138                 if (error != TBM_ERROR_NONE) {
1139                         TBM_ERR("fail to get the bo flags(memory_types)");
1140                         flags = TBM_BO_DEFAULT;
1141                 }
1142         } else if (bufmgr->backend_module_data) {
1143                 flags = bufmgr->bo_func->bo_get_memory_types(bo->bo_data, error);
1144                 if (error != TBM_ERROR_NONE) {
1145                         TBM_ERR("fail to get the bo flags(memory_types)");
1146                         flags = TBM_BO_DEFAULT;
1147                 }
1148         } else {
1149                 if (bufmgr->backend->bo_get_flags)
1150                         flags = bufmgr->backend->bo_get_flags(bo);
1151                 else
1152                         flags = TBM_BO_DEFAULT;
1153         }
1154
1155         _tbm_bufmgr_initialize_bo(bufmgr, bo, flags);
1156
1157         return bo;
1158 }
1159
1160 /* LCOV_EXCL_STOP */