f3537bc8bde2bb2eaac4606eff98386f672fb724
[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         if (hwc_commit_handler->func) {
113                 _pthread_mutex_unlock(&private_display->lock);
114                 hwc_commit_handler->func(private_hwc,
115                                                                         hwc_commit->sequence,
116                                                                         hwc_commit->tv_sec,
117                                                                         hwc_commit->tv_usec,
118                                                                         hwc_commit_handler->user_data);
119                 _pthread_mutex_lock(&private_display->lock);
120         }
121
122         free(hwc_commit_handler);
123
124         if (tdm_debug_module & TDM_DEBUG_COMMIT)
125                 TDM_INFO("-----------------------------------------...");
126 }
127
128 static void
129 _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
130                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
131 {
132         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
133         tdm_private_hwc *private_hwc;
134         tdm_thread_cb_hwc_commit hwc_commit;
135         tdm_error ret;
136
137         if (hwc_commit_handler)
138                 private_hwc = hwc_commit_handler->private_hwc;
139         else
140                 private_hwc = tdm_display_find_private_hwc(tdm_display_get(), hwc_backend);
141
142         memset(&hwc_commit, 0, sizeof hwc_commit);
143         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
144         hwc_commit.base.length = sizeof hwc_commit;
145         hwc_commit.base.object_stamp = private_hwc->stamp;
146         hwc_commit.base.data = hwc_commit_handler;
147         hwc_commit.base.sync = 0;
148         hwc_commit.sequence = sequence;
149         hwc_commit.tv_sec = tv_sec;
150         hwc_commit.tv_usec = tv_usec;
151
152         ret = tdm_thread_cb_call(private_hwc, &hwc_commit.base, 1);
153         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
154 }
155
156 INTERN tdm_error
157 tdm_hwc_init(tdm_private_display *private_display)
158 {
159         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
160
161         return TDM_ERROR_NONE;
162 }
163
164 EXTERN tdm_hwc_window *
165 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
166 {
167         tdm_hwc_window *hwc_window = NULL;
168
169         HWC_FUNC_ENTRY_ERROR();
170
171         _pthread_mutex_lock(&private_display->lock);
172
173         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
174
175         _pthread_mutex_unlock(&private_display->lock);
176
177         return hwc_window;
178 }
179
180 EXTERN tdm_error
181 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
182 {
183         tdm_private_module *private_module;
184         tdm_func_hwc *func_hwc;
185
186         HWC_FUNC_ENTRY();
187
188         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
189         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
190
191         _pthread_mutex_lock(&private_display->lock);
192
193         private_module = private_output->private_module;
194         func_hwc = &private_module->func_hwc;
195
196         if (!func_hwc->hwc_get_video_supported_formats) {
197                 /* LCOV_EXCL_START */
198                 _pthread_mutex_unlock(&private_display->lock);
199                 TDM_WRN("not implemented!!");
200                 return TDM_ERROR_NOT_IMPLEMENTED;
201                 /* LCOV_EXCL_STOP */
202         }
203
204         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
205
206         _pthread_mutex_unlock(&private_display->lock);
207
208         return ret;
209 }
210
211 EXTERN tdm_error
212 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
213 {
214         tdm_private_module *private_module;
215         tdm_func_hwc *func_hwc = NULL;
216
217         HWC_FUNC_ENTRY();
218
219         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
220         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
221
222         _pthread_mutex_lock(&private_display->lock);
223
224         private_module = private_output->private_module;
225         func_hwc = &private_module->func_hwc;
226
227         if (!func_hwc->hwc_get_video_available_properties) {
228                 /* LCOV_EXCL_START */
229                 _pthread_mutex_unlock(&private_display->lock);
230                 TDM_WRN("not implemented!!");
231                 return TDM_ERROR_NOT_IMPLEMENTED;
232                 /* LCOV_EXCL_STOP */
233         }
234
235         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
236
237         _pthread_mutex_unlock(&private_display->lock);
238
239         return ret;
240 }
241
242 EXTERN tdm_error
243 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
244 {
245         tdm_private_module *private_module;
246         tdm_func_hwc *func_hwc;
247
248         HWC_FUNC_ENTRY();
249
250         _pthread_mutex_lock(&private_display->lock);
251
252         private_module = private_output->private_module;
253         func_hwc = &private_module->func_hwc;
254
255         if (!func_hwc->hwc_get_capabilities) {
256                 _pthread_mutex_unlock(&private_display->lock);
257                 TDM_WRN("not implemented!!");
258                 return TDM_ERROR_NOT_IMPLEMENTED;
259         }
260
261         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
262
263         _pthread_mutex_unlock(&private_display->lock);
264
265         return ret;
266 }
267
268 EXTERN tdm_error
269 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
270 {
271         tdm_private_module *private_module;
272         tdm_func_hwc *func_hwc = NULL;
273
274         HWC_FUNC_ENTRY();
275
276         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
277         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
278
279         _pthread_mutex_lock(&private_display->lock);
280
281         private_module = private_output->private_module;
282         func_hwc = &private_module->func_hwc;
283
284         if (!func_hwc->hwc_get_available_properties) {
285                 /* LCOV_EXCL_START */
286                 _pthread_mutex_unlock(&private_display->lock);
287                 TDM_WRN("not implemented!!");
288                 return TDM_ERROR_NOT_IMPLEMENTED;
289                 /* LCOV_EXCL_STOP */
290         }
291
292         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
293
294         _pthread_mutex_unlock(&private_display->lock);
295
296         return ret;
297 }
298
299 EXTERN tbm_surface_queue_h
300 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
301 {
302         tdm_private_module *private_module;
303         tdm_func_hwc *func_hwc = NULL;
304         tbm_surface_queue_h queue = NULL;
305
306         HWC_FUNC_ENTRY_ERROR();
307
308         _pthread_mutex_lock(&private_display->lock);
309
310         private_module = private_hwc->private_module;
311         func_hwc = &private_module->func_hwc;
312
313         if (!func_hwc->hwc_get_client_target_buffer_queue) {
314                 /* LCOV_EXCL_START */
315                 _pthread_mutex_unlock(&private_display->lock);
316                 TDM_WRN("not implemented!!");
317                 return NULL;
318                 /* LCOV_EXCL_STOP */
319         }
320
321         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
322
323         _pthread_mutex_unlock(&private_display->lock);
324
325         return queue;
326 }
327
328 EXTERN tdm_error
329 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
330 {
331         tdm_private_module *private_module;
332         tdm_func_hwc *func_hwc = NULL;
333
334         HWC_FUNC_ENTRY();
335
336         _pthread_mutex_lock(&private_display->lock);
337
338         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
339                 /* LCOV_EXCL_START */
340                 char str[TDM_PATH_LEN];
341                 static int i;
342                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
343                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
344                 /* LCOV_EXCL_STOP */
345         }
346
347         private_module = private_hwc->private_module;
348         func_hwc = &private_module->func_hwc;
349
350         if (!func_hwc->hwc_set_client_target_buffer) {
351                 /* LCOV_EXCL_START */
352                 _pthread_mutex_unlock(&private_display->lock);
353                 TDM_WRN("not implemented!!");
354                 return TDM_ERROR_NOT_IMPLEMENTED;
355                 /* LCOV_EXCL_STOP */
356         }
357
358         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
359
360         if (private_hwc->display_target_buffer) {
361                 if (private_hwc->display_target_buffer != target_buffer) {
362                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
363                         private_hwc->display_target_buffer = target_buffer;
364                         if (target_buffer)
365                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
366                 }
367         } else {
368                 if (target_buffer) {
369                         private_hwc->display_target_buffer = target_buffer;
370                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
371                 }
372         }
373
374         _pthread_mutex_unlock(&private_display->lock);
375
376         return ret;
377 }
378
379
380 EXTERN tdm_error
381 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
382 {
383         tdm_private_module *private_module;
384         tdm_func_hwc *func_hwc = NULL;
385         tdm_private_hwc_window **composited_wnds_frontend = NULL;
386         tdm_hwc_window **composited_wnds_backend = NULL;
387         int i;
388
389         HWC_FUNC_ENTRY();
390
391         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
392
393         _pthread_mutex_lock(&private_display->lock);
394
395         private_module = private_hwc->private_module;
396         func_hwc = &private_module->func_hwc;
397
398         if (!func_hwc->hwc_validate) {
399                 /* LCOV_EXCL_START */
400                 _pthread_mutex_unlock(&private_display->lock);
401                 TDM_WRN("not implemented!!");
402                 return TDM_ERROR_NOT_IMPLEMENTED;
403                 /* LCOV_EXCL_STOP */
404         }
405
406         if (num_wnds == 0) {
407                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
408
409                 _pthread_mutex_unlock(&private_display->lock);
410                 return ret;
411         }
412
413         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
414         if (!composited_wnds_backend) {
415                 /* LCOV_EXCL_START */
416                 _pthread_mutex_unlock(&private_display->lock);
417                 return TDM_ERROR_OUT_OF_MEMORY;
418                 /* LCOV_EXCL_STOP */
419         }
420
421         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
422
423         for (i = 0; i < num_wnds; i++)
424                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
425
426         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
427                                                                 num_wnds, num_types);
428
429         free(composited_wnds_backend);
430
431         _pthread_mutex_unlock(&private_display->lock);
432
433         return ret;
434 }
435
436 EXTERN tdm_error
437 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
438                                                                 tdm_hwc_window **hwc_window,
439                                                                 tdm_hwc_window_composition *composition_types)
440 {
441         tdm_private_module *private_module;
442         tdm_func_hwc *func_hwc = NULL;
443         tdm_private_hwc_window * private_hwc_window = NULL;
444         int i = 0;
445
446         HWC_FUNC_ENTRY();
447
448         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
449
450         _pthread_mutex_lock(&private_display->lock);
451
452         private_module = private_hwc->private_module;
453         func_hwc = &private_module->func_hwc;
454
455         if (!func_hwc->hwc_get_changed_composition_types) {
456                 /* LCOV_EXCL_START */
457                 _pthread_mutex_unlock(&private_display->lock);
458                 TDM_WRN("not implemented!!");
459                 return TDM_ERROR_NOT_IMPLEMENTED;
460                 /* LCOV_EXCL_STOP */
461         }
462
463         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
464                                                         num_elements, hwc_window, composition_types);
465         if (ret != TDM_ERROR_NONE) {
466                 /* LCOV_EXCL_START */
467                 _pthread_mutex_unlock(&private_display->lock);
468                 return ret;
469                 /* LCOV_EXCL_STOP */
470         }
471
472         if (hwc_window == NULL || composition_types == NULL) {
473                 _pthread_mutex_unlock(&private_display->lock);
474                 return TDM_ERROR_NONE;
475         }
476
477         for (i = 0; i < *num_elements; i++) {
478                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
479                 if (private_hwc_window == NULL) {
480                         /* LCOV_EXCL_START */
481                         TDM_ERR("failed! This should never happen!");
482                         tdm_hwc_window_destroy_internal(private_hwc_window);
483                         *num_elements = 0;
484                         _pthread_mutex_unlock(&private_display->lock);
485                         return TDM_ERROR_OPERATION_FAILED;
486                         /* LCOV_EXCL_STOP */
487                 }
488
489                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
490         }
491
492         _pthread_mutex_unlock(&private_display->lock);
493
494         return ret;
495 }
496
497 EXTERN tdm_error
498 tdm_hwc_accept_validation(tdm_hwc *hwc)
499 {
500         tdm_private_module *private_module;
501         tdm_func_hwc *func_hwc = NULL;
502
503         HWC_FUNC_ENTRY();
504
505         _pthread_mutex_lock(&private_display->lock);
506
507         private_module = private_hwc->private_module;
508         func_hwc = &private_module->func_hwc;
509
510         if (!func_hwc->hwc_validate) {
511                 /* LCOV_EXCL_START */
512                 _pthread_mutex_unlock(&private_display->lock);
513                 TDM_WRN("not implemented!!");
514                 return TDM_ERROR_NOT_IMPLEMENTED;
515                 /* LCOV_EXCL_STOP */
516         }
517
518         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
519
520         _pthread_mutex_unlock(&private_display->lock);
521
522         return ret;
523 }
524
525 EXTERN tdm_error
526 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
527 {
528         tdm_private_module *private_module;
529         tdm_func_hwc *func_hwc = NULL;
530         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
531         tdm_private_voutput *private_voutput = NULL;
532         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
533
534         HWC_FUNC_ENTRY();
535
536         _pthread_mutex_lock(&private_display->lock);
537
538         private_module = private_hwc->private_module;
539         func_hwc = &private_module->func_hwc;
540
541         if (!func_hwc->hwc_commit) {
542                 /* LCOV_EXCL_START */
543                 TDM_WRN("not implemented!!");
544                 _pthread_mutex_unlock(&private_display->lock);
545                 return TDM_ERROR_NOT_IMPLEMENTED;
546                 /* LCOV_EXCL_STOP */
547         }
548
549 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
550 #if 0
551         /* check if the dpms is off */
552         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
553                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
554                                 tdm_dpms_str(private_output->current_dpms_value));
555                 _pthread_mutex_unlock(&private_display->lock);
556                 return TDM_ERROR_DPMS_OFF;
557         }
558 #endif
559
560         if (tdm_debug_module & TDM_DEBUG_COMMIT)
561                 TDM_INFO("hwc(%d) commit", private_hwc->index);
562
563         if (private_module == private_display->virtual_module) {
564                 if (!private_output->private_voutput) {
565                         TDM_ERR("virtual module but don't have voutput");
566                         _pthread_mutex_unlock(&private_display->lock);
567                         return TDM_ERROR_BAD_MODULE;
568                 }
569         }
570
571         if (!private_hwc->regist_commit_cb) {
572                 private_hwc->regist_commit_cb = 1;
573                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
574                 /* LCOV_EXCL_START */
575                 if (ret != TDM_ERROR_NONE) {
576                         private_hwc->regist_commit_cb = 0;
577                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
578                         _pthread_mutex_unlock(&private_display->lock);
579                         return ret;
580                 /* LCOV_EXCL_STOP */
581                 }
582         }
583
584         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
585         if (!hwc_commit_handler) {
586                 /* LCOV_EXCL_START */
587                 TDM_ERR("failed: alloc memory");
588                 _pthread_mutex_unlock(&private_display->lock);
589                 return TDM_ERROR_OUT_OF_MEMORY;
590                 /* LCOV_EXCL_STOP */
591         }
592
593         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
594                                         _tdm_hwc_thread_cb_commit, NULL);
595         if (ret != TDM_ERROR_NONE) {
596                 TDM_ERR("tdm_thread_cb_add failed");
597                 free(hwc_commit_handler);
598                 _pthread_mutex_unlock(&private_display->lock);
599                 return ret;
600         }
601
602         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
603         hwc_commit_handler->private_hwc = private_hwc;
604         hwc_commit_handler->func = func;
605         hwc_commit_handler->user_data = user_data;
606         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
607
608         if (private_module == private_display->virtual_module) {
609                 private_voutput = private_output->private_voutput;
610
611                 if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
612                         voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
613                         voutput_commit_handler->user_data = private_hwc->display_target_buffer;
614                 }
615         }
616
617         ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
618         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
619
620         if (tdm_debug_module & TDM_DEBUG_COMMIT)
621                 TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
622                                 private_hwc->index, hwc_commit_handler, func, user_data);
623
624         _pthread_mutex_unlock(&private_display->lock);
625
626         return ret;
627
628 commit_failed:
629         /* LCOV_EXCL_START */
630         if (hwc_commit_handler) {
631                 tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
632                                                 _tdm_hwc_thread_cb_commit, NULL);
633                 LIST_DEL(&hwc_commit_handler->link);
634                 free(hwc_commit_handler);
635         }
636
637         _pthread_mutex_unlock(&private_display->lock);
638
639         return ret;
640         /* LCOV_EXCL_STOP */
641 }
642
643 tdm_error
644 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
645 {
646         tdm_private_module *private_module;
647         tdm_func_hwc *func_hwc = NULL;
648
649         HWC_FUNC_ENTRY();
650
651         _pthread_mutex_lock(&private_display->lock);
652
653         private_module = private_hwc->private_module;
654         func_hwc = &private_module->func_hwc;
655
656         if (!func_hwc->hwc_set_property) {
657                 /* LCOV_EXCL_START */
658                 _pthread_mutex_unlock(&private_display->lock);
659                 TDM_WRN("not implemented!!");
660                 return TDM_ERROR_NOT_IMPLEMENTED;
661                 /* LCOV_EXCL_STOP */
662         }
663
664         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
665
666         _pthread_mutex_unlock(&private_display->lock);
667
668         return ret;
669 }
670
671 tdm_error
672 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
673 {
674         tdm_private_module *private_module;
675         tdm_func_hwc *func_hwc = NULL;
676
677         HWC_FUNC_ENTRY();
678
679         _pthread_mutex_lock(&private_display->lock);
680
681         private_module = private_hwc->private_module;
682         func_hwc = &private_module->func_hwc;
683
684         if (!func_hwc->hwc_get_property) {
685                 /* LCOV_EXCL_START */
686                 _pthread_mutex_unlock(&private_display->lock);
687                 TDM_WRN("not implemented!!");
688                 return TDM_ERROR_NOT_IMPLEMENTED;
689                 /* LCOV_EXCL_STOP */
690         }
691
692         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
693
694         _pthread_mutex_unlock(&private_display->lock);
695
696         return ret;
697 }