tbm_surface_queue: support multiple notify handler
[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 {
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 *_queue_node_create(void)
121 {
122         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
123         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
124
125         return node;
126 }
127
128 static void _queue_node_delete(queue_node * node)
129 {
130         if (node->surface)
131                 tbm_surface_destroy(node->surface);
132
133         LIST_DEL(&node->item_link);
134         LIST_DEL(&node->link);
135         free(node);
136 }
137
138 static int _queue_is_empty(queue * queue)
139 {
140         if (queue->head.next == &queue->tail)
141                 return 1;
142
143         return 0;
144 }
145
146 static void _queue_node_push_back(queue * queue, queue_node * node)
147 {
148         LIST_ADDTAIL(&node->item_link, &queue->tail);
149         queue->count++;
150         return;
151 }
152
153 static void _queue_node_push_front(queue * queue, queue_node * node)
154 {
155         LIST_ADD(&node->item_link, &queue->head);
156         queue->count++;
157         return;
158 }
159
160 static queue_node *_queue_node_pop_front(queue * queue)
161 {
162         queue_node *node = NULL;
163
164         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
165
166         LIST_DEL(&node->item_link);
167         queue->count--;
168
169         return node;
170 }
171
172 static queue_node *_queue_node_pop(queue * queue, queue_node* node)
173 {
174         LIST_DEL(&node->item_link);
175         queue->count--;
176
177         return node;
178 }
179
180 static queue_node* _queue_get_node(tbm_surface_queue_h surface_queue, int type, tbm_surface_h surface, int *out_type)
181 {
182         queue_node *node = NULL;
183         queue_node *tmp = NULL;
184
185         if (type == 0)
186                 type = FREE_QUEUE | DIRTY_QUEUE | NODE_LIST;
187         if (out_type)
188                 *out_type = 0;
189
190         if (type & FREE_QUEUE)
191         {
192                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head, item_link) {
193                         if (node->surface == surface)
194                         {
195                                 if (out_type) *out_type = FREE_QUEUE;
196                                 return node;
197                         }
198                 }
199         }
200
201         if (type & DIRTY_QUEUE)
202         {
203                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head, item_link) {
204                         if (node->surface == surface)
205                         {
206                                 if (out_type) *out_type = DIRTY_QUEUE;
207                                 return node;
208                         }
209                 }
210         }
211
212         if (type & NODE_LIST)
213         {
214                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
215                         if (node->surface == surface)
216                         {
217                                 if (out_type) *out_type = NODE_LIST;
218                                 return node;
219                         }
220                 }
221         }
222
223         return NULL;
224 }
225
226 static void _queue_init(queue * queue)
227 {
228         LIST_INITHEAD(&queue->head);
229         LIST_INITHEAD(&queue->tail);
230         LIST_ADDTAIL(&queue->head, &queue->tail);
231         queue->count = 0;
232 }
233
234 static void _notify_add(struct list_head *list, tbm_surface_queue_notify_cb cb, void* data)
235 {
236         TBM_RETURN_IF_FAIL(cb != NULL);
237
238         queue_notify *item = (queue_notify*)calloc(1, sizeof(queue_notify));
239         TBM_RETURN_IF_FAIL(item != NULL);
240
241         LIST_INITHEAD(&item->link);
242         item->cb = cb;
243         item->data = data;
244
245         LIST_ADDTAIL(&item->link, list);
246 }
247
248 static void _notify_remove(struct list_head *list, tbm_surface_queue_notify_cb cb, void* data)
249 {
250         queue_notify *item = NULL, *tmp = NULL;
251
252         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
253                 if (item->cb == cb && item->data == data) {
254                         LIST_DEL(&item->link);
255                         free(item);
256                         return;
257                 }
258         }
259
260         TBM_LOG("Cannot find notifiy\n");
261 }
262
263 static void _notify_remove_all(struct list_head *list)
264 {
265         queue_notify *item = NULL, *tmp = NULL;
266
267         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
268                 LIST_DEL(&item->link);
269                 free(item);
270         }
271 }
272
273 static void _notify_emit(tbm_surface_queue_h surface_queue, struct list_head *list)
274 {
275         queue_notify *item = NULL, *tmp = NULL;
276
277         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
278                 item->cb(surface_queue, item->data);
279         }
280 }
281
282 void _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
283 {
284         queue_node *node = NULL;
285
286         node = _queue_node_create();
287         TBM_RETURN_IF_FAIL(node != NULL);
288
289         tbm_surface_internal_ref(surface);
290         node->surface = surface;
291
292         LIST_ADDTAIL(&node->link, &surface_queue->list);
293         _queue_node_push_back(&surface_queue->free_queue, node);
294 }
295
296 void _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
297 {
298         queue_node *node = NULL;
299         int queue_type;
300
301         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
302         if (node)
303                 _queue_node_delete(node);
304 }
305
306 void _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, queue_node* node, int push_back)
307 {
308         if (push_back)
309                 _queue_node_push_back(&surface_queue->dirty_queue, node);
310         else
311                 _queue_node_push_front(&surface_queue->dirty_queue, node);
312 }
313
314 queue_node* _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
315 {
316         queue_node *node = NULL;
317
318         if (_queue_is_empty(&surface_queue->free_queue)) {
319                 if (surface_queue->impl && surface_queue->impl->need_attach)
320                         surface_queue->impl->need_attach(surface_queue);
321
322                 if (_queue_is_empty(&surface_queue->free_queue)) {
323                         return NULL;
324                 }
325         }
326
327         node = _queue_node_pop_front(&surface_queue->free_queue);
328
329         return node;
330 }
331
332 queue_node* _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
333 {
334         queue_node *node = NULL;
335
336         if (_queue_is_empty(&surface_queue->dirty_queue)) {
337                 return NULL;
338         }
339
340         node = _queue_node_pop_front(&surface_queue->dirty_queue);
341
342         return node;
343 }
344
345 void _tbm_surface_queue_release(tbm_surface_queue_h surface_queue, queue_node* node, int push_back)
346 {
347         if (push_back)
348                 _queue_node_push_back(&surface_queue->free_queue, node);
349         else
350                 _queue_node_push_front(&surface_queue->free_queue, node);
351 }
352
353 void _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
354                                 int width, int height, int format,
355                                 const tbm_surface_queue_interface* impl, void *data)
356 {
357         TBM_RETURN_IF_FAIL(surface_queue != NULL);
358         TBM_RETURN_IF_FAIL(impl != NULL);
359
360         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
361
362         pthread_mutex_init(&surface_queue->lock, NULL);
363         pthread_cond_init(&surface_queue->free_cond, NULL);
364         pthread_cond_init(&surface_queue->dirty_cond, NULL);
365
366         surface_queue->width = width;
367         surface_queue->height = height;
368         surface_queue->format = format;
369         surface_queue->impl = impl;
370         surface_queue->impl_data = data;
371
372         _queue_init(&surface_queue->free_queue);
373         _queue_init(&surface_queue->dirty_queue);
374         LIST_INITHEAD(&surface_queue->list);
375
376         LIST_INITHEAD(&surface_queue->destory_noti);
377         LIST_INITHEAD(&surface_queue->acquirable_noti);
378         LIST_INITHEAD(&surface_queue->dequeuable_noti);
379         LIST_INITHEAD(&surface_queue->reset_noti);
380
381         if (surface_queue->impl && surface_queue->impl->init)
382                 surface_queue->impl->init(surface_queue);
383 }
384
385 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)
386 {
387         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
388
389         pthread_mutex_lock(&surface_queue->lock);
390
391         surface_queue->destroy_cb = destroy_cb;
392         surface_queue->destroy_cb_data = data;
393
394         pthread_mutex_unlock(&surface_queue->lock);
395
396         return TBM_SURFACE_QUEUE_ERROR_NONE;
397 }
398
399 tbm_surface_queue_error_e tbm_surface_queue_add_destroy_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
400 {
401         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
402
403         pthread_mutex_lock(&surface_queue->lock);
404
405         _notify_add(&surface_queue->destory_noti, destroy_cb, data);
406
407         pthread_mutex_unlock(&surface_queue->lock);
408
409         return TBM_SURFACE_QUEUE_ERROR_NONE;
410 }
411
412 tbm_surface_queue_error_e tbm_surface_queue_remove_destroy_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
413 {
414         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
415
416         pthread_mutex_lock(&surface_queue->lock);
417
418         _notify_remove(&surface_queue->destory_noti, destroy_cb, data);
419
420         pthread_mutex_unlock(&surface_queue->lock);
421
422         return TBM_SURFACE_QUEUE_ERROR_NONE;
423 }
424
425 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)
426 {
427         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
428
429         pthread_mutex_lock(&surface_queue->lock);
430
431         surface_queue->dequeuable_cb = dequeuable_cb;
432         surface_queue->dequeuable_cb_data = data;
433
434         pthread_mutex_unlock(&surface_queue->lock);
435
436         return TBM_SURFACE_QUEUE_ERROR_NONE;
437 }
438
439 tbm_surface_queue_error_e tbm_surface_queue_add_dequeuable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
440 {
441         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
442
443         pthread_mutex_lock(&surface_queue->lock);
444
445         _notify_add(&surface_queue->dequeuable_noti, dequeuable_cb, data);
446
447         pthread_mutex_unlock(&surface_queue->lock);
448
449         return TBM_SURFACE_QUEUE_ERROR_NONE;
450 }
451
452 tbm_surface_queue_error_e tbm_surface_queue_remove_dequeuable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
453 {
454         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
455
456         pthread_mutex_lock(&surface_queue->lock);
457
458         _notify_remove(&surface_queue->dequeuable_noti, dequeuable_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 tbm_surface_queue_set_acquirable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
466 {
467         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
468
469         pthread_mutex_lock(&surface_queue->lock);
470
471         surface_queue->acquirable_cb = acquirable_cb;
472         surface_queue->acquirable_cb_data = data;
473
474         pthread_mutex_unlock(&surface_queue->lock);
475
476         return TBM_SURFACE_QUEUE_ERROR_NONE;
477 }
478
479 tbm_surface_queue_error_e tbm_surface_queue_add_acquirable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
480 {
481         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
482
483         pthread_mutex_lock(&surface_queue->lock);
484
485         _notify_add(&surface_queue->acquirable_noti, acquirable_cb, data);
486
487         pthread_mutex_unlock(&surface_queue->lock);
488
489         return TBM_SURFACE_QUEUE_ERROR_NONE;
490 }
491
492 tbm_surface_queue_error_e tbm_surface_queue_remove_acquirable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
493 {
494         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
495
496         pthread_mutex_lock(&surface_queue->lock);
497
498         _notify_remove(&surface_queue->acquirable_noti, acquirable_cb, data);
499
500         pthread_mutex_unlock(&surface_queue->lock);
501
502         return TBM_SURFACE_QUEUE_ERROR_NONE;
503 }
504
505 int tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
506 {
507         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
508
509         return surface_queue->width;
510 }
511
512 int tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
513 {
514         return surface_queue->height;
515 }
516
517 int tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
518 {
519         return surface_queue->format;
520 }
521
522 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)
523 {
524         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
525
526         pthread_mutex_lock(&surface_queue->lock);
527
528         surface_queue->reset_cb = reset_cb;
529         surface_queue->reset_cb_data = data;
530
531         pthread_mutex_unlock(&surface_queue->lock);
532
533         return TBM_SURFACE_QUEUE_ERROR_NONE;
534 }
535
536 tbm_surface_queue_error_e tbm_surface_queue_add_reset_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb, void *data)
537 {
538         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
539
540         pthread_mutex_lock(&surface_queue->lock);
541
542         _notify_add(&surface_queue->acquirable_noti, reset_cb, data);
543
544         pthread_mutex_unlock(&surface_queue->lock);
545
546         return TBM_SURFACE_QUEUE_ERROR_NONE;
547 }
548
549 tbm_surface_queue_error_e tbm_surface_queue_remove_reset_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb, void *data)
550 {
551         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
552
553         pthread_mutex_lock(&surface_queue->lock);
554
555         _notify_remove(&surface_queue->acquirable_noti, reset_cb, data);
556
557         pthread_mutex_unlock(&surface_queue->lock);
558
559         return TBM_SURFACE_QUEUE_ERROR_NONE;
560 }
561
562 tbm_surface_queue_error_e tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
563 {
564         queue_node *node = NULL;
565         int queue_type;
566
567         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
568         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
569
570         pthread_mutex_lock(&surface_queue->lock);
571
572         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
573         if (node == NULL || queue_type != NODE_LIST)
574         {
575                 TBM_LOG("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
576                 pthread_mutex_unlock(&surface_queue->lock);
577                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
578         }
579
580         if (surface_queue->impl && surface_queue->impl->enqueue)
581                 surface_queue->impl->enqueue(surface_queue, node);
582         else
583                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
584
585         if (_queue_is_empty(&surface_queue->dirty_queue)) {
586                 pthread_mutex_unlock(&surface_queue->lock);
587                 return TBM_SURFACE_QUEUE_ERROR_NONE;
588         }
589
590         pthread_mutex_unlock(&surface_queue->lock);
591         pthread_cond_signal(&surface_queue->dirty_cond);
592
593         _notify_emit(surface_queue, &surface_queue->acquirable_noti);
594         if (surface_queue->acquirable_cb)
595                 surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
596
597         return TBM_SURFACE_QUEUE_ERROR_NONE;
598 }
599
600 tbm_surface_queue_error_e tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
601 {
602         queue_node *node = NULL;
603
604         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
605         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
606
607         pthread_mutex_lock(&surface_queue->lock);
608
609         if (surface_queue->impl && surface_queue->impl->dequeue)
610                 node = surface_queue->impl->dequeue(surface_queue);
611         else
612                 node = _tbm_surface_queue_dequeue(surface_queue);
613
614         if (node == NULL) {
615                 *surface = NULL;
616                 pthread_mutex_unlock(&surface_queue->lock);
617                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
618         }
619
620         if (node->surface == NULL) {
621                 *surface = NULL;
622                 TBM_LOG("_queue_node_pop_front  failed\n");
623                 pthread_mutex_unlock(&surface_queue->lock);
624                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
625         }
626
627         *surface = node->surface;
628
629         pthread_mutex_unlock(&surface_queue->lock);
630
631         return TBM_SURFACE_QUEUE_ERROR_NONE;
632 }
633
634 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
635 {
636         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
637
638         pthread_mutex_lock(&surface_queue->lock);
639
640         if (_queue_is_empty(&surface_queue->free_queue)) {
641                 if (surface_queue->impl && surface_queue->impl->need_attach)
642                         surface_queue->impl->need_attach(surface_queue);
643         }
644
645         if (_queue_is_empty(&surface_queue->free_queue)) {
646                 if (wait) {
647                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
648                         pthread_mutex_unlock(&surface_queue->lock);
649                         return 1;
650                 }
651
652                 pthread_mutex_unlock(&surface_queue->lock);
653                 return 0;
654         }
655
656         pthread_mutex_unlock(&surface_queue->lock);
657
658         return 1;
659 }
660
661 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
662 {
663         queue_node *node = NULL;
664         int queue_type;
665
666         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
667         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
668
669         pthread_mutex_lock(&surface_queue->lock);
670
671         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
672         if (node == NULL || queue_type != NODE_LIST)
673         {
674                 TBM_LOG("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
675                 pthread_mutex_unlock(&surface_queue->lock);
676                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
677         }
678
679         if (surface_queue->impl && surface_queue->impl->release)
680                 surface_queue->impl->release(surface_queue, node);
681         else
682                 _tbm_surface_queue_release(surface_queue, node, 1);
683
684         if (_queue_is_empty(&surface_queue->free_queue)) {
685                 pthread_mutex_unlock(&surface_queue->lock);
686                 return TBM_SURFACE_QUEUE_ERROR_NONE;
687         }
688
689         pthread_mutex_unlock(&surface_queue->lock);
690         pthread_cond_signal(&surface_queue->free_cond);
691
692         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
693         if (surface_queue->dequeuable_cb)
694                 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
695
696         return TBM_SURFACE_QUEUE_ERROR_NONE;
697 }
698
699 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
700 {
701         queue_node *node = NULL;
702
703         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
704         TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
705
706         pthread_mutex_lock(&surface_queue->lock);
707
708         if (surface_queue->impl && surface_queue->impl->acquire)
709                 node = surface_queue->impl->acquire(surface_queue);
710         else
711                 node = _tbm_surface_queue_acquire(surface_queue);
712
713         if (node == NULL) {
714                 *surface = NULL;
715                 pthread_mutex_unlock(&surface_queue->lock);
716                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
717         }
718
719         if (node->surface == NULL) {
720                 *surface = NULL;
721                 TBM_LOG("_queue_node_pop_front  failed\n");
722                 pthread_mutex_unlock(&surface_queue->lock);
723                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
724         }
725
726         *surface = node->surface;
727
728         pthread_mutex_unlock(&surface_queue->lock);
729
730         return TBM_SURFACE_QUEUE_ERROR_NONE;
731 }
732
733 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
734 {
735         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
736
737         pthread_mutex_lock(&surface_queue->lock);
738
739         if (_queue_is_empty(&surface_queue->dirty_queue)) {
740                 if (wait) {
741                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
742                         pthread_mutex_unlock(&surface_queue->lock);
743                         return 1;
744                 }
745
746                 pthread_mutex_unlock(&surface_queue->lock);
747                 return 0;
748         }
749
750         pthread_mutex_unlock(&surface_queue->lock);
751
752         return 1;
753 }
754
755 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
756 {
757         queue_node *node = NULL, *tmp = NULL;
758
759         TBM_RETURN_IF_FAIL(surface_queue != NULL);
760
761         if (surface_queue->destroy_cb)
762                 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
763
764         _notify_emit(surface_queue, &surface_queue->destory_noti);
765
766         if (surface_queue->impl && surface_queue->impl->destroy)
767                 surface_queue->impl->destroy(surface_queue);
768
769         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
770                 _queue_node_delete(node);
771         }
772
773         _notify_remove_all(&surface_queue->destory_noti);
774         _notify_remove_all(&surface_queue->acquirable_noti);
775         _notify_remove_all(&surface_queue->dequeuable_noti);
776         _notify_remove_all(&surface_queue->reset_noti);
777
778         pthread_mutex_destroy(&surface_queue->lock);
779         free(surface_queue);
780 }
781
782 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
783 {
784         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
785
786         queue_node *node = NULL, *tmp = NULL;
787
788         if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
789                 return TBM_SURFACE_QUEUE_ERROR_NONE;
790
791         pthread_mutex_lock(&surface_queue->lock);
792
793         surface_queue->width = width;
794         surface_queue->height = height;
795         surface_queue->format = format;
796
797         /* Destory surface and Push to free_queue */
798         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
799         {
800                 _queue_node_delete(node);
801         }
802
803         /* Reset queue */
804         _queue_init(&surface_queue->free_queue);
805         _queue_init(&surface_queue->dirty_queue);
806         LIST_INITHEAD(&surface_queue->list);
807
808         if (surface_queue->impl && surface_queue->impl->reset)
809                 surface_queue->impl->reset(surface_queue);
810
811         pthread_mutex_unlock(&surface_queue->lock);
812         pthread_cond_signal(&surface_queue->free_cond);
813
814         _notify_emit(surface_queue, &surface_queue->reset_noti);
815         if (surface_queue->reset_cb)
816                 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
817
818         return TBM_SURFACE_QUEUE_ERROR_NONE;
819 }
820
821 typedef struct
822 {
823         int queue_size;
824         int num_attached;
825         int flags;
826 }tbm_queue_default;
827
828 static void __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
829 {
830         tbm_queue_default* data = surface_queue->impl_data;
831         data->num_attached = 0;
832 }
833
834 static void __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
835 {
836         tbm_queue_default* data = surface_queue->impl_data;
837         data->num_attached = 0;
838 }
839
840 static void __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
841 {
842         free(surface_queue->impl_data);
843 }
844
845 static void __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
846 {
847         tbm_queue_default* data = surface_queue->impl_data;
848         tbm_surface_h surface;
849
850         if (data->queue_size == data->num_attached)
851                 return;
852
853         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
854                                                 surface_queue->height,
855                                                 surface_queue->format,
856                                                 data->flags);
857         TBM_RETURN_IF_FAIL(surface != NULL);
858         _tbm_surface_queue_attach(surface_queue, surface);
859         tbm_surface_internal_unref(surface);
860         data->num_attached++;
861 }
862
863 static const tbm_surface_queue_interface tbm_queue_default_impl =
864 {
865         __tbm_queue_default_init,
866         __tbm_queue_default_reset,
867         __tbm_queue_default_destroy,
868         __tbm_queue_default_need_attach,
869         NULL,                           /*__tbm_queue_default_enqueue*/
870         NULL,                           /*__tbm_queue_default_release*/
871         NULL,                           /*__tbm_queue_default_dequeue*/
872         NULL,                           /*__tbm_queue_default_acquire*/
873 };
874
875 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
876 {
877         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
878         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
879         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
880         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
881
882         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
883         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
884
885         tbm_queue_default *data = (tbm_queue_default *) calloc(1, sizeof(tbm_queue_default));
886         if (data == NULL)
887         {
888                 free(surface_queue);
889                 return NULL;
890         }
891
892         data->queue_size = queue_size;
893         data->flags = flags;
894         _tbm_surface_queue_init(surface_queue,
895                 width, height, format,
896                 &tbm_queue_default_impl, data);
897
898         return surface_queue;
899 }
900
901 typedef struct
902 {
903         int queue_size;
904         int num_attached;
905         int flags;
906         queue dequeue_list;
907 }tbm_queue_sequence;
908
909 static void __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
910 {
911         tbm_queue_sequence* data = surface_queue->impl_data;
912
913         data->num_attached = 0;
914         _queue_init(&data->dequeue_list);
915 }
916
917 static void __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
918 {
919         tbm_queue_sequence* data = surface_queue->impl_data;
920
921         data->num_attached = 0;
922         _queue_init(&data->dequeue_list);
923 }
924
925 static void __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
926 {
927         free(surface_queue->impl_data);
928 }
929
930 static void __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
931 {
932         tbm_queue_sequence* data = surface_queue->impl_data;
933         tbm_surface_h surface;
934
935         if (data->queue_size == data->num_attached)
936                 return;
937
938         surface = tbm_surface_internal_create_with_flags(surface_queue->width,
939                                                 surface_queue->height,
940                                                 surface_queue->format,
941                                                 data->flags);
942         TBM_RETURN_IF_FAIL(surface != NULL);
943         _tbm_surface_queue_attach(surface_queue, surface);
944         tbm_surface_internal_unref(surface);
945         data->num_attached++;
946 }
947
948 static void __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue, queue_node* node)
949 {
950         tbm_queue_sequence* data = surface_queue->impl_data;
951         queue_node *next = NULL;
952         queue_node *tmp = NULL;
953
954         node->priv_flags = 0;
955
956         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
957                 if (next->priv_flags) break;
958         _queue_node_pop(&data->dequeue_list, next);
959                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
960         }
961 }
962
963 static queue_node* __tbm_queue_sequence_dequeue(tbm_surface_queue_h surface_queue)
964 {
965         tbm_queue_sequence* data = surface_queue->impl_data;
966         queue_node* node = NULL;
967
968         node = _tbm_surface_queue_dequeue(surface_queue);
969         if (node)
970         {
971                 _queue_node_push_back(&data->dequeue_list, node);
972                 node->priv_flags = 1;
973         }
974
975         return node;
976 }
977
978 static const tbm_surface_queue_interface tbm_queue_sequence_impl =
979 {
980         __tbm_queue_sequence_init,
981         __tbm_queue_sequence_reset,
982         __tbm_queue_sequence_destroy,
983         __tbm_queue_sequence_need_attach,
984         __tbm_queue_sequence_enqueue,
985         NULL,                           /*__tbm_queue_sequence_release*/
986         __tbm_queue_sequence_dequeue,
987         NULL,                           /*__tbm_queue_sequence_acquire*/
988 };
989
990 tbm_surface_queue_h tbm_surface_queue_sequence_create(int queue_size, int width, int height, int format, int flags)
991 {
992         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
993         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
994         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
995         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
996
997         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
998         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
999
1000         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1, sizeof(tbm_queue_sequence));
1001         if (data == NULL)
1002         {
1003                 free(surface_queue);
1004                 return NULL;
1005         }
1006
1007         data->queue_size = queue_size;
1008         data->flags = flags;
1009         _tbm_surface_queue_init(surface_queue,
1010                 width, height, format,
1011                 &tbm_queue_sequence_impl, data);
1012
1013         return surface_queue;
1014 }