From 5fa9936aab36aa16290ce80b217db0333fe05cfd Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 18 May 2020 12:26:05 +0200 Subject: [PATCH 01/14] added optional refresh rate adaption in fullscreen mode --- src/common/FrameBufferSDL2.cxx | 65 ++++++++++++++++++++++++++++++++++ src/common/FrameBufferSDL2.hxx | 8 +++++ src/emucore/FrameBuffer.hxx | 8 +++++ src/emucore/Settings.cxx | 1 + src/gui/VideoAudioDialog.cxx | 12 +++++++ src/gui/VideoAudioDialog.hxx | 1 + 6 files changed, 95 insertions(+) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 4d013a35d..a1a9c5bbd 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -340,9 +340,74 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); + adaptRefreshRate(); + return true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBufferSDL2::adaptRefreshRate() +{ + const bool adapt = myOSystem.settings().getBool("tia.refresh"); + + // adapt only in emulation (and debugger?) and fullscreen mode + // TODO: adapt while creating new window + if(adapt && fullScreen() + && (myBufferType == BufferType::Emulator/* || myBufferType == BufferType::Debugger*/)) + { + SDL_DisplayMode sdlMode; + + if(SDL_GetWindowDisplayMode(myWindow, &sdlMode) != 0) + { + Logger::error("Display mode could not be retrieved"); + return false; + } + + const int currentRefreshRate = sdlMode.refresh_rate; + const string format = myOSystem.console().getFormatString(); + const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; + + sdlMode.refresh_rate = isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too + + if(currentRefreshRate != sdlMode.refresh_rate) + { + const int display = SDL_GetWindowDisplayIndex(myWindow); + SDL_DisplayMode closestSdlMode; + + if(SDL_GetClosestDisplayMode(display, &sdlMode, &closestSdlMode) == NULL) + { + Logger::error("Closest display mode could not be retrieved"); + return false; + } + // Note: Modes are scanned with size being first priority, + // therefore the size will never change. + // Only change if the display supports a better refresh rate + if(currentRefreshRate != closestSdlMode.refresh_rate) + { + // Switch to new mode + if(SDL_SetWindowDisplayMode(myWindow, &closestSdlMode) != 0) + { + Logger::error("Display refresh rate change failed"); + return false; + } + // Any change only works in real fullscreen mode! + if(SDL_SetWindowFullscreen(myWindow, SDL_WINDOW_FULLSCREEN) != 0) + { + Logger::error("Display fullscreen change failed"); + return false; + } + ostringstream msg; + + msg << "Display refresh rate changed from " << currentRefreshRate << "Hz to " + << closestSdlMode.refresh_rate << "Hz"; + Logger::info(msg.str()); + return true; + } + } + } + return false; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setTitle(const string& title) { diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index d2825037c..0d74d100b 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,14 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + + /** + Adapt display refresh rate to game refresh rate in (real) fullscreen mode + + @return True if the refresh rate was changed + */ + bool adaptRefreshRate(); + /** This method is called to create a surface with the given attributes. diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 3912f38cd..e19fcc335 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -81,6 +81,13 @@ class FrameBuffer } }; + struct DisplayMode + { + uInt32 display; + Common::Size size; + uInt32 refresh_rate; + }; + enum class BufferType { None, Launcher, @@ -439,6 +446,7 @@ class FrameBuffer virtual int scaleY(int y) const { return y; } protected: + /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. Since several diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index f5e120408..bbcc0c4bd 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -54,6 +54,7 @@ Settings::Settings() setPermanent("tia.fs_stretch", "false"); setPermanent("tia.fs_overscan", "0"); setPermanent("tia.vsizeadjust", 0); + setPermanent("tia.refresh", "false"); setPermanent("tia.dbgcolors", "roygpb"); // Palette options setPermanent("palette", PaletteHandler::SETTING_STANDARD); diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 48fdcc8de..74b326f7c 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -166,9 +166,14 @@ void VideoAudioDialog::addDisplayTab() myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); + + // Adapt refresh rate ypos += lineHeight + VGAP; + myRefreshAdjust = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt refresh rate"); + wid.push_back(myRefreshAdjust); // Vertical size + ypos += lineHeight + VGAP; myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); @@ -176,6 +181,7 @@ void VideoAudioDialog::addDisplayTab() myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); + // Add items for tab 0 addToFocusList(wid, myTab, tabID); } @@ -486,6 +492,8 @@ void VideoAudioDialog::loadConfig() myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); + // Adapt refresh rate + myRefreshAdjust->setState(instance().settings().getBool("tia.refresh")); handleFullScreenChange(); // Aspect ratio setting (NTSC and PAL) @@ -597,6 +605,8 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); + // Adapt refresh rate + instance().settings().setValue("tia.refresh", myRefreshAdjust->getState()); // TIA zoom levels instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); @@ -709,6 +719,7 @@ void VideoAudioDialog::setDefaults() //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); myTVOverscan->setValue(0); + myRefreshAdjust->setState(false); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -834,6 +845,7 @@ void VideoAudioDialog::handleFullScreenChange() bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); myTVOverscan->setEnabled(enable); + myRefreshAdjust->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index f46740ae6..6764bc556 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -74,6 +74,7 @@ class VideoAudioDialog : public Dialog //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; + CheckboxWidget* myRefreshAdjust{nullptr}; SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 2bf7421d1b206c81e91e355dfee999103b5a8d13 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 18 May 2020 21:13:18 +0200 Subject: [PATCH 02/14] improved refresh rate code --- src/common/FrameBufferSDL2.cxx | 130 +++++++++++++++++++-------------- src/common/FrameBufferSDL2.hxx | 16 +++- src/emucore/FrameBuffer.cxx | 10 ++- src/emucore/FrameBuffer.hxx | 5 ++ src/emucore/Settings.cxx | 3 +- src/gui/VideoAudioDialog.cxx | 28 +++---- src/gui/VideoAudioDialog.hxx | 3 +- 7 files changed, 115 insertions(+), 80 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index a1a9c5bbd..37d2e5499 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -218,6 +218,10 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_WasInit(SDL_INIT_VIDEO) == 0) return false; + const bool fullScreen = mode.fsIndex != -1; + const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") + && refreshRate() != gameRefreshRate(); + // TODO: On multiple displays, switching from centered mode, does not respect // current window's display (which many not be centered anymore) @@ -261,8 +265,11 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posX = BSPF::clamp(posX, x0 - Int32(mode.screen.w) + 50, x1 - 50); posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } - uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; - flags |= SDL_WINDOW_ALLOW_HIGHDPI; + + SDL_DisplayMode adaptedSdlMode; + const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode); + const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI + | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); // macOS seems to have issues with destroying the window, and wants to // keep the same handle @@ -278,12 +285,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) int w, h; SDL_GetWindowSize(myWindow, &w, &h); - if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h) + if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h + || shouldAdapt) { SDL_DestroyWindow(myWindow); myWindow = nullptr; } } + if(myWindow) { // Even though window size stayed the same, the title may have changed @@ -312,8 +321,24 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) Logger::error(msg); return false; } + setWindowIcon(); } + if(adaptRefresh) + { + // Switch to mode for adapted refresh rate + if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0) + { + Logger::error("Display refresh rate change failed"); + } + else + { + ostringstream msg; + + msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << "Hz"; + Logger::info(msg.str()); + } + } uInt32 renderFlags = SDL_RENDERER_ACCELERATED; if(myOSystem.settings().getBool("vsync") @@ -340,70 +365,35 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); - adaptRefreshRate(); - return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::adaptRefreshRate() +bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode) { - const bool adapt = myOSystem.settings().getBool("tia.refresh"); + SDL_DisplayMode sdlMode; - // adapt only in emulation (and debugger?) and fullscreen mode - // TODO: adapt while creating new window - if(adapt && fullScreen() - && (myBufferType == BufferType::Emulator/* || myBufferType == BufferType::Debugger*/)) + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) { - SDL_DisplayMode sdlMode; + Logger::error("Display mode could not be retrieved"); + return false; + } - if(SDL_GetWindowDisplayMode(myWindow, &sdlMode) != 0) + 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("Display mode could not be retrieved"); + Logger::error("Closest display mode could not be retrieved"); return false; } - - const int currentRefreshRate = sdlMode.refresh_rate; - const string format = myOSystem.console().getFormatString(); - const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - - sdlMode.refresh_rate = isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too - - if(currentRefreshRate != sdlMode.refresh_rate) - { - const int display = SDL_GetWindowDisplayIndex(myWindow); - SDL_DisplayMode closestSdlMode; - - if(SDL_GetClosestDisplayMode(display, &sdlMode, &closestSdlMode) == NULL) - { - Logger::error("Closest display mode could not be retrieved"); - return false; - } - // Note: Modes are scanned with size being first priority, - // therefore the size will never change. - // Only change if the display supports a better refresh rate - if(currentRefreshRate != closestSdlMode.refresh_rate) - { - // Switch to new mode - if(SDL_SetWindowDisplayMode(myWindow, &closestSdlMode) != 0) - { - Logger::error("Display refresh rate change failed"); - return false; - } - // Any change only works in real fullscreen mode! - if(SDL_SetWindowFullscreen(myWindow, SDL_WINDOW_FULLSCREEN) != 0) - { - Logger::error("Display fullscreen change failed"); - return false; - } - ostringstream msg; - - msg << "Display refresh rate changed from " << currentRefreshRate << "Hz to " - << closestSdlMode.refresh_rate << "Hz"; - Logger::info(msg.str()); - return true; - } - } + // Only change if the display supports a better refresh rate + return currentRefreshRate != closestSdlMode.refresh_rate; } return false; } @@ -469,6 +459,34 @@ bool FrameBufferSDL2::fullScreen() const #endif } +int FrameBufferSDL2::refreshRate() const +{ + ASSERT_MAIN_THREAD; + + const uInt32 displayIndex = SDL_GetWindowDisplayIndex(myWindow); + SDL_DisplayMode sdlMode; + + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0) + return sdlMode.refresh_rate; + + if (myWindow != NULL) + Logger::error("Could not retrieve current display mode"); + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FrameBufferSDL2::gameRefreshRate() const +{ + if(myOSystem.hasConsole()) + { + 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 60; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::renderToScreen() { diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 0d74d100b..f0d69bc96 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -183,11 +183,11 @@ class FrameBufferSDL2 : public FrameBuffer /** - Adapt display refresh rate to game refresh rate in (real) fullscreen mode + Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode - @return True if the refresh rate was changed + @return True if the refresh rate should be changed */ - bool adaptRefreshRate(); + bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& closestSdlMode); /** This method is called to create a surface with the given attributes. @@ -241,6 +241,16 @@ class FrameBufferSDL2 : public FrameBuffer */ void determineDimensions(); + /** + Retrieve the current display's refresh rate, or 0 if no window + */ + int refreshRate() const override; + + /** + Retrieve the current game's refresh rate, or 60 if no game + */ + int gameRefreshRate() const; + private: // The SDL video buffer SDL_Window* myWindow{nullptr}; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 4599a3860..2d495c101 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -993,7 +993,15 @@ void FrameBuffer::toggleFullscreen(bool toggle) setFullscreen(isFullscreen); - showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled")); + ostringstream msg; + + msg << "Fullscreen "; + if(isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; + + showMessage(msg.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index e19fcc335..945cbb780 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -518,6 +518,11 @@ class FrameBuffer */ virtual string about() const = 0; + /** + Retrieve the current display's refresh rate + */ + virtual int refreshRate() const { return 0; } + protected: // The parent system for the framebuffer OSystem& myOSystem; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index bbcc0c4bd..dca79717d 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -52,9 +52,9 @@ Settings::Settings() setPermanent("tia.zoom", "3"); setPermanent("fullscreen", "false"); setPermanent("tia.fs_stretch", "false"); + setPermanent("tia.fs_refresh", "false"); setPermanent("tia.fs_overscan", "0"); setPermanent("tia.vsizeadjust", 0); - setPermanent("tia.refresh", "false"); setPermanent("tia.dbgcolors", "roygpb"); // Palette options setPermanent("palette", PaletteHandler::SETTING_STANDARD); @@ -442,6 +442,7 @@ void Settings::usage() const << " -tia.inter <1|0> Enable interpolated (smooth) scaling for TIA\n" << " image\n" << " -tia.fs_stretch <1|0> Stretch TIA image to fill fullscreen mode\n" + << " -tia.fs_refresh <1|0> Try to adapt display refresh rate to game\n" << " -tia.fs_overscan <0-10> Add overscan to TIA image in fullscreen mode\n" << " -tia.dbgcolors Debug colors to use for each object (see manual\n" << " for description)\n" diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 74b326f7c..46203783a 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -149,29 +149,23 @@ void VideoAudioDialog::addDisplayTab() wid.push_back(myFullscreen); ypos += lineHeight + VGAP; - /*pwidth = font.getStringWidth("0: 3840x2860@120Hz"); - myFullScreenMode = new PopUpWidget(myTab, font, xpos + INDENT + 2, ypos, pwidth, lineHeight, - instance().frameBuffer().supportedScreenModes(), "Mode "); - wid.push_back(myFullScreenMode); - ypos += lineHeight + VGAP;*/ - // FS stretch myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); + + // Adapt refresh rate ypos += lineHeight + VGAP; + myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); + wid.push_back(myRefreshAdapt); // FS overscan + ypos += lineHeight + VGAP; myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, "Overscan", lwidth - INDENT, kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); - // Adapt refresh rate - ypos += lineHeight + VGAP; - myRefreshAdjust = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt refresh rate"); - wid.push_back(myRefreshAdjust); - // Vertical size ypos += lineHeight + VGAP; myVSizeAdjust = @@ -490,10 +484,10 @@ void VideoAudioDialog::loadConfig() myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); + // Adapt refresh rate + myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); - // Adapt refresh rate - myRefreshAdjust->setState(instance().settings().getBool("tia.refresh")); handleFullScreenChange(); // Aspect ratio setting (NTSC and PAL) @@ -603,10 +597,10 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); + // Adapt refresh rate + instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); - // Adapt refresh rate - instance().settings().setValue("tia.refresh", myRefreshAdjust->getState()); // TIA zoom levels instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); @@ -718,8 +712,8 @@ void VideoAudioDialog::setDefaults() myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + myRefreshAdapt->setState(false); myTVOverscan->setValue(0); - myRefreshAdjust->setState(false); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -844,8 +838,8 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); + myRefreshAdapt->setEnabled(enable); myTVOverscan->setEnabled(enable); - myRefreshAdjust->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 6764bc556..0961f776e 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -71,10 +71,9 @@ class VideoAudioDialog : public Dialog PopUpWidget* myRenderer{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; CheckboxWidget* myFullscreen{nullptr}; - //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - CheckboxWidget* myRefreshAdjust{nullptr}; + CheckboxWidget* myRefreshAdapt{nullptr}; SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 41d217e17d32853f129689d13313eb11da62c289 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 08:53:11 +0200 Subject: [PATCH 03/14] fix window position saving when switching from/to fullscreen mode suppress fullscreen UI message outside emulation mode --- src/common/FrameBufferSDL2.cxx | 2 +- src/emucore/FrameBuffer.cxx | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 37d2e5499..8a943332c 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -482,7 +482,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 ? 75 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 2d495c101..88f62517f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -959,6 +959,7 @@ void FrameBuffer::setFullscreen(bool enable) default: return; } + saveCurrentWindowPosition(); // Changing the video mode can take some time, during which the last // sound played may get 'stuck' @@ -993,15 +994,18 @@ void FrameBuffer::toggleFullscreen(bool toggle) setFullscreen(isFullscreen); - ostringstream msg; + if(myBufferType == BufferType::Emulator) + { + ostringstream msg; - msg << "Fullscreen "; - if(isFullscreen) - msg << "enabled (" << refreshRate() << " Hz)"; - else - msg << "disabled"; + msg << "Fullscreen "; + if(isFullscreen) + msg << "enabled (" << refreshRate() << " Hz)"; + else + msg << "disabled"; - showMessage(msg.str()); + showMessage(msg.str()); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From cde78a779669a34a201baf92daaf05135e1ccd7b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 10:19:48 +0200 Subject: [PATCH 04/14] oops --- src/common/FrameBufferSDL2.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 8a943332c..37d2e5499 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -482,7 +482,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } From 5aca14c2481b8e27d55162e3eca656cc56c163cf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 12:33:01 +0200 Subject: [PATCH 05/14] try to create renderer only when required (needs testing) --- src/common/FrameBufferSDL2.cxx | 92 +++++++++++++++++++++++++++------- src/common/FrameBufferSDL2.hxx | 8 +++ 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 37d2e5499..c977405fa 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -221,6 +221,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") && refreshRate() != gameRefreshRate(); + bool forceCreateRenderer = false; // TODO: On multiple displays, switching from centered mode, does not respect // current window's display (which many not be centered anymore) @@ -230,12 +231,12 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // Get windowed window's last position myWindowedPos = myOSystem.settings().getPoint(getPositionKey()); - // Always recreate renderer (some systems need this) - if(myRenderer) - { - SDL_DestroyRenderer(myRenderer); - myRenderer = nullptr; - } + //// Always recreate renderer (some systems need this) + //if(myRenderer) + //{ + // SDL_DestroyRenderer(myRenderer); + // myRenderer = nullptr; + //} int posX, posY; @@ -313,6 +314,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) #endif else { + forceCreateRenderer = true; myWindow = SDL_CreateWindow(title.c_str(), posX, posY, mode.screen.w, mode.screen.h, flags); if(myWindow == nullptr) @@ -340,24 +342,78 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } } + return createRenderer(forceCreateRenderer); + + //uInt32 renderFlags = SDL_RENDERER_ACCELERATED; + //if(myOSystem.settings().getBool("vsync") + // && !myOSystem.settings().getBool("turbo")) // V'synced blits option + // renderFlags |= SDL_RENDERER_PRESENTVSYNC; + //const string& video = myOSystem.settings().getString("video"); // Render hint + //if(video != "") + // SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); + + //myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); + + //detectFeatures(); + //determineDimensions(); + + //if(myRenderer == nullptr) + //{ + // string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); + // Logger::error(msg); + // return false; + //} + //clear(); + + //SDL_RendererInfo renderinfo; + //if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) + // myOSystem.settings().setValue("video", renderinfo.name); + + //return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBufferSDL2::createRenderer(bool force) +{ + // A new renderer is only created when necessary: + // - new myWindow (force = true) + // - no renderer existing + // - different renderer flags + // - different renderer name + bool recreate = force || myRenderer == nullptr; uInt32 renderFlags = SDL_RENDERER_ACCELERATED; + const string& video = myOSystem.settings().getString("video"); // Render hint + SDL_RendererInfo renderInfo; + if(myOSystem.settings().getBool("vsync") && !myOSystem.settings().getBool("turbo")) // V'synced blits option renderFlags |= SDL_RENDERER_PRESENTVSYNC; - const string& video = myOSystem.settings().getString("video"); // Render hint - if(video != "") - SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); - myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); + // check renderer flags and name + recreate |= (SDL_GetRendererInfo(myRenderer, &renderInfo) != 0) + || ((renderInfo.flags & (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) != renderFlags + || (video != renderInfo.name)); - detectFeatures(); - determineDimensions(); - - if(myRenderer == nullptr) + if(recreate) { - string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); - Logger::error(msg); - return false; + cerr << "Create new renderer " << int(myBufferType) << endl; + if(myRenderer) + SDL_DestroyRenderer(myRenderer); + + if(video != "") + SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); + + myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); + + detectFeatures(); + determineDimensions(); + + if(myRenderer == nullptr) + { + string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); + Logger::error(msg); + return false; + } } clear(); @@ -482,7 +538,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 ? 75 : 50; // TODO: check for multiples e.g. 120/100 too } return 60; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index f0d69bc96..1799b5c6f 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,14 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + /** + Create a new renderer if required + + @param force If true, force new renderer creation + + @return False on any errors, else true + */ + bool createRenderer(bool force); /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode From 1a5f4aedc4d12af5d4dd8100d9d7c2cd2bfc674d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 19 May 2020 19:37:06 +0200 Subject: [PATCH 06/14] added avoiding switching refresh rate when going back to launcher improved error logging messages --- src/common/FrameBufferSDL2.cxx | 55 +++++++--------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index c977405fa..691e96510 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -220,24 +220,14 @@ 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") - && refreshRate() != gameRefreshRate(); + && gameRefreshRate() && refreshRate() != gameRefreshRate(); bool forceCreateRenderer = false; - // TODO: On multiple displays, switching from centered mode, does not respect - // current window's display (which many not be centered anymore) - // Get windowed window's last display Int32 displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt(getDisplayKey())); // Get windowed window's last position myWindowedPos = myOSystem.settings().getPoint(getPositionKey()); - //// Always recreate renderer (some systems need this) - //if(myRenderer) - //{ - // SDL_DestroyRenderer(myRenderer); - // myRenderer = nullptr; - //} - int posX, posY; myCenter = myOSystem.settings().getBool("center"); @@ -282,7 +272,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // as it's not necessary, and causes flashing in fullscreen mode if(myWindow) { - int d = SDL_GetWindowDisplayIndex(myWindow); + const int d = SDL_GetWindowDisplayIndex(myWindow); int w, h; SDL_GetWindowSize(myWindow, &w, &h); @@ -331,7 +321,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) // Switch to mode for adapted refresh rate if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0) { - Logger::error("Display refresh rate change failed"); + Logger::error("ERROR: Display refresh rate change failed"); } else { @@ -343,33 +333,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } return createRenderer(forceCreateRenderer); - - //uInt32 renderFlags = SDL_RENDERER_ACCELERATED; - //if(myOSystem.settings().getBool("vsync") - // && !myOSystem.settings().getBool("turbo")) // V'synced blits option - // renderFlags |= SDL_RENDERER_PRESENTVSYNC; - //const string& video = myOSystem.settings().getString("video"); // Render hint - //if(video != "") - // SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); - - //myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); - - //detectFeatures(); - //determineDimensions(); - - //if(myRenderer == nullptr) - //{ - // string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); - // Logger::error(msg); - // return false; - //} - //clear(); - - //SDL_RendererInfo renderinfo; - //if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) - // myOSystem.settings().setValue("video", renderinfo.name); - - //return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -396,7 +359,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); @@ -418,6 +381,7 @@ bool FrameBufferSDL2::createRenderer(bool force) clear(); SDL_RendererInfo renderinfo; + if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); @@ -431,7 +395,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& clos if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) { - Logger::error("Display mode could not be retrieved"); + Logger::error("ERROR: Display mode could not be retrieved"); return false; } @@ -445,11 +409,12 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& clos // therefore the size will never change. if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) { - Logger::error("Closest display mode could not be retrieved"); + 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; } @@ -538,9 +503,9 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 75 : 50; // TODO: check for multiples e.g. 120/100 too + return isNtsc ? 60 : 50; // TODO: check for multiples e.g. 120/100 too } - return 60; + return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 842b40e5436b76a9604dee74e037e485f71e6d05 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 20 May 2020 10:19:31 +0200 Subject: [PATCH 07/14] 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. From 0920518d29d601d81cc98bad4616b510357c9930 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 21 May 2020 22:15:13 -0230 Subject: [PATCH 08/14] Fix compilation in Xcode. --- src/common/FrameBufferSDL2.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 72484c468..0d5813168 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include + #include "SDL_lib.hxx" #include "bspf.hxx" #include "Logger.hxx" From 9ea920524bf7de4f66ac11f4239f0c5cbaee7e45 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 22 May 2020 09:05:48 +0200 Subject: [PATCH 09/14] more compact available video modes logging --- src/common/FrameBufferSDL2.cxx | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 0d5813168..6070abbce 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -101,19 +101,32 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, int numModes = SDL_GetNumDisplayModes(i); ostringstream s; - s << "Supported video modes for display " << i << ":"; - Logger::debug(s.str()); + s << "Supported video modes (" << numModes << ") for display " << i << ":"; + + string lastRes = ""; + for (int m = 0; m < numModes; m++) { SDL_DisplayMode mode; + ostringstream res; SDL_GetDisplayMode(i, m, &mode); - s.str(""); - s << " " << m << ": " << mode.w << "x" << mode.h << "@" << mode.refresh_rate << "Hz"; - if (mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate) - s << " (active)"; - Logger::debug(s.str()); + res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h; + + if(lastRes != res.str()) + { + Logger::debug(s.str()); + s.str(""); + lastRes = res.str(); + s << lastRes << ": "; + } + s << mode.refresh_rate << "Hz"; + if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate) + s << "* "; + else + s << " "; } + Logger::debug(s.str()); } // Now get the maximum windowed desktop resolution @@ -329,7 +342,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { ostringstream msg; - msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << "Hz"; + msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz"; Logger::info(msg.str()); } } @@ -412,7 +425,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - cerr << "Create new renderer " << int(myBufferType) << endl; + cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); From f426f160a96e0d25801b04bac570df1cab084180 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 22 May 2020 15:07:20 -0230 Subject: [PATCH 10/14] Fix minor warnings from clang. --- src/common/FrameBufferSDL2.cxx | 6 ++++-- src/common/FrameBufferSDL2.hxx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 6070abbce..a912b8ad3 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -376,7 +376,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap SDL_DisplayMode closestSdlMode; sdlMode.refresh_rate = wantedRefreshRate * m; - if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == NULL) + if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr) { Logger::error("ERROR: Closest display mode could not be retrieved"); return adapt; @@ -515,6 +515,7 @@ bool FrameBufferSDL2::fullScreen() const #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int FrameBufferSDL2::refreshRate() const { ASSERT_MAIN_THREAD; @@ -525,8 +526,9 @@ int FrameBufferSDL2::refreshRate() const if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0) return sdlMode.refresh_rate; - if (myWindow != NULL) + if(myWindow != nullptr) Logger::error("Could not retrieve current display mode"); + return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 08005f85a..7904ed0ee 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -184,8 +184,8 @@ class FrameBufferSDL2 : public FrameBuffer /** 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 + @param displayIndex The display which should be checked + @param adaptedSdlMode The best matching mode if the refresh rate should be changed @return True if the refresh rate should be changed */ From de9277e98e4181dcf9f6d52ef85b5d326f96ea8c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 23 May 2020 12:29:31 +0200 Subject: [PATCH 11/14] handle rounded refresh rates like 59.94 Hz disable refresh adjust option for macOS --- src/common/FrameBufferSDL2.cxx | 91 ++++++++++++++++++++++++++++++++-- src/common/FrameBufferSDL2.hxx | 2 + src/gui/VideoAudioDialog.cxx | 10 ++++ src/gui/VideoAudioDialog.hxx | 2 + 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index a912b8ad3..9bb0dae57 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -234,8 +234,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) return false; const bool fullScreen = mode.fsIndex != -1; - const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && gameRefreshRate() && refreshRate() % gameRefreshRate() != 0; bool forceCreateRenderer = false; // Get windowed window's last display @@ -272,8 +270,17 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } +#ifndef BSPF_MACOS + // macOS does not allow to change the display refresh rate SDL_DisplayMode adaptedSdlMode; + const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") + && gameRefreshRate() + // take care of 59.94 Hz + && refreshRate() % gameRefreshRate() != 0 && refreshRate() % (gameRefreshRate() - 1) != 0; const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode); +#else + const bool adaptRefresh = false; +#endif const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); @@ -331,6 +338,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) setWindowIcon(); } +#ifndef BSPF_MACOS if(adaptRefresh) { // Switch to mode for adapted refresh rate @@ -346,10 +354,11 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) Logger::info(msg.str()); } } - +#endif return createRenderer(forceCreateRenderer); } +#ifndef BSPF_MACOS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) { @@ -363,7 +372,10 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap const int currentRefreshRate = sdlMode.refresh_rate; const int wantedRefreshRate = gameRefreshRate(); - float factor = float(currentRefreshRate) / wantedRefreshRate; + // Take care of rounded refresh rates (e.g. 59.94 Hz) + float factor = std::min(float(currentRefreshRate) / wantedRefreshRate, + float(currentRefreshRate) / (wantedRefreshRate - 1)); + // Calculate difference taking care of integer factors (e.g. 100/120) float bestDiff = std::abs(factor - std::round(factor)) / factor; bool adapt = false; @@ -382,6 +394,8 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap return adapt; } factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; + factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate, + float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1)); const float diff = std::abs(factor - std::round(factor)) / factor; if(diff < bestDiff) { @@ -399,7 +413,74 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap // Only change if the display supports a better refresh rate return adapt; + +#if 0 + // Adapting resfresh rate and display size + const bool hiDpi = myOSystem.settings().getBool("hidpi"); + const float mult = float(font().getFontHeight()) / getFontDesc("medium").height * hiDpi ? 2 : 1; + const Int32 minWidth = FBMinimum::Width * mult; + const Int32 minHeight = FBMinimum::Height * mult; + SDL_DisplayMode sdlMode; + + if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) + { + Logger::error("ERROR: Display mode could not be retrieved"); + return false; + } + + const int numModes = SDL_GetNumDisplayModes(displayIndex); + if(numModes < 0) + { + Logger::error("ERROR: Number of display modes could not be retrieved"); + return false; + } + + const int currentRefreshRate = sdlMode.refresh_rate; + const int wantedRefreshRate = gameRefreshRate(); + // Take care of rounded refresh rates (e.g. 59.94) + float factor = std::min(float(currentRefreshRate) / wantedRefreshRate, + float(currentRefreshRate) / (wantedRefreshRate - 1)); + // Calculate difference taking care of integer factors (e.g. 100/120) + float bestDiff = std::abs(factor - std::round(factor)) / factor; + bool adapt = false; + + for(int mode = 0; mode < numModes; ++mode) + { + // Note: Display modes returned are sorted by width, height,... refresh_rate + if(SDL_GetDisplayMode(displayIndex, mode, &sdlMode) != 0) + { + Logger::error("ERROR: Display modes could not be retrieved"); + return false; + } + // skip too small modes + if(sdlMode.w < minWidth || sdlMode.h < minHeight) + continue; + + cerr << sdlMode.w << "x" << sdlMode.h << " " << sdlMode.refresh_rate << " Hz" << endl; + + factor = std::min(float(sdlMode.refresh_rate) / wantedRefreshRate, + float(sdlMode.refresh_rate) / (wantedRefreshRate - 1)); + const float diff = std::abs(factor - std::round(factor)) / factor; + if(diff < bestDiff) + { + bestDiff = diff; + adaptedSdlMode = sdlMode; + 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; +#endif } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::createRenderer(bool force) @@ -540,7 +621,7 @@ int FrameBufferSDL2::gameRefreshRate() const const string format = myOSystem.console().getFormatString(); const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - return isNtsc ? 60 : 50; + return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz } return 0; } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 7904ed0ee..282cf2100 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,6 +181,7 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; + #ifndef BSPF_MACOS /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode @@ -190,6 +191,7 @@ class FrameBufferSDL2 : public FrameBuffer @return True if the refresh rate should be changed */ bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); + #endif /** Create a new renderer if required diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 46203783a..edce71e10 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -153,10 +153,12 @@ void VideoAudioDialog::addDisplayTab() myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); +#ifndef BSPF_MACOS // Adapt refresh rate ypos += lineHeight + VGAP; myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); wid.push_back(myRefreshAdapt); +#endif // FS overscan ypos += lineHeight + VGAP; @@ -484,8 +486,10 @@ void VideoAudioDialog::loadConfig() myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); +#ifndef BSPF_MACOS // Adapt refresh rate myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); +#endif // Fullscreen overscan setting myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); handleFullScreenChange(); @@ -597,8 +601,10 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); +#ifndef BSPF_MACOS // Adapt refresh rate instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); +#endif // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); @@ -712,7 +718,9 @@ void VideoAudioDialog::setDefaults() myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + #ifndef BSPF_MACOS myRefreshAdapt->setState(false); + #endif myTVOverscan->setValue(0); myTIAZoom->setValue(300); myVSizeAdjust->setValue(0); @@ -838,7 +846,9 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); +#ifndef BSPF_MACOS myRefreshAdapt->setEnabled(enable); +#endif myTVOverscan->setEnabled(enable); } diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 0961f776e..c20b39438 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -73,7 +73,9 @@ class VideoAudioDialog : public Dialog CheckboxWidget* myFullscreen{nullptr}; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; + #ifndef BSPF_MACOS CheckboxWidget* myRefreshAdapt{nullptr}; + #endif SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From c4aa9b2a56bacbd74bbd3a67ffcc243272ee997a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 23 May 2020 20:50:14 +0200 Subject: [PATCH 12/14] updated doc for fullscreen refresh rate adaption removed debug output --- Changes.txt | 2 ++ docs/graphics/options_video.png | Bin 2744 -> 3001 bytes docs/index.html | 15 +++++++++++---- src/common/FrameBufferSDL2.cxx | 15 +++++++-------- src/emucore/Settings.cxx | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Changes.txt b/Changes.txt index 557157f25..616ec22f7 100644 --- a/Changes.txt +++ b/Changes.txt @@ -37,6 +37,8 @@ * Added separate positioning of launcher, emulator and debugger + * Added optional display to game refresh rate adaption in fullscreen mode + * Added option which lets default ROM path follow launcher navigation * Added debugger 'saveaccess' function, which saves memory access counts to diff --git a/docs/graphics/options_video.png b/docs/graphics/options_video.png index deb857ca4984e0d5815c693b739e4628a3b1b429..58654148ab3e6db654681c658c828eade4523b08 100644 GIT binary patch delta 2885 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 + +
-tia.fs_refresh <1|0>
+ While in fullscreen mode, adapt the display's refresh rate to the game's frame rate + to minimize judder. + +
-tia.fs_overscan <0 - 10>
Add overscan to TIA image while in fullscreen mode @@ -2943,13 +2949,14 @@ - - + + - + + - +
ItemBrief descriptionFor more information,
see CommandLine
RendererUse specified rendering mode-video
InterpolationInterpolation of TIA image-tia.inter
ZoomZoom level of TIA image-tia.zoom
InterpolationEnable interpolation of the TIA image-tia.inter
ZoomZoom level of the TIA image-tia.zoom
FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen
StretchIn fullscreen mode, completely fill screen with TIA image-tia.fs_stretch
StretchIn fullscreen mode, completely fill screen with the TIA image.-tia.fs_stretch
Adapt display...In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder.-tia.fs_refresh
OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan
V-Size adjustAdjust height of TIA image-tia.vsizeadjust
V-Size adjustAdjust height of the TIA image-tia.vsizeadjust
diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 9bb0dae57..612000943 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -393,7 +393,6 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap Logger::error("ERROR: Closest display mode could not be retrieved"); return adapt; } - factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate, float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1)); const float diff = std::abs(factor - std::round(factor)) / factor; @@ -404,12 +403,12 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap adapt = true; } } - cerr << "refresh rate adapt "; - if(adapt) - cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)"; - else - cerr << "not required/possible"; - cerr << endl; + //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; @@ -506,7 +505,7 @@ bool FrameBufferSDL2::createRenderer(bool force) if(recreate) { - cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; + //cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl; if(myRenderer) SDL_DestroyRenderer(myRenderer); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index dca79717d..790c784bb 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -442,7 +442,7 @@ void Settings::usage() const << " -tia.inter <1|0> Enable interpolated (smooth) scaling for TIA\n" << " image\n" << " -tia.fs_stretch <1|0> Stretch TIA image to fill fullscreen mode\n" - << " -tia.fs_refresh <1|0> Try to adapt display refresh rate to game\n" + << " -tia.fs_refresh <1|0> Try to adapt display refresh rate to game's FPS\n" << " -tia.fs_overscan <0-10> Add overscan to TIA image in fullscreen mode\n" << " -tia.dbgcolors Debug colors to use for each object (see manual\n" << " for description)\n" From ac9143ef08ace05655f08769e0f432cfdafef305 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 23 May 2020 17:15:42 -0230 Subject: [PATCH 13/14] Add 'ADAPTABLE_REFRESH_SUPPORT', and enable it on non-Mac systems. Cleaned up some dead code. Made MacOS toggle from windowed to fullscreen work the same as all other systems. --- src/common/FrameBufferSDL2.cxx | 96 ++-------------------------------- src/common/FrameBufferSDL2.hxx | 2 - src/common/bspf.hxx | 6 +++ src/gui/VideoAudioDialog.cxx | 24 +++------ src/gui/VideoAudioDialog.hxx | 2 - 5 files changed, 18 insertions(+), 112 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 612000943..d930b2fc0 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -270,8 +270,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } -#ifndef BSPF_MACOS - // macOS does not allow to change the display refresh rate +#ifdef ADAPTABLE_REFRESH_SUPPORT SDL_DisplayMode adaptedSdlMode; const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") && gameRefreshRate() @@ -284,12 +283,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - // macOS seems to have issues with destroying the window, and wants to - // keep the same handle - // Problem is, doing so on other platforms results in flickering when - // toggling fullscreen windowed mode - // So we have a special case for macOS -#ifndef BSPF_MACOS // Don't re-create the window if its display and size hasn't changed, // as it's not necessary, and causes flashing in fullscreen mode if(myWindow) @@ -312,18 +305,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) SDL_SetWindowTitle(myWindow, title.c_str()); SDL_SetWindowPosition(myWindow, posX, posY); } -#else - // macOS wants to *never* re-create the window - // This sometimes results in the window being resized *after* it's displayed, - // but at least the code works and doesn't crash - if(myWindow) - { - SDL_SetWindowFullscreen(myWindow, flags); - SDL_SetWindowSize(myWindow, mode.screen.w, mode.screen.h); - SDL_SetWindowPosition(myWindow, posX, posY); - SDL_SetWindowTitle(myWindow, title.c_str()); - } -#endif else { forceCreateRenderer = true; @@ -338,7 +319,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) setWindowIcon(); } -#ifndef BSPF_MACOS + +#ifdef ADAPTABLE_REFRESH_SUPPORT if(adaptRefresh) { // Switch to mode for adapted refresh rate @@ -355,10 +337,10 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } } #endif + return createRenderer(forceCreateRenderer); } -#ifndef BSPF_MACOS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) { @@ -412,74 +394,7 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap // Only change if the display supports a better refresh rate return adapt; - -#if 0 - // Adapting resfresh rate and display size - const bool hiDpi = myOSystem.settings().getBool("hidpi"); - const float mult = float(font().getFontHeight()) / getFontDesc("medium").height * hiDpi ? 2 : 1; - const Int32 minWidth = FBMinimum::Width * mult; - const Int32 minHeight = FBMinimum::Height * mult; - SDL_DisplayMode sdlMode; - - if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) - { - Logger::error("ERROR: Display mode could not be retrieved"); - return false; - } - - const int numModes = SDL_GetNumDisplayModes(displayIndex); - if(numModes < 0) - { - Logger::error("ERROR: Number of display modes could not be retrieved"); - return false; - } - - const int currentRefreshRate = sdlMode.refresh_rate; - const int wantedRefreshRate = gameRefreshRate(); - // Take care of rounded refresh rates (e.g. 59.94) - float factor = std::min(float(currentRefreshRate) / wantedRefreshRate, - float(currentRefreshRate) / (wantedRefreshRate - 1)); - // Calculate difference taking care of integer factors (e.g. 100/120) - float bestDiff = std::abs(factor - std::round(factor)) / factor; - bool adapt = false; - - for(int mode = 0; mode < numModes; ++mode) - { - // Note: Display modes returned are sorted by width, height,... refresh_rate - if(SDL_GetDisplayMode(displayIndex, mode, &sdlMode) != 0) - { - Logger::error("ERROR: Display modes could not be retrieved"); - return false; - } - // skip too small modes - if(sdlMode.w < minWidth || sdlMode.h < minHeight) - continue; - - cerr << sdlMode.w << "x" << sdlMode.h << " " << sdlMode.refresh_rate << " Hz" << endl; - - factor = std::min(float(sdlMode.refresh_rate) / wantedRefreshRate, - float(sdlMode.refresh_rate) / (wantedRefreshRate - 1)); - const float diff = std::abs(factor - std::round(factor)) / factor; - if(diff < bestDiff) - { - bestDiff = diff; - adaptedSdlMode = sdlMode; - 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; -#endif } -#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::createRenderer(bool force) @@ -637,10 +552,9 @@ void FrameBufferSDL2::renderToScreen() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setWindowIcon() { - ASSERT_MAIN_THREAD; - #if !defined(BSPF_MACOS) && !defined(RETRON77) #include "stella_icon.hxx" + ASSERT_MAIN_THREAD; SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index 282cf2100..7904ed0ee 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -181,7 +181,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool setVideoMode(const string& title, const VideoMode& mode) override; - #ifndef BSPF_MACOS /** Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode @@ -191,7 +190,6 @@ class FrameBufferSDL2 : public FrameBuffer @return True if the refresh rate should be changed */ bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); - #endif /** Create a new renderer if required diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index f21a99a4c..3fc1aaf6c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -101,6 +101,12 @@ static const string EmptyString(""); #undef PAGE_SIZE #undef PAGE_MASK +// Adaptable refresh is currently not available on MacOS +// In the future, this may expand to other systems +#if !defined(BSPF_MACOS) + #define ADAPTABLE_REFRESH_SUPPORT +#endif + namespace BSPF { static constexpr float PI_f = 3.141592653589793238462643383279502884F; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index edce71e10..c51685fcf 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -83,14 +83,6 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, addTVEffectsTab(); addAudioTab(); - //const int req_w = std::max(myFastSCBios->getRight(), myCloneBad->getRight()) + HBORDER + 1; - //const int req_h = _th + VGAP * 3 - // + std::max(myUseVSync->getBottom(), myTVScanIntense->getBottom()) - // + buttonHeight + VBORDER * 2; - //// Set real dimensions - //setSize(req_w, req_h, max_w, max_h); - - // Add Defaults, OK and Cancel buttons WidgetArray wid; addDefaultsOKCancelBGroup(wid, _font); @@ -153,11 +145,13 @@ void VideoAudioDialog::addDisplayTab() myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT // Adapt refresh rate ypos += lineHeight + VGAP; myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); wid.push_back(myRefreshAdapt); +#else + myRefreshAdapt = nullptr; #endif // FS overscan @@ -482,11 +476,9 @@ void VideoAudioDialog::loadConfig() // Fullscreen myFullscreen->setState(instance().settings().getBool("fullscreen")); - /*string mode = instance().settings().getString("fullscreenmode"); - myFullScreenMode->setSelected(mode);*/ // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT // Adapt refresh rate myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); #endif @@ -601,7 +593,7 @@ void VideoAudioDialog::saveConfig() instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT // Adapt refresh rate instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); #endif @@ -621,7 +613,6 @@ void VideoAudioDialog::saveConfig() // Note: Palette values are saved directly when changed! - ///////////////////////////////////////////////////////////////////////////// // TV Effects tab // TV Mode @@ -716,9 +707,8 @@ void VideoAudioDialog::setDefaults() myTIAInterpolate->setState(false); // screen size myFullscreen->setState(false); - //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); - #ifndef BSPF_MACOS + #ifdef ADAPTABLE_REFRESH_SUPPORT myRefreshAdapt->setState(false); #endif myTVOverscan->setValue(0); @@ -846,7 +836,7 @@ void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); -#ifndef BSPF_MACOS +#ifdef ADAPTABLE_REFRESH_SUPPORT myRefreshAdapt->setEnabled(enable); #endif myTVOverscan->setEnabled(enable); diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index c20b39438..0961f776e 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -73,9 +73,7 @@ class VideoAudioDialog : public Dialog CheckboxWidget* myFullscreen{nullptr}; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - #ifndef BSPF_MACOS CheckboxWidget* myRefreshAdapt{nullptr}; - #endif SliderWidget* myTIAZoom{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; From 449bfb38d95ac79710bd8d226b882f5ac820bdf1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 24 May 2020 10:03:53 +0200 Subject: [PATCH 14/14] updated doc (adapting refresh not available for macOS) added event and hotkey for adapting refresh rate fixed endless loop in global hotkeys --- docs/index.html | 15 ++++++++++--- src/common/PKeyboardHandler.cxx | 1 + src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 37 +++++++++++++++++++++++++++------ src/emucore/EventHandler.hxx | 10 ++++++++- src/emucore/FrameBuffer.cxx | 29 ++++++++++++++++++++++++++ src/emucore/FrameBuffer.hxx | 7 +++++++ 7 files changed, 90 insertions(+), 10 deletions(-) diff --git a/docs/index.html b/docs/index.html index 85ddf5b74..d97a89022 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1377,6 +1377,13 @@ Alt + Enter Cmd + Enter + + Toggle adapting display refresh rate to game frame rate +
+ Note: Not available for macOS. + Alt + r + Cmd + r + Decrease overscan in fullscreen mode Shift + PageDown @@ -2191,7 +2198,7 @@
-audio.dpc_pitch <10000 - 30000>
- Set the pitch o f Pitfall II music. + Set the pitch of Pitfall II music. @@ -2221,7 +2228,8 @@
-tia.fs_refresh <1|0>
While in fullscreen mode, adapt the display's refresh rate to the game's frame rate - to minimize judder. + to minimize judder.
+ Note: Not available for macOS. @@ -2954,7 +2962,8 @@ FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen StretchIn fullscreen mode, completely fill screen with the TIA image.-tia.fs_stretch - Adapt display...In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder.-tia.fs_refresh + Adapt display...In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder. +
Note: Not available for macOS.-tia.fs_refresh OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan V-Size adjustAdjust height of the TIA image-tia.vsizeadjust diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index cf4a31831..81b25cd6e 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -467,6 +467,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL}, {Event::ToggleFullScreen, KBDK_RETURN, MOD3}, + {Event::ToggleAdaptRefresh, KBDK_R, MOD3}, {Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT}, {Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT}, //{Event::VidmodeStd, KBDK_1, MOD3}, diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index fa8a4d04d..ddac653f3 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -123,6 +123,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, + ToggleAdaptRefresh, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index fa87be91d..3817232c6 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -350,17 +350,25 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; const bool isCustomFilter = myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + bool repeat; do { myAdjustSetting = AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, 0, int(AdjustSetting::MAX_ADJ))); // skip currently non-relevant adjustments - } while((myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) - || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) - || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS - && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING - && !isCustomFilter)); + repeat = (myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) + #ifdef ADAPTABLE_REFRESH_SUPPORT + || (myAdjustSetting == AdjustSetting::ADAPT_REFRESH && !isFullScreen) + #endif + || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) + || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS + && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING + && !isCustomFilter); + // avoid endless loop + if(repeat && !direction) + direction = 1; + } while(repeat); return getAdjustSetting(myAdjustSetting); } @@ -376,6 +384,9 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), std::bind(&FrameBuffer::toggleFullscreen, &myOSystem.frameBuffer(), _1), + #ifdef ADAPTABLE_REFRESH_SUPPORT + std::bind(&FrameBuffer::toggleAdaptRefresh, &myOSystem.frameBuffer(), _1), + #endif std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), std::bind(&Console::selectFormat, &myOSystem.console(), _1), std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), @@ -658,6 +669,17 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) } return; + #ifdef ADAPTABLE_REFRESH_SUPPORT + case Event::ToggleAdaptRefresh: + if(pressed && !repeated) + { + myOSystem.frameBuffer().toggleAdaptRefresh(); + myAdjustSetting = AdjustSetting::ADAPT_REFRESH; + myAdjustActive = true; + } + return; + #endif + case Event::OverscanDecrease: if(pressed) { @@ -2218,6 +2240,9 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::KeyboardOnePound, "P1 Keyboard #", "" }, // Video { Event::ToggleFullScreen, "Toggle fullscreen", "" }, +#ifdef ADAPTABLE_REFRESH_SUPPORT + { Event::ToggleAdaptRefresh, "Toggle fullscreen refresh rate adapt", "" }, +#endif { Event::OverscanDecrease, "Decrease overscan in fullscreen mode", "" }, { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, @@ -2361,7 +2386,7 @@ const Event::EventSet EventHandler::MiscEvents = { const Event::EventSet EventHandler::AudioVideoEvents = { Event::VolumeDecrease, Event::VolumeIncrease, Event::SoundToggle, Event::VidmodeDecrease, Event::VidmodeIncrease, - Event::ToggleFullScreen, + Event::ToggleFullScreen, Event::ToggleAdaptRefresh, Event::OverscanDecrease, Event::OverscanIncrease, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 0ab40c7cd..7d9dd235e 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -398,6 +398,9 @@ class EventHandler VOLUME, ZOOM, FULLSCREEN, + #ifdef ADAPTABLE_REFRESH_SUPPORT + ADAPT_REFRESH, + #endif OVERSCAN, TVFORMAT, VCENTER, @@ -517,7 +520,12 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE, + #ifdef ADAPTABLE_REFRESH_SUPPORT + REFRESH_SIZE = 1, + #else + REFRESH_SIZE = 0, + #endif + EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 88f62517f..4812e22f6 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -1008,6 +1008,35 @@ void FrameBuffer::toggleFullscreen(bool toggle) } } +#ifdef ADAPTABLE_REFRESH_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::toggleAdaptRefresh(bool toggle) +{ + bool isAdaptRefresh = myOSystem.settings().getInt("tia.fs_refresh"); + + if(toggle) + isAdaptRefresh = !isAdaptRefresh; + + if(myBufferType == BufferType::Emulator) + { + if(toggle) + { + myOSystem.settings().setValue("tia.fs_refresh", isAdaptRefresh); + // issue a complete framebuffer re-initialization + myOSystem.createFrameBuffer(); + } + + ostringstream msg; + + msg << "Adapt refresh rate "; + msg << (isAdaptRefresh ? "enabled" : "disabled"); + msg << " (" << refreshRate() << " Hz)"; + + showMessage(msg.str()); + } +} +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::changeOverscan(int direction) { diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 945cbb780..a86743911 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -269,6 +269,13 @@ class FrameBuffer */ void toggleFullscreen(bool toggle = true); + #ifdef ADAPTABLE_REFRESH_SUPPORT + /** + Toggles between adapt fullscreen refresh rate on and off. + */ + void FrameBuffer::toggleAdaptRefresh(bool toggle = true); + #endif + /** Changes the fullscreen overscan.