Revert "Revert "output: seperate output-status and output-dpms change""
[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_private.h"
41
42 #define CAPTURE_FUNC_ENTRY() \
43         tdm_func_capture *func_capture; \
44         tdm_private_display *private_display; \
45         tdm_private_module *private_module; \
46         tdm_private_capture *private_capture; \
47         tdm_error ret = TDM_ERROR_NONE; \
48         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER); \
49         private_capture = (tdm_private_capture*)capture; \
50         private_display = private_capture->private_display; \
51         private_module = private_capture->private_module; \
52         func_capture = &private_module->func_capture
53
54 static void
55 _tdm_capture_print_list(struct list_head *list)
56 {
57         tdm_capture_private_buffer *b = NULL;
58         char str[512], *p;
59         int len = sizeof(str);
60
61         TDM_RETURN_IF_FAIL(list != NULL);
62
63         p = str;
64         LIST_FOR_EACH_ENTRY(b, list, link) {
65                 if (len > 0) {
66                         int l = snprintf(p, len, " (%p)", b->buffer);
67                         p += l;
68                         len -= l;
69                 } else
70                         break;
71         }
72
73         TDM_INFO("\t %s", str);
74 }
75
76 static tdm_capture_private_buffer *
77 _tdm_capture_find_tbm_buffer(struct list_head *list, tbm_surface_h buffer)
78 {
79         tdm_capture_private_buffer *b = NULL, *bb = NULL;
80
81         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
82                 if (b->buffer == buffer)
83                         return b;
84         }
85
86         return NULL;
87 }
88
89 static tdm_capture_private_buffer *
90 _tdm_capture_find_buffer(struct list_head *list, tdm_capture_private_buffer *capture_buffer)
91 {
92         tdm_capture_private_buffer *b = NULL, *bb = NULL;
93
94         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
95                 if (b == capture_buffer)
96                         return b;
97         }
98
99         return NULL;
100 }
101
102 static void
103 _tdm_capture_thread_cb_done(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
104 {
105         tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done *)cb_base;
106         tdm_private_capture *private_capture = object;
107         tdm_capture_private_buffer *capture_buffer = NULL, *first_entry = NULL;
108         tbm_surface_h buffer;
109
110         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
111
112         assert(private_capture->owner_tid == syscall(SYS_gettid));
113
114         buffer = capture_done->buffer;
115
116         if (tdm_debug_dump & TDM_DUMP_FLAG_CAPTURE) {
117                 /* LCOV_EXCL_START */
118                 char str[TDM_PATH_LEN];
119                 static int i;
120                 snprintf(str, TDM_PATH_LEN, "capture_%03d", i++);
121                 tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str);
122                 /* LCOV_EXCL_STOP */
123         }
124
125         if (tdm_debug_module & TDM_DEBUG_BUFFER)
126                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
127
128         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
129                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, 0);
130                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
131         }
132
133         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
134                 first_entry = container_of((&private_capture->buffer_list)->next, capture_buffer, link);
135                 if (first_entry->buffer != buffer)
136                         TDM_ERR("buffer(%p) is skipped", first_entry->buffer);
137         } else {
138                 TDM_NEVER_GET_HERE();
139         }
140
141         if ((capture_buffer = _tdm_capture_find_tbm_buffer(&private_capture->buffer_list, buffer))) {
142                 LIST_DEL(&capture_buffer->link);
143                 LIST_DELINIT(&capture_buffer->commit_link);
144
145                 _pthread_mutex_unlock(&private_display->lock);
146                 if (private_capture->done_func)
147                         private_capture->done_func(capture_buffer, buffer, private_capture->done_user_data);
148                 tdm_buffer_unref_backend(buffer);
149                 _pthread_mutex_lock(&private_display->lock);
150
151                 free(capture_buffer);
152         }
153 }
154
155 static void
156 _tdm_capture_cb_done(tdm_capture *capture_module, tbm_surface_h buffer, void *user_data)
157 {
158         tdm_private_capture *private_capture = user_data;
159         tdm_thread_cb_capture_done capture_done;
160         tdm_error ret;
161
162         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
163
164         memset(&capture_done, 0, sizeof capture_done);
165         capture_done.base.type = TDM_THREAD_CB_CAPTURE_DONE;
166         capture_done.base.length = sizeof capture_done;
167         capture_done.base.object_stamp = private_capture->stamp;
168         capture_done.base.data = NULL;
169         capture_done.base.sync = 0;
170         capture_done.buffer = buffer;
171
172         ret = tdm_thread_cb_call(private_capture, &capture_done.base);
173         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
174 }
175
176 static void *
177 _tdm_capture_find_object(tdm_private_display *private_display, double stamp)
178 {
179         tdm_private_module *private_module = NULL;
180         tdm_private_capture *private_capture = NULL;
181
182         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
183
184         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
185                 LIST_FOR_EACH_ENTRY(private_capture, &private_module->capture_list, display_link) {
186                         if (private_capture->stamp == stamp)
187                                 return private_capture;
188                 }
189         }
190
191         return NULL;
192 }
193
194 INTERN tdm_error
195 tdm_capture_init(tdm_private_display *private_display)
196 {
197         tdm_thread_cb_set_find_func(TDM_THREAD_CB_CAPTURE_DONE, _tdm_capture_find_object);
198
199         return TDM_ERROR_NONE;
200 }
201
202 INTERN tdm_private_capture *
203 tdm_capture_create_output_internal(tdm_private_output *private_output,
204                                                                    tdm_error *error)
205 {
206         tdm_private_display *private_display = private_output->private_display;
207         tdm_private_module *private_module = private_output->private_module;
208         tdm_func_output *func_output = &private_module->func_output;
209         tdm_func_capture *func_capture = &private_module->func_capture;
210         tdm_private_capture *private_capture = NULL;
211         tdm_capture *capture_module = NULL;
212         tdm_error ret = TDM_ERROR_NONE;
213
214         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
215
216         if (!(private_module->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
217                 /* LCOV_EXCL_START */
218                 TDM_ERR("backend(%s) no capture capability", private_module->module_data->name);
219                 if (error)
220                         *error = TDM_ERROR_NO_CAPABILITY;
221                 return NULL;
222                 /* LCOV_EXCL_STOP */
223         }
224
225         if (!(private_module->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)) {
226                 /* LCOV_EXCL_START */
227                 TDM_ERR("backend(%s) no output capture capability", private_module->module_data->name);
228                 if (error)
229                         *error = TDM_ERROR_NO_CAPABILITY;
230                 return NULL;
231                 /* LCOV_EXCL_STOP */
232         }
233
234         capture_module = func_output->output_create_capture(
235                                                   private_output->output_backend, &ret);
236         if (ret != TDM_ERROR_NONE) {
237                 /* LCOV_EXCL_START */
238                 if (error)
239                         *error = ret;
240                 return NULL;
241                 /* LCOV_EXCL_STOP */
242         }
243
244         private_capture = calloc(1, sizeof(tdm_private_capture));
245         if (!private_capture) {
246                 /* LCOV_EXCL_START */
247                 TDM_ERR("failed: alloc memory");
248                 func_capture->capture_destroy(capture_module);
249                 if (error)
250                         *error = TDM_ERROR_OUT_OF_MEMORY;
251                 return NULL;
252                 /* LCOV_EXCL_STOP */
253         }
254
255         ret = tdm_thread_cb_add(private_capture, TDM_THREAD_CB_CAPTURE_DONE, NULL, _tdm_capture_thread_cb_done, NULL);
256         if (ret != TDM_ERROR_NONE) {
257                 TDM_ERR("capture tdm_thread_cb_add failed");
258                 func_capture->capture_destroy(capture_module);
259                 free(private_capture);
260                 if (error)
261                         *error = ret;
262                 return NULL;
263         }
264
265         ret = func_capture->capture_set_done_handler(capture_module, _tdm_capture_cb_done, private_capture);
266         if (ret != TDM_ERROR_NONE) {
267                 /* LCOV_EXCL_START */
268                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
269                 func_capture->capture_destroy(capture_module);
270                 free(private_capture);
271                 if (error)
272                         *error = ret;
273                 return NULL;
274                 /* LCOV_EXCL_STOP */
275         }
276
277         private_capture->stamp = tdm_helper_get_time();
278         while (_tdm_capture_find_object(private_display, private_capture->stamp))
279                 private_capture->stamp++;
280
281         LIST_ADD(&private_capture->link, &private_output->capture_list);
282         LIST_ADD(&private_capture->display_link, &private_module->capture_list);
283
284         private_capture->private_module = private_module;
285
286         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
287         private_capture->private_display = private_display;
288         private_capture->private_output = private_output;
289         private_capture->private_layer = NULL;
290         private_capture->capture_module = capture_module;
291         private_capture->owner_tid = syscall(SYS_gettid);
292
293         LIST_INITHEAD(&private_capture->pending_buffer_list);
294         LIST_INITHEAD(&private_capture->buffer_list);
295
296         TDM_DBG("capture(%p) create", private_capture);
297
298         if (error)
299                 *error = TDM_ERROR_NONE;
300
301         return private_capture;
302 }
303
304 /* LCOV_EXCL_START */
305 INTERN tdm_private_capture *
306 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
307                                                                   tdm_error *error)
308 {
309         tdm_private_output *private_output = private_layer->private_output;
310         tdm_private_module *private_module = private_layer->private_module;
311         tdm_private_display *private_display = private_output->private_display;
312         tdm_func_layer *func_layer = &private_module->func_layer;
313         tdm_func_capture *func_capture = &private_module->func_capture;
314         tdm_private_capture *private_capture = NULL;
315         tdm_capture *capture_module = NULL;
316         tdm_error ret = TDM_ERROR_NONE;
317
318         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
319
320         if (!(private_module->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
321                 TDM_ERR("backend(%s) no capture capability", private_module->module_data->name);
322                 if (error)
323                         *error = TDM_ERROR_NO_CAPABILITY;
324                 return NULL;
325         }
326
327         if (!(private_module->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)) {
328                 TDM_ERR("backend(%s) no layer capture capability", private_module->module_data->name);
329                 if (error)
330                         *error = TDM_ERROR_NO_CAPABILITY;
331                 return NULL;
332         }
333
334         capture_module = func_layer->layer_create_capture(private_layer->layer_backend,
335                                           &ret);
336         if (ret != TDM_ERROR_NONE)
337                 return NULL;
338
339         private_capture = calloc(1, sizeof(tdm_private_capture));
340         if (!private_capture) {
341                 TDM_ERR("failed: alloc memory");
342                 func_capture->capture_destroy(capture_module);
343                 if (error)
344                         *error = TDM_ERROR_OUT_OF_MEMORY;
345                 return NULL;
346         }
347
348         private_capture->stamp = tdm_helper_get_time();
349         while (_tdm_capture_find_object(private_display, private_capture->stamp))
350                 private_capture->stamp++;
351
352         LIST_ADD(&private_capture->link, &private_layer->capture_list);
353         LIST_ADD(&private_capture->display_link, &private_module->capture_list);
354
355         private_capture->private_module = private_module;
356
357         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
358         private_capture->private_display = private_display;
359         private_capture->private_output = private_output;
360         private_capture->private_layer = private_layer;
361         private_capture->capture_module = capture_module;
362         private_capture->owner_tid = syscall(SYS_gettid);
363
364         LIST_INITHEAD(&private_capture->pending_buffer_list);
365         LIST_INITHEAD(&private_capture->buffer_list);
366
367         TDM_DBG("capture(%p) create", private_capture);
368
369         if (error)
370                 *error = TDM_ERROR_NONE;
371
372         return private_capture;
373 }
374 /* LCOV_EXCL_STOP */
375
376 INTERN void
377 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
378 {
379         tdm_private_display *private_display;
380         tdm_private_module *private_module;
381         tdm_func_capture *func_capture;
382         tdm_capture_private_buffer *b = NULL, *bb = NULL;
383         struct list_head clone_list;
384
385         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
386
387         if (!private_capture)
388                 return;
389
390         private_display = private_capture->private_display;
391
392         tdm_thread_cb_remove(private_capture, TDM_THREAD_CB_CAPTURE_DONE, NULL, _tdm_capture_thread_cb_done, NULL);
393
394         LIST_DEL(&private_capture->link);
395         LIST_DEL(&private_capture->display_link);
396
397         private_module = private_capture->private_module;
398         func_capture = &private_module->func_capture;
399         func_capture->capture_destroy(private_capture->capture_module);
400
401         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
402                 TDM_WRN("capture(%p) not finished:", private_capture);
403                 _tdm_capture_print_list(&private_capture->pending_buffer_list);
404
405                 LIST_INITHEAD(&clone_list);
406                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
407                         LIST_DEL(&b->link);
408                         LIST_ADDTAIL(&b->link, &clone_list);
409                 }
410
411                 _pthread_mutex_unlock(&private_display->lock);
412                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
413                         LIST_DEL(&b->link);
414
415                         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
416                                 tbm_bo bo = tbm_surface_internal_get_bo(b->buffer, 0);
417                                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
418                         }
419
420                         tdm_buffer_unref_backend(b->buffer);
421                         free(b);
422                 }
423                 _pthread_mutex_lock(&private_display->lock);
424         }
425
426         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
427                 TDM_WRN("capture(%p) not finished:", private_capture);
428                 _tdm_capture_print_list(&private_capture->buffer_list);
429
430                 LIST_INITHEAD(&clone_list);
431                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
432                         LIST_DEL(&b->link);
433                         LIST_ADDTAIL(&b->link, &clone_list);
434                 }
435
436                 _pthread_mutex_unlock(&private_display->lock);
437                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
438                         LIST_DEL(&b->link);
439
440                         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
441                                 tbm_bo bo = tbm_surface_internal_get_bo(b->buffer, 0);
442                                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
443                         }
444
445                         tdm_buffer_unref_backend(b->buffer);
446                         free(b);
447                 }
448                 _pthread_mutex_lock(&private_display->lock);
449         }
450
451         private_capture->stamp = 0;
452         free(private_capture);
453 }
454
455 EXTERN void
456 tdm_capture_destroy(tdm_capture *capture)
457 {
458         tdm_private_capture *private_capture = capture;
459         tdm_private_display *private_display;
460
461         if (!private_capture)
462                 return;
463
464         TDM_DBG("capture(%p) destroy", private_capture);
465
466         private_display = private_capture->private_display;
467
468         _pthread_mutex_lock(&private_display->lock);
469         tdm_capture_destroy_internal(private_capture);
470         _pthread_mutex_unlock(&private_display->lock);
471 }
472
473 EXTERN tdm_error
474 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
475 {
476         CAPTURE_FUNC_ENTRY();
477
478         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
479         TDM_RETURN_VAL_IF_FAIL(info->type != 0, TDM_ERROR_INVALID_PARAMETER);
480
481         _pthread_mutex_lock(&private_display->lock);
482
483         if (!func_capture->capture_set_info) {
484                 /* LCOV_EXCL_START */
485                 _pthread_mutex_unlock(&private_display->lock);
486                 TDM_DBG("failed: not implemented!!");
487                 return TDM_ERROR_NOT_IMPLEMENTED;
488                 /* LCOV_EXCL_STOP */
489         }
490
491         if (info->type == TDM_CAPTURE_TYPE_STREAM && info->frequency == 0) {
492                 tdm_private_output *private_output = private_capture->private_output;
493                 info->frequency = private_output->current_mode->vrefresh;
494         }
495
496         TDM_INFO("capture(%p) info: dst(%ux%u %u,%u %ux%u %c%c%c%c) trans(%d) type(%d) freq(%d) flags(%x)",
497                          private_capture,
498                          info->dst_config.size.h, info->dst_config.size.v,
499                          info->dst_config.pos.x, info->dst_config.pos.y,
500                          info->dst_config.pos.w, info->dst_config.pos.h,
501                          FOURCC_STR(info->dst_config.format),
502                          info->transform, info->type, info->frequency, info->flags);
503
504         ret = func_capture->capture_set_info(private_capture->capture_module, info);
505         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
506
507         private_capture->info = *info;
508
509         _pthread_mutex_unlock(&private_display->lock);
510
511         return ret;
512 }
513
514 EXTERN tdm_error
515 tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
516 {
517         tdm_private_display *private_display;
518         tdm_private_capture *private_capture;
519         tdm_error ret = TDM_ERROR_NONE;
520
521         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER);
522
523         private_capture = (tdm_private_capture*)capture;
524         private_display = private_capture->private_display;
525
526         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
527
528         _pthread_mutex_lock(&private_display->lock);
529
530         private_capture->done_func = func;
531         private_capture->done_user_data = user_data;
532
533         _pthread_mutex_unlock(&private_display->lock);
534
535         return ret;
536 }
537
538 EXTERN tdm_error
539 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
540 {
541         tdm_capture_private_buffer *capture_buffer;
542
543         CAPTURE_FUNC_ENTRY();
544
545         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
546
547         _pthread_mutex_lock(&private_display->lock);
548
549         if (!func_capture->capture_attach) {
550                 /* LCOV_EXCL_START */
551                 _pthread_mutex_unlock(&private_display->lock);
552                 TDM_DBG("failed: not implemented!!");
553                 return TDM_ERROR_NOT_IMPLEMENTED;
554                 /* LCOV_EXCL_STOP */
555         }
556
557         if (tdm_module_check_abi(private_module, 1, 2) &&
558                 private_module->caps_capture.max_attach_count > 0) {
559                 /* LCOV_EXCL_START */
560                 int length = LIST_LENGTH(&private_capture->pending_buffer_list) +
561                                          LIST_LENGTH(&private_capture->buffer_list);
562                 if (length >= private_module->caps_capture.max_attach_count) {
563                         _pthread_mutex_unlock(&private_display->lock);
564                         TDM_DBG("failed: backend(%s) too many attached!! max_attach_count(%d)",
565                                         private_module->module_data->name, private_module->caps_capture.max_attach_count);
566                         return TDM_ERROR_BAD_REQUEST;
567                 }
568                 /* LCOV_EXCL_STOP */
569         }
570
571         capture_buffer = calloc(1, sizeof * capture_buffer);
572         if (!capture_buffer) {
573                 /* LCOV_EXCL_START */
574                 _pthread_mutex_unlock(&private_display->lock);
575                 TDM_ERR("alloc failed");
576                 return TDM_ERROR_OUT_OF_MEMORY;
577                 /* LCOV_EXCL_STOP */
578         }
579
580         ret = func_capture->capture_attach(private_capture->capture_module, buffer);
581         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
582
583         if (ret != TDM_ERROR_NONE) {
584                 /* LCOV_EXCL_START */
585                 free(capture_buffer);
586                 _pthread_mutex_unlock(&private_display->lock);
587                 TDM_ERR("attach failed");
588                 return ret;
589                 /* LCOV_EXCL_STOP */
590         }
591
592         LIST_ADDTAIL(&capture_buffer->link, &private_capture->pending_buffer_list);
593         capture_buffer->buffer = tdm_buffer_ref_backend(buffer);
594
595         if (tdm_debug_module & TDM_DEBUG_BUFFER) {
596                 TDM_INFO("capture(%p) attached:", private_capture);
597                 _tdm_capture_print_list(&private_capture->buffer_list);
598         }
599
600         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
601                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, 0);
602                 TDM_TRACE_ASYNC_BEGIN((intptr_t)capture, "[CAPTURE] %d", tbm_bo_export(bo));
603         }
604
605         _pthread_mutex_unlock(&private_display->lock);
606
607         return ret;
608 }
609
610 EXTERN tdm_error
611 tdm_capture_commit(tdm_capture *capture)
612 {
613         tdm_capture_private_buffer *b = NULL, *bb = NULL;
614         tdm_private_output *private_output;
615         struct list_head commit_buffer_list;
616
617         CAPTURE_FUNC_ENTRY();
618
619         _pthread_mutex_lock(&private_display->lock);
620
621         private_output = private_capture->private_output;
622
623         /* TODO: possible when standby mode? can't decide it yet. no scenario. */
624         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
625                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
626                                 tdm_dpms_str(private_output->current_dpms_value));
627                 _pthread_mutex_unlock(&private_display->lock);
628                 return TDM_ERROR_BAD_REQUEST;
629         }
630
631         if (!func_capture->capture_commit) {
632                 /* LCOV_EXCL_START */
633                 _pthread_mutex_unlock(&private_display->lock);
634                 TDM_DBG("failed: not implemented!!");
635                 return TDM_ERROR_NOT_IMPLEMENTED;
636                 /* LCOV_EXCL_STOP */
637         }
638
639         LIST_INITHEAD(&commit_buffer_list);
640
641         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
642                 LIST_DEL(&b->link);
643                 LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
644                 LIST_ADDTAIL(&b->commit_link, &commit_buffer_list);
645         }
646
647         ret = func_capture->capture_commit(private_capture->capture_module);
648         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
649
650         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &commit_buffer_list, commit_link) {
651                 LIST_DELINIT(&b->commit_link);
652
653                 if (!_tdm_capture_find_buffer(&private_capture->buffer_list, b))
654                         continue;
655
656                 if (ret != TDM_ERROR_NONE) {
657                         /* LCOV_EXCL_START */
658                         /* Not to call the user release handler when failed.
659                          * Do we have to call this function here really?
660                          * User better use set_done_handler to know when pp is done. Using
661                          * buffer_release_handler is not good.
662                          */
663                         tdm_buffer_remove_release_handler_internal(b->buffer);
664
665                         _pthread_mutex_unlock(&private_display->lock);
666                         tdm_buffer_unref_backend(b->buffer);
667                         _pthread_mutex_lock(&private_display->lock);
668                         LIST_DEL(&b->link);
669
670                         free(b);
671                         /* LCOV_EXCL_STOP */
672                 }
673         }
674
675         _pthread_mutex_unlock(&private_display->lock);
676
677         return ret;
678 }