Package version up to 3.1.8
[platform/core/uifw/libtdm.git] / src / tdm_hwc.c
index 115197c..81fb042 100644 (file)
@@ -70,6 +70,8 @@
        TDM_RETURN_IF_FAIL(private_output != NULL); \
        private_display = private_output->private_display
 
+static int hwc_use_vblank;
+static unsigned int hwc_vblank_fps;
 
 static tdm_private_hwc_window *
 _tdm_hwc_find_private_hwc_window(tdm_private_hwc *private_hwc, tdm_hwc_window *hwc_window_backend)
@@ -84,6 +86,22 @@ _tdm_hwc_find_private_hwc_window(tdm_private_hwc *private_hwc, tdm_hwc_window *h
        return NULL;
 }
 
+static tdm_error
+_tdm_hwc_check_hwc_commit_handler_validation(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
+{
+       tdm_private_hwc_commit_handler *commit_handler = NULL;
+
+       if (LIST_IS_EMPTY(&private_hwc->hwc_commit_handler_list))
+               return TDM_ERROR_INVALID_PARAMETER;
+
+       LIST_FOR_EACH_ENTRY(commit_handler, &private_hwc->hwc_commit_handler_list, link) {
+               if (commit_handler == hwc_commit_handler)
+                       return TDM_ERROR_NONE;
+       }
+
+       return TDM_ERROR_INVALID_PARAMETER;
+}
+
 static void
 _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
                                tdm_thread_cb_base *cb_base, void *user_data)
@@ -102,6 +120,8 @@ _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
        tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
                                        _tdm_hwc_thread_cb_commit, NULL);
 
