surface queue: remove useless variable
[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
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 | DUTY_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 & DUTY_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 = DUTY_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 || node->surface == NULL) {
446                 TBM_LOG("_queue_node_pop_front is failed\n");
447
448         *surface = NULL;
449                 pthread_mutex_unlock(&surface_queue->lock);
450                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
451         }
452
453         *surface = node->surface;
454
455         pthread_mutex_unlock(&surface_queue->lock);
456
457         return TBM_SURFACE_QUEUE_ERROR_NONE;
458 }
459
460 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
461 {
462         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
463
464         pthread_mutex_lock(&surface_queue->lock);
465
466         if (_queue_is_empty(&surface_queue->free_queue)) {
467                 if (surface_queue->impl && surface_queue->impl->need_attach)
468                         surface_queue->impl->need_attach(surface_queue);
469         }
470
471         if (_queue_is_empty(&surface_queue->free_queue)) {
472                 if (wait) {
473                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
474                         pthread_mutex_unlock(&surface_queue->lock);
475                         return 1;
476                 }
477
478                 pthread_mutex_unlock(&surface_queue->lock);
479                 return 0;
480         }
481
482         pthread_mutex_unlock(&surface_queue->lock);
483
484         return 1;
485 }
486
487 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
488 {
489         queue_node *node = NULL;
490         int queue_type;
491
492         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
493         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
494
495         pthread_mutex_lock(&surface_queue->lock);
496
497         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
498         if (node == NULL || queue_type != NODE_LIST)
499         {
500                 TBM_LOG("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
501                 pthread_mutex_unlock(&surface_queue->lock);
502                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
503         }
504
505         if (surface_queue->impl && surface_queue->impl->release)
506                 surface_queue->impl->release(surface_queue, node);
507         else
508                 _tbm_surface_queue_release(surface_queue, node, 1);
509
510         if (_queue_is_empty(&surface_queue->free_queue)) {
511                 pthread_mutex_unlock(&surface_queue->lock);
512                 return TBM_SURFACE_QUEUE_ERROR_NONE;
513         }
514
515         pthread_mutex_unlock(&surface_queue->lock);
516         pthread_cond_signal(&surface_queue->free_cond);
517
518         if (surface_queue->dequeuable_cb)
519                 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
520
521         return TBM_SURFACE_QUEUE_ERROR_NONE;
522 }
523
524 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
525 {
526         queue_node *node = NULL;
527
528         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
529         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
530
531         pthread_mutex_lock(&surface_queue->lock);
532
533         if (surface_queue->impl && surface_queue->impl->acquire)
534                 node = surface_queue->impl->acquire(surface_queue);
535         else
536                 node = _tbm_surface_queue_acquire(surface_queue);
537
538         if (node == NULL || node->surface == NULL) {
539                 TBM_LOG("_queue_node_pop_front  failed\n");
540
541         *surface = NULL;
542                 pthread_mutex_unlock(&surface_queue->lock);
543                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
544         }
545
546         *surface = node->surface;
547
548         pthread_mutex_unlock(&surface_queue->lock);
549
550         return TBM_SURFACE_QUEUE_ERROR_NONE;
551 }
552
553 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
554 {
555         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
556
557         pthread_mutex_lock(&surface_queue->lock);
558
559         if (_queue_is_empty(&surface_queue->dirty_queue)) {
560                 if (wait) {
561                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
562                         pthread_mutex_unlock(&surface_queue->lock);
563                         return 1;
564                 }
565
566                 pthread_mutex_unlock(&surface_queue->lock);
567                 return 0;
568         }
569
570         pthread_mutex_unlock(&surface_queue->lock);
571
572         return 1;
573 }
574
575 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
576 {
577         queue_node *node = NULL, *tmp = NULL;
578
579         TBM_RETURN_IF_FAIL(surface_queue != NULL);
580
581         if (surface_queue->destroy_cb)
582                 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
583
584         if (surface_queue->impl && surface_queue->impl->destroy)
585                 surface_queue->impl->destroy(surface_queue);
586
587         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
588                 _queue_node_delete(node);
589         }
590
591         pthread_mutex_destroy(&surface_queue->lock);
592         free(surface_queue);
593 }
594
595 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
596 {
597         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
598
599         queue_node *node = NULL, *tmp = NULL;
600
601         if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
602                 return TBM_SURFACE_QUEUE_ERROR_NONE;
603
604         pthread_mutex_lock(&surface_queue->lock);
605
606         surface_queue->width = width;
607         surface_queue->height = height;
608         surface_queue->format = format;
609
610         /* Destory surface and Push to free_queue */
611         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
612         {
613                 _queue_node_delete(node);
614         }
615
616         /* Reset queue */
617         _queue_init(&surface_queue->free_queue);
618         _queue_init(&surface_queue->dirty_queue);
619         LIST_INITHEAD(&surface_queue->list);
620
621         if (surface_queue->impl && surface_queue->impl->reset)
622                 surface_queue->impl->reset(surface_queue);
623
624         pthread_mutex_unlock(&surface_queue->lock);
625         pthread_cond_signal(&surface_queue->free_cond);
626
627         if (surface_queue->reset_cb)
628                 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
629
630         return TBM_SURFACE_QUEUE_ERROR_NONE;
631 }
632
633 typedef struct
634 {
635         int queue_size;
636         int num_attached;
637         int flags;
638 }tbm_queue_default;
639
640 static void __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
641 {
642         tbm_queue_default* data = surface_queue->impl_data;
643         data->num_attached = 0;
644 }
645
646 static void __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
647 {
648         tbm_queue_default* data = surface_queue->impl_data;
649         data->num_attached = 0;
650 }
651
652 static void __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
653 {
654         free(surface_queue->impl_data);
655 }
656
657 static void __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
658 {
659         tbm_queue_default* data = surface_queue->impl_data;
660         tbm_surface_h surface;
661
662         if (data->queue_size == data->num_attached)
663                 return;
664
665         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
666                                                 surface_queue->height,
667                                                 surface_queue->format,
668                                                 data->flags);
669         TBM_RETURN_IF_FAIL(surface != NULL);
670         _tbm_surface_queue_attach(surface_queue, surface);
671         tbm_surface_internal_unref(surface);
672         data->num_attached++;
673 }
674
675 static const tbm_surface_queue_interface tbm_queue_default_impl =
676 {
677         __tbm_queue_default_init,
678         __tbm_queue_default_reset,
679         __tbm_queue_default_destroy,
680         __tbm_queue_default_need_attach,
681         NULL,                           /*__tbm_queue_default_enqueue*/
682         NULL,                           /*__tbm_queue_default_release*/
683         NULL,                           /*__tbm_queue_default_dequeue*/
684         NULL,                           /*__tbm_queue_default_acquire*/
685 };
686
687 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
688 {
689         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
690         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
691         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
692         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
693
694         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
695         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
696
697         tbm_queue_default *data = (tbm_queue_default *) calloc(1, sizeof(tbm_queue_default));
698         if (data == NULL)
699         {
700                 free(surface_queue);
701                 return NULL;
702         }
703
704         data->queue_size = queue_size;
705         data->flags = flags;
706         _tbm_surface_queue_init(surface_queue,
707                 width, height, format,
708                 &tbm_queue_default_impl, data);
709
710         return surface_queue;
711 }
712
713 typedef struct
714 {
715         int queue_size;
716         int num_attached;
717         int flags;
718         queue dequeue_list;
719 }tbm_queue_sequence;
720
721 static void __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
722 {
723         tbm_queue_sequence* data = surface_queue->impl_data;
724
725         data->num_attached = 0;
726         _queue_init(&data->dequeue_list);
727 }
728
729 static void __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
730 {
731         tbm_queue_sequence* data = surface_queue->impl_data;
732
733         data->num_attached = 0;
734         _queue_init(&data->dequeue_list);
735 }
736
737 static void __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
738 {
739         free(surface_queue->impl_data);
740 }
741
742 static void __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
743 {
744         tbm_queue_sequence* data = surface_queue->impl_data;
745         tbm_surface_h surface;
746
747         if (data->queue_size == data->num_attached)
748                 return;
749
750         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
751                                                 surface_queue->height,
752                                                 surface_queue->format,
753                                                 data->flags);
754         TBM_RETURN_IF_FAIL(surface != NULL);
755         _tbm_surface_queue_attach(surface_queue, surface);
756         tbm_surface_internal_unref(surface);
757         data->num_attached++;
758 }
759
760 static void __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue, queue_node* node)
761 {
762         tbm_queue_sequence* data = surface_queue->impl_data;
763         queue_node *next = NULL;
764         queue_node *tmp = NULL;
765
766         node->priv_flags = 0;
767
768         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
769                 if (next->priv_flags) break;
770         _queue_node_pop(&data->dequeue_list, next);
771                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
772         }
773 }
774
775 static queue_node* __tbm_queue_sequence_dequeue(tbm_surface_queue_h surface_queue)
776 {
777         tbm_queue_sequence* data = surface_queue->impl_data;
778         queue_node* node = NULL;
779
780         node = _tbm_surface_queue_dequeue(surface_queue);
781         if (node)
782         {
783                 _queue_node_push_back(&data->dequeue_list, node);
784                 node->priv_flags = 1;
785         }
786
787         return node;
788 }
789
790 static const tbm_surface_queue_interface tbm_queue_sequence_impl =
791 {
792         __tbm_queue_sequence_init,
793         __tbm_queue_sequence_reset,
794         __tbm_queue_sequence_destroy,
795         __tbm_queue_sequence_need_attach,
796         __tbm_queue_sequence_enqueue,
797         NULL,                           /*__tbm_queue_sequence_release*/
798         __tbm_queue_sequence_dequeue,
799         NULL,                           /*__tbm_queue_sequence_acquire*/
800 };
801
802 tbm_surface_queue_h tbm_surface_queue_sequence_create(int queue_size, int width, int height, int format, int flags)
803 {
804         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
805         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
806         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
807         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
808
809         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
810         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
811
812         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1, sizeof(tbm_queue_sequence));
813         if (data == NULL)
814         {
815                 free(surface_queue);
816                 return NULL;
817         }
818
819         data->queue_size = queue_size;
820         data->flags = flags;
821         _tbm_surface_queue_init(surface_queue,
822                 width, height, format,
823                 &tbm_queue_sequence_impl, data);
824
825         return surface_queue;
826 }