diff --git a/Source/engine/demomode.cpp b/Source/engine/demomode.cpp index 5cfb4a903..e0339f0ca 100644 --- a/Source/engine/demomode.cpp +++ b/Source/engine/demomode.cpp @@ -595,10 +595,7 @@ void OverrideOptions() sgOptions.Graphics.hardwareCursor.SetValue(false); #endif if (Timedemo) { -#ifndef USE_SDL1 - sgOptions.Graphics.vSync.SetValue(false); -#endif - sgOptions.Graphics.limitFPS.SetValue(false); + sgOptions.Graphics.frameRateControl.SetValue(FrameRateControl::None); } forceResolution = Size(DemoGraphicsWidth, DemoGraphicsHeight); diff --git a/Source/engine/dx.cpp b/Source/engine/dx.cpp index ff5dc0c50..707799343 100644 --- a/Source/engine/dx.cpp +++ b/Source/engine/dx.cpp @@ -72,7 +72,7 @@ bool CanRenderDirectlyToOutputSurface() */ void LimitFrameRate() { - if (!*sgOptions.Graphics.limitFPS) + if (*sgOptions.Graphics.frameRateControl != FrameRateControl::CPUSleep) return; static uint32_t frameDeadline; uint32_t tc = SDL_GetTicks() * 1000; @@ -249,7 +249,7 @@ void RenderPresent() } SDL_RenderPresent(renderer); - if (!*sgOptions.Graphics.vSync) { + if (*sgOptions.Graphics.frameRateControl != FrameRateControl::VerticalSync) { LimitFrameRate(); } } else { diff --git a/Source/options.cpp b/Source/options.cpp index 0e4107b27..643fe3a29 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -866,21 +866,28 @@ GraphicsOptions::GraphicsOptions() { ScalingQuality::AnisotropicFiltering, N_("Anisotropic") }, }) , integerScaling("Integer Scaling", OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI, N_("Integer Scaling"), N_("Scales the image using whole number pixel ratio."), false) - , vSync("Vertical Sync", +#endif + , frameRateControl("Frame Rate Control", OptionEntryFlags::RecreateUI -#ifdef NXDK +#if defined(NXDK) || defined(__ANDROID__) | OptionEntryFlags::Invisible #endif , - N_("Vertical Sync"), - N_("Forces waiting for Vertical Sync. Prevents tearing effect when drawing a frame. Disabling it can help with mouse lag on some systems."), -#ifdef NXDK - false + N_("Frame Rate Control"), + N_("Manages frame rate to balance performance, reduce tearing, or save power."), +#if defined(NXDK) || defined(USE_SDL1) + FrameRateControl::CPUSleep #else - true + FrameRateControl::VerticalSync #endif - ) + , + { + { FrameRateControl::None, N_("None") }, +#ifndef USE_SDL1 + { FrameRateControl::VerticalSync, N_("Vertical Sync") }, #endif + { FrameRateControl::CPUSleep, N_("Limit FPS") }, + }) , gammaCorrection("Gamma Correction", OptionEntryFlags::Invisible, "Gamma Correction", "Gamma correction level.", 100) , zoom("Zoom", OptionEntryFlags::None, N_("Zoom"), N_("Zoom on when enabled."), false) , colorCycling("Color Cycling", OptionEntryFlags::None, N_("Color Cycling"), N_("Color cycling effect used for water, lava, and acid animation."), true) @@ -890,7 +897,6 @@ GraphicsOptions::GraphicsOptions() , hardwareCursorForItems("Hardware Cursor For Items", OptionEntryFlags::CantChangeInGame | (HardwareCursorSupported() ? OptionEntryFlags::None : OptionEntryFlags::Invisible), N_("Hardware Cursor For Items"), N_("Use a hardware cursor for items."), false) , hardwareCursorMaxSize("Hardware Cursor Maximum Size", OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI | (HardwareCursorSupported() ? OptionEntryFlags::None : OptionEntryFlags::Invisible), N_("Hardware Cursor Maximum Size"), N_("Maximum width / height for the hardware cursor. Larger cursors fall back to software."), 128, { 0, 64, 128, 256, 512 }) #endif - , limitFPS("FPS Limiter", OptionEntryFlags::None, N_("FPS Limiter"), N_("FPS is limited to avoid high CPU load. Limit considers refresh rate."), true) , showFPS("Show FPS", OptionEntryFlags::None, N_("Show FPS"), N_("Displays the FPS in the upper left corner of the screen."), false) { resolution.SetValueChangedCallback(ResizeWindow); @@ -901,7 +907,7 @@ GraphicsOptions::GraphicsOptions() #ifndef USE_SDL1 scaleQuality.SetValueChangedCallback(ReinitializeTexture); integerScaling.SetValueChangedCallback(ReinitializeIntegerScale); - vSync.SetValueChangedCallback(ReinitializeRenderer); + frameRateControl.SetValueChangedCallback(ReinitializeRenderer); #endif showFPS.SetValueChangedCallback(OptionShowFPSChanged); } @@ -920,11 +926,10 @@ std::vector GraphicsOptions::GetEntries() &upscale, &scaleQuality, &integerScaling, - &vSync, #endif + &frameRateControl, &gammaCorrection, &zoom, - &limitFPS, &showFPS, &colorCycling, &alternateNestArt, diff --git a/Source/options.h b/Source/options.h index 9bffa0d76..7730540cf 100644 --- a/Source/options.h +++ b/Source/options.h @@ -50,6 +50,14 @@ enum class ScalingQuality : uint8_t { AnisotropicFiltering, }; +enum class FrameRateControl : uint8_t { + None = 0, +#ifndef USE_SDL1 + VerticalSync = 1, +#endif + CPUSleep = 2, +}; + enum class Resampler : uint8_t { #ifdef DEVILUTIONX_RESAMPLER_SPEEX Speex = 0, @@ -501,9 +509,9 @@ struct GraphicsOptions : OptionCategoryBase { OptionEntryEnum scaleQuality; /** @brief Only scale by values divisible by the width and height. */ OptionEntryBoolean integerScaling; - /** @brief Enable vsync on the output. */ - OptionEntryBoolean vSync; #endif + /** @brief Limit frame rate either for vsync or CPU load. */ + OptionEntryEnum frameRateControl; /** @brief Gamma correction level. */ OptionEntryInt gammaCorrection; /** @brief Zoom on start. */ @@ -520,8 +528,6 @@ struct GraphicsOptions : OptionCategoryBase { /** @brief Maximum width / height for the hardware cursor. Larger cursors fall back to software. */ OptionEntryInt hardwareCursorMaxSize; #endif - /** @brief Enable FPS Limiter. */ - OptionEntryBoolean limitFPS; /** @brief Show FPS, even without the -f command line flag. */ OptionEntryBoolean showFPS; }; diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index efd972f8d..9ab4e2c95 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -123,9 +123,9 @@ void FreeRenderer() renderer = nullptr; } -#if defined(_WIN32) && !defined(NXDK) +#if defined(_WIN32) && !defined(NXDK) && !defined(USE_SDL1) // On Windows 11 the directx9 VSYNC timer doesn't get recreated properly, see https://github.com/libsdl-org/SDL/issues/5099 - if (wasD3D9 && *sgOptions.Graphics.upscale && *sgOptions.Graphics.vSync) { + if (wasD3D9 && *sgOptions.Graphics.upscale && *sgOptions.Graphics.frameRateControl != FrameRateControl::VerticalSync) { std::string title = SDL_GetWindowTitle(ghMainWnd); Uint32 flags = SDL_GetWindowFlags(ghMainWnd); Rectangle dimensions; @@ -425,7 +425,7 @@ void ReinitializeRenderer() if (*sgOptions.Graphics.upscale) { Uint32 rendererFlags = 0; - if (*sgOptions.Graphics.vSync) { + if (*sgOptions.Graphics.frameRateControl == FrameRateControl::VerticalSync) { rendererFlags |= SDL_RENDERER_PRESENTVSYNC; }