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