Don't return error, if fail to get handle in tbm_surface_internal_get_info
[platform/core/uifw/libtbm.git] / src / tbm_surface_internal.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2014 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 #include "tbm_bufmgr.h"
34 #include "tbm_bufmgr_int.h"
35 #include "tbm_surface_internal.h"
36 #include "list.h"
37
38 static tbm_bufmgr g_surface_bufmgr = NULL;
39 static pthread_mutex_t tbm_surface_lock;
40
41 char *_tbm_surface_internal_format_to_str(tbm_format format)
42 {
43         switch (format) {
44         case TBM_FORMAT_C8:
45                 return "TBM_FORMAT_C8";
46         case TBM_FORMAT_RGB332:
47                 return "TBM_FORMAT_RGB332";
48         case TBM_FORMAT_BGR233:
49                 return "TBM_FORMAT_BGR233";
50         case TBM_FORMAT_XRGB4444:
51                 return "TBM_FORMAT_XRGB4444";
52         case TBM_FORMAT_XBGR4444:
53                 return "TBM_FORMAT_XBGR4444";
54         case TBM_FORMAT_RGBX4444:
55                 return "TBM_FORMAT_RGBX4444";
56         case TBM_FORMAT_BGRX4444:
57                 return "TBM_FORMAT_BGRX4444";
58         case TBM_FORMAT_ARGB4444:
59                 return "TBM_FORMAT_ARGB4444";
60         case TBM_FORMAT_ABGR4444:
61                 return "TBM_FORMAT_ABGR4444";
62         case TBM_FORMAT_RGBA4444:
63                 return "TBM_FORMAT_RGBA4444";
64         case TBM_FORMAT_BGRA4444:
65                 return "TBM_FORMAT_BGRA4444";
66         case TBM_FORMAT_XRGB1555:
67                 return "TBM_FORMAT_XRGB1555";
68         case TBM_FORMAT_XBGR1555:
69                 return "TBM_FORMAT_XBGR1555";
70         case TBM_FORMAT_RGBX5551:
71                 return "TBM_FORMAT_RGBX5551";
72         case TBM_FORMAT_BGRX5551:
73                 return "TBM_FORMAT_BGRX5551";
74         case TBM_FORMAT_ARGB1555:
75                 return "TBM_FORMAT_ARGB1555";
76         case TBM_FORMAT_ABGR1555:
77                 return "TBM_FORMAT_ABGR1555";
78         case TBM_FORMAT_RGBA5551:
79                 return "TBM_FORMAT_RGBA5551";
80         case TBM_FORMAT_BGRA5551:
81                 return "TBM_FORMAT_BGRA5551";
82         case TBM_FORMAT_RGB565:
83                 return "TBM_FORMAT_RGB565";
84         case TBM_FORMAT_BGR565:
85                 return "TBM_FORMAT_BGR565";
86         case TBM_FORMAT_RGB888:
87                 return "TBM_FORMAT_RGB888";
88         case TBM_FORMAT_BGR888:
89                 return "TBM_FORMAT_BGR888";
90         case TBM_FORMAT_XRGB8888:
91                 return "TBM_FORMAT_XRGB8888";
92         case TBM_FORMAT_XBGR8888:
93                 return "TBM_FORMAT_XBGR8888";
94         case TBM_FORMAT_RGBX8888:
95                 return "TBM_FORMAT_RGBX8888";
96         case TBM_FORMAT_BGRX8888:
97                 return "TBM_FORMAT_BGRX8888";
98         case TBM_FORMAT_ARGB8888:
99                 return "TBM_FORMAT_ARGB8888";
100         case TBM_FORMAT_ABGR8888:
101                 return "TBM_FORMAT_ABGR8888";
102         case TBM_FORMAT_RGBA8888:
103                 return "TBM_FORMAT_RGBA8888";
104         case TBM_FORMAT_BGRA8888:
105                 return "TBM_FORMAT_BGRA8888";
106         case TBM_FORMAT_XRGB2101010:
107                 return "TBM_FORMAT_XRGB2101010";
108         case TBM_FORMAT_XBGR2101010:
109                 return "TBM_FORMAT_XBGR2101010";
110         case TBM_FORMAT_RGBX1010102:
111                 return "TBM_FORMAT_RGBX1010102";
112         case TBM_FORMAT_BGRX1010102:
113                 return "TBM_FORMAT_BGRX1010102";
114         case TBM_FORMAT_ARGB2101010:
115                 return "TBM_FORMAT_ARGB2101010";
116         case TBM_FORMAT_ABGR2101010:
117                 return "TBM_FORMAT_ABGR2101010";
118         case TBM_FORMAT_RGBA1010102:
119                 return "TBM_FORMAT_RGBA1010102";
120         case TBM_FORMAT_BGRA1010102:
121                 return "TBM_FORMAT_BGRA1010102";
122         case TBM_FORMAT_YUYV:
123                 return "TBM_FORMAT_YUYV";
124         case TBM_FORMAT_YVYU:
125                 return "TBM_FORMAT_YVYU";
126         case TBM_FORMAT_UYVY:
127                 return "TBM_FORMAT_UYVY";
128         case TBM_FORMAT_VYUY:
129                 return "TBM_FORMAT_VYUY";
130         case TBM_FORMAT_AYUV:
131                 return "TBM_FORMAT_AYUV";
132         case TBM_FORMAT_NV12:
133                 return "TBM_FORMAT_NV12";
134         case TBM_FORMAT_NV21:
135                 return "TBM_FORMAT_NV21";
136         case TBM_FORMAT_NV16:
137                 return "TBM_FORMAT_NV16";
138         case TBM_FORMAT_NV61:
139                 return "TBM_FORMAT_NV61";
140         case TBM_FORMAT_YUV410:
141                 return "TBM_FORMAT_YUV410";
142         case TBM_FORMAT_YVU410:
143                 return "TBM_FORMAT_YVU410";
144         case TBM_FORMAT_YUV411:
145                 return "TBM_FORMAT_YUV411";
146         case TBM_FORMAT_YVU411:
147                 return "TBM_FORMAT_YVU411";
148         case TBM_FORMAT_YUV420:
149                 return "TBM_FORMAT_YUV420";
150         case TBM_FORMAT_YVU420:
151                 return "TBM_FORMAT_YVU420";
152         case TBM_FORMAT_YUV422:
153                 return "TBM_FORMAT_YUV422";
154         case TBM_FORMAT_YVU422:
155                 return "TBM_FORMAT_YVU422";
156         case TBM_FORMAT_YUV444:
157                 return "TBM_FORMAT_YUV444";
158         case TBM_FORMAT_YVU444:
159                 return "TBM_FORMAT_YVU444";
160         case TBM_FORMAT_NV12MT:
161                 return "TBM_FORMAT_NV12MT";
162         default:
163                 return "unknwon";
164         }
165 }
166
167 static bool _tbm_surface_mutex_init(void)
168 {
169         static bool tbm_surface_mutex_init = false;
170
171         if (tbm_surface_mutex_init)
172                 return true;
173
174         if (pthread_mutex_init(&tbm_surface_lock, NULL)) {
175                 TBM_LOG("[libtbm] fail: tbm_surface mutex init\n");
176                 return false;
177         }
178
179         tbm_surface_mutex_init = true;
180
181         return true;
182 }
183
184 void _tbm_surface_mutex_lock(void)
185 {
186         if (!_tbm_surface_mutex_init())
187                 return;
188
189         pthread_mutex_lock(&tbm_surface_lock);
190 }
191
192 void _tbm_surface_mutex_unlock(void)
193 {
194         pthread_mutex_unlock(&tbm_surface_lock);
195 }
196
197 static void _init_surface_bufmgr()
198 {
199         g_surface_bufmgr = tbm_bufmgr_init(-1);
200 }
201
202 static void _deinit_surface_bufmgr()
203 {
204         if (!g_surface_bufmgr)
205                 return;
206
207         tbm_bufmgr_deinit(g_surface_bufmgr);
208         g_surface_bufmgr = NULL;
209 }
210
211 static int _tbm_surface_internal_query_size(tbm_surface_h surface)
212 {
213         TBM_RETURN_VAL_IF_FAIL(surface, 0);
214
215         struct _tbm_surface *surf = (struct _tbm_surface *)surface;
216         struct _tbm_bufmgr *mgr = surf->bufmgr;
217         int size = 0;
218
219         TBM_RETURN_VAL_IF_FAIL(mgr != NULL, 0);
220         TBM_RETURN_VAL_IF_FAIL(surf->info.width > 0, 0);
221         TBM_RETURN_VAL_IF_FAIL(surf->info.height > 0, 0);
222         TBM_RETURN_VAL_IF_FAIL(surf->info.format > 0, 0);
223
224         if (!mgr->backend->surface_get_size)
225                 return 0;
226
227         size = mgr->backend->surface_get_size(surf, surf->info.width, surf->info.height, surf->info.format);
228
229         return size;
230 }
231
232 static int _tbm_surface_internal_query_plane_data(tbm_surface_h surface, int plane_idx, uint32_t * size, uint32_t * offset, uint32_t * pitch, int *bo_idx)
233 {
234         TBM_RETURN_VAL_IF_FAIL(surface, 0);
235         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
236
237         struct _tbm_surface *surf = (struct _tbm_surface *)surface;
238         struct _tbm_bufmgr *mgr = surf->bufmgr;
239         int ret = 0;
240
241         TBM_RETURN_VAL_IF_FAIL(mgr != NULL, 0);
242         TBM_RETURN_VAL_IF_FAIL(surf->info.width > 0, 0);
243         TBM_RETURN_VAL_IF_FAIL(surf->info.height > 0, 0);
244         TBM_RETURN_VAL_IF_FAIL(surf->info.format > 0, 0);
245
246         if (!mgr->backend->surface_get_plane_data)
247                 return 0;
248
249         ret = mgr->backend->surface_get_plane_data(surf, surf->info.width, surf->info.height, surf->info.format, plane_idx, size, offset, pitch, bo_idx);
250         if (!ret)
251                 return 0;
252
253         return 1;
254 }
255
256 static int _tbm_surface_internal_query_num_bos(tbm_format format)
257 {
258         TBM_RETURN_VAL_IF_FAIL(format > 0, 0);
259         struct _tbm_bufmgr *mgr;
260         int ret = 0;
261
262         mgr = g_surface_bufmgr;
263
264         if (!mgr->backend->surface_get_num_bos)
265                 return 0;
266
267         ret = mgr->backend->surface_get_num_bos(format);
268         if (!ret)
269                 return 0;
270
271         return ret;
272 }
273
274 static void _tbm_surface_internal_destroy(tbm_surface_h surface)
275 {
276         int i;
277         tbm_bufmgr bufmgr = surface->bufmgr;
278         tbm_user_data *old_data = NULL, *tmp = NULL;
279
280         for (i = 0; i < surface->num_bos; i++) {
281                 surface->bos[i]->surface = NULL;
282
283                 tbm_bo_unref(surface->bos[i]);
284                 surface->bos[i] = NULL;
285         }
286
287         /* destory the user_data_list */
288         if (!LIST_IS_EMPTY(&surface->user_data_list)) {
289                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &surface->user_data_list, item_link) {
290                         TBM_LOG("[tbm_surface:%d] free user_data \n",
291                                 getpid());
292                         user_data_delete(old_data);
293                 }
294         }
295
296         LIST_DEL(&surface->item_link);
297
298         free(surface);
299         surface = NULL;
300
301         if (LIST_IS_EMPTY(&bufmgr->surf_list)) {
302                 LIST_DELINIT(&bufmgr->surf_list);
303                 _deinit_surface_bufmgr();
304         }
305 }
306
307 int tbm_surface_internal_query_supported_formats(uint32_t ** formats, uint32_t * num)
308 {
309         struct _tbm_bufmgr *mgr;
310         int ret = 0;
311
312         _tbm_surface_mutex_lock();
313
314         if (!g_surface_bufmgr) {
315                 _init_surface_bufmgr();
316                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
317         }
318
319         mgr = g_surface_bufmgr;
320
321         if (!mgr->backend->surface_supported_format) {
322                 _tbm_surface_mutex_unlock();
323                 return 0;
324         }
325
326         ret = mgr->backend->surface_supported_format(formats, num);
327
328         _tbm_surface_mutex_unlock();
329
330         return ret;
331 }
332
333 int tbm_surface_internal_get_num_planes(tbm_format format)
334 {
335         int num_planes = 0;
336
337         switch (format) {
338         case TBM_FORMAT_C8:
339         case TBM_FORMAT_RGB332:
340         case TBM_FORMAT_BGR233:
341         case TBM_FORMAT_XRGB4444:
342         case TBM_FORMAT_XBGR4444:
343         case TBM_FORMAT_RGBX4444:
344         case TBM_FORMAT_BGRX4444:
345         case TBM_FORMAT_ARGB4444:
346         case TBM_FORMAT_ABGR4444:
347         case TBM_FORMAT_RGBA4444:
348         case TBM_FORMAT_BGRA4444:
349         case TBM_FORMAT_XRGB1555:
350         case TBM_FORMAT_XBGR1555:
351         case TBM_FORMAT_RGBX5551:
352         case TBM_FORMAT_BGRX5551:
353         case TBM_FORMAT_ARGB1555:
354         case TBM_FORMAT_ABGR1555:
355         case TBM_FORMAT_RGBA5551:
356         case TBM_FORMAT_BGRA5551:
357         case TBM_FORMAT_RGB565:
358         case TBM_FORMAT_BGR565:
359         case TBM_FORMAT_RGB888:
360         case TBM_FORMAT_BGR888:
361         case TBM_FORMAT_XRGB8888:
362         case TBM_FORMAT_XBGR8888:
363         case TBM_FORMAT_RGBX8888:
364         case TBM_FORMAT_BGRX8888:
365         case TBM_FORMAT_ARGB8888:
366         case TBM_FORMAT_ABGR8888:
367         case TBM_FORMAT_RGBA8888:
368         case TBM_FORMAT_BGRA8888:
369         case TBM_FORMAT_XRGB2101010:
370         case TBM_FORMAT_XBGR2101010:
371         case TBM_FORMAT_RGBX1010102:
372         case TBM_FORMAT_BGRX1010102:
373         case TBM_FORMAT_ARGB2101010:
374         case TBM_FORMAT_ABGR2101010:
375         case TBM_FORMAT_RGBA1010102:
376         case TBM_FORMAT_BGRA1010102:
377         case TBM_FORMAT_YUYV:
378         case TBM_FORMAT_YVYU:
379         case TBM_FORMAT_UYVY:
380         case TBM_FORMAT_VYUY:
381         case TBM_FORMAT_AYUV:
382                 num_planes = 1;
383                 break;
384         case TBM_FORMAT_NV12:
385         case TBM_FORMAT_NV21:
386         case TBM_FORMAT_NV16:
387         case TBM_FORMAT_NV61:
388                 num_planes = 2;
389                 break;
390         case TBM_FORMAT_YUV410:
391         case TBM_FORMAT_YVU410:
392         case TBM_FORMAT_YUV411:
393         case TBM_FORMAT_YVU411:
394         case TBM_FORMAT_YUV420:
395         case TBM_FORMAT_YVU420:
396         case TBM_FORMAT_YUV422:
397         case TBM_FORMAT_YVU422:
398         case TBM_FORMAT_YUV444:
399         case TBM_FORMAT_YVU444:
400                 num_planes = 3;
401                 break;
402
403         default:
404                 break;
405         }
406
407         return num_planes;
408 }
409
410 int tbm_surface_internal_get_bpp(tbm_format format)
411 {
412         int bpp = 0;
413
414         switch (format) {
415         case TBM_FORMAT_C8:
416         case TBM_FORMAT_RGB332:
417         case TBM_FORMAT_BGR233:
418                 bpp = 8;
419                 break;
420         case TBM_FORMAT_XRGB4444:
421         case TBM_FORMAT_XBGR4444:
422         case TBM_FORMAT_RGBX4444:
423         case TBM_FORMAT_BGRX4444:
424         case TBM_FORMAT_ARGB4444:
425         case TBM_FORMAT_ABGR4444:
426         case TBM_FORMAT_RGBA4444:
427         case TBM_FORMAT_BGRA4444:
428         case TBM_FORMAT_XRGB1555:
429         case TBM_FORMAT_XBGR1555:
430         case TBM_FORMAT_RGBX5551:
431         case TBM_FORMAT_BGRX5551:
432         case TBM_FORMAT_ARGB1555:
433         case TBM_FORMAT_ABGR1555:
434         case TBM_FORMAT_RGBA5551:
435         case TBM_FORMAT_BGRA5551:
436         case TBM_FORMAT_RGB565:
437         case TBM_FORMAT_BGR565:
438                 bpp = 16;
439                 break;
440         case TBM_FORMAT_RGB888:
441         case TBM_FORMAT_BGR888:
442                 bpp = 24;
443                 break;
444         case TBM_FORMAT_XRGB8888:
445         case TBM_FORMAT_XBGR8888:
446         case TBM_FORMAT_RGBX8888:
447         case TBM_FORMAT_BGRX8888:
448         case TBM_FORMAT_ARGB8888:
449         case TBM_FORMAT_ABGR8888:
450         case TBM_FORMAT_RGBA8888:
451         case TBM_FORMAT_BGRA8888:
452         case TBM_FORMAT_XRGB2101010:
453         case TBM_FORMAT_XBGR2101010:
454         case TBM_FORMAT_RGBX1010102:
455         case TBM_FORMAT_BGRX1010102:
456         case TBM_FORMAT_ARGB2101010:
457         case TBM_FORMAT_ABGR2101010:
458         case TBM_FORMAT_RGBA1010102:
459         case TBM_FORMAT_BGRA1010102:
460         case TBM_FORMAT_YUYV:
461         case TBM_FORMAT_YVYU:
462         case TBM_FORMAT_UYVY:
463         case TBM_FORMAT_VYUY:
464         case TBM_FORMAT_AYUV:
465                 bpp = 32;
466                 break;
467         case TBM_FORMAT_NV12:
468         case TBM_FORMAT_NV21:
469                 bpp = 12;
470                 break;
471         case TBM_FORMAT_NV16:
472         case TBM_FORMAT_NV61:
473                 bpp = 16;
474                 break;
475         case TBM_FORMAT_YUV410:
476         case TBM_FORMAT_YVU410:
477                 bpp = 9;
478                 break;
479         case TBM_FORMAT_YUV411:
480         case TBM_FORMAT_YVU411:
481         case TBM_FORMAT_YUV420:
482         case TBM_FORMAT_YVU420:
483                 bpp = 12;
484                 break;
485         case TBM_FORMAT_YUV422:
486         case TBM_FORMAT_YVU422:
487                 bpp = 16;
488                 break;
489         case TBM_FORMAT_YUV444:
490         case TBM_FORMAT_YVU444:
491                 bpp = 24;
492                 break;
493         default:
494                 break;
495         }
496
497         return bpp;
498 }
499
500 tbm_surface_h tbm_surface_internal_create_with_flags(int width, int height, int format, int flags)
501 {
502         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
503         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
504
505         struct _tbm_bufmgr *mgr;
506         struct _tbm_surface *surf = NULL;
507         uint32_t size = 0;
508         uint32_t offset = 0;
509         uint32_t stride = 0;
510         uint32_t bo_size = 0;
511         int bo_idx;
512         int i, j;
513
514         _tbm_surface_mutex_lock();
515
516         if (!g_surface_bufmgr) {
517                 _init_surface_bufmgr();
518                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
519         }
520
521         mgr = g_surface_bufmgr;
522         if (!TBM_BUFMGR_IS_VALID(mgr)) {
523                 _tbm_surface_mutex_unlock();
524                 return NULL;
525         }
526         surf = calloc(1, sizeof(struct _tbm_surface));
527         if (!surf) {
528                 _tbm_surface_mutex_unlock();
529                 return NULL;
530         }
531
532         surf->bufmgr = mgr;
533         surf->info.width = width;
534         surf->info.height = height;
535         surf->info.format = format;
536         surf->info.bpp = tbm_surface_internal_get_bpp(format);
537         surf->info.size = _tbm_surface_internal_query_size(surf);
538         surf->info.num_planes = tbm_surface_internal_get_num_planes(format);
539         surf->num_bos = _tbm_surface_internal_query_num_bos(format);
540         surf->refcnt = 1;
541
542         /* get size, stride and offset bo_idx */
543         for (i = 0; i < surf->info.num_planes; i++) {
544                 _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride, &bo_idx);
545                 surf->info.planes[i].size = size;
546                 surf->info.planes[i].offset = offset;
547                 surf->info.planes[i].stride = stride;
548                 surf->planes_bo_idx[i] = bo_idx;
549         }
550
551         surf->flags = flags;
552
553         for (i = 0; i < surf->num_bos; i++) {
554                 bo_size = 0;
555                 for (j = 0; j < surf->info.num_planes; j++) {
556                         if (surf->planes_bo_idx[j] == i)
557                                 bo_size += surf->info.planes[j].size;
558                 }
559                 surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
560                 if (!surf->bos[i]) {
561                         for (j = 0; j < i; j++) {
562                                 if (surf->bos[j])
563                                         tbm_bo_unref(surf->bos[j]);
564                         }
565
566                         free(surf);
567                         surf = NULL;
568
569                         if (LIST_IS_EMPTY(&mgr->surf_list)) {
570                                 LIST_DELINIT(&mgr->surf_list);
571                                 _deinit_surface_bufmgr();
572                         }
573
574                         _tbm_surface_mutex_unlock();
575                         return NULL;
576                 }
577                 _tbm_bo_set_surface(surf->bos[i], surf);
578
579         }
580
581         LIST_INITHEAD(&surf->user_data_list);
582
583         LIST_ADD(&surf->item_link, &mgr->surf_list);
584
585         _tbm_surface_mutex_unlock();
586
587         return surf;
588 }
589
590 tbm_surface_h tbm_surface_internal_create_with_bos(tbm_surface_info_s * info, tbm_bo * bos, int num)
591 {
592         TBM_RETURN_VAL_IF_FAIL(bos, NULL);
593         TBM_RETURN_VAL_IF_FAIL(info, NULL);
594         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
595
596         struct _tbm_bufmgr *mgr;
597         struct _tbm_surface *surf = NULL;
598         int i;
599
600         _tbm_surface_mutex_lock();
601
602         if (!g_surface_bufmgr) {
603                 _init_surface_bufmgr();
604                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
605         }
606
607         mgr = g_surface_bufmgr;
608         if (!TBM_BUFMGR_IS_VALID(mgr)) {
609                 _tbm_surface_mutex_unlock();
610                 return NULL;
611         }
612
613         surf = calloc(1, sizeof(struct _tbm_surface));
614         if (!surf) {
615                 _tbm_surface_mutex_unlock();
616                 return NULL;
617         }
618
619         surf->bufmgr = mgr;
620         surf->info.width = info->width;
621         surf->info.height = info->height;
622         surf->info.format = info->format;
623         surf->info.bpp = info->bpp;
624         surf->info.num_planes = info->num_planes;
625         surf->refcnt = 1;
626
627         /* get size, stride and offset */
628         for (i = 0; i < info->num_planes; i++) {
629                 surf->info.planes[i].offset = info->planes[i].offset;
630                 surf->info.planes[i].stride = info->planes[i].stride;
631
632                 if (info->planes[i].size > 0)
633                         surf->info.planes[i].size = info->planes[i].size;
634                 else
635                         surf->info.planes[i].size += surf->info.planes[i].stride * info->height;
636
637                 if (num == 1)
638                         surf->planes_bo_idx[i] = 0;
639                 else
640                         surf->planes_bo_idx[i] = i;
641         }
642
643         if (info->size > 0) {
644                 surf->info.size = info->size;
645         } else {
646                 surf->info.size = 0;
647                 for (i = 0; i < info->num_planes; i++)
648                         surf->info.size += surf->info.planes[i].size;
649         }
650
651         surf->flags = TBM_BO_DEFAULT;
652
653         /* create only one bo */
654         surf->num_bos = num;
655         for (i = 0; i < num; i++) {
656                 if (bos[i] == NULL)
657                         goto bail1;
658
659                 surf->bos[i] = tbm_bo_ref(bos[i]);
660                 _tbm_bo_set_surface(bos[i], surf);
661         }
662
663         LIST_INITHEAD(&surf->user_data_list);
664
665         LIST_ADD(&surf->item_link, &mgr->surf_list);
666
667         _tbm_surface_mutex_unlock();
668
669         return surf;
670  bail1:
671         for (i = 0; i < num; i++) {
672                 if (surf->bos[i]) {
673                         tbm_bo_unref(surf->bos[i]);
674                         surf->bos[i] = NULL;
675                 }
676         }
677
678         free(surf);
679         surf = NULL;
680
681         if (LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
682                 LIST_DELINIT(&g_surface_bufmgr->surf_list);
683                 _deinit_surface_bufmgr();
684         }
685
686         _tbm_surface_mutex_unlock();
687
688         return NULL;
689 }
690
691 void tbm_surface_internal_destroy(tbm_surface_h surface)
692 {
693         if (!surface)
694                 return;
695
696         _tbm_surface_mutex_lock();
697
698         surface->refcnt--;
699
700         if (surface->refcnt > 0) {
701                 _tbm_surface_mutex_unlock();
702                 return;
703         }
704
705         if (surface->refcnt == 0)
706                 _tbm_surface_internal_destroy(surface);
707
708         _tbm_surface_mutex_unlock();
709 }
710
711 void tbm_surface_internal_ref(tbm_surface_h surface)
712 {
713         TBM_RETURN_IF_FAIL(surface);
714
715         _tbm_surface_mutex_lock();
716
717         surface->refcnt++;
718
719         _tbm_surface_mutex_unlock();
720 }
721
722 void tbm_surface_internal_unref(tbm_surface_h surface)
723 {
724         TBM_RETURN_IF_FAIL(surface);
725
726         _tbm_surface_mutex_lock();
727
728         surface->refcnt--;
729
730         if (surface->refcnt > 0) {
731                 _tbm_surface_mutex_unlock();
732                 return;
733         }
734
735         if (surface->refcnt == 0)
736                 _tbm_surface_internal_destroy(surface);
737
738         _tbm_surface_mutex_unlock();
739 }
740
741 int tbm_surface_internal_get_num_bos(tbm_surface_h surface)
742 {
743         TBM_RETURN_VAL_IF_FAIL(surface, 0);
744
745         struct _tbm_surface *surf;
746         int num;
747
748         _tbm_surface_mutex_lock();
749
750         surf = (struct _tbm_surface *)surface;
751         num = surf->num_bos;
752
753         _tbm_surface_mutex_unlock();
754
755         return num;
756 }
757
758 tbm_bo tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
759 {
760         TBM_RETURN_VAL_IF_FAIL(surface, NULL);
761         TBM_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
762
763         struct _tbm_surface *surf;
764         tbm_bo bo;
765
766         _tbm_surface_mutex_lock();
767
768         surf = (struct _tbm_surface *)surface;
769         bo = surf->bos[bo_idx];
770
771         _tbm_surface_mutex_unlock();
772
773         return bo;
774 }
775
776 int tbm_surface_internal_get_size(tbm_surface_h surface)
777 {
778         TBM_RETURN_VAL_IF_FAIL(surface, 0);
779
780         struct _tbm_surface *surf;
781         unsigned int size;
782
783         _tbm_surface_mutex_lock();
784
785         surf = (struct _tbm_surface *)surface;
786         size = surf->info.size;
787
788         _tbm_surface_mutex_unlock();
789
790         return size;
791 }
792
793 int tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx, uint32_t * size, uint32_t * offset, uint32_t * pitch)
794 {
795         TBM_RETURN_VAL_IF_FAIL(surface, 0);
796         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
797
798         struct _tbm_surface *surf;
799
800         _tbm_surface_mutex_lock();
801
802         surf = (struct _tbm_surface *)surface;
803
804         if (plane_idx >= surf->info.num_planes) {
805                 _tbm_surface_mutex_unlock();
806                 return 0;
807         }
808
809         if (size)
810                 *size = surf->info.planes[plane_idx].size;
811
812         if (offset)
813                 *offset = surf->info.planes[plane_idx].offset;
814
815         if (pitch)
816                 *pitch = surf->info.planes[plane_idx].stride;
817
818         _tbm_surface_mutex_unlock();
819
820         return 1;
821 }
822
823 int tbm_surface_internal_get_info(tbm_surface_h surface, int opt, tbm_surface_info_s * info, int map)
824 {
825         struct _tbm_surface *surf;
826         tbm_bo_handle bo_handles[4];
827         int i, j;
828
829         _tbm_surface_mutex_lock();
830
831         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
832
833         surf = (struct _tbm_surface *)surface;
834
835         info->width = surf->info.width;
836         info->height = surf->info.height;
837         info->format = surf->info.format;
838         info->bpp = surf->info.bpp;
839         info->size = surf->info.size;
840         info->num_planes = surf->info.num_planes;
841
842         if (map == 1) {
843                 for (i = 0; i < surf->num_bos; i++) {
844                         bo_handles[i] = tbm_bo_map(surf->bos[i], TBM_DEVICE_CPU, opt);
845                         if (bo_handles[i].ptr == NULL) {
846                                 for (j = 0; j < i; j++)
847                                         tbm_bo_unmap(surf->bos[j]);
848
849                                 _tbm_surface_mutex_unlock();
850                                 return 0;
851                         }
852                 }
853         } else {
854                 for (i = 0; i < surf->num_bos; i++) {
855                         bo_handles[i] = tbm_bo_get_handle(surf->bos[i], TBM_DEVICE_CPU);
856                 }
857         }
858
859         for (i = 0; i < surf->info.num_planes; i++) {
860                 info->planes[i].size = surf->info.planes[i].size;
861                 info->planes[i].offset = surf->info.planes[i].offset;
862                 info->planes[i].stride = surf->info.planes[i].stride;
863
864                 if (bo_handles[surf->planes_bo_idx[i]].ptr)
865                         info->planes[i].ptr = bo_handles[surf->planes_bo_idx[i]].ptr + surf->info.planes[i].offset;
866         }
867
868         _tbm_surface_mutex_unlock();
869
870         return 1;
871 }
872
873 void tbm_surface_internal_unmap(tbm_surface_h surface)
874 {
875         struct _tbm_surface *surf;
876         int i;
877
878         _tbm_surface_mutex_lock();
879
880         surf = (struct _tbm_surface *)surface;
881
882         for (i = 0; i < surf->num_bos; i++)
883                 tbm_bo_unmap(surf->bos[i]);
884
885         _tbm_surface_mutex_unlock();
886 }
887
888 unsigned int tbm_surface_internal_get_width(tbm_surface_h surface)
889 {
890         struct _tbm_surface *surf;
891         unsigned int width;
892
893         _tbm_surface_mutex_lock();
894
895         surf = (struct _tbm_surface *)surface;
896         width = surf->info.width;
897
898         _tbm_surface_mutex_unlock();
899
900         return width;
901 }
902
903 unsigned int tbm_surface_internal_get_height(tbm_surface_h surface)
904 {
905         struct _tbm_surface *surf;
906         unsigned int height;
907
908         _tbm_surface_mutex_lock();
909
910         surf = (struct _tbm_surface *)surface;
911         height = surf->info.height;
912
913         _tbm_surface_mutex_unlock();
914
915         return height;
916
917 }
918
919 tbm_format tbm_surface_internal_get_format(tbm_surface_h surface)
920 {
921         struct _tbm_surface *surf;
922         tbm_format format;
923
924         _tbm_surface_mutex_lock();
925
926         surf = (struct _tbm_surface *)surface;
927         format = surf->info.format;
928
929         _tbm_surface_mutex_unlock();
930
931         return format;
932 }
933
934 int tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
935 {
936         TBM_RETURN_VAL_IF_FAIL(surface, 0);
937         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
938         struct _tbm_surface *surf;
939         int bo_idx;
940
941         _tbm_surface_mutex_lock();
942
943         surf = (struct _tbm_surface *)surface;
944         bo_idx = surf->planes_bo_idx[plane_idx];
945
946         _tbm_surface_mutex_unlock();
947
948         return bo_idx;
949 }
950
951 unsigned int _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
952 {
953         TBM_RETURN_VAL_IF_FAIL(surface, 0);
954
955         return surface->debug_pid;
956 }
957
958 void tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
959 {
960         TBM_RETURN_IF_FAIL(surface);
961
962         surface->debug_pid = pid;
963 }
964
965 int tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key, tbm_data_free data_free_func)
966 {
967         TBM_RETURN_VAL_IF_FAIL(surface, 0);
968
969         tbm_user_data *data;
970
971         /* check if the data according to the key exist if so, return false. */
972         data = user_data_lookup(&surface->user_data_list, key);
973         if (data) {
974                 TBM_LOG("[libtbm:%d] "
975                         "waring: %s:%d user data already exist. key:%ld\n",
976                         getpid(), __FUNCTION__, __LINE__, key);
977                 return 0;
978         }
979
980         data = user_data_create(key, data_free_func);
981         if (!data)
982                 return 0;
983
984         LIST_ADD(&data->item_link, &surface->user_data_list);
985
986         return 1;
987 }
988
989 int tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key, void *data)
990 {
991         TBM_RETURN_VAL_IF_FAIL(surface, 0);
992
993         tbm_user_data *old_data;
994
995         if (LIST_IS_EMPTY(&surface->user_data_list))
996                 return 0;
997
998         old_data = user_data_lookup(&surface->user_data_list, key);
999         if (!old_data)
1000                 return 0;
1001
1002         if (old_data->data && old_data->free_func)
1003                 old_data->free_func(old_data->data);
1004
1005         old_data->data = data;
1006
1007         return 1;
1008 }
1009
1010 int tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key, void **data)
1011 {
1012         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1013
1014         tbm_user_data *old_data;
1015
1016         if (!data || LIST_IS_EMPTY(&surface->user_data_list))
1017                 return 0;
1018
1019         old_data = user_data_lookup(&surface->user_data_list, key);
1020         if (!old_data) {
1021                 *data = NULL;
1022                 return 0;
1023         }
1024
1025         *data = old_data->data;
1026
1027         return 1;
1028 }
1029
1030 int tbm_surface_internal_delete_user_data(tbm_surface_h surface, unsigned long key)
1031 {
1032         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1033
1034         tbm_user_data *old_data = (void *)0;
1035
1036         if (LIST_IS_EMPTY(&surface->user_data_list))
1037                 return 0;
1038
1039         old_data = user_data_lookup(&surface->user_data_list, key);
1040         if (!old_data)
1041                 return 0;
1042
1043         user_data_delete(old_data);
1044
1045         return 1;
1046 }
1047