From ccd82a8e0fa267e168701563ffb3dc1f566bf1f2 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Wed, 2 May 2018 19:01:26 +0200 Subject: [PATCH] HLE : Configurable viewport scaling (as a hack) --- resource/Cxbx.rc | Bin 38406 -> 38626 bytes src/Cxbx/ResCxbx.h | 1 + src/Cxbx/WndMain.cpp | 41 ++++++++++++--- src/Cxbx/WndMain.h | 3 +- src/CxbxKrnl/CxbxKrnl.cpp | 3 ++ src/CxbxKrnl/Emu.cpp | 1 + src/CxbxKrnl/Emu.h | 1 + src/CxbxKrnl/EmuD3D8.cpp | 104 ++++++++++++++++++++------------------ src/CxbxKrnl/EmuShared.h | 3 ++ 9 files changed, 99 insertions(+), 58 deletions(-) diff --git a/resource/Cxbx.rc b/resource/Cxbx.rc index 68a6add6b7ea6406dd3ad9c003312e65d317d0e2..641f567fa0b7acd946c26b882c4ba31955c1e0a9 100644 GIT binary patch delta 124 zcmZo$!}Mq^(*`T^$qm9X-oXsX42cXm45iSO7|hoI>dIqC0g5F7S;-9944RW4no0@=GdMFiGWamKGK4XB0?F{n+A`jg N4J7k6uP~2`0{{f793}t& delta 18 ZcmaE~mZ@zG(*`T^$p(^nn_Dd6;s8q$2V4LE diff --git a/src/Cxbx/ResCxbx.h b/src/Cxbx/ResCxbx.h index bfc4c47cb..43f491b45 100644 --- a/src/Cxbx/ResCxbx.h +++ b/src/Cxbx/ResCxbx.h @@ -135,6 +135,7 @@ #define ID_HACKS_UNCAPFRAMERATE 40097 #define ID_HACKS_RUNXBOXTHREADSONALLCORES 40098 #define ID_HACKS_PATCHCPUFREQUENCY 40099 +#define ID_HACKS_SCALEVIEWPORT 40100 #define IDC_STATIC -1 // Next default values for new objects diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index f4292c46a..ccf934331 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -113,7 +113,7 @@ void WndMain::InitializeSettings() { #define TIMERID_FPS 0 #define TIMERID_LED 1 -void WndMain::ResizeWindow(bool bForGUI) +void WndMain::ResizeWindow(HWND hwnd, bool bForGUI) { RECT desktopRect; RECT windowRect; @@ -149,9 +149,9 @@ void WndMain::ResizeWindow(bool bForGUI) // Resize the window so it's client area can contain the requested resolution windowRect = { m_x, m_y, m_x + m_w, m_y + m_h }; - AdjustWindowRectEx(&windowRect, GetWindowLong(m_hwnd, GWL_STYLE), GetMenu(m_hwnd) != NULL, GetWindowLong(m_hwnd, GWL_EXSTYLE)); + AdjustWindowRectEx(&windowRect, GetWindowLong(hwnd, GWL_STYLE), GetMenu(hwnd) != NULL, GetWindowLong(hwnd, GWL_EXSTYLE)); // TODO : For DPI screens, replace AdjustWindowRectEx by DwmGetWindowAttribute using DWMWA_EXTENDED_FRAME_BOUNDS - SetWindowPos(m_hwnd, 0, + SetWindowPos(hwnd, 0, windowRect.left, windowRect.top, windowRect.right - windowRect.left, @@ -230,6 +230,12 @@ WndMain::WndMain(HINSTANCE x_hInstance) : m_PatchCpuFrequency = 0; } + dwType = REG_DWORD; dwSize = sizeof(DWORD); + result = RegQueryValueEx(hKey, "HackScaleViewport", NULL, &dwType, (PBYTE)&m_ScaleViewport, &dwSize); + if (result != ERROR_SUCCESS) { + m_ScaleViewport = 0; + } + dwType = REG_DWORD; dwSize = sizeof(DWORD); result = RegQueryValueEx(hKey, "CxbxDebug", NULL, &dwType, (PBYTE)&m_CxbxDebug, &dwSize); if (result != ERROR_SUCCESS) { @@ -392,6 +398,9 @@ WndMain::~WndMain() dwType = REG_DWORD; dwSize = sizeof(DWORD); RegSetValueEx(hKey, "HackPatchCpuFrequency", 0, dwType, (PBYTE)&m_PatchCpuFrequency, dwSize); + dwType = REG_DWORD; dwSize = sizeof(DWORD); + RegSetValueEx(hKey, "HackScaleViewport", 0, dwType, (PBYTE)&m_ScaleViewport, dwSize); + dwType = REG_DWORD; dwSize = sizeof(DWORD); RegSetValueEx(hKey, "CxbxDebug", 0, dwType, (PBYTE)&m_CxbxDebug, dwSize); @@ -435,8 +444,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } // Set window size to GUI dimensions - m_hwnd = hwnd; // Needed inside ResizeWindow (will be set to the same value later wayway) - ResizeWindow(/*bForGUI=*/true); + ResizeWindow(hwnd, /*bForGUI=*/true); // initialize back buffer { @@ -1363,6 +1371,11 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP RefreshMenus(); break; + case ID_HACKS_SCALEVIEWPORT: + m_ScaleViewport = !m_ScaleViewport; + RefreshMenus(); + break; + case ID_HELP_ABOUT: { ShowAboutDialog(hwnd); @@ -1793,6 +1806,9 @@ void WndMain::RefreshMenus() chk_flag = (m_PatchCpuFrequency) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_HACKS_PATCHCPUFREQUENCY, chk_flag); + + chk_flag = (m_ScaleViewport) ? MF_CHECKED : MF_UNCHECKED; + CheckMenuItem(settings_menu, ID_HACKS_SCALEVIEWPORT, chk_flag); } // emulation menu @@ -2167,9 +2183,18 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / g_EmuShared->SetUncapFramerate(&m_UncapFramerate); g_EmuShared->SetUseAllCores(&m_UseAllCores); g_EmuShared->SetPatchCpuFrequency(&m_PatchCpuFrequency); + g_EmuShared->SetScaleViewport(&m_ScaleViewport); - // Set the window size to emulation dimensions - ResizeWindow(/*bForGUI*/false); + if (m_ScaleViewport) { + // Set the window size to emulation dimensions + // Note : Doing this here assures the emulation process will use + // the configured dimensions (because if done inside the emulation + // process, that doesn't resize correctly sometimes) + // TODO : Instead of doing the resize before launch, move it + // towards CreateDevice emulation, using Xbox-requested dimensions + // (and fix the issue of incorrect resizing) + ResizeWindow(m_hwnd, /*bForGUI*/false); + } // shell exe { @@ -2240,7 +2265,7 @@ void WndMain::StopEmulation() UpdateCaption(); RefreshMenus(); // Set the window size back to it's GUI dimensions - ResizeWindow(/*bForGUI=*/true); + ResizeWindow(m_hwnd, /*bForGUI=*/true); } diff --git a/src/Cxbx/WndMain.h b/src/Cxbx/WndMain.h index eed0e780d..c479c1058 100644 --- a/src/Cxbx/WndMain.h +++ b/src/Cxbx/WndMain.h @@ -90,7 +90,7 @@ class WndMain : public Wnd // ****************************************************************** // * resize the main window for either GUI or emulation // ****************************************************************** - void ResizeWindow(bool bForGUI); + void ResizeWindow(HWND hwnd, bool bForGUI); // ****************************************************************** // * after an xbe is loaded, some things must be updated @@ -222,6 +222,7 @@ class WndMain : public Wnd int m_UncapFramerate; int m_UseAllCores; int m_PatchCpuFrequency; + int m_ScaleViewport; // ****************************************************************** // * debug output filenames diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index bc14d8ab0..a1a986abd 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -583,6 +583,7 @@ void PrintCurrentConfigurationLog() printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off"); printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off"); printf("Patch CPU Frequency (rdtsc): %s\n", g_PatchCpuFrequency == 1 ? "On" : "Off"); + printf("Scale Xbox to host viewport (and back): %s\n", g_ScaleViewport == 1 ? "On" : "Off"); } printf("------------------------- END OF CONFIG LOG ------------------------\n"); @@ -1102,6 +1103,8 @@ __declspec(noreturn) void CxbxKrnlInit g_UseAllCores = !!HackEnabled; g_EmuShared->GetPatchCpuFrequency(&HackEnabled); g_PatchCpuFrequency = !!HackEnabled; + g_EmuShared->GetScaleViewport(&HackEnabled); + g_ScaleViewport = !!HackEnabled; } #ifdef _DEBUG_PRINT_CURRENT_CONF diff --git a/src/CxbxKrnl/Emu.cpp b/src/CxbxKrnl/Emu.cpp index 1423133ca..f10fdcb53 100644 --- a/src/CxbxKrnl/Emu.cpp +++ b/src/CxbxKrnl/Emu.cpp @@ -68,6 +68,7 @@ bool g_DisablePixelShaders = false; bool g_UncapFramerate = false; bool g_UseAllCores = false; bool g_PatchCpuFrequency = false; +bool g_ScaleViewport = false; // Delta added to host SystemTime, used in xboxkrnl::KeQuerySystemTime and xboxkrnl::NtSetSystemTime LARGE_INTEGER HostSystemTimeDelta = {}; diff --git a/src/CxbxKrnl/Emu.h b/src/CxbxKrnl/Emu.h index 62ad675d0..b825da40a 100644 --- a/src/CxbxKrnl/Emu.h +++ b/src/CxbxKrnl/Emu.h @@ -111,4 +111,5 @@ extern bool g_DisablePixelShaders; extern bool g_UncapFramerate; extern bool g_UseAllCores; extern bool g_PatchCpuFrequency; +extern bool g_ScaleViewport; #endif diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 185d86aab..f0a623ed9 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3209,36 +3209,37 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) LOG_FUNC_ONE_ARG(pViewport); + D3DVIEWPORT HostViewPort = *pViewport; + + if (g_ScaleViewport) { #if 0 // Disabled for now, as the Xbox code triggers an error-code 6 in uc_emu_start() - // Use a trampoline here, so GetViewport can be unpatched - XB_trampoline(VOID, WINAPI, D3DDevice_SetViewport, (CONST X_D3DVIEWPORT8 *)); - XB_D3DDevice_SetViewport(pViewport); + // Use a trampoline here, so GetViewport can be unpatched + XB_trampoline(VOID, WINAPI, D3DDevice_SetViewport, (CONST X_D3DVIEWPORT8 *)); + XB_D3DDevice_SetViewport(pViewport); #endif - // Get current Xbox render target dimensions - DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); - DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); + // Get current Xbox render target dimensions + DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); + DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); - // Get current host render target dimensions - DWORD HostRenderTarget_Width; - DWORD HostRenderTarget_Height; + // Get current host render target dimensions + DWORD HostRenderTarget_Width; + DWORD HostRenderTarget_Height; - D3DVIEWPORT HostViewPort; + if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) { - if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) { - - // Scale Xbox to host dimensions (avoiding hard-coding 640 x 480) - HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget_Width); - HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Height); - HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Width); - HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Height); - // TODO : Fix test-case Shenmue 2 (which halves height, leaving the bottom half unused) - HostViewPort.MinZ = pViewport->MinZ; // No need scale Z for now - HostViewPort.MaxZ = pViewport->MaxZ; - } - else { - HostViewPort = *pViewport; - EmuWarning("GetHostRenderTargetDimensions failed - SetViewport sets Xbox viewport instead!"); + // Scale Xbox to host dimensions (avoiding hard-coding 640 x 480) + HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget_Width); + HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Height); + HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Width); + HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Height); + // TODO : Fix test-case Shenmue 2 (which halves height, leaving the bottom half unused) + HostViewPort.MinZ = pViewport->MinZ; // No need scale Z for now + HostViewPort.MaxZ = pViewport->MaxZ; + } + else { + EmuWarning("GetHostRenderTargetDimensions failed - SetViewport sets Xbox viewport instead!"); + } } HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); @@ -3257,38 +3258,43 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewport) LOG_FUNC_ONE_ARG(pViewport); - // Note : We cannot return the Xbox viewport as set in EMUPATCH(D3DDevice_SetViewport) - // because various Xbox D3D functions reset the Xbox viewport. Since we call comparable - // functions on host D3D, the host viewport is better suited as a return value; - // We just need to scale the host viewport back to Xbox dimensions - the exact opposite - // operation from the up-scaling that happens in EMUPATCH(D3DDevice_SetViewport). - D3DVIEWPORT HostViewPort; HRESULT hRet = g_pD3DDevice->GetViewport(&HostViewPort); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetViewport"); - // Get current host render target dimensions - DWORD HostRenderTarget_Width; - DWORD HostRenderTarget_Height; - - if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) { - - // Get current Xbox render target dimensions - DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); - DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); - - // Scale host back to Xbox dimensions (avoiding hard-coding 640 x 480) - pViewport->X = ScaleDWORD(HostViewPort.X, HostRenderTarget_Width, XboxRenderTarget_Width); - pViewport->Y = ScaleDWORD(HostViewPort.Y, HostRenderTarget_Height, XboxRenderTarget_Height); - pViewport->Width = ScaleDWORD(HostViewPort.Width, HostRenderTarget_Width, XboxRenderTarget_Width); - pViewport->Height = ScaleDWORD(HostViewPort.Height, HostRenderTarget_Height, XboxRenderTarget_Height); - pViewport->MinZ = HostViewPort.MinZ; // No need scale Z for now - pViewport->MaxZ = HostViewPort.MaxZ; + if (!g_ScaleViewport) { + *pViewport = HostViewPort; } else { - *pViewport = HostViewPort; - EmuWarning("GetHostRenderTargetDimensions failed - GetViewport returns host viewport instead!"); + // Note : We cannot return the Xbox viewport as set in EMUPATCH(D3DDevice_SetViewport) + // because various Xbox D3D functions reset the Xbox viewport. Since we call comparable + // functions on host D3D, the host viewport is better suited as a return value; + // We just need to scale the host viewport back to Xbox dimensions - the exact opposite + // operation from the up-scaling that happens in EMUPATCH(D3DDevice_SetViewport). + + // Get current host render target dimensions + DWORD HostRenderTarget_Width; + DWORD HostRenderTarget_Height; + + if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) { + + // Get current Xbox render target dimensions + DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); + DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); + + // Scale host back to Xbox dimensions (avoiding hard-coding 640 x 480) + pViewport->X = ScaleDWORD(HostViewPort.X, HostRenderTarget_Width, XboxRenderTarget_Width); + pViewport->Y = ScaleDWORD(HostViewPort.Y, HostRenderTarget_Height, XboxRenderTarget_Height); + pViewport->Width = ScaleDWORD(HostViewPort.Width, HostRenderTarget_Width, XboxRenderTarget_Width); + pViewport->Height = ScaleDWORD(HostViewPort.Height, HostRenderTarget_Height, XboxRenderTarget_Height); + pViewport->MinZ = HostViewPort.MinZ; // No need scale Z for now + pViewport->MaxZ = HostViewPort.MaxZ; + } + else { + *pViewport = HostViewPort; + EmuWarning("GetHostRenderTargetDimensions failed - GetViewport returns host viewport instead!"); + } } } diff --git a/src/CxbxKrnl/EmuShared.h b/src/CxbxKrnl/EmuShared.h index c99042fc0..9ffedb314 100644 --- a/src/CxbxKrnl/EmuShared.h +++ b/src/CxbxKrnl/EmuShared.h @@ -128,6 +128,8 @@ class EmuShared : public Mutex void SetUseAllCores(int* value) { Lock(); m_UseAllCores = *value; Unlock(); } void GetPatchCpuFrequency(int* value) { Lock(); *value = m_PatchCpuFrequeny; Unlock(); } void SetPatchCpuFrequency(int* value) { Lock(); m_PatchCpuFrequeny = *value; Unlock(); } + void GetScaleViewport(int* value) { Lock(); *value = m_ScaleViewport; Unlock(); } + void SetScaleViewport(int* value) { Lock(); m_ScaleViewport = *value; Unlock(); } // ****************************************************************** // * MSpF/Benchmark values Accessors @@ -202,6 +204,7 @@ class EmuShared : public Mutex bool m_bMultiXbeFlag; bool m_bDebugging; int m_LedSequence[4]; + int m_ScaleViewport; }; // ******************************************************************