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