diff --git a/Source/Core/VideoBackends/D3D/D3DMain.cpp b/Source/Core/VideoBackends/D3D/D3DMain.cpp index 5bb419ac8f..286ec5928e 100644 --- a/Source/Core/VideoBackends/D3D/D3DMain.cpp +++ b/Source/Core/VideoBackends/D3D/D3DMain.cpp @@ -117,6 +117,7 @@ void VideoBackend::FillBackendInfo() g_Config.backend_info.bSupportsDynamicVertexLoader = false; g_Config.backend_info.bSupportsHDROutput = true; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; + g_Config.backend_info.bSupportsDepthClampControl = false; g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp index 13b1a2043d..a5ec46efdd 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp @@ -92,6 +92,7 @@ void VideoBackend::FillBackendInfo() g_Config.backend_info.bSupportsVSLinePointExpand = true; g_Config.backend_info.bSupportsHDROutput = true; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; + g_Config.backend_info.bSupportsDepthClampControl = false; // We can only check texture support once we have a device. if (g_dx_context) diff --git a/Source/Core/VideoBackends/Metal/MTLUtil.mm b/Source/Core/VideoBackends/Metal/MTLUtil.mm index d961725702..ad934490b7 100644 --- a/Source/Core/VideoBackends/Metal/MTLUtil.mm +++ b/Source/Core/VideoBackends/Metal/MTLUtil.mm @@ -80,6 +80,7 @@ void Metal::Util::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsHDROutput = 1.0 < [[NSScreen deepestScreen] maximumPotentialExtendedDynamicRangeColorComponentValue]; config->backend_info.bSupportsUnrestrictedDepthRange = false; + config->backend_info.bSupportsDepthClampControl = false; } void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config, diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 19e178b55b..f48ad02f56 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -64,6 +64,7 @@ void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsDynamicVertexLoader = false; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; + g_Config.backend_info.bSupportsDepthClampControl = false; // aamodes: We only support 1 sample, so no MSAA g_Config.backend_info.Adapters.clear(); diff --git a/Source/Core/VideoBackends/OGL/OGLMain.cpp b/Source/Core/VideoBackends/OGL/OGLMain.cpp index 08dbcf8bd6..0ad1a285f4 100644 --- a/Source/Core/VideoBackends/OGL/OGLMain.cpp +++ b/Source/Core/VideoBackends/OGL/OGLMain.cpp @@ -136,6 +136,7 @@ bool VideoBackend::FillBackendInfo(GLContext* context) // Unneccessary since OGL doesn't use pipelines g_Config.backend_info.bSupportsDynamicVertexLoader = false; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; + g_Config.backend_info.bSupportsDepthClampControl = false; // TODO: There is a bug here, if texel buffers or SSBOs/atomics are not supported the graphics // options will show the option when it is not supported. The only way around this would be diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index d07959e784..d9da0d17e9 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -472,6 +472,7 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsVSLinePointExpand = true; // Assumed support. config->backend_info.bSupportsHDROutput = true; // Assumed support. config->backend_info.bSupportsUnrestrictedDepthRange = false; // Dependent on features. + config->backend_info.bSupportsDepthClampControl = false; // Dependent on features. } void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list) @@ -677,12 +678,9 @@ bool VulkanContext::SelectDeviceExtensions(bool enable_surface) AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); AddExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false); - // Enabling the depth clamp control extension is harmless, but we need to ensure - // we don't enable the unrestricted depth range extension unless we can actually - // make use of it. - g_Config.backend_info.bSupportsUnrestrictedDepthRange = - AddExtension(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME, false) && - AddExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, false); + g_Config.backend_info.bSupportsUnrestrictedDepthRange = AddExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, false); + if (g_Config.backend_info.bSupportsUnrestrictedDepthRange) + g_Config.backend_info.bSupportsDepthClampControl = AddExtension(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME, false); return true; } diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index b9ab7732a0..e4af1dc197 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -215,17 +215,12 @@ void SetScissorAndViewport() y += height; height *= -1; } - if (!g_ActiveConfig.backend_info.bSupportsUnrestrictedDepthRange) - { - min_depth = min_depth / 16777216.0f; - max_depth = max_depth / 16777216.0f; - } // The maximum depth that is written to the depth buffer should never exceed this value. // This is necessary because we use a 2^24 divisor for all our depth values to prevent // floating-point round-trip errors. However the console GPU doesn't ever write a value // to the depth buffer that exceeds 2^24 - 1. - constexpr float GX_MAX_DEPTH = 16777215.0f / 16777216.0f; + constexpr float GX_MAX_DEPTH = 16777215.0f; if (!g_ActiveConfig.backend_info.bSupportsDepthClamp) { // There's no way to support oversized depth ranges in this situation. Let's just clamp the @@ -250,6 +245,12 @@ void SetScissorAndViewport() } } + if (!g_ActiveConfig.backend_info.bSupportsUnrestrictedDepthRange) + { + min_depth /= 16777216.0f; + max_depth /= 16777216.0f; + } + float near_depth, far_depth; if (g_ActiveConfig.backend_info.bSupportsReversedDepthRange) { diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index 2bbfac1e7b..d1668dcfcc 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -432,27 +432,27 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{ // if not then early z culling will improve speed. // // The depth range can also be oversized beyond the range supported by the depth buffer. The final - // depth value will still be clamped to the 0..1 range, so these games effectively add a depth - // bias to the values written to the depth buffer. + // depth value will still be clamped to the 0..2^24-1 range, so these games effectively add a + // depth bias to the values written to the depth buffer. + // + // If an unrestricted depth range is supported then we can let host driver handle the oversized + // depth range. This can only work if the host driver also supports a feature to allow us to + // clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. + // + // If only a depth range of 0..1 is supported then we process the depth equation in the vertex + // shader and handle the depth clamp by setting the depth range to 0..(2^24-1)/(2^24). + // + // If the depth range is not oversized or when we let the host driver handle the oversized depth + // range then the constants in this equation will be set so that z = -z. + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " + "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); + if (host_config.backend_unrestricted_depth_range) { - // If an unrestricted depth range is supported then we let host driver handle the oversized - // depth range. This can only work if the host driver also supports a feature to allow us to - // clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. - // On top of that we also get rid of any normalization to further avoid rounding errors. - // - // Getting rid of the normalization additionally allows us to add a small depth bias to - // influence rounding behaviour since the console expects the depth value to be truncated - // before being added to the far value of the depth range. - out.Write("o.pos.z = -o.pos.z + (0.5 / 16777216.0);\n"); - } - else - { - // If only a depth range of 0..1 is supported then we process the depth equation in the vertex - // shader and handle the depth clamp by setting the depth range to 0..(2^24-1)/(2^24). - // If the depth range is not oversized then this equation will be set to so that z = -z. - out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " - "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); + // If we don't use normalization then we can add a small depth bias to influence rounding + // behaviour since the console expects the depth value to be truncated before being added + // to the far value of the depth range. + out.Write("o.pos.z += (0.5 / 16777216.0);\n"); } if (!host_config.backend_clip_control) diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 1ec11b8cd1..8139804f46 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -618,27 +618,27 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho // if not then early z culling will improve speed. // // The depth range can also be oversized beyond the range supported by the depth buffer. The final - // depth value will still be clamped to the 0..1 range, so these games effectively add a depth - // bias to the values written to the depth buffer. + // depth value will still be clamped to the 0..2^24-1 range, so these games effectively add a + // depth bias to the values written to the depth buffer. + // + // If an unrestricted depth range is supported then we can let host driver handle the oversized + // depth range. This can only work if the host driver also supports a feature to allow us to + // clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. + // + // If only a depth range of 0..1 is supported then we process the depth equation in the vertex + // shader and handle the depth clamp by setting the depth range to 0..(2^24-1)/(2^24). + // + // If the depth range is not oversized or when we let the host driver handle the oversized depth + // range then the constants in this equation will be set so that z = -z. + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " + "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); + if (host_config.backend_unrestricted_depth_range) { - // If an unrestricted depth range is supported then we let host driver handle the oversized - // depth range. This can only work if the host driver also supports a feature to allow us to - // clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. - // On top of that we also get rid of any normalization to further avoid rounding errors. - // - // Getting rid of the normalization additionally allows us to add a small depth bias to - // influence rounding behaviour since the console expects the depth value to be truncated - // before being added to the far value of the depth range. - out.Write("o.pos.z = -o.pos.z + (0.5 / 16777216.0);\n"); - } - else - { - // If only a depth range of 0..1 is supported then we process the depth equation in the vertex - // shader and handle the depth clamp by setting the depth range to 0..(2^24-1)/(2^24). - // If the depth range is not oversized then this equation will be set to so that z = -z. - out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " - "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); + // If we don't use normalization then we can add a small depth bias to influence rounding + // behaviour since the console expects the depth value to be truncated before being added + // to the far value of the depth range. + out.Write("o.pos.z += (0.5 / 16777216.0);\n"); } if (!host_config.backend_clip_control) diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 643220b107..7860d292a3 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -140,7 +140,7 @@ void VertexShaderManager::SetProjectionMatrix(XFStateManager& xf_state_manager) bool VertexShaderManager::UseVertexDepthRange() { // Backend has full native support for the depth range including clamping the depth. - if (g_ActiveConfig.backend_info.bSupportsUnrestrictedDepthRange) + if (g_ActiveConfig.backend_info.bSupportsDepthClampControl) return false; // We can't compute the depth range in the vertex shader if we don't support depth clamp. diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 0b8f189d35..d6cb8fdab0 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -339,6 +339,7 @@ struct VideoConfig final bool bSupportsGLLayerInFS = true; bool bSupportsHDROutput = false; bool bSupportsUnrestrictedDepthRange = false; + bool bSupportsDepthClampControl = false; } backend_info; // Utility