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