Skip to content

Commit

Permalink
Merge pull request #16162 from unknownbrackets/geo-shader
Browse files Browse the repository at this point in the history
Implement negative Z clipping in geometry shader
  • Loading branch information
hrydgard authored Oct 5, 2022
2 parents 317ecda + 5d88e50 commit d6bd08c
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 108 deletions.
1 change: 0 additions & 1 deletion Core/Compatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "DateLimited", &flags_.DateLimited);
CheckSetting(iniFile, gameID, "ShaderColorBitmask", &flags_.ShaderColorBitmask);
CheckSetting(iniFile, gameID, "DisableFirstFrameReadback", &flags_.DisableFirstFrameReadback);
CheckSetting(iniFile, gameID, "DisableRangeCulling", &flags_.DisableRangeCulling);
CheckSetting(iniFile, gameID, "MpegAvcWarmUp", &flags_.MpegAvcWarmUp);
CheckSetting(iniFile, gameID, "BlueToAlpha", &flags_.BlueToAlpha);
CheckSetting(iniFile, gameID, "CenteredLines", &flags_.CenteredLines);
Expand Down
1 change: 0 additions & 1 deletion Core/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ struct CompatFlags {
bool DateLimited;
bool ShaderColorBitmask;
bool DisableFirstFrameReadback;
bool DisableRangeCulling;
bool MpegAvcWarmUp;
bool BlueToAlpha;
bool CenteredLines;
Expand Down
132 changes: 115 additions & 17 deletions GPU/Common/GeometryShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu

ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size());
p.C("layout(triangles) in;\n");
p.C("layout(triangle_strip, max_vertices = 3) out;\n");
p.C("layout(triangle_strip, max_vertices = 6) out;\n");

if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "\n");
Expand Down Expand Up @@ -76,6 +76,10 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu

// Apply culling
p.C(" bool anyInside = false;\n");
// And apply manual clipping if necessary.
if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
p.C(" float clip0[3];\n");
}

p.C(" for (int i = 0; i < 3; i++) {\n"); // TODO: 3 or gl_in.length()? which will be faster?
p.C(" vec4 outPos = gl_in[i].gl_Position;\n");
Expand All @@ -98,6 +102,13 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu
p.C(" if (projPos.z >= u_cullRangeMin.z) { anyInside = true; }\n");
p.C(" if (projPos.z <= u_cullRangeMax.z) { anyInside = true; }\n");
p.C(" }\n");

if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
// This is basically the same value as gl_ClipDistance would take, z + w.
// TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z.
p.F(" clip0[i] = projZ * outPos.w + outPos.w;\n");
}

p.C(" } // for\n");

// Cull any triangle fully outside in the same direction when depth clamp enabled.
Expand All @@ -106,27 +117,114 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu
p.C(" return;\n");
p.C(" }\n");

const char *clip0 = compat.shaderLanguage == HLSL_D3D11 ? "" : "[0]";
if (!gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
// Clipping against one half-space cuts a triangle (17/27), culls (7/27), or creates two triangles (3/27).
p.C(" int indices[4];\n");
p.C(" float factors[4];\n");
p.C(" int ind = 0;\n");

// Pass 1 - clip against first half-space.
p.C(" for (int i = 0; i < 3; i++) {\n");
// First, use this vertex if it doesn't need clipping.
p.C(" if (clip0[i] >= 0.0) {\n");
p.C(" indices[ind] = i;\n");
p.C(" factors[ind] = 0.0;\n");
p.C(" ind++;\n");
p.C(" }\n");

// Next, we generate an interpolated vertex if signs differ.
p.C(" int inext = i == 2 ? 0 : i + 1;\n");
p.C(" if (clip0[i] * clip0[inext] < 0.0) {\n");
p.C(" float t = clip0[i] < 0.0 ? clip0[i] / (clip0[i] - clip0[inext]) : 1.0 - (clip0[inext] / (clip0[inext] - clip0[i]));\n");
p.C(" indices[ind] = i;\n");
p.C(" factors[ind] = t;\n");
p.C(" ind++;\n");
p.C(" }\n");

p.C(" }\n");

p.C(" if (ind < 3) {\n");
p.C(" return;\n");
p.C(" }\n");

// Alright, time to actually emit the first triangle.
p.C(" for (int i = 0; i < 3; i++) {\n");
p.C(" int idx = indices[i];\n");
p.C(" float factor = factors[i];\n");
p.C(" int next = idx == 2 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(gl_in[idx].gl_Position, gl_in[next].gl_Position, factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = mix(%s[idx], %s[next], factor);\n", outVaryings[i].name, varyings[i].name, varyings[i].name);
}
p.C(" EmitVertex();\n");
p.C(" }\n");

// Did we end up with additional triangles? We'll do three points each for the rest.
p.C(" for (int i = 3; i < ind; i++) {\n");
p.C(" EndPrimitive();\n");

// Point one, always index zero.
p.C(" int idx = indices[0];\n");
p.C(" float factor = factors[0];\n");
p.C(" int next = idx == 2 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(gl_in[idx].gl_Position, gl_in[next].gl_Position, factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = mix(%s[idx], %s[next], factor);\n", outVaryings[i].name, varyings[i].name, varyings[i].name);
}
p.C(" EmitVertex();\n");

