check the size limitation
[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         capture_backend = func_output->output_create_capture(
168                                                   private_output->output_backend, &ret);
169         if (ret != TDM_ERROR_NONE) {
170                 if (error)
171                         *error = ret;
172                 return NULL;
173         }
174
175         private_capture = calloc(1, sizeof(tdm_private_capture));
176         if (!private_capture) {
177                 TDM_ERR("failed: alloc memory");
178                 func_capture->capture_destroy(capture_backend);
179                 if (error)
180                         *error = TDM_ERROR_OUT_OF_MEMORY;
181                 return NULL;
182         }
183
184         ret = func_capture->capture_set_done_handler(capture_backend,
185                         tdm_capture_cb_done, private_capture);
186         if (ret != TDM_ERROR_NONE) {
187                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
188                 func_capture->capture_destroy(capture_backend);
189                 if (error)
190                         *error = ret;
191                 return NULL;
192         }
193
194         private_capture->stamp = tdm_helper_get_time();
195         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
196                 private_capture->stamp++;
197
198         LIST_ADD(&private_capture->link, &private_output->capture_list);
199         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
200
201         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
202         private_capture->private_display = private_display;
203         private_capture->private_output = private_output;
204         private_capture->private_layer = NULL;
205         private_capture->capture_backend = capture_backend;
206         private_capture->owner_tid = syscall(SYS_gettid);
207
208         LIST_INITHEAD(&private_capture->pending_buffer_list);
209         LIST_INITHEAD(&private_capture->buffer_list);
210
211         if (error)
212                 *error = TDM_ERROR_NONE;
213
214         return private_capture;
215 }
216
217 INTERN tdm_private_capture *
218 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
219                                                                   tdm_error *error)
220 {
221         tdm_private_output *private_output = private_layer->private_output;
222         tdm_private_display *private_display = private_output->private_display;
223         tdm_func_layer *func_layer = &private_display->func_layer;
224         tdm_func_capture *func_capture = &private_display->func_capture;
225         tdm_private_capture *private_capture = NULL;
226         tdm_capture *capture_backend = NULL;
227         tdm_error ret = TDM_ERROR_NONE;
228
229         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
230
231         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
232                 TDM_ERR("no capture capability");
233                 if (error)
234                         *error = TDM_ERROR_NO_CAPABILITY;
235                 return NULL;
236         }
237
238         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
239                                           &ret);
240         if (ret != TDM_ERROR_NONE)
241                 return NULL;
242
243         private_capture = calloc(1, sizeof(tdm_private_capture));
244         if (!private_capture) {
245                 TDM_ERR("failed: alloc memory");
246                 func_capture->capture_destroy(capture_backend);
247                 if (error)
248                         *error = TDM_ERROR_OUT_OF_MEMORY;
249                 return NULL;
250         }
251
252         private_capture->stamp = tdm_helper_get_time();
253         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
254                 private_capture->stamp++;
255
256         LIST_ADD(&private_capture->link, &private_layer->capture_list);
257         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
258
259         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
260         private_capture->private_display = private_display;
261         private_capture->private_output = private_output;
262         private_capture->private_layer = private_layer;
263         private_capture->capture_backend = capture_backend;
264         private_capture->owner_tid = syscall(SYS_gettid);
265
266         LIST_INITHEAD(&private_capture->pending_buffer_list);
267         LIST_INITHEAD(&private_capture->buffer_list);
268
269         if (error)
270                 *error = TDM_ERROR_NONE;
271
272         return private_capture;
273 }
274
275 INTERN void
276 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
277 {
278         tdm_private_display *private_display;
279         tdm_func_capture *func_capture;
280         tdm_buffer_info *b = NULL, *bb = NULL;
281
282         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
283
284         if (!private_capture)
285                 return;
286
287         private_display = private_capture->private_display;
288
289         LIST_DEL(&private_capture->link);
290         LIST_DEL(&private_capture->display_link);
291
292         func_capture = &private_capture->private_display->func_capture;
293         func_capture->capture_destroy(private_capture->capture_backend);
294
295         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
296                 TDM_WRN("capture(%p) not finished:", private_capture);
297                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
298
299                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
300                         LIST_DEL(&b->link);
301                         _pthread_mutex_unlock(&private_display->lock);
302                         tdm_buffer_unref_backend(b->buffer);
303                         _pthread_mutex_lock(&private_display->lock);
304                 }
305         }
306
307         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
308                 TDM_WRN("capture(%p) not finished:", private_capture);
309                 tdm_buffer_list_dump(&private_capture->buffer_list);
310
311                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
312                         LIST_DEL(&b->link);
313                         _pthread_mutex_unlock(&private_display->lock);
314                         tdm_buffer_unref_backend(b->buffer);
315                         _pthread_mutex_lock(&private_display->lock);
316                 }
317         }
318
319         private_capture->stamp = 0;
320         free(private_capture);
321 }
322
323 EXTERN void
324 tdm_capture_destroy(tdm_capture *capture)
325 {
326         tdm_private_capture *private_capture = capture;
327         tdm_private_display *private_display;
328
329         if (!private_capture)
330                 return;
331
332         private_display = private_capture->private_display;
333
334         _pthread_mutex_lock(&private_display->lock);
335         tdm_capture_destroy_internal(private_capture);
336         _pthread_mutex_unlock(&private_display->lock);
337 }
338
339 EXTERN tdm_error
340 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
341 {
342         CAPTURE_FUNC_ENTRY();
343
344         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
345
346         if (private_display->caps_capture.min_w > 0) {
347                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.size.h >= private_display->caps_capture.min_w, TDM_ERROR_INVALID_PARAMETER);
348                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.pos.w >= private_display->caps_capture.min_w, TDM_ERROR_INVALID_PARAMETER);
349         }
350         if (private_display->caps_capture.min_h > 0) {
351                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.size.v >= private_display->caps_capture.min_h, TDM_ERROR_INVALID_PARAMETER);
352                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.pos.h >= private_display->caps_capture.min_h, TDM_ERROR_INVALID_PARAMETER);
353         }
354         if (private_display->caps_capture.max_w > 0) {
355                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.size.h <= private_display->caps_capture.max_w, TDM_ERROR_INVALID_PARAMETER);
356                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.pos.w <= private_display->caps_capture.max_w, TDM_ERROR_INVALID_PARAMETER);
357         }
358         if (private_display->caps_capture.max_h > 0) {
359                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.size.v <= private_display->caps_capture.max_h, TDM_ERROR_INVALID_PARAMETER);
360                 TDM_RETURN_VAL_IF_FAIL(info->dst_config.pos.h <= private_display->caps_capture.max_h, TDM_ERROR_INVALID_PARAMETER);
361         }
362
363         _pthread_mutex_lock(&private_display->lock);
364
365         if (!func_capture->capture_set_info) {
366                 _pthread_mutex_unlock(&private_display->lock);
367                 TDM_DBG("failed: not implemented!!");
368                 return TDM_ERROR_NOT_IMPLEMENTED;
369         }
370
371         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
372         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
373
374         private_capture->info = *info;
375
376         _pthread_mutex_unlock(&private_display->lock);
377
378         return ret;
379 }
380
381 EXTERN tdm_error
382 tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
383 {
384         tdm_private_display *private_display;
385         tdm_private_capture *private_capture;
386         tdm_error ret = TDM_ERROR_NONE;
387
388         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER);
389
390         private_capture = (tdm_private_capture*)capture;
391         private_display = private_capture->private_display;
392
393         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
394
395         _pthread_mutex_lock(&private_display->lock);
396
397         private_capture->done_func = func;
398         private_capture->done_user_data = user_data;
399
400         _pthread_mutex_unlock(&private_display->lock);
401
402         return ret;
403 }
404
405 EXTERN tdm_error
406 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
407 {
408         CAPTURE_FUNC_ENTRY();
409
410         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
411
412         _pthread_mutex_lock(&private_display->lock);
413
414         if (!func_capture->capture_attach) {
415                 _pthread_mutex_unlock(&private_display->lock);
416                 TDM_DBG("failed: not implemented!!");
417                 return TDM_ERROR_NOT_IMPLEMENTED;
418         }
419
420         ret = _tdm_capture_check_if_exist(private_capture, buffer);
421         if (ret != TDM_ERROR_NONE) {
422                 _pthread_mutex_unlock(&private_display->lock);
423                 return ret;
424         }
425
426         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
427         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
428
429         if (ret == TDM_ERROR_NONE) {
430                 tdm_buffer_info *buf_info;
431
432                 if ((buf_info = tdm_buffer_get_info(buffer)))
433                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
434
435                 if (tdm_debug_module & TDM_DEBUG_BUFFER) {
436                         TDM_INFO("capture(%p) attached:", private_capture);
437                         tdm_buffer_list_dump(&private_capture->buffer_list);
438                 }
439         }
440
441         _pthread_mutex_unlock(&private_display->lock);
442
443         return ret;
444 }
445
446 EXTERN tdm_error
447 tdm_capture_commit(tdm_capture *capture)
448 {
449         tdm_buffer_info *b = NULL, *bb = NULL;
450         tdm_private_output *private_output;
451
452         CAPTURE_FUNC_ENTRY();
453
454         _pthread_mutex_lock(&private_display->lock);
455
456         private_output = private_capture->private_output;
457         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
458                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
459                                 tdm_dpms_str(private_output->current_dpms_value));
460                 _pthread_mutex_unlock(&private_display->lock);
461                 return TDM_ERROR_BAD_REQUEST;
462         }
463
464         if (!func_capture->capture_commit) {
465                 _pthread_mutex_unlock(&private_display->lock);
466                 TDM_DBG("failed: not implemented!!");
467                 return TDM_ERROR_NOT_IMPLEMENTED;
468         }
469
470         ret = func_capture->capture_commit(private_capture->capture_backend);
471         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
472
473         if (ret == TDM_ERROR_NONE) {
474                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
475                         LIST_DEL(&b->link);
476                         tdm_buffer_ref_backend(b->buffer);
477                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
478                 }
479         } else {
480                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
481                         LIST_DEL(&b->link);
482         }
483
484         _pthread_mutex_unlock(&private_display->lock);
485
486         return ret;
487 }