From 85c3cf59bc60d0be104e47d795939dd9fee814f6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 20 May 2020 10:19:31 +0200 Subject: [PATCH] added refresh rate adapt for integer factors of the game's refresh rate --- src/common/FrameBufferSDL2.cxx | 90 +++++++++++++++++++++------------- src/common/FrameBufferSDL2.hxx | 17 ++++--- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 691e96510..72484c468 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -220,7 +220,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const bool fullScreen = mode.fsIndex != -1; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && gameRefreshRate() && refreshRate() != gameRefreshRate(); + && gameRefreshRate() && refreshRate() % gameRefreshRate() != 0; bool forceCreateRenderer = false; // Get windowed window's last display @@ -277,7 +277,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) SDL_GetWindowSize(myWindow, &w, &h); if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h - || shouldAdapt) + || adaptRefresh) { SDL_DestroyWindow(myWindow); myWindow = nullptr; @@ -335,6 +335,57 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) return createRenderer(forceCreateRenderer); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) +{ + SDL_DisplayMode sdlMode; + + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) + { + Logger::error("ERROR: Display mode could not be retrieved"); + return false; + } + + const int currentRefreshRate = sdlMode.refresh_rate; + const int wantedRefreshRate = gameRefreshRate(); + float factor = float(currentRefreshRate) / wantedRefreshRate; + float bestDiff = std::abs(factor - std::round(factor)) / factor; + bool adapt = false; + + // Display refresh rate should be an integer factor of the game's refresh rate + // Note: Modes are scanned with size being first priority, + // therefore the size will never change. + // Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz) + for(int m = 1; m <= 2; ++m) + { + SDL_DisplayMode closestSdlMode; + + sdlMode.refresh_rate = wantedRefreshRate * m; + if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) + { + Logger::error("ERROR: Closest display mode could not be retrieved"); + return adapt; + } + factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; + const float diff = std::abs(factor - std::round(factor)) / factor; + if(diff < bestDiff) + { + bestDiff = diff; + adaptedSdlMode = closestSdlMode; + adapt = true; + } + } + cerr << "refresh rate adapt "; + if(adapt) + cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)"; + else + cerr << "not required/possible"; + cerr << endl; + + // Only change if the display supports a better refresh rate + return adapt; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::createRenderer(bool force) { @@ -359,7 +410,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - //cerr << "Create new renderer " << int(myBufferType) << endl; + cerr << "Create new renderer " << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); @@ -388,37 +439,6 @@ bool FrameBufferSDL2::createRenderer(bool force) return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode) -{ - SDL_DisplayMode sdlMode; - - if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) - { - Logger::error("ERROR: Display mode could not be retrieved"); - return false; - } - - const int currentRefreshRate = sdlMode.refresh_rate; - - sdlMode.refresh_rate = gameRefreshRate(); - - if(currentRefreshRate != sdlMode.refresh_rate) - { - // Note: Modes are scanned with size being first priority, - // therefore the size will never change. - if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) - { - Logger::error("ERROR: Closest display mode could not be retrieved"); - return false; - } - // Only change if the display supports a better refresh rate - return currentRefreshRate != closestSdlMode.refresh_rate; - // TODO: check for multiples e.g. 120/100 too - } - return false; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setTitle(const string& title) { @@ -503,7 +523,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; } return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 1799b5c6f..08005f85a 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,16 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + /** + Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode + + @param displayIndex The display which should be checked + @adaptedSdlMode The best matching mode if the refresh rate should be changed + + @return True if the refresh rate should be changed + */ + bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); + /** Create a new renderer if required @@ -190,13 +200,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool createRenderer(bool force); - /** - Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode - - @return True if the refresh rate should be changed - */ - bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode); - /** This method is called to create a surface with the given attributes.