return TDM_ERROR_NOT_IMPLEMENTED if backend doesn't implenment
[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                 TDM_DBG("failed: not implemented!!");
292                 return TDM_ERROR_NOT_IMPLEMENTED;
293         }
294
295         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
296         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
297
298         _pthread_mutex_unlock(&private_display->lock);
299
300         return ret;
301 }
302
303 EXTERN tdm_error
304 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
305 {
306         CAPTURE_FUNC_ENTRY();
307
308         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
309
310         _pthread_mutex_lock(&private_display->lock);
311
312         if (!func_capture->capture_attach) {
313                 _pthread_mutex_unlock(&private_display->lock);
314                 TDM_DBG("failed: not implemented!!");
315                 return TDM_ERROR_NOT_IMPLEMENTED;
316         }
317
318         ret = _tdm_capture_check_if_exist(private_capture, buffer);
319         if (ret != TDM_ERROR_NONE) {
320                 _pthread_mutex_unlock(&private_display->lock);
321                 return ret;
322         }
323
324         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
325         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
326
327         if (ret == TDM_ERROR_NONE) {
328                 tdm_buffer_info *buf_info;
329
330                 if ((buf_info = tdm_buffer_get_info(buffer)))
331                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
332
333                 if (tdm_debug_buffer) {
334                         TDM_INFO("capture(%p) attached:", private_capture);
335                         tdm_buffer_list_dump(&private_capture->buffer_list);
336                 }
337         }
338
339         _pthread_mutex_unlock(&private_display->lock);
340
341         return ret;
342 }
343
344 EXTERN tdm_error
345 tdm_capture_commit(tdm_capture *capture)
346 {
347         tdm_buffer_info *b = NULL, *bb = NULL;
348
349         CAPTURE_FUNC_ENTRY();
350
351         _pthread_mutex_lock(&private_display->lock);
352
353         if (!func_capture->capture_commit) {
354                 _pthread_mutex_unlock(&private_display->lock);
355                 TDM_DBG("failed: not implemented!!");
356                 return TDM_ERROR_NOT_IMPLEMENTED;
357         }
358
359         ret = func_capture->capture_commit(private_capture->capture_backend);
360         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
361
362         if (ret == TDM_ERROR_NONE) {
363                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
364                         LIST_DEL(&b->link);
365                         tdm_buffer_ref_backend(b->buffer);
366                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
367                 }
368         } else {
369                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
370                         LIST_DEL(&b->link);
371         }
372
373         _pthread_mutex_unlock(&private_display->lock);
374
375         return ret;
376 }