+       TDM_RETURN_IF_FAIL(_tdm_hwc_check_hwc_commit_handler_validation(private_hwc, hwc_commit_handler) == TDM_ERROR_NONE)
+
        LIST_DEL(&hwc_commit_handler->link);
 
        if (tdm_debug_module & TDM_DEBUG_COMMIT) {
@@ -109,6 +129,28 @@ _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
                TDM_INFO("handler(%p)", hwc_commit_handler);
        }
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_ASYNC_END((intptr_t)hwc_commit_handler, "[HWC_COMMIT~HANDLER] %d",
+                                               private_hwc->private_output->pipe);
+
+       /* LCOV_EXCL_START */
+       if (private_display->print_fps) {
+               double curr = tdm_helper_get_time();
+               if (private_hwc->fps_stamp == 0) {
+                       private_hwc->fps_stamp = curr;
+               } else if ((curr - private_hwc->fps_stamp) > 1.0) {
+                       TDM_INFO("hwc(%p,%d) fps: %d",
+                                        private_hwc, private_hwc->index, private_hwc->fps_count);
+                       private_hwc->fps_count = 0;
+                       private_hwc->fps_stamp = curr;
+               } else
+                       private_hwc->fps_count++;
+       } else if (private_hwc->fps_stamp != 0) {
+               private_hwc->fps_stamp = 0;
+               private_hwc->fps_count = 0;
+       }
+       /* LCOV_EXCL_STOP */
+
        if (hwc_commit_handler->func) {
                _pthread_mutex_unlock(&private_display->lock);
                hwc_commit_handler->func(private_hwc,
@@ -153,6 +195,127 @@ _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
        TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
 }
 
+static void
+_tdm_hwc_cb_commit_hal_tdm(hal_tdm_hwc *hwc_backend, unsigned int sequence,
+                                         unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+       tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
+       tdm_private_hwc *private_hwc;
+       tdm_thread_cb_hwc_commit hwc_commit;
+       tdm_error ret;
+
+       if (hwc_commit_handler)
+               private_hwc = hwc_commit_handler->private_hwc;
+       else
+               private_hwc = tdm_display_find_private_hwc(tdm_display_get(), (tdm_hwc *)hwc_backend);
+
+       memset(&hwc_commit, 0, sizeof hwc_commit);
+       hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
+       hwc_commit.base.length = sizeof hwc_commit;
+       hwc_commit.base.object_stamp = private_hwc->stamp;
+       hwc_commit.base.data = hwc_commit_handler;
+       hwc_commit.base.sync = 0;
+       hwc_commit.sequence = sequence;
+       hwc_commit.tv_sec = tv_sec;
+       hwc_commit.tv_usec = tv_usec;
+
+       ret = tdm_thread_cb_call(private_hwc, &hwc_commit.base, 1);
+       TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+}
+
+/* LCOV_EXCL_START */
+static void
+_tdm_hwc_got_wait_vblank(unsigned int sequence,
+                                                unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+       tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
+       tdm_private_hwc *private_hwc;
+       tdm_thread_cb_hwc_commit hwc_commit;
+
+       private_hwc = hwc_commit_handler->private_hwc;
+       private_hwc->private_output->layer_waiting_vblank = 0;
+
+       memset(&hwc_commit, 0, sizeof hwc_commit);
+       hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
+       hwc_commit.base.length = sizeof hwc_commit;
+       hwc_commit.base.object_stamp = private_hwc->stamp;
+       hwc_commit.base.data = hwc_commit_handler;
+       hwc_commit.base.sync = 0;
+       hwc_commit.sequence = sequence;
+       hwc_commit.tv_sec = tv_sec;
+       hwc_commit.tv_usec = tv_usec;
+
+       _tdm_hwc_thread_cb_commit(private_hwc->private_output->private_display, private_hwc, &hwc_commit.base, user_data);
+}
+
+static void
+_tdm_hwc_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
+                                               unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+{
+       tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
+       tdm_private_output *private_output = NULL;
+       tdm_private_display *private_display;
+
+       if (!hwc_commit_handler->use_vblank)
+               return;
+
+       TDM_RETURN_IF_FAIL(hwc_commit_handler != NULL);
+       TDM_RETURN_IF_FAIL(hwc_commit_handler->private_hwc != NULL);
+
+       private_output = hwc_commit_handler->private_hwc->private_output;
+       TDM_RETURN_IF_FAIL(private_output != NULL);
+
+       private_display = private_output->private_display;
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       _tdm_hwc_got_wait_vblank(sequence, tv_sec, tv_usec, user_data);
+
+       _pthread_mutex_unlock(&private_display->lock);
+}
+
+static tdm_error
+_tdm_hwc_vblank(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
+{
+       tdm_private_display *private_display;
+       tdm_private_output *private_output;
+       tdm_error ret = TDM_ERROR_NONE;
+
+       private_output = private_hwc->private_output;
+       TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       private_display = private_output->private_display;
+
+       if (!private_output->vblank) {
+               /* tdm_vblank APIs is for server. it should be called in unlock status*/
+               _pthread_mutex_unlock(&private_display->lock);
+               private_output->vblank = tdm_vblank_create(private_display, private_output, NULL);
+               _pthread_mutex_lock(&private_display->lock);
+               TDM_RETURN_VAL_IF_FAIL(private_output->vblank != NULL, TDM_ERROR_OPERATION_FAILED);
+       }
+
+       if (!private_output->layer_waiting_vblank) {
+               ret = tdm_vblank_set_fps(private_output->vblank, hwc_vblank_fps);
+               if (ret != TDM_ERROR_NONE)
+                       goto done;
+
+               private_output->layer_waiting_vblank = 1;
+
+               /* tdm_vblank APIs is for server. it should be called in unlock status*/
+               _pthread_mutex_unlock(&private_display->lock);
+               ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_hwc_cb_wait_vblank, hwc_commit_handler);
+               _pthread_mutex_lock(&private_display->lock);
+               if (ret != TDM_ERROR_NONE) {
+                       if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
+                               private_output->layer_waiting_vblank = 0;
+                       }
+               }
+       }
+
+done:
+       return ret;
+}
+/* LCOV_EXCL_STOP */
+
 INTERN tdm_error
 tdm_hwc_init(tdm_private_display *private_display)
 {
@@ -161,6 +324,20 @@ tdm_hwc_init(tdm_private_display *private_display)
        return TDM_ERROR_NONE;
 }
 
+INTERN void
+tdm_hwc_set_vblank(unsigned int fps)
+{
+       hwc_use_vblank = 1;
+       hwc_vblank_fps = fps;
+}
+
+INTERN void
+tdm_hwc_unset_vblank(void)
+{
+       hwc_use_vblank = 0;
+       hwc_vblank_fps = 0;
+}
+
 EXTERN tdm_hwc_window *
 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
 {
@@ -178,7 +355,7 @@ tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
 }
 
 EXTERN tdm_error
-tdm_hwc_get_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
+tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
 {
        tdm_private_module *private_module;
        tdm_func_hwc *func_hwc;
@@ -193,16 +370,83 @@ tdm_hwc_get_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *cou
        private_module = private_output->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_get_supported_formats) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_video_supported_formats((hal_tdm_hwc *)private_hwc->hwc_backend, formats, count);
