Draft: Use a fixed-point depth buffer with an unrestricted depth range.

This commit is contained in:
Jules Blok 2024-10-05 16:25:17 +02:00
commit a1a43d7da4
18 changed files with 67 additions and 44 deletions

View file

@ -75,7 +75,7 @@ void AbstractGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool co
static_cast<float>((color >> 8) & 0xFF) / 255.0f,
static_cast<float>((color >> 0) & 0xFF) / 255.0f,
static_cast<float>((color >> 24) & 0xFF) / 255.0f},
static_cast<float>(z & 0xFFFFFF) / 16777216.0f};
static_cast<float>(z & 0xFFFFFF) / 16777215.0f};
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
uniforms.clear_depth = 1.0f - uniforms.clear_depth;
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));

View file

@ -203,8 +203,8 @@ void SetScissorAndViewport()
float y = g_framebuffer_manager->EFBToScaledYf(raw_y);
float width = g_framebuffer_manager->EFBToScaledXf(raw_width);
float height = g_framebuffer_manager->EFBToScaledYf(raw_height);
float min_depth = (xfmem.viewport.farZ - xfmem.viewport.zRange) / 16777216.0f;
float max_depth = xfmem.viewport.farZ / 16777216.0f;
float min_depth = (xfmem.viewport.farZ / 16777215.0f - xfmem.viewport.zRange / 16777215.0f);
float max_depth = xfmem.viewport.farZ / 16777215.0f;
if (width < 0.f)
{
x += width;
@ -216,17 +216,12 @@ void SetScissorAndViewport()
height *= -1;
}
// 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;
if (!g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
// There's no way to support oversized depth ranges in this situation. Let's just clamp the
// range to the maximum value supported by the console GPU and hope for the best.
min_depth = std::clamp(min_depth, 0.0f, GX_MAX_DEPTH);
max_depth = std::clamp(max_depth, 0.0f, GX_MAX_DEPTH);
min_depth = std::clamp(min_depth, 0.0f, 1.0f);
max_depth = std::clamp(max_depth, 0.0f, 1.0f);
}
if (VertexShaderManager::UseVertexDepthRange())
@ -235,13 +230,13 @@ void SetScissorAndViewport()
// Taking into account whether the depth range is inverted or not.
if (xfmem.viewport.zRange < 0.0f && g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
{
min_depth = GX_MAX_DEPTH;
min_depth = 1.0f;
max_depth = 0.0f;
}
else
{
min_depth = 0.0f;
max_depth = GX_MAX_DEPTH;
max_depth = 1.0f;
}
}

View file

@ -131,13 +131,7 @@ AbstractTextureFormat FramebufferManager::GetEFBColorFormat()
AbstractTextureFormat FramebufferManager::GetEFBDepthFormat()
{
// 32-bit depth clears are broken in the Adreno Vulkan driver, and have no effect.
// To work around this, we use a D24_S8 buffer instead, which results in a loss of accuracy.
// We still resolve this to a R32F texture, as there is no 24-bit format.
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_D32F_CLEAR))
return AbstractTextureFormat::D24_S8;
else
return AbstractTextureFormat::D32F;
return AbstractTextureFormat::D24_S8;
}
AbstractTextureFormat FramebufferManager::GetEFBDepthCopyFormat()

View file

@ -1261,9 +1261,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
else
{
if (!host_config.backend_reversed_depth_range)
out.Write("\tint zCoord = int((1.0 - rawpos.z) * 16777216.0);\n");
out.Write("\tint zCoord = int((1.0 - rawpos.z) * 16777215.0);\n");
else
out.Write("\tint zCoord = int(rawpos.z * 16777216.0);\n");
out.Write("\tint zCoord = int(rawpos.z * 16777215.0);\n");
}
out.Write("\tzCoord = clamp(zCoord, 0, 0xFFFFFF);\n");
@ -1278,9 +1278,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
if (uid_data->per_pixel_depth && early_ztest)
{
if (!host_config.backend_reversed_depth_range)
out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n");
out.Write("\tdepth = 1.0 - float(zCoord) / 16777215.0;\n");
else
out.Write("\tdepth = float(zCoord) / 16777216.0;\n");
out.Write("\tdepth = float(zCoord) / 16777215.0;\n");
}
// Note: depth texture output is only written to depth buffer if late depth test is used
@ -1299,9 +1299,9 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
if (uid_data->per_pixel_depth && uid_data->ztest == EmulatedZ::Late)
{
if (!host_config.backend_reversed_depth_range)
out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n");
out.Write("\tdepth = 1.0 - float(zCoord) / 16777215.0;\n");
else
out.Write("\tdepth = float(zCoord) / 16777216.0;\n");
out.Write("\tdepth = float(zCoord) / 16777215.0;\n");
}
// No dithering for RGB8 mode
@ -1977,14 +1977,14 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data)
// renderer)
// Maybe we want to use "ze = (A << B_SHF)/((B << B_SHF) - Zs)" instead?
// That's equivalent, but keeps the lower bits of Zs.
out.Write("\tfloat ze = (" I_FOGF ".x * 16777216.0) / float(" I_FOGI ".y - (zCoord >> " I_FOGI
out.Write("\tfloat ze = (" I_FOGF ".x * 16777215.0) / float(" I_FOGI ".y - (zCoord >> " I_FOGI
".w));\n");
}
else
{
// orthographic
// ze = a*Zs (here, no B_SHF)
out.Write("\tfloat ze = " I_FOGF ".x * float(zCoord) / 16777216.0;\n");
out.Write("\tfloat ze = " I_FOGF ".x * float(zCoord) / 16777215.0;\n");
}
// x_adjust = sqrt((x-center)^2 + k^2)/k

