enforce the thread safety of the tbm_surface_queue
[platform/core/uifw/libtbm.git] / src / tbm_surface_queue.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 "tbm_bufmgr_int.h"
33 #include "list.h"
34
35 #define FREE_QUEUE      1
36 #define DIRTY_QUEUE     2
37 #define NODE_LIST       4
38
39 #define TBM_QUEUE_DEBUG 0
40
41 #ifdef TRACE
42 #define TBM_QUEUE_TRACE(fmt, ...)  { if (bTrace&0x1) fprintf(stderr, "[TBM:TRACE(%d)(%s:%d)] " fmt, getpid(), __func__, __LINE__, ##__VA_ARGS__); }
43 #else
44 #define TBM_QUEUE_TRACE(fmt, ...)
45 #endif /* TRACE */
46
47 #if TBM_QUEUE_DEBUG
48 #define TBM_LOCK() TBM_LOG_D("[LOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
49 #define TBM_UNLOCK() TBM_LOG_D("[UNLOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
50 #else
51 #define TBM_LOCK()
52 #define TBM_UNLOCK()
53 #endif
54
55 static tbm_bufmgr g_surf_queue_bufmgr;
56 static pthread_mutex_t tbm_surf_queue_lock;
57 void _tbm_surface_queue_mutex_unlock(void);
58
59 /* check condition */
60 #define TBM_SURF_QUEUE_RETURN_IF_FAIL(cond) {\
61         if (!(cond)) {\
62                 TBM_LOG_E("'%s' failed.\n", #cond);\
63                 _tbm_surf_queue_mutex_unlock();\
64                 return;\
65         } \
66 }
67
68 #define TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(cond, val) {\
69         if (!(cond)) {\
70                 TBM_LOG_E("'%s' failed.\n", #cond);\
71                 _tbm_surf_queue_mutex_unlock();\
72                 return val;\
73         } \
74 }
75
76 typedef enum _queue_node_type {
77         QUEUE_NODE_TYPE_NONE,
78         QUEUE_NODE_TYPE_DEQUEUE,
79         QUEUE_NODE_TYPE_ENQUEUE,
80         QUEUE_NODE_TYPE_ACQUIRE,
81         QUEUE_NODE_TYPE_RELEASE
82 } Queue_Node_Type;
83
84 typedef struct {
85         struct list_head head;
86         int count;
87 } queue;
88
89 typedef struct {
90         tbm_surface_h surface;
91
92         struct list_head item_link;
93         struct list_head link;
94
95         Queue_Node_Type type;
96
97         unsigned int priv_flags;        /*for each queue*/
98 } queue_node;
99
100 typedef struct {
101         struct list_head link;
102
103         tbm_surface_queue_notify_cb cb;
104         void *data;
105 } queue_notify;
106
107 typedef struct _tbm_surface_queue_interface {
108         void (*init)(tbm_surface_queue_h queue);
109         void (*reset)(tbm_surface_queue_h queue);
110         void (*destroy)(tbm_surface_queue_h queue);
111         void (*need_attach)(tbm_surface_queue_h queue);
112
113         void (*enqueue)(tbm_surface_queue_h queue, queue_node *node);
114         void (*release)(tbm_surface_queue_h queue, queue_node *node);
115         queue_node *(*dequeue)(tbm_surface_queue_h queue);
116         queue_node *(*acquire)(tbm_surface_queue_h queue);
117 } tbm_surface_queue_interface;
118
119 struct _tbm_surface_queue {
120         int width;
121         int height;
122         int format;
123         int queue_size;
124
125         queue free_queue;
126         queue dirty_queue;
127         struct list_head list;
128
129         struct list_head destory_noti;
130         struct list_head dequeuable_noti;
131         struct list_head dequeue_noti;
132         struct list_head acquirable_noti;
133         struct list_head reset_noti;
134
135         pthread_mutex_t lock;
136         pthread_cond_t free_cond;
137         pthread_cond_t dirty_cond;
138
139         const tbm_surface_queue_interface *impl;
140         void *impl_data;
141
142         //For external buffer allocation
143         tbm_surface_alloc_cb alloc_cb;
144         tbm_surface_free_cb free_cb;
145         void *alloc_cb_data;
146
147         struct list_head item_link; /* link of surface queue */
148 };
149
150 /* LCOV_EXCL_START */
151
152 static bool
153 _tbm_surf_queue_mutex_init(void)
154 {
155         static bool tbm_surf_queue_mutex_init = false;
156
157         if (tbm_surf_queue_mutex_init)
158                 return true;
159
160         if (pthread_mutex_init(&tbm_surf_queue_lock, NULL)) {
161                 TBM_LOG_E("fail: tbm_surf_queue mutex init\n");
162                 return false;
163         }
164
165         tbm_surf_queue_mutex_init = true;
166
167         return true;
168 }
169
170 void
171 _tbm_surf_queue_mutex_lock(void)
172 {
173         if (!_tbm_surf_queue_mutex_init())
174                 return;
175
176         pthread_mutex_lock(&tbm_surf_queue_lock);
177 }
178
179 void
180 _tbm_surf_queue_mutex_unlock(void)
181 {
182         pthread_mutex_unlock(&tbm_surf_queue_lock);
183 }
184
185 static void
186 _init_tbm_surf_queue_bufmgr(void)
187 {
188         g_surf_queue_bufmgr = tbm_bufmgr_init(-1);
189 }
190
191 static void
192 _deinit_tbm_surf_queue_bufmgr(void)
193 {
194         if (!g_surf_queue_bufmgr)
195                 return;
196
197         tbm_bufmgr_deinit(g_surf_queue_bufmgr);
198         g_surf_queue_bufmgr = NULL;
199 }
200
201 static int
202 _tbm_surface_queue_is_valid(tbm_surface_queue_h surface_queue)
203 {
204         tbm_surface_queue_h old_data = NULL, tmp = NULL;
205
206         if (surface_queue == NULL || g_surf_queue_bufmgr == NULL) {
207                 TBM_TRACE("error: tbm_surface_queue(%p)\n", surface_queue);
208                 return 0;
209         }
210
211         if (!LIST_IS_EMPTY(&g_surf_queue_bufmgr->surf_queue_list)) {
212                 LIST_FOR_EACH_ENTRY_SAFE(old_data, tmp, &g_surf_queue_bufmgr->surf_queue_list, item_link) {
213                         if (old_data == surface_queue) {
214                                 TBM_TRACE("tbm_surface_queue(%p)\n", surface_queue);
215                                 return 1;
216                         }
217                 }
218         }
219         TBM_TRACE("error: tbm_surface_queue(%p)\n", surface_queue);
220         return 0;
221 }
222
223 static queue_node *
224 _queue_node_create(void)
225 {
226         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
227
228         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
229
230         return node;
231 }
232
233 static void
234 _queue_node_delete(queue_node *node)
235 {
236         LIST_DEL(&node->item_link);
237         LIST_DEL(&node->link);
238         free(node);
239 }
240
241 static int
242 _queue_is_empty(queue *queue)
243 {
244         if (LIST_IS_EMPTY(&queue->head))
245                 return 1;
246
247         return 0;
248 }
249
250 static void
251 _queue_node_push_back(queue *queue, queue_node *node)
252 {
253         LIST_ADDTAIL(&node->item_link, &queue->head);
254         queue->count++;
255 }
256
257 static void
258 _queue_node_push_front(queue *queue, queue_node *node)
259 {
260         LIST_ADD(&node->item_link, &queue->head);
261         queue->count++;
262 }
263
264 static queue_node *
265 _queue_node_pop_front(queue *queue)
266 {
267         queue_node *node = NULL;
268
269         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
270
271         LIST_DEL(&node->item_link);
272         queue->count--;
273
274         return node;
275 }
276
277 static queue_node *
278 _queue_node_pop(queue *queue, queue_node *node)
279 {
280         LIST_DEL(&node->item_link);
281         queue->count--;
282
283         return node;
284 }
285
286 static queue_node *
287 _queue_get_node(tbm_surface_queue_h surface_queue, int type,
288                 tbm_surface_h surface, int *out_type)
289 {
290         queue_node *node = NULL;
291         queue_node *tmp = NULL;
292
293         if (type == 0)
294                 type = FREE_QUEUE | DIRTY_QUEUE | NODE_LIST;
295         if (out_type)
296                 *out_type = 0;
297
298         if (type & FREE_QUEUE) {
299                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head,
300                                          item_link) {
301                         if (node->surface == surface) {
302                                 if (out_type)
303                                         *out_type = FREE_QUEUE;
304
305                                 return node;
306                         }
307                 }
308         }
309
310         if (type & DIRTY_QUEUE) {
311                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head,
312                                          item_link) {
313                         if (node->surface == surface) {
314                                 if (out_type)
315                                         *out_type = DIRTY_QUEUE;
316
317                                 return node;
318                         }
319                 }
320         }
321
322         if (type & NODE_LIST) {
323                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
324                         if (node->surface == surface) {
325                                 if (out_type)
326                                         *out_type = NODE_LIST;
327
328                                 return node;
329                         }
330                 }
331         }
332
333         return NULL;
334 }
335
336 static void
337 _queue_delete_node(tbm_surface_queue_h surface_queue, queue_node *node)
338 {
339         if (node->surface) {
340                 if (surface_queue->free_cb) {
341                         surface_queue->free_cb(surface_queue,
342                                         surface_queue->alloc_cb_data,
343                                         node->surface);
344                 }
345
346                 tbm_surface_destroy(node->surface);
347         }
348
349         _queue_node_delete(node);
350 }
351
352 static void
353 _queue_init(queue *queue)
354 {
355         LIST_INITHEAD(&queue->head);
356
357         queue->count = 0;
358 }
359
360 static void
361 _notify_add(struct list_head *list, tbm_surface_queue_notify_cb cb,
362             void *data)
363 {
364         TBM_RETURN_IF_FAIL(cb != NULL);
365
366         queue_notify *item = (queue_notify *)calloc(1, sizeof(queue_notify));
367
368         TBM_RETURN_IF_FAIL(item != NULL);
369
370         LIST_INITHEAD(&item->link);
371         item->cb = cb;
372         item->data = data;
373
374         LIST_ADDTAIL(&item->link, list);
375 }
376
377 static void
378 _notify_remove(struct list_head *list,
379                tbm_surface_queue_notify_cb cb, void *data)
380 {
381         queue_notify *item = NULL, *tmp = NULL;
382
383         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
384                 if (item->cb == cb && item->data == data) {
385                         LIST_DEL(&item->link);
386                         free(item);
387                         return;
388                 }
389         }
390
391         TBM_LOG_E("Cannot find notifiy\n");
392 }
393
394 static void
395 _notify_remove_all(struct list_head *list)
396 {
397         queue_notify *item = NULL, *tmp = NULL;
398
399         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
400                 LIST_DEL(&item->link);
401                 free(item);
402         }
403 }
404
405 static void
406 _notify_emit(tbm_surface_queue_h surface_queue,
407              struct list_head *list)
408 {
409         queue_notify *item = NULL, *tmp = NULL;
410
411         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
412                 item->cb(surface_queue, item->data);
413         }
414 }
415
416 static int
417 _tbm_surface_queue_get_node_count(tbm_surface_queue_h surface_queue, Queue_Node_Type type)
418 {
419         queue_node *node = NULL;
420         queue_node *tmp = NULL;
421         int count = 0;
422
423         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
424                 if (node->type == type)
425                         count++;
426         }
427
428         return count;
429 }
430
431 void
432 _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue,
433                           tbm_surface_h surface)
434 {
435         queue_node *node = NULL;
436
437         node = _queue_node_create();
438         TBM_RETURN_IF_FAIL(node != NULL);
439
440         tbm_surface_internal_ref(surface);
441         node->surface = surface;
442
443         LIST_ADDTAIL(&node->link, &surface_queue->list);
444         _queue_node_push_back(&surface_queue->free_queue, node);
445 }
446
447 void
448 _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue,
449                           tbm_surface_h surface)
450 {
451         queue_node *node = NULL;
452         int queue_type;
453
454         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
455         if (node)
456                 _queue_delete_node(surface_queue, node);
457 }
458
459 void
460 _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue,
461                            queue_node *node, int push_back)
462 {
463         if (push_back)
464                 _queue_node_push_back(&surface_queue->dirty_queue, node);
465         else
466                 _queue_node_push_front(&surface_queue->dirty_queue, node);
467 }
468
469 queue_node *
470 _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
471 {
472         queue_node *node = NULL;
473
474         if (_queue_is_empty(&surface_queue->free_queue)) {
475                 if (surface_queue->impl && surface_queue->impl->need_attach)
476                         surface_queue->impl->need_attach(surface_queue);
477
478                 if (_queue_is_empty(&surface_queue->free_queue))
479                         return NULL;
480         }
481
482         node = _queue_node_pop_front(&surface_queue->free_queue);
483
484         return node;
485 }
486
487 queue_node *
488 _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
489 {
490         queue_node *node = NULL;
491
492         if (_queue_is_empty(&surface_queue->dirty_queue))
493                 return NULL;
494
495         node = _queue_node_pop_front(&surface_queue->dirty_queue);
496
497         return node;
498 }
499
500 void
501 _tbm_surface_queue_release(tbm_surface_queue_h surface_queue,
502                            queue_node *node, int push_back)
503 {
504         if (push_back)
505                 _queue_node_push_back(&surface_queue->free_queue, node);
506         else
507                 _queue_node_push_front(&surface_queue->free_queue, node);
508 }
509
510 void
511 _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
512                         int queue_size,
513                         int width, int height, int format,
514                         const tbm_surface_queue_interface *impl, void *data)
515 {
516         TBM_RETURN_IF_FAIL(surface_queue != NULL);
517         TBM_RETURN_IF_FAIL(impl != NULL);
518
519         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
520
521         if (!g_surf_queue_bufmgr)
522                 _init_tbm_surf_queue_bufmgr();
523
524         pthread_mutex_init(&surface_queue->lock, NULL);
525         pthread_cond_init(&surface_queue->free_cond, NULL);
526         pthread_cond_init(&surface_queue->dirty_cond, NULL);
527
528         surface_queue->queue_size = queue_size;
529         surface_queue->width = width;
530         surface_queue->height = height;
531         surface_queue->format = format;
532         surface_queue->impl = impl;
533         surface_queue->impl_data = data;
534
535         _queue_init(&surface_queue->free_queue);
536         _queue_init(&surface_queue->dirty_queue);
537         LIST_INITHEAD(&surface_queue->list);
538
539         LIST_INITHEAD(&surface_queue->destory_noti);
540         LIST_INITHEAD(&surface_queue->acquirable_noti);
541         LIST_INITHEAD(&surface_queue->dequeuable_noti);
542         LIST_INITHEAD(&surface_queue->dequeue_noti);
543         LIST_INITHEAD(&surface_queue->reset_noti);
544
545         if (surface_queue->impl && surface_queue->impl->init)
546                 surface_queue->impl->init(surface_queue);
547
548         LIST_ADD(&surface_queue->item_link, &g_surf_queue_bufmgr->surf_queue_list);
549 }
550
551 tbm_surface_queue_error_e
552 tbm_surface_queue_add_destroy_cb(
553         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
554         void *data)
555 {
556         _tbm_surf_queue_mutex_lock();
557
558         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
559                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
560
561         pthread_mutex_lock(&surface_queue->lock);
562
563         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
564
565         _notify_add(&surface_queue->destory_noti, destroy_cb, data);
566
567         pthread_mutex_unlock(&surface_queue->lock);
568
569         _tbm_surf_queue_mutex_unlock();
570
571         return TBM_SURFACE_QUEUE_ERROR_NONE;
572 }
573
574 tbm_surface_queue_error_e
575 tbm_surface_queue_remove_destroy_cb(
576         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
577         void *data)
578 {
579         _tbm_surf_queue_mutex_lock();
580
581         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
582                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
583
584         pthread_mutex_lock(&surface_queue->lock);
585
586         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
587
588         _notify_remove(&surface_queue->destory_noti, destroy_cb, data);
589
590         pthread_mutex_unlock(&surface_queue->lock);
591
592         _tbm_surf_queue_mutex_unlock();
593
594         return TBM_SURFACE_QUEUE_ERROR_NONE;
595 }
596
597 tbm_surface_queue_error_e
598 tbm_surface_queue_add_dequeuable_cb(
599         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
600         void *data)
601 {
602         _tbm_surf_queue_mutex_lock();
603
604         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
605                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
606
607         pthread_mutex_lock(&surface_queue->lock);
608
609         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
610
611         _notify_add(&surface_queue->dequeuable_noti, dequeuable_cb, data);
612
613         pthread_mutex_unlock(&surface_queue->lock);
614
615         _tbm_surf_queue_mutex_unlock();
616
617         return TBM_SURFACE_QUEUE_ERROR_NONE;
618 }
619
620 tbm_surface_queue_error_e
621 tbm_surface_queue_remove_dequeuable_cb(
622         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
623         void *data)
624 {
625         _tbm_surf_queue_mutex_lock();
626
627         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
628                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
629
630         pthread_mutex_lock(&surface_queue->lock);
631
632         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
633
634         _notify_remove(&surface_queue->dequeuable_noti, dequeuable_cb, data);
635
636         pthread_mutex_unlock(&surface_queue->lock);
637
638         _tbm_surf_queue_mutex_unlock();
639
640         return TBM_SURFACE_QUEUE_ERROR_NONE;
641 }
642
643 tbm_surface_queue_error_e
644 tbm_surface_queue_add_dequeue_cb(
645         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeue_cb,
646         void *data)
647 {
648         _tbm_surf_queue_mutex_lock();
649
650         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
651                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
652
653         pthread_mutex_lock(&surface_queue->lock);
654
655         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
656
657         _notify_add(&surface_queue->dequeue_noti, dequeue_cb, data);
658
659         pthread_mutex_unlock(&surface_queue->lock);
660
661         _tbm_surf_queue_mutex_unlock();
662
663         return TBM_SURFACE_QUEUE_ERROR_NONE;
664 }
665
666 tbm_surface_queue_error_e
667 tbm_surface_queue_remove_dequeue_cb(
668         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeue_cb,
669         void *data)
670 {
671         _tbm_surf_queue_mutex_lock();
672
673         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
674                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
675
676         pthread_mutex_lock(&surface_queue->lock);
677
678         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
679
680         _notify_remove(&surface_queue->dequeue_noti, dequeue_cb, data);
681
682         pthread_mutex_unlock(&surface_queue->lock);
683
684         _tbm_surf_queue_mutex_unlock();
685
686         return TBM_SURFACE_QUEUE_ERROR_NONE;
687 }
688
689 tbm_surface_queue_error_e
690 tbm_surface_queue_add_acquirable_cb(
691         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
692         void *data)
693 {
694         _tbm_surf_queue_mutex_lock();
695
696         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
697                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
698
699         pthread_mutex_lock(&surface_queue->lock);
700
701         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
702
703         _notify_add(&surface_queue->acquirable_noti, acquirable_cb, data);
704
705         pthread_mutex_unlock(&surface_queue->lock);
706
707         _tbm_surf_queue_mutex_unlock();
708
709         return TBM_SURFACE_QUEUE_ERROR_NONE;
710 }
711
712 tbm_surface_queue_error_e
713 tbm_surface_queue_remove_acquirable_cb(
714         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
715         void *data)
716 {
717         _tbm_surf_queue_mutex_lock();
718
719         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
720                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
721
722         pthread_mutex_lock(&surface_queue->lock);
723
724         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
725
726         _notify_remove(&surface_queue->acquirable_noti, acquirable_cb, data);
727
728         pthread_mutex_unlock(&surface_queue->lock);
729
730         _tbm_surf_queue_mutex_unlock();
731
732         return TBM_SURFACE_QUEUE_ERROR_NONE;
733 }
734
735 tbm_surface_queue_error_e
736 tbm_surface_queue_set_alloc_cb(
737         tbm_surface_queue_h surface_queue,
738         tbm_surface_alloc_cb alloc_cb,
739         tbm_surface_free_cb free_cb,
740         void *data)
741 {
742         _tbm_surf_queue_mutex_lock();
743
744         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
745                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
746
747         pthread_mutex_lock(&surface_queue->lock);
748
749         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
750
751         surface_queue->alloc_cb = alloc_cb;
752         surface_queue->free_cb = free_cb;
753         surface_queue->alloc_cb_data = data;
754
755         pthread_mutex_unlock(&surface_queue->lock);
756
757         _tbm_surf_queue_mutex_unlock();
758
759         return TBM_SURFACE_QUEUE_ERROR_NONE;
760 }
761
762 int
763 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
764 {
765         int width;
766
767         _tbm_surf_queue_mutex_lock();
768
769         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
770
771         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
772
773         width = surface_queue->width;
774
775         _tbm_surf_queue_mutex_unlock();
776
777         return width;
778 }
779
780 int
781 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
782 {
783         int height;
784
785         _tbm_surf_queue_mutex_lock();
786
787         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
788
789         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
790
791         height = surface_queue->height;
792
793         _tbm_surf_queue_mutex_unlock();
794
795         return height;
796 }
797
798 int
799 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
800 {
801         int format;
802
803         _tbm_surf_queue_mutex_lock();
804
805         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
806
807         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
808
809         format = surface_queue->format;
810
811         _tbm_surf_queue_mutex_unlock();
812
813         return format;
814 }
815
816 int
817 tbm_surface_queue_get_size(tbm_surface_queue_h surface_queue)
818 {
819         int queue_size;
820
821         _tbm_surf_queue_mutex_lock();
822
823         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
824
825         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
826
827         queue_size = surface_queue->queue_size;
828
829         _tbm_surf_queue_mutex_unlock();
830
831         return queue_size;
832 }
833
834 tbm_surface_queue_error_e
835 tbm_surface_queue_add_reset_cb(
836         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
837         void *data)
838 {
839         _tbm_surf_queue_mutex_lock();
840
841         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
842                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
843
844         pthread_mutex_lock(&surface_queue->lock);
845
846         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
847
848         _notify_add(&surface_queue->reset_noti, reset_cb, data);
849
850         pthread_mutex_unlock(&surface_queue->lock);
851
852         _tbm_surf_queue_mutex_unlock();
853
854         return TBM_SURFACE_QUEUE_ERROR_NONE;
855 }
856
857 tbm_surface_queue_error_e
858 tbm_surface_queue_remove_reset_cb(
859         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
860         void *data)
861 {
862         _tbm_surf_queue_mutex_lock();
863
864         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
865                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
866
867         pthread_mutex_lock(&surface_queue->lock);
868
869         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
870
871         _notify_remove(&surface_queue->reset_noti, reset_cb, data);
872
873         pthread_mutex_unlock(&surface_queue->lock);
874
875         _tbm_surf_queue_mutex_unlock();
876
877         return TBM_SURFACE_QUEUE_ERROR_NONE;
878 }
879
880 tbm_surface_queue_error_e
881 tbm_surface_queue_enqueue(tbm_surface_queue_h
882                           surface_queue, tbm_surface_h surface)
883 {
884         queue_node *node = NULL;
885         int queue_type;
886
887         _tbm_surf_queue_mutex_lock();
888
889         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
890                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
891         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
892                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
893
894         if (b_dump_queue)
895                 tbm_surface_internal_dump_buffer(surface, "enqueue");
896
897         pthread_mutex_lock(&surface_queue->lock);
898
899         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
900
901         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
902         if (node == NULL || queue_type != NODE_LIST) {
903                 TBM_LOG_E("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
904                         node, queue_type);
905                 pthread_mutex_unlock(&surface_queue->lock);
906
907                 _tbm_surf_queue_mutex_unlock();
908                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
909         }
910
911         if (surface_queue->impl && surface_queue->impl->enqueue)
912                 surface_queue->impl->enqueue(surface_queue, node);
913         else
914                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
915
916         if (_queue_is_empty(&surface_queue->dirty_queue)) {
917                 pthread_mutex_unlock(&surface_queue->lock);
918
919                 _tbm_surf_queue_mutex_unlock();
920                 return TBM_SURFACE_QUEUE_ERROR_NONE;
921         }
922
923         node->type = QUEUE_NODE_TYPE_ENQUEUE;
924
925         pthread_mutex_unlock(&surface_queue->lock);
926         pthread_cond_signal(&surface_queue->dirty_cond);
927
928         _tbm_surf_queue_mutex_unlock();
929
930         _notify_emit(surface_queue, &surface_queue->acquirable_noti);
931
932         return TBM_SURFACE_QUEUE_ERROR_NONE;
933 }
934
935 tbm_surface_queue_error_e
936 tbm_surface_queue_dequeue(tbm_surface_queue_h
937                           surface_queue, tbm_surface_h *surface)
938 {
939         queue_node *node = NULL;
940
941         _tbm_surf_queue_mutex_lock();
942
943         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
944                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
945         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
946                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
947
948         pthread_mutex_lock(&surface_queue->lock);
949
950         if (surface_queue->impl && surface_queue->impl->dequeue)
951                 node = surface_queue->impl->dequeue(surface_queue);
952         else
953                 node = _tbm_surface_queue_dequeue(surface_queue);
954
955         if (node == NULL) {
956                 *surface = NULL;
957                 pthread_mutex_unlock(&surface_queue->lock);
958
959                 _tbm_surf_queue_mutex_unlock();
960                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
961         }
962
963         if (node->surface == NULL) {
964                 *surface = NULL;
965                 TBM_LOG_E("_queue_node_pop_front  failed\n");
966                 pthread_mutex_unlock(&surface_queue->lock);
967
968                 _tbm_surf_queue_mutex_unlock();
969                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
970         }
971
972         node->type = QUEUE_NODE_TYPE_DEQUEUE;
973         *surface = node->surface;
974
975         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
976
977         pthread_mutex_unlock(&surface_queue->lock);
978
979         _tbm_surf_queue_mutex_unlock();
980
981         _notify_emit(surface_queue, &surface_queue->dequeue_noti);
982
983         return TBM_SURFACE_QUEUE_ERROR_NONE;
984 }
985
986 int
987 tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
988 {
989         _tbm_surf_queue_mutex_lock();
990
991         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
992
993         pthread_mutex_lock(&surface_queue->lock);
994
995         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
996
997         if (_queue_is_empty(&surface_queue->free_queue)) {
998                 if (surface_queue->impl && surface_queue->impl->need_attach)
999                         surface_queue->impl->need_attach(surface_queue);
1000
1001                 if (!_tbm_surface_queue_is_valid(surface_queue)) {
1002                                 TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1003                                 _tbm_surf_queue_mutex_unlock();
1004                                 return 0;
1005                 }
1006         }
1007
1008         if (_queue_is_empty(&surface_queue->free_queue)) {
1009                 if (wait &&
1010                         _tbm_surface_queue_get_node_count(surface_queue, QUEUE_NODE_TYPE_ACQUIRE)) {
1011
1012                         _tbm_surf_queue_mutex_unlock();
1013
1014                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
1015
1016                         _tbm_surf_queue_mutex_lock();
1017
1018                         if (!_tbm_surface_queue_is_valid(surface_queue)) {
1019                                   TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1020                                   _tbm_surf_queue_mutex_unlock();
1021                                   return 0;
1022                         }
1023
1024                         pthread_mutex_unlock(&surface_queue->lock);
1025
1026                         _tbm_surf_queue_mutex_unlock();
1027                         return 1;
1028                 }
1029
1030                 pthread_mutex_unlock(&surface_queue->lock);
1031
1032                 _tbm_surf_queue_mutex_unlock();
1033                 return 0;
1034         }
1035
1036         pthread_mutex_unlock(&surface_queue->lock);
1037
1038         _tbm_surf_queue_mutex_unlock();
1039
1040         return 1;
1041 }
1042
1043 tbm_surface_queue_error_e
1044 tbm_surface_queue_release(tbm_surface_queue_h
1045                           surface_queue, tbm_surface_h surface)
1046 {
1047         queue_node *node = NULL;
1048         int queue_type;
1049
1050         _tbm_surf_queue_mutex_lock();
1051
1052         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1053                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1054         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
1055                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
1056
1057         pthread_mutex_lock(&surface_queue->lock);
1058
1059         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
1060
1061         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
1062         if (node == NULL || queue_type != NODE_LIST) {
1063                 TBM_LOG_E("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
1064                         node, queue_type);
1065                 pthread_mutex_unlock(&surface_queue->lock);
1066
1067                 _tbm_surf_queue_mutex_unlock();
1068                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
1069         }
1070
1071         if (surface_queue->impl && surface_queue->impl->release)
1072                 surface_queue->impl->release(surface_queue, node);
1073         else
1074                 _tbm_surface_queue_release(surface_queue, node, 1);
1075
1076         if (_queue_is_empty(&surface_queue->free_queue)) {
1077                 pthread_mutex_unlock(&surface_queue->lock);
1078
1079                 _tbm_surf_queue_mutex_unlock();
1080                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1081         }
1082
1083         node->type = QUEUE_NODE_TYPE_RELEASE;
1084
1085         pthread_mutex_unlock(&surface_queue->lock);
1086         pthread_cond_signal(&surface_queue->free_cond);
1087
1088         _tbm_surf_queue_mutex_unlock();
1089
1090         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
1091
1092         return TBM_SURFACE_QUEUE_ERROR_NONE;
1093 }
1094
1095 tbm_surface_queue_error_e
1096 tbm_surface_queue_acquire(tbm_surface_queue_h
1097                           surface_queue, tbm_surface_h *surface)
1098 {
1099         queue_node *node = NULL;
1100
1101         _tbm_surf_queue_mutex_lock();
1102
1103         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1104                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1105         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
1106                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
1107
1108         pthread_mutex_lock(&surface_queue->lock);
1109
1110         if (surface_queue->impl && surface_queue->impl->acquire)
1111                 node = surface_queue->impl->acquire(surface_queue);
1112         else
1113                 node = _tbm_surface_queue_acquire(surface_queue);
1114
1115         if (node == NULL) {
1116                 *surface = NULL;
1117                 pthread_mutex_unlock(&surface_queue->lock);
1118
1119                 _tbm_surf_queue_mutex_unlock();
1120                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
1121         }
1122
1123         if (node->surface == NULL) {
1124                 *surface = NULL;
1125                 TBM_LOG_E("_queue_node_pop_front  failed\n");
1126                 pthread_mutex_unlock(&surface_queue->lock);
1127
1128                 _tbm_surf_queue_mutex_unlock();
1129                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
1130         }
1131
1132         node->type = QUEUE_NODE_TYPE_ACQUIRE;
1133
1134         *surface = node->surface;
1135
1136         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
1137
1138         pthread_mutex_unlock(&surface_queue->lock);
1139
1140         _tbm_surf_queue_mutex_unlock();
1141
1142         if (b_dump_queue)
1143                 tbm_surface_internal_dump_buffer(*surface, "acquire");
1144
1145         return TBM_SURFACE_QUEUE_ERROR_NONE;
1146 }
1147
1148 int
1149 tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
1150 {
1151         _tbm_surf_queue_mutex_lock();
1152
1153         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
1154
1155         pthread_mutex_lock(&surface_queue->lock);
1156
1157         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1158
1159         if (_queue_is_empty(&surface_queue->dirty_queue)) {
1160                 if (wait &&
1161                         _tbm_surface_queue_get_node_count(surface_queue, QUEUE_NODE_TYPE_DEQUEUE)) {
1162
1163                         _tbm_surf_queue_mutex_unlock();
1164
1165                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
1166
1167                         _tbm_surf_queue_mutex_lock();
1168
1169                         if (!_tbm_surface_queue_is_valid(surface_queue)) {
1170                                   TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1171                                   _tbm_surf_queue_mutex_unlock();
1172                                   return 0;
1173                         }
1174
1175                         pthread_mutex_unlock(&surface_queue->lock);
1176
1177                         _tbm_surf_queue_mutex_unlock();
1178                         return 1;
1179                 }
1180
1181                 pthread_mutex_unlock(&surface_queue->lock);
1182
1183                 _tbm_surf_queue_mutex_unlock();
1184                 return 0;
1185         }
1186
1187         pthread_mutex_unlock(&surface_queue->lock);
1188
1189         _tbm_surf_queue_mutex_unlock();
1190
1191         return 1;
1192 }
1193
1194 void
1195 tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
1196 {
1197         queue_node *node = NULL, *tmp = NULL;
1198
1199         _tbm_surf_queue_mutex_lock();
1200
1201         TBM_SURF_QUEUE_RETURN_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue));
1202
1203         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1204
1205         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1206                 _queue_delete_node(surface_queue, node);
1207         }
1208
1209         if (surface_queue->impl && surface_queue->impl->destroy)
1210                 surface_queue->impl->destroy(surface_queue);
1211
1212         _notify_emit(surface_queue, &surface_queue->destory_noti);
1213
1214         _notify_remove_all(&surface_queue->destory_noti);
1215         _notify_remove_all(&surface_queue->acquirable_noti);
1216         _notify_remove_all(&surface_queue->dequeuable_noti);
1217         _notify_remove_all(&surface_queue->reset_noti);
1218
1219         pthread_mutex_destroy(&surface_queue->lock);
1220
1221         LIST_DEL(&surface_queue->item_link);
1222
1223         free(surface_queue);
1224         surface_queue = NULL;
1225
1226         if (LIST_IS_EMPTY(&g_surf_queue_bufmgr->surf_queue_list))
1227                 _deinit_tbm_surf_queue_bufmgr();
1228
1229         _tbm_surf_queue_mutex_unlock();
1230 }
1231
1232 tbm_surface_queue_error_e
1233 tbm_surface_queue_reset(tbm_surface_queue_h
1234                         surface_queue, int width, int height, int format)
1235 {
1236         queue_node *node = NULL, *tmp = NULL;
1237
1238         _tbm_surf_queue_mutex_lock();
1239
1240         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1241                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1242
1243         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1244
1245         if (width == surface_queue->width && height == surface_queue->height &&
1246             format == surface_queue->format)
1247                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1248
1249         pthread_mutex_lock(&surface_queue->lock);
1250
1251         surface_queue->width = width;
1252         surface_queue->height = height;
1253         surface_queue->format = format;
1254
1255         /* Destory surface and Push to free_queue */
1256         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1257                 _queue_delete_node(surface_queue, node);
1258         }
1259
1260         /* Reset queue */
1261         _queue_init(&surface_queue->free_queue);
1262         _queue_init(&surface_queue->dirty_queue);
1263         LIST_INITHEAD(&surface_queue->list);
1264
1265         if (surface_queue->impl && surface_queue->impl->reset)
1266                 surface_queue->impl->reset(surface_queue);
1267
1268         pthread_mutex_unlock(&surface_queue->lock);
1269         pthread_cond_signal(&surface_queue->free_cond);
1270
1271         _tbm_surf_queue_mutex_unlock();
1272
1273         _notify_emit(surface_queue, &surface_queue->reset_noti);
1274
1275         return TBM_SURFACE_QUEUE_ERROR_NONE;
1276 }
1277
1278 tbm_surface_queue_error_e
1279 tbm_surface_queue_flush(tbm_surface_queue_h surface_queue)
1280 {
1281         queue_node *node = NULL, *tmp = NULL;
1282
1283         _tbm_surf_queue_mutex_lock();
1284
1285         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1286                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1287
1288         pthread_mutex_lock(&surface_queue->lock);
1289
1290         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1291
1292         /* Destory surface and Push to free_queue */
1293         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1294                 _queue_delete_node(surface_queue, node);
1295         }
1296
1297         /* Reset queue */
1298         _queue_init(&surface_queue->free_queue);
1299         _queue_init(&surface_queue->dirty_queue);
1300         LIST_INITHEAD(&surface_queue->list);
1301
1302         if (surface_queue->impl && surface_queue->impl->reset)
1303                 surface_queue->impl->reset(surface_queue);
1304
1305         pthread_mutex_unlock(&surface_queue->lock);
1306         pthread_cond_signal(&surface_queue->free_cond);
1307
1308         _tbm_surf_queue_mutex_unlock();
1309
1310         _notify_emit(surface_queue, &surface_queue->reset_noti);
1311
1312         return TBM_SURFACE_QUEUE_ERROR_NONE;
1313 }
1314
1315 tbm_surface_queue_error_e
1316 tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
1317                         tbm_surface_h *surfaces, int *num)
1318 {
1319         queue_node *node = NULL;
1320         queue_node *tmp = NULL;
1321
1322         _tbm_surf_queue_mutex_lock();
1323
1324         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1325                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1326         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(num != NULL,
1327                                TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
1328
1329         pthread_mutex_lock(&surface_queue->lock);
1330
1331         *num = 0;
1332         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1333                 if (surfaces)
1334                         surfaces[*num] = node->surface;
1335
1336                 *num = *num + 1;
1337         }
1338
1339         pthread_mutex_unlock(&surface_queue->lock);
1340
1341         _tbm_surf_queue_mutex_unlock();
1342
1343         return TBM_SURFACE_QUEUE_ERROR_NONE;
1344 }
1345
1346 typedef struct {
1347         int queue_size;
1348         int num_attached;
1349         int flags;
1350 } tbm_queue_default;
1351
1352 static void
1353 __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
1354 {
1355         tbm_queue_default *data = surface_queue->impl_data;
1356
1357         data->num_attached = 0;
1358 }
1359
1360 static void
1361 __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
1362 {
1363         tbm_queue_default *data = surface_queue->impl_data;
1364
1365         data->num_attached = 0;
1366 }
1367
1368 static void
1369 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
1370 {
1371         free(surface_queue->impl_data);
1372 }
1373
1374 static void
1375 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
1376 {
1377         tbm_queue_default *data = surface_queue->impl_data;
1378         tbm_surface_h surface;
1379
1380         if (data->queue_size == data->num_attached)
1381                 return;
1382
1383         if (surface_queue->alloc_cb) {
1384
1385                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1386                 TBM_RETURN_IF_FAIL(surface != NULL);
1387                 tbm_surface_internal_ref(surface);
1388         } else {
1389                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1390                                 surface_queue->height,
1391                                 surface_queue->format,
1392                                 data->flags);
1393                 TBM_RETURN_IF_FAIL(surface != NULL);
1394         }
1395
1396         _tbm_surface_queue_attach(surface_queue, surface);
1397         tbm_surface_internal_unref(surface);
1398         data->num_attached++;
1399 }
1400
1401 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1402         __tbm_queue_default_init,
1403         __tbm_queue_default_reset,
1404         __tbm_queue_default_destroy,
1405         __tbm_queue_default_need_attach,
1406         NULL,                           /*__tbm_queue_default_enqueue*/
1407         NULL,                           /*__tbm_queue_default_release*/
1408         NULL,                           /*__tbm_queue_default_dequeue*/
1409         NULL,                           /*__tbm_queue_default_acquire*/
1410 };
1411
1412 tbm_surface_queue_h
1413 tbm_surface_queue_create(int queue_size, int width,
1414                          int height, int format, int flags)
1415 {
1416         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1417         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1418         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1419         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1420
1421         _tbm_surf_queue_mutex_lock();
1422
1423         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1424                                             sizeof(struct _tbm_surface_queue));
1425         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1426
1427         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1428
1429         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1430                                   sizeof(tbm_queue_default));
1431         if (data == NULL) {
1432                 free(surface_queue);
1433                 _tbm_surf_queue_mutex_unlock();
1434                 return NULL;
1435         }
1436
1437         data->queue_size = queue_size;
1438         data->flags = flags;
1439         _tbm_surface_queue_init(surface_queue,
1440                                 data->queue_size,
1441                                 width, height, format,
1442                                 &tbm_queue_default_impl, data);
1443
1444         _tbm_surf_queue_mutex_unlock();
1445
1446         return surface_queue;
1447 }
1448
1449 typedef struct {
1450         int queue_size;
1451         int num_attached;
1452         int flags;
1453         queue dequeue_list;
1454 } tbm_queue_sequence;
1455
1456 static void
1457 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1458 {
1459         tbm_queue_sequence *data = surface_queue->impl_data;
1460
1461         data->num_attached = 0;
1462         _queue_init(&data->dequeue_list);
1463 }
1464
1465 static void
1466 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1467 {
1468         tbm_queue_sequence *data = surface_queue->impl_data;
1469
1470         data->num_attached = 0;
1471         _queue_init(&data->dequeue_list);
1472 }
1473
1474 static void
1475 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1476 {
1477         free(surface_queue->impl_data);
1478 }
1479
1480 static void
1481 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1482 {
1483         tbm_queue_sequence *data = surface_queue->impl_data;
1484         tbm_surface_h surface;
1485
1486         if (data->queue_size == data->num_attached)
1487                 return;
1488
1489         if (surface_queue->alloc_cb) {
1490                 _tbm_surf_queue_mutex_unlock();
1491                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1492                 _tbm_surf_queue_mutex_lock();
1493
1494                 if (!surface)
1495                         return;
1496
1497                 tbm_surface_internal_ref(surface);
1498         } else {
1499                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1500                                 surface_queue->height,
1501                                 surface_queue->format,
1502                                 data->flags);
1503                 TBM_RETURN_IF_FAIL(surface != NULL);
1504         }
1505
1506         _tbm_surface_queue_attach(surface_queue, surface);
1507         tbm_surface_internal_unref(surface);
1508         data->num_attached++;
1509 }
1510
1511 static void
1512 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1513                              queue_node *node)
1514 {
1515         tbm_queue_sequence *data = surface_queue->impl_data;
1516         queue_node *next = NULL;
1517         queue_node *tmp = NULL;
1518
1519         node->priv_flags = 0;
1520
1521         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1522                 if (next->priv_flags)
1523                         break;
1524                 _queue_node_pop(&data->dequeue_list, next);
1525                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1526         }
1527 }
1528
1529 static queue_node *
1530 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1531                              surface_queue)
1532 {
1533         tbm_queue_sequence *data = surface_queue->impl_data;
1534         queue_node *node = NULL;
1535
1536         node = _tbm_surface_queue_dequeue(surface_queue);
1537         if (node) {
1538                 _queue_node_push_back(&data->dequeue_list, node);
1539                 node->priv_flags = 1;
1540         }
1541
1542         return node;
1543 }
1544
1545 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1546         __tbm_queue_sequence_init,
1547         __tbm_queue_sequence_reset,
1548         __tbm_queue_sequence_destroy,
1549         __tbm_queue_sequence_need_attach,
1550         __tbm_queue_sequence_enqueue,
1551         NULL,                                   /*__tbm_queue_sequence_release*/
1552         __tbm_queue_sequence_dequeue,
1553         NULL,                                   /*__tbm_queue_sequence_acquire*/
1554 };
1555
1556 tbm_surface_queue_h
1557 tbm_surface_queue_sequence_create(int queue_size, int width,
1558                                   int height, int format, int flags)
1559 {
1560         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1561         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1562         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1563         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1564
1565         _tbm_surf_queue_mutex_lock();
1566
1567         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1568                                             sizeof(struct _tbm_surface_queue));
1569         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1570
1571         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1572
1573         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1574                                    sizeof(tbm_queue_sequence));
1575         if (data == NULL) {
1576                 free(surface_queue);
1577                 return NULL;
1578         }
1579
1580         data->queue_size = queue_size;
1581         data->flags = flags;
1582         _tbm_surface_queue_init(surface_queue,
1583                                 data->queue_size,
1584                                 width, height, format,
1585                                 &tbm_queue_sequence_impl, data);
1586
1587         _tbm_surf_queue_mutex_unlock();
1588
1589         return surface_queue;
1590 }
1591 /* LCOV_EXCL_STOP */