Skip to content

Commit

Permalink
Turn off vertex range culling in bezier/spline calls.
Browse files Browse the repository at this point in the history
When we do lower res tess than the real PSP, we cant trust the game to not cause range culling to kick in.

Fixes #11692
  • Loading branch information
hrydgard committed Dec 13, 2020
1 parent c546c60 commit f3ebd65
Show file tree
Hide file tree
Showing 11 changed files with 43 additions and 19 deletions.
8 changes: 8 additions & 0 deletions Common/GPU/ShaderWriter.cpp
Expand Up @@ -83,6 +83,8 @@ void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions
case ShaderStage::Fragment:
W(vulkan_glsl_preamble_fs);
break;
default:
break;
}
break;
case HLSL_D3D11:
Expand All @@ -99,6 +101,8 @@ void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions
W(hlsl_d3d11_preamble_fs);
}
break;
default:
break;
}
break;
default: // OpenGL
Expand All @@ -125,6 +129,8 @@ void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions
}
C("#define gl_VertexIndex gl_VertexID\n");
break;
default:
break;
}
if (!lang_.gles) {
C("#define lowp\n");
Expand Down Expand Up @@ -293,6 +299,8 @@ void ShaderWriter::DeclareSampler2D(const char *name, int binding) {
case HLSL_D3D11:
F("SamplerState %s : register(s%d);\n", name, binding);
break;
default:
break;
}
}

Expand Down
8 changes: 6 additions & 2 deletions GPU/Common/ShaderId.cpp
Expand Up @@ -56,6 +56,7 @@ std::string VertexShaderDesc(const VShaderID &id) {
if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT ";
if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN ";
if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN ";
if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull ";

return desc.str();
}
Expand All @@ -70,17 +71,20 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;

bool doBezier = gstate_c.bezier;
bool doSpline = gstate_c.spline;
bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER;
bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE;

bool enableFog = gstate.isFogEnabled() && !isModeThrough && !gstate.isModeClear();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
bool vertexRangeCulling = gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING) &&
!isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692

VShaderID id;
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);
id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
id.SetBit(VS_BIT_HAS_COLOR, hasColor);
id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling);

if (doTexture) {
id.SetBit(VS_BIT_DO_TEXTURE);
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/ShaderId.h
Expand Up @@ -15,7 +15,7 @@ enum VShaderBit : uint8_t {
VS_BIT_ENABLE_FOG = 2,
VS_BIT_HAS_COLOR = 3,
VS_BIT_DO_TEXTURE = 4,
// 5 is free.
VS_BIT_VERTEX_RANGE_CULLING = 5,
// 6 is free,
// 7 is free.
VS_BIT_USE_HW_TRANSFORM = 8,
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/ShaderUniforms.cpp
Expand Up @@ -215,7 +215,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
const int h = gstate.getTextureHeight(0);
const float widthFactor = (float)w * invW;
const float heightFactor = (float)h * invH;
if (gstate_c.bezier || gstate_c.spline) {
if (gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE) {
// When we are generating UV coordinates through the bezier/spline, we need to apply the scaling.
// However, this is missing a check that we're not getting our UV:s supplied for us in the vertices.
ub->uvScaleOffset[0] = gstate_c.uv.uScale * widthFactor;
Expand Down
4 changes: 3 additions & 1 deletion GPU/Common/VertexShaderGenerator.cpp
Expand Up @@ -207,6 +207,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
bool texCoordInVec3 = false;

bool vertexRangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING);

if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "\n");
WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr);
Expand Down Expand Up @@ -1086,7 +1088,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " %sv_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n", compat.vsOutPrefix);
}

if (!isModeThrough && gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING)) {
if (vertexRangeCulling) {
WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n");
// Vertex range culling doesn't happen when depth is clamped, so only do this if in range.
WRITE(p, " if (u_cullRangeMin.w <= 0.0 || (projPos.z >= u_cullRangeMin.z && projPos.z <= u_cullRangeMax.z)) {\n");
Expand Down
2 changes: 1 addition & 1 deletion GPU/D3D11/DrawEngineD3D11.cpp
Expand Up @@ -341,7 +341,7 @@ void DrawEngineD3D11::DoFlush() {
ApplyDrawState(prim);

// Always use software for flat shading to fix the provoking index.
bool tess = gstate_c.bezier || gstate_c.spline;
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);

if (useHWTransform) {
Expand Down
2 changes: 1 addition & 1 deletion GPU/Directx9/ShaderManagerDX9.cpp
Expand Up @@ -543,7 +543,7 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays

VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType) {
// Always use software for flat shading to fix the provoking index.
bool tess = gstate_c.bezier || gstate_c.spline;
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
useHWTransform = useHWTransform && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);

VShaderID VSID;
Expand Down
2 changes: 1 addition & 1 deletion GPU/GLES/ShaderManagerGLES.cpp
Expand Up @@ -409,7 +409,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
const float widthFactor = (float)w * invW;
const float heightFactor = (float)h * invH;
float uvscaleoff[4];
if (gstate_c.bezier || gstate_c.spline) {
if (gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE) {
// When we are generating UV coordinates through the bezier/spline, we need to apply the scaling.
// However, this is missing a check that we're not getting our UV:s supplied for us in the vertices.
uvscaleoff[0] = gstate_c.uv.uScale * widthFactor;
Expand Down
18 changes: 10 additions & 8 deletions GPU/GPUCommon.cpp
Expand Up @@ -1830,20 +1830,21 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) {

if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = true;
gstate_c.submitType = SubmitType::HW_BEZIER;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_num_points_u = surface.num_points_u;
}
} else {
gstate_c.submitType = SubmitType::BEZIER;
}

int bytesRead = 0;
UpdateUVScaleOffset();
drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier");

if (gstate_c.bezier)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = false;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.submitType = SubmitType::DRAW;

// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = surface.num_points_u * surface.num_points_v;
Expand Down Expand Up @@ -1896,20 +1897,21 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) {

if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = true;
gstate_c.submitType = SubmitType::HW_SPLINE;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_num_points_u = surface.num_points_u;
}
} else {
gstate_c.submitType = SubmitType::SPLINE;
}

int bytesRead = 0;
UpdateUVScaleOffset();
drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline");

if (gstate_c.spline)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = false;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.submitType = SubmitType::DRAW;

// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = surface.num_points_u * surface.num_points_v;
Expand Down
12 changes: 10 additions & 2 deletions GPU/GPUState.h
Expand Up @@ -504,6 +504,14 @@ struct KnownVertexBounds {
u16 maxV;
};

enum class SubmitType {
DRAW,
BEZIER,
SPLINE,
HW_BEZIER,
HW_SPLINE,
};

struct GPUStateCache {
bool Supports(u32 flags) { return (featureFlags & flags) != 0; } // Return true if ANY of flags are true.
bool SupportsAll(u32 flags) { return (featureFlags & flags) == flags; } // Return true if ALL flags are true.
Expand Down Expand Up @@ -602,8 +610,8 @@ struct GPUStateCache {
}
u32 curRTOffsetX;

bool bezier;
bool spline;
// Set if we are doing hardware bezier/spline.
SubmitType submitType;
int spline_num_points_u;

bool useShaderDepal;
Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/DrawEngineVulkan.cpp
Expand Up @@ -598,7 +598,7 @@ void DrawEngineVulkan::DoFlush() {

FrameData *frame = &frame_[vulkan_->GetCurFrame()];

bool tess = gstate_c.bezier || gstate_c.spline;
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;

bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
Expand Down

0 comments on commit f3ebd65

Please sign in to comment.