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"
36 struct list_head head;
38 struct list_head tail;
44 tbm_surface_h surface;
46 struct list_head item_link;
49 struct _tbm_surface_queue {
58 queue_node **node_list;
60 tbm_surface_queue_notify_cb destroy_cb;
61 void *destroy_cb_data;
63 tbm_surface_queue_notify_cb dequeuable_cb;
64 void *dequeuable_cb_data;
66 tbm_surface_queue_notify_cb acquirable_cb;
67 void *acquirable_cb_data;
69 tbm_surface_queue_notify_cb reset_cb;
73 pthread_cond_t free_cond;
74 pthread_cond_t duty_cond;
77 static queue_node *_queue_node_create(void)
79 queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
80 TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
85 static void _queue_node_delete(queue_node * node)
88 tbm_surface_destroy(node->surface);
89 LIST_DEL(&node->item_link);
93 static int _queue_is_empty(queue * queue)
95 if (queue->head.next == &queue->tail)
101 static void _queue_node_push_back(queue * queue, queue_node * node)
103 LIST_ADDTAIL(&node->item_link, &queue->tail);
108 static void _queue_node_push_front(queue * queue, queue_node * node)
110 LIST_ADD(&node->item_link, &queue->head);
115 static queue_node *_queue_node_pop_front(queue * queue)
117 queue_node *node = NULL;
119 node = LIST_ENTRY(queue_node, queue->head.next, item_link);
121 LIST_DEL(&node->item_link);
127 static int _queue_node_exist_in_queue(queue * queue, queue_node * node)
129 queue_node *search_node = NULL;
130 queue_node *temp = NULL;
132 if (!_queue_is_empty(queue)) {
133 LIST_FOR_EACH_ENTRY_SAFE(search_node, temp, &queue->head, item_link) {
134 if (search_node == node)
142 static void _queue_init(queue * queue)
144 LIST_INITHEAD(&queue->head);
145 LIST_INITHEAD(&queue->tail);
146 LIST_ADDTAIL(&queue->head, &queue->tail);
150 tbm_surface_queue_error_e tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
152 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
153 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
157 pthread_mutex_lock(&surface_queue->lock);
159 for (i = 0; i < surface_queue->size; i++) {
160 if (surface_queue->node_list[i]->surface == surface)
164 if (i == surface_queue->size) {
165 TBM_LOG("Can't find the surface in queue\n");
166 pthread_mutex_unlock(&surface_queue->lock);
167 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
170 if (_queue_node_exist_in_queue(&surface_queue->duty_queue, surface_queue->node_list[i])) {
171 TBM_LOG("Surface exist in queue\n");
172 pthread_mutex_unlock(&surface_queue->lock);
173 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
176 _queue_node_push_back(&surface_queue->duty_queue, surface_queue->node_list[i]);
178 pthread_mutex_unlock(&surface_queue->lock);
179 pthread_cond_signal(&surface_queue->duty_cond);
181 if (surface_queue->acquirable_cb)
182 surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
184 return TBM_SURFACE_QUEUE_ERROR_NONE;
187 tbm_surface_queue_error_e tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
189 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
190 TBM_RETURN_VAL_IF_FAIL(surface_queue->free_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
192 pthread_mutex_lock(&surface_queue->lock);
194 if (_queue_is_empty(&surface_queue->free_queue)) {
195 TBM_LOG("Surface queue is empty\n");
196 pthread_mutex_unlock(&surface_queue->lock);
197 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
200 queue_node *node = NULL;
202 node = _queue_node_pop_front(&surface_queue->free_queue);
204 TBM_LOG("_queue_node_pop_front is failed\n");
205 pthread_mutex_unlock(&surface_queue->lock);
206 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
209 if (!node->surface) {
210 tbm_surface_h surface = tbm_surface_internal_create_with_flags(surface_queue->width,
211 surface_queue->height,
212 surface_queue->format,
213 surface_queue->flags);
214 if (surface == NULL) {
215 TBM_LOG("tbm surface create failed");
216 pthread_mutex_unlock(&surface_queue->lock);
217 return TBM_SURFACE_QUEUE_ERROR_SURFACE_ALLOC_FAILED;
219 node->surface = surface;
222 *surface = node->surface;
224 pthread_mutex_unlock(&surface_queue->lock);
226 return TBM_SURFACE_QUEUE_ERROR_NONE;
229 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
231 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
232 TBM_RETURN_VAL_IF_FAIL(surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
234 pthread_mutex_lock(&surface_queue->lock);
237 for (i = 0; i < surface_queue->size; i++) {
238 if (surface_queue->node_list[i]->surface == surface)
241 if (i == surface_queue->size) {
242 TBM_LOG("Can't find the surface in queue\n");
243 pthread_mutex_unlock(&surface_queue->lock);
244 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
247 if (_queue_node_exist_in_queue(&surface_queue->free_queue, surface_queue->node_list[i])) {
248 TBM_LOG("Surface exist in queue\n");
249 pthread_mutex_unlock(&surface_queue->lock);
250 return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
253 _queue_node_push_front(&surface_queue->free_queue, surface_queue->node_list[i]);
255 pthread_mutex_unlock(&surface_queue->lock);
256 pthread_cond_signal(&surface_queue->free_cond);
258 if (surface_queue->dequeuable_cb)
259 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
261 return TBM_SURFACE_QUEUE_ERROR_NONE;
264 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
266 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
267 TBM_RETURN_VAL_IF_FAIL(surface_queue->duty_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
269 pthread_mutex_lock(&surface_queue->lock);
271 if (_queue_is_empty(&surface_queue->duty_queue)) {
272 TBM_LOG("Surface queue is empty\n");
273 pthread_mutex_unlock(&surface_queue->lock);
274 return TBM_SURFACE_QUEUE_ERROR_EMPTY;
277 queue_node *node = NULL;
279 node = _queue_node_pop_front(&surface_queue->duty_queue);
281 TBM_LOG("_queue_node_pop_front failed\n");
282 pthread_mutex_unlock(&surface_queue->lock);
283 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
286 *surface = node->surface;
288 pthread_mutex_unlock(&surface_queue->lock);
290 return TBM_SURFACE_QUEUE_ERROR_NONE;
293 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
295 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
297 pthread_mutex_lock(&surface_queue->lock);
299 if (_queue_is_empty(&surface_queue->free_queue)) {
301 pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
302 pthread_mutex_unlock(&surface_queue->lock);
306 pthread_mutex_unlock(&surface_queue->lock);
310 pthread_mutex_unlock(&surface_queue->lock);
314 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
316 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
318 pthread_mutex_lock(&surface_queue->lock);
320 if (_queue_is_empty(&surface_queue->duty_queue)) {
322 pthread_cond_wait(&surface_queue->duty_cond, &surface_queue->lock);
323 pthread_mutex_unlock(&surface_queue->lock);
327 pthread_mutex_unlock(&surface_queue->lock);
331 pthread_mutex_unlock(&surface_queue->lock);
336 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
338 TBM_RETURN_VAL_IF_FAIL(queue_size > 0, NULL);
339 TBM_RETURN_VAL_IF_FAIL(width > 0, NULL);
340 TBM_RETURN_VAL_IF_FAIL(height > 0, NULL);
341 TBM_RETURN_VAL_IF_FAIL(format > 0, NULL);
344 tbm_surface_queue_h surface_queue = (tbm_surface_queue_h) calloc(1, sizeof(struct _tbm_surface_queue));
345 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, NULL);
347 pthread_mutex_init(&surface_queue->lock, NULL);
348 pthread_cond_init(&surface_queue->free_cond, NULL);
349 pthread_cond_init(&surface_queue->duty_cond, NULL);
351 surface_queue->width = width;
352 surface_queue->height = height;
353 surface_queue->format = format;
354 surface_queue->flags = flags;
355 surface_queue->size = queue_size;
356 surface_queue->node_list = (queue_node **) calloc(queue_size, sizeof(queue_node *));
357 if (!surface_queue->node_list) {
358 TBM_LOG("surface node list alloc failed");
360 pthread_mutex_destroy(&surface_queue->lock);
364 _queue_init(&surface_queue->free_queue);
365 _queue_init(&surface_queue->duty_queue);
367 for (i = 0; i < queue_size; i++) {
368 queue_node *node = _queue_node_create();
370 TBM_LOG("surface node create failed");
374 surface_queue->node_list[i] = node;
375 _queue_node_push_back(&surface_queue->free_queue, node);
378 return surface_queue;
381 for (j = 0; j < i; j++)
382 _queue_node_delete(surface_queue->node_list[j]);
384 free(surface_queue->node_list);
385 pthread_mutex_destroy(&surface_queue->lock);
391 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
393 TBM_RETURN_IF_FAIL(surface_queue != NULL);
395 if (surface_queue->destroy_cb)
396 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
400 for (i = 0; i < surface_queue->size; i++)
401 _queue_node_delete(surface_queue->node_list[i]);
403 free(surface_queue->node_list);
407 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)
409 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
411 pthread_mutex_lock(&surface_queue->lock);
413 surface_queue->destroy_cb = destroy_cb;
414 surface_queue->destroy_cb_data = data;
416 pthread_mutex_unlock(&surface_queue->lock);
418 return TBM_SURFACE_QUEUE_ERROR_NONE;
421 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)
423 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
425 pthread_mutex_lock(&surface_queue->lock);
427 surface_queue->dequeuable_cb = dequeuable_cb;
428 surface_queue->dequeuable_cb_data = data;
430 pthread_mutex_unlock(&surface_queue->lock);
432 return TBM_SURFACE_QUEUE_ERROR_NONE;
435 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)
437 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
439 pthread_mutex_lock(&surface_queue->lock);
441 surface_queue->acquirable_cb = acquirable_cb;
442 surface_queue->acquirable_cb_data = data;
444 pthread_mutex_unlock(&surface_queue->lock);
446 return TBM_SURFACE_QUEUE_ERROR_NONE;
449 int tbm_surface_queue_get_queue_size(tbm_surface_queue_h surface_queue)
451 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
453 return surface_queue->size;
456 int tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
458 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
460 return surface_queue->width;
463 int tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
465 return surface_queue->height;
468 int tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
470 return surface_queue->format;
473 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
475 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
478 queue_node *node = NULL;
480 if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
481 return TBM_SURFACE_QUEUE_ERROR_NONE;
483 pthread_mutex_lock(&surface_queue->lock);
485 surface_queue->width = width;
486 surface_queue->height = height;
487 surface_queue->format = format;
490 _queue_init(&surface_queue->free_queue);
491 _queue_init(&surface_queue->duty_queue);
493 /* Destory surface and Push to free_queue */
494 for (i = 0; i < surface_queue->size; i++) {
495 node = surface_queue->node_list[i];
497 tbm_surface_destroy(node->surface);
498 node->surface = NULL;
501 _queue_node_push_back(&surface_queue->free_queue, node);
504 pthread_mutex_unlock(&surface_queue->lock);
505 pthread_cond_signal(&surface_queue->free_cond);
507 if (surface_queue->reset_cb)
508 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
510 return TBM_SURFACE_QUEUE_ERROR_NONE;
513 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)
515 TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
517 pthread_mutex_lock(&surface_queue->lock);
519 surface_queue->reset_cb = reset_cb;
520 surface_queue->reset_cb_data = data;
522 pthread_mutex_unlock(&surface_queue->lock);
524 return TBM_SURFACE_QUEUE_ERROR_NONE;