Apply tizen coding rule
[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->reset_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 tbm_surface_queue_error_e
959 tbm_surface_queue_get_surfaces(tbm_surface_queue_h surface_queue,
960                         tbm_surface_h *surfaces, int *num)
961 {
962         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
963                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
964         TBM_RETURN_VAL_IF_FAIL(num != NULL,
965                                TBM_SURFACE_QUEUE_ERROR_INVALID_PARAMETER);
966
967         queue_node *node = NULL;
968         queue_node *tmp = NULL;
969
970         pthread_mutex_lock(&surface_queue->lock);
971
972         *num = 0;
973         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
974                 if (surfaces)
975                         surfaces[*num] = node->surface;
976
977                 *num = *num + 1;
978         }
979
980         pthread_mutex_unlock(&surface_queue->lock);
981
982         return TBM_SURFACE_QUEUE_ERROR_NONE;
983 }
984
985 typedef struct {
986         int queue_size;
987         int num_attached;
988         int flags;
989 } tbm_queue_default;
990
991 static void
992 __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
993 {
994         tbm_queue_default *data = surface_queue->impl_data;
995
996         data->num_attached = 0;
997 }
998
999 static void
1000 __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
1001 {
1002         tbm_queue_default *data = surface_queue->impl_data;
1003
1004         data->num_attached = 0;
1005 }
1006
1007 static void
1008 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
1009 {
1010         free(surface_queue->impl_data);
1011 }
1012
1013 static void
1014 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
1015 {
1016         tbm_queue_default *data = surface_queue->impl_data;
1017         tbm_surface_h surface;
1018
1019         if (data->queue_size == data->num_attached)
1020                 return;
1021
1022         if (surface_queue->alloc_cb) {
1023                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1024                 TBM_RETURN_IF_FAIL(surface != NULL);
1025                 tbm_surface_internal_ref(surface);
1026         } else {
1027                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1028                                 surface_queue->height,
1029                                 surface_queue->format,
1030                                 data->flags);
1031                 TBM_RETURN_IF_FAIL(surface != NULL);
1032         }
1033
1034         _tbm_surface_queue_attach(surface_queue, surface);
1035         tbm_surface_internal_unref(surface);
1036         data->num_attached++;
1037 }
1038
1039 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1040         __tbm_queue_default_init,
1041         __tbm_queue_default_reset,
1042         __tbm_queue_default_destroy,
1043         __tbm_queue_default_need_attach,
1044         NULL,                           /*__tbm_queue_default_enqueue*/
1045         NULL,                           /*__tbm_queue_default_release*/
1046         NULL,                           /*__tbm_queue_default_dequeue*/
1047         NULL,                           /*__tbm_queue_default_acquire*/
1048 };
1049
1050 tbm_surface_queue_h
1051 tbm_surface_queue_create(int queue_size, int width,
1052                          int height, int format, int flags)
1053 {
1054         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1055         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1056         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1057         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1058
1059         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1060                                             sizeof(struct _tbm_surface_queue));
1061         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1062
1063         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1064
1065         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1066                                   sizeof(tbm_queue_default));
1067         if (data == NULL) {
1068                 free(surface_queue);
1069                 return NULL;
1070         }
1071
1072         data->queue_size = queue_size;
1073         data->flags = flags;
1074         _tbm_surface_queue_init(surface_queue,
1075                                 data->queue_size,
1076                                 width, height, format,
1077                                 &tbm_queue_default_impl, data);
1078
1079         return surface_queue;
1080 }
1081
1082 typedef struct {
1083         int queue_size;
1084         int num_attached;
1085         int flags;
1086         queue dequeue_list;
1087 } tbm_queue_sequence;
1088
1089 static void
1090 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1091 {
1092         tbm_queue_sequence *data = surface_queue->impl_data;
1093
1094         data->num_attached = 0;
1095         _queue_init(&data->dequeue_list);
1096 }
1097
1098 static void
1099 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1100 {
1101         tbm_queue_sequence *data = surface_queue->impl_data;
1102
1103         data->num_attached = 0;
1104         _queue_init(&data->dequeue_list);
1105 }
1106
1107 static void
1108 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1109 {
1110         free(surface_queue->impl_data);
1111 }
1112
1113 static void
1114 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1115 {
1116         tbm_queue_sequence *data = surface_queue->impl_data;
1117         tbm_surface_h surface;
1118
1119         if (data->queue_size == data->num_attached)
1120                 return;
1121
1122         if (surface_queue->alloc_cb) {
1123                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1124                 TBM_RETURN_IF_FAIL(surface != NULL);
1125                 tbm_surface_internal_ref(surface);
1126         } else {
1127                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1128                                 surface_queue->height,
1129                                 surface_queue->format,
1130                                 data->flags);
1131                 TBM_RETURN_IF_FAIL(surface != NULL);
1132         }
1133
1134         _tbm_surface_queue_attach(surface_queue, surface);
1135         tbm_surface_internal_unref(surface);
1136         data->num_attached++;
1137 }
1138
1139 static void
1140 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1141                              queue_node *node)
1142 {
1143         tbm_queue_sequence *data = surface_queue->impl_data;
1144         queue_node *next = NULL;
1145         queue_node *tmp = NULL;
1146
1147         node->priv_flags = 0;
1148
1149         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1150                 if (next->priv_flags)
1151                         break;
1152                 _queue_node_pop(&data->dequeue_list, next);
1153                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1154         }
1155 }
1156
1157 static queue_node *
1158 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1159                              surface_queue)
1160 {
1161         tbm_queue_sequence *data = surface_queue->impl_data;
1162         queue_node *node = NULL;
1163
1164         node = _tbm_surface_queue_dequeue(surface_queue);
1165         if (node) {
1166                 _queue_node_push_back(&data->dequeue_list, node);
1167                 node->priv_flags = 1;
1168         }
1169
1170         return node;
1171 }
1172
1173 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1174         __tbm_queue_sequence_init,
1175         __tbm_queue_sequence_reset,
1176         __tbm_queue_sequence_destroy,
1177         __tbm_queue_sequence_need_attach,
1178         __tbm_queue_sequence_enqueue,
1179         NULL,                                   /*__tbm_queue_sequence_release*/
1180         __tbm_queue_sequence_dequeue,
1181         NULL,                                   /*__tbm_queue_sequence_acquire*/
1182 };
1183
1184 tbm_surface_queue_h
1185 tbm_surface_queue_sequence_create(int queue_size, int width,
1186                                   int height, int format, int flags)
1187 {
1188         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1189         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1190         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1191         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1192
1193         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1194                                             sizeof(struct _tbm_surface_queue));
1195         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1196
1197         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1198
1199         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1200                                    sizeof(tbm_queue_sequence));
1201         if (data == NULL) {
1202                 free(surface_queue);
1203                 return NULL;
1204         }
1205
1206         data->queue_size = queue_size;
1207         data->flags = flags;
1208         _tbm_surface_queue_init(surface_queue,
1209                                 data->queue_size,
1210                                 width, height, format,
1211                                 &tbm_queue_sequence_impl, data);
1212
1213         return surface_queue;
1214 }
1215 /* LCOV_EXCL_STOP */