mirror of
https://github.com/libretro/RetroArch
synced 2025-04-16 08:43:10 +00:00
'Automatic Frame Delay' improvements: (#13297)
- swap interval handling - d3dx handling
This commit is contained in:
parent
72e49d82d6
commit
121ca3a482
@ -3975,3 +3975,163 @@ void video_driver_reinit(int flags)
|
|||||||
video_driver_reinit_context(settings, flags);
|
video_driver_reinit_context(settings, flags);
|
||||||
video_st->cache_context = false;
|
video_st->cache_context = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FRAME_DELAY_AUTO_DEBUG 0
|
||||||
|
void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_auto_t *vfda)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
unsigned frame_time = 0;
|
||||||
|
unsigned frame_time_frames = vfda->frame_time_interval;
|
||||||
|
unsigned frame_time_target = 1000000.0f / vfda->refresh_rate;
|
||||||
|
unsigned frame_time_limit_min = frame_time_target * 1.30f;
|
||||||
|
unsigned frame_time_limit_med = frame_time_target * 1.50f;
|
||||||
|
unsigned frame_time_limit_max = frame_time_target * 1.90f;
|
||||||
|
unsigned frame_time_limit_cap = frame_time_target * 2.50f;
|
||||||
|
unsigned frame_time_limit_ign = frame_time_target * 3.75f;
|
||||||
|
unsigned frame_time_min = frame_time_target;
|
||||||
|
unsigned frame_time_max = frame_time_target;
|
||||||
|
unsigned frame_time_count_pos = 0;
|
||||||
|
unsigned frame_time_count_min = 0;
|
||||||
|
unsigned frame_time_count_med = 0;
|
||||||
|
unsigned frame_time_count_max = 0;
|
||||||
|
unsigned frame_time_count_ign = 0;
|
||||||
|
unsigned frame_time_index =
|
||||||
|
(video_st->frame_time_count &
|
||||||
|
(MEASURE_FRAME_TIME_SAMPLES_COUNT - 1));
|
||||||
|
|
||||||
|
/* Calculate average frame time */
|
||||||
|
for (i = 1; i < frame_time_frames + 1; i++)
|
||||||
|
{
|
||||||
|
unsigned frame_time_i = 0;
|
||||||
|
|
||||||
|
if (i > frame_time_index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
frame_time_i = video_st->frame_time_samples[frame_time_index - i];
|
||||||
|
|
||||||
|
if (frame_time_max < frame_time_i)
|
||||||
|
frame_time_max = frame_time_i;
|
||||||
|
if (frame_time_min > frame_time_i)
|
||||||
|
frame_time_min = frame_time_i;
|
||||||
|
|
||||||
|
/* Count frames over the target */
|
||||||
|
if (frame_time_i > frame_time_target)
|
||||||
|
{
|
||||||
|
frame_time_count_pos++;
|
||||||
|
if (frame_time_i > frame_time_limit_min)
|
||||||
|
frame_time_count_min++;
|
||||||
|
if (frame_time_i > frame_time_limit_med)
|
||||||
|
frame_time_count_med++;
|
||||||
|
if (frame_time_i > frame_time_limit_max)
|
||||||
|
frame_time_count_max++;
|
||||||
|
if (frame_time_i > frame_time_limit_ign)
|
||||||
|
frame_time_count_ign++;
|
||||||
|
|
||||||
|
/* Limit maximum to prevent false positives */
|
||||||
|
if (frame_time_i > frame_time_limit_cap)
|
||||||
|
frame_time_i = frame_time_limit_cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_time += frame_time_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_time /= frame_time_frames;
|
||||||
|
|
||||||
|
/* Ignore values when core is doing internal frame skipping */
|
||||||
|
if (frame_time_count_ign > 0)
|
||||||
|
frame_time = 0;
|
||||||
|
|
||||||
|
/* Special handlings for different video driver frame timings */
|
||||||
|
if (frame_time < frame_time_limit_med && frame_time > frame_time_target)
|
||||||
|
{
|
||||||
|
unsigned frame_time_frames_half = frame_time_frames / 2;
|
||||||
|
unsigned frame_time_delta = frame_time_max - frame_time_min;
|
||||||
|
|
||||||
|
/* Ensure outcome on certain conditions */
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
/* All frames are above the target */
|
||||||
|
if (frame_time_count_pos == frame_time_frames)
|
||||||
|
mode = 1;
|
||||||
|
/* At least half of interval frames are above minimum level */
|
||||||
|
else if (frame_time_count_min >= frame_time_frames_half)
|
||||||
|
mode = 2;
|
||||||
|
/* D3Dx stripe equalizer */
|
||||||
|
else if (
|
||||||
|
frame_time_count_pos == frame_time_frames_half
|
||||||
|
&& frame_time_count_min >= 1
|
||||||
|
&& frame_time_delta > (frame_time_target / 3)
|
||||||
|
&& frame_time_delta < (frame_time_target / 2)
|
||||||
|
&& frame_time > frame_time_target
|
||||||
|
)
|
||||||
|
mode = 3;
|
||||||
|
/* Boost med/max spikes */
|
||||||
|
else if (
|
||||||
|
frame_time_count_pos >= frame_time_frames_half
|
||||||
|
&& ( frame_time_count_max > 0
|
||||||
|
|| frame_time_count_med > 1)
|
||||||
|
&& frame_time_count_max == frame_time_count_med
|
||||||
|
&& frame_time_delta < frame_time_target
|
||||||
|
)
|
||||||
|
mode = 4;
|
||||||
|
/* Ignore */
|
||||||
|
else if (frame_time_delta > frame_time_target
|
||||||
|
&& frame_time_count_med == 0
|
||||||
|
)
|
||||||
|
mode = -1;
|
||||||
|
|
||||||
|
if (mode > 0)
|
||||||
|
{
|
||||||
|
#if FRAME_DELAY_AUTO_DEBUG
|
||||||
|
RARCH_LOG("[Video]: Frame delay nudge %d by mode %d.\n", frame_time, mode);
|
||||||
|
#endif
|
||||||
|
frame_time = frame_time_limit_med;
|
||||||
|
}
|
||||||
|
else if (mode < 0)
|
||||||
|
{
|
||||||
|
#if FRAME_DELAY_AUTO_DEBUG
|
||||||
|
RARCH_LOG("[Video]: Frame delay ignore %d.\n", frame_time);
|
||||||
|
#endif
|
||||||
|
frame_time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final output decision */
|
||||||
|
if (frame_time > frame_time_limit_min)
|
||||||
|
{
|
||||||
|
unsigned delay_decrease = 1;
|
||||||
|
|
||||||
|
/* Increase decrease the more frame time is off target */
|
||||||
|
if (frame_time > frame_time_limit_med && video_st->frame_delay_effective > delay_decrease)
|
||||||
|
{
|
||||||
|
delay_decrease++;
|
||||||
|
if (frame_time > frame_time_limit_max && video_st->frame_delay_effective > delay_decrease)
|
||||||
|
delay_decrease++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfda->decrease = delay_decrease;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfda->time = frame_time;
|
||||||
|
vfda->target = frame_time_target;
|
||||||
|
|
||||||
|
#if FRAME_DELAY_AUTO_DEBUG
|
||||||
|
if (frame_time_index > frame_time_frames)
|
||||||
|
RARCH_LOG("[Video]: %5d / pos:%d min:%d med:%d max:%d / delta:%5d = %5d %5d %5d %5d %5d %5d %5d %5d\n",
|
||||||
|
frame_time,
|
||||||
|
frame_time_count_pos,
|
||||||
|
frame_time_count_min,
|
||||||
|
frame_time_count_med,
|
||||||
|
frame_time_count_max,
|
||||||
|
frame_time_max - frame_time_min,
|
||||||
|
video_st->frame_time_samples[frame_time_index - 1],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 2],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 3],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 4],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 5],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 6],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 7],
|
||||||
|
video_st->frame_time_samples[frame_time_index - 8]
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -958,6 +958,14 @@ typedef struct
|
|||||||
#endif
|
#endif
|
||||||
} video_driver_state_t;
|
} video_driver_state_t;
|
||||||
|
|
||||||
|
typedef struct video_frame_delay_auto {
|
||||||
|
float refresh_rate;
|
||||||
|
unsigned frame_time_interval;
|
||||||
|
unsigned decrease;
|
||||||
|
unsigned target;
|
||||||
|
unsigned time;
|
||||||
|
} video_frame_delay_auto_t;
|
||||||
|
|
||||||
extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END];
|
extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END];
|
||||||
|
|
||||||
bool video_driver_has_windowed(void);
|
bool video_driver_has_windowed(void);
|
||||||
@ -1227,6 +1235,8 @@ bool *video_driver_get_threaded(void);
|
|||||||
|
|
||||||
void video_driver_set_threaded(bool val);
|
void video_driver_set_threaded(bool val);
|
||||||
|
|
||||||
|
void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_auto_t *vfda);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* video_context_driver_init:
|
* video_context_driver_init:
|
||||||
* @core_set_shared_context : Boolean value that tells us whether shared context
|
* @core_set_shared_context : Boolean value that tells us whether shared context
|
||||||
|
@ -1813,6 +1813,10 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
#if HAVE_NETWORKING
|
#if HAVE_NETWORKING
|
||||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
|
netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
/* Recalibrate frame delay target */
|
||||||
|
if (settings->bools.video_frame_delay_auto)
|
||||||
|
video_st->frame_delay_target = 0;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
case CMD_EVENT_SAVE_STATE:
|
case CMD_EVENT_SAVE_STATE:
|
||||||
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
||||||
|
60
runloop.c
60
runloop.c
@ -7554,12 +7554,17 @@ int runloop_iterate(void)
|
|||||||
if (settings->bools.video_frame_delay_auto)
|
if (settings->bools.video_frame_delay_auto)
|
||||||
{
|
{
|
||||||
float refresh_rate = settings->floats.video_refresh_rate;
|
float refresh_rate = settings->floats.video_refresh_rate;
|
||||||
|
unsigned video_swap_interval = settings->uints.video_swap_interval;
|
||||||
|
unsigned video_bfi = settings->uints.video_black_frame_insertion;
|
||||||
unsigned frame_time_interval = 8;
|
unsigned frame_time_interval = 8;
|
||||||
bool frame_time_update =
|
bool frame_time_update =
|
||||||
/* Skip some starting frames for stabilization */
|
/* Skip some starting frames for stabilization */
|
||||||
video_st->frame_count > 10 &&
|
video_st->frame_count > frame_time_interval &&
|
||||||
video_st->frame_count % frame_time_interval == 0;
|
video_st->frame_count % frame_time_interval == 0;
|
||||||
|
|
||||||
|
/* Black frame insertion + swap interval multiplier */
|
||||||
|
refresh_rate = (refresh_rate / (video_bfi + 1.0f) / video_swap_interval);
|
||||||
|
|
||||||
/* Set target moderately as half frame time with 0 delay */
|
/* Set target moderately as half frame time with 0 delay */
|
||||||
if (video_frame_delay == 0)
|
if (video_frame_delay == 0)
|
||||||
video_frame_delay = 1 / refresh_rate * 1000 / 2;
|
video_frame_delay = 1 / refresh_rate * 1000 / 2;
|
||||||
@ -7572,55 +7577,16 @@ int runloop_iterate(void)
|
|||||||
|
|
||||||
if (video_frame_delay_effective > 0 && frame_time_update)
|
if (video_frame_delay_effective > 0 && frame_time_update)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
video_frame_delay_auto_t vfda = {0};
|
||||||
unsigned frame_time = 0;
|
vfda.frame_time_interval = frame_time_interval;
|
||||||
unsigned frame_time_frames = frame_time_interval - 1;
|
vfda.refresh_rate = refresh_rate;
|
||||||
unsigned frame_time_target = 1000000.0f / refresh_rate;
|
|
||||||
unsigned frame_time_limit_min = frame_time_target * 1.25;
|
|
||||||
unsigned frame_time_limit_med = frame_time_target * 1.50;
|
|
||||||
unsigned frame_time_limit_max = frame_time_target * 1.90;
|
|
||||||
unsigned frame_time_limit_cap = frame_time_target * 2.25;
|
|
||||||
unsigned frame_time_limit_ign = frame_time_target * 2.50;
|
|
||||||
unsigned frame_time_index =
|
|
||||||
(video_st->frame_time_count &
|
|
||||||
(MEASURE_FRAME_TIME_SAMPLES_COUNT - 1));
|
|
||||||
|
|
||||||
/* Calculate average frame time to balance spikes */
|
video_frame_delay_auto(video_st, &vfda);
|
||||||
for (i = 1; i < frame_time_frames + 1; i++)
|
if (vfda.decrease > 0)
|
||||||
{
|
{
|
||||||
retro_time_t frame_time_i = 0;
|
video_frame_delay_effective -= vfda.decrease;
|
||||||
|
|
||||||
if (i > (unsigned)frame_time_index)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
frame_time_i = video_st->frame_time_samples[frame_time_index - i];
|
|
||||||
|
|
||||||
/* Ignore values when core is doing internal frame skipping */
|
|
||||||
if (frame_time_i > frame_time_limit_ign)
|
|
||||||
frame_time_i = 0;
|
|
||||||
/* Limit maximum to prevent false positives */
|
|
||||||
else if (frame_time_i > frame_time_limit_cap)
|
|
||||||
frame_time_i = frame_time_limit_cap;
|
|
||||||
|
|
||||||
frame_time += frame_time_i;
|
|
||||||
}
|
|
||||||
frame_time /= frame_time_frames;
|
|
||||||
|
|
||||||
if (frame_time > frame_time_limit_min)
|
|
||||||
{
|
|
||||||
unsigned delay_decrease = 1;
|
|
||||||
|
|
||||||
/* Increase decrease the more frame time is off target */
|
|
||||||
if (frame_time > frame_time_limit_med && video_frame_delay_effective > delay_decrease)
|
|
||||||
{
|
|
||||||
delay_decrease++;
|
|
||||||
if (frame_time > frame_time_limit_max && video_frame_delay_effective > delay_decrease)
|
|
||||||
delay_decrease++;
|
|
||||||
}
|
|
||||||
|
|
||||||
video_frame_delay_effective -= delay_decrease;
|
|
||||||
RARCH_LOG("[Video]: Frame delay decrease by %d to %d due to frame time: %d > %d.\n",
|
RARCH_LOG("[Video]: Frame delay decrease by %d to %d due to frame time: %d > %d.\n",
|
||||||
delay_decrease, video_frame_delay_effective, frame_time, frame_time_target);
|
vfda.decrease, video_frame_delay_effective, vfda.time, vfda.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user