bugfix: reset_notificaton
[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_QUEUE_TRACE(fmt, ...)  fprintf(stderr, "[TBM(%d):%s] " fmt, getpid(), __func__, ##__VA_ARGS__)
43 #define TBM_LOCK() TBM_LOG("[LOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
44 #define TBM_UNLOCK() TBM_LOG("[UNLOCK] %s:%d surface:%p\n", __func__, __LINE__, surface_queue)
45 #else
46 #define TBM_QUEUE_TRACE(fmt, ...)
47 #define TBM_LOCK()
48 #define TBM_UNLOCK()
49 #endif
50
51 typedef struct {
52         struct list_head head;
53         int count;
54 } queue;
55
56 typedef struct {
57         tbm_surface_h surface;
58
59         struct list_head item_link;
60         struct list_head link;
61
62         unsigned int priv_flags;        /*for each queue*/
63 } queue_node;
64
65 typedef struct {
66         struct list_head link;
67
68         tbm_surface_queue_notify_cb cb;
69         void *data;
70 } queue_notify;
71
72 typedef struct _tbm_surface_queue_interface {
73         void (*init)(tbm_surface_queue_h queue);
74         void (*reset)(tbm_surface_queue_h queue);
75         void (*destroy)(tbm_surface_queue_h queue);
76         void (*need_attach)(tbm_surface_queue_h queue);
77
78         void (*enqueue)(tbm_surface_queue_h queue, queue_node *node);
79         void (*release)(tbm_surface_queue_h queue, queue_node *node);
80         queue_node *(*dequeue)(tbm_surface_queue_h queue);
81         queue_node *(*acquire)(tbm_surface_queue_h queue);
82 } tbm_surface_queue_interface;
83
84 struct _tbm_surface_queue {
85         int width;
86         int height;
87         int format;
88         int queue_size;
89
90         queue free_queue;
91         queue dirty_queue;
92         struct list_head list;
93
94         struct list_head destory_noti;
95         struct list_head dequeuable_noti;
96         struct list_head acquirable_noti;
97         struct list_head reset_noti;
98
99         pthread_mutex_t lock;
100         pthread_cond_t free_cond;
101         pthread_cond_t dirty_cond;
102
103         const tbm_surface_queue_interface *impl;
104         void *impl_data;
105
106         //For external buffer allocation
107         tbm_surface_alloc_cb alloc_cb;
108         tbm_surface_free_cb free_cb;
109         void *alloc_cb_data;
110 };
111
112 static queue_node *
113 _queue_node_create(void)
114 {
115         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
116
117         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
118
119         return node;
120 }
121
122 static void
123 _queue_node_delete(queue_node *node)
124 {
125         LIST_DEL(&node->item_link);
126         LIST_DEL(&node->link);
127         free(node);
128 }
129
130 static int
131 _queue_is_empty(queue *queue)
132 {
133         if (LIST_IS_EMPTY(&queue->head))
134                 return 1;
135
136         return 0;
137 }
138
139 static void
140 _queue_node_push_back(queue *queue, queue_node *node)
141 {
142         LIST_ADDTAIL(&node->item_link, &queue->head);
143         queue->count++;
144 }
145
146 static void
147 _queue_node_push_front(queue *queue, queue_node *node)
148 {
149         LIST_ADD(&node->item_link, &queue->head);
150         queue->count++;
151 }
152
153 static queue_node *
154 _queue_node_pop_front(queue *queue)
155 {
156         queue_node *node = NULL;
157
158         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
159
160         LIST_DEL(&node->item_link);
161         queue->count--;
162
163         return node;
164 }
165
166 static queue_node *
167 _queue_node_pop(queue *queue, queue_node *node)
168 {
169         LIST_DEL(&node->item_link);
170         queue->count--;
171
172         return node;
173 }
174
175 static queue_node *
176 _queue_get_node(tbm_surface_queue_h surface_queue, int type,
177                 tbm_surface_h surface, int *out_type)
178 {
179         queue_node *node = NULL;
180         queue_node *tmp = NULL;
181
182         if (type == 0)
183                 type = FREE_QUEUE | DIRTY_QUEUE | NODE_LIST;
184         if (out_type)
185                 *out_type = 0;
186
187         if (type & FREE_QUEUE) {
188                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head,
189                                          item_link) {
190                         if (node->surface == surface) {
191                                 if (out_type)
192                                         *out_type = FREE_QUEUE;
193
194                                 return node;
195                         }
196                 }
197         }
198
199         if (type & DIRTY_QUEUE) {
200                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head,
201                                          item_link) {
202                         if (node->surface == surface) {
203                                 if (out_type)
204                                         *out_type = DIRTY_QUEUE;
205
206                                 return node;
207                         }
208                 }
209         }
210
211         if (type & NODE_LIST) {
212                 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
213                         if (node->surface == surface) {
214                                 if (out_type)
215                                         *out_type = NODE_LIST;
216
217                                 return node;
218                         }
219                 }
220         }
221
222         return NULL;
223 }
224
225 static void
226 _queue_delete_node(tbm_surface_queue_h surface_queue, queue_node *node)
227 {
228         if (node->surface) {
229                 if (surface_queue->free_cb) {
230                         surface_queue->free_cb(surface_queue,
231                                         surface_queue->alloc_cb_data,
232                                         node->surface);
233                 }
234
235                 tbm_surface_destroy(node->surface);
236         }
237
238         _queue_node_delete(node);
239 }
240
241 static void
242 _queue_init(queue *queue)
243 {
244         LIST_INITHEAD(&queue->head);
245
246         queue->count = 0;
247 }
248
249 static void
250 _notify_add(struct list_head *list, tbm_surface_queue_notify_cb cb,
251             void *data)
252 {
253         TBM_RETURN_IF_FAIL(cb != NULL);
254
255         queue_notify *item = (queue_notify *)calloc(1, sizeof(queue_notify));
256
257         TBM_RETURN_IF_FAIL(item != NULL);
258
259         LIST_INITHEAD(&item->link);
260         item->cb = cb;
261         item->data = data;
262
263         LIST_ADDTAIL(&item->link, list);
264 }
265
266 static void
267 _notify_remove(struct list_head *list,
268                tbm_surface_queue_notify_cb cb, void *data)
269 {
270         queue_notify *item = NULL, *tmp = NULL;
271
272         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
273                 if (item->cb == cb && item->data == data) {
274                         LIST_DEL(&item->link);
275                         free(item);
276                         return;
277                 }
278         }
279
280         TBM_LOG("Cannot find notifiy\n");
281 }
282
283 static void
284 _notify_remove_all(struct list_head *list)
285 {
286         queue_notify *item = NULL, *tmp = NULL;
287
288         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
289                 LIST_DEL(&item->link);
290                 free(item);
291         }
292 }
293
294 static void
295 _notify_emit(tbm_surface_queue_h surface_queue,
296              struct list_head *list)
297 {
298         queue_notify *item = NULL, *tmp = NULL;
299
300         LIST_FOR_EACH_ENTRY_SAFE(item, tmp, list, link) {
301                 item->cb(surface_queue, item->data);
302         }
303 }
304
305 void
306 _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue,
307                           tbm_surface_h surface)
308 {
309         queue_node *node = NULL;
310
311         node = _queue_node_create();
312         TBM_RETURN_IF_FAIL(node != NULL);
313
314         tbm_surface_internal_ref(surface);
315         node->surface = surface;
316
317         LIST_ADDTAIL(&node->link, &surface_queue->list);
318         _queue_node_push_back(&surface_queue->free_queue, node);
319 }
320
321 void
322 _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue,
323                           tbm_surface_h surface)
324 {
325         queue_node *node = NULL;
326         int queue_type;
327
328         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
329         if (node)
330                 _queue_delete_node(surface_queue, node);
331 }
332
333 void
334 _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue,
335                            queue_node *node, int push_back)
336 {
337         if (push_back)
338                 _queue_node_push_back(&surface_queue->dirty_queue, node);
339         else
340                 _queue_node_push_front(&surface_queue->dirty_queue, node);
341 }
342
343 queue_node *
344 _tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue)
345 {
346         queue_node *node = NULL;
347
348         if (_queue_is_empty(&surface_queue->free_queue)) {
349                 if (surface_queue->impl && surface_queue->impl->need_attach)
350                         surface_queue->impl->need_attach(surface_queue);
351
352                 if (_queue_is_empty(&surface_queue->free_queue))
353                         return NULL;
354         }
355
356         node = _queue_node_pop_front(&surface_queue->free_queue);
357
358         return node;
359 }
360
361 queue_node *
362 _tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue)
363 {
364         queue_node *node = NULL;
365
366         if (_queue_is_empty(&surface_queue->dirty_queue))
367                 return NULL;
368
369         node = _queue_node_pop_front(&surface_queue->dirty_queue);
370
371         return node;
372 }
373
374 void
375 _tbm_surface_queue_release(tbm_surface_queue_h surface_queue,
376                            queue_node *node, int push_back)
377 {
378         if (push_back)
379                 _queue_node_push_back(&surface_queue->free_queue, node);
380         else
381                 _queue_node_push_front(&surface_queue->free_queue, node);
382 }
383
384 void
385 _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
386                         int queue_size,
387                         int width, int height, int format,
388                         const tbm_surface_queue_interface *impl, void *data)
389 {
390         TBM_RETURN_IF_FAIL(surface_queue != NULL);
391         TBM_RETURN_IF_FAIL(impl != NULL);
392
393         memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
394
395         pthread_mutex_init(&surface_queue->lock, NULL);
396         pthread_cond_init(&surface_queue->free_cond, NULL);
397         pthread_cond_init(&surface_queue->dirty_cond, NULL);
398
399         surface_queue->queue_size = queue_size;
400         surface_queue->width = width;
401         surface_queue->height = height;
402         surface_queue->format = format;
403         surface_queue->impl = impl;
404         surface_queue->impl_data = data;
405
406         _queue_init(&surface_queue->free_queue);
407         _queue_init(&surface_queue->dirty_queue);
408         LIST_INITHEAD(&surface_queue->list);
409
410         LIST_INITHEAD(&surface_queue->destory_noti);
411         LIST_INITHEAD(&surface_queue->acquirable_noti);
412         LIST_INITHEAD(&surface_queue->dequeuable_noti);
413         LIST_INITHEAD(&surface_queue->reset_noti);
414
415         if (surface_queue->impl && surface_queue->impl->init)
416                 surface_queue->impl->init(surface_queue);
417 }
418
419 tbm_surface_queue_error_e
420 tbm_surface_queue_add_destroy_cb(
421         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
422         void *data)
423 {
424         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
425                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
426
427         pthread_mutex_lock(&surface_queue->lock);
428
429         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
430
431         _notify_add(&surface_queue->destory_noti, destroy_cb, data);
432
433         pthread_mutex_unlock(&surface_queue->lock);
434
435         return TBM_SURFACE_QUEUE_ERROR_NONE;
436 }
437
438 tbm_surface_queue_error_e
439 tbm_surface_queue_remove_destroy_cb(
440         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb,
441         void *data)
442 {
443         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
444                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
445
446         pthread_mutex_lock(&surface_queue->lock);
447
448         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
449
450         _notify_remove(&surface_queue->destory_noti, destroy_cb, data);
451
452         pthread_mutex_unlock(&surface_queue->lock);
453
454         return TBM_SURFACE_QUEUE_ERROR_NONE;
455 }
456
457 tbm_surface_queue_error_e
458 tbm_surface_queue_add_dequeuable_cb(
459         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
460         void *data)
461 {
462         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
463                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
464
465         pthread_mutex_lock(&surface_queue->lock);
466
467         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
468
469         _notify_add(&surface_queue->dequeuable_noti, dequeuable_cb, data);
470
471         pthread_mutex_unlock(&surface_queue->lock);
472
473         return TBM_SURFACE_QUEUE_ERROR_NONE;
474 }
475
476 tbm_surface_queue_error_e
477 tbm_surface_queue_remove_dequeuable_cb(
478         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb,
479         void *data)
480 {
481         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
482                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
483
484         pthread_mutex_lock(&surface_queue->lock);
485
486         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
487
488         _notify_remove(&surface_queue->dequeuable_noti, dequeuable_cb, data);
489
490         pthread_mutex_unlock(&surface_queue->lock);
491
492         return TBM_SURFACE_QUEUE_ERROR_NONE;
493 }
494
495 tbm_surface_queue_error_e
496 tbm_surface_queue_add_acquirable_cb(
497         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
498         void *data)
499 {
500         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
501                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
502
503         pthread_mutex_lock(&surface_queue->lock);
504
505         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
506
507         _notify_add(&surface_queue->acquirable_noti, acquirable_cb, data);
508
509         pthread_mutex_unlock(&surface_queue->lock);
510
511         return TBM_SURFACE_QUEUE_ERROR_NONE;
512 }
513
514 tbm_surface_queue_error_e
515 tbm_surface_queue_remove_acquirable_cb(
516         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb,
517         void *data)
518 {
519         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
520                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
521
522         pthread_mutex_lock(&surface_queue->lock);
523
524         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
525
526         _notify_remove(&surface_queue->acquirable_noti, acquirable_cb, data);
527
528         pthread_mutex_unlock(&surface_queue->lock);
529
530         return TBM_SURFACE_QUEUE_ERROR_NONE;
531 }
532
533 tbm_surface_queue_error_e
534 tbm_surface_queue_set_alloc_cb(
535         tbm_surface_queue_h surface_queue,
536         tbm_surface_alloc_cb alloc_cb,
537         tbm_surface_free_cb free_cb,
538         void *data)
539 {
540         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
541                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
542
543         pthread_mutex_lock(&surface_queue->lock);
544
545         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
546
547         surface_queue->alloc_cb = alloc_cb;
548         surface_queue->free_cb = free_cb;
549         surface_queue->alloc_cb_data = data;
550
551         pthread_mutex_unlock(&surface_queue->lock);
552
553         return TBM_SURFACE_QUEUE_ERROR_NONE;
554 }
555
556 int
557 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
558 {
559         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
560
561         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
562
563         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
564
565         return surface_queue->width;
566 }
567
568 int
569 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
570 {
571         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
572
573         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
574
575         return surface_queue->height;
576 }
577
578 int
579 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
580 {
581         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
582
583         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
584
585         return surface_queue->format;
586 }
587
588 int
589 tbm_surface_queue_get_size(tbm_surface_queue_h surface_queue)
590 {
591         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
592
593         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
594
595         return surface_queue->queue_size;
596 }
597
598 tbm_surface_queue_error_e
599 tbm_surface_queue_add_reset_cb(
600         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
601         void *data)
602 {
603         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
604                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
605
606         pthread_mutex_lock(&surface_queue->lock);
607
608         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
609
610         _notify_add(&surface_queue->reset_noti, reset_cb, data);
611
612         pthread_mutex_unlock(&surface_queue->lock);
613
614         return TBM_SURFACE_QUEUE_ERROR_NONE;
615 }
616
617 tbm_surface_queue_error_e
618 tbm_surface_queue_remove_reset_cb(
619         tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb,
620         void *data)
621 {
622         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
623                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
624
625         pthread_mutex_lock(&surface_queue->lock);
626
627         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
628
629         _notify_remove(&surface_queue->acquirable_noti, reset_cb, data);
630
631         pthread_mutex_unlock(&surface_queue->lock);
632
633         return TBM_SURFACE_QUEUE_ERROR_NONE;
634 }
635
636 tbm_surface_queue_error_e
637 tbm_surface_queue_enqueue(tbm_surface_queue_h
638                           surface_queue, tbm_surface_h surface)
639 {
640         queue_node *node = NULL;
641         int queue_type;
642
643         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
644                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
645         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
646                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
647
648         pthread_mutex_lock(&surface_queue->lock);
649
650         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
651
652         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
653         if (node == NULL || queue_type != NODE_LIST) {
654                 TBM_LOG("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
655                         node, queue_type);
656                 pthread_mutex_unlock(&surface_queue->lock);
657                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
658         }
659
660         if (surface_queue->impl && surface_queue->impl->enqueue)
661                 surface_queue->impl->enqueue(surface_queue, node);
662         else
663                 _tbm_surface_queue_enqueue(surface_queue, node, 1);
664
665         if (_queue_is_empty(&surface_queue->dirty_queue)) {
666                 pthread_mutex_unlock(&surface_queue->lock);
667                 return TBM_SURFACE_QUEUE_ERROR_NONE;
668         }
669
670         pthread_mutex_unlock(&surface_queue->lock);
671         pthread_cond_signal(&surface_queue->dirty_cond);
672
673         _notify_emit(surface_queue, &surface_queue->acquirable_noti);
674
675         return TBM_SURFACE_QUEUE_ERROR_NONE;
676 }
677
678 tbm_surface_queue_error_e
679 tbm_surface_queue_dequeue(tbm_surface_queue_h
680                           surface_queue, tbm_surface_h *surface)
681 {
682         queue_node *node = NULL;
683
684         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
685                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
686         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
687                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
688
689         pthread_mutex_lock(&surface_queue->lock);
690
691         if (surface_queue->impl && surface_queue->impl->dequeue)
692                 node = surface_queue->impl->dequeue(surface_queue);
693         else
694                 node = _tbm_surface_queue_dequeue(surface_queue);
695
696         if (node == NULL) {
697                 *surface = NULL;
698                 pthread_mutex_unlock(&surface_queue->lock);
699                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
700         }
701
702         if (node->surface == NULL) {
703                 *surface = NULL;
704                 TBM_LOG("_queue_node_pop_front  failed\n");
705                 pthread_mutex_unlock(&surface_queue->lock);
706                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
707         }
708
709         *surface = node->surface;
710
711         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
712
713         pthread_mutex_unlock(&surface_queue->lock);
714
715         return TBM_SURFACE_QUEUE_ERROR_NONE;
716 }
717
718 int
719 tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
720 {
721         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
722
723         pthread_mutex_lock(&surface_queue->lock);
724
725         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
726
727         if (_queue_is_empty(&surface_queue->free_queue)) {
728                 if (surface_queue->impl && surface_queue->impl->need_attach)
729                         surface_queue->impl->need_attach(surface_queue);
730         }
731
732         if (_queue_is_empty(&surface_queue->free_queue)) {
733                 if (wait) {
734                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
735                         pthread_mutex_unlock(&surface_queue->lock);
736                         return 1;
737                 }
738
739                 pthread_mutex_unlock(&surface_queue->lock);
740                 return 0;
741         }
742
743         pthread_mutex_unlock(&surface_queue->lock);
744
745         return 1;
746 }
747
748 tbm_surface_queue_error_e
749 tbm_surface_queue_release(tbm_surface_queue_h
750                           surface_queue, tbm_surface_h surface)
751 {
752         queue_node *node = NULL;
753         int queue_type;
754
755         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
756                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
757         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
758                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
759
760         pthread_mutex_lock(&surface_queue->lock);
761
762         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, surface);
763
764         node = _queue_get_node(surface_queue, 0, surface, &queue_type);
765         if (node == NULL || queue_type != NODE_LIST) {
766                 TBM_LOG("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n",
767                         node, queue_type);
768                 pthread_mutex_unlock(&surface_queue->lock);
769                 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
770         }
771
772         if (surface_queue->impl && surface_queue->impl->release)
773                 surface_queue->impl->release(surface_queue, node);
774         else
775                 _tbm_surface_queue_release(surface_queue, node, 1);
776
777         if (_queue_is_empty(&surface_queue->free_queue)) {
778                 pthread_mutex_unlock(&surface_queue->lock);
779                 return TBM_SURFACE_QUEUE_ERROR_NONE;
780         }
781
782         pthread_mutex_unlock(&surface_queue->lock);
783         pthread_cond_signal(&surface_queue->free_cond);
784
785         _notify_emit(surface_queue, &surface_queue->dequeuable_noti);
786
787         return TBM_SURFACE_QUEUE_ERROR_NONE;
788 }
789
790 tbm_surface_queue_error_e
791 tbm_surface_queue_acquire(tbm_surface_queue_h
792                           surface_queue, tbm_surface_h *surface)
793 {
794         queue_node *node = NULL;
795
796         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
797                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
798         TBM_RETURN_VAL_IF_FAIL(surface != NULL,
799                                TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
800
801         pthread_mutex_lock(&surface_queue->lock);
802
803         if (surface_queue->impl && surface_queue->impl->acquire)
804                 node = surface_queue->impl->acquire(surface_queue);
805         else
806                 node = _tbm_surface_queue_acquire(surface_queue);
807
808         if (node == NULL) {
809                 *surface = NULL;
810                 pthread_mutex_unlock(&surface_queue->lock);
811                 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
812         }
813
814         if (node->surface == NULL) {
815                 *surface = NULL;
816                 TBM_LOG("_queue_node_pop_front  failed\n");
817                 pthread_mutex_unlock(&surface_queue->lock);
818                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
819         }
820
821         *surface = node->surface;
822
823         TBM_QUEUE_TRACE("tbm_surface_queue(%p) tbm_surface(%p)\n", surface_queue, *surface);
824
825         pthread_mutex_unlock(&surface_queue->lock);
826
827         return TBM_SURFACE_QUEUE_ERROR_NONE;
828 }
829
830 int
831 tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
832 {
833         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
834
835         pthread_mutex_lock(&surface_queue->lock);
836
837         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
838
839         if (_queue_is_empty(&surface_queue->dirty_queue)) {
840                 if (wait) {
841                         pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
842                         pthread_mutex_unlock(&surface_queue->lock);
843                         return 1;
844                 }
845
846                 pthread_mutex_unlock(&surface_queue->lock);
847                 return 0;
848         }
849
850         pthread_mutex_unlock(&surface_queue->lock);
851
852         return 1;
853 }
854
855 void
856 tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
857 {
858         queue_node *node = NULL, *tmp = NULL;
859
860         TBM_RETURN_IF_FAIL(surface_queue != NULL);
861
862         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
863
864         _notify_emit(surface_queue, &surface_queue->destory_noti);
865
866         if (surface_queue->impl && surface_queue->impl->destroy)
867                 surface_queue->impl->destroy(surface_queue);
868
869         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
870                 _queue_delete_node(surface_queue, node);
871         }
872
873         _notify_remove_all(&surface_queue->destory_noti);
874         _notify_remove_all(&surface_queue->acquirable_noti);
875         _notify_remove_all(&surface_queue->dequeuable_noti);
876         _notify_remove_all(&surface_queue->reset_noti);
877
878         pthread_mutex_destroy(&surface_queue->lock);
879         free(surface_queue);
880 }
881
882 tbm_surface_queue_error_e
883 tbm_surface_queue_reset(tbm_surface_queue_h
884                         surface_queue, int width, int height, int format)
885 {
886         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
887                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
888
889         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
890
891         queue_node *node = NULL, *tmp = NULL;
892
893         if (width == surface_queue->width && height == surface_queue->height &&
894             format == surface_queue->format)
895                 return TBM_SURFACE_QUEUE_ERROR_NONE;
896
897         pthread_mutex_lock(&surface_queue->lock);
898
899         surface_queue->width = width;
900         surface_queue->height = height;
901         surface_queue->format = format;
902
903         /* Destory surface and Push to free_queue */
904         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
905                 _queue_delete_node(surface_queue, node);
906         }
907
908         /* Reset queue */
909         _queue_init(&surface_queue->free_queue);
910         _queue_init(&surface_queue->dirty_queue);
911         LIST_INITHEAD(&surface_queue->list);
912
913         if (surface_queue->impl && surface_queue->impl->reset)
914                 surface_queue->impl->reset(surface_queue);
915
916         pthread_mutex_unlock(&surface_queue->lock);
917         pthread_cond_signal(&surface_queue->free_cond);
918
919         _notify_emit(surface_queue, &surface_queue->reset_noti);
920
921         return TBM_SURFACE_QUEUE_ERROR_NONE;
922 }
923
924 tbm_surface_queue_error_e
925 tbm_surface_queue_flush(tbm_surface_queue_h surface_queue)
926 {
927         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL,
928                                TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
929
930         queue_node *node = NULL, *tmp = NULL;
931
932         pthread_mutex_lock(&surface_queue->lock);
933
934         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
935
936         /* Destory surface and Push to free_queue */
937         LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
938                 _queue_delete_node(surface_queue, node);
939         }
940
941         /* Reset queue */
942         _queue_init(&surface_queue->free_queue);
943         _queue_init(&surface_queue->dirty_queue);
944         LIST_INITHEAD(&surface_queue->list);
945
946         if (surface_queue->impl && surface_queue->impl->reset)
947                 surface_queue->impl->reset(surface_queue);
948
949         _notify_emit(surface_queue, &surface_queue->reset_noti);
950
951         pthread_mutex_unlock(&surface_queue->lock);
952         pthread_cond_signal(&surface_queue->free_cond);
953
954         return TBM_SURFACE_QUEUE_ERROR_NONE;
955 }
956
957 typedef struct {
958         int queue_size;
959         int num_attached;
960         int flags;
961 } tbm_queue_default;
962
963 static void
964 __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
965 {
966         tbm_queue_default *data = surface_queue->impl_data;
967
968         data->num_attached = 0;
969 }
970
971 static void
972 __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
973 {
974         tbm_queue_default *data = surface_queue->impl_data;
975
976         data->num_attached = 0;
977 }
978
979 static void
980 __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
981 {
982         free(surface_queue->impl_data);
983 }
984
985 static void
986 __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
987 {
988         tbm_queue_default *data = surface_queue->impl_data;
989         tbm_surface_h surface;
990
991         if (data->queue_size == data->num_attached)
992                 return;
993
994         if (surface_queue->alloc_cb) {
995                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
996                 TBM_RETURN_IF_FAIL(surface != NULL);
997                 tbm_surface_internal_ref(surface);
998         } else {
999                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1000                                 surface_queue->height,
1001                                 surface_queue->format,
1002                                 data->flags);
1003                 TBM_RETURN_IF_FAIL(surface != NULL);
1004         }
1005
1006         _tbm_surface_queue_attach(surface_queue, surface);
1007         tbm_surface_internal_unref(surface);
1008         data->num_attached++;
1009 }
1010
1011 static const tbm_surface_queue_interface tbm_queue_default_impl = {
1012         __tbm_queue_default_init,
1013         __tbm_queue_default_reset,
1014         __tbm_queue_default_destroy,
1015         __tbm_queue_default_need_attach,
1016         NULL,                           /*__tbm_queue_default_enqueue*/
1017         NULL,                           /*__tbm_queue_default_release*/
1018         NULL,                           /*__tbm_queue_default_dequeue*/
1019         NULL,                           /*__tbm_queue_default_acquire*/
1020 };
1021
1022 tbm_surface_queue_h
1023 tbm_surface_queue_create(int queue_size, int width,
1024                          int height, int format, int flags)
1025 {
1026         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1027         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1028         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1029         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1030
1031         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1032                                             sizeof(struct _tbm_surface_queue));
1033         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1034
1035         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1036
1037         tbm_queue_default *data = (tbm_queue_default *) calloc(1,
1038                                   sizeof(tbm_queue_default));
1039         if (data == NULL) {
1040                 free(surface_queue);
1041                 return NULL;
1042         }
1043
1044         data->queue_size = queue_size;
1045         data->flags = flags;
1046         _tbm_surface_queue_init(surface_queue,
1047                                 data->queue_size,
1048                                 width, height, format,
1049                                 &tbm_queue_default_impl, data);
1050
1051         return surface_queue;
1052 }
1053
1054 typedef struct {
1055         int queue_size;
1056         int num_attached;
1057         int flags;
1058         queue dequeue_list;
1059 } tbm_queue_sequence;
1060
1061 static void
1062 __tbm_queue_sequence_init(tbm_surface_queue_h surface_queue)
1063 {
1064         tbm_queue_sequence *data = surface_queue->impl_data;
1065
1066         data->num_attached = 0;
1067         _queue_init(&data->dequeue_list);
1068 }
1069
1070 static void
1071 __tbm_queue_sequence_reset(tbm_surface_queue_h surface_queue)
1072 {
1073         tbm_queue_sequence *data = surface_queue->impl_data;
1074
1075         data->num_attached = 0;
1076         _queue_init(&data->dequeue_list);
1077 }
1078
1079 static void
1080 __tbm_queue_sequence_destroy(tbm_surface_queue_h surface_queue)
1081 {
1082         free(surface_queue->impl_data);
1083 }
1084
1085 static void
1086 __tbm_queue_sequence_need_attach(tbm_surface_queue_h surface_queue)
1087 {
1088         tbm_queue_sequence *data = surface_queue->impl_data;
1089         tbm_surface_h surface;
1090
1091         if (data->queue_size == data->num_attached)
1092                 return;
1093
1094         if (surface_queue->alloc_cb) {
1095                 surface = surface_queue->alloc_cb(surface_queue, surface_queue->alloc_cb_data);
1096                 TBM_RETURN_IF_FAIL(surface != NULL);
1097                 tbm_surface_internal_ref(surface);
1098         } else {
1099                 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
1100                                 surface_queue->height,
1101                                 surface_queue->format,
1102                                 data->flags);
1103                 TBM_RETURN_IF_FAIL(surface != NULL);
1104         }
1105
1106         _tbm_surface_queue_attach(surface_queue, surface);
1107         tbm_surface_internal_unref(surface);
1108         data->num_attached++;
1109 }
1110
1111 static void
1112 __tbm_queue_sequence_enqueue(tbm_surface_queue_h surface_queue,
1113                              queue_node *node)
1114 {
1115         tbm_queue_sequence *data = surface_queue->impl_data;
1116         queue_node *next = NULL;
1117         queue_node *tmp = NULL;
1118
1119         node->priv_flags = 0;
1120
1121         LIST_FOR_EACH_ENTRY_SAFE(next, tmp, &data->dequeue_list.head, item_link) {
1122                 if (next->priv_flags)
1123                         break;
1124                 _queue_node_pop(&data->dequeue_list, next);
1125                 _tbm_surface_queue_enqueue(surface_queue, next, 1);
1126         }
1127 }
1128
1129 static queue_node *
1130 __tbm_queue_sequence_dequeue(tbm_surface_queue_h
1131                              surface_queue)
1132 {
1133         tbm_queue_sequence *data = surface_queue->impl_data;
1134         queue_node *node = NULL;
1135
1136         node = _tbm_surface_queue_dequeue(surface_queue);
1137         if (node) {
1138                 _queue_node_push_back(&data->dequeue_list, node);
1139                 node->priv_flags = 1;
1140         }
1141
1142         return node;
1143 }
1144
1145 static const tbm_surface_queue_interface tbm_queue_sequence_impl = {
1146         __tbm_queue_sequence_init,
1147         __tbm_queue_sequence_reset,
1148         __tbm_queue_sequence_destroy,
1149         __tbm_queue_sequence_need_attach,
1150         __tbm_queue_sequence_enqueue,
1151         NULL,                                   /*__tbm_queue_sequence_release*/
1152         __tbm_queue_sequence_dequeue,
1153         NULL,                                   /*__tbm_queue_sequence_acquire*/
1154 };
1155
1156 tbm_surface_queue_h
1157 tbm_surface_queue_sequence_create(int queue_size, int width,
1158                                   int height, int format, int flags)
1159 {
1160         TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
1161         TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
1162         TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
1163         TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
1164
1165         tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1,
1166                                             sizeof(struct _tbm_surface_queue));
1167         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
1168
1169         TBM_QUEUE_TRACE("tbm_surface_queue(%p)\n", surface_queue);
1170
1171         tbm_queue_sequence *data = (tbm_queue_sequence *) calloc(1,
1172                                    sizeof(tbm_queue_sequence));
1173         if (data == NULL) {
1174                 free(surface_queue);
1175                 return NULL;
1176         }
1177
1178         data->queue_size = queue_size;
1179         data->flags = flags;
1180         _tbm_surface_queue_init(surface_queue,
1181                                 data->queue_size,
1182                                 width, height, format,
1183                                 &tbm_queue_sequence_impl, data);
1184
1185         return surface_queue;
1186 }