VideoCommon: Don't process the depth range in the vertex shader if it's not oversized.

This commit is contained in:
Jules Blok 2016-11-23 23:25:44 +01:00
parent 8e506cb974
commit ef82aebb97
6 changed files with 48 additions and 44 deletions

View File

@ -559,6 +559,10 @@ void Renderer::SetViewport()
float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff); float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff);
float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd);
float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht);
float range = MathUtil::Clamp<float>(xfmem.viewport.zRange, 0.0f, 16777216.0f);
float min_depth =
MathUtil::Clamp<float>(xfmem.viewport.farZ - range, 0.0f, 16777215.0f) / 16777216.0f;
float max_depth = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
if (Wd < 0.0f) if (Wd < 0.0f)
{ {
X += Wd; X += Wd;
@ -569,6 +573,11 @@ void Renderer::SetViewport()
Y += Ht; Y += Ht;
Ht = -Ht; Ht = -Ht;
} }
if (xfmem.viewport.zRange < 0.0f)
{
min_depth = 1.0f - min_depth;
max_depth = 1.0f - max_depth;
}
// In D3D, the viewport rectangle must fit within the render target. // In D3D, the viewport rectangle must fit within the render target.
X = (X >= 0.f) ? X : 0.f; X = (X >= 0.f) ? X : 0.f;
@ -581,7 +590,7 @@ void Renderer::SetViewport()
// the maximum value supported by the console GPU. We also need to account for the // 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 // fact that the entire depth buffer is inverted on D3D, so we set GX_MAX_DEPTH as
// an inverted near value. // an inverted near value.
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, 1.0f - GX_MAX_DEPTH, D3D11_MAX_DEPTH); D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, 1.0f - max_depth, 1.0f - min_depth);
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
} }

View File

@ -464,6 +464,10 @@ void Renderer::SetViewport()
float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset); float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset);
float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd);
float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht);
float range = MathUtil::Clamp<float>(xfmem.viewport.zRange, 0.0f, 16777216.0f);
float min_depth =
MathUtil::Clamp<float>(xfmem.viewport.farZ - range, 0.0f, 16777215.0f) / 16777216.0f;
float max_depth = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
if (width < 0.0f) if (width < 0.0f)
{ {
x += width; x += width;
@ -474,6 +478,11 @@ void Renderer::SetViewport()
y += height; y += height;
height = -height; height = -height;
} }
if (xfmem.viewport.zRange < 0.0f)
{
min_depth = 1.0f - min_depth;
max_depth = 1.0f - max_depth;
}
// In D3D, the viewport rectangle must fit within the render target. // In D3D, the viewport rectangle must fit within the render target.
x = (x >= 0.f) ? x : 0.f; x = (x >= 0.f) ? x : 0.f;
@ -486,7 +495,7 @@ void Renderer::SetViewport()
// the maximum value supported by the console GPU. We also need to account for the // 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 // fact that the entire depth buffer is inverted on D3D, so we set GX_MAX_DEPTH as
// an inverted near value. // an inverted near value.
D3D12_VIEWPORT vp = {x, y, width, height, 1.0f - GX_MAX_DEPTH, D3D12_MAX_DEPTH}; D3D12_VIEWPORT vp = {x, y, width, height, 1.0f - max_depth, 1.0f - min_depth};
D3D::current_command_list->RSSetViewports(1, &vp); D3D::current_command_list->RSSetViewports(1, &vp);
} }

View File

@ -1122,12 +1122,10 @@ void Renderer::SetViewport()
(float)scissorYOff); (float)scissorYOff);
float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd); float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd);
float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht); float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht);
float GLNear = MathUtil::Clamp<float>( float range = MathUtil::Clamp<float>(xfmem.viewport.zRange, -16777216.0f, 16777216.0f);
xfmem.viewport.farZ - float min_depth =
MathUtil::Clamp<float>(xfmem.viewport.zRange, -16777216.0f, 16777216.0f), MathUtil::Clamp<float>(xfmem.viewport.farZ - range, 0.0f, 16777215.0f) / 16777216.0f;
0.0f, 16777215.0f) / float max_depth = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
16777216.0f;
float GLFar = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
if (Width < 0) if (Width < 0)
{ {
X += Width; X += Width;
@ -1154,17 +1152,7 @@ void Renderer::SetViewport()
// vertex shader we only need to ensure depth values don't exceed the maximum // 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 // value supported by the console GPU. If not, we simply clamp the near/far values
// themselves to the maximum value as done above. // themselves to the maximum value as done above.
if (g_ActiveConfig.backend_info.bSupportsDepthClamp) glDepthRangef(max_depth, min_depth);
{
if (xfmem.viewport.zRange < 0.0f)
glDepthRangef(0.0f, GX_MAX_DEPTH);
else
glDepthRangef(GX_MAX_DEPTH, 0.0f);
}
else
{
glDepthRangef(GLFar, GLNear);
}
} }
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,

View File

