drm/amd/display: Add flip interval workaround
[WHY] Some games experience low FPS issues when FreeSync is on and VSync is toggled to half refresh rate. [HOW] First create a function to determine workaround conditions, which is when we detect 2 or more VSync interrupts between flips and a very short VSync to flip interval. We do the workaround during VSync interrupts and set the v_total_max and min to nominal. We also cleanup after we exit the game. Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Tom Chung <chiahsuan.chung@amd.com> Signed-off-by: Angus Wang <Angus.Wang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
35b2186b13
commit
3fe5739db4
2 changed files with 85 additions and 1 deletions
|
@ -29,6 +29,7 @@
|
||||||
#include "dc.h"
|
#include "dc.h"
|
||||||
#include "mod_freesync.h"
|
#include "mod_freesync.h"
|
||||||
#include "core_types.h"
|
#include "core_types.h"
|
||||||
|
#include "dm_services.h"
|
||||||
|
|
||||||
#define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
|
#define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32
|
||||||
|
|
||||||
|
@ -46,6 +47,10 @@
|
||||||
/* Number of consecutive frames to check before entering/exiting fixed refresh */
|
/* Number of consecutive frames to check before entering/exiting fixed refresh */
|
||||||
#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
|
#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
|
||||||
#define FIXED_REFRESH_EXIT_FRAME_COUNT 10
|
#define FIXED_REFRESH_EXIT_FRAME_COUNT 10
|
||||||
|
/* Flip interval workaround constants */
|
||||||
|
#define VSYNCS_BETWEEN_FLIP_THRESHOLD 2
|
||||||
|
#define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5
|
||||||
|
#define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500
|
||||||
|
|
||||||
struct core_freesync {
|
struct core_freesync {
|
||||||
struct mod_freesync public;
|
struct mod_freesync public;
|
||||||
|
@ -466,6 +471,41 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void determine_flip_interval_workaround_req(struct mod_vrr_params *in_vrr,
|
||||||
|
unsigned int curr_time_stamp_in_us)
|
||||||
|
{
|
||||||
|
in_vrr->flip_interval.vsync_to_flip_in_us = curr_time_stamp_in_us -
|
||||||
|
in_vrr->flip_interval.v_update_timestamp_in_us;
|
||||||
|
|
||||||
|
/* Determine conditions for stopping workaround */
|
||||||
|
if (in_vrr->flip_interval.flip_interval_workaround_active &&
|
||||||
|
in_vrr->flip_interval.vsyncs_between_flip < VSYNCS_BETWEEN_FLIP_THRESHOLD &&
|
||||||
|
in_vrr->flip_interval.vsync_to_flip_in_us > FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
|
||||||
|
in_vrr->flip_interval.flip_interval_detect_counter = 0;
|
||||||
|
in_vrr->flip_interval.program_flip_interval_workaround = true;
|
||||||
|
in_vrr->flip_interval.flip_interval_workaround_active = false;
|
||||||
|
} else {
|
||||||
|
/* Determine conditions for starting workaround */
|
||||||
|
if (in_vrr->flip_interval.vsyncs_between_flip >= VSYNCS_BETWEEN_FLIP_THRESHOLD &&
|
||||||
|
in_vrr->flip_interval.vsync_to_flip_in_us < FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
|
||||||
|
/* Increase flip interval counter we have 2 vsyncs between flips and
|
||||||
|
* vsync to flip interval is less than 500us
|
||||||
|
*/
|
||||||
|
in_vrr->flip_interval.flip_interval_detect_counter++;
|
||||||
|
if (in_vrr->flip_interval.flip_interval_detect_counter > FREESYNC_CONSEC_FLIP_AFTER_VSYNC) {
|
||||||
|
/* Start workaround if we detect 5 consecutive instances of the above case */
|
||||||
|
in_vrr->flip_interval.program_flip_interval_workaround = true;
|
||||||
|
in_vrr->flip_interval.flip_interval_workaround_active = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Reset the flip interval counter if we condition is no longer met */
|
||||||
|
in_vrr->flip_interval.flip_interval_detect_counter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in_vrr->flip_interval.vsyncs_between_flip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool vrr_settings_require_update(struct core_freesync *core_freesync,
|
static bool vrr_settings_require_update(struct core_freesync *core_freesync,
|
||||||
struct mod_freesync_config *in_config,
|
struct mod_freesync_config *in_config,
|
||||||
unsigned int min_refresh_in_uhz,
|
unsigned int min_refresh_in_uhz,
|
||||||
|
@ -1179,6 +1219,9 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
|
||||||
in_out_vrr);
|
in_out_vrr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
determine_flip_interval_workaround_req(in_out_vrr,
|
||||||
|
curr_time_stamp_in_us);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,6 +1230,7 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
|
||||||
struct mod_vrr_params *in_out_vrr)
|
struct mod_vrr_params *in_out_vrr)
|
||||||
{
|
{
|
||||||
struct core_freesync *core_freesync = NULL;
|
struct core_freesync *core_freesync = NULL;
|
||||||
|
unsigned int cur_timestamp_in_us;
|
||||||
|
|
||||||
if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
|
if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
|
||||||
return;
|
return;
|
||||||
|
@ -1196,6 +1240,34 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
|
||||||
if (in_out_vrr->supported == false)
|
if (in_out_vrr->supported == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
cur_timestamp_in_us = dm_get_timestamp(core_freesync->dc->ctx)/10;
|
||||||
|
|
||||||
|
in_out_vrr->flip_interval.vsyncs_between_flip++;
|
||||||
|
in_out_vrr->flip_interval.v_update_timestamp_in_us = cur_timestamp_in_us;
|
||||||
|
|
||||||
|
if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
|
||||||
|
(in_out_vrr->flip_interval.flip_interval_workaround_active ||
|
||||||
|
(!in_out_vrr->flip_interval.flip_interval_workaround_active &&
|
||||||
|
in_out_vrr->flip_interval.program_flip_interval_workaround))) {
|
||||||
|
// set freesync vmin vmax to nominal for workaround
|
||||||
|
in_out_vrr->adjust.v_total_min =
|
||||||
|
mod_freesync_calc_v_total_from_refresh(
|
||||||
|
stream, in_out_vrr->max_refresh_in_uhz);
|
||||||
|
in_out_vrr->adjust.v_total_max =
|
||||||
|
in_out_vrr->adjust.v_total_min;
|
||||||
|
in_out_vrr->flip_interval.program_flip_interval_workaround = false;
|
||||||
|
in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_out_vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
|
||||||
|
in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup) {
|
||||||
|
in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = false;
|
||||||
|
in_out_vrr->flip_interval.flip_interval_detect_counter = 0;
|
||||||
|
in_out_vrr->flip_interval.vsyncs_between_flip = 0;
|
||||||
|
in_out_vrr->flip_interval.vsync_to_flip_in_us = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Below the Range Logic */
|
/* Below the Range Logic */
|
||||||
|
|
||||||
/* Only execute if in fullscreen mode */
|
/* Only execute if in fullscreen mode */
|
||||||
|
|
|
@ -105,6 +105,16 @@ struct mod_vrr_params_fixed_refresh {
|
||||||
uint32_t frame_counter;
|
uint32_t frame_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mod_vrr_params_flip_interval {
|
||||||
|
bool flip_interval_workaround_active;
|
||||||
|
bool program_flip_interval_workaround;
|
||||||
|
bool do_flip_interval_workaround_cleanup;
|
||||||
|
uint32_t flip_interval_detect_counter;
|
||||||
|
uint32_t vsyncs_between_flip;
|
||||||
|
uint32_t vsync_to_flip_in_us;
|
||||||
|
uint32_t v_update_timestamp_in_us;
|
||||||
|
};
|
||||||
|
|
||||||
struct mod_vrr_params {
|
struct mod_vrr_params {
|
||||||
bool supported;
|
bool supported;
|
||||||
bool send_info_frame;
|
bool send_info_frame;
|
||||||
|
@ -121,6 +131,8 @@ struct mod_vrr_params {
|
||||||
struct mod_vrr_params_fixed_refresh fixed;
|
struct mod_vrr_params_fixed_refresh fixed;
|
||||||
|
|
||||||
struct mod_vrr_params_btr btr;
|
struct mod_vrr_params_btr btr;
|
||||||
|
|
||||||
|
struct mod_vrr_params_flip_interval flip_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mod_freesync *mod_freesync_create(struct dc *dc);
|
struct mod_freesync *mod_freesync_create(struct dc *dc);
|
||||||
|
|
Loading…
Add table
Reference in a new issue