// After that, one less than i (basically a triangle fan.)
p.C(" idx = indices[i - 1];\n");
p.C(" factor = factors[i - 1];\n");
p.C(" next = idx == 2 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(gl_in[idx].gl_Position, gl_in[next].gl_Position, factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = mix(%s[idx], %s[next], factor);\n", outVaryings[i].name, varyings[i].name, varyings[i].name);
}
p.C(" EmitVertex();\n");

// And the new vertex itself.
p.C(" idx = indices[i];\n");
p.C(" factor = factors[i];\n");
p.C(" next = idx == 2 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(gl_in[idx].gl_Position, gl_in[next].gl_Position, factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = mix(%s[idx], %s[next], factor);\n", outVaryings[i].name, varyings[i].name, varyings[i].name);
}
p.C(" EmitVertex();\n");

p.C(" }\n");
} else {
const char *clipSuffix0 = compat.shaderLanguage == HLSL_D3D11 ? "" : "[0]";

p.C(" for (int i = 0; i < 3; i++) {\n"); // TODO: 3 or gl_in.length()? which will be faster?
p.C(" vec4 outPos = gl_in[i].gl_Position;\n");
p.C(" gl_Position = outPos;\n");
// TODO: Not rectangles...
if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
p.C(" for (int i = 0; i < 3; i++) {\n"); // TODO: 3 or gl_in.length()? which will be faster?
p.C(" vec4 outPos = gl_in[i].gl_Position;\n");
p.C(" vec3 projPos = outPos.xyz / outPos.w;\n");
p.C(" float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clip0);
}
// TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z.
p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix0);
p.C(" gl_Position = outPos;\n");
if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
}

for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = %s[i];\n", outVaryings[i].name, varyings[i].name);
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = %s[i];\n", outVaryings[i].name, varyings[i].name);
}
// Debug - null the red channel
//p.C(" if (i == 0) v_color0Out.x = 0.0;\n");
p.C(" EmitVertex();\n");
p.C(" }\n");
}
// Debug - null the red channel
//p.C(" if (i == 0) v_color0Out.x = 0.0;\n");
p.C(" EmitVertex();\n");
p.C(" }\n");

p.EndGSMain();

Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/VertexShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]";
const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]";
if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
// TODO: Not rectangles...
// TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z.
WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, vertexRangeClipSuffix);
}
if (gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) {
Expand Down
6 changes: 1 addition & 5 deletions GPU/GPUCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3306,11 +3306,7 @@ u32 GPUCommon::CheckGPUFeatures() const {
}

if (!draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) {
// Ignore the compat setting if clip and cull are both enabled.
// When supported, we can do the depth side of range culling more correctly.
const bool supported = draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported;
const bool disabled = PSP_CoreParameter().compat.flags().DisableRangeCulling;
if (supported || !disabled) {
if (draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported) {
features |= GPU_SUPPORTS_VS_RANGE_CULLING;
}
}
Expand Down
83 changes: 0 additions & 83 deletions assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -156,89 +156,6 @@ NPJH90062 = true
# Phantasy Star Portable Infinity Demo
NPJH90157 = true # Infinity demo

[DisableRangeCulling]
# Phantasy Star games also have range culling issues.
# Phantasy Star Portable 2 and Infinity
ULJM05309 = true
ULUS10410 = true
ULES01218 = true
ULJM08023 = true
ULES01218 = true
# Phantasy Star Portable 1 Demo
NPUH90023 = true
# Phantasy Star Portable 2
ULES01439 = true
ULUS10529 = true
ULJM05493 = true
NPJH50043 = true
ULJM08030 = true
NPUH90023 = true
ULJM91014 = true
NPJH90002 = true
ULJM05732 = true
NPJH50332 = true
# Phantasy Star Portable 2 JP Demo
ULJM91018 = true
NPJH90062 = true
# Phantasy Star Portable Infinity Demo
NPJH90157 = true # Infinity demo

# Test Drive Unlimited
ULET00386 = true
ULES00637 = true
ULKS46126 = true
ULUS10249 = true

# Metal Gear Solid : Peace Walker (see issue #12348)
ULUS10509 = true
ULES01372 = true
ULJM08038 = true
NPJH50045 = true
ULJM05630 = true
NPJH90082 = true
NPJH90063 = true

# Metal Gear Solid : Peace Walker Demo Ops (see issue #12348)
NPUH90066 = true
NPHH00145 = true
NPEH90023 = true

# Metal Gear Solid: Portable Ops (see issue #12348)
ULES00645 = true
ULJM05193 = true
ULJM05227 = true
ULUS10202 = true
ULES01003 = true
ULJM05261 = true
ULUS10290 = true
ULED90040 = true
ULJM05284 = true
ULES00645 = true

# Splinter Cell Essentials (#13035)
ULES00281 = true
ULUS10070 = true

# Asphalt 2 (#14299)
ULES00719 = true
# No US release, it seems

# Star Wars: Lethal Alliance (#11551)
ULES00599 = true
ULUS10188 = true

# Digimon World Re:Digitize
ULJS00496 = true
NPJH50588 = true
ULAS42319 = true

# NOVA: Near Orbit Vanguard Alliance
NPUZ00179 = true
NPEZ00222 = true

# Street Riders (only region found. See #14746)
ULES00276 = true

[ClearToRAM]
# SOCOM Navy Seals games require this. See issue #8973.
# Navy Seals : Tactical Strike
Expand Down

0 comments on commit d6bd08c

Please sign in to comment.