From 77f24947f091b13ee3b217112150edc82f3f21d7 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 18 May 2020 12:26:05 +0200 Subject: [PATCH] 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};