Add tbm surface queue source
[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     pthread_mutex_t lock;
73     pthread_cond_t free_cond;
74     pthread_cond_t duty_cond;
75 };
76
77 static queue_node *
78 _queue_node_create (tbm_surface_h surface)
79 {
80     queue_node *node = (queue_node *) calloc (1, sizeof(queue_node));
81     TBM_RETURN_VAL_IF_FAIL (node != NULL, NULL);
82
83     node->surface = surface;
84
85     return node;
86 }
87
88 static void
89 _queue_node_delete (queue_node *node)
90 {
91     tbm_surface_destroy (node->surface);
92     LIST_DEL (&node->item_link);
93     free (node);
94 }
95
96 static int
97 _queue_is_empty (queue *queue)
98 {
99     if (queue->head.next == &queue->tail)
100         return 1;
101
102     return 0;
103 }
104
105 static void
106 _queue_node_push_back (queue *queue, queue_node *node)
107 {
108     LIST_ADDTAIL (&node->item_link, &queue->tail);
109     queue->count++;
110     return;
111 }
112
113 static queue_node *
114 _queue_node_pop_front (queue *queue)
115 {
116     queue_node *node = NULL;
117
118     node = LIST_ENTRY (queue_node, queue->head.next, item_link);
119
120     LIST_DEL (&node->item_link);
121     queue->count--;
122
123     return node;
124 }
125
126 static int
127 _queue_node_exist_in_queue (queue *queue, queue_node *node)
128 {
129     queue_node *search_node = NULL;
130     queue_node *temp = NULL;
131
132     if (!_queue_is_empty(queue))
133     {
134         LIST_FOR_EACH_ENTRY_SAFE (search_node, temp, &queue->head, item_link)
135         {
136             if (search_node == node)
137                 return 1;
138         }
139     }
140
141     return 0;
142 }
143
144 tbm_surface_queue_error_e
145 tbm_surface_queue_enqueue (tbm_surface_queue_h surface_queue, tbm_surface_h surface)
146 {
147     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
148     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
149
150     int i;
151
152     pthread_mutex_lock (&surface_queue->lock);
153
154     for (i = 0 ; i < surface_queue->size ; i++)
155     {
156         if (surface_queue->node_list[i]->surface == surface)
157             break;
158     }
159
160     if (i == surface_queue->size)
161     {
162         TBM_LOG ("Can't fine surface list in queue\n");
163         pthread_mutex_unlock (&surface_queue->lock);
164         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
165     }
166
167     if (_queue_node_exist_in_queue (&surface_queue->duty_queue, surface_queue->node_list[i]))
168     {
169         TBM_LOG ("Surface exist in queue\n");
170         pthread_mutex_unlock (&surface_queue->lock);
171         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
172     }
173
174     _queue_node_push_back(&surface_queue->duty_queue, surface_queue->node_list[i]);
175
176     pthread_mutex_unlock (&surface_queue->lock);
177     pthread_cond_signal(&surface_queue->duty_cond);
178
179     if (surface_queue->acquirable_cb)
180         surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
181
182     return TBM_SURFACE_QUEUE_ERROR_NONE;
183 }
184
185 tbm_surface_queue_error_e
186 tbm_surface_queue_dequeue (tbm_surface_queue_h surface_queue, tbm_surface_h *surface)
187 {
188     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
189     TBM_RETURN_VAL_IF_FAIL (surface_queue->free_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
190
191     pthread_mutex_lock (&surface_queue->lock);
192
193     if (_queue_is_empty (&surface_queue->free_queue))
194     {
195         TBM_LOG ("Surface queue is empty\n");
196         pthread_mutex_unlock (&surface_queue->lock);
197         return TBM_SURFACE_QUEUE_ERROR_EMPTY;
198     }
199
200     queue_node *node = NULL;
201
202     node = _queue_node_pop_front (&surface_queue->free_queue);
203     if (node == NULL)
204     {
205         TBM_LOG ("_queue_node_pop_front is failed\n");
206         pthread_mutex_unlock (&surface_queue->lock);
207         return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
208     }
209
210     *surface = node->surface;
211
212     pthread_mutex_unlock (&surface_queue->lock);
213
214     return TBM_SURFACE_QUEUE_ERROR_NONE;
215 }
216
217 tbm_surface_queue_error_e
218 tbm_surface_queue_release (tbm_surface_queue_h surface_queue, tbm_surface_h surface)
219 {
220     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
221     TBM_RETURN_VAL_IF_FAIL (surface != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE);
222
223     pthread_mutex_lock (&surface_queue->lock);
224
225     int i;
226     for (i = 0 ; i < surface_queue->size ; i++)
227     {
228         if (surface_queue->node_list[i]->surface == surface)
229             break;
230     }
231     if (i == surface_queue->size)
232     {
233         TBM_LOG ("Can't fine surface list in queue\n");
234         pthread_mutex_unlock (&surface_queue->lock);
235         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
236     }
237
238     if (_queue_node_exist_in_queue (&surface_queue->free_queue, surface_queue->node_list[i]))
239     {
240         TBM_LOG ("Surface exist in queue\n");
241         pthread_mutex_unlock (&surface_queue->lock);
242         return TBM_SURFACE_QUEUE_ERROR_INVALID_SURFACE;
243     }
244
245     _queue_node_push_back(&surface_queue->free_queue, surface_queue->node_list[i]);
246
247     pthread_mutex_unlock (&surface_queue->lock);
248     pthread_cond_signal(&surface_queue->free_cond);
249
250     if (surface_queue->dequeuable_cb)
251         surface_queue->dequeuable_cb (surface_queue, surface_queue->dequeuable_cb_data);
252
253     return TBM_SURFACE_QUEUE_ERROR_NONE;
254 }
255
256 tbm_surface_queue_error_e
257 tbm_surface_queue_acquire (tbm_surface_queue_h surface_queue, tbm_surface_h *surface)
258 {
259     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
260     TBM_RETURN_VAL_IF_FAIL (surface_queue->duty_queue.count > 0, TBM_SURFACE_QUEUE_ERROR_EMPTY);
261
262     pthread_mutex_lock (&surface_queue->lock);
263
264     if (_queue_is_empty (&surface_queue->duty_queue))
265     {
266         TBM_LOG ("Surface queue is empty\n");
267         pthread_mutex_unlock (&surface_queue->lock);
268         return TBM_SURFACE_QUEUE_ERROR_EMPTY;
269     }
270
271     queue_node *node = NULL;
272
273     node = _queue_node_pop_front (&surface_queue->duty_queue);
274     if (node == NULL)
275     {
276         TBM_LOG ("_queue_node_pop_front  failed\n");
277         pthread_mutex_unlock (&surface_queue->lock);
278         return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
279     }
280
281     *surface = node->surface;
282
283     pthread_mutex_unlock (&surface_queue->lock);
284
285     return TBM_SURFACE_QUEUE_ERROR_NONE;
286 }
287
288 int
289 tbm_surface_queue_can_dequeue (tbm_surface_queue_h surface_queue, int wait)
290 {
291     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
292
293     pthread_mutex_lock (&surface_queue->lock);
294
295     if (_queue_is_empty (&surface_queue->free_queue))
296     {
297         if (wait)
298         {
299             pthread_cond_wait (&surface_queue->free_cond, &surface_queue->lock);
300             pthread_mutex_unlock (&surface_queue->lock);
301             return 1;
302         }
303
304         pthread_mutex_unlock (&surface_queue->lock);
305         return 0;
306     }
307
308     pthread_mutex_unlock (&surface_queue->lock);
309     return 1;
310 }
311
312 int
313 tbm_surface_queue_can_acquire (tbm_surface_queue_h surface_queue, int wait)
314 {
315     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
316
317     pthread_mutex_lock (&surface_queue->lock);
318
319     if (_queue_is_empty (&surface_queue->duty_queue))
320     {
321         if (wait)
322         {
323             pthread_cond_wait (&surface_queue->duty_cond, &surface_queue->lock);
324             pthread_mutex_unlock (&surface_queue->lock);
325             return 1;
326         }
327
328         pthread_mutex_unlock (&surface_queue->lock);
329         return 0;
330     }
331
332     pthread_mutex_unlock (&surface_queue->lock);
333
334     return 1;
335 }
336
337 tbm_surface_queue_h
338 tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
339 {
340     TBM_RETURN_VAL_IF_FAIL (queue_size > 0, NULL);
341     TBM_RETURN_VAL_IF_FAIL (width > 0, NULL);
342     TBM_RETURN_VAL_IF_FAIL (height > 0, NULL);
343     TBM_RETURN_VAL_IF_FAIL (format > 0, NULL);
344
345     int i, j;
346     tbm_surface_queue_h surface_queue = (tbm_surface_queue_h)calloc(1, sizeof(struct _tbm_surface_queue));
347     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, NULL);
348
349     pthread_mutex_init (&surface_queue->lock, NULL);
350     pthread_cond_init (&surface_queue->free_cond, NULL);
351     pthread_cond_init (&surface_queue->duty_cond, NULL);
352
353     surface_queue->width = width;
354     surface_queue->height = height;
355     surface_queue->format = format;
356     surface_queue->flags = flags;
357     surface_queue->size = queue_size;
358     surface_queue->node_list = (queue_node **)calloc(queue_size, sizeof(queue_node *));
359     if (!surface_queue->node_list)
360     {
361         TBM_LOG ("surface node list alloc failed");
362         free (surface_queue);
363         pthread_mutex_destroy (&surface_queue->lock);
364         return NULL;
365     }
366
367     LIST_INITHEAD (&surface_queue->free_queue.tail);
368     LIST_ADDTAIL (&surface_queue->free_queue.head, &surface_queue->free_queue.tail);
369
370     LIST_INITHEAD (&surface_queue->duty_queue.tail);
371     LIST_ADDTAIL (&surface_queue->duty_queue.head, &surface_queue->duty_queue.tail);
372
373     for (i = 0 ; i < queue_size; i++)
374     {
375         tbm_surface_h surface = tbm_surface_internal_create_with_flags (width, height, format, flags);
376         if (surface == NULL)
377         {
378             TBM_LOG ("tbm surface create  failed");
379             goto fail;
380         }
381
382         queue_node *node = _queue_node_create(surface);
383         if (node == NULL)
384         {
385             TBM_LOG ("surface node create failed");
386             goto fail;
387         }
388
389         surface_queue->node_list[i] = node;
390         _queue_node_push_back (&surface_queue->free_queue, node);
391     }
392
393     return surface_queue;
394
395 fail:
396     for (j = 0 ; j < i ; j++)
397         _queue_node_delete (surface_queue->node_list[j]);
398
399     free (surface_queue->node_list);
400     free (surface_queue);
401     pthread_mutex_destroy (&surface_queue->lock);
402
403     return NULL;
404 }
405
406 void
407 tbm_surface_queue_destroy (tbm_surface_queue_h surface_queue)
408 {
409     TBM_RETURN_IF_FAIL (surface_queue != NULL);
410
411     if (surface_queue->destroy_cb)
412         surface_queue->destroy_cb (surface_queue, surface_queue->destroy_cb_data);
413
414     int i;
415
416     for (i = 0 ; i < surface_queue->size ; i++)
417         _queue_node_delete (surface_queue->node_list[i]);
418
419     free (surface_queue->node_list);
420     free (surface_queue);
421 }
422
423 tbm_surface_queue_error_e
424 tbm_surface_queue_set_destroy_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb destroy_cb, void *data)
425 {
426     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
427
428     pthread_mutex_lock (&surface_queue->lock);
429
430     surface_queue->destroy_cb = destroy_cb;
431     surface_queue->destroy_cb_data = data;
432
433     pthread_mutex_unlock (&surface_queue->lock);
434
435     return TBM_SURFACE_QUEUE_ERROR_NONE;
436 }
437
438 tbm_surface_queue_error_e
439 tbm_surface_queue_set_dequeuable_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb dequeuable_cb, void *data)
440 {
441     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
442
443     pthread_mutex_lock (&surface_queue->lock);
444
445     surface_queue->dequeuable_cb = dequeuable_cb;
446     surface_queue->dequeuable_cb_data = data;
447
448     pthread_mutex_unlock (&surface_queue->lock);
449
450     return TBM_SURFACE_QUEUE_ERROR_NONE;
451 }
452
453 tbm_surface_queue_error_e
454 tbm_surface_queue_set_acquirable_cb (tbm_surface_queue_h surface_queue, tbm_surface_queue_notify_cb acquirable_cb, void *data)
455 {
456     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
457
458     pthread_mutex_lock (&surface_queue->lock);
459
460     surface_queue->acquirable_cb = acquirable_cb;
461     surface_queue->acquirable_cb_data = data;
462
463     pthread_mutex_unlock (&surface_queue->lock);
464
465     return TBM_SURFACE_QUEUE_ERROR_NONE;
466 }
467
468 int
469 tbm_surface_queue_get_queue_size (tbm_surface_queue_h surface_queue)
470 {
471     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
472
473     return surface_queue->size;
474 }
475
476 int
477 tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
478 {
479     TBM_RETURN_VAL_IF_FAIL (surface_queue != NULL, 0);
480
481     return surface_queue->width;
482 }
483
484 int
485 tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
486 {
487     return surface_queue->height;
488 }
489
490 int
491 tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
492 {
493     return surface_queue->format;
494 }