From 2ab6711f43d77d987850a782f5ef88cb9996e399 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Tue, 27 Dec 2016 14:26:11 +0100 Subject: [PATCH] VideoBackends: Use the full depth range when inverted depth range is unsupported. --- Source/Core/VideoBackends/D3D/Render.cpp | 15 ++++++++------- Source/Core/VideoBackends/D3D12/Render.cpp | 15 ++++++++------- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 13 ++++++++----- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 1877fde9d7..35fd561e5e 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -573,10 +573,13 @@ void Renderer::SetViewport() Y += Ht; Ht = -Ht; } + + // If an inverted depth range is used, which D3D doesn't support, + // we need to calculate the depth range in the vertex shader. if (xfmem.viewport.zRange < 0.0f) { - min_depth = 1.0f - min_depth; - max_depth = 1.0f - max_depth; + min_depth = 0.0f; + max_depth = GX_MAX_DEPTH; } // In D3D, the viewport rectangle must fit within the render target. @@ -585,11 +588,9 @@ void Renderer::SetViewport() Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); - // We do depth clipping and depth range in the vertex shader instead of relying - // on the graphics API. However we still need to ensure depth values don't exceed - // the maximum value supported by the console GPU. We also need to account for the - // fact that the entire depth buffer is inverted on D3D, so we set GX_MAX_DEPTH as - // an inverted near value. + // We use an inverted depth range here to apply the Reverse Z trick. + // This trick makes sure we match the precision provided by the 1:0 + // clipping depth range on the hardware. D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, 1.0f - max_depth, 1.0f - min_depth); D3D::context->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index ce22583c68..2b8e204ee2 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -478,10 +478,13 @@ void Renderer::SetViewport() y += height; height = -height; } + + // If an inverted depth range is used, which D3D doesn't support, + // we need to calculate the depth range in the vertex shader. if (xfmem.viewport.zRange < 0.0f) { - min_depth = 1.0f - min_depth; - max_depth = 1.0f - max_depth; + min_depth = 0.0f; + max_depth = GX_MAX_DEPTH; } // In D3D, the viewport rectangle must fit within the render target. @@ -490,11 +493,9 @@ void Renderer::SetViewport() width = (x + width <= GetTargetWidth()) ? width : (GetTargetWidth() - x); height = (y + height <= GetTargetHeight()) ? height : (GetTargetHeight() - y); - // We do depth clipping and depth range in the vertex shader instead of relying - // on the graphics API. However we still need to ensure depth values don't exceed - // the maximum value supported by the console GPU. We also need to account for the - // fact that the entire depth buffer is inverted on D3D, so we set GX_MAX_DEPTH as - // an inverted near value. + // We use an inverted depth range here to apply the Reverse Z trick. + // This trick makes sure we match the precision provided by the 1:0 + // clipping depth range on the hardware. D3D12_VIEWPORT vp = {x, y, width, height, 1.0f - max_depth, 1.0f - min_depth}; D3D::current_command_list->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index a375d89012..43d3f5e280 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -1649,15 +1649,18 @@ void Renderer::SetViewport() y += height; height = -height; } + + // If an inverted depth range is used, which D3D doesn't support, + // we need to calculate the depth range in the vertex shader. if (xfmem.viewport.zRange < 0.0f) { - min_depth = 1.0f - min_depth; - max_depth = 1.0f - max_depth; + min_depth = 0.0f; + max_depth = GX_MAX_DEPTH; } - // If we do depth clipping and depth range in the vertex shader we only need to ensure - // depth values don't exceed the maximum value supported by the console GPU. If not, - // we simply clamp the near/far values themselves to the maximum value as done above. + // We use an inverted depth range here to apply the Reverse Z trick. + // This trick makes sure we match the precision provided by the 1:0 + // clipping depth range on the hardware. VkViewport viewport = {x, y, width, height, 1.0f - max_depth, 1.0f - min_depth}; StateTracker::GetInstance()->SetViewport(viewport); }