Add check condition for queue
[platform/core/uifw/libtbm.git] / src / tbm_surface_queue.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "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 static int
335 _tbm_surface_queue_get_node_count(tbm_surface_queue_h surface_queue, Queue_Node_Type type)
336 {
337         queue_node *node = NULL;
338         queue_node *tmp = NULL;
339         int count = 0;
340
341         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
342                 if (node->type == type)
343                         count++;
344         }
345
346         return count;
347 }
348
349 void
350 _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue,
351                           tbm_surface_h surface)
352 {
353         queue_node *node = NULL;
354
355         node = _queue_node_create();
356         TBM_RETURN_IF_FAIL(node != NULL);
357
358         tbm_surface_internal_ref(surface);
359         node->surface = surface;
360
361         LIST_ADDTAIL(&node->link, &surface_queue->list);
362         _queue_node_push_back(&surface_queue->free_queue, node);
363 }
364
365 void
366 _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue,
367                           tbm_surface_h surface)
368 {
369         queue_node *node = NULL;
370         int queue_type;
371
372         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
373         if (node)
374                 _queue_delete_node(surface_queue, node);
375 }
376
377 void
378 _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue,
379                            queue_node *node, int push_back)
380 {
381         if (push_back)
382                 _queue_node_push_back(&surface_queue->dirty_queue, node);
383         else
384                 _queue_node_push_front(&surface_queue->dirty_queue, node);
385 }
386
387 queue_node *
388 _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
389 {
390         queue_node *node = NULL;
391
392         if (_queue_is_empty(&surface_queue->free_queue)) {
393                 if (surface_queue->impl && surface_queue->impl->need_attach)
394                         surface_queue->impl->need_attach(surface_queue);
395
396                 if (_queue_is_empty(&surface_queue->free_queue))
397                         return NULL;
398         }
399
400         node = _queue_node_pop_front(&surface_queue->free_queue);
401
402         return node;
403 }
404
405 queue_node *
406 _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
407 {
408         queue_node *node = NULL;
409
410         if (_queue_is_empty(&surface_queue->dirty_queue))
411                 return NULL;
412
413         node = _queue_node_pop_front(&surface_queue->dirty_queue);
414
415         return node;
416 }
417
418 void
419 _tbm_surface_queue_release(tbm_surface_queue_h surface_queue,
420                            queue_node *node, int push_back)
421 {
422         if (push_back)
423                 _queue_node_push_back(&surface_queue->free_queue, node);
424         else
425                 _queue_node_push_front(&surface_queue->free_queue, node);
426 }
427
428 void
429 _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
430                         int queue_size,
431                         int width, int height, int format,
432                         const tbm_surface_queue_interface *impl, void *data)
433 {
434         TBM_RETURN_IF_FAIL(surface_queue != NULL);
435         TBM_RETURN_IF_FAIL(impl != NULL);
436
437         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
438
439         pthread_mutex_init(&surface_queue->lock, NULL);
440         pthread_cond_init(&surface_queue->free_cond, NULL);
441         pthread_cond_init(&surface_queue->dirty_cond, NULL);
442
443         surface_queue->queue_size = queue_size;
444         surface_queue->width = width;
445         surface_queue->height = height;
446         surface_queue->format = format;
447         surface_queue->impl = impl;
448         surface_queue->impl_data = data;
449
450         _queue_init(&surface_queue->free_queue);
451         _queue_init(&surface_queue->dirty_queue);
452         LIST_INITHEAD(&surface_queue->list);
453
454         LIST_INITHEAD(&surface_queue->destory_noti);
455         LIST_INITHEAD(&surface_queue->acquirable_noti);
456         LIST_INITHEAD(&surface_queue->dequeuable_noti);
457         LIST_INITHEAD(&surface_queue->reset_noti);
458
459         if (surface_queue->impl && surface_queue->impl->init)
460                 surface_queue->impl->init(surface_queue);
461 }
462
463 tbm_surface_queue_error_e
464 tbm_surface_queue_add_destroy_cb(
465         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
466         void *data)
467 {
468         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
469                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
470
471         pthread_mutex_lock(&surface_queue->lock);
472
473         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
474
475         _notify_add(&surface_queue->destory_noti, destroy_cb, data);
476
477         pthread_mutex_unlock(&surface_queue->lock);
478
479         return TBM_SURFACE_QUEUE_ERROR_NONE;
480 }
481
482 tbm_surface_queue_error_e
483 tbm_surface_queue_remove_destroy_cb(
484         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
485         void *data)
486 {
487         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
488                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
489
490         pthread_mutex_lock(&surface_queue->lock);
491
492         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
493
494         _notify_remove(&surface_queue->destory_noti, destroy_cb, data);
495
496         pthread_mutex_unlock(&surface_queue->lock);
497
498         return TBM_SURFACE_QUEUE_ERROR_NONE;
499 }
500
501 tbm_surface_queue_error_e
502 tbm_surface_queue_add_dequeuable_cb(
503         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
504         void *data)
505 {
506         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
507                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
508
509         pthread_mutex_lock(&surface_queue->lock);
510
511         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
512
513         _notify_add(&surface_queue->dequeuable_noti, dequeuable_cb, data);
514
515         pthread_mutex_unlock(&surface_queue->lock);
516
517         return TBM_SURFACE_QUEUE_ERROR_NONE;
518 }
519
520 tbm_surface_queue_error_e
521 tbm_surface_queue_remove_dequeuable_cb(
522         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
523         void *data)
524 {
525         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
526                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
527
528         pthread_mutex_lock(&surface_queue->lock);
529
530         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
531
532         _notify_remove(&surface_queue->dequeuable_noti, dequeuable_cb, data);
533
534         pthread_mutex_unlock(&surface_queue->lock);
535
536         return TBM_SURFACE_QUEUE_ERROR_NONE;
537 }
538
539 tbm_surface_queue_error_e
540 tbm_surface_queue_add_acquirable_cb(
541         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
542         void *data)
543 {
544         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
545                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
546
547         pthread_mutex_lock(&surface_queue->lock);
548
549         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
550
551         _notify_add(&surface_queue->acquirable_noti, acquirable_cb, data);
552
553         pthread_mutex_unlock(&surface_queue->lock);
554
555         return TBM_SURFACE_QUEUE_ERROR_NONE;
556 }
557
558 tbm_surface_queue_error_e
559 tbm_surface_queue_remove_acquirable_cb(
560         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
561         void *data)
562 {
563         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
564                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
565
566         pthread_mutex_lock(&surface_queue->lock);
567
568         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
569
570         _notify_remove(&surface_queue->acquirable_noti, acquirable_cb, data);
571
572         pthread_mutex_unlock(&surface_queue->lock);
573
574         return TBM_SURFACE_QUEUE_ERROR_NONE;
575 }
576
577 tbm_surface_queue_error_e
578 tbm_surface_queue_set_alloc_cb(
579         tbm_surface_queue_h surface_queue,
580         tbm_surface_alloc_cb alloc_cb,
581         tbm_surface_free_cb free_cb,
582         void *data)
583 {
584         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
585                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
586
587         pthread_mutex_lock(&surface_queue->lock);
588
589         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
590
591         surface_queue->alloc_cb = alloc_cb;
592         surface_queue->free_cb = free_cb;
593         surface_queue->alloc_cb_data = data;
594
595         pthread_mutex_unlock(&surface_queue->lock);
596
597         return TBM_SURFACE_QUEUE_ERROR_NONE;
598 }
599
600 int
601 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
602 {
603         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
604
605         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
606
607         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
608
609         return surface_queue->width;
610 }
611
612 int
613 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
614 {
615         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
616
617         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
618
619         return surface_queue->height;
620 }
621
622 int
623 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
624 {
625         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
626
627         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
628
629         return surface_queue->format;
630 }
631
632 int
633 tbm_surface_queue_get_size(tbm_surface_queue_h surface_queue)
634 {
635         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
636
637         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
638
639         return surface_queue->queue_size;
640 }
641
642 tbm_surface_queue_error_e
643 tbm_surface_queue_add_reset_cb(
644         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
645         void *data)
646 {
647         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
648                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
649
650         pthread_mutex_lock(&surface_queue->lock);
651
652         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
653
654         _notify_add(&surface_queue->reset_noti, reset_cb, data);
655
656         pthread_mutex_unlock(&surface_queue->lock);
657
658         return TBM_SURFACE_QUEUE_ERROR_NONE;
659 }
660
661 tbm_surface_queue_error_e
662 tbm_surface_queue_remove_reset_cb(
663         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
664         void *data)
665 {
666         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
667                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
668
669         pthread_mutex_lock(&surface_queue->lock);
670
671         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
672
673         _notify_remove(&surface_queue->reset_noti, reset_cb, data);
674
675         pthread_mutex_unlock(&surface_queue->lock);
676
677         return TBM_SURFACE_QUEUE_ERROR_NONE;
678 }
679
680 tbm_surface_queue_error_e
681 tbm_surface_queue_enqueue(tbm_surface_queue_h
682                           surface_queue, tbm_surface_h surface)
683 {
684         queue_node *node = NULL;
685         int queue_type;
686
687         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
688                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
689         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
690                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
691
692         if (b_dump_queue)
693                 tbm_surface_internal_dump_buffer(surface, "enqueue");
694
695         pthread_mutex_lock(&surface_queue->lock);
696
697         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
698
699         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
700         if (node == NULL || queue_type != NODE_LIST) {
701                 TBM_LOG_E("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
702                         node, queue_type);
703                 pthread_mutex_unlock(&surface_queue->lock);
704                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
705         }
706
707         if (surface_queue->impl && surface_queue->impl->enqueue)
708                 surface_queue->impl->enqueue(surface_queue, node);
709         else
710                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
711
712         if (_queue_is_empty(&surface_queue->dirty_queue)) {
713                 pthread_mutex_unlock(&surface_queue->lock);
714                 return TBM_SURFACE_QUEUE_ERROR_NONE;
715         }
716
717         node->type = QUEUE_NODE_TYPE_ENQUEUE;
718
719         pthread_mutex_unlock(&surface_queue->lock);
720         pthread_cond_signal(&surface_queue->dirty_cond);
721
722         _notify_emit(surface_queue, &surface_queue->acquirable_noti);
723
724         return TBM_SURFACE_QUEUE_ERROR_NONE;
725 }
726
727 tbm_surface_queue_error_e
728 tbm_surface_queue_dequeue(tbm_surface_queue_h
729                           surface_queue, tbm_surface_h *surface)
730 {
731         queue_node *node = NULL;
732
733         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
734                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
735         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
736                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
737
738         pthread_mutex_lock(&surface_queue->lock);
739
740         if (surface_queue->impl && surface_queue->impl->dequeue)
741                 node = surface_queue->impl->dequeue(surface_queue);
742         else
743                 node = _tbm_surface_queue_dequeue(surface_queue);
744
745         if (node == NULL) {
746                 *surface = NULL;
747                 pthread_mutex_unlock(&surface_queue->lock);
748                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
749         }
750
751         if (node->surface == NULL) {
752                 *surface = NULL;
753                 TBM_LOG_E("_queue_node_pop_front  failed\n");
754                 pthread_mutex_unlock(&surface_queue->lock);
755                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
756         }
757
758         node->type = QUEUE_NODE_TYPE_DEQUEUE;
759         *surface = node->surface;
760
761         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
762
763         pthread_mutex_unlock(&surface_queue->lock);
764
765         return TBM_SURFACE_QUEUE_ERROR_NONE;
766 }
767
768 int
769 tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
770 {
771         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
772
773         pthread_mutex_lock(&surface_queue->lock);
774
775         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
776
777         if (_queue_is_empty(&surface_queue->free_queue)) {
778                 if (surface_queue->impl && surface_queue->impl->need_attach)
779                         surface_queue->impl->need_attach(surface_queue);
780         }
781
782         if (_queue_is_empty(&surface_queue->free_queue)) {
783                 if (wait &&
784                         _tbm_surface_queue_get_node_count(surface_queue,QUEUE_NODE_TYPE_ACQUIRE)) {
785
786                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
787                         pthread_mutex_unlock(&surface_queue->lock);
788                         return 1;
789                 }
790
791                 pthread_mutex_unlock(&surface_queue->lock);
792                 return 0;
793         }
794
795         pthread_mutex_unlock(&surface_queue->lock);
796
797         return 1;
798 }
799
800 tbm_surface_queue_error_e
801 tbm_surface_queue_release(tbm_surface_queue_h
802                           surface_queue, tbm_surface_h surface)
803 {
804         queue_node *node = NULL;
805         int queue_type;
806
807         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
808                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
809         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
810                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
811
812         pthread_mutex_lock(&surface_queue->lock);
813
814         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
815
816         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
817         if (node == NULL || queue_type != NODE_LIST) {
818                 TBM_LOG_E("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
819                         node, queue_type);
820                 pthread_mutex_unlock(&surface_queue->lock);
821                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
822         }
823
824         if (surface_queue->impl && surface_queue->impl->release)
825                 surface_queue->impl->release(surface_queue, node);
826         else
827                 _tbm_surface_queue_release(surface_queue, node, 1);
828
829         if (_queue_is_empty(&surface_queue->free_queue)) {
830                 pthread_mutex_unlock(&surface_queue->lock);
831                 return TBM_SURFACE_QUEUE_ERROR_NONE;
832         }
833
834         node->type = QUEUE_NODE_TYPE_RELEASE;
835
836         pthread_mutex_unlock(&surface_queue->lock);
837         pthread_cond_signal(&surface_queue->free_cond);
838
839         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
840
841         return TBM_SURFACE_QUEUE_ERROR_NONE;
842 }
843
844 tbm_surface_queue_error_e
845 tbm_surface_queue_acquire(tbm_surface_queue_h
846                           surface_queue, tbm_surface_h *surface)
847 {
848         queue_node *node = NULL;
849
850         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
851                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
852         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
853                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
854
855         pthread_mutex_lock(&surface_queue->lock);
856
857         if (surface_queue->impl && surface_queue->impl->acquire)
858                 node = surface_queue->impl->acquire(surface_queue);
859         else
860                 node = _tbm_surface_queue_acquire(surface_queue);
861
862         if (node == NULL) {
863                 *surface = NULL;
864                 pthread_mutex_unlock(&surface_queue->lock);
865                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
866         }
867
868         if (node->surface == NULL) {
869                 *surface = NULL;
870                 TBM_LOG_E("_queue_node_pop_front  failed\n");
871                 pthread_mutex_unlock(&surface_queue->lock);
872                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
873         }
874
875         node->type = QUEUE_NODE_TYPE_ACQUIRE;
876
877         *surface = node->surface;
878
879         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
880
881         pthread_mutex_unlock(&surface_queue->lock);
882
883         if (b_dump_queue)
884                 tbm_surface_internal_dump_buffer(*surface, "acquire");
885
886         return TBM_SURFACE_QUEUE_ERROR_NONE;
887 }
888
889 int
890 tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
891 {
892         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
893
894         pthread_mutex_lock(&surface_queue->lock);
895
896         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
897
898         if (_queue_is_empty(&surface_queue->dirty_queue)) {
899                 if (wait &&
900                         _tbm_surface_queue_get_node_count(surface_queue,QUEUE_NODE_TYPE_DEQUEUE)) {
901
902                         if (!_queue_has_node_type(surface_queue, QUEUE_NODE_TYPE_DEQUEUE)) {
903                                 TBM_LOG_E("Deosn't have dequeue type node\n");
904                                 pthread_mutex_unlock(&surface_queue->lock);
905                                 return 0;
906                         }
907
908                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
909                         pthread_mutex_unlock(&surface_queue->lock);
910                         return 1;
911                 }
912
913                 pthread_mutex_unlock(&surface_queue->lock);
914                 return 0;
915         }
916
917         pthread_mutex_unlock(&surface_queue->lock);
918
919         return 1;
920 }
921
922 void
923 tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
924 {
925         queue_node *node = NULL, *tmp = NULL;
926
927         TBM_RETURN_IF_FAIL(surface_queue != NULL);
928
929         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
930
931         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
932                 _queue_delete_node(surface_queue, node);
933         }
934
935         _notify_emit(surface_queue, &surface_queue->destory_noti);
936
937         if (surface_queue->impl && surface_queue->impl->destroy)
938                 surface_queue->impl->destroy(surface_queue);
939
940         _notify_remove_all(&surface_queue->destory_noti);
941         _notify_remove_all(&surface_queue->acquirable_noti);
942         _notify_remove_all(&surface_queue->dequeuable_noti);
943         _notify_remove_all(&surface_queue->reset_noti);
944
945         pthread_mutex_destroy(&surface_queue->lock);
946         free(surface_queue);
947 }
948
949 tbm_surface_queue_error_e
950 tbm_surface_queue_reset(tbm_surface_queue_h
951                         surface_queue, int width, int height, int format)
952 {
953         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
954                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
955
956         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
957
958         queue_node *node = NULL, *tmp = NULL;
959
960         if (width == surface_queue->width && height == surface_queue->height &&
961             format == surface_queue->format)
962                 return TBM_SURFACE_QUEUE_ERROR_NONE;
963
964         pthread_mutex_lock(&surface_queue->lock);
965
966         surface_queue->width = width;
967         surface_queue->height = height;
968         surface_queue->format = format;
969
970         /* Destory surface and Push to free_queue */
971         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
972                 _queue_delete_node(surface_queue, node);
973         }
974
975         /* Reset queue */
976         _queue_init(&surface_queue->free_queue);
977         _queue_init(&surface_queue->dirty_queue);
978         LIST_INITHEAD(&surface_queue->list);
979
980         if (surface_queue->impl && surface_queue->impl->reset)
981                 surface_queue->impl->reset(surface_queue);
982
983         pthread_mutex_unlock(&surface_queue->lock);
984         pthread_cond_signal(&surface_queue->free_cond);
985
986         _notify_emit(surface_queue, &surface_queue->reset_noti);
987
988         return TBM_SURFACE_QUEUE_ERROR_NONE;
989 }
990
991 tbm_surface_queue_error_e
992 tbm_surface_queue_flush(tbm_surface_queue_h surface_queue)
993 {
994         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
995                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
996
997         queue_node *node = NULL, *tmp = NULL;
998
999         pthread_mutex_lock(&surface_queue->lock);
1000
1001         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1002
1003         /* Destory surface and Push to free_queue */
1004         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1005                 _queue_delete_node(surface_queue, node);
1006         }
1007
1008         /* Reset queue */
1009         _queue_init(&surface_queue->free_queue);
1010         _queue_init(&surface_queue->dirty_queue);
1011         LIST_INITHEAD(&surface_queue->list);
1012
1013         if (surface_queue->impl && surface_queue->impl->reset)
1014                 surface_queue->impl->reset(surface_queue);
1015
1016         _notify_emit(surface_queue, &surface_queue->reset_noti);
1017
1018         pthread_mutex_unlock(&surface_queue->lock);
1019         pthread_cond_signal(&surface_queue->free_cond);
1020
1021         return TBM_SURFACE_QUEUE_ERROR_NONE;
1022 }
1023
1024 tbm_surface_queue_error_e
1025 tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
1026                         tbm_surface_h *surfaces, int *num)
1027 {
1028         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
1029                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
1030         TBM_RETURN_VAL_IF_FAIL(num != NULL,
1031                                TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
1032
1033         queue_node *node = NULL;
1034         queue_node *tmp = NULL;
1035
1036         pthread_mutex_lock(&surface_queue->lock);
1037
1038         *num = 0;
1039         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
1040                 if (surfaces)
1041                         surfaces[*num] = node->surface;
1042
1043                 *num = *num + 1;
1044         }
1045
1046         pthread_mutex_unlock(&surface_queue->lock);
1047
1048         return TBM_SURFACE_QUEUE_ERROR_NONE;
1049 }
1050
1051 typedef struct {
1052         int queue_size;
1053         int num_attached;
1054         int flags;
1055 } tbm_queue_default;
1056
1057 static void
1058 __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
1059 {
1060         tbm_queue_default *data = surface_queue->impl_data;
1061
1062         data->num_attached = 0;
1063 }
1064
1065 static void
1066 __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
1067 {
1068         tbm_queue_default *data = surface_queue->impl_data;
1069
1070         data->num_attached = 0;
1071 }
1072
1073 static void
1074 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
1075 {
1076         free(surface_queue->impl_data);
1077 }
1078
1079 static void
1080 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
1081 {
1082         tbm_queue_default *data = surface_queue->impl_data;
1083         tbm_surface_h surface;
1084
1085         if (data->queue_size == data->num_attached)
1086                 return;
1087
1088         if (surface_queue->alloc_cb) {
1089                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1090                 TBM_RETURN_IF_FAIL(surface != NULL);
1091                 tbm_surface_internal_ref(surface);
1092         } else {
1093                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1094                                 surface_queue->height,
1095                                 surface_queue->format,
1096                                 data->flags);
1097                 TBM_RETURN_IF_FAIL(surface != NULL);
1098         }
1099
1100         _tbm_surface_queue_attach(surface_queue, surface);
1101         tbm_surface_internal_unref(surface);
1102         data->num_attached++;
1103 }
1104
1105 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1106         __tbm_queue_default_init,
1107         __tbm_queue_default_reset,
1108         __tbm_queue_default_destroy,
1109         __tbm_queue_default_need_attach,
1110         NULL,                           /*__tbm_queue_default_enqueue*/
1111         NULL,                           /*__tbm_queue_default_release*/
1112         NULL,                           /*__tbm_queue_default_dequeue*/
1113         NULL,                           /*__tbm_queue_default_acquire*/
1114 };
1115
1116 tbm_surface_queue_h
1117 tbm_surface_queue_create(int queue_size, int width,
1118                          int height, int format, int flags)
1119 {
1120         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1121         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1122         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1123         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1124
1125         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1126                                             sizeof(struct _tbm_surface_queue));
1127         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1128
1129         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1130
1131         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1132                                   sizeof(tbm_queue_default));
1133         if (data == NULL) {
1134                 free(surface_queue);
1135                 return NULL;
1136         }
1137
1138         data->queue_size = queue_size;
1139         data->flags = flags;
1140         _tbm_surface_queue_init(surface_queue,
1141                                 data->queue_size,
1142                                 width, height, format,
1143                                 &tbm_queue_default_impl, data);
1144
1145         return surface_queue;
1146 }
1147
1148 typedef struct {
1149         int queue_size;
1150         int num_attached;
1151         int flags;
1152         queue dequeue_list;
1153 } tbm_queue_sequence;
1154
1155 static void
1156 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1157 {
1158         tbm_queue_sequence *data = surface_queue->impl_data;
1159
1160         data->num_attached = 0;
1161         _queue_init(&data->dequeue_list);
1162 }
1163
1164 static void
1165 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1166 {
1167         tbm_queue_sequence *data = surface_queue->impl_data;
1168
1169         data->num_attached = 0;
1170         _queue_init(&data->dequeue_list);
1171 }
1172
1173 static void
1174 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1175 {
1176         free(surface_queue->impl_data);
1177 }
1178
1179 static void
1180 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1181 {
1182         tbm_queue_sequence *data = surface_queue->impl_data;
1183         tbm_surface_h surface;
1184
1185         if (data->queue_size == data->num_attached)
1186                 return;
1187
1188         if (surface_queue->alloc_cb) {
1189                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1190                 TBM_RETURN_IF_FAIL(surface != NULL);
1191                 tbm_surface_internal_ref(surface);
1192         } else {
1193                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1194                                 surface_queue->height,
1195                                 surface_queue->format,
1196                                 data->flags);
1197                 TBM_RETURN_IF_FAIL(surface != NULL);
1198         }
1199
1200         _tbm_surface_queue_attach(surface_queue, surface);
1201         tbm_surface_internal_unref(surface);
1202         data->num_attached++;
1203 }
1204
1205 static void
1206 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1207                              queue_node *node)
1208 {
1209         tbm_queue_sequence *data = surface_queue->impl_data;
1210         queue_node *next = NULL;
1211         queue_node *tmp = NULL;
1212
1213         node->priv_flags = 0;
1214
1215         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1216                 if (next->priv_flags)
1217                         break;
1218                 _queue_node_pop(&data->dequeue_list, next);
1219                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1220         }
1221 }
1222
1223 static queue_node *
1224 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1225                              surface_queue)
1226 {
1227         tbm_queue_sequence *data = surface_queue->impl_data;
1228         queue_node *node = NULL;
1229
1230         node = _tbm_surface_queue_dequeue(surface_queue);
1231         if (node) {
1232                 _queue_node_push_back(&data->dequeue_list, node);
1233                 node->priv_flags = 1;
1234         }
1235
1236         return node;
1237 }
1238
1239 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1240         __tbm_queue_sequence_init,
1241         __tbm_queue_sequence_reset,
1242         __tbm_queue_sequence_destroy,
1243         __tbm_queue_sequence_need_attach,
1244         __tbm_queue_sequence_enqueue,
1245         NULL,                                   /*__tbm_queue_sequence_release*/
1246         __tbm_queue_sequence_dequeue,
1247         NULL,                                   /*__tbm_queue_sequence_acquire*/
1248 };
1249
1250 tbm_surface_queue_h
1251 tbm_surface_queue_sequence_create(int queue_size, int width,
1252                                   int height, int format, int flags)
1253 {
1254         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1255         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1256         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1257         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1258
1259         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1260                                             sizeof(struct _tbm_surface_queue));
1261         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1262
1263         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1264
1265         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1266                                    sizeof(tbm_queue_sequence));
1267         if (data == NULL) {
1268                 free(surface_queue);
1269                 return NULL;
1270         }
1271
1272         data->queue_size = queue_size;
1273         data->flags = flags;
1274         _tbm_surface_queue_init(surface_queue,
1275                                 data->queue_size,
1276                                 width, height, format,
1277                                 &tbm_queue_sequence_impl, data);
1278
1279         return surface_queue;
1280 }
1281 /* LCOV_EXCL_STOP */