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