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