From 7b0a31ade539f9e1e90801cf79a2b12deb5d2e00 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 29 Aug 2015 17:43:09 +0200 Subject: [PATCH] Adjust D3D depth calculations to get them to match OpenGL as close as I can get it. --- GPU/Directx9/ShaderManagerDX9.cpp | 13 ++++++++++--- GPU/Directx9/StateMappingDX9.cpp | 8 +++++--- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 2 ++ GPU/GLES/ShaderManager.cpp | 5 ++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 98fb0df3b..8874b325c 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -482,14 +482,21 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) { if (dirtyUniforms & DIRTY_DEPTHRANGE) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); - float viewZCenterClean = gstate.getViewportZCenter(); + + // Adjust for D3D projection matrix. We got squashed up to only 0-1, so we multiply + // the scale factor by 2, and add an offset. + // Given the way we do the rounding, the offset is probably mostly irrelevant as we cancel + // it afterwards anyway. + viewZScale *= 2.0f; + viewZCenter -= 32768.0f; float viewZInvScale; if (viewZScale != 0.0) { - viewZInvScale = 1.0f / gstate.getViewportZScale(); + viewZInvScale = 1.0f / viewZScale; } else { viewZInvScale = 0.0; } - float data[4] = { viewZScale, viewZCenter, viewZCenterClean, viewZInvScale }; + + float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale }; VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data); } // Lighting diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 65aefcc29..f67f05d69 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -745,10 +745,12 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) { float zScale = gstate.getViewportZScale() / 65535.0f; float zCenter = gstate.getViewportZCenter() / 65535.0f; - // Note - we lose the sign of the zscale here. Although I suppose we still keep it in gstate_c.vpDepth... - float depthRangeMin = zCenter - fabsf(zScale); - float depthRangeMax = zCenter + fabsf(zScale); + // Note - We lose the sign of the zscale here. But we keep it in gstate_c.vpDepth. + // That variable is only check for sign later so the multiplication by 2 isn't really necessary. + // It's unclear why we need this Z offset of 1 to match OpenGL, but this checks out in multiple games. + float depthRangeMin = zCenter - fabsf(zScale) - 1.0f/65535.0f; + float depthRangeMax = zCenter + fabsf(zScale) - 1.0f/65535.0f; gstate_c.vpDepth = zScale * 2; // D3D doesn't like viewports partially outside the target, so we diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 12acdfe0d..dba65ed8c 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -284,6 +284,8 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) { } WRITE(p, "};\n"); + // Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene. + if (!gstate.isModeThrough()) { // Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection. // Not completely sure this is 100% right under DX9 as the Z range is different... diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index d8e592669..3216572d4 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -592,14 +592,13 @@ void LinkedShader::UpdateUniforms(u32 vertType) { if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); - float viewZCenterClean = gstate.getViewportZCenter(); float viewZInvScale; if (viewZScale != 0.0) { - viewZInvScale = 1.0f / gstate.getViewportZScale(); + viewZInvScale = 1.0f / viewZScale; } else { viewZInvScale = 0.0; } - float data[4] = { viewZScale, viewZCenter, viewZCenterClean, viewZInvScale }; + float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale }; SetFloatUniform4(u_depthRange, data); }