add tdm_pp_set_done_handler and tdm_capture_set_done_handler
[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, 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, unsigned long 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_in_millis();
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_in_millis();
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         _pthread_mutex_lock(&private_display->lock);
347
348         if (!func_capture->capture_set_info) {
349                 _pthread_mutex_unlock(&private_display->lock);
350                 TDM_DBG("failed: not implemented!!");
351                 return TDM_ERROR_NOT_IMPLEMENTED;
352         }
353
354         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
355         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
356
357         private_capture->info = *info;
358
359         _pthread_mutex_unlock(&private_display->lock);
360
361         return ret;
362 }
363
364 EXTERN tdm_error
365 tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
366 {
367         tdm_private_display *private_display;
368         tdm_private_capture *private_capture;
369         tdm_error ret = TDM_ERROR_NONE;
370
371         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER);
372
373         private_capture = (tdm_private_capture*)capture;
374         private_display = private_capture->private_display;
375
376         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
377
378         _pthread_mutex_lock(&private_display->lock);
379
380         private_capture->done_func = func;
381         private_capture->done_user_data = user_data;
382
383         _pthread_mutex_unlock(&private_display->lock);
384
385         return ret;
386 }
387
388 EXTERN tdm_error
389 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
390 {
391         CAPTURE_FUNC_ENTRY();
392
393         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
394
395         _pthread_mutex_lock(&private_display->lock);
396
397         if (!func_capture->capture_attach) {
398                 _pthread_mutex_unlock(&private_display->lock);
399                 TDM_DBG("failed: not implemented!!");
400                 return TDM_ERROR_NOT_IMPLEMENTED;
401         }
402
403         ret = _tdm_capture_check_if_exist(private_capture, buffer);
404         if (ret != TDM_ERROR_NONE) {
405                 _pthread_mutex_unlock(&private_display->lock);
406                 return ret;
407         }
408
409         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
410         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
411
412         if (ret == TDM_ERROR_NONE) {
413                 tdm_buffer_info *buf_info;
414
415                 if ((buf_info = tdm_buffer_get_info(buffer)))
416                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
417
418                 if (tdm_debug_module & TDM_DEBUG_BUFFER) {
419                         TDM_INFO("capture(%p) attached:", private_capture);
420                         tdm_buffer_list_dump(&private_capture->buffer_list);
421                 }
422         }
423
424         _pthread_mutex_unlock(&private_display->lock);
425
426         return ret;
427 }
428
429 EXTERN tdm_error
430 tdm_capture_commit(tdm_capture *capture)
431 {
432         tdm_buffer_info *b = NULL, *bb = NULL;
433         tdm_private_output *private_output;
434
435         CAPTURE_FUNC_ENTRY();
436
437         _pthread_mutex_lock(&private_display->lock);
438
439         private_output = private_capture->private_output;
440         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
441                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
442                                 tdm_dpms_str(private_output->current_dpms_value));
443                 _pthread_mutex_unlock(&private_display->lock);
444                 return TDM_ERROR_BAD_REQUEST;
445         }
446
447         if (!func_capture->capture_commit) {
448                 _pthread_mutex_unlock(&private_display->lock);
449                 TDM_DBG("failed: not implemented!!");
450                 return TDM_ERROR_NOT_IMPLEMENTED;
451         }
452
453         ret = func_capture->capture_commit(private_capture->capture_backend);
454         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
455
456         if (ret == TDM_ERROR_NONE) {
457                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
458                         LIST_DEL(&b->link);
459                         tdm_buffer_ref_backend(b->buffer);
460                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
461                 }
462         } else {
463                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
464                         LIST_DEL(&b->link);
465         }
466
467         _pthread_mutex_unlock(&private_display->lock);
468
469         return ret;
470 }