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