From 5c085284e4ee58080f4a67f6dc9914ac9c2e49cf Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Sep 2017 14:35:40 +0900 Subject: [PATCH] use SW timer when output disconnected If enable_fake == 1, use SW timer when output disconnected as well as DPMS off. Change-Id: I9e528b6eb6749d099c6b8f7ff765ce46a7728f5a --- client/tdm_client.c | 22 ++++++++--- client/tdm_client.h | 14 +++++-- src/tdm_vblank.c | 93 ++++++++++++++++++++++++++++++++------------- 3 files changed, 92 insertions(+), 37 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 6ab849d0..d80100da 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -833,11 +833,16 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli if (!private_vblank->started) private_vblank->started = 1; - if (private_output->watch_output_changes) - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); + if (private_output->watch_output_changes && !private_vblank->enable_fake) { + if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + TDM_ERR("output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { + TDM_ERR("dpms off"); return TDM_ERROR_DPMS_OFF; } + } w = calloc(1, sizeof *w); if (!w) { @@ -910,11 +915,16 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, if (!private_vblank->started) private_vblank->started = 1; - if (private_output->watch_output_changes) - if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - TDM_INFO("dpms off"); + if (private_output->watch_output_changes && !private_vblank->enable_fake) { + if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + TDM_ERR("output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_output->dpms != TDM_OUTPUT_DPMS_ON) { + TDM_ERR("dpms off"); return TDM_ERROR_DPMS_OFF; } + } w = calloc(1, sizeof *w); if (!w) { diff --git a/client/tdm_client.h b/client/tdm_client.h index 8a2fcd0b..175bb455 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -226,6 +226,12 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms); /** * @brief Create the client vblank object of the given client output + * @details + * tdm client vblank basically uses the HW vblank resource. Therefore, if HW vblank + * is not available for some reasons, such as output disconnection and dpms off, + * #tdm_client_vblank_wait will return error. If you want it to work propery in spite + * of these reasons, you can use #tdm_client_vblank_set_enable_fake to get SW fake + * vblank events. * @param[in] output The client output object * @param[out] error #TDM_ERROR_NONE if success. Otherwise, error value. * @return A client vblank object if success. Otherwise, NULL. @@ -286,8 +292,8 @@ tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms); /** * @brief Enable/Disable the fake vblank to the client vblank object * @details - * If enable_fake == 0, #tdm_client_vblank_wait will return TDM_ERROR_DPMS_OFF - * when DPMS off. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE + * If enable_fake == 0, #tdm_client_vblank_wait will return error when HW vblank is + * not available. Otherwise, #tdm_client_vblank_wait will return TDM_ERROR_NONE * as success. Once #tdm_client_vblank_wait returns TDM_ERROR_NONE, the user client * vblank handler(#tdm_client_vblank_handler) SHOULD be called after the given * interval of #tdm_client_vblank_wait. Default is @b disable. @@ -301,7 +307,7 @@ tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable /** * @brief Wait for a vblank * @details - * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However, + * This function will return error when HW vblank resource is not available. However, * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler) @@ -389,7 +395,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli /** * @brief Wait for a vblank with the target sequence number * @details - * This function will return TDM_ERROR_DPMS_OFF when DPMS off. However, + * This function will return error when HW vblank resource is not available. However, * #tdm_client_vblank_wait will return TDM_ERROR_NONE as success if * #tdm_client_vblank_set_enable_fake sets true. Once #tdm_client_vblank_wait_seq * returns TDM_ERROR_NONE, the user client vblank handler(#tdm_client_vblank_handler) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 97deab54..337e7cf3 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -54,6 +54,8 @@ * - use a tdm_event_loop_source object only. */ +#define TDM_VBLANK_DEFAULT_VREFRESH 30 + /* We expact "(unsigned int)(0.0016667 / 0.0016667) = 1". But it becomes 0. */ #define TDM_TIME_MARGIN 0.0000001 @@ -89,12 +91,14 @@ typedef struct _tdm_private_vblank { tdm_display *dpy; tdm_output *output; + tdm_output_conn_status connection; tdm_output_dpms dpms; unsigned int vrefresh; unsigned int check_HW_or_SW; char name[TDM_NAME_LEN]; unsigned int fps; + unsigned int fps_changeable; int offset; unsigned int enable_fake; unsigned int ignore_global_fps; @@ -307,6 +311,39 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un } } +static void +_tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) +{ + tdm_output *output = private_vblank->output; + tdm_output_conn_status connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + tdm_output_dpms dpms = TDM_OUTPUT_DPMS_OFF; + unsigned int vrefresh = 0; + + tdm_output_get_conn_status(output, &connection); + + if (connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + const tdm_output_mode *mode = NULL; + tdm_output_get_mode(output, &mode); + vrefresh = (mode) ? mode->vrefresh : 0; + tdm_output_get_dpms(output, &dpms); + } + + if (vrefresh == 0) + vrefresh = TDM_VBLANK_DEFAULT_VREFRESH; + + private_vblank->dpms = dpms; + private_vblank->connection = connection; + private_vblank->vrefresh = vrefresh; + private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh; + + if (private_vblank->fps_changeable) + private_vblank->fps = vrefresh; + + VDB("dpms(%d) connection(%d) vrefresh(%d) fps(%d)", + private_vblank->dpms, private_vblank->connection, + private_vblank->vrefresh, private_vblank->fps); +} + static void _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, tdm_value value, void *user_data) @@ -320,7 +357,7 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, if (private_vblank->dpms == value.u32) break; VDB("dpms %s", tdm_dpms_str(value.u32)); - private_vblank->dpms = value.u32; + _tdm_vblank_update_output_info(private_vblank); private_vblank->check_HW_or_SW = 1; if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { if (private_vblank->enable_fake) @@ -330,9 +367,17 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, } break; case TDM_OUTPUT_CHANGE_CONNECTION: + if (private_vblank->connection == value.u32) + break; VDB("output %s", tdm_status_str(value.u32)); - if (value.u32 == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) - _tdm_vblank_free_HW_wait(private_vblank, 0, 0); + _tdm_vblank_update_output_info(private_vblank); + private_vblank->check_HW_or_SW = 1; + if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + if (private_vblank->enable_fake) + _tdm_vblank_change_to_SW(private_vblank); + else + _tdm_vblank_free_HW_wait(private_vblank, TDM_ERROR_OUTPUT_DISCONNECTED, 1); + } break; default: break; @@ -410,8 +455,6 @@ EXTERN tdm_vblank * tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) { tdm_private_vblank *private_vblank; - const tdm_output_mode *mode = NULL; - tdm_output_dpms dpms = TDM_OUTPUT_DPMS_ON; tdm_error ret; TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); @@ -432,16 +475,6 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) vblank_list_inited = 1; } - tdm_output_get_mode(output, &mode); - if (!mode) { - if (error) - *error = TDM_ERROR_OPERATION_FAILED; - TDM_ERR("no mode"); - return NULL; - } - - tdm_output_get_dpms(output, &dpms); - private_vblank = calloc(1, sizeof * private_vblank); if (!private_vblank) { if (error) @@ -456,12 +489,10 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) private_vblank->owner_tid = syscall(SYS_gettid); private_vblank->dpy = dpy; private_vblank->output = output; - private_vblank->dpms = dpms; - private_vblank->vrefresh = mode->vrefresh; - private_vblank->HW_vblank_gap = 1.0 / private_vblank->vrefresh; - private_vblank->check_HW_or_SW = 1; - private_vblank->fps = mode->vrefresh; + private_vblank->fps_changeable = 1; + + _tdm_vblank_update_output_info(private_vblank); strncpy(private_vblank->name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1); private_vblank->name[TDM_NAME_LEN - 1] = '\0'; @@ -472,8 +503,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) _tdm_vblank_valid_list_add(&private_vblank->valid_link, &valid_vblank_list); if (tdm_debug_module & TDM_DEBUG_VBLANK) - VIN("created. vrefresh(%d) dpms(%d)", - private_vblank->vrefresh, private_vblank->dpms); + VIN("created. vrefresh(%d) dpms(%d) connection(%d)", + private_vblank->vrefresh, private_vblank->dpms, private_vblank->connection); return (tdm_vblank *)private_vblank; } @@ -556,6 +587,7 @@ tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) return TDM_ERROR_NONE; private_vblank->fps = fps; + private_vblank->fps_changeable = 0; private_vblank->check_HW_or_SW = 1; if (tdm_debug_module & TDM_DEBUG_VBLANK) @@ -1022,9 +1054,15 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, return TDM_ERROR_BAD_REQUEST; } - if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) { - VIN("can't wait a vblank because of DPMS off"); - return TDM_ERROR_DPMS_OFF; + if (!private_vblank->enable_fake) { + if (private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) { + VIN("can't wait a vblank: output disconnected"); + return TDM_ERROR_OUTPUT_DISCONNECTED; + } + if (private_vblank->dpms != TDM_OUTPUT_DPMS_ON) { + VIN("can't wait a vblank: DPMS off"); + return TDM_ERROR_DPMS_OFF; + } } wait_info = calloc(1, sizeof * wait_info); @@ -1072,7 +1110,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, */ if (private_vblank->vrefresh % fps) wait_info->type = VBLANK_TYPE_SW; - else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF) + else if (private_vblank->dpms == TDM_OUTPUT_DPMS_OFF || + private_vblank->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) wait_info->type = VBLANK_TYPE_SW_FAKE; else if (private_vblank->offset == 0) wait_info->type = VBLANK_TYPE_HW; @@ -1083,7 +1122,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, ret = _tdm_vblank_wait_SW(wait_info); else { ret = _tdm_vblank_wait_HW(wait_info); - if (ret == TDM_ERROR_DPMS_OFF) + if (ret == TDM_ERROR_OUTPUT_DISCONNECTED || ret == TDM_ERROR_DPMS_OFF) ret = _tdm_vblank_wait_SW(wait_info); } -- 2.34.1