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