From 190ef8c3d5b7627e0bc7f50904c4ebdeca1a13c7 Mon Sep 17 00:00:00 2001 From: Silent Date: Thu, 8 Oct 2020 21:05:28 +0200 Subject: [PATCH 1/2] Implement X_D3DRS_MULTISAMPLETYPE --- src/core/hle/D3D8/Direct3D9/RenderStates.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/RenderStates.cpp b/src/core/hle/D3D8/Direct3D9/RenderStates.cpp index 71782cc0d..7014acb85 100644 --- a/src/core/hle/D3D8/Direct3D9/RenderStates.cpp +++ b/src/core/hle/D3D8/Direct3D9/RenderStates.cpp @@ -32,6 +32,8 @@ #include "core/hle/D3D8/Direct3D9/Direct3D9.h" // For g_pD3DDevice #include "core/hle/D3D8/XbConvert.h" +void SetXboxMultiSampleType(xbox::X_D3DMULTISAMPLE_TYPE value); + bool XboxRenderStateConverter::Init() { if (g_SymbolAddresses.find("D3DDeferredRenderState") != g_SymbolAddresses.end()) { @@ -457,6 +459,9 @@ void XboxRenderStateConverter::ApplyComplexRenderState(uint32_t State, uint32_t case xbox::X_D3DRS_MULTISAMPLEANTIALIAS: case xbox::X_D3DRS_MULTISAMPLEMASK: break; + case xbox::X_D3DRS_MULTISAMPLETYPE: + SetXboxMultiSampleType(Value); + break; default: // Only log missing state if it has a PC counterpart if (RenderStateInfo.PC != 0) { From f42009a27ef165642db234ba0f82fb8c3165213b Mon Sep 17 00:00:00 2001 From: Silent Date: Thu, 8 Oct 2020 21:54:36 +0200 Subject: [PATCH 2/2] Implement MSAA scaling to be closer to Xbox Now scales clears, and applies scaling based on a bound render target. X/Y scale masks now also match the xbox runtime (at least xdk-3911) --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 68 ++++++++++++++--------- src/core/hle/D3D8/XbD3D8Types.h | 4 +- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 969efa21c..06e2bfd94 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -173,6 +173,8 @@ static xbox::X_D3DSurface *g_pXbox_DefaultDepthStencilSurface = xbox:: xbox::X_D3DSurface *g_pXbox_RenderTarget = xbox::zeroptr; static xbox::X_D3DSurface *g_pXbox_DepthStencil = xbox::zeroptr; xbox::X_D3DMULTISAMPLE_TYPE g_Xbox_MultiSampleType = xbox::X_D3DMULTISAMPLE_NONE; +static float g_Xbox_MultiSampleXScale = 1.0f; +static float g_Xbox_MultiSampleYScale = 1.0f; xbox::X_VERTEXSHADERCONSTANTMODE g_Xbox_VertexShaderConstantMode = X_D3DSCM_192CONSTANTS; // Set by D3DDevice_SetShaderConstantMode, TODO : Move to XbVertexShader.cpp static xbox::dword_xt g_Xbox_BaseVertexIndex = 0; // Set by D3DDevice_SetIndices, read by D3DDevice_DrawIndexedVertices : a value that's effectively added to every vertex index (as stored in an index buffer) by multiplying this by vertex stride and added to the vertex buffer start (see BaseVertexIndex in CxbxDrawIndexed) @@ -2995,15 +2997,10 @@ static inline void GetMultiSampleOffset(float& xOffset, float& yOffset) xOffset = yOffset = GetMultiSampleOffsetDelta(); } -static inline void GetMultiSampleScale(float& xScale, float& yScale) -{ - xScale = (float)CXBX_D3DMULTISAMPLE_XSCALE(g_Xbox_MultiSampleType); - yScale = (float)CXBX_D3DMULTISAMPLE_YSCALE(g_Xbox_MultiSampleType); -} - void GetMultiSampleOffsetAndScale(float& xScale, float& yScale, float& xOffset, float& yOffset) { - GetMultiSampleScale(xScale, yScale); + xScale = g_Xbox_MultiSampleXScale; + yScale = g_Xbox_MultiSampleYScale; GetMultiSampleOffset(xOffset, yOffset); } @@ -3016,10 +3013,8 @@ static void ApplyXboxMultiSampleOffset(float& x, float& y) static void ApplyXboxMultiSampleScale(float& x, float& y) { - float xs, ys; - GetMultiSampleScale(xs, ys); - x *= xs; - y *= ys; + x *= g_Xbox_MultiSampleXScale; + y *= g_Xbox_MultiSampleYScale; } void ApplyXboxMultiSampleOffsetAndScale(float& x, float& y) @@ -3028,6 +3023,30 @@ void ApplyXboxMultiSampleOffsetAndScale(float& x, float& y) ApplyXboxMultiSampleOffset(x, y); } +void CalculateMultiSampleScaleForRenderTarget(xbox::X_D3DSurface* renderTarget) +{ + float xScale = 1.0f; + float yScale = 1.0f; + if (renderTarget == g_pXbox_BackBufferSurface && (g_Xbox_MultiSampleType & xbox::X_D3DMULTISAMPLE_SAMPLING_MASK) != 0) { + xScale = static_cast(CXBX_D3DMULTISAMPLE_XSCALE(g_Xbox_MultiSampleType)); + yScale = static_cast(CXBX_D3DMULTISAMPLE_YSCALE(g_Xbox_MultiSampleType)); + if (xScale > 3.0f || yScale > 3.0f) { + // No games known to do this, but XSCALE and YSCALE masks technically allow for it + LOG_TEST_CASE("g_Xbox_MultiSampleXScale or g_Xbox_MultiSampleYScale over 3"); + } + // TODO: Buffers should not be upscaled when using multisampling + /*if ((g_Xbox_MultiSampleType & xbox::X_D3DMULTISAMPLE_SAMPLING_MULTI) != 0) { + xScale /= 2.0f; + if (yScale > 1.0f) { + yScale /= 2.0f; + } + }*/ + } + + g_Xbox_MultiSampleXScale = xScale; + g_Xbox_MultiSampleYScale = yScale; +} + void Direct3D_CreateDevice_Start ( xbox::X_D3DPRESENT_PARAMETERS *pPresentationParameters @@ -3971,8 +3990,8 @@ void GetViewPortOffsetAndScale(float (&vOffset)[4], float(&vScale)[4]) // Since Width and Height are DWORD, subtracting MultiSampleOffset 0.0f or 0.5f makes no sense //ViewPort.Width -= xOffset; //ViewPort.Height -= yOffset; - ViewPort.Width /= (DWORD)xScale; - ViewPort.Height /= (DWORD)yScale; + ViewPort.Width = static_cast(ViewPort.Width / xScale); + ViewPort.Height = static_cast(ViewPort.Height / yScale); // Calculate Width/Height scale & offset float scaleWidth = (2.0f / ViewPort.Width) * g_RenderScaleFactor; @@ -4101,10 +4120,8 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetViewport) } // Apply MSAA scale and offset - float xScale, yScale; - GetMultiSampleScale(xScale, yScale); - HostViewPort.Width *= (DWORD)xScale; - HostViewPort.Height *= (DWORD)yScale; + HostViewPort.Width = static_cast(HostViewPort.Width * g_Xbox_MultiSampleXScale); + HostViewPort.Height = static_cast(HostViewPort.Height * g_Xbox_MultiSampleYScale); // Since Width and Height are DWORD, adding GetMultiSampleOffset 0.0f or 0.5f makes no sense HRESULT hRet = g_pD3DDevice->SetViewport(&HostViewPort); @@ -4984,12 +5001,12 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_Clear) HRESULT hRet; if (pRects != nullptr) { - // Scale the fill based on our scale factor - D3DRECT rect = *pRects; - rect.x1 *= g_RenderScaleFactor; - rect.x2 *= g_RenderScaleFactor; - rect.y1 *= g_RenderScaleFactor; - rect.y2 *= g_RenderScaleFactor; + // Scale the fill based on our scale factor and MSAA scale + D3DRECT rect; + rect.x1 = static_cast(pRects->x1 * g_Xbox_MultiSampleXScale * g_RenderScaleFactor); + rect.x2 = static_cast(pRects->x2 * g_Xbox_MultiSampleXScale * g_RenderScaleFactor); + rect.y1 = static_cast(pRects->y1 * g_Xbox_MultiSampleYScale * g_RenderScaleFactor); + rect.y2 = static_cast(pRects->y2 * g_Xbox_MultiSampleYScale * g_RenderScaleFactor); hRet = g_pD3DDevice->Clear(Count, &rect, HostFlags, Color, Z, Stencil); } else { hRet = g_pD3DDevice->Clear(Count, pRects, HostFlags, Color, Z, Stencil); @@ -5280,8 +5297,8 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(D3DDevice_Swap) DWORD XboxBackBufferHeight = GetPixelContainerHeight(g_pXbox_BackBufferSurface); // We also need to account for any MSAA which may have enlarged the Xbox Backbuffer - float xScale, yScale; - GetMultiSampleScale(xScale, yScale); + float xScale = g_Xbox_MultiSampleXScale; + float yScale = g_Xbox_MultiSampleYScale; xScale = (float)width / ((float)XboxBackBufferWidth / xScale); yScale = (float)height / ((float)XboxBackBufferHeight / yScale); @@ -7801,6 +7818,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_SetRenderTarget) } UpdateViewPortOffsetAndScaleConstants(); + CalculateMultiSampleScaleForRenderTarget(pRenderTarget); } // LTCG specific D3DDevice_SetPalette function... diff --git a/src/core/hle/D3D8/XbD3D8Types.h b/src/core/hle/D3D8/XbD3D8Types.h index b66aadeb0..d820763fb 100644 --- a/src/core/hle/D3D8/XbD3D8Types.h +++ b/src/core/hle/D3D8/XbD3D8Types.h @@ -480,10 +480,10 @@ const int X_D3DMULTISAMPLE_9_SAMPLES_MULTISAMPLE_GAUSSIAN = 0x1233; const int X_D3DMULTISAMPLE_9_SAMPLES_SUPERSAMPLE_GAUSSIAN = 0x2233; // Multisample masks (Cxbx additions) -const int X_D3DMULTISAMPLE_YSCALE_MASK = 0x0003; +const int X_D3DMULTISAMPLE_YSCALE_MASK = 0x000F; const int X_D3DMULTISAMPLE_YSCALE_SHIFT = 0; -const int X_D3DMULTISAMPLE_XSCALE_MASK = 0x0030; +const int X_D3DMULTISAMPLE_XSCALE_MASK = 0x00F0; const int X_D3DMULTISAMPLE_XSCALE_SHIFT = 4; const int X_D3DMULTISAMPLE_ALGO_LINEAR = 0x0000;