Merge branch 'tizen' into sandbox/cyeon/devel
[platform/core/uifw/libtdm.git] / src / tdm_hwc.c
index 013eb34..9238b29 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,24 @@ _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
                TDM_INFO("handler(%p)", hwc_commit_handler);
        }
 
+       /* 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,
@@ -134,6 +172,9 @@ _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
        tdm_thread_cb_hwc_commit hwc_commit;
        tdm_error ret;
 
+       if (hwc_commit_handler && hwc_commit_handler->use_vblank)
+               return;
+
        if (hwc_commit_handler)
                private_hwc = hwc_commit_handler->private_hwc;
        else
@@ -153,6 +194,99 @@ _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
        TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
 }
 
+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;
+
+               hwc_commit_handler->use_vblank = 1;
+               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)) {
+                               hwc_commit_handler->use_vblank = 0;
+                               private_output->layer_waiting_vblank = 0;
+                       }
+               }
+       }
+
+done:
+       return ret;
+}
+
 INTERN tdm_error
 tdm_hwc_init(tdm_private_display *private_display)
 {
@@ -161,6 +295,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)
 {
@@ -209,8 +357,38 @@ tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, in
 }
 
 EXTERN tdm_error
-tdm_hwc_get_video_capability(tdm_hwc *hwc,
-                                                       tdm_hwc_video_capability *video_capability)
+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 (!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;
@@ -222,14 +400,13 @@ tdm_hwc_get_video_capability(tdm_hwc *hwc,
        private_module = private_output->private_module;
        func_hwc = &private_module->func_hwc;
 
-       if (!func_hwc->hwc_get_video_capability) {
+       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_video_capability(private_hwc->hwc_backend,
-                                                                                       video_capability);
+       ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -328,11 +505,52 @@ tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_
 
        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);
+               }
+       }
+
        _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 (!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)
@@ -485,6 +703,8 @@ 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();
 
@@ -515,6 +735,14 @@ 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");
+                       _pthread_mutex_unlock(&private_display->lock);
+                       return TDM_ERROR_BAD_MODULE;
+               }
+       }
+
        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);
@@ -552,12 +780,31 @@ 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);
 
+       if (private_module == private_display->virtual_module) {
+               private_voutput = private_output->private_voutput;
+
+               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;
+               }
+       }
+
        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 (hwc_use_vblank) {
+               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;
+       } else {
+               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);
+       }
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -576,4 +823,88 @@ 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);
+
+       private_module = private_hwc->private_module;
+       func_hwc = &private_module->func_hwc;
+
+       if (!func_hwc->hwc_get_commit_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_get_commit_fence(private_hwc->hwc_backend, commit_fence);
+
+       _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 (!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 (!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;
+}