add trace messages for debugging
[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 "tbm_bufmgr_int.h"
33 #include "list.h"
34
35 #define FREE_QUEUE      1
36 #define DIRTY_QUEUE     2
37 #define NODE_LIST       4
38
39 #define TBM_QUEUE_DEBUG 0
40
41 #ifdef TRACE
42 #define TBM_QUEUE_TRACE(fmt, ...)  { if (bTrace&0x1) fprintf(stderr, "[TBM:TRACE(%d)(%s:%d)] " fmt, getpid(), __func__, __LINE__, ##__VA_ARGS__); }
43 #else
44 #define TBM_QUEUE_TRACE(fmt, ...)
45 #endif /* TRACE */
46
47 #if TBM_QUEUE_DEBUG
48 #define TBM_LOCK() TBM_LOG_D("[LOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
49 #define TBM_UNLOCK() TBM_LOG_D("[UNLOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
50 #else
51 #define TBM_LOCK()
52 #define TBM_UNLOCK()
53 #endif
54
55 typedef struct {
56         struct list_head head;
57         int count;
58 } queue;
59
60 typedef struct {
61         tbm_surface_h surface;
62
63         struct list_head item_link;
64         struct list_head link;
65
66         unsigned int priv_flags;        /*for each queue*/
67 } queue_node;
68
69 typedef struct {
70         struct list_head link;
71
72         tbm_surface_queue_notify_cb cb;
73         void *data;
74 } queue_notify;
75
76 typedef struct _tbm_surface_queue_interface {
77         void (*init)(tbm_surface_queue_h queue);
78         void (*reset)(tbm_surface_queue_h queue);
79         void (*destroy)(tbm_surface_queue_h queue);
80         void (*need_attach)(tbm_surface_queue_h queue);
81
82         void (*enqueue)(tbm_surface_queue_h queue, queue_node *node);
83         void (*release)(tbm_surface_queue_h queue, queue_node *node);
84         queue_node *(*dequeue)(tbm_surface_queue_h queue);
85         queue_node *(*acquire)(tbm_surface_queue_h queue);
86 } tbm_surface_queue_interface;
87
88 struct _tbm_surface_queue {
89         int width;
90         int height;
91         int format;
92         int queue_size;
93
94         queue free_queue;
95         queue dirty_queue;
96         struct list_head list;
97
98         struct list_head destory_noti;
99         struct list_head dequeuable_noti;
100         struct list_head acquirable_noti;
101         struct list_head reset_noti;
102
103         pthread_mutex_t lock;
104         pthread_cond_t free_cond;
105         pthread_cond_t dirty_cond;
106
107         const tbm_surface_queue_interface *impl;
108         void *impl_data;
109
110         //For external buffer allocation
111         tbm_surface_alloc_cb alloc_cb;
112         tbm_surface_free_cb free_cb;
113         void *alloc_cb_data;
114 };
115
116 /* LCOV_EXCL_START */
117 static queue_node *
118 _queue_node_create(void)
119 {
120         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
121
122         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
123
124         return node;
125 }
126
127 static void
128 _queue_node_delete(queue_node *node)
129 {
130         LIST_DEL(&node->item_link);
131         LIST_DEL(&node->link);
132         free(node);
133 }
134
135 static int
136 _queue_is_empty(queue *queue)
137 {
138         if (LIST_IS_EMPTY(&queue->head))
139                 return 1;
140
141         return 0;
142 }
143
144 static void
145 _queue_node_push_back(queue *queue, queue_node *node)
146 {
147         LIST_ADDTAIL(&node->item_link, &queue->head);
148         queue->count++;
149 }
150
151 static void
152 _queue_node_push_front(queue *queue, queue_node *node)
153 {
154         LIST_ADD(&node->item_link, &queue->head);
155         queue->count++;
156 }
157
158 static queue_node *
159 _queue_node_pop_front(queue *queue)
160 {
161         queue_node *node = NULL;
162
163         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
164
165         LIST_DEL(&node->item_link);
166         queue->count--;
167
168         return node;
169 }
170
171 static queue_node *
172 _queue_node_pop(queue *queue, queue_node *node)
173 {
174         LIST_DEL(&node->item_link);
175         queue->count--;
176
177         return node;
178 }
179
180 static queue_node *
181 _queue_get_node(tbm_surface_queue_h surface_queue, int type,
182                 tbm_surface_h surface, int *out_type)
183 {
184         queue_node *node = NULL;
185         queue_node *tmp = NULL;
186
187         if (type == 0)
188                 type = FREE_QUEUE | DIRTY_QUEUE | NODE_LIST;
189         if (out_type)
190                 *out_type = 0;
191
192         if (type & FREE_QUEUE) {
193                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head,
194                                          item_link) {
195                         if (node->surface == surface) {
196                                 if (out_type)
197                                         *out_type = FREE_QUEUE;
198
199                                 return node;
200                         }
201                 }
202         }
203
204         if (type & DIRTY_QUEUE) {
205                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head,
206                                          item_link) {
207                         if (node->surface == surface) {
208                                 if (out_type)
209                                         *out_type = DIRTY_QUEUE;
210
211                                 return node;
212                         }
213                 }
214         }
215
216         if (type & NODE_LIST) {
217                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
218                         if (node->surface == surface) {
219                                 if (out_type)
220                                         *out_type = NODE_LIST;
221
222                                 return node;
223                         }
224                 }
225         }
226
227         return NULL;
228 }
229
230 static void
231 _queue_delete_node(tbm_surface_queue_h surface_queue, queue_node *node)
232 {
233         if (node->surface) {
234                 if (surface_queue->free_cb) {
235                         surface_queue->free_cb(surface_queue,
236                                         surface_queue->alloc_cb_data,
237                                         node->surface);
238                 }
239
240                 tbm_surface_destroy(node->surface);
241         }
242
243         _queue_node_delete(node);
244 }
245
246 static void
247 _queue_init(queue *queue)
248 {
249         LIST_INITHEAD(&queue->head);
250
251         queue->count = 0;
252 }
253
254 static void
255 _notify_add(struct list_head *list, tbm_surface_queue_notify_cb cb,
256             void *data)
257 {
258         TBM_RETURN_IF_FAIL(cb != NULL);
259
260         queue_notify *item = (queue_notify *)calloc(1, sizeof(queue_notify));
261
262         TBM_RETURN_IF_FAIL(item != NULL);
263
264         LIST_INITHEAD(&item->link);
265         item->cb = cb;
266         item->data = data;
267
268         LIST_ADDTAIL(&item->link, list);
269 }
270
271 static void
272 _notify_remove(struct list_head *list,
273                tbm_surface_queue_notify_cb cb, void *data)
274 {
275         queue_notify *item = NULL, *tmp = NULL;
276
277         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
278                 if (item->cb == cb && item->data == data) {
279                         LIST_DEL(&item->link);
280                         free(item);
281                         return;
282                 }
283         }
284
285         TBM_LOG_E("Cannot find notifiy\n");
286 }
287
288 static void
289 _notify_remove_all(struct list_head *list)
290 {
291         queue_notify *item = NULL, *tmp = NULL;
292
293         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
294                 LIST_DEL(&item->link);
295                 free(item);
296         }
297 }
298
299 static void
300 _notify_emit(tbm_surface_queue_h surface_queue,
301              struct list_head *list)
302 {
303         queue_notify *item = NULL, *tmp = NULL;
304
305         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
306                 item->cb(surface_queue, item->data);
307         }
308 }
309
310 void
311 _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue,
312                           tbm_surface_h surface)
313 {
314         queue_node *node = NULL;
315
316         node = _queue_node_create();
317         TBM_RETURN_IF_FAIL(node != NULL);
318
319         tbm_surface_internal_ref(surface);
320         node->surface = surface;
321
322         LIST_ADDTAIL(&node->link, &surface_queue->list);
323         _queue_node_push_back(&surface_queue->free_queue, node);
324 }
325
326 void
327 _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue,
328                           tbm_surface_h surface)
329 {
330         queue_node *node = NULL;
331         int queue_type;
332
333         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
334         if (node)
335                 _queue_delete_node(surface_queue, node);
336 }
337
338 void
339 _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue,
340                            queue_node *node, int push_back)
341 {
342         if (push_back)
343                 _queue_node_push_back(&surface_queue->dirty_queue, node);
344         else
345                 _queue_node_push_front(&surface_queue->dirty_queue, node);
346 }
347
348 queue_node *
349 _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
350 {
351         queue_node *node = NULL;
352
353         if (_queue_is_empty(&surface_queue->free_queue)) {
354                 if (surface_queue->impl && surface_queue->impl->need_attach)
355                         surface_queue->impl->need_attach(surface_queue);
356
357                 if (_queue_is_empty(&surface_queue->free_queue))
358                         return NULL;
359         }
360
361         node = _queue_node_pop_front(&surface_queue->free_queue);
362
363         return node;
364 }
365
366 queue_node *
367 _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
368 {
369         queue_node *node = NULL;
370
371         if (_queue_is_empty(&surface_queue->dirty_queue))
372                 return NULL;
373
374         node = _queue_node_pop_front(&surface_queue->dirty_queue);
375
376         return node;
377 }
378
379 void
380 _tbm_surface_queue_release(tbm_surface_queue_h surface_queue,
381                            queue_node *node, int push_back)
382 {
383         if (push_back)
384                 _queue_node_push_back(&surface_queue->free_queue, node);
385         else
386                 _queue_node_push_front(&surface_queue->free_queue, node);
387 }
388
389 void
390 _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
391                         int queue_size,
392                         int width, int height, int format,
393                         const tbm_surface_queue_interface *impl, void *data)
394 {
395         TBM_RETURN_IF_FAIL(surface_queue != NULL);
396         TBM_RETURN_IF_FAIL(impl != NULL);
397
398         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
399
400         pthread_mutex_init(&surface_queue->lock, NULL);
401         pthread_cond_init(&surface_queue->free_cond, NULL);
402         pthread_cond_init(&surface_queue->dirty_cond, NULL);
403
404         surface_queue->queue_size = queue_size;
405         surface_queue->width = width;
406         surface_queue->height = height;
407         surface_queue->format = format;
408         surface_queue->impl = impl;
409         surface_queue->impl_data = data;
410
411         _queue_init(&surface_queue->free_queue);
412         _queue_init(&surface_queue->dirty_queue);
413         LIST_INITHEAD(&surface_queue->list);
414
415         LIST_INITHEAD(&surface_queue->destory_noti);
416         LIST_INITHEAD(&surface_queue->acquirable_noti);
417         LIST_INITHEAD(&surface_queue->dequeuable_noti);
418         LIST_INITHEAD(&surface_queue->reset_noti);
419
420         if (surface_queue->impl && surface_queue->impl->init)
421                 surface_queue->impl->init(surface_queue);
422 }
423
424 tbm_surface_queue_error_e
425 tbm_surface_queue_add_destroy_cb(
426         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
427         void *data)
428 {
429         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
430                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
431
432         pthread_mutex_lock(&surface_queue->lock);
433
434         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
435
436         _notify_add(&surface_queue->destory_noti, destroy_cb, data);
437
438         pthread_mutex_unlock(&surface_queue->lock);
439
440         return TBM_SURFACE_QUEUE_ERROR_NONE;
441 }
442
443 tbm_surface_queue_error_e
444 tbm_surface_queue_remove_destroy_cb(
445         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
446         void *data)
447 {
448         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
449                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
450
451         pthread_mutex_lock(&surface_queue->lock);
452
453         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
454
455         _notify_remove(&surface_queue->destory_noti, destroy_cb, data);
456
457         pthread_mutex_unlock(&surface_queue->lock);
458
459         return TBM_SURFACE_QUEUE_ERROR_NONE;
460 }
461
462 tbm_surface_queue_error_e
463 tbm_surface_queue_add_dequeuable_cb(
464         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
465         void *data)
466 {
467         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
468                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
469
470         pthread_mutex_lock(&surface_queue->lock);
471
472         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
473
474         _notify_add(&surface_queue->dequeuable_noti, dequeuable_cb, data);
475
476         pthread_mutex_unlock(&surface_queue->lock);
477
478         return TBM_SURFACE_QUEUE_ERROR_NONE;
479 }
480
481 tbm_surface_queue_error_e
482 tbm_surface_queue_remove_dequeuable_cb(
483         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
484         void *data)
485 {
486         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
487                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
488
489         pthread_mutex_lock(&surface_queue->lock);
490
491         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
492
493         _notify_remove(&surface_queue->dequeuable_noti, dequeuable_cb, data);
494
495         pthread_mutex_unlock(&surface_queue->lock);
496
497         return TBM_SURFACE_QUEUE_ERROR_NONE;
498 }
499
500 tbm_surface_queue_error_e
501 tbm_surface_queue_add_acquirable_cb(
502         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
503         void *data)
504 {
505         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
506                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
507
508         pthread_mutex_lock(&surface_queue->lock);
509
510         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
511
512         _notify_add(&surface_queue->acquirable_noti, acquirable_cb, data);
513
514         pthread_mutex_unlock(&surface_queue->lock);
515
516         return TBM_SURFACE_QUEUE_ERROR_NONE;
517 }
518
519 tbm_surface_queue_error_e
520 tbm_surface_queue_remove_acquirable_cb(
521         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
522         void *data)
523 {
524         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
525                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
526
527         pthread_mutex_lock(&surface_queue->lock);
528
529         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
530
531         _notify_remove(&surface_queue->acquirable_noti, acquirable_cb, data);
532
533         pthread_mutex_unlock(&surface_queue->lock);
534
535         return TBM_SURFACE_QUEUE_ERROR_NONE;
536 }
537
538 tbm_surface_queue_error_e
539 tbm_surface_queue_set_alloc_cb(
540         tbm_surface_queue_h surface_queue,
541         tbm_surface_alloc_cb alloc_cb,
542         tbm_surface_free_cb free_cb,
543         void *data)
544 {
545         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
546                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
547
548         pthread_mutex_lock(&surface_queue->lock);
549
550         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
551
552         surface_queue->alloc_cb = alloc_cb;
553         surface_queue->free_cb = free_cb;
554         surface_queue->alloc_cb_data = data;
555
556         pthread_mutex_unlock(&surface_queue->lock);
557
558         return TBM_SURFACE_QUEUE_ERROR_NONE;
559 }
560
561 int
562 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
563 {
564         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
565
566         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
567
568         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
569
570         return surface_queue->width;
571 }
572
573 int
574 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
575 {
576         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
577
578         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
579
580         return surface_queue->height;
581 }
582
583 int
584 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
585 {
586         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
587
588         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
589
590         return surface_queue->format;
591 }
592
593 int
594 tbm_surface_queue_get_size(tbm_surface_queue_h surface_queue)
595 {
596         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
597
598         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
599
600         return surface_queue->queue_size;
601 }
602
603 tbm_surface_queue_error_e
604 tbm_surface_queue_add_reset_cb(
605         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
606         void *data)
607 {
608         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
609                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
610
611         pthread_mutex_lock(&surface_queue->lock);
612
613         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
614
615         _notify_add(&surface_queue->reset_noti, reset_cb, data);
616
617         pthread_mutex_unlock(&surface_queue->lock);
618
619         return TBM_SURFACE_QUEUE_ERROR_NONE;
620 }
621
622 tbm_surface_queue_error_e
623 tbm_surface_queue_remove_reset_cb(
624         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
625         void *data)
626 {
627         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
628                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
629
630         pthread_mutex_lock(&surface_queue->lock);
631
632         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
633
634         _notify_remove(&surface_queue->reset_noti, reset_cb, data);
635
636         pthread_mutex_unlock(&surface_queue->lock);
637
638         return TBM_SURFACE_QUEUE_ERROR_NONE;
639 }
640
641 tbm_surface_queue_error_e
642 tbm_surface_queue_enqueue(tbm_surface_queue_h
643                           surface_queue, tbm_surface_h surface)
644 {
645         queue_node *node = NULL;
646         int queue_type;
647
648         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
649                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
650         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
651                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
652
653         pthread_mutex_lock(&surface_queue->lock);
654
655         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
656
657         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
658         if (node == NULL || queue_type != NODE_LIST) {
659                 TBM_LOG_E("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
660                         node, queue_type);
661                 pthread_mutex_unlock(&surface_queue->lock);
662                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
663         }
664
665         if (surface_queue->impl && surface_queue->impl->enqueue)
666                 surface_queue->impl->enqueue(surface_queue, node);
667         else
668                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
669
670         if (_queue_is_empty(&surface_queue->dirty_queue)) {
671                 pthread_mutex_unlock(&surface_queue->lock);
672                 return TBM_SURFACE_QUEUE_ERROR_NONE;
673         }
674
675         pthread_mutex_unlock(&surface_queue->lock);
676         pthread_cond_signal(&surface_queue->dirty_cond);
677
678         _notify_emit(surface_queue, &surface_queue->acquirable_noti);
679
680         return TBM_SURFACE_QUEUE_ERROR_NONE;
681 }
682
683 tbm_surface_queue_error_e
684 tbm_surface_queue_dequeue(tbm_surface_queue_h
685                           surface_queue, tbm_surface_h *surface)
686 {
687         queue_node *node = NULL;
688
689         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
690                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
691         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
692                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
693
694         pthread_mutex_lock(&surface_queue->lock);
695
696         if (surface_queue->impl && surface_queue->impl->dequeue)
697                 node = surface_queue->impl->dequeue(surface_queue);
698         else
699                 node = _tbm_surface_queue_dequeue(surface_queue);
700
701         if (node == NULL) {
702                 *surface = NULL;
703                 pthread_mutex_unlock(&surface_queue->lock);
704                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
705         }
706
707         if (node->surface == NULL) {
708                 *surface = NULL;
709                 TBM_LOG_E("_queue_node_pop_front  failed\n");
710                 pthread_mutex_unlock(&surface_queue->lock);
711                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
712         }
713
714         *surface = node->surface;
715
716         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
717
718         pthread_mutex_unlock(&surface_queue->lock);
719
720         return TBM_SURFACE_QUEUE_ERROR_NONE;
721 }
722
723 int
724 tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
725 {
726         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
727
728         pthread_mutex_lock(&surface_queue->lock);
729
730         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
731
732         if (_queue_is_empty(&surface_queue->free_queue)) {
733                 if (surface_queue->impl && surface_queue->impl->need_attach)
734                         surface_queue->impl->need_attach(surface_queue);
735         }
736
737         if (_queue_is_empty(&surface_queue->free_queue)) {
738                 if (wait) {
739                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
740                         pthread_mutex_unlock(&surface_queue->lock);
741                         return 1;
742                 }
743
744                 pthread_mutex_unlock(&surface_queue->lock);
745                 return 0;
746         }
747
748         pthread_mutex_unlock(&surface_queue->lock);
749
750         return 1;
751 }
752
753 tbm_surface_queue_error_e
754 tbm_surface_queue_release(tbm_surface_queue_h
755                           surface_queue, tbm_surface_h surface)
756 {
757         queue_node *node = NULL;
758         int queue_type;
759
760         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
761                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
762         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
763                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
764
765         pthread_mutex_lock(&surface_queue->lock);
766
767         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
768
769         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
770         if (node == NULL || queue_type != NODE_LIST) {
771                 TBM_LOG_E("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
772                         node, queue_type);
773                 pthread_mutex_unlock(&surface_queue->lock);
774                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
775         }
776
777         if (surface_queue->impl && surface_queue->impl->release)
778                 surface_queue->impl->release(surface_queue, node);
779         else
780                 _tbm_surface_queue_release(surface_queue, node, 1);
781
782         if (_queue_is_empty(&surface_queue->free_queue)) {
783                 pthread_mutex_unlock(&surface_queue->lock);
784                 return TBM_SURFACE_QUEUE_ERROR_NONE;
785         }
786
787         pthread_mutex_unlock(&surface_queue->lock);
788         pthread_cond_signal(&surface_queue->free_cond);
789
790         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
791
792         return TBM_SURFACE_QUEUE_ERROR_NONE;
793 }
794
795 tbm_surface_queue_error_e
796 tbm_surface_queue_acquire(tbm_surface_queue_h
797                           surface_queue, tbm_surface_h *surface)
798 {
799         queue_node *node = NULL;
800
801         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
802                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
803         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
804                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
805
806         pthread_mutex_lock(&surface_queue->lock);
807
808         if (surface_queue->impl && surface_queue->impl->acquire)
809                 node = surface_queue->impl->acquire(surface_queue);
810         else
811                 node = _tbm_surface_queue_acquire(surface_queue);
812
813         if (node == NULL) {
814                 *surface = NULL;
815                 pthread_mutex_unlock(&surface_queue->lock);
816                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
817         }
818
819         if (node->surface == NULL) {
820                 *surface = NULL;
821                 TBM_LOG_E("_queue_node_pop_front  failed\n");
822                 pthread_mutex_unlock(&surface_queue->lock);
823                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
824         }
825
826         *surface = node->surface;
827
828         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
829
830         pthread_mutex_unlock(&surface_queue->lock);
831
832         return TBM_SURFACE_QUEUE_ERROR_NONE;
833 }
834
835 int
836 tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
837 {
838         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
839
840         pthread_mutex_lock(&surface_queue->lock);
841
842         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
843
844         if (_queue_is_empty(&surface_queue->dirty_queue)) {
845                 if (wait) {
846                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
847                         pthread_mutex_unlock(&surface_queue->lock);
848                         return 1;
849                 }
850
851                 pthread_mutex_unlock(&surface_queue->lock);
852                 return 0;
853         }
854
855         pthread_mutex_unlock(&surface_queue->lock);
856
857         return 1;
858 }
859
860 void
861 tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
862 {
863         queue_node *node = NULL, *tmp = NULL;
864
865         TBM_RETURN_IF_FAIL(surface_queue != NULL);
866
867         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
868
869         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
870                 _queue_delete_node(surface_queue, node);
871         }
872
873         _notify_emit(surface_queue, &surface_queue->destory_noti);
874
875         if (surface_queue->impl && surface_queue->impl->destroy)
876                 surface_queue->impl->destroy(surface_queue);
877
878         _notify_remove_all(&surface_queue->destory_noti);
879         _notify_remove_all(&surface_queue->acquirable_noti);
880         _notify_remove_all(&surface_queue->dequeuable_noti);
881         _notify_remove_all(&surface_queue->reset_noti);
882
883         pthread_mutex_destroy(&surface_queue->lock);
884         free(surface_queue);
885 }
886
887 tbm_surface_queue_error_e
888 tbm_surface_queue_reset(tbm_surface_queue_h
889                         surface_queue, int width, int height, int format)
890 {
891         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
892                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
893
894         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
895
896         queue_node *node = NULL, *tmp = NULL;
897
898         if (width == surface_queue->width && height == surface_queue->height &&
899             format == surface_queue->format)
900                 return TBM_SURFACE_QUEUE_ERROR_NONE;
901
902         pthread_mutex_lock(&surface_queue->lock);
903
904         surface_queue->width = width;
905         surface_queue->height = height;
906         surface_queue->format = format;
907
908         /* Destory surface and Push to free_queue */
909         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
910                 _queue_delete_node(surface_queue, node);
911         }
912
913         /* Reset queue */
914         _queue_init(&surface_queue->free_queue);
915         _queue_init(&surface_queue->dirty_queue);
916         LIST_INITHEAD(&surface_queue->list);
917
918         if (surface_queue->impl && surface_queue->impl->reset)
919                 surface_queue->impl->reset(surface_queue);
920
921         pthread_mutex_unlock(&surface_queue->lock);
922         pthread_cond_signal(&surface_queue->free_cond);
923
924         _notify_emit(surface_queue, &surface_queue->reset_noti);
925
926         return TBM_SURFACE_QUEUE_ERROR_NONE;
927 }
928
929 tbm_surface_queue_error_e
930 tbm_surface_queue_flush(tbm_surface_queue_h surface_queue)
931 {
932         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
933                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
934
935         queue_node *node = NULL, *tmp = NULL;
936
937         pthread_mutex_lock(&surface_queue->lock);
938
939         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
940
941         /* Destory surface and Push to free_queue */
942         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
943                 _queue_delete_node(surface_queue, node);
944         }
945
946         /* Reset queue */
947         _queue_init(&surface_queue->free_queue);
948         _queue_init(&surface_queue->dirty_queue);
949         LIST_INITHEAD(&surface_queue->list);
950
951         if (surface_queue->impl && surface_queue->impl->reset)
952                 surface_queue->impl->reset(surface_queue);
953
954         _notify_emit(surface_queue, &surface_queue->reset_noti);
955
956         pthread_mutex_unlock(&surface_queue->lock);
957         pthread_cond_signal(&surface_queue->free_cond);
958
959         return TBM_SURFACE_QUEUE_ERROR_NONE;
960 }
961
962 tbm_surface_queue_error_e
963 tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
964                         tbm_surface_h *surfaces, int *num)
965 {
966         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
967                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
968         TBM_RETURN_VAL_IF_FAIL(num != NULL,
969                                TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
970
971         queue_node *node = NULL;
972         queue_node *tmp = NULL;
973
974         pthread_mutex_lock(&surface_queue->lock);
975
976         *num = 0;
977         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
978                 if (surfaces)
979                         surfaces[*num] = node->surface;
980
981                 *num = *num + 1;
982         }
983
984         pthread_mutex_unlock(&surface_queue->lock);
985
986         return TBM_SURFACE_QUEUE_ERROR_NONE;
987 }
988
989 typedef struct {
990         int queue_size;
991         int num_attached;
992         int flags;
993 } tbm_queue_default;
994
995 static void
996 __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
997 {
998         tbm_queue_default *data = surface_queue->impl_data;
999
1000         data->num_attached = 0;
1001 }
1002
1003 static void
1004 __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
1005 {
1006         tbm_queue_default *data = surface_queue->impl_data;
1007
1008         data->num_attached = 0;
1009 }
1010
1011 static void
1012 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
1013 {
1014         free(surface_queue->impl_data);
1015 }
1016
1017 static void
1018 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
1019 {
1020         tbm_queue_default *data = surface_queue->impl_data;
1021         tbm_surface_h surface;
1022
1023         if (data->queue_size == data->num_attached)
1024                 return;
1025
1026         if (surface_queue->alloc_cb) {
1027                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1028                 TBM_RETURN_IF_FAIL(surface != NULL);
1029                 tbm_surface_internal_ref(surface);
1030         } else {
1031                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1032                                 surface_queue->height,
1033                                 surface_queue->format,
1034                                 data->flags);
1035                 TBM_RETURN_IF_FAIL(surface != NULL);
1036         }
1037
1038         _tbm_surface_queue_attach(surface_queue, surface);
1039         tbm_surface_internal_unref(surface);
1040         data->num_attached++;
1041 }
1042
1043 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1044         __tbm_queue_default_init,
1045         __tbm_queue_default_reset,
1046         __tbm_queue_default_destroy,
1047         __tbm_queue_default_need_attach,
1048         NULL,                           /*__tbm_queue_default_enqueue*/
1049         NULL,                           /*__tbm_queue_default_release*/
1050         NULL,                           /*__tbm_queue_default_dequeue*/
1051         NULL,                           /*__tbm_queue_default_acquire*/
1052 };
1053
1054 tbm_surface_queue_h
1055 tbm_surface_queue_create(int queue_size, int width,
1056                          int height, int format, int flags)
1057 {
1058         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1059         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1060         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1061         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1062
1063         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1064                                             sizeof(struct _tbm_surface_queue));
1065         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1066
1067         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1068
1069         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1070                                   sizeof(tbm_queue_default));
1071         if (data == NULL) {
1072                 free(surface_queue);
1073                 return NULL;
1074         }
1075
1076         data->queue_size = queue_size;
1077         data->flags = flags;
1078         _tbm_surface_queue_init(surface_queue,
1079                                 data->queue_size,
1080                                 width, height, format,
1081                                 &tbm_queue_default_impl, data);
1082
1083         return surface_queue;
1084 }
1085
1086 typedef struct {
1087         int queue_size;
1088         int num_attached;
1089         int flags;
1090         queue dequeue_list;
1091 } tbm_queue_sequence;
1092
1093 static void
1094 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1095 {
1096         tbm_queue_sequence *data = surface_queue->impl_data;
1097
1098         data->num_attached = 0;
1099         _queue_init(&data->dequeue_list);
1100 }
1101
1102 static void
1103 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1104 {
1105         tbm_queue_sequence *data = surface_queue->impl_data;
1106
1107         data->num_attached = 0;
1108         _queue_init(&data->dequeue_list);
1109 }
1110
1111 static void
1112 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1113 {
1114         free(surface_queue->impl_data);
1115 }
1116
1117 static void
1118 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1119 {
1120         tbm_queue_sequence *data = surface_queue->impl_data;
1121         tbm_surface_h surface;
1122
1123         if (data->queue_size == data->num_attached)
1124                 return;
1125
1126         if (surface_queue->alloc_cb) {
1127                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1128                 TBM_RETURN_IF_FAIL(surface != NULL);
1129                 tbm_surface_internal_ref(surface);
1130         } else {
1131                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1132                                 surface_queue->height,
1133                                 surface_queue->format,
1134                                 data->flags);
1135                 TBM_RETURN_IF_FAIL(surface != NULL);
1136         }
1137
1138         _tbm_surface_queue_attach(surface_queue, surface);
1139         tbm_surface_internal_unref(surface);
1140         data->num_attached++;
1141 }
1142
1143 static void
1144 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1145                              queue_node *node)
1146 {
1147         tbm_queue_sequence *data = surface_queue->impl_data;
1148         queue_node *next = NULL;
1149         queue_node *tmp = NULL;
1150
1151         node->priv_flags = 0;
1152
1153         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1154                 if (next->priv_flags)
1155                         break;
1156                 _queue_node_pop(&data->dequeue_list, next);
1157                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1158         }
1159 }
1160
1161 static queue_node *
1162 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1163                              surface_queue)
1164 {
1165         tbm_queue_sequence *data = surface_queue->impl_data;
1166         queue_node *node = NULL;
1167
1168         node = _tbm_surface_queue_dequeue(surface_queue);
1169         if (node) {
1170                 _queue_node_push_back(&data->dequeue_list, node);
1171                 node->priv_flags = 1;
1172         }
1173
1174         return node;
1175 }
1176
1177 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1178         __tbm_queue_sequence_init,
1179         __tbm_queue_sequence_reset,
1180         __tbm_queue_sequence_destroy,
1181         __tbm_queue_sequence_need_attach,
1182         __tbm_queue_sequence_enqueue,
1183         NULL,                                   /*__tbm_queue_sequence_release*/
1184         __tbm_queue_sequence_dequeue,
1185         NULL,                                   /*__tbm_queue_sequence_acquire*/
1186 };
1187
1188 tbm_surface_queue_h
1189 tbm_surface_queue_sequence_create(int queue_size, int width,
1190                                   int height, int format, int flags)
1191 {
1192         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1193         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1194         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1195         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1196
1197         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1198                                             sizeof(struct _tbm_surface_queue));
1199         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1200
1201         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1202
1203         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1204                                    sizeof(tbm_queue_sequence));
1205         if (data == NULL) {
1206                 free(surface_queue);
1207                 return NULL;
1208         }
1209
1210         data->queue_size = queue_size;
1211         data->flags = flags;
1212         _tbm_surface_queue_init(surface_queue,
1213                                 data->queue_size,
1214                                 width, height, format,
1215                                 &tbm_queue_sequence_impl, data);
1216
1217         return surface_queue;
1218 }
1219 /* LCOV_EXCL_STOP */