+       } else {
+               if (!func_hwc->hwc_get_video_supported_formats) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
+       }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_output->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_video_available_properties((hal_tdm_hwc *)private_hwc->hwc_backend,
+                                                                                                                               (const hal_tdm_prop **)props, count);
+       } else {
+               if (!func_hwc->hwc_get_video_available_properties) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
        }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
 
-       ret = func_hwc->hwc_get_supported_formats(private_hwc->hwc_backend, formats, count);
+       private_module = private_output->private_module;
+       func_hwc = &private_module->func_hwc;
 
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_capabilities((hal_tdm_hwc *)private_hwc->hwc_backend, (hal_tdm_hwc_capability *)capabilities);
+       } else {
+               if (!func_hwc->hwc_get_capabilities) {
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+               }
+
+               ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
+       }
        _pthread_mutex_unlock(&private_display->lock);
 
        return ret;
@@ -224,16 +468,19 @@ tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *coun
        private_module = private_output->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_get_available_properties) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
-       }
-
-       ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_available_properties((hal_tdm_hwc *)private_hwc->hwc_backend, (const hal_tdm_prop **)props, count);
+       } else {
+               if (!func_hwc->hwc_get_available_properties) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
 
+               ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
+       }
        _pthread_mutex_unlock(&private_display->lock);
 
        return ret;
@@ -253,19 +500,53 @@ tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_get_client_target_buffer_queue) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return NULL;
-               /* LCOV_EXCL_STOP */
+       if (private_module->use_hal_tdm) {
+               queue = hal_tdm_hwc_get_client_target_buffer_queue((hal_tdm_hwc *)private_hwc->hwc_backend, (hal_tdm_error *)error);
+       } else {
+               if (!func_hwc->hwc_get_client_target_buffer_queue) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return NULL;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
        }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return queue;
+}
+
+EXTERN tdm_error
+tdm_hwc_set_client_target_buffer_info(tdm_hwc *hwc, tdm_hwc_window_info *info)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
 
-       queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_set_client_target_buffer_info((hal_tdm_hwc *)private_hwc->hwc_backend, (hal_tdm_hwc_window_info *)info);
+       } else {
+               if (!func_hwc->hwc_set_client_target_buffer_info) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_set_client_target_buffer_info(private_hwc->hwc_backend, info);
+       }
 
        _pthread_mutex_unlock(&private_display->lock);
 
-       return queue;
+       return ret;
 }
 
 EXTERN tdm_error
@@ -278,6 +559,15 @@ tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC) {
+               if (target_buffer) {
+                       tbm_bo bo = tbm_surface_internal_get_bo(target_buffer, 0);
+                       TDM_TRACE_BEGIN("tdm_hwc_set_client_target_buffer %d", tbm_bo_export(bo));
+               } else {
+                       TDM_TRACE_BEGIN("tdm_hwc_set_client_target_buffer NULL");
+               }
+       }
+
        if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
                /* LCOV_EXCL_START */
                char str[TDM_PATH_LEN];
@@ -290,21 +580,74 @@ tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_set_client_target_buffer) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
+       if (private_module->use_hal_tdm) {
+               hal_tdm_region hdamage;
+               memcpy(&hdamage, &damage, sizeof(hal_tdm_region));
+               ret = (tdm_error)hal_tdm_hwc_set_client_target_buffer((hal_tdm_hwc *)private_hwc->hwc_backend, target_buffer, hdamage);
+       } else {
+               if (!func_hwc->hwc_set_client_target_buffer) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
+       }
+       if (private_hwc->display_target_buffer) {
+               if (private_hwc->display_target_buffer != target_buffer) {
+                       tbm_surface_internal_unref(private_hwc->display_target_buffer);
+                       private_hwc->display_target_buffer = target_buffer;
+                       if (target_buffer)
+                               tbm_surface_internal_ref(private_hwc->display_target_buffer);
+               }
+       } else {
+               if (target_buffer) {
+                       private_hwc->display_target_buffer = target_buffer;
+                       tbm_surface_internal_ref(private_hwc->display_target_buffer);
+               }
        }
 
-       ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
 
        _pthread_mutex_unlock(&private_display->lock);
 
        return ret;
 }
 
