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