@ -1635,6 +1635,10 @@ void Renderer::SetViewport()
float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset); float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset);
float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd);
float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht);
float range = MathUtil::Clamp<float>(xfmem.viewport.zRange, -16777216.0f, 16777216.0f);
float min_depth =
MathUtil::Clamp<float>(xfmem.viewport.farZ - range, 0.0f, 16777215.0f) / 16777216.0f;
float max_depth = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
if (width < 0.0f) if (width < 0.0f)
{ {
x += width; x += width;
@ -1645,29 +1649,16 @@ void Renderer::SetViewport()
y += height; y += height;
height = -height; height = -height;
} }
if (xfmem.viewport.zRange < 0.0f)
{
min_depth = 1.0f - min_depth;
max_depth = 1.0f - max_depth;
}
// If we do depth clipping and depth range in the vertex shader we only need to ensure // 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, // 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 simply clamp the near/far values themselves to the maximum value as done above.
float min_depth, max_depth; VkViewport viewport = {x, y, width, height, 1.0f - max_depth, 1.0f - min_depth};
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
min_depth = 1.0f - GX_MAX_DEPTH;
max_depth = 1.0f;
}
else
{
float near_val = MathUtil::Clamp<float>(xfmem.viewport.farZ -
MathUtil::Clamp<float>(xfmem.viewport.zRange,
-16777216.0f, 16777216.0f),
0.0f, 16777215.0f) /
16777216.0f;
float far_val = MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f;
min_depth = near_val;
max_depth = far_val;
}
VkViewport viewport = {x, y, width, height, min_depth, max_depth};
StateTracker::GetInstance()->SetViewport(viewport); StateTracker::GetInstance()->SetViewport(viewport);
} }

View File

@ -30,6 +30,10 @@ VertexShaderUid GetVertexShaderUid()
uid_data->msaa = g_ActiveConfig.iMultisamples > 1; uid_data->msaa = g_ActiveConfig.iMultisamples > 1;
uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA;
uid_data->numColorChans = xfmem.numChan.numColorChans; uid_data->numColorChans = xfmem.numChan.numColorChans;
uid_data->vertex_depth =
g_ActiveConfig.backend_info.bSupportsDepthClamp &&
((fabs(xfmem.viewport.zRange) > 16777215.0f || fabs(xfmem.viewport.farZ) > 16777215.0f) ||
(xfmem.viewport.zRange < 0.0f && !g_ActiveConfig.backend_info.bSupportsReversedDepthRange));
GetLightingShaderUid(uid_data->lighting); GetLightingShaderUid(uid_data->lighting);
@ -416,13 +420,10 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
out.Write("o.colors_1 = color1;\n"); out.Write("o.colors_1 = color1;\n");
} }
// Write the true depth value. If the game uses depth textures, then the pixel shader will
// override it with the correct values if not then early z culling will improve speed.
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
// If we can disable the incorrect depth clipping planes using depth clamping, then we can do // If we can disable the incorrect depth clipping planes using depth clamping, then we can do
// our own depth clipping and calculate the depth range before the perspective divide. // our own depth clipping and calculate the depth range before the perspective divide.
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
// Since we're adjusting z for the depth range before the perspective divide, we have to do our // Since we're adjusting z for the depth range before the perspective divide, we have to do our
// own clipping. We want to clip so that -w <= z <= 0, which matches the console -1..0 range. // own clipping. We want to clip so that -w <= z <= 0, which matches the console -1..0 range.
// We adjust our depth value for clipping purposes to match the perspective projection in the // We adjust our depth value for clipping purposes to match the perspective projection in the
@ -430,7 +431,12 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da
out.Write("float clipDepth = o.pos.z * (1.0 - 1e-7);\n"); out.Write("float clipDepth = o.pos.z * (1.0 - 1e-7);\n");
out.Write("o.clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w out.Write("o.clipDist0 = clipDepth + o.pos.w;\n"); // Near: z < -w
out.Write("o.clipDist1 = -clipDepth;\n"); // Far: z > 0 out.Write("o.clipDist1 = -clipDepth;\n"); // Far: z > 0
}
// Write the true depth value. If the game uses depth textures, then the pixel shader will
// override it with the correct values if not then early z culling will improve speed.
if (uid_data->vertex_depth)
{
// Adjust z for the depth range. We're using an equation which incorperates a depth inversion, // Adjust z for the depth range. We're using an equation which incorperates a depth inversion,
// so we can map the console -1..0 range to the 0..1 range used in the depth buffer. // so we can map the console -1..0 range to the 0..1 range used in the depth buffer.
// We have to handle the depth range in the vertex shader instead of after the perspective // We have to handle the depth range in the vertex shader instead of after the perspective

View File

@ -43,7 +43,8 @@ struct vertex_shader_uid_data
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is
// 8 bits wide // 8 bits wide
u32 ssaa : 1; u32 ssaa : 1;
u32 pad : 15; u32 vertex_depth : 1;
u32 pad : 14;
struct struct
{ {