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.
This commit is contained in:
parent
13daf887c0
commit
8b2e758377
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -207,7 +207,6 @@ public:
|
|||
// Hack settings
|
||||
struct s_hack {
|
||||
bool DisablePixelShaders;
|
||||
bool UncapFramerate;
|
||||
bool UseAllCores;
|
||||
bool SkipRdtscPatching;
|
||||
bool ScaleViewport;
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
// 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
|
||||
|
||||
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<double, std::milli>(((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();
|
||||
}
|
||||
frameStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
UpdateFPSCounter();
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@ void UpdateDeferredRenderStates()
|
|||
if (XTL::EmuD3DDeferredRenderState != 0) {
|
||||
// Loop through all deferred render states
|
||||
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];
|
||||
|
||||
|
@ -118,9 +123,15 @@ void UpdateDeferredRenderStates()
|
|||
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
|
||||
// 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:
|
||||
|
|
|
@ -375,7 +375,6 @@ std::map<const std::string, const xbox_patch_t> 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),
|
||||
|
|
|
@ -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
|
||||
// ******************************************************************
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue