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.bSupportsDynamicVertexLoader = false;
g_Config.backend_info.bSupportsHDROutput = true; g_Config.backend_info.bSupportsHDROutput = true;
g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false;
g_Config.backend_info.bSupportsDepthClampControl = false;
g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames();
g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); 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.bSupportsVSLinePointExpand = true;
g_Config.backend_info.bSupportsHDROutput = true; g_Config.backend_info.bSupportsHDROutput = true;
g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false;
g_Config.backend_info.bSupportsDepthClampControl = false;
// We can only check texture support once we have a device. // We can only check texture support once we have a device.
if (g_dx_context) if (g_dx_context)

View File

@ -80,6 +80,7 @@ void Metal::Util::PopulateBackendInfo(VideoConfig* config)
config->backend_info.bSupportsHDROutput = config->backend_info.bSupportsHDROutput =
1.0 < [[NSScreen deepestScreen] maximumPotentialExtendedDynamicRangeColorComponentValue]; 1.0 < [[NSScreen deepestScreen] maximumPotentialExtendedDynamicRangeColorComponentValue];
config->backend_info.bSupportsUnrestrictedDepthRange = false; config->backend_info.bSupportsUnrestrictedDepthRange = false;
config->backend_info.bSupportsDepthClampControl = false;
} }
void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config, 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.bSupportsPartialMultisampleResolve = true;
g_Config.backend_info.bSupportsDynamicVertexLoader = false; g_Config.backend_info.bSupportsDynamicVertexLoader = false;
g_Config.backend_info.bSupportsUnrestrictedDepthRange = false; g_Config.backend_info.bSupportsUnrestrictedDepthRange = false;
g_Config.backend_info.bSupportsDepthClampControl = false;
// aamodes: We only support 1 sample, so no MSAA // aamodes: We only support 1 sample, so no MSAA
g_Config.backend_info.Adapters.clear(); g_Config.backend_info.Adapters.clear();

View File

@ -136,6 +136,7 @@ bool VideoBackend::FillBackendInfo(GLContext* context)
// Unneccessary since OGL doesn't use pipelines // Unneccessary since OGL doesn't use pipelines
g_Config.backend_info.bSupportsDynamicVertexLoader = false; g_Config.backend_info.bSupportsDynamicVertexLoader = false;
g_Config.backend_info.bSupportsUnrestrictedDepthRange = 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 // 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 // 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.bSupportsVSLinePointExpand = true; // Assumed support.
config->backend_info.bSupportsHDROutput = true; // Assumed support. config->backend_info.bSupportsHDROutput = true; // Assumed support.
config->backend_info.bSupportsUnrestrictedDepthRange = false; // Dependent on features. 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) 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_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
AddExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false); AddExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
// Enabling the depth clamp control extension is harmless, but we need to ensure g_Config.backend_info.bSupportsUnrestrictedDepthRange = AddExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, false);
// we don't enable the unrestricted depth range extension unless we can actually if (g_Config.backend_info.bSupportsUnrestrictedDepthRange)
// make use of it. g_Config.backend_info.bSupportsDepthClampControl = AddExtension(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME, false);
g_Config.backend_info.bSupportsUnrestrictedDepthRange =
AddExtension(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME, false) &&
AddExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, false);
return true; return true;
} }

View File

@ -215,17 +215,12 @@ void SetScissorAndViewport()
y += height; y += height;
height *= -1; 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. // 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 // 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 // floating-point round-trip errors. However the console GPU doesn't ever write a value
// to the depth buffer that exceeds 2^24 - 1. // 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) if (!g_ActiveConfig.backend_info.bSupportsDepthClamp)
{ {
// There's no way to support oversized depth ranges in this situation. Let's just clamp the // 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; float near_depth, far_depth;
if (g_ActiveConfig.backend_info.bSupportsReversedDepthRange) 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. // 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 // 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 // depth value will still be clamped to the 0..2^24-1 range, so these games effectively add a
// bias to the values written to the depth buffer. // 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 (host_config.backend_unrestricted_depth_range)
{ {
// If an unrestricted depth range is supported then we let host driver handle the oversized // If we don't use normalization then we can add a small depth bias to influence rounding
// depth range. This can only work if the host driver also supports a feature to allow us to // behaviour since the console expects the depth value to be truncated before being added
// clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. // to the far value of the depth range.
// On top of that we also get rid of any normalization to further avoid rounding errors. out.Write("o.pos.z += (0.5 / 16777216.0);\n");
//
// 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 (!host_config.backend_clip_control) 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. // 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 // 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 // depth value will still be clamped to the 0..2^24-1 range, so these games effectively add a
// bias to the values written to the depth buffer. // 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 (host_config.backend_unrestricted_depth_range)
{ {
// If an unrestricted depth range is supported then we let host driver handle the oversized // If we don't use normalization then we can add a small depth bias to influence rounding
// depth range. This can only work if the host driver also supports a feature to allow us to // behaviour since the console expects the depth value to be truncated before being added
// clamp any depth values that are beyond the supported 0..2^24-1 of the depth buffer. // to the far value of the depth range.
// On top of that we also get rid of any normalization to further avoid rounding errors. out.Write("o.pos.z += (0.5 / 16777216.0);\n");
//
// 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 (!host_config.backend_clip_control) if (!host_config.backend_clip_control)

View File

@ -140,7 +140,7 @@ void VertexShaderManager::SetProjectionMatrix(XFStateManager& xf_state_manager)
bool VertexShaderManager::UseVertexDepthRange() bool VertexShaderManager::UseVertexDepthRange()
{ {
// Backend has full native support for the depth range including clamping the depth. // 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; return false;
// We can't compute the depth range in the vertex shader if we don't support depth clamp. // 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 bSupportsGLLayerInFS = true;
bool bSupportsHDROutput = false; bool bSupportsHDROutput = false;
bool bSupportsUnrestrictedDepthRange = false; bool bSupportsUnrestrictedDepthRange = false;
bool bSupportsDepthClampControl = false;
} backend_info; } backend_info;
// Utility // Utility