56fe1489eee65c100352c47c220b885f90b6b48d
[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 INTERN void
78 tdm_capture_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_thread_in_display_thread(private_display)) {
89                 tdm_thread_cb_capture_done capture_done;
90                 tdm_error ret;
91
92                 capture_done.base.type = TDM_THREAD_CB_PP_DONE;
93                 capture_done.base.length = sizeof capture_done;
94                 capture_done.capture_stamp = private_capture->stamp;
95                 capture_done.buffer = buffer;
96                 capture_done.user_data = user_data;
97
98                 ret = tdm_thread_send_cb(private_display, &capture_done.base);
99                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
100
101                 return;
102         }
103
104         if (tdm_debug_buffer)
105                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
106
107         first_entry = tdm_buffer_list_get_first_entry(&private_capture->buffer_list);
108         if (first_entry != buffer)
109                 TDM_ERR("%p is skipped", first_entry);
110
111         if ((buf_info = tdm_buffer_get_info(buffer)))
112                 LIST_DEL(&buf_info->link);
113
114         ret = pthread_mutex_trylock(&private_display->lock);
115         if (ret == 0)
116                 _pthread_mutex_unlock(&private_display->lock);
117         else  if (ret == EBUSY) {
118                 _pthread_mutex_unlock(&private_display->lock);
119                 lock_after_cb_done = 1;
120         }
121
122         tdm_buffer_unref_backend(buffer);
123
124         if (lock_after_cb_done)
125                 _pthread_mutex_lock(&private_display->lock);
126 }
127
128 INTERN tdm_private_capture *
129 tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp)
130 {
131         tdm_private_capture *private_capture = NULL;
132
133         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
134                 if (private_capture->stamp == stamp)
135                         return private_capture;
136         }
137
138         return NULL;
139 }
140
141 INTERN tdm_private_capture *
142 tdm_capture_create_output_internal(tdm_private_output *private_output,
143                                    tdm_error *error)
144 {
145         tdm_private_display *private_display = private_output->private_display;
146         tdm_func_output *func_output = &private_display->func_output;
147         tdm_func_capture *func_capture = &private_display->func_capture;
148         tdm_private_capture *private_capture = NULL;
149         tdm_capture *capture_backend = NULL;
150         tdm_error ret = TDM_ERROR_NONE;
151
152         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
153                 TDM_ERR("no capture capability");
154                 if (error)
155                         *error = TDM_ERROR_NO_CAPABILITY;
156                 return NULL;
157         }
158
159         capture_backend = func_output->output_create_capture(
160                                   private_output->output_backend, &ret);
161         if (ret != TDM_ERROR_NONE) {
162                 if (error)
163                         *error = ret;
164                 return NULL;
165         }
166
167         private_capture = calloc(1, sizeof(tdm_private_capture));
168         if (!private_capture) {
169                 TDM_ERR("failed: alloc memory");
170                 func_capture->capture_destroy(capture_backend);
171                 if (error)
172                         *error = TDM_ERROR_OUT_OF_MEMORY;
173                 return NULL;
174         }
175
176         ret = func_capture->capture_set_done_handler(capture_backend,
177                         tdm_capture_cb_done, private_capture);
178         if (ret != TDM_ERROR_NONE) {
179                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
180                 func_capture->capture_destroy(capture_backend);
181                 if (error)
182                         *error = ret;
183                 return NULL;
184         }
185
186         private_capture->stamp = tdm_helper_get_time_in_millis();
187         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
188                 private_capture->stamp++;
189
190         LIST_ADD(&private_capture->link, &private_output->capture_list);
191         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
192
193         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
194         private_capture->private_display = private_display;
195         private_capture->private_output = private_output;
196         private_capture->private_layer = NULL;
197         private_capture->capture_backend = capture_backend;
198
199         LIST_INITHEAD(&private_capture->pending_buffer_list);
200         LIST_INITHEAD(&private_capture->buffer_list);
201
202         if (error)
203                 *error = TDM_ERROR_NONE;
204
205         return private_capture;
206 }
207
208 INTERN tdm_private_capture *
209 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
210                                   tdm_error *error)
211 {
212         tdm_private_output *private_output = private_layer->private_output;
213         tdm_private_display *private_display = private_output->private_display;
214         tdm_func_layer *func_layer = &private_display->func_layer;
215         tdm_func_capture *func_capture = &private_display->func_capture;
216         tdm_private_capture *private_capture = NULL;
217         tdm_capture *capture_backend = NULL;
218         tdm_error ret = TDM_ERROR_NONE;
219
220         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
221                 TDM_ERR("no capture capability");
222                 if (error)
223                         *error = TDM_ERROR_NO_CAPABILITY;
224                 return NULL;
225         }
226
227         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
228                           &ret);
229         if (ret != TDM_ERROR_NONE)
230                 return NULL;
231
232         private_capture = calloc(1, sizeof(tdm_private_capture));
233         if (!private_capture) {
234                 TDM_ERR("failed: alloc memory");
235                 func_capture->capture_destroy(capture_backend);
236                 if (error)
237                         *error = TDM_ERROR_OUT_OF_MEMORY;
238                 return NULL;
239         }
240
241         private_capture->stamp = tdm_helper_get_time_in_millis();
242         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
243                 private_capture->stamp++;
244
245         LIST_ADD(&private_capture->link, &private_layer->capture_list);
246         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
247
248         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
249         private_capture->private_display = private_display;
250         private_capture->private_output = private_output;
251         private_capture->private_layer = private_layer;
252         private_capture->capture_backend = capture_backend;
253
254         LIST_INITHEAD(&private_capture->pending_buffer_list);
255         LIST_INITHEAD(&private_capture->buffer_list);
256
257         if (error)
258                 *error = TDM_ERROR_NONE;
259
260         return private_capture;
261 }
262
263 INTERN void
264 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
265 {
266         tdm_private_display *private_display = private_capture->private_display;
267         tdm_func_capture *func_capture;
268         tdm_buffer_info *b = NULL, *bb = NULL;
269
270         if (!private_capture)
271                 return;
272
273         LIST_DEL(&private_capture->link);
274         LIST_DEL(&private_capture->display_link);
275
276         func_capture = &private_capture->private_display->func_capture;
277         func_capture->capture_destroy(private_capture->capture_backend);
278
279         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
280                 TDM_ERR("capture(%p) not finished:", private_capture);
281                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
282
283                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
284                         LIST_DEL(&b->link);
285                         _pthread_mutex_unlock(&private_display->lock);
286                         tdm_buffer_unref_backend(b->buffer);
287                         _pthread_mutex_lock(&private_display->lock);
288                 }
289         }
290
291         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
292                 TDM_ERR("capture(%p) not finished:", private_capture);
293                 tdm_buffer_list_dump(&private_capture->buffer_list);
294
295                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
296                         LIST_DEL(&b->link);
297                         _pthread_mutex_unlock(&private_display->lock);
298                         tdm_buffer_unref_backend(b->buffer);
299                         _pthread_mutex_lock(&private_display->lock);
300                 }
301         }
302
303         private_capture->stamp = 0;
304         free(private_capture);
305 }
306
307 EXTERN void
308 tdm_capture_destroy(tdm_capture *capture)
309 {
310         tdm_private_capture *private_capture = capture;
311         tdm_private_display *private_display;
312
313         if (!private_capture)
314                 return;
315
316         private_display = private_capture->private_display;
317
318         _pthread_mutex_lock(&private_display->lock);
319         tdm_capture_destroy_internal(private_capture);
320         _pthread_mutex_unlock(&private_display->lock);
321 }
322
323 EXTERN tdm_error
324 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
325 {
326         CAPTURE_FUNC_ENTRY();
327
328         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
329
330         _pthread_mutex_lock(&private_display->lock);
331
332         if (!func_capture->capture_set_info) {
333                 _pthread_mutex_unlock(&private_display->lock);
334                 TDM_DBG("failed: not implemented!!");
335                 return TDM_ERROR_NOT_IMPLEMENTED;
336         }
337
338         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
339         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
340
341         _pthread_mutex_unlock(&private_display->lock);
342
343         return ret;
344 }
345
346 EXTERN tdm_error
347 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
348 {
349         CAPTURE_FUNC_ENTRY();
350
351         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
352
353         _pthread_mutex_lock(&private_display->lock);
354
355         if (!func_capture->capture_attach) {
356                 _pthread_mutex_unlock(&private_display->lock);
357                 TDM_DBG("failed: not implemented!!");
358                 return TDM_ERROR_NOT_IMPLEMENTED;
359         }
360
361         ret = _tdm_capture_check_if_exist(private_capture, buffer);
362         if (ret != TDM_ERROR_NONE) {
363                 _pthread_mutex_unlock(&private_display->lock);
364                 return ret;
365         }
366
367         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
368         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
369
370         if (ret == TDM_ERROR_NONE) {
371                 tdm_buffer_info *buf_info;
372
373                 if ((buf_info = tdm_buffer_get_info(buffer)))
374                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
375
376                 if (tdm_debug_buffer) {
377                         TDM_INFO("capture(%p) attached:", private_capture);
378                         tdm_buffer_list_dump(&private_capture->buffer_list);
379                 }
380         }
381
382         _pthread_mutex_unlock(&private_display->lock);
383
384         return ret;
385 }
386
387 EXTERN tdm_error
388 tdm_capture_commit(tdm_capture *capture)
389 {
390         tdm_buffer_info *b = NULL, *bb = NULL;
391
392         CAPTURE_FUNC_ENTRY();
393
394         _pthread_mutex_lock(&private_display->lock);
395
396         if (!func_capture->capture_commit) {
397                 _pthread_mutex_unlock(&private_display->lock);
398                 TDM_DBG("failed: not implemented!!");
399                 return TDM_ERROR_NOT_IMPLEMENTED;
400         }
401
402         ret = func_capture->capture_commit(private_capture->capture_backend);
403         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
404
405         if (ret == TDM_ERROR_NONE) {
406                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
407                         LIST_DEL(&b->link);
408                         tdm_buffer_ref_backend(b->buffer);
409                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
410                 }
411         } else {
412                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
413                         LIST_DEL(&b->link);
414         }
415
416         _pthread_mutex_unlock(&private_display->lock);
417
418         return ret;
419 }