From 8b2e7583779c6c2086dafa6bb1e26b4ea64316c6 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Thu, 4 Apr 2019 16:10:45 +0100 Subject: [PATCH 1/3] Respect Xbox presentation interval This allows us to improve our frame-limiter, so that we can disable it if a game does not require a fixed frame-rate, and enable it for titles that do. Result: XDK Samples can now run at high frame-rates (100+ fps) without effecting actual speed (just like on real hardware) Dashboard can reach over 100fps, and still run at the correct speed JSRF and other titles that tie game speed to frame-rate are limited to 60FPS. Fixed broken VSYNC handling too: Disable VSYNC has been broken since the D3D9 port, perhaps before then. --- resource/Cxbx.rc | 1 - src/common/Settings.cpp | 3 -- src/common/Settings.hpp | 1 - src/common/win32/EmuShared.h | 2 - src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 64 ++++++++++++++--------- src/core/hle/D3D8/XbState.cpp | 21 ++++++-- src/core/hle/Patches.cpp | 1 - src/core/hle/XAPI/Xapi.cpp | 15 ------ src/core/kernel/init/CxbxKrnl.cpp | 3 -- src/core/kernel/support/Emu.cpp | 1 - src/core/kernel/support/Emu.h | 1 - src/gui/ResCxbx.h | 1 - src/gui/WndMain.cpp | 8 --- 13 files changed, 55 insertions(+), 67 deletions(-) diff --git a/resource/Cxbx.rc b/resource/Cxbx.rc index 2c39c4356..d7558cc52 100644 --- a/resource/Cxbx.rc +++ b/resource/Cxbx.rc @@ -617,7 +617,6 @@ BEGIN BEGIN MENUITEM "Run Xbox threads on all cores", ID_HACKS_RUNXBOXTHREADSONALLCORES,MFT_STRING,MFS_ENABLED MENUITEM "Render directly to Host Backbuffer", ID_HACKS_RENDERDIRECTLYTOHOSTBACKBUFFER,MFT_STRING,MFS_ENABLED - MENUITEM "Uncap Framerate", ID_HACKS_UNCAPFRAMERATE,MFT_STRING,MFS_ENABLED END MENUITEM "Disable Pixel Shaders", ID_HACKS_DISABLEPIXELSHADERS,MFT_STRING,MFS_ENABLED MENUITEM "Skip rdtsc patching", ID_HACKS_SKIPRDTSCPATCHING,MFT_STRING,MFS_ENABLED diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 43bc7c203..663c428f3 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -118,7 +118,6 @@ static struct { static const char* section_hack = "hack"; static struct { const char* DisablePixelShaders = "DisablePixelShaders"; - const char* UncapFramerate = "UncapFramerate"; const char* UseAllCores = "UseAllCores"; const char* SkipRdtscPatching = "SkipRdtscPatching"; const char* ScaleViewPort = "ScaleViewPort"; @@ -376,7 +375,6 @@ bool Settings::LoadConfig() // ==== Hack Begin ========== m_hacks.DisablePixelShaders = m_si.GetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, /*Default=*/false); - m_hacks.UncapFramerate = m_si.GetBoolValue(section_hack, sect_hack_keys.UncapFramerate, /*Default=*/false); m_hacks.UseAllCores = m_si.GetBoolValue(section_hack, sect_hack_keys.UseAllCores, /*Default=*/false); m_hacks.SkipRdtscPatching = m_si.GetBoolValue(section_hack, sect_hack_keys.SkipRdtscPatching, /*Default=*/false); m_hacks.ScaleViewport = m_si.GetBoolValue(section_hack, sect_hack_keys.ScaleViewPort, /*Default=*/false); @@ -636,7 +634,6 @@ bool Settings::Save(std::string file_path) // ==== Hack Begin ========== m_si.SetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, m_hacks.DisablePixelShaders, nullptr, true); - m_si.SetBoolValue(section_hack, sect_hack_keys.UncapFramerate, m_hacks.UncapFramerate, nullptr, true); m_si.SetBoolValue(section_hack, sect_hack_keys.UseAllCores, m_hacks.UseAllCores, nullptr, true); m_si.SetBoolValue(section_hack, sect_hack_keys.SkipRdtscPatching, m_hacks.SkipRdtscPatching, nullptr, true); m_si.SetBoolValue(section_hack, sect_hack_keys.ScaleViewPort, m_hacks.ScaleViewport, nullptr, true); diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index d168e129f..68929620e 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -207,7 +207,6 @@ public: // Hack settings struct s_hack { bool DisablePixelShaders; - bool UncapFramerate; bool UseAllCores; bool SkipRdtscPatching; bool ScaleViewport; diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index e41c75781..4bfa8b1c7 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -143,8 +143,6 @@ class EmuShared : public Mutex void GetDisablePixelShaders(int* value) { Lock(); *value = m_hacks.DisablePixelShaders; Unlock(); } void SetDisablePixelShaders(const int* value) { Lock(); m_hacks.DisablePixelShaders = *value; Unlock(); } - void GetUncapFramerate(int* value) { Lock(); *value = m_hacks.UncapFramerate; Unlock(); } - void SetUncapFramerate(const int* value) { Lock(); m_hacks.UncapFramerate = *value; Unlock(); } void GetUseAllCores(int* value) { Lock(); *value = m_hacks.UseAllCores; Unlock(); } void SetUseAllCores(const int* value) { Lock(); m_hacks.UseAllCores = *value; Unlock(); } void GetSkipRdtscPatching(int* value) { Lock(); *value = m_hacks.SkipRdtscPatching; Unlock(); } diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index c71b55b7d..296d83126 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -168,7 +168,8 @@ static DWORD g_dwVertexShaderUsage = 0; static DWORD g_VertexShaderSlots[136]; DWORD g_XboxBaseVertexIndex = 0; - +DWORD g_DefaultPresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; +DWORD g_PresentationIntervalOverride = 0; // Active D3D Vertex Streams (and strides) XTL::X_D3DVertexBuffer*g_D3DStreams[16]; @@ -1916,21 +1917,11 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) { g_EmuCDPD.HostPresentationParameters.Windowed = !g_XBVideo.bFullScreen; - if(g_XBVideo.bVSync) - g_EmuCDPD.HostPresentationParameters.SwapEffect = XTL::D3DSWAPEFFECT_COPY; // Was D3DSWAPEFFECT_COPY_VSYNC; - g_EmuCDPD.HostPresentationParameters.BackBufferFormat = XTL::EmuXB2PC_D3DFormat(g_EmuCDPD.XboxPresentationParameters.BackBufferFormat); g_EmuCDPD.HostPresentationParameters.AutoDepthStencilFormat = XTL::EmuXB2PC_D3DFormat(g_EmuCDPD.XboxPresentationParameters.AutoDepthStencilFormat); - if(!g_XBVideo.bVSync && (g_D3DCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) && g_XBVideo.bFullScreen) - g_EmuCDPD.HostPresentationParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - else - { - if(g_D3DCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE && g_XBVideo.bFullScreen) - g_EmuCDPD.HostPresentationParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; - else - g_EmuCDPD.HostPresentationParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - } + g_EmuCDPD.HostPresentationParameters.PresentationInterval = g_XBVideo.bVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + g_DefaultPresentationInterval = g_EmuCDPD.XboxPresentationParameters.PresentationInterval; // HACK: Disable Tripple Buffering for now... // TODO: Enumerate maximum BackBufferCount if possible. @@ -4555,19 +4546,42 @@ DWORD WINAPI XTL::EMUPATCH(D3DDevice_Swap) hRet = g_pD3DDevice->BeginScene(); - if (!g_UncapFramerate) { - // If the last frame completed faster than the Xbox VBlank period, wait for it - // TODO: Read the frame rate target from the Xbox display mode - // See comments in GetNextVblankTime(); - auto targetDuration = 16.6666666667ms; - while (std::chrono::high_resolution_clock::now() - frameStartTime < targetDuration) { - // We use an empty while loop because actually sleeping is too unstable - // Sleeping causes the frame duration to jitter... - ; - } + // Check if we need to enable our frame-limiter + DWORD presentationInverval = g_PresentationIntervalOverride > 0 ? g_PresentationIntervalOverride : g_DefaultPresentationInterval; + if (presentationInverval != D3DPRESENT_INTERVAL_IMMEDIATE) { + // If the last frame completed faster than the Xbox target swap rate, wait for it - frameStartTime = std::chrono::high_resolution_clock::now(); - } + auto targetRefreshRate = 60.0f; // TODO: Read from Xbox Display Mode + + // Determine how many 'frames' worth of time we need to wait for + // This allows games that require a locked framerate (eg JSRF) to function correctly + // While allowing titles with an unlocked frame-rate to not be limited + auto multiplier = 1.0f; + switch (presentationInverval) { + case D3DPRESENT_INTERVAL_ONE: + case 0x80000001: // D3DPRESENT_INTERVAL_ONE_OR_IMMEDIATE: + multiplier = 1.0f; + break; + case D3DPRESENT_INTERVAL_TWO: + case 0x80000002: // D3DPRESENT_INTERVAL_TWO_OR_IMMEDIATE: + multiplier = 2.0f; + break; + case D3DPRESENT_INTERVAL_THREE: + multiplier = 3.0f; + break; + case D3DPRESENT_INTERVAL_FOUR: + multiplier = 4.0f; + break; + } + + auto targetDuration = std::chrono::duration(((1.0f / targetRefreshRate) * multiplier) * 1000.0f); + while (std::chrono::high_resolution_clock::now() - frameStartTime < targetDuration) { + // We use an empty while loop because actually sleeping is too unstable + // Sleeping causes the frame duration to jitter... + ; + } + } + frameStartTime = std::chrono::high_resolution_clock::now(); UpdateFPSCounter(); diff --git a/src/core/hle/D3D8/XbState.cpp b/src/core/hle/D3D8/XbState.cpp index b7e31c317..99034010a 100644 --- a/src/core/hle/D3D8/XbState.cpp +++ b/src/core/hle/D3D8/XbState.cpp @@ -79,7 +79,12 @@ void UpdateDeferredRenderStates() // Certain D3DRS values need to be checked on each Draw[Indexed]Vertices if (XTL::EmuD3DDeferredRenderState != 0) { // Loop through all deferred render states - for (unsigned int RenderState = XTL::X_D3DRS_FOGENABLE; RenderState <= XTL::X_D3DRS_PRESENTATIONINTERVAL; RenderState++) { + for (unsigned int RenderState = XTL::X_D3DRS_FOGENABLE; RenderState <= XTL::X_D3DRS_PRESENTATIONINTERVAL; RenderState++) { + // If the current state is not present within our desired XDK, skip it + if (XTL::DxbxRenderStateInfo[RenderState].V >= g_BuildVersion) { + continue; + } + uint8_t index = RenderState - XTL::X_D3DRS_FOGENABLE; DWORD Value = XTL::EmuD3DDeferredRenderState[index]; @@ -117,10 +122,16 @@ void UpdateDeferredRenderStates() case XTL::X_D3DRS_BACKAMBIENTMATERIALSOURCE: case XTL::X_D3DRS_BACKEMISSIVEMATERIALSOURCE: case XTL::X_D3DRS_BACKAMBIENT: - case XTL::X_D3DRS_SWAPFILTER: - case XTL::X_D3DRS_PRESENTATIONINTERVAL: - // These render states are unsupported by the host, so we skip them entirely + case XTL::X_D3DRS_SWAPFILTER: + // These states are unsupported by the host and are ignored (for now) continue; + case XTL::X_D3DRS_PRESENTATIONINTERVAL: { + // Store this as an override for our frame limiter + // Games can use this to limit certain scenes to a desired target framerate for a specific scene + // If this value is not set, or is set to 0, the default interval passed to CreateDevice is used + extern DWORD g_PresentationIntervalOverride; + g_PresentationIntervalOverride = Value; + } continue; case XTL::X_D3DRS_WRAP0: case XTL::X_D3DRS_WRAP1: case XTL::X_D3DRS_WRAP2: @@ -229,7 +240,7 @@ void UpdateDeferredTextureStates() // If point sprites are enabled, we need to overwrite our existing state 0 with State 3 also DWORD HostStage = (pointSpriteOverride && XboxStage == 3) ? 0 : XboxStage; - for (int StateIndex = XTL::X_D3DTSS_DEFERRED_FIRST; StateIndex <= XTL::X_D3DTSS_DEFERRED_LAST; StateIndex++) { + for (int StateIndex = XTL::X_D3DTSS_DEFERRED_FIRST; StateIndex <= XTL::X_D3DTSS_DEFERRED_LAST; StateIndex++) { // Read the value of the current stage/state from the Xbox data structure DWORD Value = XTL::EmuD3DDeferredTextureState[(XboxStage * XTL::X_D3DTS_STAGESIZE) + StateIndex]; diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index d73b6105e..8002b1fb6 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -375,7 +375,6 @@ std::map g_PatchTable = { PATCH_ENTRY("GetExitCodeThread", XTL::EMUPATCH(GetExitCodeThread), PATCH_ALWAYS), PATCH_ENTRY("GetThreadPriority", XTL::EMUPATCH(GetThreadPriority), PATCH_ALWAYS), PATCH_ENTRY("OutputDebugStringA", XTL::EMUPATCH(OutputDebugStringA), PATCH_ALWAYS), - PATCH_ENTRY("QueryPerformanceCounter", XTL::EMUPATCH(QueryPerformanceCounter), PATCH_ALWAYS), PATCH_ENTRY("RaiseException", XTL::EMUPATCH(RaiseException), PATCH_ALWAYS), PATCH_ENTRY("SetThreadPriority", XTL::EMUPATCH(SetThreadPriority), PATCH_ALWAYS), PATCH_ENTRY("SetThreadPriorityBoost", XTL::EMUPATCH(SetThreadPriorityBoost), PATCH_ALWAYS), diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 84d539141..9a2a6e702 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -1484,21 +1484,6 @@ LPVOID WINAPI XTL::EMUPATCH(ConvertThreadToFiber) RETURN(pRet); } -// ****************************************************************** -// * patch: QueryPerformanceCounter -// ****************************************************************** -ULONGLONG CxbxGetPerformanceCounter(bool acpi); // implemented in EmuKrnlKe.cpp -BOOL WINAPI XTL::EMUPATCH(QueryPerformanceCounter) -( - LARGE_INTEGER * lpPerformanceCount -) -{ - // NOTE: QueryPerformanceCounter runs from the tsc via RdTsc (733mhz) - // However, KeQueryPerformanceCounter runs at 3.375Mhz, so we can't use that here - lpPerformanceCount->QuadPart = CxbxGetPerformanceCounter(false); - return TRUE; -} - // ****************************************************************** // * patch: QueueUserAPC // ****************************************************************** diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index a0324ecbc..fa4ce9524 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -608,7 +608,6 @@ void PrintCurrentConfigurationLog() { printf("--------------------------- HACKS CONFIG ---------------------------\n"); printf("Disable Pixel Shaders: %s\n", g_DisablePixelShaders == 1 ? "On" : "Off (Default)"); - printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off (Default)"); printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off (Default)"); printf("Skip RDTSC Patching: %s\n", g_SkipRdtscPatching == 1 ? "On" : "Off (Default)"); printf("Scale Xbox to host viewport (and back): %s\n", g_ScaleViewport == 1 ? "On" : "Off (Default)"); @@ -1407,8 +1406,6 @@ __declspec(noreturn) void CxbxKrnlInit int HackEnabled = 0; g_EmuShared->GetDisablePixelShaders(&HackEnabled); g_DisablePixelShaders = !!HackEnabled; - g_EmuShared->GetUncapFramerate(&HackEnabled); - g_UncapFramerate = !!HackEnabled; g_EmuShared->GetUseAllCores(&HackEnabled); g_UseAllCores = !!HackEnabled; g_EmuShared->GetSkipRdtscPatching(&HackEnabled); diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index b0fadf749..134dd796b 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -53,7 +53,6 @@ volatile thread_local bool g_bEmuException = false; volatile bool g_bEmuSuspended = false; volatile bool g_bPrintfOn = true; bool g_DisablePixelShaders = false; -bool g_UncapFramerate = false; bool g_UseAllCores = false; bool g_SkipRdtscPatching = false; bool g_ScaleViewport = false; diff --git a/src/core/kernel/support/Emu.h b/src/core/kernel/support/Emu.h index 8da6ec3cb..74f7300b5 100644 --- a/src/core/kernel/support/Emu.h +++ b/src/core/kernel/support/Emu.h @@ -102,7 +102,6 @@ typedef struct DUMMY_KERNEL extern bool g_DisablePixelShaders; -extern bool g_UncapFramerate; extern bool g_UseAllCores; extern bool g_SkipRdtscPatching; extern bool g_ScaleViewport; diff --git a/src/gui/ResCxbx.h b/src/gui/ResCxbx.h index 3551f1947..7beaf5a7a 100644 --- a/src/gui/ResCxbx.h +++ b/src/gui/ResCxbx.h @@ -342,7 +342,6 @@ #define ID_SETTINGS_INITIALIZE 40091 #define ID_EMULATION_STARTDEBUGGER 40092 #define ID_FPS 40096 -#define ID_HACKS_UNCAPFRAMERATE 40097 #define ID_HACKS_RUNXBOXTHREADSONALLCORES 40098 #define ID_HACKS_SKIPRDTSCPATCHING 40099 #define ID_HACKS_SCALEVIEWPORT 40100 diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 4d201e418..452ef3f9d 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -1248,11 +1248,6 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP RefreshMenus(); break; - case ID_HACKS_UNCAPFRAMERATE: - g_Settings->m_hacks.UncapFramerate = !g_Settings->m_hacks.UncapFramerate; - RefreshMenus(); - break; - case ID_HACKS_RUNXBOXTHREADSONALLCORES: g_Settings->m_hacks.UseAllCores = !g_Settings->m_hacks.UseAllCores; RefreshMenus(); @@ -1712,9 +1707,6 @@ void WndMain::RefreshMenus() chk_flag = (g_Settings->m_hacks.DisablePixelShaders) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_HACKS_DISABLEPIXELSHADERS, chk_flag); - chk_flag = (g_Settings->m_hacks.UncapFramerate) ? MF_CHECKED : MF_UNCHECKED; - CheckMenuItem(settings_menu, ID_HACKS_UNCAPFRAMERATE, chk_flag); - chk_flag = (g_Settings->m_hacks.UseAllCores) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_HACKS_RUNXBOXTHREADSONALLCORES, chk_flag); From 2ad5cfce8dcd6cd7a071bf52fd0bd0ee3071c821 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Mon, 8 Apr 2019 11:01:42 +0100 Subject: [PATCH 2/3] Feedback --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 296d83126..4d7bfb04e 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -57,6 +57,7 @@ namespace xboxkrnl #include #include #include +#include // Allow use of time duration literals (making 16ms, etc possible) using namespace std::literals::chrono_literals; @@ -1917,6 +1918,9 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) { g_EmuCDPD.HostPresentationParameters.Windowed = !g_XBVideo.bFullScreen; + // TODO: Investigate the best option for this + g_EmuCDPD.HostPresentationParameters.SwapEffect = XTL::D3DSWAPEFFECT_COPY; + g_EmuCDPD.HostPresentationParameters.BackBufferFormat = XTL::EmuXB2PC_D3DFormat(g_EmuCDPD.XboxPresentationParameters.BackBufferFormat); g_EmuCDPD.HostPresentationParameters.AutoDepthStencilFormat = XTL::EmuXB2PC_D3DFormat(g_EmuCDPD.XboxPresentationParameters.AutoDepthStencilFormat); @@ -4574,13 +4578,21 @@ DWORD WINAPI XTL::EMUPATCH(D3DDevice_Swap) break; } - auto targetDuration = std::chrono::duration(((1.0f / targetRefreshRate) * multiplier) * 1000.0f); - while (std::chrono::high_resolution_clock::now() - frameStartTime < targetDuration) { - // We use an empty while loop because actually sleeping is too unstable - // Sleeping causes the frame duration to jitter... - ; + auto targetDuration = std::chrono::duration(((1000.0f / targetRefreshRate) * multiplier)); + auto targetTimestamp = frameStartTime + targetDuration; + + // If we need to wait for a larger amount of time (>= 1 frame at 60FPS), we can just sleep + if (std::chrono::duration_cast(targetTimestamp - std::chrono::high_resolution_clock::now()).count() > 16) { + std::this_thread::sleep_until(targetTimestamp); + } else { + // Otherwise, we fall-through and just keep polling + // This prevents large waits from hogging CPU power, but allows small waits/ to remain precice. + while (std::chrono::high_resolution_clock::now() < targetTimestamp) { + ; + } } } + frameStartTime = std::chrono::high_resolution_clock::now(); UpdateFPSCounter(); From 843c65a11c84042c7ee2aa10984fddebf9c71531 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Mon, 8 Apr 2019 14:58:45 +0100 Subject: [PATCH 3/3] Add dummy item where UncapFramerate used to sit, add note to explain why --- src/common/Settings.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 68929620e..29c4a9fdd 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -204,9 +204,13 @@ public: unsigned int XboxPortMapHostPort[XBCTRL_MAX_GAMEPAD_PORTS] = { 0, 1, 2, 3 }; } m_controller_port; - // Hack settings + // Hack settings + // NOTE: When removing fields, replace them with place-holders + // The size and order of this structure should *not* be allowed to change + // TODO: Fix IPC/Shared Memory so this isn't necessary struct s_hack { - bool DisablePixelShaders; + bool DisablePixelShaders; + bool Reserved2; bool UseAllCores; bool SkipRdtscPatching; bool ScaleViewport;