Fix typo on tbm_surface_queue.c
[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", __FUNCTION__, __LINE__, surface_queue)
43 #define TBM_LOCK() TBM_LOG("[LOCK] %s:%d surface:%p\n", __FUNCTION__, __LINE__, surface_queue)
44 #define TBM_UNLOCK() TBM_LOG("[UNLOCK] %s:%d surface:%p\n", __FUNCTION__, __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 _tbm_surface_queue_interface {
68         void (*init)(tbm_surface_queue_h queue);
69         void (*reset)(tbm_surface_queue_h queue);
70         void (*destroy)(tbm_surface_queue_h queue);
71         void (*need_attach)(tbm_surface_queue_h queue);
72
73         void (*enqueue)(tbm_surface_queue_h queue, queue_node* node);
74         void (*release)(tbm_surface_queue_h queue, queue_node* node);
75         queue_node* (*dequeue)(tbm_surface_queue_h queue);
76         queue_node* (*acquire)(tbm_surface_queue_h queue);
77 }tbm_surface_queue_interface;
78
79 struct _tbm_surface_queue {
80         int width;
81         int height;
82         int format;
83
84         queue free_queue;
85         queue dirty_queue;
86         struct list_head list;
87
88         tbm_surface_queue_notify_cb destroy_cb;
89         void *destroy_cb_data;
90
91         tbm_surface_queue_notify_cb dequeuable_cb;
92         void *dequeuable_cb_data;
93
94         tbm_surface_queue_notify_cb acquirable_cb;
95         void *acquirable_cb_data;
96
97         tbm_surface_queue_notify_cb reset_cb;
98         void *reset_cb_data;
99
100         pthread_mutex_t lock;
101         pthread_cond_t free_cond;
102         pthread_cond_t dirty_cond;
103
104         const tbm_surface_queue_interface *impl;
105         void *impl_data;
106 };
107
108 static queue_node *_queue_node_create(void)
109 {
110         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
111         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
112
113         return node;
114 }
115
116 static void _queue_node_delete(queue_node * node)
117 {
118         if (node->surface)
119                 tbm_surface_destroy(node->surface);
120
121         LIST_DEL(&node->item_link);
122         LIST_DEL(&node->link);
123         free(node);
124 }
125
126 static int _queue_is_empty(queue * queue)
127 {
128         if (queue->head.next == &queue->tail)
129                 return 1;
130
131         return 0;
132 }
133
134 static void _queue_node_push_back(queue * queue, queue_node * node)
135 {
136         LIST_ADDTAIL(&node->item_link, &queue->tail);
137         queue->count++;
138         return;
139 }
140
141 static void _queue_node_push_front(queue * queue, queue_node * node)
142 {
143         LIST_ADD(&node->item_link, &queue->head);
144         queue->count++;
145         return;
146 }
147
148 static queue_node *_queue_node_pop_front(queue * queue)
149 {
150         queue_node *node = NULL;
151
152         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
153
154         LIST_DEL(&node->item_link);
155         queue->count--;
156
157         return node;
158 }
159
160 static queue_node *_queue_node_pop(queue * queue, queue_node* node)
161 {
162         LIST_DEL(&node->item_link);
163         queue->count--;
164
165         return node;
166 }
167
168 static queue_node* _queue_get_node(tbm_surface_queue_h surface_queue, int type, tbm_surface_h surface, int *out_type)
169 {
170         queue_node *node = NULL;
171         queue_node *tmp = NULL;
172
173         if (type == 0)
174                 type = FREE_QUEUE | DIRTY_QUEUE | NODE_LIST;
175         if (out_type)
176                 *out_type = 0;
177
178         if (type & FREE_QUEUE)
179         {
180                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head, item_link) {
181                         if (node->surface == surface)
182                         {
183                                 if (out_type) *out_type = FREE_QUEUE;
184                                 return node;
185                         }
186                 }
187         }
188
189         if (type & DIRTY_QUEUE)
190         {
191                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head, item_link) {
192                         if (node->surface == surface)
193                         {
194                                 if (out_type) *out_type = DIRTY_QUEUE;
195                                 return node;
196                         }
197                 }
198         }
199
200         if (type & NODE_LIST)
201         {
202                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
203                         if (node->surface == surface)
204                         {
205                                 if (out_type) *out_type = NODE_LIST;
206                                 return node;
207                         }
208                 }
209         }
210
211         return NULL;
212 }
213
214 static void _queue_init(queue * queue)
215 {
216         LIST_INITHEAD(&queue->head);
217         LIST_INITHEAD(&queue->tail);
218         LIST_ADDTAIL(&queue->head, &queue->tail);
219         queue->count = 0;
220 }
221
222 void _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
223 {
224         queue_node *node = NULL;
225
226         node = _queue_node_create();
227         TBM_RETURN_IF_FAIL(node != NULL);
228
229         tbm_surface_internal_ref(surface);
230         node->surface = surface;
231
232         LIST_ADDTAIL(&node->link, &surface_queue->list);
233         _queue_node_push_back(&surface_queue->free_queue, node);
234 }
235
236 void _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
237 {
238         queue_node *node = NULL;
239         int queue_type;
240
241         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
242         if (node)
243                 _queue_node_delete(node);
244 }
245
246 void _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, queue_node* node, int push_back)
247 {
248         if (push_back)
249                 _queue_node_push_back(&surface_queue->dirty_queue, node);
250         else
251                 _queue_node_push_front(&surface_queue->dirty_queue, node);
252 }
253
254 queue_node* _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
255 {
256         queue_node *node = NULL;
257
258         if (_queue_is_empty(&surface_queue->free_queue)) {
259                 if (surface_queue->impl && surface_queue->impl->need_attach)
260                         surface_queue->impl->need_attach(surface_queue);
261
262                 if (_queue_is_empty(&surface_queue->free_queue)) {
263                         return NULL;
264                 }
265         }
266
267         node = _queue_node_pop_front(&surface_queue->free_queue);
268
269         return node;
270 }
271
272 queue_node* _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
273 {
274         queue_node *node = NULL;
275
276         if (_queue_is_empty(&surface_queue->dirty_queue)) {
277                 return NULL;
278         }
279
280         node = _queue_node_pop_front(&surface_queue->dirty_queue);
281
282         return node;
283 }
284
285 void _tbm_surface_queue_release(tbm_surface_queue_h surface_queue, queue_node* node, int push_back)
286 {
287         if (push_back)
288                 _queue_node_push_back(&surface_queue->free_queue, node);
289         else
290                 _queue_node_push_front(&surface_queue->free_queue, node);
291 }
292
293 void _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
294                                 int width, int height, int format,
295                                 const tbm_surface_queue_interface* impl, void *data)
296 {
297         TBM_RETURN_IF_FAIL(surface_queue != NULL);
298         TBM_RETURN_IF_FAIL(impl != NULL);
299
300         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
301
302         pthread_mutex_init(&surface_queue->lock, NULL);
303         pthread_cond_init(&surface_queue->free_cond, NULL);
304         pthread_cond_init(&surface_queue->dirty_cond, NULL);
305
306         surface_queue->width = width;
307         surface_queue->height = height;
308         surface_queue->format = format;
309         surface_queue->impl = impl;
310         surface_queue->impl_data = data;
311
312         _queue_init(&surface_queue->free_queue);
313         _queue_init(&surface_queue->dirty_queue);
314         LIST_INITHEAD(&surface_queue->list);
315
316         if (surface_queue->impl && surface_queue->impl->init)
317                 surface_queue->impl->init(surface_queue);
318 }
319
320 tbm_surface_queue_error_e tbm_surface_queue_set_destroy_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
321 {
322         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
323
324         pthread_mutex_lock(&surface_queue->lock);
325
326         surface_queue->destroy_cb = destroy_cb;
327         surface_queue->destroy_cb_data = data;
328
329         pthread_mutex_unlock(&surface_queue->lock);
330
331         return TBM_SURFACE_QUEUE_ERROR_NONE;
332 }
333
334 tbm_surface_queue_error_e tbm_surface_queue_set_dequeuable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
335 {
336         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
337
338         pthread_mutex_lock(&surface_queue->lock);
339
340         surface_queue->dequeuable_cb = dequeuable_cb;
341         surface_queue->dequeuable_cb_data = data;
342
343         pthread_mutex_unlock(&surface_queue->lock);
344
345         return TBM_SURFACE_QUEUE_ERROR_NONE;
346 }
347
348 tbm_surface_queue_error_e tbm_surface_queue_set_acquirable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
349 {
350         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
351
352         pthread_mutex_lock(&surface_queue->lock);
353
354         surface_queue->acquirable_cb = acquirable_cb;
355         surface_queue->acquirable_cb_data = data;
356
357         pthread_mutex_unlock(&surface_queue->lock);
358
359         return TBM_SURFACE_QUEUE_ERROR_NONE;
360 }
361
362 int tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
363 {
364         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
365
366         return surface_queue->width;
367 }
368
369 int tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
370 {
371         return surface_queue->height;
372 }
373
374 int tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
375 {
376         return surface_queue->format;
377 }
378
379 tbm_surface_queue_error_e tbm_surface_queue_set_reset_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb, void *data)
380 {
381         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
382
383         pthread_mutex_lock(&surface_queue->lock);
384
385         surface_queue->reset_cb = reset_cb;
386         surface_queue->reset_cb_data = data;
387
388         pthread_mutex_unlock(&surface_queue->lock);
389
390         return TBM_SURFACE_QUEUE_ERROR_NONE;
391 }
392
393
394 tbm_surface_queue_error_e tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
395 {
396         queue_node *node = NULL;
397         int queue_type;
398
399         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
400         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
401
402         pthread_mutex_lock(&surface_queue->lock);
403
404         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
405         if (node == NULL || queue_type != NODE_LIST)
406         {
407                 TBM_LOG("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
408                 pthread_mutex_unlock(&surface_queue->lock);
409                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
410         }
411
412         if (surface_queue->impl && surface_queue->impl->enqueue)
413                 surface_queue->impl->enqueue(surface_queue, node);
414         else
415                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
416
417         if (_queue_is_empty(&surface_queue->dirty_queue)) {
418                 pthread_mutex_unlock(&surface_queue->lock);
419                 return TBM_SURFACE_QUEUE_ERROR_NONE;
420         }
421
422         pthread_mutex_unlock(&surface_queue->lock);
423         pthread_cond_signal(&surface_queue->dirty_cond);
424
425         if (surface_queue->acquirable_cb)
426                 surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
427
428         return TBM_SURFACE_QUEUE_ERROR_NONE;
429 }
430
431 tbm_surface_queue_error_e tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
432 {
433         queue_node *node = NULL;
434
435         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
436         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
437
438         pthread_mutex_lock(&surface_queue->lock);
439
440         if (surface_queue->impl && surface_queue->impl->dequeue)
441                 node = surface_queue->impl->dequeue(surface_queue);
442         else
443                 node = _tbm_surface_queue_dequeue(surface_queue);
444
445         if (node == NULL) {
446                 *surface = NULL;
447                 pthread_mutex_unlock(&surface_queue->lock);
448                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
449         }
450
451         if (node->surface == NULL) {
452                 *surface = NULL;
453                 TBM_LOG("_queue_node_pop_front  failed\n");
454                 pthread_mutex_unlock(&surface_queue->lock);
455                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
456         }
457
458         *surface = node->surface;
459
460         pthread_mutex_unlock(&surface_queue->lock);
461
462         return TBM_SURFACE_QUEUE_ERROR_NONE;
463 }
464
465 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
466 {
467         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
468
469         pthread_mutex_lock(&surface_queue->lock);
470
471         if (_queue_is_empty(&surface_queue->free_queue)) {
472                 if (surface_queue->impl && surface_queue->impl->need_attach)
473                         surface_queue->impl->need_attach(surface_queue);
474         }
475
476         if (_queue_is_empty(&surface_queue->free_queue)) {
477                 if (wait) {
478                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
479                         pthread_mutex_unlock(&surface_queue->lock);
480                         return 1;
481                 }
482
483                 pthread_mutex_unlock(&surface_queue->lock);
484                 return 0;
485         }
486
487         pthread_mutex_unlock(&surface_queue->lock);
488
489         return 1;
490 }
491
492 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
493 {
494         queue_node *node = NULL;
495         int queue_type;
496
497         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
498         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
499
500         pthread_mutex_lock(&surface_queue->lock);
501
502         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
503         if (node == NULL || queue_type != NODE_LIST)
504         {
505                 TBM_LOG("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
506                 pthread_mutex_unlock(&surface_queue->lock);
507                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
508         }
509
510         if (surface_queue->impl && surface_queue->impl->release)
511                 surface_queue->impl->release(surface_queue, node);
512         else
513                 _tbm_surface_queue_release(surface_queue, node, 1);
514
515         if (_queue_is_empty(&surface_queue->free_queue)) {
516                 pthread_mutex_unlock(&surface_queue->lock);
517                 return TBM_SURFACE_QUEUE_ERROR_NONE;
518         }
519
520         pthread_mutex_unlock(&surface_queue->lock);
521         pthread_cond_signal(&surface_queue->free_cond);
522
523         if (surface_queue->dequeuable_cb)
524                 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
525
526         return TBM_SURFACE_QUEUE_ERROR_NONE;
527 }
528
529 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
530 {
531         queue_node *node = NULL;
532
533         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
534         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
535
536         pthread_mutex_lock(&surface_queue->lock);
537
538         if (surface_queue->impl && surface_queue->impl->acquire)
539                 node = surface_queue->impl->acquire(surface_queue);
540         else
541                 node = _tbm_surface_queue_acquire(surface_queue);
542
543         if (node == NULL) {
544                 *surface = NULL;
545                 pthread_mutex_unlock(&surface_queue->lock);
546                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
547         }
548
549         if (node->surface == NULL) {
550                 *surface = NULL;
551                 TBM_LOG("_queue_node_pop_front  failed\n");
552                 pthread_mutex_unlock(&surface_queue->lock);
553                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
554         }
555
556         *surface = node->surface;
557
558         pthread_mutex_unlock(&surface_queue->lock);
559
560         return TBM_SURFACE_QUEUE_ERROR_NONE;
561 }
562
563 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
564 {
565         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
566
567         pthread_mutex_lock(&surface_queue->lock);
568
569         if (_queue_is_empty(&surface_queue->dirty_queue)) {
570                 if (wait) {
571                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
572                         pthread_mutex_unlock(&surface_queue->lock);
573                         return 1;
574                 }
575
576                 pthread_mutex_unlock(&surface_queue->lock);
577                 return 0;
578         }
579
580         pthread_mutex_unlock(&surface_queue->lock);
581
582         return 1;
583 }
584
585 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
586 {
587         queue_node *node = NULL, *tmp = NULL;
588
589         TBM_RETURN_IF_FAIL(surface_queue != NULL);
590
591         if (surface_queue->destroy_cb)
592                 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
593
594         if (surface_queue->impl && surface_queue->impl->destroy)
595                 surface_queue->impl->destroy(surface_queue);
596
597         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
598                 _queue_node_delete(node);
599         }
600
601         pthread_mutex_destroy(&surface_queue->lock);
602         free(surface_queue);
603 }
604
605 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
606 {
607         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
608
609         queue_node *node = NULL, *tmp = NULL;
610
611         if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
612                 return TBM_SURFACE_QUEUE_ERROR_NONE;
613
614         pthread_mutex_lock(&surface_queue->lock);
615
616         surface_queue->width = width;
617         surface_queue->height = height;
618         surface_queue->format = format;
619
620         /* Destory surface and Push to free_queue */
621         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
622         {
623                 _queue_node_delete(node);
624         }
625
626         /* Reset queue */
627         _queue_init(&surface_queue->free_queue);
628         _queue_init(&surface_queue->dirty_queue);
629         LIST_INITHEAD(&surface_queue->list);
630
631         if (surface_queue->impl && surface_queue->impl->reset)
632                 surface_queue->impl->reset(surface_queue);
633
634         pthread_mutex_unlock(&surface_queue->lock);
635         pthread_cond_signal(&surface_queue->free_cond);
636
637         if (surface_queue->reset_cb)
638                 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
639
640         return TBM_SURFACE_QUEUE_ERROR_NONE;
641 }
642
643 typedef struct
644 {
645         int queue_size;
646         int num_attached;
647         int flags;
648 }tbm_queue_default;
649
650 static void __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
651 {
652         tbm_queue_default* data = surface_queue->impl_data;
653         data->num_attached = 0;
654 }
655
656 static void __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
657 {
658         tbm_queue_default* data = surface_queue->impl_data;
659         data->num_attached = 0;
660 }
661
662 static void __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
663 {
664         free(surface_queue->impl_data);
665 }
666
667 static void __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
668 {
669         tbm_queue_default* data = surface_queue->impl_data;
670         tbm_surface_h surface;
671
672         if (data->queue_size == data->num_attached)
673                 return;
674
675         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
676                                                 surface_queue->height,
677                                                 surface_queue->format,
678                                                 data->flags);
679         TBM_RETURN_IF_FAIL(surface != NULL);
680         _tbm_surface_queue_attach(surface_queue, surface);
681         tbm_surface_internal_unref(surface);
682         data->num_attached++;
683 }
684
685 static const tbm_surface_queue_interface tbm_queue_default_impl =
686 {
687         __tbm_queue_default_init,
688         __tbm_queue_default_reset,
689         __tbm_queue_default_destroy,
690         __tbm_queue_default_need_attach,
691         NULL,                           /*__tbm_queue_default_enqueue*/
692         NULL,                           /*__tbm_queue_default_release*/
693         NULL,                           /*__tbm_queue_default_dequeue*/
694         NULL,                           /*__tbm_queue_default_acquire*/
695 };
696
697 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
698 {
699         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
700         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
701         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
702         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
703
704         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
705         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
706
707         tbm_queue_default *data = (tbm_queue_default *) calloc(1, sizeof(tbm_queue_default));
708         if (data == NULL)
709         {
710                 free(surface_queue);
711                 return NULL;
712         }
713
714         data->queue_size = queue_size;
715         data->flags = flags;
716         _tbm_surface_queue_init(surface_queue,
717                 width, height, format,
718                 &tbm_queue_default_impl, data);
719
720         return surface_queue;
721 }
722
723 typedef struct
724 {
725         int queue_size;
726         int num_attached;
727         int flags;
728         queue dequeue_list;
729 }tbm_queue_sequence;
730
731 static void __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
732 {
733         tbm_queue_sequence* data = surface_queue->impl_data;
734
735         data->num_attached = 0;
736         _queue_init(&data->dequeue_list);
737 }
738
739 static void __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
740 {
741         tbm_queue_sequence* data = surface_queue->impl_data;
742
743         data->num_attached = 0;
744         _queue_init(&data->dequeue_list);
745 }
746
747 static void __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
748 {
749         free(surface_queue->impl_data);
750 }
751
752 static void __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
753 {
754         tbm_queue_sequence* data = surface_queue->impl_data;
755         tbm_surface_h surface;
756
757         if (data->queue_size == data->num_attached)
758                 return;
759
760         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
761                                                 surface_queue->height,
762                                                 surface_queue->format,
763                                                 data->flags);
764         TBM_RETURN_IF_FAIL(surface != NULL);
765         _tbm_surface_queue_attach(surface_queue, surface);
766         tbm_surface_internal_unref(surface);
767         data->num_attached++;
768 }
769
770 static void __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue, queue_node* node)
771 {
772         tbm_queue_sequence* data = surface_queue->impl_data;
773         queue_node *next = NULL;
774         queue_node *tmp = NULL;
775
776         node->priv_flags = 0;
777
778         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
779                 if (next->priv_flags) break;
780         _queue_node_pop(&data->dequeue_list, next);
781                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
782         }
783 }
784
785 static queue_node* __tbm_queue_sequence_dequeue(tbm_surface_queue_h surface_queue)
786 {
787         tbm_queue_sequence* data = surface_queue->impl_data;
788         queue_node* node = NULL;
789
790         node = _tbm_surface_queue_dequeue(surface_queue);
791         if (node)
792         {
793                 _queue_node_push_back(&data->dequeue_list, node);
794                 node->priv_flags = 1;
795         }
796
797         return node;
798 }
799
800 static const tbm_surface_queue_interface tbm_queue_sequence_impl =
801 {
802         __tbm_queue_sequence_init,
803         __tbm_queue_sequence_reset,
804         __tbm_queue_sequence_destroy,
805         __tbm_queue_sequence_need_attach,
806         __tbm_queue_sequence_enqueue,
807         NULL,                           /*__tbm_queue_sequence_release*/
808         __tbm_queue_sequence_dequeue,
809         NULL,                           /*__tbm_queue_sequence_acquire*/
810 };
811
812 tbm_surface_queue_h tbm_surface_queue_sequence_create(int queue_size, int width, int height, int format, int flags)
813 {
814         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
815         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
816         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
817         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
818
819         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
820         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
821
822         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1, sizeof(tbm_queue_sequence));
823         if (data == NULL)
824         {
825                 free(surface_queue);
826                 return NULL;
827         }
828
829         data->queue_size = queue_size;
830         data->flags = flags;
831         _tbm_surface_queue_init(surface_queue,
832                 width, height, format,
833                 &tbm_queue_sequence_impl, data);
834
835         return surface_queue;
836 }