View file

@ -127,7 +127,7 @@ static void WriteSampleFunction(ShaderCode& code, const EFBCopyParams& params, A
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
code.Write(" tex_sample.x = 1.0 - tex_sample.x;\n");
code.Write(" uint depth = uint(tex_sample.x * 16777216.0);\n"
code.Write(" uint depth = uint(tex_sample.x * 16777215.0);\n"
" return uint4((depth >> 16) & 255u, (depth >> 8) & 255u, depth & 255u, 255u);\n"
"}}\n");
}

View file

@ -113,7 +113,7 @@ ShaderCode GeneratePixelShader(APIType api_type, const UidData* uid_data)
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
out.Write(" tex_sample.x = 1.0 - tex_sample.x;\n");
out.Write(" uint depth = uint(tex_sample.x * 16777216.0);\n"
out.Write(" uint depth = uint(tex_sample.x * 16777215.0);\n"
" return uint4((depth >> 16) & 255u, (depth >> 8) & 255u, depth & 255u, 255u);\n"
"}}\n");
}

View file

@ -1327,9 +1327,9 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
if (host_config.fast_depth_calc)
{
if (!host_config.backend_reversed_depth_range)
out.Write(" int zCoord = int((1.0 - rawpos.z) * 16777216.0);\n");
out.Write(" int zCoord = int((1.0 - rawpos.z) * 16777215.0);\n");
else
out.Write(" int zCoord = int(rawpos.z * 16777216.0);\n");
out.Write(" int zCoord = int(rawpos.z * 16777215.0);\n");
out.Write(" zCoord = clamp(zCoord, 0, 0xFFFFFF);\n"
"\n");
}
@ -1383,9 +1383,9 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" // If early depth isn't enabled, we write to the zbuffer here\n"
" int zbuffer_zCoord = bpmem_late_ztest ? zCoord : early_zCoord;\n");
if (!host_config.backend_reversed_depth_range)
out.Write(" depth = 1.0 - float(zbuffer_zCoord) / 16777216.0;\n");
out.Write(" depth = 1.0 - float(zbuffer_zCoord) / 16777215.0;\n");
else
out.Write(" depth = float(zbuffer_zCoord) / 16777216.0;\n");
out.Write(" depth = float(zbuffer_zCoord) / 16777215.0;\n");
}
out.Write(" // Alpha Test\n");
@ -1454,12 +1454,12 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
BitfieldExtract<&FogParam3::proj>("bpmem_fogParam3"));
out.Write(" // perspective\n"
" // ze = A/(B - (Zs >> B_SHF)\n"
" ze = (" I_FOGF ".x * 16777216.0) / float(" I_FOGI ".y - (zCoord >> " I_FOGI
" ze = (" I_FOGF ".x * 16777215.0) / float(" I_FOGI ".y - (zCoord >> " I_FOGI
".w));\n"
" }} else {{\n"
" // orthographic\n"
" // ze = a*Zs (here, no B_SHF)\n"
" ze = " I_FOGF ".x * float(zCoord) / 16777216.0;\n"
" ze = " I_FOGF ".x * float(zCoord) / 16777215.0;\n"
" }}\n"
"\n"
" if (bool({})) {{\n",

View file

@ -139,6 +139,9 @@ void VertexShaderManager::SetProjectionMatrix(XFStateManager& xf_state_manager)
bool VertexShaderManager::UseVertexDepthRange()
{
if (g_Config.backend_info.bSupportsUnrestrictedDepthRange)
return false;
// We can't compute the depth range in the vertex shader if we don't support depth clamp.
if (!g_ActiveConfig.backend_info.bSupportsDepthClamp)
return false;

View file

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