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