diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 1ee227793..2efc506fa 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -70,7 +70,11 @@ Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration createContext(configuration); } -Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t): _glContext{nullptr}, _flags{Flag::Redraw} { +Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t): _glContext{nullptr}, + #ifndef CORRADE_TARGET_EMSCRIPTEN + _minimalLoopPeriod{0}, + #endif + _flags{Flag::Redraw} { #ifdef CORRADE_TARGET_EMSCRIPTEN CORRADE_ASSERT(!_instance, "Platform::Sdl2Application::Sdl2Application(): the instance is already created", ); _instance = this; @@ -222,14 +226,17 @@ Int Sdl2Application::swapInterval() const { bool Sdl2Application::setSwapInterval(const Int interval) { if(SDL_GL_SetSwapInterval(interval) == -1) { Error() << "Platform::Sdl2Application::setSwapInterval(): cannot set swap interval:" << SDL_GetError(); + _flags &= ~Flag::VSyncEnabled; return false; } if(SDL_GL_GetSwapInterval() != interval) { Error() << "Platform::Sdl2Application::setSwapInterval(): swap interval setting ignored by the driver"; + _flags &= ~Flag::VSyncEnabled; return false; } + _flags |= Flag::VSyncEnabled; return true; } @@ -265,8 +272,9 @@ void Sdl2Application::exit() { } void Sdl2Application::mainLoop() { - SDL_Event event; + const UnsignedInt timeBefore = _minimalLoopPeriod ? SDL_GetTicks() : 0; + SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_WINDOWEVENT: @@ -317,10 +325,28 @@ void Sdl2Application::mainLoop() { if(_flags & Flag::Redraw) { _flags &= ~Flag::Redraw; drawEvent(); + + #ifndef CORRADE_TARGET_EMSCRIPTEN + /* If VSync is not enabled, delay to prevent CPU hogging (if set) */ + if(!(_flags & Flag::VSyncEnabled) && _minimalLoopPeriod) { + const UnsignedInt loopTime = SDL_GetTicks() - timeBefore; + if(loopTime < _minimalLoopPeriod) + SDL_Delay(_minimalLoopPeriod - loopTime); + } + #endif + return; } #ifndef CORRADE_TARGET_EMSCRIPTEN + /* If not drawing anything, delay to prevent CPU hogging (if set) */ + if(_minimalLoopPeriod) { + const UnsignedInt loopTime = SDL_GetTicks() - timeBefore; + if(loopTime < _minimalLoopPeriod) + SDL_Delay(_minimalLoopPeriod - loopTime); + } + + /* Then wait indefinitely for next input event */ SDL_WaitEvent(nullptr); #endif } diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index 0f94d67d3..0e03c121e 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -291,9 +291,26 @@ class Sdl2Application { * `-1` for late swap tearing. Prints error message and returns `false` * if swap interval cannot be set, `true` otherwise. Default is * driver-dependent, you can query the value with @ref swapInterval(). + * @see @ref setMinimalLoopPeriod() */ bool setSwapInterval(Int interval); + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Set minimal loop period + * + * This setting reduces the main loop frequency in case VSync is + * not/cannot be enabled or no drawing is done. Default is `0` (i.e. + * looping at maximum frequency). + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", + * the browser is managing the frequency instead. + * @see @ref setSwapInterval() + */ + void setMinimalLoopPeriod(UnsignedInt milliseconds) { + _minimalLoopPeriod = milliseconds; + } + #endif + /** * @brief Redraw immediately * @@ -403,8 +420,9 @@ class Sdl2Application { private: enum class Flag: UnsignedByte { Redraw = 1 << 0, + VSyncEnabled = 1 << 1, #ifndef CORRADE_TARGET_EMSCRIPTEN - Exit = 1 << 1 + Exit = 1 << 2 #endif }; @@ -421,6 +439,7 @@ class Sdl2Application { #ifndef CORRADE_TARGET_EMSCRIPTEN SDL_Window* _window; SDL_GLContext _glContext; + UnsignedInt _minimalLoopPeriod; #else SDL_Surface* _glContext; #endif