Fix prevent issues
[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         struct list_head head;
37
38         struct list_head tail;
39
40         int count;
41 } queue;
42
43 typedef struct {
44         tbm_surface_h surface;
45
46         struct list_head item_link;
47 } queue_node;
48
49 struct _tbm_surface_queue {
50         int width;
51         int height;
52         int format;
53         int size;
54         int flags;
55
56         queue free_queue;
57         queue duty_queue;
58         queue_node **node_list;
59
60         tbm_surface_queue_notify_cb destroy_cb;
61         void *destroy_cb_data;
62
63         tbm_surface_queue_notify_cb dequeuable_cb;
64         void *dequeuable_cb_data;
65
66         tbm_surface_queue_notify_cb acquirable_cb;
67         void *acquirable_cb_data;
68
69         tbm_surface_queue_notify_cb reset_cb;
70         void *reset_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 *_queue_node_create(void)
78 {
79         queue_node *node = (queue_node *) calloc(1, sizeof(queue_node));
80         TBM_RETURN_VAL_IF_FAIL(node != NULL, NULL);
81
82         return node;
83 }
84
85 static void _queue_node_delete(queue_node * node)
86 {
87         if (node->surface)
88                 tbm_surface_destroy(node->surface);
89         LIST_DEL(&node->item_link);
90         free(node);
91 }
92
93 static int _queue_is_empty(queue * queue)
94 {
95         if (queue->head.next == &queue->tail)
96                 return 1;
97
98         return 0;
99 }
100
101 static void _queue_node_push_back(queue * queue, queue_node * node)
102 {
103         LIST_ADDTAIL(&node->item_link, &queue->tail);
104         queue->count++;
105         return;
106 }
107
108 static void _queue_node_push_front(queue * queue, queue_node * node)
109 {
110         LIST_ADD(&node->item_link, &queue->head);
111         queue->count++;
112         return;
113 }
114
115 static queue_node *_queue_node_pop_front(queue * queue)
116 {
117         queue_node *node = NULL;
118
119         node = LIST_ENTRY(queue_node, queue->head.next, item_link);
120
121         LIST_DEL(&node->item_link);
122         queue->count--;
123
124         return node;
125 }
126
127 static int _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                 LIST_FOR_EACH_ENTRY_SAFE(search_node, temp, &queue->head, item_link) {
134                         if (search_node == node)
135                                 return 1;
136                 }
137         }
138
139         return 0;
140 }
141
142 static void _queue_init(queue * queue)
143 {
144         LIST_INITHEAD(&queue->head);
145         LIST_INITHEAD(&queue->tail);
146         LIST_ADDTAIL(&queue->head, &queue->tail);
147         queue->count = 0;
148 }
149
150 tbm_surface_queue_error_e tbm_surface_queue_enqueue(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
151 {
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);
154
155         int i;
156
157         pthread_mutex_lock(&surface_queue->lock);
158
159         for (i = 0; i < surface_queue->size; i++) {
160                 if (surface_queue->node_list[i]->surface == surface)
161                         break;
162         }
163
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;
168         }
169
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;
174         }
175
176         _queue_node_push_back(&surface_queue->duty_queue, surface_queue->node_list[i]);
177
178         pthread_mutex_unlock(&surface_queue->lock);
179         pthread_cond_signal(&surface_queue->duty_cond);
180
181         if (surface_queue->acquirable_cb)
182                 surface_queue->acquirable_cb(surface_queue, surface_queue->acquirable_cb_data);
183
184         return TBM_SURFACE_QUEUE_ERROR_NONE;
185 }
186
187 tbm_surface_queue_error_e tbm_surface_queue_dequeue(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
188 {
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);
191
192         pthread_mutex_lock(&surface_queue->lock);
193
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;
198         }
199
200         queue_node *node = NULL;
201
202         node = _queue_node_pop_front(&surface_queue->free_queue);
203         if (node == NULL) {
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;
207         }
208
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;
218                 }
219                 node->surface = surface;
220         }
221
222         *surface = node->surface;
223
224         pthread_mutex_unlock(&surface_queue->lock);
225
226         return TBM_SURFACE_QUEUE_ERROR_NONE;
227 }
228
229 tbm_surface_queue_error_e tbm_surface_queue_release(tbm_surface_queue_h surface_queue, tbm_surface_h surface)
230 {
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);
233
234         pthread_mutex_lock(&surface_queue->lock);
235
236         int i;
237         for (i = 0; i < surface_queue->size; i++) {
238                 if (surface_queue->node_list[i]->surface == surface)
239                         break;
240         }
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;
245         }
246
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;
251         }
252
253         _queue_node_push_front(&surface_queue->free_queue, surface_queue->node_list[i]);
254
255         pthread_mutex_unlock(&surface_queue->lock);
256         pthread_cond_signal(&surface_queue->free_cond);
257
258         if (surface_queue->dequeuable_cb)
259                 surface_queue->dequeuable_cb(surface_queue, surface_queue->dequeuable_cb_data);
260
261         return TBM_SURFACE_QUEUE_ERROR_NONE;
262 }
263
264 tbm_surface_queue_error_e tbm_surface_queue_acquire(tbm_surface_queue_h surface_queue, tbm_surface_h * surface)
265 {
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);
268
269         pthread_mutex_lock(&surface_queue->lock);
270
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;
275         }
276
277         queue_node *node = NULL;
278
279         node = _queue_node_pop_front(&surface_queue->duty_queue);
280         if (node == NULL) {
281                 TBM_LOG("_queue_node_pop_front  failed\n");
282                 pthread_mutex_unlock(&surface_queue->lock);
283                 return TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE;
284         }
285
286         *surface = node->surface;
287
288         pthread_mutex_unlock(&surface_queue->lock);
289
290         return TBM_SURFACE_QUEUE_ERROR_NONE;
291 }
292
293 int tbm_surface_queue_can_dequeue(tbm_surface_queue_h surface_queue, int wait)
294 {
295         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
296
297         pthread_mutex_lock(&surface_queue->lock);
298
299         if (_queue_is_empty(&surface_queue->free_queue)) {
300                 if (wait) {
301                         pthread_cond_wait(&surface_queue->free_cond, &surface_queue->lock);
302                         pthread_mutex_unlock(&surface_queue->lock);
303                         return 1;
304                 }
305
306                 pthread_mutex_unlock(&surface_queue->lock);
307                 return 0;
308         }
309
310         pthread_mutex_unlock(&surface_queue->lock);
311         return 1;
312 }
313
314 int tbm_surface_queue_can_acquire(tbm_surface_queue_h surface_queue, int wait)
315 {
316         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
317
318         pthread_mutex_lock(&surface_queue->lock);
319
320         if (_queue_is_empty(&surface_queue->duty_queue)) {
321                 if (wait) {
322                         pthread_cond_wait(&surface_queue->duty_cond, &surface_queue->lock);
323                         pthread_mutex_unlock(&surface_queue->lock);
324                         return 1;
325                 }
326
327                 pthread_mutex_unlock(&surface_queue->lock);
328                 return 0;
329         }
330
331         pthread_mutex_unlock(&surface_queue->lock);
332
333         return 1;
334 }
335
336 tbm_surface_queue_h tbm_surface_queue_create(int queue_size, int width, int height, int format, int flags)
337 {
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);
342
343         int i, j;
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);
346
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);
350
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");
359                 free(surface_queue);
360                 pthread_mutex_destroy(&surface_queue->lock);
361                 return NULL;
362         }
363
364         _queue_init(&surface_queue->free_queue);
365         _queue_init(&surface_queue->duty_queue);
366
367         for (i = 0; i < queue_size; i++) {
368                 queue_node *node = _queue_node_create();
369                 if (node == NULL) {
370                         TBM_LOG("surface node create failed");
371                         goto fail;
372                 }
373
374                 surface_queue->node_list[i] = node;
375                 _queue_node_push_back(&surface_queue->free_queue, node);
376         }
377
378         return surface_queue;
379
380  fail:
381         for (j = 0; j < i; j++)
382                 _queue_node_delete(surface_queue->node_list[j]);
383
384         free(surface_queue->node_list);
385         pthread_mutex_destroy(&surface_queue->lock);
386         free(surface_queue);
387
388         return NULL;
389 }
390
391 void tbm_surface_queue_destroy(tbm_surface_queue_h surface_queue)
392 {
393         TBM_RETURN_IF_FAIL(surface_queue != NULL);
394
395         if (surface_queue->destroy_cb)
396                 surface_queue->destroy_cb(surface_queue, surface_queue->destroy_cb_data);
397
398         int i;
399
400         for (i = 0; i < surface_queue->size; i++)
401                 _queue_node_delete(surface_queue->node_list[i]);
402
403         free(surface_queue->node_list);
404         free(surface_queue);
405 }
406
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)
408 {
409         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
410
411         pthread_mutex_lock(&surface_queue->lock);
412
413         surface_queue->destroy_cb = destroy_cb;
414         surface_queue->destroy_cb_data = data;
415
416         pthread_mutex_unlock(&surface_queue->lock);
417
418         return TBM_SURFACE_QUEUE_ERROR_NONE;
419 }
420
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)
422 {
423         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
424
425         pthread_mutex_lock(&surface_queue->lock);
426
427         surface_queue->dequeuable_cb = dequeuable_cb;
428         surface_queue->dequeuable_cb_data = data;
429
430         pthread_mutex_unlock(&surface_queue->lock);
431
432         return TBM_SURFACE_QUEUE_ERROR_NONE;
433 }
434
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)
436 {
437         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
438
439         pthread_mutex_lock(&surface_queue->lock);
440
441         surface_queue->acquirable_cb = acquirable_cb;
442         surface_queue->acquirable_cb_data = data;
443
444         pthread_mutex_unlock(&surface_queue->lock);
445
446         return TBM_SURFACE_QUEUE_ERROR_NONE;
447 }
448
449 int tbm_surface_queue_get_queue_size(tbm_surface_queue_h surface_queue)
450 {
451         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
452
453         return surface_queue->size;
454 }
455
456 int tbm_surface_queue_get_width(tbm_surface_queue_h surface_queue)
457 {
458         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, 0);
459
460         return surface_queue->width;
461 }
462
463 int tbm_surface_queue_get_height(tbm_surface_queue_h surface_queue)
464 {
465         return surface_queue->height;
466 }
467
468 int tbm_surface_queue_get_format(tbm_surface_queue_h surface_queue)
469 {
470         return surface_queue->format;
471 }
472
473 tbm_surface_queue_error_e tbm_surface_queue_reset(tbm_surface_queue_h surface_queue, int width, int height, int format)
474 {
475         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
476
477         int i;
478         queue_node *node = NULL;
479
480         if (width == surface_queue->width && height == surface_queue->height && format == surface_queue->format)
481                 return TBM_SURFACE_QUEUE_ERROR_NONE;
482
483         pthread_mutex_lock(&surface_queue->lock);
484
485         surface_queue->width = width;
486         surface_queue->height = height;
487         surface_queue->format = format;
488
489         /* Reset queue */
490         _queue_init(&surface_queue->free_queue);
491         _queue_init(&surface_queue->duty_queue);
492
493         /* Destory surface and Push to free_queue */
494         for (i = 0; i < surface_queue->size; i++) {
495                 node = surface_queue->node_list[i];
496                 if (node->surface) {
497                         tbm_surface_destroy(node->surface);
498                         node->surface = NULL;
499                 }
500
501                 _queue_node_push_back(&surface_queue->free_queue, node);
502         }
503
504         pthread_mutex_unlock(&surface_queue->lock);
505         pthread_cond_signal(&surface_queue->free_cond);
506
507         if (surface_queue->reset_cb)
508                 surface_queue->reset_cb(surface_queue, surface_queue->reset_cb_data);
509
510         return TBM_SURFACE_QUEUE_ERROR_NONE;
511 }
512
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)
514 {
515         TBM_RETURN_VAL_IF_FAIL(surface_queue != NULL, TBM_SURFACE_QUEUE_ERROR_INVALID_QUEUE);
516
517         pthread_mutex_lock(&surface_queue->lock);
518
519         surface_queue->reset_cb = reset_cb;
520         surface_queue->reset_cb_data = data;
521
522         pthread_mutex_unlock(&surface_queue->lock);
523
524         return TBM_SURFACE_QUEUE_ERROR_NONE;
525 }