Turn off vertex range culling in bezier/spline calls.

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
This commit is contained in:
Henrik Rydgård 2020-12-13 16:04:16 +01:00
parent c546c60324
commit f3ebd6553d
11 changed files with 43 additions and 19 deletions

View File

@ -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:
@ -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
@ -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");
@ -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;
}
}

View File

@ -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();
}
@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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);
@ -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");

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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;
@ -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;

View File

@ -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.
@ -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;

View File

@ -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()) {