Add environment callback to get the rate retro_run is called (#13022)

* Add GET_THROTTLE_STATE environment callback

* Add RETRO_THROTTLE_UNBLOCKED
to report the case where neither vsync nor audio is limiting the call rate.
Also fix reporting of some special cases when the menu is open.

* Change throttle state mode to unsigned
Use #defines Instead of the untyped C enum to allow easier future additions.

* Spelling fixes

* Avoid any divide-by-zero
This commit is contained in:
Bernhard Schelling 2021-10-12 01:05:13 +09:00 committed by GitHub
parent e7f182811a
commit a3d9201581
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 0 deletions

View File

@ -1747,6 +1747,12 @@ enum retro_mod
* to test whether the callback is supported.
*/
#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_throttle_state * --
* Allows an implementation to get details on the actual rate
* the frontend is attempting to call retro_run().
*/
/* VFS functionality */
/* File paths:
@ -3692,6 +3698,43 @@ struct retro_fastforwarding_override
bool inhibit_toggle;
};
/* During normal operation. Rate will be equal to the core's internal FPS. */
#define RETRO_THROTTLE_NONE 0
/* While paused or stepping single frames. Rate will be 0. */
#define RETRO_THROTTLE_FRAME_STEPPING 1
/* During fast forwarding.
* Rate will be 0 if not specifically limited to a maximum speed. */
#define RETRO_THROTTLE_FAST_FORWARD 2
/* During slow motion. Rate will be less than the core's internal FPS. */
#define RETRO_THROTTLE_SLOW_MOTION 3
/* While rewinding recorded save states. Rate can vary depending on the rewind
* speed or be 0 if the frontend is not aiming for a specific rate. */
#define RETRO_THROTTLE_REWINDING 4
/* While vsync is active in the video driver and the target refresh rate is
* lower than the core's internal FPS. Rate is the target refresh rate. */
#define RETRO_THROTTLE_VSYNC 5
/* When the frontend does not throttle in any way. Rate will be 0.
* An example could be if no vsync or audio output is active. */
#define RETRO_THROTTLE_UNBLOCKED 6
struct retro_throttle_state
{
/* The current throttling mode. Should be one of the values above. */
unsigned mode;
/* How many times per second the frontend aims to call retro_run.
* Depending on the mode, it can be 0 if there is no known fixed rate.
* This won't be accurate if the total processing time of the core and
* the frontend is longer than what is available for one frame. */
float rate;
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing

View File

@ -11843,6 +11843,89 @@ static bool retroarch_environment_cb(unsigned cmd, void *data)
break;
}
case RETRO_ENVIRONMENT_GET_THROTTLE_STATE:
{
struct retro_throttle_state *throttle_state =
(struct retro_throttle_state *)data;
bool menu_opened = false;
bool core_paused = runloop_state.paused;
bool no_audio = (p_rarch->audio_suspended || !p_rarch->audio_driver_active);
float core_fps = (float)p_rarch->video_driver_av_info.timing.fps;
#ifdef HAVE_REWIND
if (p_rarch->rewind_st.frame_is_reversed)
{
throttle_state->mode = RETRO_THROTTLE_REWINDING;
throttle_state->rate = 0.0f;
break; /* ignore vsync */
}
#endif
#ifdef HAVE_MENU
menu_opened = menu_state_get_ptr()->alive;
if (menu_opened)
core_paused = settings->bools.menu_pause_libretro;
#endif
if (core_paused)
{
throttle_state->mode = RETRO_THROTTLE_FRAME_STEPPING;
throttle_state->rate = 0.0f;
break; /* ignore vsync */
}
/* Base mode and rate. */
throttle_state->mode = RETRO_THROTTLE_NONE;
throttle_state->rate = core_fps;
if (runloop_state.fastmotion)
{
throttle_state->mode = RETRO_THROTTLE_FAST_FORWARD;
throttle_state->rate *= retroarch_get_runloop_fastforward_ratio(
settings, &runloop_state.fastmotion_override.current);
}
else if (runloop_state.slowmotion && !no_audio)
{
throttle_state->mode = RETRO_THROTTLE_SLOW_MOTION;
throttle_state->rate /= (settings->floats.slowmotion_ratio > 0.0f ?
settings->floats.slowmotion_ratio : 1.0f);
}
/* VSync overrides the mode if the rate is limited by the display. */
if (menu_opened || /* Menu currently always runs with vsync on. */
(settings->bools.video_vsync && !runloop_state.force_nonblock
&& !input_state_get_ptr()->nonblocking_flag))
{
float refresh_rate = video_driver_get_refresh_rate();
if (refresh_rate == 0.0f)
refresh_rate = settings->floats.video_refresh_rate;
if (refresh_rate < throttle_state->rate || !throttle_state->rate)
{
/* Keep the mode as fast forward even if vsync limits it. */
if (refresh_rate < core_fps)
throttle_state->mode = RETRO_THROTTLE_VSYNC;
throttle_state->rate = refresh_rate;
}
}
/* Special behavior while audio output is not available. */
if (no_audio && throttle_state->mode != RETRO_THROTTLE_FAST_FORWARD
&& throttle_state->mode != RETRO_THROTTLE_VSYNC)
{
/* Keep base if frame limiter matching the core is active. */
retro_time_t core_limit = (core_fps ?
(retro_time_t)(1000000.0f / core_fps) : (retro_time_t)0);
retro_time_t frame_limit = p_rarch->frame_limit_minimum_time;
if (abs((int)(core_limit - frame_limit)) > 10)
{
throttle_state->mode = RETRO_THROTTLE_UNBLOCKED;
throttle_state->rate = 0.0f;
}
}
break;
}
case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS:
/* Just falldown, the function will return true */
break;