From 0920f6c6eb848267752b73bdf2194015bc47850d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2016 20:26:31 -0800 Subject: [PATCH] Use minz/maxz as the depth range. This allows values that fall outside the viewport, but still within the depth range, to be drawn. --- GPU/Common/GPUStateUtils.cpp | 45 +++++++++---------------------- GPU/Directx9/ShaderManagerDX9.cpp | 23 +++++----------- GPU/GLES/ShaderManager.cpp | 23 +++++----------- 3 files changed, 26 insertions(+), 65 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 7c9a3675f4..c8647febfd 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -597,8 +597,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo float xOffset = 0.0f; float hScale = 1.0f; float yOffset = 0.0f; - float zScale = 1.0f; - float zOffset = 0.0f; // If we're within the bounds, we want clipping the viewport way. So leave it be. if (left < 0.0f || right > renderWidth) { @@ -632,29 +630,22 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.viewportW = right - left; out.viewportH = bottom - top; + // The depth viewport parameters are the same, but we handle it a bit differently. + // When clipping is enabled, depth is clamped to [0, 65535]. And minz/maxz discard. + // So, we apply the depth range as minz/maxz, and transform for the viewport. float vpZScale = gstate.getViewportZScale(); float vpZCenter = gstate.getViewportZCenter(); - // Near/far can be inverted. We deal with that in the projection/scale. - float near = vpZCenter - fabsf(vpZScale); - float far = vpZCenter + fabsf(vpZScale); + float minz = gstate.getDepthRangeMin(); + float maxz = gstate.getDepthRangeMax(); - if (near < 0.0f || far > 65535.0f) { - float overageNear = std::max(-near, 0.0f); - float overageFar = std::max(far - 65535.0f, 0.0f); - float drift = overageFar - overageNear; + // Okay. So, in our shader, -1 will map to minz, and +1 will map to maxz. + float halfActualZRange = (maxz - minz) * (1.0f / 2.0f); + float zScale = vpZScale / halfActualZRange; + // This adjusts the center from halfActualZRange to vpZCenter. + float zOffset = (vpZCenter - (minz + halfActualZRange)) / halfActualZRange; - near += overageNear; - far -= overageFar; - - zScale = (vpZScale * 2.0f) / (far - near); - zOffset = drift / (far - near); - } else if (vpZScale < 0.0f) { - // This flips to match our near/far. - zScale = -zScale; - } - - out.depthRangeMin = near * (1.0f / 65535.0f); - out.depthRangeMax = far * (1.0f / 65535.0f); + out.depthRangeMin = ToScaledDepth(minz); + out.depthRangeMax = ToScaledDepth(maxz); bool scaleChanged = gstate_c.vpWidthScale != wScale || gstate_c.vpHeightScale != hScale; bool offsetChanged = gstate_c.vpXOffset != xOffset || gstate_c.vpYOffset != yOffset; @@ -669,18 +660,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo out.dirtyProj = true; out.dirtyDepth = depthChanged; } - -#ifndef MOBILE_DEVICE - float minz = gstate.getDepthRangeMin(); - float maxz = gstate.getDepthRangeMax(); - if (minz > near || maxz < far) { - if ((gstate.clipEnable & 1) == 0) { - WARN_LOG_REPORT_ONCE(minmaxznoclip, G3D, "Unsupported depth range test without clipping - clip: %f-%f, test: %f-%f", near, far, minz, maxz); - } else { - WARN_LOG_REPORT_ONCE(minmaxz, G3D, "Unsupported depth range test - clip: %f-%f, test: %f-%f", near, far, minz, maxz); - } - } -#endif } } diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 95b0256c72..fe5c041982 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -480,23 +480,14 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) { } if (dirtyUniforms & DIRTY_DEPTHRANGE) { - float viewZScale = gstate.getViewportZScale(); - float viewZCenter = gstate.getViewportZCenter(); - float viewZInvScale; + // Depth is [0, 1] mapping to [minz, maxz], not too hard. + float minz = gstate.getDepthRangeMin(); + float maxz = gstate.getDepthRangeMax(); - // We had to scale and translate Z to account for our clamped Z range. - // Therefore, we also need to reverse this to round properly. - // - // Example: scale = 65535.0, center = 0.0 - // Resulting range = -65535 to 65535, clamped to [0, 65535] - // gstate_c.vpDepthScale = 2.0f - // gstate_c.vpZOffset = -1.0f - // - // The projection already accounts for those, so we need to reverse them. - // - // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. - viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; - viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; + float actualZRange = maxz - minz; + float viewZScale = actualZRange; + float viewZCenter = minz; + float viewZInvScale; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale; diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index 7676d53ed8..a0543cc21d 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -589,23 +589,14 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { SetMatrix4x3(u_texmtx, gstate.tgenMatrix); } if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) { - float viewZScale = gstate.getViewportZScale(); - float viewZCenter = gstate.getViewportZCenter(); - float viewZInvScale; + // Since depth is [-1, 1] mapping to [minz, maxz], this is easy. + float minz = gstate.getDepthRangeMin(); + float maxz = gstate.getDepthRangeMax(); - // We had to scale and translate Z to account for our clamped Z range. - // Therefore, we also need to reverse this to round properly. - // - // Example: scale = 65535.0, center = 0.0 - // Resulting range = -65535 to 65535, clamped to [0, 65535] - // gstate_c.vpDepthScale = 2.0f - // gstate_c.vpZOffset = -1.0f - // - // The projection already accounts for those, so we need to reverse them. - // - // Additionally, OpenGL uses a range from [-1, 1]. So we multiply by scale and add the center. - viewZScale *= 1.0f / gstate_c.vpDepthScale; - viewZCenter -= 65535.0f * gstate_c.vpZOffset; + float halfActualZRange = (maxz - minz) * (1.0f / 2.0f); + float viewZScale = halfActualZRange; + float viewZCenter = minz + halfActualZRange; + float viewZInvScale; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale;