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