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