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