1 /**************************************************************************
5 Copyright 2014 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
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.
30 **************************************************************************/
32 #include "tbm_bufmgr_int.h"
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)
52 struct list_head head;
53 struct list_head tail;
59 tbm_surface_h surface;
61 struct list_head item_link;
62 struct list_head link;
65 typedef struct _tbm_surface_queue_interface {
66 void (*init)(tbm_surface_queue_h queue);
67 void (*reset)(tbm_surface_queue_h queue);
68 void (*destroy)(tbm_surface_queue_h queue);
69 void (*need_attach)(tbm_surface_queue_h queue);
71 void (*enqueue)(tbm_surface_queue_h queue, tbm_surface_h surface);
72 void (*release)(tbm_surface_queue_h queue, tbm_surface_h surface);
73 void (*dequeue)(tbm_surface_queue_h queue);
74 void (*acquire)(tbm_surface_queue_h queue);
75 }tbm_surface_queue_interface;
77 struct _tbm_surface_queue {
84 struct list_head list;
86 tbm_surface_queue_notify_cb destroy_cb;
87 void *destroy_cb_data;
89 tbm_surface_queue_notify_cb dequeuable_cb;
90 void *dequeuable_cb_data;
92 tbm_surface_queue_notify_cb acquirable_cb;
93 void *acquirable_cb_data;
95 tbm_surface_queue_notify_cb reset_cb;
99 pthread_cond_t free_cond;
100 pthread_cond_t dirty_cond;
102 const tbm_surface_queue_interface *impl;
106 static queue_node *_queue_node_create(void)
108 queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
109 TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
114 static void _queue_node_delete(queue_node * node)
117 tbm_surface_destroy(node->surface);
119 LIST_DEL(&node->item_link);
120 LIST_DEL(&node->link);
124 static int _queue_is_empty(queue * queue)
126 if (queue->head.next == &queue->tail)
132 static void _queue_node_push_back(queue * queue, queue_node * node)
134 LIST_ADDTAIL(&node->item_link, &queue->tail);
139 static void _queue_node_push_front(queue * queue, queue_node * node)
141 LIST_ADD(&node->item_link, &queue->head);
146 static queue_node *_queue_node_pop_front(queue * queue)
148 queue_node *node = NULL;
150 node = LIST_ENTRY(queue_node, queue->head.next, item_link);
152 LIST_DEL(&node->item_link);
158 static queue_node* _queue_get_node(tbm_surface_queue_h surface_queue, int type, tbm_surface_h surface, int *out_type)
160 queue_node *node = NULL;
161 queue_node *tmp = NULL;
164 type = FREE_QUEUE | DUTY_QUEUE | NODE_LIST;
168 if (type & FREE_QUEUE)
170 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->free_queue.head, item_link) {
171 if (node->surface == surface)
173 if (out_type) *out_type = FREE_QUEUE;
179 if (type & DUTY_QUEUE)
181 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->dirty_queue.head, item_link) {
182 if (node->surface == surface)
184 if (out_type) *out_type = DUTY_QUEUE;
190 if (type & NODE_LIST)
192 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
193 if (node->surface == surface)
195 if (out_type) *out_type = NODE_LIST;
204 static void _queue_init(queue * queue)
206 LIST_INITHEAD(&queue->head);
207 LIST_INITHEAD(&queue->tail);
208 LIST_ADDTAIL(&queue->head, &queue->tail);
212 void _tbm_surface_queue_attach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
214 queue_node *node = NULL;
216 node = _queue_node_create();
217 TBM_RETURN_IF_FAIL(node != NULL);
219 tbm_surface_internal_ref(surface);
220 node->surface = surface;
222 LIST_ADDTAIL(&node->link, &surface_queue->list);
223 _queue_node_push_back(&surface_queue->free_queue, node);
226 void _tbm_surface_queue_detach(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
228 queue_node *node = NULL;
231 node = _queue_get_node(surface_queue, 0, surface, &queue_type);
233 _queue_node_delete(node);
236 void _tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface, int push_back)
238 queue_node *node = NULL;
241 node = _queue_get_node(surface_queue, 0, surface, &queue_type);
242 TBM_RETURN_IF_FAIL(node != NULL);
243 TBM_RETURN_IF_FAIL(queue_type == NODE_LIST);
246 _queue_node_push_back(&surface_queue->dirty_queue, node);
248 _queue_node_push_front(&surface_queue->dirty_queue, node);
251 void _tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface, int push_back)
253 queue_node *node = NULL;
256 node = _queue_get_node(surface_queue, 0, surface, &queue_type);
257 TBM_RETURN_IF_FAIL(node != NULL);
258 TBM_RETURN_IF_FAIL(queue_type == NODE_LIST);
261 _queue_node_push_back(&surface_queue->free_queue, node);
263 _queue_node_push_front(&surface_queue->free_queue, node);
266 void _tbm_surface_queue_init(tbm_surface_queue_h surface_queue,
267 int width, int height, int format,
268 const tbm_surface_queue_interface* impl, void *data)
270 TBM_RETURN_IF_FAIL(surface_queue != NULL);
271 TBM_RETURN_IF_FAIL(impl != NULL);
273 memset(surface_queue, 0x00, sizeof(struct _tbm_surface_queue));
275 pthread_mutex_init(&surface_queue->lock, NULL);
276 pthread_cond_init(&surface_queue->free_cond, NULL);
277 pthread_cond_init(&surface_queue->dirty_cond, NULL);
279 surface_queue->width = width;
280 surface_queue->height = height;
281 surface_queue->format = format;
282 surface_queue->impl = impl;
283 surface_queue->impl_data = data;
285 _queue_init(&surface_queue->free_queue);
286 _queue_init(&surface_queue->dirty_queue);
287 LIST_INITHEAD(&surface_queue->list);
289 if (surface_queue->impl && surface_queue->impl->init)
290 surface_queue->impl->init(surface_queue);
293 tbm_surface_queue_error_e tbm_surface_queue_set_destroy_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
295 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
297 pthread_mutex_lock(&surface_queue->lock);
299 surface_queue->destroy_cb = destroy_cb;
300 surface_queue->destroy_cb_data = data;
302 pthread_mutex_unlock(&surface_queue->lock);
304 return TBM_SURFACE_QUEUE_ERROR_NONE;
307 tbm_surface_queue_error_e tbm_surface_queue_set_dequeuable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
309 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
311 pthread_mutex_lock(&surface_queue->lock);
313 surface_queue->dequeuable_cb = dequeuable_cb;
314 surface_queue->dequeuable_cb_data = data;
316 pthread_mutex_unlock(&surface_queue->lock);
318 return TBM_SURFACE_QUEUE_ERROR_NONE;
321 tbm_surface_queue_error_e tbm_surface_queue_set_acquirable_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
323 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
325 pthread_mutex_lock(&surface_queue->lock);
327 surface_queue->acquirable_cb = acquirable_cb;
328 surface_queue->acquirable_cb_data = data;
330 pthread_mutex_unlock(&surface_queue->lock);
332 return TBM_SURFACE_QUEUE_ERROR_NONE;
335 int tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
337 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
339 return surface_queue->width;
342 int tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
344 return surface_queue->height;
347 int tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
349 return surface_queue->format;
352 tbm_surface_queue_error_e tbm_surface_queue_set_reset_cb(tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb, void *data)
354 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
356 pthread_mutex_lock(&surface_queue->lock);
358 surface_queue->reset_cb = reset_cb;
359 surface_queue->reset_cb_data = data;
361 pthread_mutex_unlock(&surface_queue->lock);
363 return TBM_SURFACE_QUEUE_ERROR_NONE;
367 tbm_surface_queue_error_e tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
369 queue_node *node = NULL;
372 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
373 TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
375 pthread_mutex_lock(&surface_queue->lock);
377 node = _queue_get_node(surface_queue, 0, surface, &queue_type);
378 if (node == NULL || queue_type != NODE_LIST)
380 TBM_LOG("tbm_surface_queue_enqueue::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
381 pthread_mutex_unlock(&surface_queue->lock);
382 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
385 if (surface_queue->impl && surface_queue->impl->enqueue)
386 surface_queue->impl->enqueue(surface_queue, surface);
388 _queue_node_push_back(&surface_queue->dirty_queue, node);
390 pthread_mutex_unlock(&surface_queue->lock);
391 pthread_cond_signal(&surface_queue->dirty_cond);
393 if (!_queue_is_empty(&surface_queue->dirty_queue) && surface_queue->acquirable_cb)
394 surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
396 return TBM_SURFACE_QUEUE_ERROR_NONE;
399 tbm_surface_queue_error_e tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
401 queue_node *node = NULL;
403 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
404 TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
406 pthread_mutex_lock(&surface_queue->lock);
408 if (surface_queue->impl && surface_queue->impl->dequeue)
409 surface_queue->impl->dequeue(surface_queue);
411 if (_queue_is_empty(&surface_queue->free_queue)) {
412 if (surface_queue->impl && surface_queue->impl->need_attach)
413 surface_queue->impl->need_attach(surface_queue);
415 if (_queue_is_empty(&surface_queue->free_queue)) {
416 pthread_mutex_unlock(&surface_queue->lock);
417 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
421 node = _queue_node_pop_front(&surface_queue->free_queue);
422 if (node == NULL || node->surface == NULL) {
423 TBM_LOG("_queue_node_pop_front is failed\n");
424 pthread_mutex_unlock(&surface_queue->lock);
425 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
428 *surface = node->surface;
430 pthread_mutex_unlock(&surface_queue->lock);
432 return TBM_SURFACE_QUEUE_ERROR_NONE;
435 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
437 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
439 pthread_mutex_lock(&surface_queue->lock);
441 if (_queue_is_empty(&surface_queue->free_queue)) {
442 if (surface_queue->impl && surface_queue->impl->need_attach)
443 surface_queue->impl->need_attach(surface_queue);
446 if (_queue_is_empty(&surface_queue->free_queue)) {
448 pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
449 pthread_mutex_unlock(&surface_queue->lock);
453 pthread_mutex_unlock(&surface_queue->lock);
457 pthread_mutex_unlock(&surface_queue->lock);
462 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
464 queue_node *node = NULL;
467 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
468 TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
470 pthread_mutex_lock(&surface_queue->lock);
472 node = _queue_get_node(surface_queue, 0, surface, &queue_type);
473 if (node == NULL || queue_type != NODE_LIST)
475 TBM_LOG("tbm_surface_queue_release::Surface exist in free_queue or dirty_queue node:%p, queue:%d\n", node, queue_type);
476 pthread_mutex_unlock(&surface_queue->lock);
477 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
480 if (surface_queue->impl && surface_queue->impl->release)
481 surface_queue->impl->release(surface_queue, surface);
483 _queue_node_push_front(&surface_queue->free_queue, node);
485 pthread_mutex_unlock(&surface_queue->lock);
486 pthread_cond_signal(&surface_queue->free_cond);
488 if (!_queue_is_empty(&surface_queue->free_queue) && surface_queue->dequeuable_cb)
489 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
491 return TBM_SURFACE_QUEUE_ERROR_NONE;
494 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
496 queue_node *node = NULL;
498 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
499 TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
501 pthread_mutex_lock(&surface_queue->lock);
503 if (surface_queue->impl && surface_queue->impl->acquire)
504 surface_queue->impl->acquire(surface_queue);
506 if (_queue_is_empty(&surface_queue->dirty_queue)) {
507 pthread_mutex_unlock(&surface_queue->lock);
508 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
511 node = _queue_node_pop_front(&surface_queue->dirty_queue);
513 TBM_LOG("_queue_node_pop_front failed\n");
514 pthread_mutex_unlock(&surface_queue->lock);
515 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
518 *surface = node->surface;
520 pthread_mutex_unlock(&surface_queue->lock);
522 return TBM_SURFACE_QUEUE_ERROR_NONE;
525 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
527 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
529 pthread_mutex_lock(&surface_queue->lock);
531 if (_queue_is_empty(&surface_queue->dirty_queue)) {
533 pthread_cond_wait(&surface_queue->dirty_cond, &surface_queue->lock);
534 pthread_mutex_unlock(&surface_queue->lock);
538 pthread_mutex_unlock(&surface_queue->lock);
542 pthread_mutex_unlock(&surface_queue->lock);
547 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
549 queue_node *node = NULL, *tmp = NULL;
551 TBM_RETURN_IF_FAIL(surface_queue != NULL);
553 if (surface_queue->destroy_cb)
554 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
556 if (surface_queue->impl && surface_queue->impl->destroy)
557 surface_queue->impl->destroy(surface_queue);
559 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link) {
560 _queue_node_delete(node);
563 pthread_mutex_destroy(&surface_queue->lock);
567 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
569 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
571 queue_node *node = NULL, *tmp = NULL;
573 if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
574 return TBM_SURFACE_QUEUE_ERROR_NONE;
576 pthread_mutex_lock(&surface_queue->lock);
578 surface_queue->width = width;
579 surface_queue->height = height;
580 surface_queue->format = format;
582 /* Destory surface and Push to free_queue */
583 LIST_FOR_EACH_ENTRY_SAFE(node, tmp, &surface_queue->list, link)
585 _queue_node_delete(node);
589 _queue_init(&surface_queue->free_queue);
590 _queue_init(&surface_queue->dirty_queue);
591 LIST_INITHEAD(&surface_queue->list);
593 if (surface_queue->impl && surface_queue->impl->reset)
594 surface_queue->impl->reset(surface_queue);
596 pthread_mutex_unlock(&surface_queue->lock);
597 pthread_cond_signal(&surface_queue->free_cond);
599 if (surface_queue->reset_cb)
600 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
602 return TBM_SURFACE_QUEUE_ERROR_NONE;
612 static void __tbm_queue_default_init(tbm_surface_queue_h surface_queue)
616 static void __tbm_queue_default_reset(tbm_surface_queue_h surface_queue)
618 tbm_queue_default* data = surface_queue->impl_data;
619 data->num_attached = 0;
622 static void __tbm_queue_default_destroy(tbm_surface_queue_h surface_queue)
624 free(surface_queue->impl_data);
627 static void __tbm_queue_default_need_attach(tbm_surface_queue_h surface_queue)
629 tbm_queue_default* data = surface_queue->impl_data;
630 tbm_surface_h surface;
632 if (data->queue_size == data->num_attached)
635 surface = tbm_surface_internal_create_with_flags(surface_queue->width,
636 surface_queue->height,
637 surface_queue->format,
639 TBM_RETURN_IF_FAIL(surface != NULL);
640 _tbm_surface_queue_attach(surface_queue, surface);
641 tbm_surface_internal_unref(surface);
642 data->num_attached++;
645 static void __tbm_queue_default_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
647 /* Push to back of dirty_queue */
648 _tbm_surface_queue_enqueue(surface_queue, surface, 1);
651 static void __tbm_queue_default_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
653 /* Push to front of free_queue */
654 _tbm_surface_queue_release(surface_queue, surface, 0);
657 static void __tbm_queue_default_dequeue(tbm_surface_queue_h surface_queue)
662 static void __tbm_queue_default_acquire(tbm_surface_queue_h surface_queue)
667 static const tbm_surface_queue_interface tbm_queue_default_impl =
669 __tbm_queue_default_init,
670 __tbm_queue_default_reset,
671 __tbm_queue_default_destroy,
672 __tbm_queue_default_need_attach,
673 __tbm_queue_default_enqueue,
674 __tbm_queue_default_release,
675 __tbm_queue_default_dequeue,
676 __tbm_queue_default_acquire
679 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
681 TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
682 TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
683 TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
684 TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
686 tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
687 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
689 tbm_queue_default *data = (tbm_queue_default *) calloc(1, sizeof(tbm_queue_default));
696 data->queue_size = queue_size;
698 _tbm_surface_queue_init(surface_queue,
699 width, height, format,
700 &tbm_queue_default_impl, data);
702 return surface_queue;