mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
Rework optional fast-forward frame skipping: Drop frames based on frame timing (#13578)
This commit is contained in:
parent
6aa89b3723
commit
a953b27614
@ -2803,6 +2803,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
|
||||
|
||||
video_info->runloop_is_paused = runloop_st->paused;
|
||||
video_info->runloop_is_slowmotion = runloop_st->slowmotion;
|
||||
video_info->fastforward_frameskip = settings->bools.fastforward_frameskip;
|
||||
|
||||
video_info->input_driver_nonblock_state = input_st ?
|
||||
input_st->nonblocking_flag : false;
|
||||
@ -3568,13 +3569,16 @@ void video_driver_frame(const void *data, unsigned width,
|
||||
{
|
||||
char status_text[128];
|
||||
static char video_driver_msg[256];
|
||||
static retro_time_t last_time;
|
||||
static retro_time_t curr_time;
|
||||
static retro_time_t fps_time;
|
||||
static retro_time_t frame_time_accumulator;
|
||||
static float last_fps, frame_time;
|
||||
static uint64_t last_used_memory, last_total_memory;
|
||||
/* Initialise 'last_frame_duped' to 'true'
|
||||
* to ensure that the first frame is rendered */
|
||||
static bool last_frame_duped = true;
|
||||
bool render_frame = true;
|
||||
retro_time_t new_time;
|
||||
video_frame_info_t video_info;
|
||||
video_driver_state_t *video_st= &video_driver_st;
|
||||
@ -3582,7 +3586,6 @@ void video_driver_frame(const void *data, unsigned width,
|
||||
const enum retro_pixel_format
|
||||
video_driver_pix_fmt = video_st->pix_fmt;
|
||||
bool runloop_idle = runloop_st->idle;
|
||||
bool render_frame = !runloop_st->fastforward_frameskip_frames_current;
|
||||
bool video_driver_active = video_st->active;
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
bool widgets_active = dispwidget_get_ptr()->active;
|
||||
@ -3621,17 +3624,55 @@ void video_driver_frame(const void *data, unsigned width,
|
||||
|
||||
video_driver_build_info(&video_info);
|
||||
|
||||
/* Always render a frame if:
|
||||
* - Menu is open
|
||||
/* If fast forward is active and fast forward
|
||||
* frame skipping is enabled, drop any frames
|
||||
* that occur at a rate higher than the core-set
|
||||
* refresh rate. However: We must always render
|
||||
* the current frame when:
|
||||
* - The menu is open
|
||||
* - The last frame was NULL and the
|
||||
* current frame is not (i.e. if core was
|
||||
* previously sending duped frames, ensure
|
||||
* that the next frame update is captured) */
|
||||
render_frame |= video_info.menu_is_alive || (last_frame_duped && !!data);
|
||||
last_frame_duped = !data;
|
||||
if (video_info.input_driver_nonblock_state &&
|
||||
video_info.fastforward_frameskip &&
|
||||
!(video_info.menu_is_alive ||
|
||||
(last_frame_duped && !!data)))
|
||||
{
|
||||
/* Accumulate the elapsed time since the
|
||||
* last frame */
|
||||
frame_time_accumulator += new_time - last_time;
|
||||
|
||||
if (!render_frame)
|
||||
runloop_st->fastforward_frameskip_frames_current--;
|
||||
/* Render frame if the accumulated time is
|
||||
* greater than or equal to the expected
|
||||
* core frame time */
|
||||
render_frame = frame_time_accumulator >=
|
||||
video_st->core_frame_time;
|
||||
|
||||
/* If frame is to be rendered, subtract
|
||||
* expected frame time from accumulator */
|
||||
if (render_frame)
|
||||
{
|
||||
frame_time_accumulator -= video_st->core_frame_time;
|
||||
|
||||
/* If fast forward is working correctly,
|
||||
* the actual frame time will always be
|
||||
* less than the expected frame time.
|
||||
* But if the host cannot run the core
|
||||
* fast enough to achieve at least 1x
|
||||
* speed then the frame time accumulator
|
||||
* will never empty and may potentially
|
||||
* overflow. If a 'runaway' accumulator
|
||||
* is detected, we simply reset it */
|
||||
if (frame_time_accumulator > video_st->core_frame_time)
|
||||
frame_time_accumulator = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
frame_time_accumulator = 0;
|
||||
|
||||
last_time = new_time;
|
||||
last_frame_duped = !data;
|
||||
|
||||
/* Get the amount of frames per seconds. */
|
||||
if (video_st->frame_count)
|
||||
@ -3933,16 +3974,12 @@ void video_driver_frame(const void *data, unsigned width,
|
||||
}
|
||||
|
||||
if (render_frame && video_st->current_video && video_st->current_video->frame)
|
||||
{
|
||||
video_st->active = video_st->current_video->frame(
|
||||
video_st->data, data, width, height,
|
||||
video_st->frame_count, (unsigned)pitch,
|
||||
video_info.menu_screensaver_active || video_info.notifications_hidden ? "" : video_driver_msg,
|
||||
&video_info);
|
||||
|
||||
runloop_st->fastforward_frameskip_frames_current = runloop_st->fastforward_frameskip_frames;
|
||||
}
|
||||
|
||||
video_st->frame_count++;
|
||||
|
||||
/* Display the status text, with a higher priority. */
|
||||
|
@ -497,6 +497,7 @@ typedef struct video_frame_info
|
||||
bool timedate_enable;
|
||||
bool runloop_is_slowmotion;
|
||||
bool runloop_is_paused;
|
||||
bool fastforward_frameskip;
|
||||
bool menu_is_alive;
|
||||
bool menu_screensaver_active;
|
||||
bool msg_bgcolor_enable;
|
||||
@ -819,6 +820,7 @@ typedef struct
|
||||
#endif
|
||||
struct retro_system_av_info av_info; /* double alignment */
|
||||
retro_time_t frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT];
|
||||
retro_time_t core_frame_time;
|
||||
uint64_t frame_time_count;
|
||||
uint64_t frame_count;
|
||||
uint8_t *record_gpu_buffer;
|
||||
|
25
runloop.c
25
runloop.c
@ -2628,6 +2628,10 @@ bool runloop_environment_cb(unsigned cmd, void *data)
|
||||
(*info)->timing.sample_rate);
|
||||
|
||||
memcpy(av_info, *info, sizeof(*av_info));
|
||||
video_st->core_frame_time = 1000000 /
|
||||
((video_st->av_info.timing.fps > 0.0) ?
|
||||
video_st->av_info.timing.fps : 60.0);
|
||||
|
||||
command_event(CMD_EVENT_REINIT, &reinit_flags);
|
||||
if (no_video_reinit)
|
||||
video_driver_set_aspect_ratio();
|
||||
@ -4910,22 +4914,6 @@ static bool core_unload_game(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void runloop_apply_fastmotion_frameskip(runloop_state_t *runloop_st, settings_t *settings)
|
||||
{
|
||||
unsigned frames = 0;
|
||||
|
||||
if (runloop_st->fastmotion && settings->bools.fastforward_frameskip)
|
||||
{
|
||||
frames = (unsigned)settings->floats.fastforward_ratio;
|
||||
/* Pick refresh rate as unlimited throttle rate */
|
||||
frames = (!frames) ? (unsigned)roundf(settings->floats.video_refresh_rate) : frames;
|
||||
/* Decrease one to represent skipped frames */
|
||||
frames--;
|
||||
}
|
||||
|
||||
runloop_st->fastforward_frameskip_frames_current = runloop_st->fastforward_frameskip_frames = frames;
|
||||
}
|
||||
|
||||
static void runloop_apply_fastmotion_override(runloop_state_t *runloop_st, settings_t *settings)
|
||||
{
|
||||
video_driver_state_t *video_st = video_state_get_ptr();
|
||||
@ -4963,7 +4951,6 @@ static void runloop_apply_fastmotion_override(runloop_state_t *runloop_st, setti
|
||||
if (!runloop_st->fastmotion)
|
||||
runloop_st->fastforward_after_frames = 1;
|
||||
|
||||
runloop_apply_fastmotion_frameskip(runloop_st, settings);
|
||||
driver_set_nonblock_state();
|
||||
|
||||
/* Reset frame time counter when toggling
|
||||
@ -5315,6 +5302,9 @@ static bool core_load(unsigned poll_type_behavior)
|
||||
return false;
|
||||
|
||||
runloop_st->current_core.retro_get_system_av_info(&video_st->av_info);
|
||||
video_st->core_frame_time = 1000000 /
|
||||
((video_st->av_info.timing.fps > 0.0) ?
|
||||
video_st->av_info.timing.fps : 60.0);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -7080,7 +7070,6 @@ static enum runloop_state_enum runloop_check_state(
|
||||
runloop_st->fastmotion = true;
|
||||
}
|
||||
|
||||
runloop_apply_fastmotion_frameskip(runloop_st, settings);
|
||||
driver_set_nonblock_state();
|
||||
|
||||
/* Reset frame time counter when toggling
|
||||
|
@ -216,8 +216,6 @@ struct runloop
|
||||
unsigned max_frames;
|
||||
unsigned audio_latency;
|
||||
unsigned fastforward_after_frames;
|
||||
unsigned fastforward_frameskip_frames;
|
||||
unsigned fastforward_frameskip_frames_current;
|
||||
unsigned perf_ptr_libretro;
|
||||
unsigned subsystem_current_count;
|
||||
unsigned entry_state_slot;
|
||||
|
Loading…
Reference in New Issue
Block a user