Merge remote-tracking branch 'remotes/origin/feature-fullscreen'

This commit is contained in:
thrust26 2020-05-24 10:39:11 +02:00
commit 1fb1809049
15 changed files with 376 additions and 84 deletions

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1377,6 +1377,13 @@
<td>Alt + Enter</td>
<td>Cmd + Enter</td>
</tr>
<tr>
<td>Toggle adapting display refresh rate to game frame rate
</br>
Note: Not available for macOS.</td>
<td>Alt + r</td>
<td>Cmd + r</td>
</tr>
<tr>
<td><i>Decrease</i> overscan in fullscreen mode</td>
<td>Shift + PageDown</td>
@ -2191,7 +2198,7 @@
<tr>
<td><pre>-audio.dpc_pitch &lt;10000 - 30000&gt;</pre></td>
<td>Set the pitch o f Pitfall II music.</td>
<td>Set the pitch of Pitfall II music.</td>
</tr>
<tr>
@ -2218,6 +2225,13 @@
aspect ratio.</td>
</tr>
<tr>
<td><pre>-tia.fs_refresh &lt;1|0&gt;</pre></td>
<td>While in fullscreen mode, adapt the display's refresh rate to the game's frame rate
to minimize judder.</br>
Note: Not available for macOS.</td>
</tr>
<tr>
<td><pre>-tia.fs_overscan &lt;0 - 10&gt;</pre></td>
<td>Add overscan to TIA image while in fullscreen mode</td>
@ -2943,13 +2957,15 @@
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
<tr><td>Renderer</td><td>Use specified rendering mode</td><td>-video</td></tr>
<tr><td>Interpolation</td><td>Interpolation of TIA image</td><td>-tia.inter</td></tr>
<tr><td>Zoom</td><td>Zoom level of TIA image</td><td>-tia.zoom</td></tr>
<tr><td>Interpolation</td><td>Enable interpolation of the TIA image</td><td>-tia.inter</td></tr>
<tr><td>Zoom</td><td>Zoom level of the TIA image</td><td>-tia.zoom</td></tr>
<tr><td>Fullscreen</td><td>Self-explanatory - Note that colors may slightly change.
This depends on the OS and renderer used.</td><td>-fullscreen</td></tr>
<tr><td>Stretch</td><td>In fullscreen mode, completely fill screen with TIA image</td><td>-tia.fs_stretch</td></tr>
<tr><td>Stretch</td><td>In fullscreen mode, completely fill screen with the TIA image.</td><td>-tia.fs_stretch</td></tr>
<tr><td>Adapt display...</td><td>In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder.
</br>Note: Not available for macOS.</td><td>-tia.fs_refresh</td></tr>
<tr><td>Overscan</td><td>In fullscreen mode, add overscan to the TIA image</td><td>-tia.fs_overscan</td></tr>
<tr><td>V-Size adjust</td><td>Adjust height of TIA image</td><td>-tia.vsizeadjust</td></tr>
<tr><td>V-Size adjust</td><td>Adjust height of the TIA image</td><td>-tia.vsizeadjust</td></tr>
</table>
</td>
</tr>

View File

@ -15,6 +15,8 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cmath>
#include "SDL_lib.hxx"
#include "bspf.hxx"
#include "Logger.hxx"
@ -99,19 +101,32 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& 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
@ -218,21 +233,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
return false;
// TODO: On multiple displays, switching from centered mode, does not respect
// current window's display (which many not be centered anymore)
const bool fullScreen = mode.fsIndex != -1;
bool forceCreateRenderer = false;
// 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");
@ -261,49 +269,45 @@ 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;
// 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
#ifdef ADAPTABLE_REFRESH_SUPPORT
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);
// 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)
{
int d = SDL_GetWindowDisplayIndex(myWindow);
const int d = SDL_GetWindowDisplayIndex(myWindow);
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
|| adaptRefresh)
{
SDL_DestroyWindow(myWindow);
myWindow = nullptr;
}
}
if(myWindow)
{
// Even though window size stayed the same, the title may have changed
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;
myWindow = SDL_CreateWindow(title.c_str(), posX, posY,
mode.screen.w, mode.screen.h, flags);
if(myWindow == nullptr)
@ -312,31 +316,133 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
Logger::error(msg);
return false;
}
setWindowIcon();
}
#ifdef ADAPTABLE_REFRESH_SUPPORT
if(adaptRefresh)
{
// Switch to mode for adapted refresh rate
if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0)
{
Logger::error("ERROR: Display refresh rate change failed");
}
else
{
ostringstream msg;
msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz";
Logger::info(msg.str());
}
}
#endif
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();
// 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;
// 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) == nullptr)
{
Logger::error("ERROR: Closest display mode could not be retrieved");
return adapt;
}
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)
{
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)
{
// 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 for buffer type #" << 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();
SDL_RendererInfo renderinfo;
if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0)
myOSystem.settings().setValue("video", renderinfo.name);
@ -404,6 +510,36 @@ 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 != nullptr)
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; // The code will take care of 59/49 Hz
}
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::renderToScreen()
{
@ -416,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);

