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