unref buffer when destroyed
[platform/core/uifw/libtdm.git] / src / tdm_capture.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43
44 #define CAPTURE_FUNC_ENTRY() \
45     tdm_func_capture *func_capture; \
46     tdm_private_display *private_display; \
47     tdm_private_capture *private_capture; \
48     tdm_error ret = TDM_ERROR_NONE; \
49     TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER); \
50     private_capture = (tdm_private_capture*)capture; \
51     private_display = private_capture->private_display; \
52     func_capture = &private_display->func_capture
53
54 static tdm_error
55 _tdm_capture_check_if_exist(tdm_private_capture *private_capture,
56                             tbm_surface_h buffer)
57 {
58         tdm_buffer_info *buf_info = NULL;
59
60         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->buffer_list, link) {
61                 if (buf_info->buffer == buffer) {
62                         TDM_ERR("%p attached twice", buffer);
63                         return TDM_ERROR_BAD_REQUEST;
64                 }
65         }
66
67         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->pending_buffer_list, link) {
68                 if (buf_info->buffer == buffer) {
69                         TDM_ERR("%p attached twice", buffer);
70                         return TDM_ERROR_BAD_REQUEST;
71                 }
72         }
73
74         return TDM_ERROR_NONE;
75 }
76
77 static void
78 _tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
79                      void *user_data)
80 {
81         tdm_private_capture *private_capture = user_data;
82         tdm_private_display *private_display = private_capture->private_display;
83         tdm_buffer_info *buf_info;
84         tbm_surface_h first_entry;
85         int lock_after_cb_done = 0;
86         int ret;
87
88         if (tdm_debug_buffer)
89                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
90
91         first_entry = tdm_buffer_list_get_first_entry(&private_capture->buffer_list);
92         if (first_entry != buffer)
93                 TDM_ERR("%p is skipped", first_entry);
94
95         if ((buf_info = tdm_buffer_get_info(buffer)))
96                 LIST_DEL(&buf_info->link);
97
98         ret = pthread_mutex_trylock(&private_display->lock);
99         if (ret == 0)
100                 pthread_mutex_unlock(&private_display->lock);
101         else  if (ret == EBUSY) {
102                 pthread_mutex_unlock(&private_display->lock);
103                 lock_after_cb_done = 1;
104         }
105
106         tdm_buffer_unref_backend(buffer);
107
108         if (lock_after_cb_done)
109                 pthread_mutex_lock(&private_display->lock);
110 }
111
112 INTERN tdm_private_capture *
113 tdm_capture_create_output_internal(tdm_private_output *private_output,
114                                    tdm_error *error)
115 {
116         tdm_private_display *private_display = private_output->private_display;
117         tdm_func_output *func_output = &private_display->func_output;
118         tdm_func_capture *func_capture = &private_display->func_capture;
119         tdm_private_capture *private_capture = NULL;
120         tdm_capture *capture_backend = NULL;
121         tdm_error ret = TDM_ERROR_NONE;
122
123         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
124                 TDM_ERR("no capture capability");
125                 if (error)
126                         *error = TDM_ERROR_NO_CAPABILITY;
127                 return NULL;
128         }
129
130         capture_backend = func_output->output_create_capture(
131                                   private_output->output_backend, &ret);
132         if (ret != TDM_ERROR_NONE) {
133                 if (error)
134                         *error = ret;
135                 return NULL;
136         }
137
138         private_capture = calloc(1, sizeof(tdm_private_capture));
139         if (!private_capture) {
140                 TDM_ERR("failed: alloc memory");
141                 func_capture->capture_destroy(capture_backend);
142                 if (error)
143                         *error = TDM_ERROR_OUT_OF_MEMORY;
144                 return NULL;
145         }
146
147         ret = func_capture->capture_set_done_handler(capture_backend,
148                         _tdm_caputre_cb_done, private_capture);
149         if (ret != TDM_ERROR_NONE) {
150                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
151                 func_capture->capture_destroy(capture_backend);
152                 if (error)
153                         *error = ret;
154                 return NULL;
155         }
156
157         LIST_ADD(&private_capture->link, &private_output->capture_list);
158         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
159         private_capture->private_display = private_display;
160         private_capture->private_output = private_output;
161         private_capture->private_layer = NULL;
162         private_capture->capture_backend = capture_backend;
163
164         LIST_INITHEAD(&private_capture->pending_buffer_list);
165         LIST_INITHEAD(&private_capture->buffer_list);
166
167         if (error)
168                 *error = TDM_ERROR_NONE;
169
170         return private_capture;
171 }
172
173 INTERN tdm_private_capture *
174 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
175                                   tdm_error *error)
176 {
177         tdm_private_output *private_output = private_layer->private_output;
178         tdm_private_display *private_display = private_output->private_display;
179         tdm_func_layer *func_layer = &private_display->func_layer;
180         tdm_func_capture *func_capture = &private_display->func_capture;
181         tdm_private_capture *private_capture = NULL;
182         tdm_capture *capture_backend = NULL;
183         tdm_error ret = TDM_ERROR_NONE;
184
185         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
186                 TDM_ERR("no capture capability");
187                 if (error)
188                         *error = TDM_ERROR_NO_CAPABILITY;
189                 return NULL;
190         }
191
192         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
193                           &ret);
194         if (ret != TDM_ERROR_NONE)
195                 return NULL;
196
197         private_capture = calloc(1, sizeof(tdm_private_capture));
198         if (!private_capture) {
199                 TDM_ERR("failed: alloc memory");
200                 func_capture->capture_destroy(capture_backend);
201                 if (error)
202                         *error = TDM_ERROR_OUT_OF_MEMORY;
203                 return NULL;
204         }
205
206         LIST_ADD(&private_capture->link, &private_output->capture_list);
207         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
208         private_capture->private_display = private_display;
209         private_capture->private_output = private_output;
210         private_capture->private_layer = private_layer;
211         private_capture->capture_backend = capture_backend;
212
213         LIST_INITHEAD(&private_capture->pending_buffer_list);
214         LIST_INITHEAD(&private_capture->buffer_list);
215
216         if (error)
217                 *error = TDM_ERROR_NONE;
218
219         return private_capture;
220 }
221
222 INTERN void
223 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
224 {
225         tdm_private_display *private_display = private_capture->private_display;
226         tdm_func_capture *func_capture;
227         tdm_buffer_info *b = NULL, *bb = NULL;
228
229         if (!private_capture)
230                 return;
231
232         LIST_DEL(&private_capture->link);
233
234         func_capture = &private_capture->private_display->func_capture;
235         func_capture->capture_destroy(private_capture->capture_backend);
236
237         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
238                 TDM_ERR("capture(%p) not finished:", private_capture);
239                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
240
241                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
242                         LIST_DEL(&b->link);
243                         pthread_mutex_unlock(&private_display->lock);
244                         tdm_buffer_unref_backend(b->buffer);
245                         pthread_mutex_lock(&private_display->lock);
246                 }
247         }
248
249         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
250                 TDM_ERR("capture(%p) not finished:", private_capture);
251                 tdm_buffer_list_dump(&private_capture->buffer_list);
252
253                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
254                         LIST_DEL(&b->link);
255                         pthread_mutex_unlock(&private_display->lock);
256                         tdm_buffer_unref_backend(b->buffer);
257                         pthread_mutex_lock(&private_display->lock);
258                 }
259         }
260
261         free(private_capture);
262 }
263
264 EXTERN void
265 tdm_capture_destroy(tdm_capture *capture)
266 {
267         tdm_private_capture *private_capture = capture;
268         tdm_private_display *private_display;
269
270         if (!private_capture)
271                 return;
272
273         private_display = private_capture->private_display;
274
275         pthread_mutex_lock(&private_display->lock);
276         tdm_capture_destroy_internal(private_capture);
277         pthread_mutex_unlock(&private_display->lock);
278 }
279
280 EXTERN tdm_error
281 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
282 {
283         CAPTURE_FUNC_ENTRY();
284
285         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
286
287         pthread_mutex_lock(&private_display->lock);
288
289         if (!func_capture->capture_set_info) {
290                 pthread_mutex_unlock(&private_display->lock);
291                 return TDM_ERROR_NONE;
292         }
293
294         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
295         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
296
297         pthread_mutex_unlock(&private_display->lock);
298
299         return ret;
300 }
301
302 EXTERN tdm_error
303 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
304 {
305         CAPTURE_FUNC_ENTRY();
306
307         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
308
309         pthread_mutex_lock(&private_display->lock);
310
311         if (!func_capture->capture_attach) {
312                 pthread_mutex_unlock(&private_display->lock);
313                 return TDM_ERROR_NONE;
314         }
315
316         ret = _tdm_capture_check_if_exist(private_capture, buffer);
317         if (ret != TDM_ERROR_NONE) {
318                 pthread_mutex_unlock(&private_display->lock);
319                 return ret;
320         }
321
322         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
323         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
324
325         if (ret == TDM_ERROR_NONE) {
326                 tdm_buffer_info *buf_info;
327
328                 if ((buf_info = tdm_buffer_get_info(buffer)))
329                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
330
331                 if (tdm_debug_buffer) {
332                         TDM_INFO("capture(%p) attached:", private_capture);
333                         tdm_buffer_list_dump(&private_capture->buffer_list);
334                 }
335         }
336
337         pthread_mutex_unlock(&private_display->lock);
338
339         return ret;
340 }
341
342 EXTERN tdm_error
343 tdm_capture_commit(tdm_capture *capture)
344 {
345         tdm_buffer_info *b = NULL, *bb = NULL;
346
347         CAPTURE_FUNC_ENTRY();
348
349         pthread_mutex_lock(&private_display->lock);
350
351         if (!func_capture->capture_commit) {
352                 pthread_mutex_unlock(&private_display->lock);
353                 return TDM_ERROR_NONE;
354         }
355
356         ret = func_capture->capture_commit(private_capture->capture_backend);
357         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
358
359         if (ret == TDM_ERROR_NONE) {
360                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
361                         LIST_DEL(&b->link);
362                         tdm_buffer_ref_backend(b->buffer);
363                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
364                 }
365         } else {
366                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
367                         LIST_DEL(&b->link);
368         }
369
370         pthread_mutex_unlock(&private_display->lock);
371
372         return ret;
373 }