surface_queue: wrap mutex lock when check valid of surface_queue
[platform/core/uifw/libtbm.git] / src / tbm_surface_queue.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "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_mutex_lock();
1044
1045         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
1046
1047         _tbm_surf_queue_mutex_unlock();
1048
1049         _notify_emit(surface_queue, &surface_queue->can_dequeue_noti);
1050
1051         _tbm_surf_queue_mutex_lock();
1052
1053         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
1054
1055         pthread_mutex_lock(&surface_queue->lock);
1056
1057         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1058
1059         if (_queue_is_empty(&surface_queue->free_queue)) {
1060                 if (surface_queue->impl && surface_queue->impl->need_attach)
1061                         surface_queue->impl->need_attach(surface_queue);
1062
1063                 if (!_tbm_surface_queue_is_valid(surface_queue)) {
1064                         TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1065                         _tbm_surf_queue_mutex_unlock();
1066                         return 0;
1067                 }
1068         }
1069
1070         if (!_queue_is_empty(&surface_queue->free_queue)) {
1071                 pthread_mutex_unlock(&surface_queue->lock);
1072                 _tbm_surf_queue_mutex_unlock();
1073                 return 1;
1074         }
1075
1076         if (wait && _tbm_surface_queue_get_node_count(surface_queue,
1077                                                 QUEUE_NODE_TYPE_ACQUIRE)) {
1078                 _tbm_surf_queue_mutex_unlock();
1079                 pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
1080                 _tbm_surf_queue_mutex_lock();
1081
1082                 if (!_tbm_surface_queue_is_valid(surface_queue)) {
1083                           TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1084                         pthread_mutex_unlock(&surface_queue->lock);
1085                           _tbm_surf_queue_mutex_unlock();
1086                           return 0;
1087                 }
1088
1089                 pthread_mutex_unlock(&surface_queue->lock);
1090                 _tbm_surf_queue_mutex_unlock();
1091                 return 1;
1092         }
1093
1094         pthread_mutex_unlock(&surface_queue->lock);
1095         _tbm_surf_queue_mutex_unlock();
1096         return 0;
1097 }
1098
1099 tbm_surface_queue_error_e
1100 tbm_surface_queue_release(tbm_surface_queue_h
1101                           surface_queue, tbm_surface_h surface)
1102 {
1103         queue_node *node;
1104         int queue_type;
1105
1106         _tbm_surf_queue_mutex_lock();
1107
1108         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1109                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1110         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
1111                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
1112
1113         pthread_mutex_lock(&surface_queue->lock);
1114
1115         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
1116
1117         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
1118         if (node == NULL || queue_type != NODE_LIST) {
1119                 TBM_LOG_E("tbm_surface_queue_release::Surface is existed in free_queue or dirty_queue node:%p, type:%d\n",
1120                         node, queue_type);
1121                 pthread_mutex_unlock(&surface_queue->lock);
1122
1123                 _tbm_surf_queue_mutex_unlock();
1124                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
1125         }
1126
1127         if (surface_queue->queue_size < surface_queue->num_attached) {
1128                 TBM_QUEUE_TRACE("deatch tbm_surface_queue(%p) surface(%p)\n", surface_queue, node->surface);
1129
1130                 if (surface_queue->impl && surface_queue->impl->need_detach)
1131                         surface_queue->impl->need_detach(surface_queue, node);
1132                 else
1133                         _tbm_surface_queue_detach(surface_queue, surface);
1134
1135                 pthread_mutex_unlock(&surface_queue->lock);
1136
1137                 _tbm_surf_queue_mutex_unlock();
1138                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1139         }
1140
1141         if (surface_queue->impl && surface_queue->impl->release)
1142                 surface_queue->impl->release(surface_queue, node);
1143         else
1144                 _tbm_surface_queue_release(surface_queue, node, 1);
1145
1146         if (_queue_is_empty(&surface_queue->free_queue)) {
1147                 pthread_mutex_unlock(&surface_queue->lock);
1148
1149                 _tbm_surf_queue_mutex_unlock();
1150                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
1151         }
1152
1153         node->type = QUEUE_NODE_TYPE_RELEASE;
1154
1155         pthread_mutex_unlock(&surface_queue->lock);
1156         pthread_cond_signal(&surface_queue->free_cond);
1157
1158         _tbm_surf_queue_mutex_unlock();
1159
1160         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
1161
1162         return TBM_SURFACE_QUEUE_ERROR_NONE;
1163 }
1164
1165 tbm_surface_queue_error_e
1166 tbm_surface_queue_acquire(tbm_surface_queue_h
1167                           surface_queue, tbm_surface_h *surface)
1168 {
1169         queue_node *node;
1170
1171         _tbm_surf_queue_mutex_lock();
1172
1173         *surface = NULL;
1174
1175         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1176                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1177         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface != NULL,
1178                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
1179
1180         pthread_mutex_lock(&surface_queue->lock);
1181
1182         if (surface_queue->impl && surface_queue->impl->acquire)
1183                 node = surface_queue->impl->acquire(surface_queue);
1184         else
1185                 node = _tbm_surface_queue_acquire(surface_queue);
1186
1187         if (node == NULL || node->surface == NULL) {
1188                 TBM_LOG_E("_queue_node_pop_front failed\n");
1189                 pthread_mutex_unlock(&surface_queue->lock);
1190
1191                 _tbm_surf_queue_mutex_unlock();
1192                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
1193         }
1194
1195         node->type = QUEUE_NODE_TYPE_ACQUIRE;
1196
1197         *surface = node->surface;
1198
1199         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
1200
1201         pthread_mutex_unlock(&surface_queue->lock);
1202
1203         _tbm_surf_queue_mutex_unlock();
1204
1205         if (b_dump_queue)
1206                 tbm_surface_internal_dump_buffer(*surface, "acquire");
1207
1208         return TBM_SURFACE_QUEUE_ERROR_NONE;
1209 }
1210
1211 int
1212 tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
1213 {
1214         _tbm_surf_queue_mutex_lock();
1215
1216         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue), 0);
1217
1218         pthread_mutex_lock(&surface_queue->lock);
1219
1220         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1221
1222         if (!_queue_is_empty(&surface_queue->dirty_queue)) {
1223                 pthread_mutex_unlock(&surface_queue->lock);
1224                 _tbm_surf_queue_mutex_unlock();
1225                 return 1;
1226         }
1227
1228         if (wait && _tbm_surface_queue_get_node_count(surface_queue,
1229                                                 QUEUE_NODE_TYPE_DEQUEUE)) {
1230                 _tbm_surf_queue_mutex_unlock();
1231                 pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
1232                 _tbm_surf_queue_mutex_lock();
1233
1234                 if (!_tbm_surface_queue_is_valid(surface_queue)) {
1235                           TBM_LOG_E("surface_queue:%p is invalid", surface_queue);
1236                         pthread_mutex_unlock(&surface_queue->lock);
1237                           _tbm_surf_queue_mutex_unlock();
1238                           return 0;
1239                 }
1240
1241                 pthread_mutex_unlock(&surface_queue->lock);
1242                 _tbm_surf_queue_mutex_unlock();
1243                 return 1;
1244         }
1245
1246         pthread_mutex_unlock(&surface_queue->lock);
1247         _tbm_surf_queue_mutex_unlock();
1248         return 0;
1249 }
1250
1251 void
1252 tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
1253 {
1254         queue_node *node = NULL, *tmp;
1255
1256         _tbm_surf_queue_mutex_lock();
1257
1258         TBM_SURF_QUEUE_RETURN_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue));
1259
1260         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1261
1262         LIST_DEL(&surface_queue->item_link);
1263
1264         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
1265                 _queue_delete_node(surface_queue, node);
1266
1267         if (surface_queue->impl && surface_queue->impl->destroy)
1268                 surface_queue->impl->destroy(surface_queue);
1269
1270         _notify_emit(surface_queue, &surface_queue->destory_noti);
1271
1272         _notify_remove_all(&surface_queue->destory_noti);
1273         _notify_remove_all(&surface_queue->dequeuable_noti);
1274         _notify_remove_all(&surface_queue->dequeue_noti);
1275         _notify_remove_all(&surface_queue->can_dequeue_noti);
1276         _notify_remove_all(&surface_queue->acquirable_noti);
1277         _notify_remove_all(&surface_queue->reset_noti);
1278
1279         pthread_mutex_destroy(&surface_queue->lock);
1280
1281         free(surface_queue);
1282
1283         if (LIST_IS_EMPTY(&g_surf_queue_bufmgr->surf_queue_list))
1284                 _deinit_tbm_surf_queue_bufmgr();
1285
1286         _tbm_surf_queue_mutex_unlock();
1287 }
1288
1289 tbm_surface_queue_error_e
1290 tbm_surface_queue_reset(tbm_surface_queue_h
1291                         surface_queue, int width, int height, int format)
1292 {
1293         queue_node *node = NULL, *tmp;
1294
1295         _tbm_surf_queue_mutex_lock();
1296
1297         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1298                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1299
1300         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1301
1302         if (width == surface_queue->width && height == surface_queue->height &&
1303                 format == surface_queue->format) {
1304                 _tbm_surf_queue_mutex_unlock();
1305                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1306         }
1307
1308         pthread_mutex_lock(&surface_queue->lock);
1309
1310         surface_queue->width = width;
1311         surface_queue->height = height;
1312         surface_queue->format = format;
1313
1314         /* Destory surface and Push to free_queue */
1315         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
1316                 _queue_delete_node(surface_queue, node);
1317
1318         /* Reset queue */
1319         _queue_init(&surface_queue->free_queue);
1320         _queue_init(&surface_queue->dirty_queue);
1321         LIST_INITHEAD(&surface_queue->list);
1322
1323         surface_queue->num_attached = 0;
1324
1325         if (surface_queue->impl && surface_queue->impl->reset)
1326                 surface_queue->impl->reset(surface_queue);
1327
1328         pthread_mutex_unlock(&surface_queue->lock);
1329         pthread_cond_signal(&surface_queue->free_cond);
1330
1331         _tbm_surf_queue_mutex_unlock();
1332
1333         _notify_emit(surface_queue, &surface_queue->reset_noti);
1334
1335         return TBM_SURFACE_QUEUE_ERROR_NONE;
1336 }
1337
1338 tbm_surface_queue_error_e
1339 tbm_surface_queue_notify_reset(tbm_surface_queue_h surface_queue)
1340 {
1341         _tbm_surf_queue_mutex_lock();
1342
1343         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1344                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1345
1346         _tbm_surf_queue_mutex_unlock();
1347
1348         _notify_emit(surface_queue, &surface_queue->reset_noti);
1349
1350         return TBM_SURFACE_QUEUE_ERROR_NONE;
1351 }
1352
1353 tbm_surface_queue_error_e
1354 tbm_surface_queue_set_size(tbm_surface_queue_h
1355                         surface_queue, int queue_size, int flush)
1356 {
1357         queue_node *node = NULL, *tmp;
1358
1359         _tbm_surf_queue_mutex_lock();
1360
1361         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1362                                         TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1363         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(queue_size > 0,
1364                                         TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
1365
1366         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1367
1368         if ((surface_queue->queue_size == queue_size) && !flush) {
1369                 _tbm_surf_queue_mutex_unlock();
1370                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1371         }
1372
1373         pthread_mutex_lock(&surface_queue->lock);
1374
1375         if (flush) {
1376                 /* Destory surface and Push to free_queue */
1377                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
1378                         _queue_delete_node(surface_queue, node);
1379
1380                 /* Reset queue */
1381                 _queue_init(&surface_queue->free_queue);
1382                 _queue_init(&surface_queue->dirty_queue);
1383                 LIST_INITHEAD(&surface_queue->list);
1384
1385                 surface_queue->num_attached = 0;
1386                 surface_queue->queue_size = queue_size;
1387
1388                 if (surface_queue->impl && surface_queue->impl->reset)
1389                         surface_queue->impl->reset(surface_queue);
1390
1391                 pthread_mutex_unlock(&surface_queue->lock);
1392                 pthread_cond_signal(&surface_queue->free_cond);
1393
1394                 _tbm_surf_queue_mutex_unlock();
1395
1396                 _notify_emit(surface_queue, &surface_queue->reset_noti);
1397
1398                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1399         } else {
1400                 if (surface_queue->queue_size > queue_size) {
1401                         int need_del = surface_queue->queue_size - queue_size;
1402
1403                         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head, item_link) {
1404                                 TBM_QUEUE_TRACE("deatch tbm_surface_queue(%p) surface(%p)\n", surface_queue, node->surface);
1405
1406                                 if (surface_queue->impl && surface_queue->impl->need_detach)
1407                                         surface_queue->impl->need_detach(surface_queue, node);
1408                                 else
1409                                         _tbm_surface_queue_detach(surface_queue, node->surface);
1410
1411                                 need_del--;
1412                                 if (need_del == 0)
1413                                         break;
1414                         }
1415                 }
1416
1417                 surface_queue->queue_size = queue_size;
1418
1419                 pthread_mutex_unlock(&surface_queue->lock);
1420
1421                 _tbm_surf_queue_mutex_unlock();
1422
1423                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1424         }
1425 }
1426
1427 tbm_surface_queue_error_e
1428 tbm_surface_queue_flush(tbm_surface_queue_h surface_queue)
1429 {
1430         queue_node *node = NULL, *tmp;
1431
1432         _tbm_surf_queue_mutex_lock();
1433
1434         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1435                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1436
1437         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1438
1439         if (surface_queue->num_attached == 0) {
1440                 _tbm_surf_queue_mutex_unlock();
1441                 return TBM_SURFACE_QUEUE_ERROR_NONE;
1442         }
1443
1444         pthread_mutex_lock(&surface_queue->lock);
1445
1446         /* Destory surface and Push to free_queue */
1447         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
1448                 _queue_delete_node(surface_queue, node);
1449
1450         /* Reset queue */
1451         _queue_init(&surface_queue->free_queue);
1452         _queue_init(&surface_queue->dirty_queue);
1453         LIST_INITHEAD(&surface_queue->list);
1454
1455         surface_queue->num_attached = 0;
1456
1457         if (surface_queue->impl && surface_queue->impl->reset)
1458                 surface_queue->impl->reset(surface_queue);
1459
1460         pthread_mutex_unlock(&surface_queue->lock);
1461         pthread_cond_signal(&surface_queue->free_cond);
1462
1463         _tbm_surf_queue_mutex_unlock();
1464
1465         _notify_emit(surface_queue, &surface_queue->reset_noti);
1466
1467         return TBM_SURFACE_QUEUE_ERROR_NONE;
1468 }
1469
1470 tbm_surface_queue_error_e
1471 tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
1472                         tbm_surface_h *surfaces, int *num)
1473 {
1474         queue_node *node = NULL;
1475
1476         _tbm_surf_queue_mutex_lock();
1477
1478         *num = 0;
1479
1480         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(_tbm_surface_queue_is_valid(surface_queue),
1481                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1482         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(num != NULL,
1483                                TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
1484
1485         pthread_mutex_lock(&surface_queue->lock);
1486
1487         LIST_FOR_EACH_ENTRY(node, &surface_queue->list, link) {
1488                 if (surfaces)
1489                         surfaces[*num] = node->surface;
1490
1491                 *num = *num + 1;
1492         }
1493
1494         pthread_mutex_unlock(&surface_queue->lock);
1495
1496         _tbm_surf_queue_mutex_unlock();
1497
1498         return TBM_SURFACE_QUEUE_ERROR_NONE;
1499 }
1500
1501 typedef struct {
1502         int flags;
1503 } tbm_queue_default;
1504
1505 static void
1506 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
1507 {
1508         free(surface_queue->impl_data);
1509 }
1510
1511 static void
1512 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
1513 {
1514         tbm_queue_default *data = (tbm_queue_default *)surface_queue->impl_data;
1515         tbm_surface_h surface;
1516
1517         if (surface_queue->queue_size == surface_queue->num_attached)
1518                 return;
1519
1520         if (surface_queue->alloc_cb) {
1521                 pthread_mutex_unlock(&surface_queue->lock);
1522                 _tbm_surf_queue_mutex_unlock();
1523                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1524                 _tbm_surf_queue_mutex_lock();
1525                 pthread_mutex_lock(&surface_queue->lock);
1526
1527                 if (!surface)
1528                         return;
1529
1530                 tbm_surface_internal_ref(surface);
1531         } else {
1532                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1533                                 surface_queue->height,
1534                                 surface_queue->format,
1535                                 data->flags);
1536                 TBM_RETURN_IF_FAIL(surface != NULL);
1537         }
1538
1539         _tbm_surface_queue_attach(surface_queue, surface);
1540         tbm_surface_internal_unref(surface);
1541 }
1542
1543 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1544         NULL,                           /*__tbm_queue_default_init*/
1545         NULL,                           /*__tbm_queue_default_reset*/
1546         __tbm_queue_default_destroy,
1547         __tbm_queue_default_need_attach,
1548         NULL,                           /*__tbm_queue_default_enqueue*/
1549         NULL,                           /*__tbm_queue_default_release*/
1550         NULL,                           /*__tbm_queue_default_dequeue*/
1551         NULL,                           /*__tbm_queue_default_acquire*/
1552         NULL,                           /*__tbm_queue_default_need_detach*/
1553 };
1554
1555 tbm_surface_queue_h
1556 tbm_surface_queue_create(int queue_size, int width,
1557                          int height, int format, int flags)
1558 {
1559         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1560         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1561         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1562         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1563
1564         _tbm_surf_queue_mutex_lock();
1565
1566         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1567                                             sizeof(struct _tbm_surface_queue));
1568         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1569
1570         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1571
1572         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1573                                   sizeof(tbm_queue_default));
1574         if (data == NULL) {
1575                 free(surface_queue);
1576                 _tbm_surf_queue_mutex_unlock();
1577                 return NULL;
1578         }
1579
1580         data->flags = flags;
1581         _tbm_surface_queue_init(surface_queue,
1582                                 queue_size,
1583                                 width, height, format,
1584                                 &tbm_queue_default_impl, data);
1585
1586         _tbm_surf_queue_mutex_unlock();
1587
1588         return surface_queue;
1589 }
1590
1591 typedef struct {
1592         int flags;
1593         queue dequeue_list;
1594 } tbm_queue_sequence;
1595
1596 static void
1597 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1598 {
1599         tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
1600
1601         _queue_init(&data->dequeue_list);
1602 }
1603
1604 static void
1605 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1606 {
1607         tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
1608
1609         _queue_init(&data->dequeue_list);
1610 }
1611
1612 static void
1613 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1614 {
1615         free(surface_queue->impl_data);
1616 }
1617
1618 static void
1619 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1620 {
1621         tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
1622         tbm_surface_h surface;
1623
1624         if (surface_queue->queue_size == surface_queue->num_attached)
1625                 return;
1626
1627         if (surface_queue->alloc_cb) {
1628                 pthread_mutex_unlock(&surface_queue->lock);
1629                 _tbm_surf_queue_mutex_unlock();
1630                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1631                 _tbm_surf_queue_mutex_lock();
1632                 pthread_mutex_lock(&surface_queue->lock);
1633
1634                 if (!surface)
1635                         return;
1636
1637                 tbm_surface_internal_ref(surface);
1638         } else {
1639                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1640                                 surface_queue->height,
1641                                 surface_queue->format,
1642                                 data->flags);
1643                 TBM_RETURN_IF_FAIL(surface != NULL);
1644         }
1645
1646         _tbm_surface_queue_attach(surface_queue, surface);
1647         tbm_surface_internal_unref(surface);
1648 }
1649
1650 static void
1651 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1652                              queue_node *node)
1653 {
1654         tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
1655         queue_node *next = NULL, *tmp;
1656
1657         node->priv_flags = 0;
1658
1659         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1660                 if (next->priv_flags)
1661                         break;
1662                 _queue_node_pop(&data->dequeue_list, next);
1663                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1664         }
1665 }
1666
1667 static queue_node *
1668 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1669                              surface_queue)
1670 {
1671         tbm_queue_sequence *data = (tbm_queue_sequence *)surface_queue->impl_data;
1672         queue_node *node;
1673
1674         node = _tbm_surface_queue_dequeue(surface_queue);
1675         if (node) {
1676                 _queue_node_push_back(&data->dequeue_list, node);
1677                 node->priv_flags = 1;
1678         }
1679
1680         return node;
1681 }
1682
1683 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1684         __tbm_queue_sequence_init,
1685         __tbm_queue_sequence_reset,
1686         __tbm_queue_sequence_destroy,
1687         __tbm_queue_sequence_need_attach,
1688         __tbm_queue_sequence_enqueue,
1689         NULL,                                   /*__tbm_queue_sequence_release*/
1690         __tbm_queue_sequence_dequeue,
1691         NULL,                                   /*__tbm_queue_sequence_acquire*/
1692         NULL,                                   /*__tbm_queue_sequence_need_dettach*/
1693 };
1694
1695 tbm_surface_queue_h
1696 tbm_surface_queue_sequence_create(int queue_size, int width,
1697                                   int height, int format, int flags)
1698 {
1699         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1700         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1701         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1702         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1703
1704         _tbm_surf_queue_mutex_lock();
1705
1706         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1707                                             sizeof(struct _tbm_surface_queue));
1708         TBM_SURF_QUEUE_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1709
1710         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1711
1712         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1713                                    sizeof(tbm_queue_sequence));
1714         if (data == NULL) {
1715                 free(surface_queue);
1716                 _tbm_surf_queue_mutex_unlock();
1717                 return NULL;
1718         }
1719
1720         data->flags = flags;
1721         _tbm_surface_queue_init(surface_queue,
1722                                 queue_size,
1723                                 width, height, format,
1724                                 &tbm_queue_sequence_impl, data);
1725
1726         _tbm_surf_queue_mutex_unlock();
1727
1728         return surface_queue;
1729 }
1730 /* LCOV_EXCL_STOP */