Add backend interface surface_alloc_bo
[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                         }
589
590                         bo->ref_cnt = 1;
591                         bo->flags = flags;
592                         bo->priv = bo_priv;
593
594                         LIST_INITHEAD(&bo->user_data_list);
595
596                         LIST_ADD(&bo->item_link, &surf->bufmgr->bo_list);
597
598                         pthread_mutex_unlock(&surf->bufmgr->lock);
599
600                         surf->bos[i] = bo;
601
602                 } else {
603                         surf->bos[i] = tbm_bo_alloc(mgr, bo_size, flags);
604                 }
605
606                 if (!surf->bos[i]) {
607                         TBM_LOG("[libtbm:%d] "
608                                 "error %s:%d fail to alloc bo\n",
609                                 getpid(), __func__, __LINE__);
610                         goto alloc_fail;
611                 }
612
613                 _tbm_bo_set_surface(surf->bos[i], surf);
614
615         }
616
617         LIST_INITHEAD(&surf->user_data_list);
618
619         LIST_ADD(&surf->item_link, &mgr->surf_list);
620
621         _tbm_surface_mutex_unlock();
622
623         return surf;
624
625 alloc_fail:
626         for (j = 0; j < i; j++) {
627                 if (surf->bos[j])
628                         tbm_bo_unref(surf->bos[j]);
629         }
630
631         free(surf);
632         surf = NULL;
633
634         if (LIST_IS_EMPTY(&mgr->surf_list)) {
635                 LIST_DELINIT(&mgr->surf_list);
636                 _deinit_surface_bufmgr();
637         }
638
639         _tbm_surface_mutex_unlock();
640         return NULL;
641 }
642
643 tbm_surface_h
644 tbm_surface_internal_create_with_bos(tbm_surface_info_s *info,
645                                      tbm_bo *bos, int num)
646 {
647         TBM_RETURN_VAL_IF_FAIL(bos, NULL);
648         TBM_RETURN_VAL_IF_FAIL(info, NULL);
649         TBM_RETURN_VAL_IF_FAIL(num == 1 || info->num_planes == num, NULL);
650
651         struct _tbm_bufmgr *mgr;
652         struct _tbm_surface *surf = NULL;
653         int i;
654
655         _tbm_surface_mutex_lock();
656
657         if (!g_surface_bufmgr) {
658                 _init_surface_bufmgr();
659                 LIST_INITHEAD(&g_surface_bufmgr->surf_list);
660         }
661
662         mgr = g_surface_bufmgr;
663         if (!TBM_BUFMGR_IS_VALID(mgr)) {
664                 _tbm_surface_mutex_unlock();
665                 return NULL;
666         }
667
668         surf = calloc(1, sizeof(struct _tbm_surface));
669         if (!surf) {
670                 _tbm_surface_mutex_unlock();
671                 return NULL;
672         }
673
674         surf->bufmgr = mgr;
675         surf->info.width = info->width;
676         surf->info.height = info->height;
677         surf->info.format = info->format;
678         surf->info.bpp = info->bpp;
679         surf->info.num_planes = info->num_planes;
680         surf->refcnt = 1;
681
682         /* get size, stride and offset */
683         for (i = 0; i < info->num_planes; i++) {
684                 surf->info.planes[i].offset = info->planes[i].offset;
685                 surf->info.planes[i].stride = info->planes[i].stride;
686
687                 if (info->planes[i].size > 0)
688                         surf->info.planes[i].size = info->planes[i].size;
689                 else
690                         surf->info.planes[i].size += surf->info.planes[i].stride * info->height;
691
692                 if (num == 1)
693                         surf->planes_bo_idx[i] = 0;
694                 else
695                         surf->planes_bo_idx[i] = i;
696         }
697
698         if (info->size > 0) {
699                 surf->info.size = info->size;
700         } else {
701                 surf->info.size = 0;
702                 for (i = 0; i < info->num_planes; i++)
703                         surf->info.size += surf->info.planes[i].size;
704         }
705
706         surf->flags = TBM_BO_DEFAULT;
707
708         /* create only one bo */
709         surf->num_bos = num;
710         for (i = 0; i < num; i++) {
711                 if (bos[i] == NULL)
712                         goto bail1;
713
714                 surf->bos[i] = tbm_bo_ref(bos[i]);
715                 _tbm_bo_set_surface(bos[i], surf);
716         }
717
718         LIST_INITHEAD(&surf->user_data_list);
719
720         LIST_ADD(&surf->item_link, &mgr->surf_list);
721
722         _tbm_surface_mutex_unlock();
723
724         return surf;
725 bail1:
726         for (i = 0; i < num; i++) {
727                 if (surf->bos[i]) {
728                         tbm_bo_unref(surf->bos[i]);
729                         surf->bos[i] = NULL;
730                 }
731         }
732
733         free(surf);
734         surf = NULL;
735
736         if (LIST_IS_EMPTY(&g_surface_bufmgr->surf_list)) {
737                 LIST_DELINIT(&g_surface_bufmgr->surf_list);
738                 _deinit_surface_bufmgr();
739         }
740
741         _tbm_surface_mutex_unlock();
742
743         return NULL;
744 }
745
746 void
747 tbm_surface_internal_destroy(tbm_surface_h surface)
748 {
749         if (!_tbm_surface_is_valid(surface))
750                 return;
751
752         _tbm_surface_mutex_lock();
753
754         surface->refcnt--;
755
756         if (surface->refcnt > 0) {
757                 _tbm_surface_mutex_unlock();
758                 return;
759         }
760
761         if (surface->refcnt == 0)
762                 _tbm_surface_internal_destroy(surface);
763
764         _tbm_surface_mutex_unlock();
765 }
766
767 void
768 tbm_surface_internal_ref(tbm_surface_h surface)
769 {
770         TBM_RETURN_IF_FAIL(_tbm_surface_is_valid(surface));
771
772         _tbm_surface_mutex_lock();
773
774         surface->refcnt++;
775
776         _tbm_surface_mutex_unlock();
777 }
778
779 void
780 tbm_surface_internal_unref(tbm_surface_h surface)
781 {
782         TBM_RETURN_IF_FAIL(_tbm_surface_is_valid(surface));
783
784         _tbm_surface_mutex_lock();
785
786         surface->refcnt--;
787
788         if (surface->refcnt > 0) {
789                 _tbm_surface_mutex_unlock();
790                 return;
791         }
792
793         if (surface->refcnt == 0)
794                 _tbm_surface_internal_destroy(surface);
795
796         _tbm_surface_mutex_unlock();
797 }
798
799 int
800 tbm_surface_internal_get_num_bos(tbm_surface_h surface)
801 {
802         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
803
804         struct _tbm_surface *surf;
805         int num;
806
807         _tbm_surface_mutex_lock();
808
809         surf = (struct _tbm_surface *)surface;
810         num = surf->num_bos;
811
812         _tbm_surface_mutex_unlock();
813
814         return num;
815 }
816
817 tbm_bo
818 tbm_surface_internal_get_bo(tbm_surface_h surface, int bo_idx)
819 {
820         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), NULL);
821         TBM_RETURN_VAL_IF_FAIL(bo_idx > -1, NULL);
822
823         struct _tbm_surface *surf;
824         tbm_bo bo;
825
826         _tbm_surface_mutex_lock();
827
828         surf = (struct _tbm_surface *)surface;
829         bo = surf->bos[bo_idx];
830
831         _tbm_surface_mutex_unlock();
832
833         return bo;
834 }
835
836 int
837 tbm_surface_internal_get_size(tbm_surface_h surface)
838 {
839         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
840
841         struct _tbm_surface *surf;
842         unsigned int size;
843
844         _tbm_surface_mutex_lock();
845
846         surf = (struct _tbm_surface *)surface;
847         size = surf->info.size;
848
849         _tbm_surface_mutex_unlock();
850
851         return size;
852 }
853
854 int
855 tbm_surface_internal_get_plane_data(tbm_surface_h surface, int plane_idx,
856                                     uint32_t *size, uint32_t *offset, uint32_t *pitch)
857 {
858         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
859         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
860
861         struct _tbm_surface *surf;
862
863         _tbm_surface_mutex_lock();
864
865         surf = (struct _tbm_surface *)surface;
866
867         if (plane_idx >= surf->info.num_planes) {
868                 _tbm_surface_mutex_unlock();
869                 return 0;
870         }
871
872         if (size)
873                 *size = surf->info.planes[plane_idx].size;
874
875         if (offset)
876                 *offset = surf->info.planes[plane_idx].offset;
877
878         if (pitch)
879                 *pitch = surf->info.planes[plane_idx].stride;
880
881         _tbm_surface_mutex_unlock();
882
883         return 1;
884 }
885
886 int
887 tbm_surface_internal_get_info(tbm_surface_h surface, int opt,
888                               tbm_surface_info_s *info, int map)
889 {
890         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
891
892         struct _tbm_surface *surf;
893         tbm_bo_handle bo_handles[4];
894         int i, j;
895
896         _tbm_surface_mutex_lock();
897
898         memset(bo_handles, 0, sizeof(tbm_bo_handle) * 4);
899
900         surf = (struct _tbm_surface *)surface;
901
902         memset(info, 0x00, sizeof(tbm_surface_info_s));
903         info->width = surf->info.width;
904         info->height = surf->info.height;
905         info->format = surf->info.format;
906         info->bpp = surf->info.bpp;
907         info->size = surf->info.size;
908         info->num_planes = surf->info.num_planes;
909
910         if (map == 1) {
911                 for (i = 0; i < surf->num_bos; i++) {
912                         bo_handles[i] = tbm_bo_map(surf->bos[i], TBM_DEVICE_CPU, opt);
913                         if (bo_handles[i].ptr == NULL) {
914                                 for (j = 0; j < i; j++)
915                                         tbm_bo_unmap(surf->bos[j]);
916
917                                 _tbm_surface_mutex_unlock();
918                                 return 0;
919                         }
920                 }
921         } else {
922                 for (i = 0; i < surf->num_bos; i++)
923                         bo_handles[i] = tbm_bo_get_handle(surf->bos[i], TBM_DEVICE_CPU);
924         }
925
926         for (i = 0; i < surf->info.num_planes; i++) {
927                 info->planes[i].size = surf->info.planes[i].size;
928                 info->planes[i].offset = surf->info.planes[i].offset;
929                 info->planes[i].stride = surf->info.planes[i].stride;
930
931                 if (bo_handles[surf->planes_bo_idx[i]].ptr)
932                         info->planes[i].ptr = bo_handles[surf->planes_bo_idx[i]].ptr +
933                                               surf->info.planes[i].offset;
934         }
935
936         _tbm_surface_mutex_unlock();
937
938         return 1;
939 }
940
941 void
942 tbm_surface_internal_unmap(tbm_surface_h surface)
943 {
944         TBM_RETURN_IF_FAIL(_tbm_surface_is_valid(surface));
945
946         struct _tbm_surface *surf;
947         int i;
948
949         _tbm_surface_mutex_lock();
950
951         surf = (struct _tbm_surface *)surface;
952
953         for (i = 0; i < surf->num_bos; i++)
954                 tbm_bo_unmap(surf->bos[i]);
955
956         _tbm_surface_mutex_unlock();
957 }
958
959 unsigned int
960 tbm_surface_internal_get_width(tbm_surface_h surface)
961 {
962         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
963
964         struct _tbm_surface *surf;
965         unsigned int width;
966
967         _tbm_surface_mutex_lock();
968
969         surf = (struct _tbm_surface *)surface;
970         width = surf->info.width;
971
972         _tbm_surface_mutex_unlock();
973
974         return width;
975 }
976
977 unsigned int
978 tbm_surface_internal_get_height(tbm_surface_h surface)
979 {
980         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
981
982         struct _tbm_surface *surf;
983         unsigned int height;
984
985         _tbm_surface_mutex_lock();
986
987         surf = (struct _tbm_surface *)surface;
988         height = surf->info.height;
989
990         _tbm_surface_mutex_unlock();
991
992         return height;
993
994 }
995
996 tbm_format
997 tbm_surface_internal_get_format(tbm_surface_h surface)
998 {
999         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1000
1001         struct _tbm_surface *surf;
1002         tbm_format format;
1003
1004         _tbm_surface_mutex_lock();
1005
1006         surf = (struct _tbm_surface *)surface;
1007         format = surf->info.format;
1008
1009         _tbm_surface_mutex_unlock();
1010
1011         return format;
1012 }
1013
1014 int
1015 tbm_surface_internal_get_plane_bo_idx(tbm_surface_h surface, int plane_idx)
1016 {
1017         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1018         TBM_RETURN_VAL_IF_FAIL(plane_idx > -1, 0);
1019         struct _tbm_surface *surf;
1020         int bo_idx;
1021
1022         _tbm_surface_mutex_lock();
1023
1024         surf = (struct _tbm_surface *)surface;
1025         bo_idx = surf->planes_bo_idx[plane_idx];
1026
1027         _tbm_surface_mutex_unlock();
1028
1029         return bo_idx;
1030 }
1031
1032 unsigned int
1033 _tbm_surface_internal_get_debug_pid(tbm_surface_h surface)
1034 {
1035         TBM_RETURN_VAL_IF_FAIL(surface, 0);
1036
1037         return surface->debug_pid;
1038 }
1039
1040 void
1041 tbm_surface_internal_set_debug_pid(tbm_surface_h surface, unsigned int pid)
1042 {
1043         TBM_RETURN_IF_FAIL(_tbm_surface_is_valid(surface));
1044
1045         surface->debug_pid = pid;
1046 }
1047
1048 int
1049 tbm_surface_internal_add_user_data(tbm_surface_h surface, unsigned long key,
1050                                    tbm_data_free data_free_func)
1051 {
1052         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1053
1054         tbm_user_data *data;
1055
1056         /* check if the data according to the key exist if so, return false. */
1057         data = user_data_lookup(&surface->user_data_list, key);
1058         if (data) {
1059                 TBM_LOG("[libtbm:%d] "
1060                         "waring: %s:%d user data already exist. key:%ld\n",
1061                         getpid(), __func__, __LINE__, key);
1062                 return 0;
1063         }
1064
1065         data = user_data_create(key, data_free_func);
1066         if (!data)
1067                 return 0;
1068
1069         LIST_ADD(&data->item_link, &surface->user_data_list);
1070
1071         return 1;
1072 }
1073
1074 int
1075 tbm_surface_internal_set_user_data(tbm_surface_h surface, unsigned long key,
1076                                    void *data)
1077 {
1078         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1079
1080         tbm_user_data *old_data;
1081
1082         if (LIST_IS_EMPTY(&surface->user_data_list))
1083                 return 0;
1084
1085         old_data = user_data_lookup(&surface->user_data_list, key);
1086         if (!old_data)
1087                 return 0;
1088
1089         if (old_data->data && old_data->free_func)
1090                 old_data->free_func(old_data->data);
1091
1092         old_data->data = data;
1093
1094         return 1;
1095 }
1096
1097 int
1098 tbm_surface_internal_get_user_data(tbm_surface_h surface, unsigned long key,
1099                                    void **data)
1100 {
1101         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1102
1103         tbm_user_data *old_data;
1104
1105         if (!data || LIST_IS_EMPTY(&surface->user_data_list))
1106                 return 0;
1107
1108         old_data = user_data_lookup(&surface->user_data_list, key);
1109         if (!old_data) {
1110                 *data = NULL;
1111                 return 0;
1112         }
1113
1114         *data = old_data->data;
1115
1116         return 1;
1117 }
1118
1119 int
1120 tbm_surface_internal_delete_user_data(tbm_surface_h surface,
1121                                       unsigned long key)
1122 {
1123         TBM_RETURN_VAL_IF_FAIL(_tbm_surface_is_valid(surface), 0);
1124
1125         tbm_user_data *old_data = (void *)0;
1126
1127         if (LIST_IS_EMPTY(&surface->user_data_list))
1128                 return 0;
1129
1130         old_data = user_data_lookup(&surface->user_data_list, key);
1131         if (!old_data)
1132                 return 0;
1133
1134         user_data_delete(old_data);
1135
1136         return 1;
1137 }
1138