VideoCommon: Always utilize unrestricted depth range to get rid of normalization.

This commit is contained in:
Jules Blok 2024-10-05 14:52:21 +02:00
parent 9f9b1752cb
commit e0fe72bfc0
11 changed files with 56 additions and 51 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -339,6 +339,7 @@ struct VideoConfig final
bool bSupportsGLLayerInFS = true;
bool bSupportsHDROutput = false;
bool bSupportsUnrestrictedDepthRange = false;
bool bSupportsDepthClampControl = false;
} backend_info;
// Utility