ebba248847653894ffea3c5883dc0566e352c4d5
[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
279         for (i = 0; i < surface->num_bos; i++) {
280                 surface->bos[i]->surface = NULL;
281
282                 tbm_bo_unref(surface->bos[i]);
283                 surface->bos[i] = NULL;
284         }
285
286         free(surface);
287         surface = NULL;
288
289         if (LIST_IS_EMPTY(&bufmgr->surf_list)) {
290                 LIST_DELINIT(&bufmgr->surf_list);
291                 _deinit_surface_bufmgr();
292         }
293 }
294
295 int tbm_surface_internal_query_supported_formats(uint32_t ** formats, uint32_t * num)
296 {
297         struct _tbm_bufmgr *mgr;
298         int ret = 0;
299
300         _tbm_surface_mutex_lock();
301
302         if (!g_surface_bufmgr) {
303                 _init_surface_bufmgr();
304                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
305         }
306
307         mgr = g_surface_bufmgr;
308
309         if (!mgr->backend->surface_supported_format) {
310                 _tbm_surface_mutex_unlock();
311                 return 0;
312         }
313
314         ret = mgr->backend->surface_supported_format(formats, num);
315
316         _tbm_surface_mutex_unlock();
317
318         return ret;
319 }
320
321 int tbm_surface_internal_get_num_planes(tbm_format format)
322 {
323         int num_planes = 0;
324
325         switch (format) {
326         case TBM_FORMAT_C8:
327         case TBM_FORMAT_RGB332:
328         case TBM_FORMAT_BGR233:
329         case TBM_FORMAT_XRGB4444:
330         case TBM_FORMAT_XBGR4444:
331         case TBM_FORMAT_RGBX4444:
332         case TBM_FORMAT_BGRX4444:
333         case TBM_FORMAT_ARGB4444:
334         case TBM_FORMAT_ABGR4444:
335         case TBM_FORMAT_RGBA4444:
336         case TBM_FORMAT_BGRA4444:
337         case TBM_FORMAT_XRGB1555:
338         case TBM_FORMAT_XBGR1555:
339         case TBM_FORMAT_RGBX5551:
340         case TBM_FORMAT_BGRX5551:
341         case TBM_FORMAT_ARGB1555:
342         case TBM_FORMAT_ABGR1555:
343         case TBM_FORMAT_RGBA5551:
344         case TBM_FORMAT_BGRA5551:
345         case TBM_FORMAT_RGB565:
346         case TBM_FORMAT_BGR565:
347         case TBM_FORMAT_RGB888:
348         case TBM_FORMAT_BGR888:
349         case TBM_FORMAT_XRGB8888:
350         case TBM_FORMAT_XBGR8888:
351         case TBM_FORMAT_RGBX8888:
352         case TBM_FORMAT_BGRX8888:
353         case TBM_FORMAT_ARGB8888:
354         case TBM_FORMAT_ABGR8888:
355         case TBM_FORMAT_RGBA8888:
356         case TBM_FORMAT_BGRA8888:
357         case TBM_FORMAT_XRGB2101010:
358         case TBM_FORMAT_XBGR2101010:
359         case TBM_FORMAT_RGBX1010102:
360         case TBM_FORMAT_BGRX1010102:
361         case TBM_FORMAT_ARGB2101010:
362         case TBM_FORMAT_ABGR2101010:
363         case TBM_FORMAT_RGBA1010102:
364         case TBM_FORMAT_BGRA1010102:
365         case TBM_FORMAT_YUYV:
366         case TBM_FORMAT_YVYU:
367         case TBM_FORMAT_UYVY:
368         case TBM_FORMAT_VYUY:
369         case TBM_FORMAT_AYUV:
370                 num_planes = 1;
371                 break;
372         case TBM_FORMAT_NV12:
373         case TBM_FORMAT_NV21:
374         case TBM_FORMAT_NV16:
375         case TBM_FORMAT_NV61:
376                 num_planes = 2;
377                 break;
378         case TBM_FORMAT_YUV410:
379         case TBM_FORMAT_YVU410:
380         case TBM_FORMAT_YUV411:
381         case TBM_FORMAT_YVU411:
382         case TBM_FORMAT_YUV420:
383         case TBM_FORMAT_YVU420:
384         case TBM_FORMAT_YUV422:
385         case TBM_FORMAT_YVU422:
386         case TBM_FORMAT_YUV444:
387         case TBM_FORMAT_YVU444:
388                 num_planes = 3;
389                 break;
390
391         default:
392                 break;
393         }
394
395         return num_planes;
396 }
397
398 int tbm_surface_internal_get_bpp(tbm_format format)
399 {
400         int bpp = 0;
401
402         switch (format) {
403         case TBM_FORMAT_C8:
404         case TBM_FORMAT_RGB332:
405         case TBM_FORMAT_BGR233:
406                 bpp = 8;
407                 break;
408         case TBM_FORMAT_XRGB4444:
409         case TBM_FORMAT_XBGR4444:
410         case TBM_FORMAT_RGBX4444:
411         case TBM_FORMAT_BGRX4444:
412         case TBM_FORMAT_ARGB4444:
413         case TBM_FORMAT_ABGR4444:
414         case TBM_FORMAT_RGBA4444:
415         case TBM_FORMAT_BGRA4444:
416         case TBM_FORMAT_XRGB1555:
417         case TBM_FORMAT_XBGR1555:
418         case TBM_FORMAT_RGBX5551:
419         case TBM_FORMAT_BGRX5551:
420         case TBM_FORMAT_ARGB1555:
421         case TBM_FORMAT_ABGR1555:
422         case TBM_FORMAT_RGBA5551:
423         case TBM_FORMAT_BGRA5551:
424         case TBM_FORMAT_RGB565:
425         case TBM_FORMAT_BGR565:
426                 bpp = 16;
427                 break;
428         case TBM_FORMAT_RGB888:
429         case TBM_FORMAT_BGR888:
430                 bpp = 24;
431                 break;
432         case TBM_FORMAT_XRGB8888:
433         case TBM_FORMAT_XBGR8888:
434         case TBM_FORMAT_RGBX8888:
435         case TBM_FORMAT_BGRX8888:
436         case TBM_FORMAT_ARGB8888:
437         case TBM_FORMAT_ABGR8888:
438         case TBM_FORMAT_RGBA8888:
439         case TBM_FORMAT_BGRA8888:
440         case TBM_FORMAT_XRGB2101010:
441         case TBM_FORMAT_XBGR2101010:
442         case TBM_FORMAT_RGBX1010102:
443         case TBM_FORMAT_BGRX1010102:
444         case TBM_FORMAT_ARGB2101010:
445         case TBM_FORMAT_ABGR2101010:
446         case TBM_FORMAT_RGBA1010102:
447         case TBM_FORMAT_BGRA1010102:
448         case TBM_FORMAT_YUYV:
449         case TBM_FORMAT_YVYU:
450         case TBM_FORMAT_UYVY:
451         case TBM_FORMAT_VYUY:
452         case TBM_FORMAT_AYUV:
453                 bpp = 32;
454                 break;
455         case TBM_FORMAT_NV12:
456         case TBM_FORMAT_NV21:
457                 bpp = 12;
458                 break;
459         case TBM_FORMAT_NV16:
460         case TBM_FORMAT_NV61:
461                 bpp = 16;
462                 break;
463         case TBM_FORMAT_YUV410:
464         case TBM_FORMAT_YVU410:
465                 bpp = 9;
466                 break;
467         case TBM_FORMAT_YUV411:
468         case TBM_FORMAT_YVU411:
469         case TBM_FORMAT_YUV420:
470         case TBM_FORMAT_YVU420:
471                 bpp = 12;
472                 break;
473         case TBM_FORMAT_YUV422:
474         case TBM_FORMAT_YVU422:
475                 bpp = 16;
476                 break;
477         case TBM_FORMAT_YUV444:
478         case TBM_FORMAT_YVU444:
479                 bpp = 24;
480                 break;
481         default:
482                 break;
483         }
484
485         return bpp;
486 }
487
488 tbm_surface_h tbm_surface_internal_create_with_flags(int width, int height, int format, int flags)
489 {
490         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
491         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
492
493         struct _tbm_bufmgr *mgr;
494         struct _tbm_surface *surf = NULL;
495         uint32_t size = 0;
496         uint32_t offset = 0;
497         uint32_t stride = 0;
498         uint32_t bo_size = 0;
499         int bo_idx;
500         int i, j;
501
502         _tbm_surface_mutex_lock();
503
504         if (!g_surface_bufmgr) {
505                 _init_surface_bufmgr();
506                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
507         }
508
509         mgr = g_surface_bufmgr;
510         if (!TBM_BUFMGR_IS_VALID(mgr)) {
511                 _tbm_surface_mutex_unlock();
512                 return NULL;
513         }
514         surf = calloc(1, sizeof(struct _tbm_surface));
515         if (!surf) {
516                 _tbm_surface_mutex_unlock();
517                 return NULL;
518         }
519
520         surf->bufmgr = mgr;
521         surf->info.width = width;
522         surf->info.height = height;
523         surf->info.format = format;
524         surf->info.bpp = tbm_surface_internal_get_bpp(format);
525         surf->info.size = _tbm_surface_internal_query_size(surf);
526         surf->info.num_planes = tbm_surface_internal_get_num_planes(format);
527         surf->num_bos = _tbm_surface_internal_query_num_bos(format);
528         surf->refcnt = 1;
529
530         /* get size, stride and offset bo_idx */
531         for (i = 0; i < surf->info.num_planes; i++) {
532                 _tbm_surface_internal_query_plane_data(surf, i, &size, &offset, &stride, &bo_idx);
533                 surf->info.planes[i].size = size;
534                 surf->info.planes[i].offset = offset;
535                 surf->info.planes[i].stride = stride;
536                 surf->planes_bo_idx[i] = bo_idx;
537         }
538
539         surf->flags = flags;
540
541         for (i = 0; i < surf->num_bos; i++) {
542                 bo_size = 0;
543                 for (j = 0; j < surf->info.num_planes; j++) {
544                         if (surf->planes_bo_idx[j] == i)
545                                 bo_size += surf->info.planes[j].size;
546                 }
547                 surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
548                 if (!surf->bos[i]) {
549                         for (j = 0; j < i; j++)
550                                 tbm_bo_unref(surf->bos[j]);
551
552                         free(surf);
553                         surf = NULL;
554
555                         if (LIST_IS_EMPTY(&mgr->surf_list)) {
556                                 LIST_DELINIT(&mgr->surf_list);
557                                 _deinit_surface_bufmgr();
558                         }
559
560                         _tbm_surface_mutex_unlock();
561                         return NULL;
562                 }
563                 _tbm_bo_set_surface(surf->bos[i], surf);
564
565         }
566
567         LIST_ADD(&surf->item_link, &mgr->surf_list);
568
569         _tbm_surface_mutex_unlock();
570
571         return surf;
572 }
573
574 tbm_surface_h tbm_surface_internal_create_with_bos(tbm_surface_info_s * info, tbm_bo * bos, int num)
575 {
576         TBM_RETURN_VAL_IF_FAIL(bos, NULL);
577         TBM_RETURN_VAL_IF_FAIL(info, NULL);
578         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
579
580         struct _tbm_bufmgr *mgr;
581         struct _tbm_surface *surf = NULL;
582         int i;
583
584         _tbm_surface_mutex_lock();
585
586         if (!g_surface_bufmgr) {
587                 _init_surface_bufmgr();
588                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
589         }
590
591         mgr = g_surface_bufmgr;
592         if (!TBM_BUFMGR_IS_VALID(mgr)) {
593                 _tbm_surface_mutex_unlock();
594                 return NULL;
595         }
596
597         surf = calloc(1, sizeof(struct _tbm_surface));
598         if (!surf) {
599                 _tbm_surface_mutex_unlock();
600                 return NULL;
601         }
602
603         surf->bufmgr = mgr;
604         surf->info.width = info->width;
605         surf->info.height = info->height;
606         surf->info.format = info->format;
607         surf->info.bpp = info->bpp;
608         surf->info.num_planes = info->num_planes;
609         surf->refcnt = 1;
610
611         /* get size, stride and offset */
612         for (i = 0; i < info->num_planes; i++) {
613                 surf->info.planes[i].offset = info->planes[i].offset;
614                 surf->info.planes[i].stride = info->planes[i].stride;
615
616                 if (info->planes[i].size > 0)
617                         surf->info.planes[i].size = info->planes[i].size;
618                 else
619                         surf->info.planes[i].size += surf->info.planes[i].stride * info->height;
620
621                 if (num == 1)
622                         surf->planes_bo_idx[i] = 0;
623                 else
624                         surf->planes_bo_idx[i] = i;
625         }
626
627         if (info->size > 0) {
628                 surf->info.size = info->size;
629         } else {
630                 surf->info.size = 0;
631                 for (i = 0; i < info->num_planes; i++)
632                         surf->info.size += surf->info.planes[i].size;
633         }
634
635         surf->flags = TBM_BO_DEFAULT;
636
637         /* create only one bo */
638         surf->num_bos = num;
639         for (i = 0; i < num; i++) {
640                 if (bos[i] == NULL)
641                         goto bail1;
642
643                 surf->bos[i] = tbm_bo_ref(bos[i]);
644                 _tbm_bo_set_surface(bos[i], surf);
645         }
646
647         LIST_ADD(&surf->item_link, &mgr->surf_list);
648
649         _tbm_surface_mutex_unlock();
650
651         return surf;
652  bail1:
653         for (i = 0; i < num; i++) {
654                 if (surf->bos[i]) {
655                         tbm_bo_unref(surf->bos[i]);
656                         surf->bos[i] = NULL;
657                 }
658         }
659
660         free(surf);
661         surf = NULL;
662
663         if (LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
664                 LIST_DELINIT(&g_surface_bufmgr->surf_list);
665                 _deinit_surface_bufmgr();
666         }
667
668         _tbm_surface_mutex_unlock();
669
670         return NULL;
671 }
672
673 void tbm_surface_internal_destroy(tbm_surface_h surface)
674 {
675         if (!surface)
676                 return;
677
678         _tbm_surface_mutex_lock();
679
680         surface->refcnt--;
681
682         if (surface->refcnt > 0) {
683                 _tbm_surface_mutex_unlock();
684                 return;
685         }
686
687         if (surface->refcnt == 0)
688                 _tbm_surface_internal_destroy(surface);
689
690         _tbm_surface_mutex_unlock();
691 }
692
693 void tbm_surface_internal_ref(tbm_surface_h surface)
694 {
695         TBM_RETURN_IF_FAIL(surface);
696
697         _tbm_surface_mutex_lock();
698
699         surface->refcnt++;
700
701         _tbm_surface_mutex_unlock();
702 }
703
704 void tbm_surface_internal_unref(tbm_surface_h surface)
705 {
706         TBM_RETURN_IF_FAIL(surface);
707
708         _tbm_surface_mutex_lock();
709
710         surface->refcnt--;
711
712         if (surface->refcnt > 0) {
713                 _tbm_surface_mutex_unlock();
714                 return;
715         }
716
717         if (surface->refcnt == 0)
718                 _tbm_surface_internal_destroy(surface);
719
720         _tbm_surface_mutex_unlock();
721 }
722
723 int tbm_surface_internal_get_num_bos(tbm_surface_h surface)
724 {
725         TBM_RETURN_VAL_IF_FAIL(surface, 0);
726
727         struct _tbm_surface *surf;
728         int num;
729
730         _tbm_surface_mutex_lock();
731
732         surf = (struct _tbm_surface *)surface;
733         num = surf->num_bos;
734
735         _tbm_surface_mutex_unlock();
736
737         return num;
738 }
739
740 tbm_bo tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
741 {
742         TBM_RETURN_VAL_IF_FAIL(surface, NULL);
743         TBM_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
744
745         struct _tbm_surface *surf;
746         tbm_bo bo;
747
748         _tbm_surface_mutex_lock();
749
750         surf = (struct _tbm_surface *)surface;
751         bo = surf->bos[bo_idx];
752
753         _tbm_surface_mutex_unlock();
754
755         return bo;
756 }
757
758 int tbm_surface_internal_get_size(tbm_surface_h surface)
759 {
760         TBM_RETURN_VAL_IF_FAIL(surface, 0);
761
762         struct _tbm_surface *surf;
763         unsigned int size;
764
765         _tbm_surface_mutex_lock();
766
767         surf = (struct _tbm_surface *)surface;
768         size = surf->info.size;
769
770         _tbm_surface_mutex_unlock();
771
772         return size;
773 }
774
775 int tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx, uint32_t * size, uint32_t * offset, uint32_t * pitch)
776 {
777         TBM_RETURN_VAL_IF_FAIL(surface, 0);
778         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
779
780         struct _tbm_surface *surf;
781
782         _tbm_surface_mutex_lock();
783
784         surf = (struct _tbm_surface *)surface;
785
786         if (plane_idx >= surf->info.num_planes) {
787                 _tbm_surface_mutex_unlock();
788                 return 0;
789         }
790
791         *size = surf->info.planes[plane_idx].size;
792         *offset = surf->info.planes[plane_idx].offset;
793         *pitch = surf->info.planes[plane_idx].stride;
794
795         _tbm_surface_mutex_unlock();
796
797         return 1;
798 }
799
800 int tbm_surface_internal_get_info(tbm_surface_h surface, int opt, tbm_surface_info_s * info, int map)
801 {
802         struct _tbm_surface *surf;
803         tbm_bo_handle bo_handles[4];
804         int i, j;
805
806         _tbm_surface_mutex_lock();
807
808         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
809
810         surf = (struct _tbm_surface *)surface;
811
812         info->width = surf->info.width;
813         info->height = surf->info.height;
814         info->format = surf->info.format;
815         info->bpp = surf->info.bpp;
816         info->size = surf->info.size;
817         info->num_planes = surf->info.num_planes;
818
819         if (map == 1) {
820                 for (i = 0; i < surf->num_bos; i++) {
821                         bo_handles[i] = tbm_bo_map(surf->bos[i], TBM_DEVICE_CPU, opt);
822                         if (bo_handles[i].ptr == NULL) {
823                                 for (j = 0; j < i; j++)
824                                         tbm_bo_unmap(surf->bos[j]);
825
826                                 _tbm_surface_mutex_unlock();
827                                 return 0;
828                         }
829                 }
830         } else {
831                 for (i = 0; i < surf->num_bos; i++) {
832                         bo_handles[i] = tbm_bo_get_handle(surf->bos[i], TBM_DEVICE_CPU);
833                         if (bo_handles[i].ptr == NULL) {
834                                 _tbm_surface_mutex_unlock();
835                                 return 0;
836                         }
837                 }
838         }
839
840         for (i = 0; i < surf->info.num_planes; i++) {
841                 info->planes[i].size = surf->info.planes[i].size;
842                 info->planes[i].offset = surf->info.planes[i].offset;
843                 info->planes[i].stride = surf->info.planes[i].stride;
844                 info->planes[i].ptr = bo_handles[surf->planes_bo_idx[i]].ptr + surf->info.planes[i].offset;
845         }
846
847         _tbm_surface_mutex_unlock();
848
849         return 1;
850 }
851
852 void tbm_surface_internal_unmap(tbm_surface_h surface)
853 {
854         struct _tbm_surface *surf;
855         int i;
856
857         _tbm_surface_mutex_lock();
858
859         surf = (struct _tbm_surface *)surface;
860
861         for (i = 0; i < surf->num_bos; i++)
862                 tbm_bo_unmap(surf->bos[i]);
863
864         _tbm_surface_mutex_unlock();
865 }
866
867 unsigned int tbm_surface_internal_get_width(tbm_surface_h surface)
868 {
869         struct _tbm_surface *surf;
870         unsigned int width;
871
872         _tbm_surface_mutex_lock();
873
874         surf = (struct _tbm_surface *)surface;
875         width = surf->info.width;
876
877         _tbm_surface_mutex_unlock();
878
879         return width;
880 }
881
882 unsigned int tbm_surface_internal_get_height(tbm_surface_h surface)
883 {
884         struct _tbm_surface *surf;
885         unsigned int height;
886
887         _tbm_surface_mutex_lock();
888
889         surf = (struct _tbm_surface *)surface;
890         height = surf->info.height;
891
892         _tbm_surface_mutex_unlock();
893
894         return height;
895
896 }
897
898 tbm_format tbm_surface_internal_get_format(tbm_surface_h surface)
899 {
900         struct _tbm_surface *surf;
901         tbm_format format;
902
903         _tbm_surface_mutex_lock();
904
905         surf = (struct _tbm_surface *)surface;
906         format = surf->info.format;
907
908         _tbm_surface_mutex_unlock();
909
910         return format;
911 }
912
913 int tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
914 {
915         TBM_RETURN_VAL_IF_FAIL(surface, 0);
916         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
917         struct _tbm_surface *surf;
918         int bo_idx;
919
920         _tbm_surface_mutex_lock();
921
922         surf = (struct _tbm_surface *)surface;
923         bo_idx = surf->planes_bo_idx[plane_idx];
924
925         _tbm_surface_mutex_unlock();
926
927         return bo_idx;
928 }
929
930 unsigned int _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
931 {
932         TBM_RETURN_VAL_IF_FAIL(surface, 0);
933
934         return surface->debug_pid;
935 }
936
937 void tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
938 {
939         TBM_RETURN_IF_FAIL(surface);
940
941         surface->debug_pid = pid;
942 }
943