check capture capability
[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 #include "tdm_helper.h"
44
45 #define CAPTURE_FUNC_ENTRY() \
46         tdm_func_capture *func_capture; \
47         tdm_private_display *private_display; \
48         tdm_private_capture *private_capture; \
49         tdm_error ret = TDM_ERROR_NONE; \
50         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER); \
51         private_capture = (tdm_private_capture*)capture; \
52         private_display = private_capture->private_display; \
53         func_capture = &private_display->func_capture
54
55 static tdm_error
56 _tdm_capture_check_if_exist(tdm_private_capture *private_capture,
57                                                         tbm_surface_h buffer)
58 {
59         tdm_buffer_info *buf_info = NULL;
60
61         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->buffer_list, link) {
62                 if (buf_info->buffer == buffer) {
63                         TDM_ERR("%p attached twice", buffer);
64                         return TDM_ERROR_BAD_REQUEST;
65                 }
66         }
67
68         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->pending_buffer_list, link) {
69                 if (buf_info->buffer == buffer) {
70                         TDM_ERR("%p attached twice", buffer);
71                         return TDM_ERROR_BAD_REQUEST;
72                 }
73         }
74
75         return TDM_ERROR_NONE;
76 }
77
78 INTERN void
79 tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
80                                         void *user_data)
81 {
82         tdm_private_capture *private_capture = user_data;
83         tdm_private_display *private_display = private_capture->private_display;
84         tdm_buffer_info *buf_info;
85         tbm_surface_h first_entry;
86
87         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
88
89         if (private_capture->owner_tid != syscall(SYS_gettid)) {
90                 tdm_thread_cb_capture_done capture_done;
91                 tdm_error ret;
92
93                 capture_done.base.type = TDM_THREAD_CB_PP_DONE;
94                 capture_done.base.length = sizeof capture_done;
95                 capture_done.capture_stamp = private_capture->stamp;
96                 capture_done.buffer = buffer;
97                 capture_done.user_data = user_data;
98
99                 ret = tdm_thread_send_cb(private_display->private_loop, &capture_done.base);
100                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
101
102                 return;
103         }
104
105         if (private_capture->owner_tid != syscall(SYS_gettid))
106                 TDM_NEVER_GET_HERE();
107
108         if (tdm_debug_dump & TDM_DUMP_FLAG_CAPTURE) {
109                 char str[TDM_PATH_LEN];
110                 static int i;
111                 snprintf(str, TDM_PATH_LEN, "capture_%03d", i++);
112                 tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str);
113         }
114
115         if (tdm_debug_module & TDM_DEBUG_BUFFER)
116                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
117
118         first_entry = tdm_buffer_list_get_first_entry(&private_capture->buffer_list);
119         if (first_entry != buffer)
120                 TDM_ERR("%p is skipped", first_entry);
121
122         if ((buf_info = tdm_buffer_get_info(buffer)))
123                 LIST_DEL(&buf_info->link);
124
125         _pthread_mutex_unlock(&private_display->lock);
126         if (private_capture->done_func)
127                 private_capture->done_func(private_capture, buffer, private_capture->done_user_data);
128         tdm_buffer_unref_backend(buffer);
129         _pthread_mutex_lock(&private_display->lock);
130 }
131
132 INTERN tdm_private_capture *
133 tdm_capture_find_stamp(tdm_private_display *private_display, double stamp)
134 {
135         tdm_private_capture *private_capture = NULL;
136
137         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
138
139         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
140                 if (private_capture->stamp == stamp)
141                         return private_capture;
142         }
143
144         return NULL;
145 }
146
147 INTERN tdm_private_capture *
148 tdm_capture_create_output_internal(tdm_private_output *private_output,
149                                                                    tdm_error *error)
150 {
151         tdm_private_display *private_display = private_output->private_display;
152         tdm_func_output *func_output = &private_display->func_output;
153         tdm_func_capture *func_capture = &private_display->func_capture;
154         tdm_private_capture *private_capture = NULL;
155         tdm_capture *capture_backend = NULL;
156         tdm_error ret = TDM_ERROR_NONE;
157
158         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
159
160         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
161                 TDM_ERR("no capture capability");
162                 if (error)
163                         *error = TDM_ERROR_NO_CAPABILITY;
164                 return NULL;
165         }
166
167         if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)) {
168                 TDM_ERR("no output capture capability");
169                 if (error)
170                         *error = TDM_ERROR_NO_CAPABILITY;
171                 return NULL;
172         }
173
174         capture_backend = func_output->output_create_capture(
175                                                   private_output->output_backend, &ret);
176         if (ret != TDM_ERROR_NONE) {
177                 if (error)
178                         *error = ret;
179                 return NULL;
180         }
181
182         private_capture = calloc(1, sizeof(tdm_private_capture));
183         if (!private_capture) {
184                 TDM_ERR("failed: alloc memory");
185                 func_capture->capture_destroy(capture_backend);
186                 if (error)
187                         *error = TDM_ERROR_OUT_OF_MEMORY;
188                 return NULL;
189         }
190
191         ret = func_capture->capture_set_done_handler(capture_backend,
192                         tdm_capture_cb_done, private_capture);
193         if (ret != TDM_ERROR_NONE) {
194                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
195                 func_capture->capture_destroy(capture_backend);
196                 if (error)
197                         *error = ret;
198                 return NULL;
199         }
200
201         private_capture->stamp = tdm_helper_get_time();
202         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
203                 private_capture->stamp++;
204
205         LIST_ADD(&private_capture->link, &private_output->capture_list);
206         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
207
208         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
209         private_capture->private_display = private_display;
210         private_capture->private_output = private_output;
211         private_capture->private_layer = NULL;
212         private_capture->capture_backend = capture_backend;
213         private_capture->owner_tid = syscall(SYS_gettid);
214
215         LIST_INITHEAD(&private_capture->pending_buffer_list);
216         LIST_INITHEAD(&private_capture->buffer_list);
217
218         if (error)
219                 *error = TDM_ERROR_NONE;
220
221         return private_capture;
222 }
223
224 INTERN tdm_private_capture *
225 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
226                                                                   tdm_error *error)
227 {
228         tdm_private_output *private_output = private_layer->private_output;
229         tdm_private_display *private_display = private_output->private_display;
230         tdm_func_layer *func_layer = &private_display->func_layer;
231         tdm_func_capture *func_capture = &private_display->func_capture;
232         tdm_private_capture *private_capture = NULL;
233         tdm_capture *capture_backend = NULL;
234         tdm_error ret = TDM_ERROR_NONE;
235
236         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
237
238         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
239                 TDM_ERR("no capture capability");
240                 if (error)
241                         *error = TDM_ERROR_NO_CAPABILITY;
242                 return NULL;
243         }
244
245         if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)) {
246                 TDM_ERR("no layer capture capability");
247                 if (error)
248                         *error = TDM_ERROR_NO_CAPABILITY;
249                 return NULL;
250         }
251
252         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
253                                           &ret);
254         if (ret != TDM_ERROR_NONE)
255                 return NULL;
256
257         private_capture = calloc(1, sizeof(tdm_private_capture));
258         if (!private_capture) {
259                 TDM_ERR("failed: alloc memory");
260                 func_capture->capture_destroy(capture_backend);
261                 if (error)
262                         *error = TDM_ERROR_OUT_OF_MEMORY;
263                 return NULL;
264         }
265
266         private_capture->stamp = tdm_helper_get_time();
267         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
268                 private_capture->stamp++;
269
270         LIST_ADD(&private_capture->link, &private_layer->capture_list);
271         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
272
273         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
274         private_capture->private_display = private_display;
275         private_capture->private_output = private_output;
276         private_capture->private_layer = private_layer;
277         private_capture->capture_backend = capture_backend;
278         private_capture->owner_tid = syscall(SYS_gettid);
279
280         LIST_INITHEAD(&private_capture->pending_buffer_list);
281         LIST_INITHEAD(&private_capture->buffer_list);
282
283         if (error)
284                 *error = TDM_ERROR_NONE;
285
286         return private_capture;
287 }
288
289 INTERN void
290 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
291 {
292         tdm_private_display *private_display;
293         tdm_func_capture *func_capture;
294         tdm_buffer_info *b = NULL, *bb = NULL;
295
296         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
297
298         if (!private_capture)
299                 return;
300
301         private_display = private_capture->private_display;
302
303         LIST_DEL(&private_capture->link);
304         LIST_DEL(&private_capture->display_link);
305
306         func_capture = &private_capture->private_display->func_capture;
307         func_capture->capture_destroy(private_capture->capture_backend);
308
309         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
310                 TDM_WRN("capture(%p) not finished:", private_capture);
311                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
312
313                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
314                         LIST_DEL(&b->link);
315                         _pthread_mutex_unlock(&private_display->lock);
316                         tdm_buffer_unref_backend(b->buffer);
317                         _pthread_mutex_lock(&private_display->lock);
318                 }
319         }
320
321         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
322                 TDM_WRN("capture(%p) not finished:", private_capture);
323                 tdm_buffer_list_dump(&private_capture->buffer_list);
324
325                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
326                         LIST_DEL(&b->link);
327                         _pthread_mutex_unlock(&private_display->lock);
328                         tdm_buffer_unref_backend(b->buffer);
329                         _pthread_mutex_lock(&private_display->lock);
330                 }
331         }
332
333         private_capture->stamp = 0;
334         free(private_capture);
335 }
336
337 EXTERN void
338 tdm_capture_destroy(tdm_capture *capture)
339 {
340         tdm_private_capture *private_capture = capture;
341         tdm_private_display *private_display;
342
343         if (!private_capture)
344                 return;
345
346         private_display = private_capture->private_display;
347
348         _pthread_mutex_lock(&private_display->lock);
349         tdm_capture_destroy_internal(private_capture);
350         _pthread_mutex_unlock(&private_display->lock);
351 }
352
353 EXTERN tdm_error
354 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
355 {
356         CAPTURE_FUNC_ENTRY();
357
358         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
359
360         _pthread_mutex_lock(&private_display->lock);
361
362         if (!func_capture->capture_set_info) {
363                 _pthread_mutex_unlock(&private_display->lock);
364                 TDM_DBG("failed: not implemented!!");
365                 return TDM_ERROR_NOT_IMPLEMENTED;
366         }
367
368         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
369         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
370
371         private_capture->info = *info;
372
373         _pthread_mutex_unlock(&private_display->lock);
374
375         return ret;
376 }
377
378 EXTERN tdm_error
379 tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
380 {
381         tdm_private_display *private_display;
382         tdm_private_capture *private_capture;
383         tdm_error ret = TDM_ERROR_NONE;
384
385         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER);
386
387         private_capture = (tdm_private_capture*)capture;
388         private_display = private_capture->private_display;
389
390         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
391
392         _pthread_mutex_lock(&private_display->lock);
393
394         private_capture->done_func = func;
395         private_capture->done_user_data = user_data;
396
397         _pthread_mutex_unlock(&private_display->lock);
398
399         return ret;
400 }
401
402 EXTERN tdm_error
403 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
404 {
405         CAPTURE_FUNC_ENTRY();
406
407         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
408
409         _pthread_mutex_lock(&private_display->lock);
410
411         if (!func_capture->capture_attach) {
412                 _pthread_mutex_unlock(&private_display->lock);
413                 TDM_DBG("failed: not implemented!!");
414                 return TDM_ERROR_NOT_IMPLEMENTED;
415         }
416
417         ret = _tdm_capture_check_if_exist(private_capture, buffer);
418         if (ret != TDM_ERROR_NONE) {
419                 _pthread_mutex_unlock(&private_display->lock);
420                 return ret;
421         }
422
423         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
424         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
425
426         if (ret == TDM_ERROR_NONE) {
427                 tdm_buffer_info *buf_info;
428
429                 if ((buf_info = tdm_buffer_get_info(buffer)))
430                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
431
432                 if (tdm_debug_module & TDM_DEBUG_BUFFER) {
433                         TDM_INFO("capture(%p) attached:", private_capture);
434                         tdm_buffer_list_dump(&private_capture->buffer_list);
435                 }
436         }
437
438         _pthread_mutex_unlock(&private_display->lock);
439
440         return ret;
441 }
442
443 EXTERN tdm_error
444 tdm_capture_commit(tdm_capture *capture)
445 {
446         tdm_buffer_info *b = NULL, *bb = NULL;
447         tdm_private_output *private_output;
448
449         CAPTURE_FUNC_ENTRY();
450
451         _pthread_mutex_lock(&private_display->lock);
452
453         private_output = private_capture->private_output;
454         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
455                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
456                                 tdm_dpms_str(private_output->current_dpms_value));
457                 _pthread_mutex_unlock(&private_display->lock);
458                 return TDM_ERROR_BAD_REQUEST;
459         }
460
461         if (!func_capture->capture_commit) {
462                 _pthread_mutex_unlock(&private_display->lock);
463                 TDM_DBG("failed: not implemented!!");
464                 return TDM_ERROR_NOT_IMPLEMENTED;
465         }
466
467         ret = func_capture->capture_commit(private_capture->capture_backend);
468         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
469
470         if (ret == TDM_ERROR_NONE) {
471                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
472                         LIST_DEL(&b->link);
473                         tdm_buffer_ref_backend(b->buffer);
474                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
475                 }
476         } else {
477                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
478                         LIST_DEL(&b->link);
479         }
480
481         _pthread_mutex_unlock(&private_display->lock);
482
483         return ret;
484 }