+EXTERN tdm_error
+tdm_hwc_set_client_target_acquire_fence(tdm_hwc *hwc, int acquire_fence)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_set_client_target_acquire_fence((hal_tdm_hwc *)private_hwc->hwc_backend, acquire_fence);
+       } else {
+               if (!func_hwc->hwc_set_client_target_acquire_fence) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_set_client_target_acquire_fence(private_hwc->hwc_backend, acquire_fence);
+       }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
 
 EXTERN tdm_error
 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
@@ -321,29 +664,36 @@ tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wn
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_validate) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
-       }
-
-       if (num_wnds == 0) {
-               ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
+       if (private_module->use_hal_tdm) {
+               if (num_wnds == 0) {
+                       ret = (tdm_error)hal_tdm_hwc_validate((hal_tdm_hwc *)private_hwc->hwc_backend, NULL, 0, num_types);
+                       goto done;
+               }
+       } else {
+               if (!func_hwc->hwc_validate) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
 
-               _pthread_mutex_unlock(&private_display->lock);
-               return ret;
+               if (num_wnds == 0) {
+                       ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
+                       goto done;
+               }
        }
-
        composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
        if (!composited_wnds_backend) {
                /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               return TDM_ERROR_OUT_OF_MEMORY;
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               goto done;
                /* LCOV_EXCL_STOP */
        }
 
@@ -352,11 +702,19 @@ tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wn
        for (i = 0; i < num_wnds; i++)
                composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
 
-       ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
-                                                               num_wnds, num_types);
+       if (private_module->use_hal_tdm)
+               ret = (tdm_error)hal_tdm_hwc_validate((hal_tdm_hwc *)private_hwc->hwc_backend, (hal_tdm_hwc_window **)composited_wnds_backend,
+                                                                       num_wnds, num_types);
+       else
+               ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
+                                                                       num_wnds, num_types);
 
        free(composited_wnds_backend);
 
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
+
        _pthread_mutex_unlock(&private_display->lock);
 
        return ret;
@@ -378,29 +736,36 @@ tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_get_changed_composition_types) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
-       }
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_changed_composition_types((hal_tdm_hwc *)private_hwc->hwc_backend, num_elements,
+                                                                       (hal_tdm_hwc_window **)hwc_window,
+                                                                       (hal_tdm_hwc_window_composition *)composition_types);
+       } else {
+               if (!func_hwc->hwc_get_changed_composition_types) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
 
-       ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
-                                                       num_elements, hwc_window, composition_types);
+               ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
+                                                               num_elements, hwc_window, composition_types);
+       }
        if (ret != TDM_ERROR_NONE) {
                /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               return ret;
+               goto done;
                /* LCOV_EXCL_STOP */
        }
 
        if (hwc_window == NULL || composition_types == NULL) {
-               _pthread_mutex_unlock(&private_display->lock);
-               return TDM_ERROR_NONE;
+               goto done;
        }
 
        for (i = 0; i < *num_elements; i++) {
@@ -410,21 +775,25 @@ tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
                        TDM_ERR("failed! This should never happen!");
                        tdm_hwc_window_destroy_internal(private_hwc_window);
                        *num_elements = 0;
-                       _pthread_mutex_unlock(&private_display->lock);
-                       return TDM_ERROR_OPERATION_FAILED;
+                       ret = TDM_ERROR_OPERATION_FAILED;
+                       goto done;
                        /* LCOV_EXCL_STOP */
                }
 
                hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
        }
 
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
+
        _pthread_mutex_unlock(&private_display->lock);
 
        return ret;
 }
 
 EXTERN tdm_error
-tdm_hwc_accept_changes(tdm_hwc *hwc)
+tdm_hwc_accept_validation(tdm_hwc *hwc)
 {
        tdm_private_module *private_module;
        tdm_func_hwc *func_hwc = NULL;
@@ -433,18 +802,29 @@ tdm_hwc_accept_changes(tdm_hwc *hwc)
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_validate) {
-               /* LCOV_EXCL_START */
-               _pthread_mutex_unlock(&private_display->lock);
-               TDM_WRN("not implemented!!");
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_accept_validation((hal_tdm_hwc *)private_hwc->hwc_backend);
+       } else {
+               if (!func_hwc->hwc_validate) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
        }
 
-       ret = func_hwc->hwc_accept_changes(private_hwc->hwc_backend);
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -457,20 +837,27 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
        tdm_private_module *private_module;
        tdm_func_hwc *func_hwc = NULL;
        tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
