mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-06-04 19:07:40 +00:00
main: Adjust how SDL_HINT_MAIN_CALLBACK_RATE works.
Now (only in the generic backend, where it is implemented), this hint is always respected. Previously it would only be used if no windows were created, to help reduce CPU load on things like loopwave. Since it's always used now, the default has changed from 60 (Hz) to 0 (run as fast as possible). Things like loopwave should still likely force this way lower than the previous default (and already do: loopwave explicitly sets it to 5). The hint can now also be set to "waitevent" which will cause SDL_AppIterate to only be called after new events have arrived, for apps that are entirely driven by input and want to consume (almost) no power or CPU time until then. Fixes #11093. Fixes #11387.
This commit is contained in:
parent
cd1bd0ac2e
commit
fa9c3331d5
2 changed files with 38 additions and 17 deletions
|
@ -2391,13 +2391,21 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* Request SDL_AppIterate() be called at a specific rate.
|
* Request SDL_AppIterate() be called at a specific rate.
|
||||||
*
|
*
|
||||||
* This number is in Hz, so "60" means try to iterate 60 times per second.
|
* If this is set to a number, it represents Hz, so "60" means try to
|
||||||
|
* iterate 60 times per second. "0" means to iterate as fast as possible.
|
||||||
|
* Negative values are illegal, but reserved, in case they are useful in
|
||||||
|
* a future revision of SDL.
|
||||||
|
*
|
||||||
|
* There are other strings that have special meaning. If set to "waitevent",
|
||||||
|
* SDL_AppIterate will not be called until new event(s) have arrived (and been
|
||||||
|
* processed by SDL_AppEvent). This can be useful for apps that are completely
|
||||||
|
* idle except in response to input.
|
||||||
*
|
*
|
||||||
* On some platforms, or if you are using SDL_main instead of SDL_AppIterate,
|
* On some platforms, or if you are using SDL_main instead of SDL_AppIterate,
|
||||||
* this hint is ignored. When the hint can be used, it is allowed to be
|
* this hint is ignored. When the hint can be used, it is allowed to be
|
||||||
* changed at any time.
|
* changed at any time.
|
||||||
*
|
*
|
||||||
* This defaults to 60, and specifying NULL for the hint's value will restore
|
* This defaults to 0, and specifying NULL for the hint's value will restore
|
||||||
* the default.
|
* the default.
|
||||||
*
|
*
|
||||||
* This hint can be set anytime.
|
* This hint can be set anytime.
|
||||||
|
|
|
@ -26,17 +26,31 @@
|
||||||
#ifndef SDL_PLATFORM_IOS
|
#ifndef SDL_PLATFORM_IOS
|
||||||
|
|
||||||
static int callback_rate_increment = 0;
|
static int callback_rate_increment = 0;
|
||||||
|
static bool iterate_after_waitevent = false;
|
||||||
|
|
||||||
static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)
|
static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)
|
||||||
{
|
{
|
||||||
const int callback_rate = newValue ? SDL_atoi(newValue) : 60;
|
iterate_after_waitevent = newValue && (SDL_strcmp(newValue, "waitevent") == 0);
|
||||||
if (callback_rate > 0) {
|
if (iterate_after_waitevent) {
|
||||||
callback_rate_increment = ((Uint64) 1000000000) / ((Uint64) callback_rate);
|
|
||||||
} else {
|
|
||||||
callback_rate_increment = 0;
|
callback_rate_increment = 0;
|
||||||
|
} else {
|
||||||
|
const int callback_rate = newValue ? SDL_atoi(newValue) : 0;
|
||||||
|
if (callback_rate > 0) {
|
||||||
|
callback_rate_increment = ((Uint64) 1000000000) / ((Uint64) callback_rate);
|
||||||
|
} else {
|
||||||
|
callback_rate_increment = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_AppResult GenericIterateMainCallbacks(void)
|
||||||
|
{
|
||||||
|
if (iterate_after_waitevent) {
|
||||||
|
SDL_WaitEvent(NULL);
|
||||||
|
}
|
||||||
|
return SDL_IterateMainCallbacks(!iterate_after_waitevent);
|
||||||
|
}
|
||||||
|
|
||||||
int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
|
int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
|
||||||
{
|
{
|
||||||
SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
|
SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
|
||||||
|
@ -45,7 +59,7 @@ int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit,
|
||||||
|
|
||||||
Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0;
|
Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0;
|
||||||
|
|
||||||
while ((rc = SDL_IterateMainCallbacks(true)) == SDL_APP_CONTINUE) {
|
while ((rc = GenericIterateMainCallbacks()) == SDL_APP_CONTINUE) {
|
||||||
// !!! FIXME: this can be made more complicated if we decide to
|
// !!! FIXME: this can be made more complicated if we decide to
|
||||||
// !!! FIXME: optionally hand off callback responsibility to the
|
// !!! FIXME: optionally hand off callback responsibility to the
|
||||||
// !!! FIXME: video subsystem (for example, if Wayland has a
|
// !!! FIXME: video subsystem (for example, if Wayland has a
|
||||||
|
@ -53,21 +67,20 @@ int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit,
|
||||||
// !!! FIXME: off to them here if/when the video subsystem becomes
|
// !!! FIXME: off to them here if/when the video subsystem becomes
|
||||||
// !!! FIXME: initialized).
|
// !!! FIXME: initialized).
|
||||||
|
|
||||||
// !!! FIXME: maybe respect this hint even if there _is_ a window.
|
// Try to run at whatever rate the hint requested. This makes this
|
||||||
// if there's no window, try to run at about 60fps (or whatever rate
|
// not eat all the CPU in simple things like loopwave. By
|
||||||
// the hint requested). This makes this not eat all the CPU in
|
// default, we run as fast as possible, which means we'll clamp to
|
||||||
// simple things like loopwave. If there's a window, we run as fast
|
// vsync in common cases, and won't be restrained to vsync if the
|
||||||
// as possible, which means we'll clamp to vsync in common cases,
|
// app is doing a benchmark or doesn't want to be, based on how
|
||||||
// and won't be restrained to vsync if the app is doing a benchmark
|
// they've set up that window.
|
||||||
// or doesn't want to be, based on how they've set up that window.
|
if (callback_rate_increment == 0) {
|
||||||
if ((callback_rate_increment == 0) || SDL_HasWindows()) {
|
|
||||||
next_iteration = 0; // just clear the timer and run at the pace the video subsystem allows.
|
next_iteration = 0; // just clear the timer and run at the pace the video subsystem allows.
|
||||||
} else {
|
} else {
|
||||||
const Uint64 now = SDL_GetTicksNS();
|
const Uint64 now = SDL_GetTicksNS();
|
||||||
if (next_iteration > now) { // Running faster than the limit, sleep a little.
|
if (next_iteration > now) { // Running faster than the limit, sleep a little.
|
||||||
SDL_DelayPrecise(next_iteration - now);
|
SDL_DelayPrecise(next_iteration - now);
|
||||||
} else {
|
} else {
|
||||||
next_iteration = now; // running behind (or just lost the window)...reset the timer.
|
next_iteration = now; // if running behind, reset the timer. If right on time, `next_iteration` already equals `now`.
|
||||||
}
|
}
|
||||||
next_iteration += callback_rate_increment;
|
next_iteration += callback_rate_increment;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue