From d3a278a5aa953503055416c91dab6c32060715a1 Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Fri, 20 Apr 2018 18:52:25 +0200 Subject: [PATCH 01/12] HLE : Scale viewport from Xbox to host (this might fix some drawns to the upper-left corner) --- src/CxbxKrnl/EmuD3D8.cpp | 106 ++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 3e806568a..152a9ec23 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1119,6 +1119,40 @@ uint CxbxGetPixelContainerMipMapLevels return 1; } +uint32_t GetPixelContainerWidth(XTL::X_D3DPixelContainer *pPixelContainer) +{ + DWORD Size = pPixelContainer->Size; + uint32_t Result; + + if (Size != 0) { + Result = ((Size & X_D3DSIZE_WIDTH_MASK) /* >> X_D3DSIZE_WIDTH_SHIFT*/) + 1; + } + else { + DWORD l2w = (pPixelContainer->Format & X_D3DFORMAT_USIZE_MASK) >> X_D3DFORMAT_USIZE_SHIFT; + + Result = 1 << l2w; + } + + return Result; +} + +uint32_t GetPixelContainerHeigth(XTL::X_D3DPixelContainer *pPixelContainer) +{ + DWORD Size = pPixelContainer->Size; + uint32_t Result; + + if (Size != 0) { + Result = ((Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1; + } + else { + DWORD l2h = (pPixelContainer->Format & X_D3DFORMAT_VSIZE_MASK) >> X_D3DFORMAT_VSIZE_SHIFT; + + Result = 1 << l2h; + } + + return Result; +} + VOID CxbxGetPixelContainerMeasures ( XTL::X_D3DPixelContainer *pPixelContainer, @@ -3134,6 +3168,14 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetBackBuffer) *ppBackBuffer = EMUPATCH(D3DDevice_GetBackBuffer2)(BackBuffer); } +DWORD ScaleDWORD(DWORD XboxIn, DWORD XboxMax, DWORD HostMax) +{ + uint64_t tmp = XboxIn; + tmp *= HostMax; + tmp /= XboxMax; + return (DWORD)tmp; +} + // ****************************************************************** // * patch: D3DDevice_SetViewport // ****************************************************************** @@ -3146,42 +3188,34 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) LOG_FUNC_ONE_ARG(pViewport); - DWORD dwWidth = pViewport->Width; - DWORD dwHeight = pViewport->Height; + // Use a trampoline here, so GetViewport can be unpatched + XB_trampoline(VOID, WINAPI, D3DDevice_SetViewport, (CONST X_D3DVIEWPORT8 *)); + XB_D3DDevice_SetViewport(pViewport); - // resize to fit screen (otherwise crashes occur) - /*{ - if(dwWidth > 640) - { - EmuWarning("Resizing Viewport->Width to 640"); - ((D3DVIEWPORT*)pViewport)->Width = 640; - } + // The following can only work if we have a host render target + IDirect3DSurface *pHostRenderTarget = GetHostSurface(g_pCachedRenderTarget); + if (pHostRenderTarget) { + // Get current host render target dimensions + D3DSURFACE_DESC HostRenderTarget; + pHostRenderTarget->GetDesc(&HostRenderTarget); - if(dwHeight > 480) - { - EmuWarning("Resizing Viewport->Height to 480"); - ((D3DVIEWPORT*)pViewport)->Height = 480; - } - }*/ + // Get current Xbox render target dimensions + DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pCachedRenderTarget); + DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pCachedRenderTarget); - HRESULT hRet = g_pD3DDevice->SetViewport(pViewport); + // Scale to host backbuffer dimensions (avoiding hard-coding 640 x 480) + D3DVIEWPORT HostViewPort; - // restore originals - /*{ - if(dwWidth > 640) - ((D3DVIEWPORT*)pViewport)->Width = dwWidth; + 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); + HostViewPort.MinZ = pViewport->MinZ; // TODO : Must we scale Z too? + HostViewPort.MaxZ = pViewport->MaxZ; - if(dwHeight > 480) - ((D3DVIEWPORT*)pViewport)->Height = dwHeight; - } - - DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetViewport"); - - if(FAILED(hRet)) - { - EmuWarning("Unable to set viewport! We're lying"); - hRet = D3D_OK; - }*/ + HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); + DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetViewport"); + } } // ****************************************************************** @@ -3192,7 +3226,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewport) X_D3DVIEWPORT8 *pViewport ) { - FUNC_EXPORTS + // FUNC_EXPORTS LOG_FUNC_ONE_ARG(pViewport); @@ -3237,7 +3271,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) X_D3DXVECTOR4 *pScale ) { - FUNC_EXPORTS + // FUNC_EXPORTS LOG_FUNC_BEGIN LOG_FUNC_ARG(pOffset) @@ -6570,8 +6604,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader) // 59 (c-37) used for screen space transformation. if(g_VertexShaderConstantMode != X_D3DSCM_NORESERVEDCONSTANTS) { - // TODO: Proper solution. - static float vScale[] = { (2.0f / 640), (-2.0f / 480), 0.0f, 0.0f }; + D3DVIEWPORT ViewPort; + g_pD3DDevice->GetViewport(&ViewPort); + + float vScale[] = { (2.0f / ViewPort.Width), (-2.0f / ViewPort.Height), 0.0f, 0.0f }; static float vOffset[] = { -1.0f, 1.0f, 0.0f, 1.0f }; #ifdef CXBX_USE_D3D9 From 0ec58ff4b84fed4119acbb157157e37393580cee Mon Sep 17 00:00:00 2001 From: patrickvl Date: Mon, 23 Apr 2018 00:26:44 +0200 Subject: [PATCH 02/12] HLE : Cache render-target (and depth-stencil while we're at it) for use in SetViewPort --- src/CxbxKrnl/EmuD3D8.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 152a9ec23..a6f6fc558 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3193,17 +3193,16 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) XB_D3DDevice_SetViewport(pViewport); // The following can only work if we have a host render target - IDirect3DSurface *pHostRenderTarget = GetHostSurface(g_pCachedRenderTarget); - if (pHostRenderTarget) { + if (g_pHostRenderTarget) { // Get current host render target dimensions D3DSURFACE_DESC HostRenderTarget; - pHostRenderTarget->GetDesc(&HostRenderTarget); + g_pHostRenderTarget->GetDesc(&HostRenderTarget); // Get current Xbox render target dimensions - DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pCachedRenderTarget); - DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pCachedRenderTarget); + DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); + DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); - // Scale to host backbuffer dimensions (avoiding hard-coding 640 x 480) + // Scale to host dimensions (avoiding hard-coding 640 x 480) D3DVIEWPORT HostViewPort; HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget.Width); @@ -4555,12 +4554,11 @@ void CreateHostResource(XTL::X_D3DResource *pResource, int iTextureStage, DWORD XTL::X_D3DPixelContainer *pPixelContainer = (XTL::X_D3DPixelContainer*)pResource; XTL::X_D3DFORMAT X_Format = GetXboxPixelContainerFormat(pPixelContainer); DWORD D3DUsage = 0; + D3DPOOL D3DPool = D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed - if (pPixelContainer == g_pXboxDepthStencil) { - if (EmuXBFormatIsDepthBuffer(X_Format)) - D3DUsage = D3DUSAGE_DEPTHSTENCIL; - else - EmuWarning("Updating DepthStencil %s with an incompatible format!", ResourceTypeName); + if (EmuXBFormatIsDepthBuffer(X_Format)) { + D3DUsage = D3DUSAGE_DEPTHSTENCIL; + D3DPool = D3DPOOL_DEFAULT; } else if (pPixelContainer == g_pXboxRenderTarget) { if (EmuXBFormatIsRenderTarget(X_Format)) @@ -4704,8 +4702,6 @@ void CreateHostResource(XTL::X_D3DResource *pResource, int iTextureStage, DWORD XTL::IDirect3DTexture *pNewHostTexture = nullptr; // for X_D3DRTYPE_TEXTURE XTL::IDirect3DVolumeTexture *pNewHostVolumeTexture = nullptr; // for X_D3DRTYPE_VOLUMETEXTURE XTL::IDirect3DCubeTexture *pNewHostCubeTexture = nullptr; // for X_D3DRTYPE_CUBETEXTURE - - XTL::D3DPOOL D3DPool = XTL::D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed HRESULT hRet; // Create the surface/volume/(volume/cube/)texture From 25e32d8d7c96e215e9f2bf3cf89b7141c6d4f5f0 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Thu, 26 Apr 2018 23:20:17 +0200 Subject: [PATCH 03/12] HLE : Post-rebase fixes --- src/CxbxKrnl/EmuD3D8.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index a6f6fc558..1fa696f28 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3192,11 +3192,20 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) XB_trampoline(VOID, WINAPI, D3DDevice_SetViewport, (CONST X_D3DVIEWPORT8 *)); XB_D3DDevice_SetViewport(pViewport); - // The following can only work if we have a host render target - if (g_pHostRenderTarget) { + IDirect3DSurface* pHostRenderTarget = nullptr; + + g_pD3DDevice->GetRenderTarget( +#ifdef CXBX_USE_D3D9 + 0, // RenderTargetIndex +#endif + &pHostRenderTarget); + + // The following can only work if we could retrieve a host render target + if (pHostRenderTarget) { // Get current host render target dimensions - D3DSURFACE_DESC HostRenderTarget; - g_pHostRenderTarget->GetDesc(&HostRenderTarget); + D3DSURFACE_DESC HostRenderTarget_Desc; + pHostRenderTarget->GetDesc(&HostRenderTarget_Desc); + pHostRenderTarget->Release(); // Get current Xbox render target dimensions DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); @@ -3205,10 +3214,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) // Scale to host dimensions (avoiding hard-coding 640 x 480) D3DVIEWPORT HostViewPort; - 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); + HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); + HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); + HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); + HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); HostViewPort.MinZ = pViewport->MinZ; // TODO : Must we scale Z too? HostViewPort.MaxZ = pViewport->MaxZ; From eff073e5187c65384e43afc6542e2accdd35f0f9 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Fri, 27 Apr 2018 16:29:39 +0200 Subject: [PATCH 04/12] HLE : Use CxbxGetPixelContainerMeasures to get overlay dimensions --- src/CxbxKrnl/EmuD3D8.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 1fa696f28..5ba38cece 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -99,9 +99,6 @@ static bool g_bSupportsFormatVolumeTexture[XTL::X_D3DFMT static bool g_bSupportsFormatCubeTexture[XTL::X_D3DFMT_LIN_R8G8B8A8 + 1] = { false }; // Does device support surface format? static XTL::LPDIRECTDRAW7 g_pDD7 = NULL; // DirectDraw7 static XTL::DDCAPS g_DriverCaps = { 0 }; -static DWORD g_dwOverlayW = 640; // Cached Overlay Width -static DWORD g_dwOverlayH = 480; // Cached Overlay Height -static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch static HBRUSH g_hBgBrush = NULL; // Background Brush static volatile bool g_bRenderWindowActive = false; static XBVideo g_XBVideo; @@ -5259,11 +5256,12 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay) if (pSurface == NULL) { EmuWarning("pSurface == NULL!"); } else { - uint08 *pYUY2SourceBuffer = (uint08*)GetDataFromXboxResource(pSurface); - - g_dwOverlayW = (pSurface->Size & X_D3DSIZE_WIDTH_MASK) + 1; - g_dwOverlayH = ((pSurface->Size & X_D3DSIZE_HEIGHT_MASK) >> X_D3DSIZE_HEIGHT_SHIFT) + 1; - g_dwOverlayP = (((pSurface->Size & X_D3DSIZE_PITCH_MASK) >> X_D3DSIZE_PITCH_SHIFT) + 1) * 64; + uint08 *pOverlayData = (uint08*)GetDataFromXboxResource(pSurface); + UINT OverlayWidth, OverlayHeight, OverlayDepth, OverlayRowPitch, OverlaySlicePitch; + CxbxGetPixelContainerMeasures( + (XTL::X_D3DPixelContainer *)pSurface, + 0, // dwMipMapLevel + &OverlayWidth, &OverlayHeight, &OverlayDepth, &OverlayRowPitch, &OverlaySlicePitch); RECT EmuSourRect; RECT EmuDestRect; @@ -5271,7 +5269,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay) if (SrcRect != NULL) { EmuSourRect = *SrcRect; } else { - SetRect(&EmuSourRect, 0, 0, g_dwOverlayW, g_dwOverlayH); + SetRect(&EmuSourRect, 0, 0, OverlayWidth, OverlayHeight); } if (DstRect != NULL) { @@ -5318,9 +5316,9 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay) /* pDestSurface = */ pCurrentHostBackBuffer, /* pDestPalette = */ nullptr, // Palette not needed for YUY2 /* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable - /* pSrcMemory = */ pYUY2SourceBuffer, // Source buffer + /* pSrcMemory = */ pOverlayData, // Source buffer /* SrcFormat = */ D3DFMT_YUY2, - /* SrcPitch = */ g_dwOverlayP, + /* SrcPitch = */ OverlayRowPitch, /* pSrcPalette = */ nullptr, // Palette not needed for YUY2 /* SrcRect = */ &EmuSourRect, /* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders From 73b96ac783289dc1d920ce3476965b7c998cfd3d Mon Sep 17 00:00:00 2001 From: patrickvl Date: Fri, 27 Apr 2018 17:16:39 +0200 Subject: [PATCH 05/12] HLE : Disable calling the Xbox SetViewport code, as it causes regressions. Also start collecting test-cases for D3DDevice_GetViewportOffsetAndScale --- src/CxbxKrnl/EmuD3D8.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 5ba38cece..90ffd0926 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3185,9 +3185,11 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) LOG_FUNC_ONE_ARG(pViewport); +#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); +#endif IDirect3DSurface* pHostRenderTarget = nullptr; @@ -3215,7 +3217,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); - HostViewPort.MinZ = pViewport->MinZ; // TODO : Must we scale Z too? + HostViewPort.MinZ = pViewport->MinZ; // No need scale Z for now HostViewPort.MaxZ = pViewport->MaxZ; HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); @@ -3231,19 +3233,12 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewport) X_D3DVIEWPORT8 *pViewport ) { - // FUNC_EXPORTS + FUNC_EXPORTS LOG_FUNC_ONE_ARG(pViewport); HRESULT hRet = g_pD3DDevice->GetViewport(pViewport); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetViewport"); - - if(FAILED(hRet)) - { - EmuWarning("Unable to get viewport! - We're lying"); - - hRet = D3D_OK; - } } // LTCG specific D3DDevice_GetViewportOffsetAndScale function... @@ -3276,13 +3271,15 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) X_D3DXVECTOR4 *pScale ) { - // FUNC_EXPORTS + FUNC_EXPORTS LOG_FUNC_BEGIN LOG_FUNC_ARG(pOffset) LOG_FUNC_ARG(pScale) LOG_FUNC_END; + LOG_TEST_CASE("D3DDevice_GetViewportOffsetAndScale"); // Get us some test-cases + float fScaleX = 1.0f; float fScaleY = 1.0f; float fScaleZ = 1.0f; @@ -3290,10 +3287,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) float fOffsetY = 0.5 + 1.0/32; X_D3DVIEWPORT8 Viewport; - EMUPATCH(D3DDevice_GetViewport)(&Viewport); - - pScale->x = 1.0f; pScale->y = 1.0f; @@ -3316,8 +3310,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) pOffset->z = Viewport.MinZ * fScaleZ; pOffset->w = 0; */ - - } // LTCG specific D3DDevice_SetShaderConstantMode function... // This uses a custom calling convention where parameter is passed in EAX From df81c52372227c2ee69e150e5eeb9b09a810c28f Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 28 Apr 2018 02:44:40 +0200 Subject: [PATCH 06/12] HLE : Resize window according to configuration --- src/Cxbx/WndMain.cpp | 67 ++++++++----- src/Cxbx/WndMain.h | 3 + src/CxbxKrnl/EmuD3D8.cpp | 199 ++++++++++++++++++++++----------------- 3 files changed, 162 insertions(+), 107 deletions(-) diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index ee589eb8f..ca10b3775 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -113,6 +113,42 @@ void WndMain::InitializeSettings() { #define TIMERID_FPS 0 #define TIMERID_LED 1 +void WndMain::CenterToDesktop() +{ + RECT rect; + + GetWindowRect(GetDesktopWindow(), &rect); + + m_x = rect.left + ((rect.right - rect.left - m_w) / 2); + m_y = rect.top + ((rect.bottom - rect.top - m_h) / 2); +} + +void WndMain::ResizeWindowForFullClientArea(HWND hwnd) +{ +#if 0 + RECT cRect; + RECT wRect; + + GetClientRect(hwnd, &cRect); + GetWindowRect(hwnd, &wRect); + + uint32 difW = (wRect.right - wRect.left) - (cRect.right); + uint32 difH = (wRect.bottom - wRect.top) - (cRect.bottom); + + MoveWindow(hwnd, wRect.left, wRect.top, difW + m_w, difH + m_h, TRUE); +#else + RECT windowRect = { m_x, m_y, m_x + m_w, m_y + m_h }; + + AdjustWindowRectEx(&windowRect, GetWindowLong(hwnd, GWL_STYLE), GetMenu(hwnd) != NULL, GetWindowLong(hwnd, GWL_EXSTYLE)); + SetWindowPos(hwnd, 0, + windowRect.left, + windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top, + SWP_NOOWNERZORDER | SWP_NOZORDER); +#endif +} + WndMain::WndMain(HINSTANCE x_hInstance) : Wnd(x_hInstance), m_bCreated(false), @@ -142,15 +178,7 @@ WndMain::WndMain(HINSTANCE x_hInstance) : m_szRecentXbe[v] = 0; } - // center to desktop - { - RECT rect; - - GetWindowRect(GetDesktopWindow(), &rect); - - m_x = rect.left + (rect.right - rect.left)/2 - m_w/2; - m_y = rect.top + (rect.bottom - rect.top)/2 - m_h/2; - } + CenterToDesktop(); // load configuration from registry { @@ -402,20 +430,9 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } // resize window so that client area := 640x480 - { - RECT cRect; - RECT wRect; + ResizeWindowForFullClientArea(hwnd); - GetClientRect(hwnd, &cRect); - GetWindowRect(hwnd, &wRect); - - uint32 difW = (wRect.right - wRect.left) - (cRect.right); - uint32 difH = (wRect.bottom - wRect.top) - (cRect.bottom); - - MoveWindow(hwnd, wRect.left, wRect.top, difW + m_w, difH + m_h, TRUE); - } - - // initialize back buffer + // initialize back buffer { HDC hDC = GetDC(hwnd); @@ -2211,6 +2228,12 @@ void WndMain::StopEmulation() UpdateCaption(); RefreshMenus(); + // Set the window size back to it's GUI dimensions + m_w = 640; + m_h = 480; + CenterToDesktop(); + ResizeWindowForFullClientArea(m_hwnd); + // TODO : Combine the above into one operation } diff --git a/src/Cxbx/WndMain.h b/src/Cxbx/WndMain.h index 7182cb307..3531fcead 100644 --- a/src/Cxbx/WndMain.h +++ b/src/Cxbx/WndMain.h @@ -87,6 +87,9 @@ class WndMain : public Wnd static void SuggestFilename(const char *x_orig_filename, char *x_filename, char x_extension[4]); private: + void CenterToDesktop(); + void ResizeWindowForFullClientArea(HWND hwnd); + // ****************************************************************** // * after an xbe is loaded, some things must be updated // ****************************************************************** diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 90ffd0926..fd877f30e 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -920,7 +920,6 @@ void SetHostResource(XTL::X_D3DResource* pXboxResource, XTL::IDirect3DResource* hostResourceInfo.forceRehash = false; g_HostResources[key] = hostResourceInfo; - } XTL::IDirect3DSurface *GetHostSurface(XTL::X_D3DResource *pXboxResource) @@ -1418,36 +1417,58 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) // create the window { - DWORD dwStyle = (g_XBVideo.GetFullscreen() || (CxbxKrnl_hEmuParent == 0))? WS_OVERLAPPEDWINDOW : WS_CHILD; - - int nTitleHeight = GetSystemMetrics(SM_CYCAPTION); - int nBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME); - int nBorderHeight = GetSystemMetrics(SM_CYSIZEFRAME); - - int x = 100, y = 100, nWidth = 640, nHeight = 480; - - nWidth += nBorderWidth*2; - nHeight += nBorderHeight*2 + nTitleHeight; - - sscanf(g_XBVideo.GetVideoResolution(), "%d x %d", &nWidth, &nHeight); - - if(g_XBVideo.GetFullscreen()) - { - x = y = nWidth = nHeight = 0; - dwStyle = WS_POPUP; - } - HWND hwndParent = GetDesktopWindow(); + DWORD dwStyle = WS_POPUP; + RECT windowRect = { 0 }; - if(!g_XBVideo.GetFullscreen()) - { - hwndParent = CxbxKrnl_hEmuParent; + if (!g_XBVideo.GetFullscreen()) { + + int nWidth = 640, nHeight = 480; + const char* resolution = g_XBVideo.GetVideoResolution(); + if (2 != sscanf(resolution, "%d x %d", &nWidth, &nHeight)) { + DbgPrintf("EmuD3D8: Couldn't parse resolution : %s.\n", resolution); + } + else { + if (nWidth == 640) + DbgPrintf("EmuD3D8: Default width wasn't updated.\n"); + if (nWidth == 480) + DbgPrintf("EmuD3D8: Default height wasn't updated.\n"); + } + + // See void WndMain::CenterToDesktop() + { + RECT rect; + + GetWindowRect(hwndParent/*=GetDesktopWindow()*/, &rect); + + windowRect.left = rect.left + ((rect.right - rect.left - nWidth) / 2); + windowRect.top = rect.top + ((rect.bottom - rect.top - nHeight) / 2); + } + + // Resize the parent window so it can contain the requested window resolution + windowRect.right = windowRect.left + nWidth; + windowRect.bottom = windowRect.top + nHeight; + hwndParent = CxbxKrnl_hEmuParent; + dwStyle = (CxbxKrnl_hEmuParent == 0) ? WS_OVERLAPPEDWINDOW : WS_CHILD; + AdjustWindowRectEx(&windowRect, dwStyle, GetMenu(hwndParent) != NULL, GetWindowLong(hwndParent, GWL_EXSTYLE)); + // TODO : For DPI screens, replace AdjustWindowRectEx by DwmGetWindowAttribute using DWMWA_EXTENDED_FRAME_BOUNDS + + SetWindowPos(hwndParent, 0, + windowRect.left, + windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top, + SWP_ASYNCWINDOWPOS | SWP_NOOWNERZORDER | SWP_NOZORDER); } g_hEmuWindow = CreateWindow ( "CxbxRender", "Cxbx-Reloaded", - dwStyle, x, y, nWidth, nHeight, + dwStyle, + windowRect.left, + windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top, hwndParent, NULL, GetModuleHandle(NULL), NULL ); } @@ -1836,25 +1857,51 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) { DbgPrintf("EmuD3D8: CreateDevice proxy thread received request.\n"); - if(g_EmuCDPD.bCreate) - { - // only one device should be created at once - // TODO: ensure all surfaces are somehow cleaned up? - if(g_pD3DDevice != nullptr) - { - DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n"); + // only one device should be created at once + if (g_pD3DDevice != nullptr) { + DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n"); - g_pD3DDevice->EndScene(); + g_pD3DDevice->EndScene(); - // Address DirectX Debug Runtime reported error in _DEBUG builds - // Direct3D8: (ERROR) :Not all objects were freed: the following indicate the types of unfreed objects. - #ifndef _DEBUG - while(g_pD3DDevice->Release() != 0); - #endif + for (auto &hostResourceIterator : g_HostResources) { + if (hostResourceIterator.second.pHostResource) { + (hostResourceIterator.second.pHostResource)->Release(); + } + } + g_HostResources.clear(); - g_pD3DDevice = nullptr; - } + // TODO: ensure all other resources are cleaned up too + g_EmuCDPD.hRet = g_pD3DDevice->Release(); + + // Address DirectX Debug Runtime reported error in _DEBUG builds + // Direct3D8: (ERROR) :Not all objects were freed: the following indicate the types of unfreed objects. + #ifndef _DEBUG + while(g_pD3DDevice->Release() != 0); + #endif + + g_pD3DDevice = nullptr; + + // cleanup overlay clipper + if (g_pDDClipper != nullptr) { + g_pDDClipper->Release(); + g_pDDClipper = nullptr; + } + + // cleanup directdraw surface + if (g_pDDSPrimary != nullptr) { + g_pDDSPrimary->Release(); + g_pDDSPrimary = nullptr; + } + + // cleanup directdraw + if (g_pDD7 != nullptr) { + g_pDD7->Release(); + g_pDD7 = nullptr; + } + } + + if (g_EmuCDPD.bCreate) { if(g_EmuCDPD.XboxPresentationParameters.BufferSurfaces[0] != NULL) EmuWarning("BufferSurfaces[0] : 0x%.08X", g_EmuCDPD.XboxPresentationParameters.BufferSurfaces[0]); @@ -1915,7 +1962,16 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) // retrieve resolution from configuration if(g_EmuCDPD.HostPresentationParameters.Windowed) { - sscanf(g_XBVideo.GetVideoResolution(), "%d x %d", &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, &g_EmuCDPD.HostPresentationParameters.BackBufferHeight); + const char* resolution = g_XBVideo.GetVideoResolution(); + if (2 != sscanf(resolution, "%d x %d", &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, &g_EmuCDPD.HostPresentationParameters.BackBufferHeight)) { + DbgPrintf("EmuCreateDeviceProxy: Couldn't parse resolution : %s.\n", resolution); + } + else { + if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 640) + DbgPrintf("EmuCreateDeviceProxy: Default width wasn't updated.\n"); + if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 480) + DbgPrintf("EmuCreateDeviceProxy: Default height wasn't updated.\n"); + } XTL::D3DDISPLAYMODE D3DDisplayMode; @@ -1928,11 +1984,20 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) { char szBackBufferFormat[16]; - sscanf(g_XBVideo.GetVideoResolution(), "%d x %d %*dbit %s (%d hz)", - &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, - &g_EmuCDPD.HostPresentationParameters.BackBufferHeight, - szBackBufferFormat, - &g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz); + const char* resolution = g_XBVideo.GetVideoResolution(); + if (4 != sscanf(resolution, "%d x %d %*dbit %s (%d hz)", + &g_EmuCDPD.HostPresentationParameters.BackBufferWidth, + &g_EmuCDPD.HostPresentationParameters.BackBufferHeight, + szBackBufferFormat, + &g_EmuCDPD.HostPresentationParameters.FullScreen_RefreshRateInHz)) { + DbgPrintf("EmuCreateDeviceProxy: Couldn't parse resolution : %s.\n", resolution); + } + else { + if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 640) + DbgPrintf("EmuCreateDeviceProxy: Default width wasn't updated.\n"); + if (g_EmuCDPD.HostPresentationParameters.BackBufferWidth == 480) + DbgPrintf("EmuCreateDeviceProxy: Default height wasn't updated.\n"); + } if(strcmp(szBackBufferFormat, "x1r5g5b5") == 0) g_EmuCDPD.HostPresentationParameters.BackBufferFormat = XTL::D3DFMT_X1R5G5B5; @@ -2182,48 +2247,10 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID) // begin scene hRet = g_pD3DDevice->BeginScene(); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene(2nd)"); - - // signal completion - g_EmuCDPD.bReady = false; } - else - { - // release direct3d - if(g_pD3DDevice != nullptr) - { - DbgPrintf("EmuD3D8: CreateDevice proxy thread releasing old Device.\n"); - g_pD3DDevice->EndScene(); - - g_EmuCDPD.hRet = g_pD3DDevice->Release(); - if(g_EmuCDPD.hRet == 0) - g_pD3DDevice = nullptr; - } - - // cleanup overlay clipper - if (g_pDDClipper != nullptr) - { - g_pDDClipper->Release(); - g_pDDClipper = nullptr; - } - - // cleanup directdraw surface - if(g_pDDSPrimary != nullptr) - { - g_pDDSPrimary->Release(); - g_pDDSPrimary = nullptr; - } - - // cleanup directdraw - if(g_pDD7 != nullptr) - { - g_pDD7->Release(); - g_pDD7 = nullptr; - } - - // signal completion - g_EmuCDPD.bReady = false; - } + // signal completion + g_EmuCDPD.bReady = false; } Sleep(1); @@ -3217,6 +3244,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Desc.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; @@ -3279,6 +3307,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) LOG_FUNC_END; LOG_TEST_CASE("D3DDevice_GetViewportOffsetAndScale"); // Get us some test-cases + // Test case : Spongebob - Battle for Bikini Bottom float fScaleX = 1.0f; float fScaleY = 1.0f; From 2654eaae3c7ae12f4b194ac9aa15fa38dcfe455a Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 28 Apr 2018 03:16:28 +0200 Subject: [PATCH 07/12] HLE : Limit width/height to desktop resolution --- src/CxbxKrnl/EmuD3D8.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index fd877f30e..6e080174c 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1437,12 +1437,21 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) // See void WndMain::CenterToDesktop() { - RECT rect; + RECT desktop; - GetWindowRect(hwndParent/*=GetDesktopWindow()*/, &rect); + // TODO : Acknowledge DPI scaling here + GetWindowRect(hwndParent/*=GetDesktopWindow()*/, &desktop); - windowRect.left = rect.left + ((rect.right - rect.left - nWidth) / 2); - windowRect.top = rect.top + ((rect.bottom - rect.top - nHeight) / 2); + // Limit width/height to desktop resolution + int dWidth = desktop.right - desktop.left; + int dHeight = desktop.bottom - desktop.top; + if (nWidth > dWidth) + nWidth = dWidth; + if (nHeight > dHeight) + nHeight = dHeight; + + windowRect.left = desktop.left + ((dWidth - nWidth) / 2); + windowRect.top = desktop.top + ((dHeight - nHeight) / 2); } // Resize the parent window so it can contain the requested window resolution From 8fa81b99affa14ec82b3c2844b57a326c58a6f33 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 28 Apr 2018 23:36:13 +0200 Subject: [PATCH 08/12] HLE : Post-rebase fixes --- src/CxbxKrnl/EmuD3D8.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 6e080174c..743d0e540 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -4590,11 +4590,11 @@ void CreateHostResource(XTL::X_D3DResource *pResource, int iTextureStage, DWORD XTL::X_D3DPixelContainer *pPixelContainer = (XTL::X_D3DPixelContainer*)pResource; XTL::X_D3DFORMAT X_Format = GetXboxPixelContainerFormat(pPixelContainer); DWORD D3DUsage = 0; - D3DPOOL D3DPool = D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed + XTL::D3DPOOL D3DPool = XTL::D3DPOOL_MANAGED; // TODO : Nuance D3DPOOL where/when needed if (EmuXBFormatIsDepthBuffer(X_Format)) { D3DUsage = D3DUSAGE_DEPTHSTENCIL; - D3DPool = D3DPOOL_DEFAULT; + D3DPool = XTL::D3DPOOL_DEFAULT; } else if (pPixelContainer == g_pXboxRenderTarget) { if (EmuXBFormatIsRenderTarget(X_Format)) From bed1d7bfc7182d0b53bc1db9dcc816e5f83fd7b1 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sun, 29 Apr 2018 00:09:47 +0200 Subject: [PATCH 09/12] HLE : Fake field rendering by halving the perceived height in SetViewPort --- src/CxbxKrnl/EmuD3D8.cpp | 6 ++++++ src/CxbxKrnl/EmuD3D8Types.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 743d0e540..370983115 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3246,6 +3246,12 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); + // Emulate field-rendering not by halving the host backbuffer, but by faking + // the host backbuffer to half-height, which results in a correct viewport scale : + if (g_EmuCDPD.XboxPresentationParameters.Flags & X_D3DPRESENTFLAG_FIELD) { + HostRenderTarget_Desc.Height /= 2; + } + // Scale to host dimensions (avoiding hard-coding 640 x 480) D3DVIEWPORT HostViewPort; diff --git a/src/CxbxKrnl/EmuD3D8Types.h b/src/CxbxKrnl/EmuD3D8Types.h index e452d84ed..0ba6f76b4 100755 --- a/src/CxbxKrnl/EmuD3D8Types.h +++ b/src/CxbxKrnl/EmuD3D8Types.h @@ -358,7 +358,12 @@ typedef enum _X_D3DSET_DEPTH_CLIP_PLANES_FLAGS } X_D3DSET_DEPTH_CLIP_PLANES_FLAGS; +#define X_D3DPRESENTFLAG_LOCKABLE_BACKBUFFER 0x00000001 +#define X_D3DPRESENTFLAG_WIDESCREEN 0x00000010 #define X_D3DPRESENTFLAG_INTERLACED 0x00000020 +#define X_D3DPRESENTFLAG_PROGRESSIVE 0x00000040 +#define X_D3DPRESENTFLAG_FIELD 0x00000080 +#define X_D3DPRESENTFLAG_10X11PIXELASPECTRATIO 0x00000100 typedef struct _X_D3DDISPLAYMODE { From 6a897212a792ba8834c9ce48c82047710cb231e6 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sun, 29 Apr 2018 15:14:10 +0200 Subject: [PATCH 10/12] HLE : Refactored window resizing, so it's done only when needed, only in the GUI process. --- src/Cxbx/Wnd.cpp | 4 +- src/Cxbx/WndMain.cpp | 87 ++++++++++++++++++++++------------------ src/Cxbx/WndMain.h | 6 ++- src/CxbxKrnl/EmuD3D8.cpp | 45 +-------------------- 4 files changed, 54 insertions(+), 88 deletions(-) diff --git a/src/Cxbx/Wnd.cpp b/src/Cxbx/Wnd.cpp index 9e65c24e3..d7118cb85 100644 --- a/src/Cxbx/Wnd.cpp +++ b/src/Cxbx/Wnd.cpp @@ -45,8 +45,8 @@ Wnd::Wnd(HINSTANCE x_hInstance) : m_hInstance(x_hInstance) m_wndname = "Cxbx-Reloaded Generic Window"; m_x = 150; m_y = 150; - m_w = 320; - m_h = 240; + m_w = 640; + m_h = 480; m_parent = NULL; m_clsstyle = CS_HREDRAW | CS_VREDRAW; m_wndstyle = WS_CLIPCHILDREN | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE; diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index ca10b3775..f4292c46a 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -113,40 +113,50 @@ void WndMain::InitializeSettings() { #define TIMERID_FPS 0 #define TIMERID_LED 1 -void WndMain::CenterToDesktop() +void WndMain::ResizeWindow(bool bForGUI) { - RECT rect; + RECT desktopRect; + RECT windowRect; - GetWindowRect(GetDesktopWindow(), &rect); + // Set the window size back to it's GUI dimensions + m_w = 640; + m_h = 480; + if (!bForGUI) { + // For emulation, get the configured window dimensions + XBVideo XBVideoConf; + g_EmuShared->GetXBVideo(&XBVideoConf); - m_x = rect.left + ((rect.right - rect.left - m_w) / 2); - m_y = rect.top + ((rect.bottom - rect.top - m_h) / 2); -} + const char* resolution = XBVideoConf.GetVideoResolution(); + if (2 != sscanf(resolution, "%d x %d", &m_w, &m_h)) { + DbgPrintf("Couldn't parse resolution : %s.\n", resolution); + } + } -void WndMain::ResizeWindowForFullClientArea(HWND hwnd) -{ -#if 0 - RECT cRect; - RECT wRect; + // TODO : Acknowledge DPI scaling here + GetWindowRect(GetDesktopWindow(), &desktopRect); - GetClientRect(hwnd, &cRect); - GetWindowRect(hwnd, &wRect); + // Limit width/height to desktop resolution + int dWidth = desktopRect.right - desktopRect.left; + int dHeight = desktopRect.bottom - desktopRect.top; + if (m_w > dWidth) + m_w = dWidth; + if (m_h > dHeight) + m_h = dHeight; - uint32 difW = (wRect.right - wRect.left) - (cRect.right); - uint32 difH = (wRect.bottom - wRect.top) - (cRect.bottom); + // Center to desktop + m_x = desktopRect.left + ((desktopRect.right - desktopRect.left - m_w) / 2); + m_y = desktopRect.top + ((desktopRect.bottom - desktopRect.top - m_h) / 2); - MoveWindow(hwnd, wRect.left, wRect.top, difW + m_w, difH + m_h, TRUE); -#else - RECT windowRect = { m_x, m_y, m_x + m_w, m_y + m_h }; - - AdjustWindowRectEx(&windowRect, GetWindowLong(hwnd, GWL_STYLE), GetMenu(hwnd) != NULL, GetWindowLong(hwnd, GWL_EXSTYLE)); - SetWindowPos(hwnd, 0, + // 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)); + // TODO : For DPI screens, replace AdjustWindowRectEx by DwmGetWindowAttribute using DWMWA_EXTENDED_FRAME_BOUNDS + SetWindowPos(m_hwnd, 0, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_NOOWNERZORDER | SWP_NOZORDER); -#endif } WndMain::WndMain(HINSTANCE x_hInstance) : @@ -166,9 +176,6 @@ WndMain::WndMain(HINSTANCE x_hInstance) : m_classname = "WndMain"; m_wndname = "Cxbx-Reloaded " _CXBX_VERSION; - m_w = 640; - m_h = 480; - m_XbeFilename = (char*)calloc(1, MAX_PATH); m_CxbxDebugFilename = (char*)calloc(1, MAX_PATH); @@ -178,8 +185,6 @@ WndMain::WndMain(HINSTANCE x_hInstance) : m_szRecentXbe[v] = 0; } - CenterToDesktop(); - // load configuration from registry { DWORD dwDisposition, dwType, dwSize; @@ -429,8 +434,9 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP SetMenu(hwnd, hMenu); } - // resize window so that client area := 640x480 - ResizeWindowForFullClientArea(hwnd); + // Set window size to GUI dimensions + m_hwnd = hwnd; // Needed inside ResizeWindow (will be set to the same value later wayway) + ResizeWindow(/*bForGUI=*/true); // initialize back buffer { @@ -494,8 +500,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP { CreateThread(NULL, NULL, CrashMonitorWrapper, (void*)this, NULL, NULL); // create the crash monitoring thread if (m_hwndChild == NULL) { - float fps = 0; - float mspf = 0; + float fps = 0.0f; + float mspf = 0.0f; int LedSequence[4] = { XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN, XBOX_LED_COLOUR_GREEN }; g_EmuShared->SetCurrentMSpF(&mspf); g_EmuShared->SetCurrentFPS(&fps); @@ -671,13 +677,15 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case VK_F9: { // Try to open the most recent Xbe if none is opened yet : - if (m_Xbe == nullptr) - OpenMRU(0); + if (!m_bIsStarted) { + if (m_Xbe == nullptr) + OpenMRU(0); - if (m_Xbe != nullptr) - if (!m_bIsStarted) + if (m_Xbe != nullptr) StartEmulation(hwnd, debuggerOn); + } } + break; default: { @@ -2160,6 +2168,9 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / g_EmuShared->SetUseAllCores(&m_UseAllCores); g_EmuShared->SetPatchCpuFrequency(&m_PatchCpuFrequency); + // Set the window size to emulation dimensions + ResizeWindow(/*bForGUI*/false); + // shell exe { GetModuleFileName(NULL, szBuffer, MAX_PATH); @@ -2229,11 +2240,7 @@ void WndMain::StopEmulation() UpdateCaption(); RefreshMenus(); // Set the window size back to it's GUI dimensions - m_w = 640; - m_h = 480; - CenterToDesktop(); - ResizeWindowForFullClientArea(m_hwnd); - // TODO : Combine the above into one operation + ResizeWindow(/*bForGUI=*/true); } diff --git a/src/Cxbx/WndMain.h b/src/Cxbx/WndMain.h index 3531fcead..eed0e780d 100644 --- a/src/Cxbx/WndMain.h +++ b/src/Cxbx/WndMain.h @@ -87,8 +87,10 @@ class WndMain : public Wnd static void SuggestFilename(const char *x_orig_filename, char *x_filename, char x_extension[4]); private: - void CenterToDesktop(); - void ResizeWindowForFullClientArea(HWND hwnd); + // ****************************************************************** + // * resize the main window for either GUI or emulation + // ****************************************************************** + void ResizeWindow(bool bForGUI); // ****************************************************************** // * after an xbe is loaded, some things must be updated diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 370983115..aca958558 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1422,52 +1422,9 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) RECT windowRect = { 0 }; if (!g_XBVideo.GetFullscreen()) { - - int nWidth = 640, nHeight = 480; - const char* resolution = g_XBVideo.GetVideoResolution(); - if (2 != sscanf(resolution, "%d x %d", &nWidth, &nHeight)) { - DbgPrintf("EmuD3D8: Couldn't parse resolution : %s.\n", resolution); - } - else { - if (nWidth == 640) - DbgPrintf("EmuD3D8: Default width wasn't updated.\n"); - if (nWidth == 480) - DbgPrintf("EmuD3D8: Default height wasn't updated.\n"); - } - - // See void WndMain::CenterToDesktop() - { - RECT desktop; - - // TODO : Acknowledge DPI scaling here - GetWindowRect(hwndParent/*=GetDesktopWindow()*/, &desktop); - - // Limit width/height to desktop resolution - int dWidth = desktop.right - desktop.left; - int dHeight = desktop.bottom - desktop.top; - if (nWidth > dWidth) - nWidth = dWidth; - if (nHeight > dHeight) - nHeight = dHeight; - - windowRect.left = desktop.left + ((dWidth - nWidth) / 2); - windowRect.top = desktop.top + ((dHeight - nHeight) / 2); - } - - // Resize the parent window so it can contain the requested window resolution - windowRect.right = windowRect.left + nWidth; - windowRect.bottom = windowRect.top + nHeight; hwndParent = CxbxKrnl_hEmuParent; + GetWindowRect(hwndParent, &windowRect); dwStyle = (CxbxKrnl_hEmuParent == 0) ? WS_OVERLAPPEDWINDOW : WS_CHILD; - AdjustWindowRectEx(&windowRect, dwStyle, GetMenu(hwndParent) != NULL, GetWindowLong(hwndParent, GWL_EXSTYLE)); - // TODO : For DPI screens, replace AdjustWindowRectEx by DwmGetWindowAttribute using DWMWA_EXTENDED_FRAME_BOUNDS - - SetWindowPos(hwndParent, 0, - windowRect.left, - windowRect.top, - windowRect.right - windowRect.left, - windowRect.bottom - windowRect.top, - SWP_ASYNCWINDOWPOS | SWP_NOOWNERZORDER | SWP_NOZORDER); } g_hEmuWindow = CreateWindow From 7ac82d5de1e8a88352cc3202ab358ce4731d445f Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Tue, 1 May 2018 17:03:49 +0200 Subject: [PATCH 11/12] HLE : GetViewport scales host viewport back to Xbox dimensions (some titles might get less confused by the return value) --- src/CxbxKrnl/EmuD3D8.cpp | 147 ++++++++++++++++++++++++++------------- 1 file changed, 99 insertions(+), 48 deletions(-) diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index aca958558..185d86aab 100755 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -3158,11 +3158,42 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetBackBuffer) *ppBackBuffer = EMUPATCH(D3DDevice_GetBackBuffer2)(BackBuffer); } -DWORD ScaleDWORD(DWORD XboxIn, DWORD XboxMax, DWORD HostMax) +bool GetHostRenderTargetDimensions(DWORD *pHostWidth, DWORD *pHostHeight) { - uint64_t tmp = XboxIn; - tmp *= HostMax; - tmp /= XboxMax; + XTL::IDirect3DSurface* pHostRenderTarget = nullptr; + + g_pD3DDevice->GetRenderTarget( +#ifdef CXBX_USE_D3D9 + 0, // RenderTargetIndex +#endif + &pHostRenderTarget); + + // The following can only work if we could retrieve a host render target + if (!pHostRenderTarget) + return false; + + // Get current host render target dimensions + XTL::D3DSURFACE_DESC HostRenderTarget_Desc; + pHostRenderTarget->GetDesc(&HostRenderTarget_Desc); + pHostRenderTarget->Release(); + + // Emulate field-rendering not by halving the host backbuffer, but by faking + // the host backbuffer to half-height, which results in a correct viewport scale : + if (g_EmuCDPD.XboxPresentationParameters.Flags & X_D3DPRESENTFLAG_FIELD) { + HostRenderTarget_Desc.Height /= 2; + } + + *pHostWidth = HostRenderTarget_Desc.Width; + *pHostHeight = HostRenderTarget_Desc.Height; + + return true; +} + +DWORD ScaleDWORD(DWORD Value, DWORD FromMax, DWORD ToMax) +{ + uint64_t tmp = Value; + tmp *= ToMax; + tmp /= FromMax; return (DWORD)tmp; } @@ -3184,45 +3215,34 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetViewport) XB_D3DDevice_SetViewport(pViewport); #endif - IDirect3DSurface* pHostRenderTarget = nullptr; + // Get current Xbox render target dimensions + DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); + DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); - g_pD3DDevice->GetRenderTarget( -#ifdef CXBX_USE_D3D9 - 0, // RenderTargetIndex -#endif - &pHostRenderTarget); + // Get current host render target dimensions + DWORD HostRenderTarget_Width; + DWORD HostRenderTarget_Height; - // The following can only work if we could retrieve a host render target - if (pHostRenderTarget) { - // Get current host render target dimensions - D3DSURFACE_DESC HostRenderTarget_Desc; - pHostRenderTarget->GetDesc(&HostRenderTarget_Desc); - pHostRenderTarget->Release(); + D3DVIEWPORT HostViewPort; - // Get current Xbox render target dimensions - DWORD XboxRenderTarget_Width = GetPixelContainerWidth(g_pXboxRenderTarget); - DWORD XboxRenderTarget_Height = GetPixelContainerHeigth(g_pXboxRenderTarget); + if (GetHostRenderTargetDimensions(&HostRenderTarget_Width, &HostRenderTarget_Height)) { - // Emulate field-rendering not by halving the host backbuffer, but by faking - // the host backbuffer to half-height, which results in a correct viewport scale : - if (g_EmuCDPD.XboxPresentationParameters.Flags & X_D3DPRESENTFLAG_FIELD) { - HostRenderTarget_Desc.Height /= 2; - } - - // Scale to host dimensions (avoiding hard-coding 640 x 480) - D3DVIEWPORT HostViewPort; - - HostViewPort.X = ScaleDWORD(pViewport->X, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); - HostViewPort.Y = ScaleDWORD(pViewport->Y, XboxRenderTarget_Height, HostRenderTarget_Desc.Height); - HostViewPort.Width = ScaleDWORD(pViewport->Width, XboxRenderTarget_Width, HostRenderTarget_Desc.Width); - HostViewPort.Height = ScaleDWORD(pViewport->Height, XboxRenderTarget_Height, HostRenderTarget_Desc.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; - - HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); - DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetViewport"); } + else { + HostViewPort = *pViewport; + EmuWarning("GetHostRenderTargetDimensions failed - SetViewport sets Xbox viewport instead!"); + } + + HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); + DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetViewport"); } // ****************************************************************** @@ -3237,8 +3257,39 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewport) LOG_FUNC_ONE_ARG(pViewport); - HRESULT hRet = g_pD3DDevice->GetViewport(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; + } + else { + *pViewport = HostViewPort; + EmuWarning("GetHostRenderTargetDimensions failed - GetViewport returns host viewport instead!"); + } } // LTCG specific D3DDevice_GetViewportOffsetAndScale function... @@ -3281,6 +3332,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) LOG_TEST_CASE("D3DDevice_GetViewportOffsetAndScale"); // Get us some test-cases // Test case : Spongebob - Battle for Bikini Bottom +#if 0 float fScaleX = 1.0f; float fScaleY = 1.0f; float fScaleZ = 1.0f; @@ -3290,17 +3342,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) EMUPATCH(D3DDevice_GetViewport)(&Viewport); - pScale->x = 1.0f; - pScale->y = 1.0f; - pScale->z = 1.0f; - pScale->w = 1.0f; - - pOffset->x = 0.0f; - pOffset->y = 0.0f; - pOffset->z = 0.0f; - pOffset->w = 0.0f; - -/* pScale->x = (float)Viewport.Width * 0.5f * fScaleX; pScale->y = (float)Viewport.Height * -0.5f * fScaleY; pScale->z = (Viewport.MaxZ - Viewport.MinZ) * fScaleZ; @@ -3310,7 +3351,17 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_GetViewportOffsetAndScale) pOffset->y = (float)Viewport.Height * fScaleY * 0.5f + (float)Viewport.Y * fScaleY + fOffsetY; pOffset->z = Viewport.MinZ * fScaleZ; pOffset->w = 0; -*/ +#else + pScale->x = 1.0f; + pScale->y = 1.0f; + pScale->z = 1.0f; + pScale->w = 1.0f; + + pOffset->x = 0.0f; + pOffset->y = 0.0f; + pOffset->z = 0.0f; + pOffset->w = 0.0f; +#endif } // LTCG specific D3DDevice_SetShaderConstantMode function... // This uses a custom calling convention where parameter is passed in EAX From ccd82a8e0fa267e168701563ffb3dc1f566bf1f2 Mon Sep 17 00:00:00 2001 From: patrickvl Date: Wed, 2 May 2018 19:01:26 +0200 Subject: [PATCH 12/12] 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; }; // ******************************************************************