Package version up to 2.9.5
[platform/core/uifw/libtdm.git] / src / tdm_hwc.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2018 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: SooChan Lim <sc1.lim@samsung.com>,
8  *          Boram Park <boram1288.park@samsung.com>,
9  *          Changyeon Lee <cyeon.lee@samsung.com>,
10  *          Sangjin Lee <lsj119@samsung.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the
14  * "Software"), to deal in the Software without restriction, including
15  * without limitation the rights to use, copy, modify, merge, publish,
16  * distribute, sub license, and/or sell copies of the Software, and to
17  * permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  *
20  * The above copyright notice and this permission notice (including the
21  * next paragraph) shall be included in all copies or substantial portions
22  * of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
28  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31  *
32 **************************************************************************/
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "tdm_private.h"
39
40 #define HWC_FUNC_ENTRY() \
41         tdm_private_display *private_display; \
42         tdm_private_output *private_output; \
43         tdm_private_hwc *private_hwc; \
44         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
45         TDM_RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER); \
46         private_hwc = (tdm_private_hwc*)hwc; \
47         private_output = private_hwc->private_output; \
48         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER); \
49         private_display = private_output->private_display
50
51 #define HWC_FUNC_ENTRY_ERROR() \
52         tdm_private_display *private_display; \
53         tdm_private_output *private_output; \
54         tdm_private_hwc *private_hwc; \
55         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
56         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(hwc != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
57         private_hwc = (tdm_private_hwc*)hwc; \
58         private_output = private_hwc->private_output; \
59         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
60         private_display = private_output->private_display
61
62 #define HWC_FUNC_ENTRY_VOID_RETURN() \
63         tdm_private_display *private_display; \
64         tdm_private_output *private_output; \
65         tdm_private_hwc *private_hwc; \
66         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
67         TDM_RETURN_IF_FAIL(hwc != NULL); \
68         private_hwc = (tdm_private_hwc*)hwc; \
69         private_output = private_hwc->private_output; \
70         TDM_RETURN_IF_FAIL(private_output != NULL); \
71         private_display = private_output->private_display
72
73
74 static tdm_private_hwc_window *
75 _tdm_hwc_find_private_hwc_window(tdm_private_hwc *private_hwc, tdm_hwc_window *hwc_window_backend)
76 {
77         tdm_private_hwc_window *private_hwc_window = NULL;
78
79         LIST_FOR_EACH_ENTRY(private_hwc_window, &private_hwc->hwc_window_list, link) {
80                 if (private_hwc_window->hwc_window_backend == hwc_window_backend)
81                         return private_hwc_window;
82         }
83
84         return NULL;
85 }
86
87 static void
88 _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
89                                 tdm_thread_cb_base *cb_base, void *user_data)
90 {
91         tdm_thread_cb_hwc_commit *hwc_commit = (tdm_thread_cb_hwc_commit *)cb_base;
92         tdm_private_hwc_commit_handler *hwc_commit_handler = hwc_commit->base.data;
93         tdm_private_hwc *private_hwc = object;
94
95         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
96
97         if (!hwc_commit_handler)
98                 return;
99
100         assert(hwc_commit_handler->owner_tid == syscall(SYS_gettid));
101
102         tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
103                                         _tdm_hwc_thread_cb_commit, NULL);
104
105         LIST_DEL(&hwc_commit_handler->link);
106
107         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
108                 TDM_INFO("----------------------------------------- hwc(%d) committed", private_hwc->index);
109                 TDM_INFO("handler(%p)", hwc_commit_handler);
110         }
111
112         /* LCOV_EXCL_START */
113         if (private_display->print_fps) {
114                 double curr = tdm_helper_get_time();
115                 if (private_hwc->fps_stamp == 0) {
116                         private_hwc->fps_stamp = curr;
117                 } else if ((curr - private_hwc->fps_stamp) > 1.0) {
118                         TDM_INFO("hwc(%p,%d) fps: %d",
119                                          private_hwc, private_hwc->index, private_hwc->fps_count);
120                         private_hwc->fps_count = 0;
121                         private_hwc->fps_stamp = curr;
122                 } else
123                         private_hwc->fps_count++;
124         } else if (private_hwc->fps_stamp != 0) {
125                 private_hwc->fps_stamp = 0;
126                 private_hwc->fps_count = 0;
127         }
128         /* LCOV_EXCL_STOP */
129
130         if (hwc_commit_handler->func) {
131                 _pthread_mutex_unlock(&private_display->lock);
132                 hwc_commit_handler->func(private_hwc,
133                                                                         hwc_commit->sequence,
134                                                                         hwc_commit->tv_sec,
135                                                                         hwc_commit->tv_usec,
136                                                                         hwc_commit_handler->user_data);
137                 _pthread_mutex_lock(&private_display->lock);
138         }
139
140         free(hwc_commit_handler);
141
142         if (tdm_debug_module & TDM_DEBUG_COMMIT)
143                 TDM_INFO("-----------------------------------------...");
144 }
145
146 static void
147 _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
148                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
149 {
150         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
151         tdm_private_hwc *private_hwc;
152         tdm_thread_cb_hwc_commit hwc_commit;
153         tdm_error ret;
154
155         if (hwc_commit_handler)
156                 private_hwc = hwc_commit_handler->private_hwc;
157         else
158                 private_hwc = tdm_display_find_private_hwc(tdm_display_get(), hwc_backend);
159
160         memset(&hwc_commit, 0, sizeof hwc_commit);
161         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
162         hwc_commit.base.length = sizeof hwc_commit;
163         hwc_commit.base.object_stamp = private_hwc->stamp;
164         hwc_commit.base.data = hwc_commit_handler;
165         hwc_commit.base.sync = 0;
166         hwc_commit.sequence = sequence;
167         hwc_commit.tv_sec = tv_sec;
168         hwc_commit.tv_usec = tv_usec;
169
170         ret = tdm_thread_cb_call(private_hwc, &hwc_commit.base, 1);
171         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
172 }
173
174 INTERN tdm_error
175 tdm_hwc_init(tdm_private_display *private_display)
176 {
177         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
178
179         return TDM_ERROR_NONE;
180 }
181
182 EXTERN tdm_hwc_window *
183 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
184 {
185         tdm_hwc_window *hwc_window = NULL;
186
187         HWC_FUNC_ENTRY_ERROR();
188
189         _pthread_mutex_lock(&private_display->lock);
190
191         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
192
193         _pthread_mutex_unlock(&private_display->lock);
194
195         return hwc_window;
196 }
197
198 EXTERN tdm_error
199 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
200 {
201         tdm_private_module *private_module;
202         tdm_func_hwc *func_hwc;
203
204         HWC_FUNC_ENTRY();
205
206         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
207         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
208
209         _pthread_mutex_lock(&private_display->lock);
210
211         private_module = private_output->private_module;
212         func_hwc = &private_module->func_hwc;
213
214         if (!func_hwc->hwc_get_video_supported_formats) {
215                 /* LCOV_EXCL_START */
216                 _pthread_mutex_unlock(&private_display->lock);
217                 TDM_WRN("not implemented!!");
218                 return TDM_ERROR_NOT_IMPLEMENTED;
219                 /* LCOV_EXCL_STOP */
220         }
221
222         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
223
224         _pthread_mutex_unlock(&private_display->lock);
225
226         return ret;
227 }
228
229 EXTERN tdm_error
230 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
231 {
232         tdm_private_module *private_module;
233         tdm_func_hwc *func_hwc = NULL;
234
235         HWC_FUNC_ENTRY();
236
237         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
238         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
239
240         _pthread_mutex_lock(&private_display->lock);
241
242         private_module = private_output->private_module;
243         func_hwc = &private_module->func_hwc;
244
245         if (!func_hwc->hwc_get_video_available_properties) {
246                 /* LCOV_EXCL_START */
247                 _pthread_mutex_unlock(&private_display->lock);
248                 TDM_WRN("not implemented!!");
249                 return TDM_ERROR_NOT_IMPLEMENTED;
250                 /* LCOV_EXCL_STOP */
251         }
252
253         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
254
255         _pthread_mutex_unlock(&private_display->lock);
256
257         return ret;
258 }
259
260 EXTERN tdm_error
261 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
262 {
263         tdm_private_module *private_module;
264         tdm_func_hwc *func_hwc;
265
266         HWC_FUNC_ENTRY();
267
268         _pthread_mutex_lock(&private_display->lock);
269
270         private_module = private_output->private_module;
271         func_hwc = &private_module->func_hwc;
272
273         if (!func_hwc->hwc_get_capabilities) {
274                 _pthread_mutex_unlock(&private_display->lock);
275                 TDM_WRN("not implemented!!");
276                 return TDM_ERROR_NOT_IMPLEMENTED;
277         }
278
279         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
280
281         _pthread_mutex_unlock(&private_display->lock);
282
283         return ret;
284 }
285
286 EXTERN tdm_error
287 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
288 {
289         tdm_private_module *private_module;
290         tdm_func_hwc *func_hwc = NULL;
291
292         HWC_FUNC_ENTRY();
293
294         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
295         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
296
297         _pthread_mutex_lock(&private_display->lock);
298
299         private_module = private_output->private_module;
300         func_hwc = &private_module->func_hwc;
301
302         if (!func_hwc->hwc_get_available_properties) {
303                 /* LCOV_EXCL_START */
304                 _pthread_mutex_unlock(&private_display->lock);
305                 TDM_WRN("not implemented!!");
306                 return TDM_ERROR_NOT_IMPLEMENTED;
307                 /* LCOV_EXCL_STOP */
308         }
309
310         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
311
312         _pthread_mutex_unlock(&private_display->lock);
313
314         return ret;
315 }
316
317 EXTERN tbm_surface_queue_h
318 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
319 {
320         tdm_private_module *private_module;
321         tdm_func_hwc *func_hwc = NULL;
322         tbm_surface_queue_h queue = NULL;
323
324         HWC_FUNC_ENTRY_ERROR();
325
326         _pthread_mutex_lock(&private_display->lock);
327
328         private_module = private_hwc->private_module;
329         func_hwc = &private_module->func_hwc;
330
331         if (!func_hwc->hwc_get_client_target_buffer_queue) {
332                 /* LCOV_EXCL_START */
333                 _pthread_mutex_unlock(&private_display->lock);
334                 TDM_WRN("not implemented!!");
335                 return NULL;
336                 /* LCOV_EXCL_STOP */
337         }
338
339         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
340
341         _pthread_mutex_unlock(&private_display->lock);
342
343         return queue;
344 }
345
346 EXTERN tdm_error
347 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
348 {
349         tdm_private_module *private_module;
350         tdm_func_hwc *func_hwc = NULL;
351
352         HWC_FUNC_ENTRY();
353
354         _pthread_mutex_lock(&private_display->lock);
355
356         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
357                 /* LCOV_EXCL_START */
358                 char str[TDM_PATH_LEN];
359                 static int i;
360                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
361                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
362                 /* LCOV_EXCL_STOP */
363         }
364
365         private_module = private_hwc->private_module;
366         func_hwc = &private_module->func_hwc;
367
368         if (!func_hwc->hwc_set_client_target_buffer) {
369                 /* LCOV_EXCL_START */
370                 _pthread_mutex_unlock(&private_display->lock);
371                 TDM_WRN("not implemented!!");
372                 return TDM_ERROR_NOT_IMPLEMENTED;
373                 /* LCOV_EXCL_STOP */
374         }
375
376         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
377
378         if (private_hwc->display_target_buffer) {
379                 if (private_hwc->display_target_buffer != target_buffer) {
380                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
381                         private_hwc->display_target_buffer = target_buffer;
382                         if (target_buffer)
383                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
384                 }
385         } else {
386                 if (target_buffer) {
387                         private_hwc->display_target_buffer = target_buffer;
388                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
389                 }
390         }
391
392         _pthread_mutex_unlock(&private_display->lock);
393
394         return ret;
395 }
396
397
398 EXTERN tdm_error
399 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
400 {
401         tdm_private_module *private_module;
402         tdm_func_hwc *func_hwc = NULL;
403         tdm_private_hwc_window **composited_wnds_frontend = NULL;
404         tdm_hwc_window **composited_wnds_backend = NULL;
405         int i;
406
407         HWC_FUNC_ENTRY();
408
409         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
410
411         _pthread_mutex_lock(&private_display->lock);
412
413         private_module = private_hwc->private_module;
414         func_hwc = &private_module->func_hwc;
415
416         if (!func_hwc->hwc_validate) {
417                 /* LCOV_EXCL_START */
418                 _pthread_mutex_unlock(&private_display->lock);
419                 TDM_WRN("not implemented!!");
420                 return TDM_ERROR_NOT_IMPLEMENTED;
421                 /* LCOV_EXCL_STOP */
422         }
423
424         if (num_wnds == 0) {
425                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
426
427                 _pthread_mutex_unlock(&private_display->lock);
428                 return ret;
429         }
430
431         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
432         if (!composited_wnds_backend) {
433                 /* LCOV_EXCL_START */
434                 _pthread_mutex_unlock(&private_display->lock);
435                 return TDM_ERROR_OUT_OF_MEMORY;
436                 /* LCOV_EXCL_STOP */
437         }
438
439         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
440
441         for (i = 0; i < num_wnds; i++)
442                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
443
444         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
445                                                                 num_wnds, num_types);
446
447         free(composited_wnds_backend);
448
449         _pthread_mutex_unlock(&private_display->lock);
450
451         return ret;
452 }
453
454 EXTERN tdm_error
455 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
456                                                                 tdm_hwc_window **hwc_window,
457                                                                 tdm_hwc_window_composition *composition_types)
458 {
459         tdm_private_module *private_module;
460         tdm_func_hwc *func_hwc = NULL;
461         tdm_private_hwc_window * private_hwc_window = NULL;
462         int i = 0;
463
464         HWC_FUNC_ENTRY();
465
466         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
467
468         _pthread_mutex_lock(&private_display->lock);
469
470         private_module = private_hwc->private_module;
471         func_hwc = &private_module->func_hwc;
472
473         if (!func_hwc->hwc_get_changed_composition_types) {
474                 /* LCOV_EXCL_START */
475                 _pthread_mutex_unlock(&private_display->lock);
476                 TDM_WRN("not implemented!!");
477                 return TDM_ERROR_NOT_IMPLEMENTED;
478                 /* LCOV_EXCL_STOP */
479         }
480
481         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
482                                                         num_elements, hwc_window, composition_types);
483         if (ret != TDM_ERROR_NONE) {
484                 /* LCOV_EXCL_START */
485                 _pthread_mutex_unlock(&private_display->lock);
486                 return ret;
487                 /* LCOV_EXCL_STOP */
488         }
489
490         if (hwc_window == NULL || composition_types == NULL) {
491                 _pthread_mutex_unlock(&private_display->lock);
492                 return TDM_ERROR_NONE;
493         }
494
495         for (i = 0; i < *num_elements; i++) {
496                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
497                 if (private_hwc_window == NULL) {
498                         /* LCOV_EXCL_START */
499                         TDM_ERR("failed! This should never happen!");
500                         tdm_hwc_window_destroy_internal(private_hwc_window);
501                         *num_elements = 0;
502                         _pthread_mutex_unlock(&private_display->lock);
503                         return TDM_ERROR_OPERATION_FAILED;
504                         /* LCOV_EXCL_STOP */
505                 }
506
507                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
508         }
509
510         _pthread_mutex_unlock(&private_display->lock);
511
512         return ret;
513 }
514
515 EXTERN tdm_error
516 tdm_hwc_accept_validation(tdm_hwc *hwc)
517 {
518         tdm_private_module *private_module;
519         tdm_func_hwc *func_hwc = NULL;
520
521         HWC_FUNC_ENTRY();
522
523         _pthread_mutex_lock(&private_display->lock);
524
525         private_module = private_hwc->private_module;
526         func_hwc = &private_module->func_hwc;
527
528         if (!func_hwc->hwc_validate) {
529                 /* LCOV_EXCL_START */
530                 _pthread_mutex_unlock(&private_display->lock);
531                 TDM_WRN("not implemented!!");
532                 return TDM_ERROR_NOT_IMPLEMENTED;
533                 /* LCOV_EXCL_STOP */
534         }
535
536         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
537
538         _pthread_mutex_unlock(&private_display->lock);
539
540         return ret;
541 }
542
543 EXTERN tdm_error
544 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
545 {
546         tdm_private_module *private_module;
547         tdm_func_hwc *func_hwc = NULL;
548         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
549         tdm_private_voutput *private_voutput = NULL;
550         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
551
552         HWC_FUNC_ENTRY();
553
554         _pthread_mutex_lock(&private_display->lock);
555
556         private_module = private_hwc->private_module;
557         func_hwc = &private_module->func_hwc;
558
559         if (!func_hwc->hwc_commit) {
560                 /* LCOV_EXCL_START */
561                 TDM_WRN("not implemented!!");
562                 _pthread_mutex_unlock(&private_display->lock);
563                 return TDM_ERROR_NOT_IMPLEMENTED;
564                 /* LCOV_EXCL_STOP */
565         }
566
567 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
568 #if 0
569         /* check if the dpms is off */
570         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
571                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
572                                 tdm_dpms_str(private_output->current_dpms_value));
573                 _pthread_mutex_unlock(&private_display->lock);
574                 return TDM_ERROR_DPMS_OFF;
575         }
576 #endif
577
578         if (tdm_debug_module & TDM_DEBUG_COMMIT)
579                 TDM_INFO("hwc(%d) commit", private_hwc->index);
580
581         if (private_module == private_display->virtual_module) {
582                 if (!private_output->private_voutput) {
583                         TDM_ERR("virtual module but don't have voutput");
584                         _pthread_mutex_unlock(&private_display->lock);
585                         return TDM_ERROR_BAD_MODULE;
586                 }
587         }
588
589         if (!private_hwc->regist_commit_cb) {
590                 private_hwc->regist_commit_cb = 1;
591                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
592                 /* LCOV_EXCL_START */
593                 if (ret != TDM_ERROR_NONE) {
594                         private_hwc->regist_commit_cb = 0;
595                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
596                         _pthread_mutex_unlock(&private_display->lock);
597                         return ret;
598                 /* LCOV_EXCL_STOP */
599                 }
600         }
601
602         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
603         if (!hwc_commit_handler) {
604                 /* LCOV_EXCL_START */
605                 TDM_ERR("failed: alloc memory");
606                 _pthread_mutex_unlock(&private_display->lock);
607                 return TDM_ERROR_OUT_OF_MEMORY;
608                 /* LCOV_EXCL_STOP */
609         }
610
611         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
612                                         _tdm_hwc_thread_cb_commit, NULL);
613         if (ret != TDM_ERROR_NONE) {
614                 TDM_ERR("tdm_thread_cb_add failed");
615                 free(hwc_commit_handler);
616                 _pthread_mutex_unlock(&private_display->lock);
617                 return ret;
618         }
619
620         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
621         hwc_commit_handler->private_hwc = private_hwc;
622         hwc_commit_handler->func = func;
623         hwc_commit_handler->user_data = user_data;
624         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
625
626         if (private_module == private_display->virtual_module) {
627                 private_voutput = private_output->private_voutput;
628
629                 if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
630                         voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
631                         voutput_commit_handler->user_data = private_hwc->display_target_buffer;
632                 }
633         }
634
635         ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
636         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
637
638         if (tdm_debug_module & TDM_DEBUG_COMMIT)
639                 TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
640                                 private_hwc->index, hwc_commit_handler, func, user_data);
641
642         _pthread_mutex_unlock(&private_display->lock);
643
644         return ret;
645
646 commit_failed:
647         /* LCOV_EXCL_START */
648         if (hwc_commit_handler) {
649                 tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
650                                                 _tdm_hwc_thread_cb_commit, NULL);
651                 LIST_DEL(&hwc_commit_handler->link);
652                 free(hwc_commit_handler);
653         }
654
655         _pthread_mutex_unlock(&private_display->lock);
656
657         return ret;
658         /* LCOV_EXCL_STOP */
659 }
660
661 tdm_error
662 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
663 {
664         tdm_private_module *private_module;
665         tdm_func_hwc *func_hwc = NULL;
666
667         HWC_FUNC_ENTRY();
668
669         _pthread_mutex_lock(&private_display->lock);
670
671         private_module = private_hwc->private_module;
672         func_hwc = &private_module->func_hwc;
673
674         if (!func_hwc->hwc_set_property) {
675                 /* LCOV_EXCL_START */
676                 _pthread_mutex_unlock(&private_display->lock);
677                 TDM_WRN("not implemented!!");
678                 return TDM_ERROR_NOT_IMPLEMENTED;
679                 /* LCOV_EXCL_STOP */
680         }
681
682         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
683
684         _pthread_mutex_unlock(&private_display->lock);
685
686         return ret;
687 }
688
689 tdm_error
690 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
691 {
692         tdm_private_module *private_module;
693         tdm_func_hwc *func_hwc = NULL;
694
695         HWC_FUNC_ENTRY();
696
697         _pthread_mutex_lock(&private_display->lock);
698
699         private_module = private_hwc->private_module;
700         func_hwc = &private_module->func_hwc;
701
702         if (!func_hwc->hwc_get_property) {
703                 /* LCOV_EXCL_START */
704                 _pthread_mutex_unlock(&private_display->lock);
705                 TDM_WRN("not implemented!!");
706                 return TDM_ERROR_NOT_IMPLEMENTED;
707                 /* LCOV_EXCL_STOP */
708         }
709
710         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
711
712         _pthread_mutex_unlock(&private_display->lock);
713
714         return ret;
715 }