ea3f5f04ff396217a478955cb02027f13dd2dcd0
[platform/core/uifw/libtdm.git] / src / tdm_pp.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 <boram1288.park@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 PP_FUNC_ENTRY() \
43         tdm_private_module *private_module; \
44         tdm_func_pp *func_pp; \
45         tdm_private_display *private_display; \
46         tdm_private_pp *private_pp; \
47         tdm_error ret = TDM_ERROR_NONE; \
48         TDM_RETURN_VAL_IF_FAIL(pp != NULL, TDM_ERROR_INVALID_PARAMETER); \
49         private_pp = (tdm_private_pp*)pp; \
50         private_display = private_pp->private_display; \
51         private_module = private_pp->private_module; \
52         func_pp = &private_module->func_pp
53
54 static void
55 _tdm_pp_print_list(struct list_head *list)
56 {
57         tdm_pp_private_buffer *b = NULL;
58         char str[512], *p;
59         int len = sizeof(str);
60
61         TDM_RETURN_IF_FAIL(list != NULL);
62
63         str[0] = '\0';
64         p = str;
65         LIST_FOR_EACH_ENTRY(b, list, link) {
66                 if (len > 0) {
67                         tbm_bo src_bo = tbm_surface_internal_get_bo(b->src, 0);
68                         tbm_bo dst_bo = tbm_surface_internal_get_bo(b->dst, 0);
69                         int src_flags = tbm_bo_get_flags(src_bo);
70                         int dst_flags = tbm_bo_get_flags(dst_bo);
71                         int l = snprintf(p, len, " (%p[bo_flags:%x], %p[bo_flags:%x])",
72                                                          b->src, src_flags, b->dst, dst_flags);
73                         p += l;
74                         len -= l;
75                 } else
76                         break;
77         }
78
79         TDM_INFO("\t %s", str);
80 }
81
82 static tdm_pp_private_buffer *
83 _tdm_pp_find_tbm_buffers(struct list_head *list, tbm_surface_h src, tbm_surface_h dst)
84 {
85         tdm_pp_private_buffer *b = NULL, *bb = NULL;
86
87         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
88                 if (b->src == src && b->dst == dst)
89                         return b;
90         }
91
92         return NULL;
93 }
94
95 static tdm_pp_private_buffer *
96 _tdm_pp_find_buffer(struct list_head *list, tdm_pp_private_buffer *pp_buffer)
97 {
98         tdm_pp_private_buffer *b = NULL, *bb = NULL;
99
100         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
101                 if (b == pp_buffer)
102                         return b;
103         }
104
105         return NULL;
106 }
107
108 static void
109 _tdm_pp_thread_cb_done(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
110 {
111         tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done *)cb_base;
112         tdm_private_pp *private_pp = object;
113         tdm_pp_private_buffer *pp_buffer = NULL, *first_entry = NULL;
114         tbm_surface_h src;
115         tbm_surface_h dst;
116
117         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
118
119         assert(private_pp->owner_tid == syscall(SYS_gettid));
120
121         src = pp_done->src;
122         dst = pp_done->dst;
123
124         if (tdm_debug_dump & TDM_DUMP_FLAG_PP) {
125                 /* LCOV_EXCL_START */
126                 char str[TDM_PATH_LEN];
127                 static int i;
128                 snprintf(str, TDM_PATH_LEN, "pp_dst_%03d", i++);
129                 tdm_helper_dump_buffer_str(dst, tdm_debug_dump_dir, str);
130                 /* LCOV_EXCL_STOP */
131         }
132
133         if (!LIST_IS_EMPTY(&private_pp->buffer_list)) {
134                 first_entry = container_of((&private_pp->buffer_list)->next, pp_buffer, link);
135                 if (first_entry->src != src || first_entry->dst != dst)
136                         TDM_ERR("buffer(%p,%p) is skipped", first_entry->src, first_entry->dst);
137         } else {
138                 TDM_NEVER_GET_HERE();
139         }
140
141         if ((pp_buffer = _tdm_pp_find_tbm_buffers(&private_pp->buffer_list, src, dst))) {
142                 LIST_DEL(&pp_buffer->link);
143                 LIST_DELINIT(&pp_buffer->commit_link);
144
145                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
146                         TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
147
148                 if (tdm_ttrace_module & TDM_TTRACE_PP) {
149                         tbm_bo bo = tbm_surface_internal_get_bo(dst, 0);
150                         TDM_TRACE_ASYNC_END((intptr_t)private_pp, "[PP] %d", tbm_bo_export(bo));
151                 }
152
153                 _pthread_mutex_unlock(&private_display->lock);
154                 if (private_pp->done_func)
155                         private_pp->done_func(private_pp, src, dst, private_pp->done_user_data);
156                 tdm_buffer_unref_backend(src);
157                 tdm_buffer_unref_backend(dst);
158                 _pthread_mutex_lock(&private_display->lock);
159
160                 free(pp_buffer);
161         }
162 }
163
164 static void
165 _tdm_pp_cb_done(tdm_pp *pp_module, tbm_surface_h src, tbm_surface_h dst, void *user_data)
166 {
167         tdm_thread_cb_pp_done pp_done;
168         tdm_private_pp *private_pp = user_data;
169         tdm_error ret;
170
171         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
172
173         memset(&pp_done, 0, sizeof pp_done);
174         pp_done.base.type = TDM_THREAD_CB_PP_DONE;
175         pp_done.base.length = sizeof pp_done;
176         pp_done.base.object_stamp = private_pp->stamp;
177         pp_done.base.data = NULL;
178         pp_done.base.sync = 0;
179         pp_done.src = src;
180         pp_done.dst = dst;
181
182         ret = tdm_thread_cb_call(private_pp, &pp_done.base, 1);
183         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
184 }
185
186 static void
187 _tdm_pp_cb_done_hal_tdm(hal_tdm_pp *pp_module, tbm_surface_h src, tbm_surface_h dst, void *user_data)
188 {
189         tdm_thread_cb_pp_done pp_done;
190         tdm_private_pp *private_pp = user_data;
191         tdm_error ret;
192
193         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
194
195         memset(&pp_done, 0, sizeof pp_done);
196         pp_done.base.type = TDM_THREAD_CB_PP_DONE;
197         pp_done.base.length = sizeof pp_done;
198         pp_done.base.object_stamp = private_pp->stamp;
199         pp_done.base.data = NULL;
200         pp_done.base.sync = 0;
201         pp_done.src = src;
202         pp_done.dst = dst;
203
204         ret = tdm_thread_cb_call(private_pp, &pp_done.base, 1);
205         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
206 }
207
208 static void *
209 _tdm_pp_find_object(tdm_private_display *private_display, double stamp)
210 {
211         tdm_private_module *private_module = NULL;
212         tdm_private_pp *private_pp = NULL;
213
214         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
215
216         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
217                 LIST_FOR_EACH_ENTRY(private_pp, &private_module->pp_list, link) {
218                         if (private_pp->stamp == stamp)
219                                 return private_pp;
220                 }
221         }
222
223         return NULL;
224 }
225
226 INTERN tdm_error
227 tdm_pp_init(tdm_private_display *private_display)
228 {
229         tdm_thread_cb_set_find_func(TDM_THREAD_CB_PP_DONE, _tdm_pp_find_object);
230
231         return TDM_ERROR_NONE;
232 }
233
234 INTERN tdm_private_pp *
235 tdm_pp_create_internal(tdm_private_module *private_module, tdm_error *error)
236 {
237         tdm_private_display *private_display;
238         tdm_func_display *func_display;
239         tdm_func_pp *func_pp;
240         tdm_private_pp *private_pp = NULL;
241         tdm_pp *pp_module = NULL;
242         tdm_error ret = TDM_ERROR_NONE;
243
244         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
245         TDM_RETURN_VAL_IF_FAIL(private_module != NULL, NULL);
246
247         if (!(private_module->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
248                 /* LCOV_EXCL_START */
249                 TDM_ERR("backend no pp capability");
250                 if (error)
251                         *error = TDM_ERROR_NO_CAPABILITY;
252                 return NULL;
253                 /* LCOV_EXCL_STOP */
254         }
255
256         private_display = private_module->private_display;
257         func_display = &private_module->func_display;
258         func_pp = &private_module->func_pp;
259
260         if (private_module->use_hal_tdm) {
261                 pp_module = (tdm_pp *)hal_tdm_display_create_pp(private_module->htdm_dpy, (hal_tdm_error *)&ret);
262         } else {
263                 pp_module = func_display->display_create_pp(private_module->bdata, &ret);
264         }
265         if (ret != TDM_ERROR_NONE) {
266                 /* LCOV_EXCL_START */
267                 TDM_ERR("create pp fail");
268                 if (error)
269                         *error = ret;
270                 return NULL;
271                 /* LCOV_EXCL_STOP */
272         }
273
274         private_pp = calloc(1, sizeof(tdm_private_pp));
275         if (!private_pp) {
276                 /* LCOV_EXCL_START */
277                 TDM_ERR("memory alloc fail");
278                 if (error)
279                         *error = TDM_ERROR_OUT_OF_MEMORY;
280                 goto alloc_fail;
281                 /* LCOV_EXCL_STOP */
282         }
283
284         ret = tdm_thread_cb_add(private_pp, TDM_THREAD_CB_PP_DONE, NULL, _tdm_pp_thread_cb_done, NULL);
285         if (ret != TDM_ERROR_NONE) {
286                 /* LCOV_EXCL_START */
287                 TDM_ERR("pp tdm_thread_cb_add failed");
288                 if (error)
289                         *error = ret;
290                 goto thread_fail;
291                 /* LCOV_EXCL_STOP */
292         }
293
294         if (private_module->use_hal_tdm)
295                 ret = (tdm_error)hal_tdm_pp_set_done_handler((hal_tdm_pp *)pp_module, _tdm_pp_cb_done_hal_tdm, private_pp);
296         else
297                 ret = func_pp->pp_set_done_handler(pp_module, _tdm_pp_cb_done, private_pp);
298         if (ret != TDM_ERROR_NONE) {
299                 /* LCOV_EXCL_START */
300                 TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
301                 if (error)
302                         *error = ret;
303                 goto thread_fail;
304                 /* LCOV_EXCL_STOP */
305         }
306
307         private_pp->stamp = tdm_helper_get_time();
308         while (_tdm_pp_find_object(private_display, private_pp->stamp))
309                 private_pp->stamp++;
310
311         LIST_ADD(&private_pp->link, &private_module->pp_list);
312         private_pp->private_display = private_module->private_display;
313         private_pp->private_module = private_module;
314         private_pp->pp_module = pp_module;
315         private_pp->owner_tid = syscall(SYS_gettid);
316
317         LIST_INITHEAD(&private_pp->pending_buffer_list);
318         LIST_INITHEAD(&private_pp->buffer_list);
319
320         if (error)
321                 *error = TDM_ERROR_NONE;
322
323         return private_pp;
324
325 thread_fail:
326         free(private_pp);
327 alloc_fail:
328         if (private_module->use_hal_tdm)
329                 hal_tdm_pp_destroy((hal_tdm_pp *)pp_module);
330         else
331                 func_pp->pp_destroy(pp_module);
332
333         return NULL;
334 }
335
336 INTERN void
337 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
338 {
339         tdm_private_display *private_display;
340         tdm_private_module *private_module;
341         tdm_func_pp *func_pp;
342         tdm_pp_private_buffer *b = NULL, *bb = NULL;
343         struct list_head clone_list;
344
345         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
346
347         if (!private_pp)
348                 return;
349
350         tdm_thread_cb_remove(private_pp, TDM_THREAD_CB_PP_DONE, NULL, _tdm_pp_thread_cb_done, NULL);
351
352         private_display = private_pp->private_display;
353         private_module = private_pp->private_module;
354         func_pp = &private_module->func_pp;
355
356         LIST_DEL(&private_pp->link);
357
358         if (private_module->use_hal_tdm)
359                 hal_tdm_pp_destroy((hal_tdm_pp *)private_pp->pp_module);
360         else
361                 func_pp->pp_destroy(private_pp->pp_module);
362
363         if (!LIST_IS_EMPTY(&private_pp->pending_buffer_list)) {
364                 TDM_WRN("pp(%p) not finished:", private_pp);
365                 _tdm_pp_print_list(&private_pp->pending_buffer_list);
366
367                 LIST_INITHEAD(&clone_list);
368                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->pending_buffer_list, link) {
369                         LIST_DEL(&b->link);
370                         LIST_ADDTAIL(&b->link, &clone_list);
371                 }
372
373                 _pthread_mutex_unlock(&private_display->lock);
374                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
375                         LIST_DEL(&b->link);
376
377                         if (tdm_ttrace_module & TDM_TTRACE_PP) {
378                                 tbm_bo bo = tbm_surface_internal_get_bo(b->dst, 0);
379                                 TDM_TRACE_ASYNC_END((intptr_t)private_pp, "[PP] %d", tbm_bo_export(bo));
380                         }
381
382                         tdm_buffer_unref_backend(b->src);
383                         tdm_buffer_unref_backend(b->dst);
384                         free(b);
385                 }
386                 _pthread_mutex_lock(&private_display->lock);
387         }
388
389         if (!LIST_IS_EMPTY(&private_pp->buffer_list)) {
390                 TDM_WRN("pp(%p) not finished:", private_pp);
391                 _tdm_pp_print_list(&private_pp->buffer_list);
392
393                 LIST_INITHEAD(&clone_list);
394                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->buffer_list, link) {
395                         LIST_DEL(&b->link);
396                         LIST_ADDTAIL(&b->link, &clone_list);
397                 }
398
399                 _pthread_mutex_unlock(&private_display->lock);
400                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
401                         LIST_DEL(&b->link);
402
403                         if (tdm_ttrace_module & TDM_TTRACE_PP) {
404                                 tbm_bo bo = tbm_surface_internal_get_bo(b->dst, 0);
405                                 TDM_TRACE_ASYNC_END((intptr_t)private_pp, "[PP] %d", tbm_bo_export(bo));
406                         }
407
408                         tdm_buffer_unref_backend(b->src);
409                         tdm_buffer_unref_backend(b->dst);
410                         free(b);
411                 }
412                 _pthread_mutex_lock(&private_display->lock);
413         }
414
415         private_pp->stamp = 0;
416         free(private_pp);
417 }
418
419 EXTERN void
420 tdm_pp_destroy(tdm_pp *pp)
421 {
422         tdm_private_pp *private_pp = pp;
423         tdm_private_display *private_display;
424
425         if (!private_pp)
426                 return;
427
428         private_display = private_pp->private_display;
429
430         _pthread_mutex_lock(&private_display->lock);
431         tdm_pp_destroy_internal(private_pp);
432         _pthread_mutex_unlock(&private_display->lock);
433 }
434
435 EXTERN tdm_error
436 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
437 {
438         PP_FUNC_ENTRY();
439
440         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
441
442         _pthread_mutex_lock(&private_display->lock);
443
444         if (!private_module->use_hal_tdm) {
445                 if (!func_pp->pp_set_info) {
446                         /* LCOV_EXCL_START */
447                         _pthread_mutex_unlock(&private_display->lock);
448                         TDM_DBG("failed: not implemented!!");
449                         return TDM_ERROR_NOT_IMPLEMENTED;
450                         /* LCOV_EXCL_STOP */
451                 }
452         }
453
454         TDM_INFO("pp(%p) info: src(%ux%u %u,%u %ux%u %c%c%c%c) dst(%ux%u %u,%u %ux%u %c%c%c%c) trans(%d) sync(%d) flags(%x)",
455                          private_pp, info->src_config.size.h, info->src_config.size.v,
456                          info->src_config.pos.x, info->src_config.pos.y,
457                          info->src_config.pos.w, info->src_config.pos.h,
458                          FOURCC_STR(info->src_config.format),
459                          info->dst_config.size.h, info->dst_config.size.v,
460                          info->dst_config.pos.x, info->dst_config.pos.y,
461                          info->dst_config.pos.w, info->dst_config.pos.h,
462                          FOURCC_STR(info->dst_config.format),
463                          info->transform, info->sync, info->flags);
464
465         if (private_module->use_hal_tdm)
466                 ret = (tdm_error)hal_tdm_pp_set_info((hal_tdm_pp *)private_pp->pp_module, (hal_tdm_info_pp *)info);
467         else
468                 ret = func_pp->pp_set_info(private_pp->pp_module, info);
469         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
470
471         private_pp->info = *info;
472
473         _pthread_mutex_unlock(&private_display->lock);
474
475         return ret;
476 }
477
478 EXTERN tdm_error
479 tdm_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data)
480 {
481         tdm_private_display *private_display;
482         tdm_private_pp *private_pp;
483         tdm_error ret = TDM_ERROR_NONE;
484
485         TDM_RETURN_VAL_IF_FAIL(pp != NULL, TDM_ERROR_INVALID_PARAMETER);
486
487         private_pp = (tdm_private_pp*)pp;
488         private_display = private_pp->private_display;
489
490         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
491
492         _pthread_mutex_lock(&private_display->lock);
493
494         private_pp->done_func = func;
495         private_pp->done_user_data = user_data;
496
497         _pthread_mutex_unlock(&private_display->lock);
498
499         return ret;
500 }
501
502 EXTERN tdm_error
503 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
504 {
505         tdm_pp_private_buffer *pp_buffer;
506
507         PP_FUNC_ENTRY();
508
509         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
510         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
511
512         _pthread_mutex_lock(&private_display->lock);
513
514         if (!private_module->use_hal_tdm) {
515                 if (!func_pp->pp_attach) {
516                         /* LCOV_EXCL_START */
517                         _pthread_mutex_unlock(&private_display->lock);
518                         TDM_DBG("failed: not implemented!!");
519                         return TDM_ERROR_NOT_IMPLEMENTED;
520                         /* LCOV_EXCL_STOP */
521                 }
522         }
523
524         if (tdm_module_check_abi(private_module, 1, 2) &&
525                 private_module->caps_pp.max_attach_count > 0) {
526                 /* LCOV_EXCL_START */
527                 int length = LIST_LENGTH(&private_pp->pending_buffer_list) +
528                                          LIST_LENGTH(&private_pp->buffer_list);
529                 if (length >= private_module->caps_pp.max_attach_count) {
530                         _pthread_mutex_unlock(&private_display->lock);
531                         TDM_DBG("failed: backend(%s) too many attached!! max_attach_count(%d)",
532                                         private_module->module_data->name, private_module->caps_pp.max_attach_count);
533                         return TDM_ERROR_BAD_REQUEST;
534                 }
535                 /* LCOV_EXCL_STOP */
536         }
537
538         if (tdm_debug_dump & TDM_DUMP_FLAG_PP) {
539                 /* LCOV_EXCL_START */
540                 char str[TDM_PATH_LEN];
541                 static int i;
542                 snprintf(str, TDM_PATH_LEN, "pp_src_%03d", i++);
543                 tdm_helper_dump_buffer_str(src, tdm_debug_dump_dir, str);
544                 /* LCOV_EXCL_STOP */
545         }
546
547         pp_buffer = calloc(1, sizeof * pp_buffer);
548         if (!pp_buffer) {
549                 /* LCOV_EXCL_START */
550                 _pthread_mutex_unlock(&private_display->lock);
551                 TDM_ERR("alloc failed");
552                 return TDM_ERROR_OUT_OF_MEMORY;
553                 /* LCOV_EXCL_STOP */
554         }
555
556         if (private_module->use_hal_tdm)
557                 ret = (tdm_error)hal_tdm_pp_attach((hal_tdm_pp *)private_pp->pp_module, src, dst);
558         else
559                 ret = func_pp->pp_attach(private_pp->pp_module, src, dst);
560         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
561
562         if (ret != TDM_ERROR_NONE) {
563                 /* LCOV_EXCL_START */
564                 free(pp_buffer);
565                 _pthread_mutex_unlock(&private_display->lock);
566                 TDM_ERR("attach failed");
567                 return ret;
568                 /* LCOV_EXCL_STOP */
569         }
570
571         LIST_ADDTAIL(&pp_buffer->link, &private_pp->pending_buffer_list);
572         pp_buffer->src = tdm_buffer_ref_backend(src);
573         pp_buffer->dst = tdm_buffer_ref_backend(dst);
574
575         if (tdm_debug_module & TDM_DEBUG_BUFFER) {
576                 TDM_INFO("pp(%p) attached:", private_pp);
577                 _tdm_pp_print_list(&private_pp->pending_buffer_list);
578         }
579
580         if (tdm_ttrace_module & TDM_TTRACE_PP) {
581                 tbm_bo bo = tbm_surface_internal_get_bo(dst, 0);
582                 TDM_TRACE_ASYNC_BEGIN((intptr_t)pp, "[PP] %d", tbm_bo_export(bo));
583         }
584
585         _pthread_mutex_unlock(&private_display->lock);
586
587         return ret;
588 }
589
590 EXTERN tdm_error
591 tdm_pp_commit(tdm_pp *pp)
592 {
593         tdm_pp_private_buffer *b = NULL, *bb = NULL;
594         struct list_head commit_buffer_list;
595
596         PP_FUNC_ENTRY();
597
598         _pthread_mutex_lock(&private_display->lock);
599
600         if (!private_module->use_hal_tdm) {
601                 if (!func_pp->pp_commit) {
602                         /* LCOV_EXCL_START */
603                         _pthread_mutex_unlock(&private_display->lock);
604                         TDM_DBG("failed: not implemented!!");
605                         return TDM_ERROR_NOT_IMPLEMENTED;
606                         /* LCOV_EXCL_STOP */
607                 }
608         }
609
610         LIST_INITHEAD(&commit_buffer_list);
611
612         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->pending_buffer_list, link) {
613                 LIST_DEL(&b->link);
614                 LIST_ADDTAIL(&b->link, &private_pp->buffer_list);
615                 LIST_ADDTAIL(&b->commit_link, &commit_buffer_list);
616         }
617
618         if (private_module->use_hal_tdm)
619                 ret = (tdm_error)hal_tdm_pp_commit((hal_tdm_pp *)private_pp->pp_module);
620         else
621                 ret = func_pp->pp_commit(private_pp->pp_module);
622         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
623
624         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &commit_buffer_list, commit_link) {
625                 LIST_DELINIT(&b->commit_link);
626
627                 if (!_tdm_pp_find_buffer(&private_pp->buffer_list, b))
628                         continue;
629
630                 if (ret != TDM_ERROR_NONE) {
631                         _pthread_mutex_unlock(&private_display->lock);
632                         tdm_buffer_unref_backend(b->src);
633                         tdm_buffer_unref_backend(b->dst);
634                         _pthread_mutex_lock(&private_display->lock);
635                         LIST_DEL(&b->link);
636
637                         free(b);
638                 }
639         }
640
641         _pthread_mutex_unlock(&private_display->lock);
642
643         return ret;
644 }