surface_queue: Add new apis for reset queue
[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 typedef struct
36 {
37     struct list_head head;
38
39     struct list_head tail;
40
41     int count;
42 } queue;
43
44 typedef struct
45 {
46     tbm_surface_h surface;
47
48     struct list_head item_link;
49 } queue_node;
50
51 struct _tbm_surface_queue
52 {
53     int width;
54     int height;
55     int format;
56     int size;
57     int flags;
58
59     queue free_queue;
60     queue duty_queue;
61     queue_node **node_list;
62
63     tbm_surface_queue_notify_cb destroy_cb;
64     void *destroy_cb_data;
65
66     tbm_surface_queue_notify_cb dequeuable_cb;
67     void *dequeuable_cb_data;
68
69     tbm_surface_queue_notify_cb acquirable_cb;
70     void *acquirable_cb_data;
71
72     tbm_surface_queue_notify_cb reset_cb;
73     void *reset_cb_data;
74
75     pthread_mutex_t lock;
76     pthread_cond_t free_cond;
77     pthread_cond_t duty_cond;
78 };
79
80 static queue_node *
81 _queue_node_create (void)
82 {
83     queue_node *node = (queue_node *) calloc (1, sizeof(queue_node));
84     TBM_RETURN_VAL_IF_FAIL (node != NULL, NULL);
85
86     return node;
87 }
88
89 static void
90 _queue_node_delete (queue_node *node)
91 {
92     if (node->surface)
93         tbm_surface_destroy (node->surface);
94     LIST_DEL (&node->item_link);
95     free (node);
96 }
97
98 static int
99 _queue_is_empty (queue *queue)
100 {
101     if (queue->head.next == &queue->tail)
102         return 1;
103
104     return 0;
105 }
106
107 static void
108 _queue_node_push_back (queue *queue, queue_node *node)
109 {
110     LIST_ADDTAIL (&node->item_link, &queue->tail);
111     queue->count++;
112     return;
113 }
114
115 static void
116 _queue_node_push_front (queue *queue, queue_node *node)
117 {
118     LIST_ADD (&node->item_link, &queue->head);
119     queue->count++;
120     return;
121 }
122
123 static queue_node *
124 _queue_node_pop_front (queue *queue)
125 {
126     queue_node *node = NULL;
127
128     node = LIST_ENTRY (queue_node, queue->head.next, item_link);
129
130     LIST_DEL (&node->item_link);
131     queue->count--;
132
133     return node;
134 }
135
136 static int
137 _queue_node_exist_in_queue (queue *queue, queue_node *node)
138 {
139     queue_node *search_node = NULL;
140     queue_node *temp = NULL;
141
142     if (!_queue_is_empty(queue))
143     {
144         LIST_FOR_EACH_ENTRY_SAFE (search_node, temp, &queue->head, item_link)
145         {
146             if (search_node == node)
147                 return 1;
148         }
149     }
150
151     return 0;
152 }
153
154 static void
155 _queue_init (queue *queue)
156 {
157     LIST_INITHEAD (&queue->head);
158     LIST_INITHEAD (&queue->tail);
159     LIST_ADDTAIL (&queue->head, &queue->tail);
160     queue->count = 0;
161 }
162
163 tbm_surface_queue_error_e
164 tbm_surface_queue_enqueue (tbm_surface_queue_h surface_queue, tbm_surface_h surface)
165 {
166     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
167     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
168
169     int i;
170
171     pthread_mutex_lock (&surface_queue->lock);
172
173     for (i = 0 ; i < surface_queue->size ; i++)
174     {
175         if (surface_queue->node_list[i]->surface == surface)
176             break;
177     }
178
179     if (i == surface_queue->size)
180     {
181         TBM_LOG ("Can't find the surface in queue\n");
182         pthread_mutex_unlock (&surface_queue->lock);
183         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
184     }
185
186     if (_queue_node_exist_in_queue (&surface_queue->duty_queue, surface_queue->node_list[i]))
187     {
188         TBM_LOG ("Surface exist in queue\n");
189         pthread_mutex_unlock (&surface_queue->lock);
190         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
191     }
192
193     _queue_node_push_back(&surface_queue->duty_queue, surface_queue->node_list[i]);
194
195     pthread_mutex_unlock (&surface_queue->lock);
196     pthread_cond_signal(&surface_queue->duty_cond);
197
198     if (surface_queue->acquirable_cb)
199         surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
200
201     return TBM_SURFACE_QUEUE_ERROR_NONE;
202 }
203
204 tbm_surface_queue_error_e
205 tbm_surface_queue_dequeue (tbm_surface_queue_h surface_queue, tbm_surface_h *surface)
206 {
207     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
208     TBM_RETURN_VAL_IF_FAIL (surface_queue->free_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
209
210     pthread_mutex_lock (&surface_queue->lock);
211
212     if (_queue_is_empty (&surface_queue->free_queue))
213     {
214         TBM_LOG ("Surface queue is empty\n");
215         pthread_mutex_unlock (&surface_queue->lock);
216         return TBM_SURFACE_QUEUE_ERROR_EMPTY;
217     }
218
219     queue_node *node = NULL;
220
221     node = _queue_node_pop_front (&surface_queue->free_queue);
222     if (node == NULL)
223     {
224         TBM_LOG ("_queue_node_pop_front is failed\n");
225         pthread_mutex_unlock (&surface_queue->lock);
226         return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
227     }
228
229         if (!node->surface)
230     {
231         tbm_surface_h surface = tbm_surface_internal_create_with_flags (surface_queue->width,
232                                                     surface_queue->height,
233                                                     surface_queue->format,
234                                                     surface_queue->flags);
235         if (surface == NULL)
236         {
237             TBM_LOG ("tbm surface create  failed");
238                 pthread_mutex_unlock (&surface_queue->lock);
239                 return TBM_SURFACE_QUEUE_ERROR_SURFACE_ALLOC_FAILED;
240         }
241         node->surface = surface;
242     }
243
244     *surface = node->surface;
245
246     pthread_mutex_unlock (&surface_queue->lock);
247
248     return TBM_SURFACE_QUEUE_ERROR_NONE;
249 }
250
251 tbm_surface_queue_error_e
252 tbm_surface_queue_release (tbm_surface_queue_h surface_queue, tbm_surface_h surface)
253 {
254     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
255     TBM_RETURN_VAL_IF_FAIL (surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
256
257     pthread_mutex_lock (&surface_queue->lock);
258
259     int i;
260     for (i = 0 ; i < surface_queue->size ; i++)
261     {
262         if (surface_queue->node_list[i]->surface == surface)
263             break;
264     }
265     if (i == surface_queue->size)
266     {
267         TBM_LOG ("Can't find the surface in queue\n");
268         pthread_mutex_unlock (&surface_queue->lock);
269         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
270     }
271
272     if (_queue_node_exist_in_queue (&surface_queue->free_queue, surface_queue->node_list[i]))
273     {
274         TBM_LOG ("Surface exist in queue\n");
275         pthread_mutex_unlock (&surface_queue->lock);
276         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
277     }
278
279     _queue_node_push_front(&surface_queue->free_queue, surface_queue->node_list[i]);
280
281     pthread_mutex_unlock (&surface_queue->lock);
282     pthread_cond_signal(&surface_queue->free_cond);
283
284     if (surface_queue->dequeuable_cb)
285         surface_queue->dequeuable_cb (surface_queue, surface_queue->dequeuable_cb_data);
286
287     return TBM_SURFACE_QUEUE_ERROR_NONE;
288 }
289
290 tbm_surface_queue_error_e
291 tbm_surface_queue_acquire (tbm_surface_queue_h surface_queue, tbm_surface_h *surface)
292 {
293     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
294     TBM_RETURN_VAL_IF_FAIL (surface_queue->duty_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
295
296     pthread_mutex_lock (&surface_queue->lock);
297
298     if (_queue_is_empty (&surface_queue->duty_queue))
299     {
300         TBM_LOG ("Surface queue is empty\n");
301         pthread_mutex_unlock (&surface_queue->lock);
302         return TBM_SURFACE_QUEUE_ERROR_EMPTY;
303     }
304
305     queue_node *node = NULL;
306
307     node = _queue_node_pop_front (&surface_queue->duty_queue);
308     if (node == NULL)
309     {
310         TBM_LOG ("_queue_node_pop_front  failed\n");
311         pthread_mutex_unlock (&surface_queue->lock);
312         return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
313     }
314
315     *surface = node->surface;
316
317     pthread_mutex_unlock (&surface_queue->lock);
318
319     return TBM_SURFACE_QUEUE_ERROR_NONE;
320 }
321
322 int
323 tbm_surface_queue_can_dequeue (tbm_surface_queue_h surface_queue, int wait)
324 {
325     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
326
327     pthread_mutex_lock (&surface_queue->lock);
328
329     if (_queue_is_empty (&surface_queue->free_queue))
330     {
331         if (wait)
332         {
333             pthread_cond_wait (&surface_queue->free_cond, &surface_queue->lock);
334             pthread_mutex_unlock (&surface_queue->lock);
335             return 1;
336         }
337
338         pthread_mutex_unlock (&surface_queue->lock);
339         return 0;
340     }
341
342     pthread_mutex_unlock (&surface_queue->lock);
343     return 1;
344 }
345
346 int
347 tbm_surface_queue_can_acquire (tbm_surface_queue_h surface_queue, int wait)
348 {
349     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
350
351     pthread_mutex_lock (&surface_queue->lock);
352
353     if (_queue_is_empty (&surface_queue->duty_queue))
354     {
355         if (wait)
356         {
357             pthread_cond_wait (&surface_queue->duty_cond, &surface_queue->lock);
358             pthread_mutex_unlock (&surface_queue->lock);
359             return 1;
360         }
361
362         pthread_mutex_unlock (&surface_queue->lock);
363         return 0;
364     }
365
366     pthread_mutex_unlock (&surface_queue->lock);
367
368     return 1;
369 }
370
371 tbm_surface_queue_h
372 tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
373 {
374     TBM_RETURN_VAL_IF_FAIL (queue_size > 0, NULL);
375     TBM_RETURN_VAL_IF_FAIL (width > 0, NULL);
376     TBM_RETURN_VAL_IF_FAIL (height > 0, NULL);
377     TBM_RETURN_VAL_IF_FAIL (format > 0, NULL);
378
379     int i, j;
380     tbm_surface_queue_h surface_queue = (tbm_surface_queue_h)calloc(1, sizeof(struct _tbm_surface_queue));
381     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, NULL);
382
383     pthread_mutex_init (&surface_queue->lock, NULL);
384     pthread_cond_init (&surface_queue->free_cond, NULL);
385     pthread_cond_init (&surface_queue->duty_cond, NULL);
386
387     surface_queue->width = width;
388     surface_queue->height = height;
389     surface_queue->format = format;
390     surface_queue->flags = flags;
391     surface_queue->size = queue_size;
392     surface_queue->node_list = (queue_node **)calloc(queue_size, sizeof(queue_node *));
393     if (!surface_queue->node_list)
394     {
395         TBM_LOG ("surface node list alloc failed");
396         free (surface_queue);
397         pthread_mutex_destroy (&surface_queue->lock);
398         return NULL;
399     }
400
401         _queue_init (&surface_queue->free_queue);
402         _queue_init (&surface_queue->duty_queue);
403
404     for (i = 0 ; i < queue_size; i++)
405     {
406         queue_node *node = _queue_node_create();
407         if (node == NULL)
408         {
409             TBM_LOG ("surface node create failed");
410             goto fail;
411         }
412
413         surface_queue->node_list[i] = node;
414         _queue_node_push_back (&surface_queue->free_queue, node);
415     }
416
417     return surface_queue;
418
419 fail:
420     for (j = 0 ; j < i ; j++)
421         _queue_node_delete (surface_queue->node_list[j]);
422
423     free (surface_queue->node_list);
424     free (surface_queue);
425     pthread_mutex_destroy (&surface_queue->lock);
426
427     return NULL;
428 }
429
430 void
431 tbm_surface_queue_destroy (tbm_surface_queue_h surface_queue)
432 {
433     TBM_RETURN_IF_FAIL (surface_queue != NULL);
434
435     if (surface_queue->destroy_cb)
436         surface_queue->destroy_cb (surface_queue, surface_queue->destroy_cb_data);
437
438     int i;
439
440     for (i = 0 ; i < surface_queue->size ; i++)
441         _queue_node_delete (surface_queue->node_list[i]);
442
443     free (surface_queue->node_list);
444     free (surface_queue);
445 }
446
447 tbm_surface_queue_error_e
448 tbm_surface_queue_set_destroy_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
449 {
450     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
451
452     pthread_mutex_lock (&surface_queue->lock);
453
454     surface_queue->destroy_cb = destroy_cb;
455     surface_queue->destroy_cb_data = data;
456
457     pthread_mutex_unlock (&surface_queue->lock);
458
459     return TBM_SURFACE_QUEUE_ERROR_NONE;
460 }
461
462 tbm_surface_queue_error_e
463 tbm_surface_queue_set_dequeuable_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
464 {
465     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
466
467     pthread_mutex_lock (&surface_queue->lock);
468
469     surface_queue->dequeuable_cb = dequeuable_cb;
470     surface_queue->dequeuable_cb_data = data;
471
472     pthread_mutex_unlock (&surface_queue->lock);
473
474     return TBM_SURFACE_QUEUE_ERROR_NONE;
475 }
476
477 tbm_surface_queue_error_e
478 tbm_surface_queue_set_acquirable_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
479 {
480     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
481
482     pthread_mutex_lock (&surface_queue->lock);
483
484     surface_queue->acquirable_cb = acquirable_cb;
485     surface_queue->acquirable_cb_data = data;
486
487     pthread_mutex_unlock (&surface_queue->lock);
488
489     return TBM_SURFACE_QUEUE_ERROR_NONE;
490 }
491
492 int
493 tbm_surface_queue_get_queue_size (tbm_surface_queue_h surface_queue)
494 {
495     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
496
497     return surface_queue->size;
498 }
499
500 int
501 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
502 {
503     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
504
505     return surface_queue->width;
506 }
507
508 int
509 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
510 {
511     return surface_queue->height;
512 }
513
514 int
515 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
516 {
517     return surface_queue->format;
518 }
519
520 tbm_surface_queue_error_e
521 tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
522 {
523     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
524
525     int i;
526     queue_node *node = NULL;
527
528     if (width == surface_queue->width &&
529         height == surface_queue->height &&
530         format == surface_queue->format)
531         return TBM_SURFACE_QUEUE_ERROR_NONE;
532
533     pthread_mutex_lock (&surface_queue->lock);
534
535     surface_queue->width = width;
536     surface_queue->height = height;
537     surface_queue->format = format;
538
539     //Reset queue
540     _queue_init(&surface_queue->free_queue);
541     _queue_init(&surface_queue->duty_queue);
542
543     //Destory surface and Push to free_queue
544     for (i = 0 ; i < surface_queue->size; i++)
545     {
546         node = surface_queue->node_list[i];
547         if (node->surface)
548         {
549             tbm_surface_destroy(node->surface);
550             node->surface = NULL;
551         }
552
553         _queue_node_push_back(&surface_queue->free_queue, node);
554     }
555
556     pthread_mutex_unlock (&surface_queue->lock);
557     pthread_cond_signal(&surface_queue->free_cond);
558
559     if (surface_queue->reset_cb)
560         surface_queue->reset_cb (surface_queue, surface_queue->reset_cb_data);
561
562     return TBM_SURFACE_QUEUE_ERROR_NONE;
563 }
564
565 tbm_surface_queue_error_e
566 tbm_surface_queue_set_reset_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb reset_cb, void *data)
567 {
568     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
569
570     pthread_mutex_lock (&surface_queue->lock);
571
572     surface_queue->reset_cb = reset_cb;
573     surface_queue->reset_cb_data = data;
574
575     pthread_mutex_unlock (&surface_queue->lock);
576
577     return TBM_SURFACE_QUEUE_ERROR_NONE;
578 }