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