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