View File

@ -181,6 +181,25 @@ 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
@param 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
@param force If true, force new renderer creation
@return False on any errors, else true
*/
bool createRenderer(bool force);
/**
This method is called to create a surface with the given attributes.
@ -233,6 +252,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};

View File

@ -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},

View File

@ -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;

View File

@ -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
};

View File

@ -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,

View File

@ -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
;

View File

@ -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,9 +994,49 @@ void FrameBuffer::toggleFullscreen(bool toggle)
setFullscreen(isFullscreen);
showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled"));
if(myBufferType == BufferType::Emulator)
{
ostringstream msg;
msg << "Fullscreen ";
if(isFullscreen)
msg << "enabled (" << refreshRate() << " Hz)";
else
msg << "disabled";
showMessage(msg.str());
}
}
#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)
{

View File

@ -81,6 +81,13 @@ class FrameBuffer
}
};
struct DisplayMode
{
uInt32 display;
Common::Size size;
uInt32 refresh_rate;
};
enum class BufferType {
None,
Launcher,
@ -262,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.
@ -439,6 +453,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
@ -510,6 +525,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;

View File

@ -52,6 +52,7 @@ 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.dbgcolors", "roygpb");
@ -441,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's FPS\n"
<< " -tia.fs_overscan <0-10> Add overscan to TIA image in fullscreen mode\n"
<< " -tia.dbgcolors <string> Debug colors to use for each object (see manual\n"
<< " for description)\n"

View File

@ -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);
@ -149,26 +141,29 @@ 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);
#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
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);
ypos += lineHeight + VGAP;
// 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 +171,7 @@ void VideoAudioDialog::addDisplayTab()
myVSizeAdjust->setTickmarkIntervals(2);
wid.push_back(myVSizeAdjust);
// Add items for tab 0
addToFocusList(wid, myTab, tabID);
}
@ -480,10 +476,12 @@ 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"));
#ifdef ADAPTABLE_REFRESH_SUPPORT
// Adapt refresh rate
myRefreshAdapt->setState(instance().settings().getBool("tia.fs_refresh"));
#endif
// Fullscreen overscan setting
myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan"));
handleFullScreenChange();
@ -595,6 +593,10 @@ void VideoAudioDialog::saveConfig()
instance().settings().setValue("fullscreen", myFullscreen->getState());
// Fullscreen stretch setting
instance().settings().setValue("tia.fs_stretch", myUseStretch->getState());
#ifdef ADAPTABLE_REFRESH_SUPPORT
// Adapt refresh rate
instance().settings().setValue("tia.fs_refresh", myRefreshAdapt->getState());
#endif
// Fullscreen overscan
instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel());
@ -611,7 +613,6 @@ void VideoAudioDialog::saveConfig()
// Note: Palette values are saved directly when changed!
/////////////////////////////////////////////////////////////////////////////
// TV Effects tab
// TV Mode
@ -706,8 +707,10 @@ void VideoAudioDialog::setDefaults()
myTIAInterpolate->setState(false);
// screen size
myFullscreen->setState(false);
//myFullScreenMode->setSelectedIndex(0);
myUseStretch->setState(false);
#ifdef ADAPTABLE_REFRESH_SUPPORT
myRefreshAdapt->setState(false);
#endif
myTVOverscan->setValue(0);
myTIAZoom->setValue(300);
myVSizeAdjust->setValue(0);
@ -833,6 +836,9 @@ void VideoAudioDialog::handleFullScreenChange()
{
bool enable = myFullscreen->getState();
myUseStretch->setEnabled(enable);
#ifdef ADAPTABLE_REFRESH_SUPPORT
myRefreshAdapt->setEnabled(enable);
#endif
myTVOverscan->setEnabled(enable);
}

View File

@ -71,9 +71,9 @@ class VideoAudioDialog : public Dialog
PopUpWidget* myRenderer{nullptr};
CheckboxWidget* myTIAInterpolate{nullptr};
CheckboxWidget* myFullscreen{nullptr};
//PopUpWidget* myFullScreenMode;
CheckboxWidget* myUseStretch{nullptr};
SliderWidget* myTVOverscan{nullptr};
CheckboxWidget* myRefreshAdapt{nullptr};
SliderWidget* myTIAZoom{nullptr};
SliderWidget* myVSizeAdjust{nullptr};