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