HLE : Configurable viewport scaling (as a hack)

This commit is contained in:
patrickvl 2018-05-02 19:01:26 +02:00
parent 7ac82d5de1
commit ccd82a8e0f
9 changed files with 99 additions and 58 deletions

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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!");
}
}
}

View File

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