+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;
+}
+