handle rounded refresh rates like 59.94 Hz

disable refresh adjust option for macOS
This commit is contained in:
thrust26 2020-05-23 12:29:31 +02:00
parent 94b1800cc4
commit 137ba30593
4 changed files with 100 additions and 5 deletions

View File

@ -234,8 +234,6 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
return false; return false;
const bool fullScreen = mode.fsIndex != -1; const bool fullScreen = mode.fsIndex != -1;
const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh")
&& gameRefreshRate() && refreshRate() % gameRefreshRate() != 0;
bool forceCreateRenderer = false; bool forceCreateRenderer = false;
// Get windowed window's last display // 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); posY = BSPF::clamp(posY, y0 + 50, y1 - 50);
} }
#ifndef BSPF_MACOS
// macOS does not allow to change the display refresh rate
SDL_DisplayMode adaptedSdlMode; 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); const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode);
#else
const bool adaptRefresh = false;
#endif
const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI
| (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
@ -331,6 +338,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
setWindowIcon(); setWindowIcon();
} }
#ifndef BSPF_MACOS
if(adaptRefresh) if(adaptRefresh)
{ {
// Switch to mode for adapted refresh rate // Switch to mode for adapted refresh rate
@ -346,10 +354,11 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
Logger::info(msg.str()); Logger::info(msg.str());
} }
} }
#endif
return createRenderer(forceCreateRenderer); return createRenderer(forceCreateRenderer);
} }
#ifndef BSPF_MACOS
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) 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 currentRefreshRate = sdlMode.refresh_rate;
const int wantedRefreshRate = gameRefreshRate(); 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; float bestDiff = std::abs(factor - std::round(factor)) / factor;
bool adapt = false; bool adapt = false;
@ -382,6 +394,8 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap
return adapt; return adapt;
} }
factor = float(closestSdlMode.refresh_rate) / sdlMode.refresh_rate; 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; const float diff = std::abs(factor - std::round(factor)) / factor;
if(diff < bestDiff) 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 // Only change if the display supports a better refresh rate
return adapt; 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) bool FrameBufferSDL2::createRenderer(bool force)
@ -540,7 +621,7 @@ int FrameBufferSDL2::gameRefreshRate() const
const string format = myOSystem.console().getFormatString(); const string format = myOSystem.console().getFormatString();
const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; 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; return 0;
} }

View File

@ -181,6 +181,7 @@ class FrameBufferSDL2 : public FrameBuffer
*/ */
bool setVideoMode(const string& title, const VideoMode& mode) override; 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 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 @return True if the refresh rate should be changed
*/ */
bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
#endif
/** /**
Create a new renderer if required Create a new renderer if required

View File

@ -153,10 +153,12 @@ void VideoAudioDialog::addDisplayTab()
myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch");
wid.push_back(myUseStretch); wid.push_back(myUseStretch);
#ifndef BSPF_MACOS
// Adapt refresh rate // Adapt refresh rate
ypos += lineHeight + VGAP; ypos += lineHeight + VGAP;
myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate"); myRefreshAdapt = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Adapt display refresh rate");
wid.push_back(myRefreshAdapt); wid.push_back(myRefreshAdapt);
#endif
// FS overscan // FS overscan
ypos += lineHeight + VGAP; ypos += lineHeight + VGAP;
@ -484,8 +486,10 @@ void VideoAudioDialog::loadConfig()
myFullScreenMode->setSelected(mode);*/ myFullScreenMode->setSelected(mode);*/
// Fullscreen stretch setting // Fullscreen stretch setting
myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); myUseStretch->setState(instance().settings().getBool("tia.fs_stretch"));
#ifndef BSPF_MACOS
// Adapt refresh rate // Adapt refresh rate
myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh")); myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh"));
#endif
// Fullscreen overscan setting // Fullscreen overscan setting
myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan"));
handleFullScreenChange(); handleFullScreenChange();
@ -597,8 +601,10 @@ void VideoAudioDialog::saveConfig()
instance().settings().setValue("fullscreen", myFullscreen->getState()); instance().settings().setValue("fullscreen", myFullscreen->getState());
// Fullscreen stretch setting // Fullscreen stretch setting
instance().settings().setValue("tia.fs_stretch", myUseStretch->getState()); instance().settings().setValue("tia.fs_stretch", myUseStretch->getState());
#ifndef BSPF_MACOS
// Adapt refresh rate // Adapt refresh rate
instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState()); instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState());
#endif
// Fullscreen overscan // Fullscreen overscan
instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel());
@ -712,7 +718,9 @@ void VideoAudioDialog::setDefaults()
myFullscreen->setState(false); myFullscreen->setState(false);
//myFullScreenMode->setSelectedIndex(0); //myFullScreenMode->setSelectedIndex(0);
myUseStretch->setState(false); myUseStretch->setState(false);
#ifndef BSPF_MACOS
myRefreshAdapt->setState(false); myRefreshAdapt->setState(false);
#endif
myTVOverscan->setValue(0); myTVOverscan->setValue(0);
myTIAZoom->setValue(300); myTIAZoom->setValue(300);
myVSizeAdjust->setValue(0); myVSizeAdjust->setValue(0);
@ -838,7 +846,9 @@ void VideoAudioDialog::handleFullScreenChange()
{ {
bool enable = myFullscreen->getState(); bool enable = myFullscreen->getState();
myUseStretch->setEnabled(enable); myUseStretch->setEnabled(enable);
#ifndef BSPF_MACOS
myRefreshAdapt->setEnabled(enable); myRefreshAdapt->setEnabled(enable);
#endif
myTVOverscan->setEnabled(enable); myTVOverscan->setEnabled(enable);
} }

View File

@ -73,7 +73,9 @@ class VideoAudioDialog : public Dialog
CheckboxWidget* myFullscreen{nullptr}; CheckboxWidget* myFullscreen{nullptr};
CheckboxWidget* myUseStretch{nullptr}; CheckboxWidget* myUseStretch{nullptr};
SliderWidget* myTVOverscan{nullptr}; SliderWidget* myTVOverscan{nullptr};
#ifndef BSPF_MACOS
CheckboxWidget* myRefreshAdapt{nullptr}; CheckboxWidget* myRefreshAdapt{nullptr};
#endif
SliderWidget* myTIAZoom{nullptr}; SliderWidget* myTIAZoom{nullptr};
SliderWidget* myVSizeAdjust{nullptr}; SliderWidget* myVSizeAdjust{nullptr};