+       tdm_private_voutput *private_voutput = NULL;
+       tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
 
        HWC_FUNC_ENTRY();
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
        private_module = private_hwc->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_commit) {
-               /* LCOV_EXCL_START */
-               TDM_WRN("not implemented!!");
-               _pthread_mutex_unlock(&private_display->lock);
-               return TDM_ERROR_NOT_IMPLEMENTED;
-               /* LCOV_EXCL_STOP */
+       if (!private_module->use_hal_tdm) {
+               if (!func_hwc->hwc_commit) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
        }
 
 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
@@ -487,15 +874,25 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
        if (tdm_debug_module & TDM_DEBUG_COMMIT)
                TDM_INFO("hwc(%d) commit", private_hwc->index);
 
+       if (private_module == private_display->virtual_module) {
+               if (!private_output->private_voutput) {
+                       TDM_ERR("virtual module but don't have voutput");
+                       ret = TDM_ERROR_BAD_MODULE;
+                       goto done;
+               }
+       }
+
        if (!private_hwc->regist_commit_cb) {
                private_hwc->regist_commit_cb = 1;
-               ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
+               if (private_module->use_hal_tdm)
+                       ret = (tdm_error)hal_tdm_hwc_set_commit_handler((hal_tdm_hwc *)private_hwc->hwc_backend, _tdm_hwc_cb_commit_hal_tdm);
+               else
+                       ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
                /* LCOV_EXCL_START */
                if (ret != TDM_ERROR_NONE) {
                        private_hwc->regist_commit_cb = 0;
                        TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
-                       _pthread_mutex_unlock(&private_display->lock);
-                       return ret;
+                       goto done;
                /* LCOV_EXCL_STOP */
                }
        }
@@ -504,8 +901,8 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
        if (!hwc_commit_handler) {
                /* LCOV_EXCL_START */
                TDM_ERR("failed: alloc memory");
-               _pthread_mutex_unlock(&private_display->lock);
-               return TDM_ERROR_OUT_OF_MEMORY;
+               ret = TDM_ERROR_OUT_OF_MEMORY;
+               goto done;
                /* LCOV_EXCL_STOP */
        }
 
@@ -514,7 +911,7 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
        if (ret != TDM_ERROR_NONE) {
                TDM_ERR("tdm_thread_cb_add failed");
                free(hwc_commit_handler);
-               return ret;
+               goto done;
        }
 
        LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
@@ -523,12 +920,52 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
        hwc_commit_handler->user_data = user_data;
        hwc_commit_handler->owner_tid = syscall(SYS_gettid);
 
-       ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
-       TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
+       if (private_module == private_display->virtual_module) {
+               private_voutput = private_output->private_voutput;
 
-       if (tdm_debug_module & TDM_DEBUG_COMMIT)
-               TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
-                               private_hwc->index, hwc_commit_handler, func, user_data);
+               if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
+                       voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
+                       voutput_commit_handler->user_data = private_hwc->display_target_buffer;
+               }
+       }
+
+       if (hwc_use_vblank) {
+               /* LCOV_EXCL_START */
+               hwc_commit_handler->use_vblank = 1;
+
+               if (private_module->use_hal_tdm)
+                       ret = (tdm_error)hal_tdm_hwc_commit((hal_tdm_hwc *)private_hwc->hwc_backend, sync, NULL);
+               else
+                       ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, NULL);
+               TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
+
+               ret = _tdm_hwc_vblank(private_hwc, hwc_commit_handler);
+               if (ret == TDM_ERROR_NONE) {
+                       if (tdm_debug_module & TDM_DEBUG_COMMIT)
+                               TDM_INFO("hwc(%d) backend commit: wait vblank handle(%p) func(%p) user_data(%p)",
+                                       private_hwc->index, hwc_commit_handler, func, user_data);
+               } else
+                       goto commit_failed;
+               /* LCOV_EXCL_STOP */
+       } else {
+               if (private_module->use_hal_tdm)
+                       ret = (tdm_error)hal_tdm_hwc_commit((hal_tdm_hwc *)private_hwc->hwc_backend, sync, hwc_commit_handler);
+               else
+                       ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
+               TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
+
+               if (tdm_debug_module & TDM_DEBUG_COMMIT)
+                       TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
+                                       private_hwc->index, hwc_commit_handler, func, user_data);
+       }
+
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_ASYNC_BEGIN((intptr_t)hwc_commit_handler, "[HWC_COMMIT~HANDLER] %d",
+                                                       private_hwc->private_output->pipe);
+
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -536,6 +973,9 @@ tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_d
 
 commit_failed:
        /* LCOV_EXCL_START */
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
+
        if (hwc_commit_handler) {
                tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
                                                _tdm_hwc_thread_cb_commit, NULL);
