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