return error if a buffer is attached twice
[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_func_capture *func_capture;
226         tdm_buffer_info *b = NULL, *bb = NULL;
227
228         if (!private_capture)
229                 return;
230
231         LIST_DEL(&private_capture->link);
232
233         func_capture = &private_capture->private_display->func_capture;
234         func_capture->capture_destroy(private_capture->capture_backend);
235
236         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
237                 TDM_ERR("capture(%p) not finished:", private_capture);
238                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
239
240                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
241                         LIST_DEL(&b->link);
242         }
243
244         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
245                 TDM_ERR("capture(%p) not finished:", private_capture);
246                 tdm_buffer_list_dump(&private_capture->buffer_list);
247
248                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link)
249                         LIST_DEL(&b->link);
250         }
251
252         free(private_capture);
253 }
254
255 EXTERN void
256 tdm_capture_destroy(tdm_capture *capture)
257 {
258         tdm_private_capture *private_capture = capture;
259         tdm_private_display *private_display;
260
261         if (!private_capture)
262                 return;
263
264         private_display = private_capture->private_display;
265
266         pthread_mutex_lock(&private_display->lock);
267         tdm_capture_destroy_internal(private_capture);
268         pthread_mutex_unlock(&private_display->lock);
269 }
270
271 EXTERN tdm_error
272 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
273 {
274         CAPTURE_FUNC_ENTRY();
275
276         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
277
278         pthread_mutex_lock(&private_display->lock);
279
280         if (!func_capture->capture_set_info) {
281                 pthread_mutex_unlock(&private_display->lock);
282                 return TDM_ERROR_NONE;
283         }
284
285         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
286         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
287
288         pthread_mutex_unlock(&private_display->lock);
289
290         return ret;
291 }
292
293 EXTERN tdm_error
294 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
295 {
296         CAPTURE_FUNC_ENTRY();
297
298         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
299
300         pthread_mutex_lock(&private_display->lock);
301
302         if (!func_capture->capture_attach) {
303                 pthread_mutex_unlock(&private_display->lock);
304                 return TDM_ERROR_NONE;
305         }
306
307         ret = _tdm_capture_check_if_exist(private_capture, buffer);
308         if (ret != TDM_ERROR_NONE) {
309                 pthread_mutex_unlock(&private_display->lock);
310                 return ret;
311         }
312
313         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
314         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
315
316         if (ret == TDM_ERROR_NONE) {
317                 tdm_buffer_info *buf_info;
318
319                 if ((buf_info = tdm_buffer_get_info(buffer)))
320                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
321
322                 if (tdm_debug_buffer) {
323                         TDM_INFO("capture(%p) attached:", private_capture);
324                         tdm_buffer_list_dump(&private_capture->buffer_list);
325                 }
326         }
327
328         pthread_mutex_unlock(&private_display->lock);
329
330         return ret;
331 }
332
333 EXTERN tdm_error
334 tdm_capture_commit(tdm_capture *capture)
335 {
336         tdm_buffer_info *b = NULL, *bb = NULL;
337
338         CAPTURE_FUNC_ENTRY();
339
340         pthread_mutex_lock(&private_display->lock);
341
342         if (!func_capture->capture_commit) {
343                 pthread_mutex_unlock(&private_display->lock);
344                 return TDM_ERROR_NONE;
345         }
346
347         ret = func_capture->capture_commit(private_capture->capture_backend);
348         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
349
350         if (ret == TDM_ERROR_NONE) {
351                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
352                         LIST_DEL(&b->link);
353                         tdm_buffer_ref_backend(b->buffer);
354                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
355                 }
356         } else {
357                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
358                         LIST_DEL(&b->link);
359         }
360
361         pthread_mutex_unlock(&private_display->lock);
362
363         return ret;
364 }