@@ -547,4 +987,201 @@ commit_failed:
 
        return ret;
        /* LCOV_EXCL_STOP */
-}
\ No newline at end of file
+}
+
+EXTERN tdm_error
+tdm_hwc_get_commit_fence(tdm_hwc *hwc, int *commit_fence)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_commit_fence((hal_tdm_hwc *)private_hwc->hwc_backend, commit_fence);
+       } else {
+               if (!func_hwc->hwc_get_commit_fence) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_get_commit_fence(private_hwc->hwc_backend, commit_fence);
+       }
+
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+EXTERN tdm_error
+tdm_hwc_get_release_fences(tdm_hwc *hwc, uint32_t *num_elements,
+                                               tdm_hwc_window **hwc_windows, int *fences)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+       tdm_private_hwc_window *private_hwc_window = NULL;
+       int i;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_BEGIN(__FUNCTION__);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_release_fences((hal_tdm_hwc *)private_hwc->hwc_backend, num_elements,
+                                                                                       (hal_tdm_hwc_window **)hwc_windows, fences);
+       } else {
+               if (!func_hwc->hwc_get_release_fences) {
+                       /* LCOV_EXCL_START */
+                       TDM_WRN("not implemented!!");
+                       ret = TDM_ERROR_NOT_IMPLEMENTED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_get_release_fences(private_hwc->hwc_backend, num_elements,
+                                                                                       hwc_windows, fences);
+       }
+       if (hwc_windows == NULL || fences == NULL)
+               goto done;
+
+       for (i = 0; i < *num_elements; i++) {
+               private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_windows[i]);
+               if (private_hwc_window == NULL) {
+                       /* LCOV_EXCL_START */
+                       TDM_ERR("failed! This should never happen!");
+                       tdm_hwc_window_destroy_internal(private_hwc_window);
+                       *num_elements = 0;
+                       ret = TDM_ERROR_OPERATION_FAILED;
+                       goto done;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               hwc_windows[i] = (tdm_hwc_window*)private_hwc_window;
+       }
+
+done:
+       if (tdm_ttrace_module & TDM_TTRACE_HWC)
+               TDM_TRACE_END();
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+tdm_error
+tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               hal_tdm_value hvalue;
+               memcpy(&hvalue.ptr, &value.ptr, sizeof(hal_tdm_value));
+               ret = (tdm_error)hal_tdm_hwc_set_property((hal_tdm_hwc *)private_hwc->hwc_backend, id, hvalue);
+       } else {
+               if (!func_hwc->hwc_set_property) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
+       }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+tdm_error
+tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               hal_tdm_value hvalue;
+               ret = (tdm_error)hal_tdm_hwc_get_property((hal_tdm_hwc *)private_hwc->hwc_backend, id, &hvalue);
+               if (ret == TDM_ERROR_NONE)
+                       memcpy(&value->ptr, &hvalue.ptr, sizeof(tdm_value));
+       } else {
+               if (!func_hwc->hwc_get_property) {
+                       /* LCOV_EXCL_START */
+                       _pthread_mutex_unlock(&private_display->lock);
+                       TDM_WRN("not implemented!!");
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+                       /* LCOV_EXCL_STOP */
+               }
+
+               ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
+       }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
+tdm_error
+tdm_hwc_get_commit_interval(tdm_hwc *hwc, tdm_hwc_commit_interval *refresh)
+{
+       tdm_private_module *private_module;
+       tdm_func_hwc *func_hwc = NULL;
+
+       HWC_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (private_module->use_hal_tdm) {
+               ret = (tdm_error)hal_tdm_hwc_get_commit_interval((hal_tdm_hwc *)private_hwc->hwc_backend, (hal_tdm_hwc_commit_interval *)refresh);
+       } else {
+               /* LCOV_EXCL_START */
+               if (!func_hwc->hwc_get_commit_interval) {
+                       _pthread_mutex_unlock(&private_display->lock);
+                       return TDM_ERROR_NOT_IMPLEMENTED;
+               }
+
+               ret = func_hwc->hwc_get_commit_interval(private_hwc->hwc_backend, refresh);
+               /* LCOV_EXCL_STOP */
+       }
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}