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