D3D11-only experimental way to cull out-of-bounds triangles. Helps #5001, at least for Toca.

Really not sure how big the guard band should be, and the right way to
do this would be to use a geometry shader instead of killing triangles
by setting w = NaN, which I'm not sure will do sane things on all
hardware. Unfortunately geometry shaders are not available everywhere.
This commit is contained in:
Henrik Rydgard committed 2017-04-02 20:56:10 +02:00
1 parent 97058b4db7
commit e576a623e2
3 files changed
+36 -14

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
Uint8x3ToInt4_Alpha(ub->colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask());
}
if (dirtyUniforms & DIRTY_FOGCOLOR) {
Uint8x3ToFloat4(ub->fogColor, gstate.fogcolor);
Uint8x3ToFloat4_Alpha(ub->fogColor, gstate.fogcolor, NAN);
}
if (dirtyUniforms & DIRTY_SHADERBLEND) {
Uint8x3ToFloat4(ub->blendFixA, gstate.getFixA());
+2 -2
View File
@@ -59,7 +59,7 @@ R"( mat4 proj_mtx;
int spline_count_v;
int spline_type_u;
int spline_type_v;
vec3 fogcolor;
vec3 fogcolor; float nanValue;
vec3 texenv;
ivec4 alphacolorref;
ivec4 alphacolormask;
@@ -84,7 +84,7 @@ R"( float4x4 u_proj;
int u_spline_count_v;
int u_spline_type_u;
int u_spline_type_v;
float3 u_fogcolor;
float3 u_fogcolor; float nanValue;
float3 u_texenv;
uint4 u_alphacolorref;
uint4 u_alphacolormask;
+33 -11
View File
@@ -37,6 +37,16 @@
namespace DX9 {
// The PSP does not have a proper triangle clipper, but it does have a guard band and can rasterize rather large
// triangles that go outside the viewport. However, there are limits, and it will drop triangles that are very
// large. Some games appear to draw broken geometry, probably game bugs that were never discovered because the PSP
// would drop the geometry, including Parappa The Rapper in an obscure case and Outrun. Try to get rid of those
// triangles by setting the W of one of the vertices to NaN if they are discovered.
const bool guardBandCulling = true;
// Not sure what a good value for this is, it should probably depend on the framebuffer size.
// Let's be conservative.
const float guardBand = 64.0f;
static const char * const boneWeightAttrDecl[9] = {
"#ERROR#",
"float a_w1:TEXCOORD1;\n",
@@ -344,6 +354,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l
}
}
WRITE(p, "VS_OUT main(VS_IN In) {\n");
WRITE(p, " VS_OUT Out;\n");
if (!useHWTransform) {
@@ -369,26 +380,32 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l
}
if (lang == HLSL_D3D11 || lang == HLSL_D3D11_LEVEL9) {
if (gstate.isModeThrough()) {
WRITE(p, " Out.gl_Position = mul(u_proj_through, float4(In.position.xyz, 1.0));\n");
WRITE(p, " float4 outPos = mul(u_proj_through, float4(In.position.xyz, 1.0));\n");
} else {
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, float4(In.position.xyz, 1.0)));\n");
WRITE(p, " float4 outPos = depthRoundZVP(mul(u_proj, float4(In.position.xyz, 1.0)));\n");
} else {
WRITE(p, " Out.gl_Position = mul(u_proj, float4(In.position.xyz, 1.0));\n");
WRITE(p, " float4 outPos = mul(u_proj, float4(In.position.xyz, 1.0));\n");
}
}
} else {
if (gstate.isModeThrough()) {
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n");
WRITE(p, " float4 outPos = mul(float4(In.position.xyz, 1.0), u_proj_through);\n");
} else {
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n");
WRITE(p, " float4 outPos = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n");
} else {
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n");
WRITE(p, " float4 outPos = mul(float4(In.position.xyz, 1.0), u_proj);\n");
}
}
}
} else {
if (lang != HLSL_DX9 && guardBandCulling) {
// Guard band culling
WRITE(p, " float2 projPos = outPos.xy / outPos.w;\n");
WRITE(p, " if (abs(projPos.x) > %f || abs(projPos.y) > %f) outPos.w = nanValue;\n", guardBand, guardBand);
}
WRITE(p, " Out.gl_Position = outPos;\n");
} else {
// Step 1: World Transform / Skinning
if (!enableBones) {
// Hardware tessellation
@@ -574,18 +591,23 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l
if (lang == HLSL_D3D11 || lang == HLSL_D3D11_LEVEL9) {
// Final view and projection transforms.
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, viewPos));\n");
WRITE(p, " float4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n");
} else {
WRITE(p, " Out.gl_Position = mul(u_proj, viewPos);\n");
WRITE(p, " float4 outPos = mul(u_proj, viewPos);\n");
}
} else {
// Final view and projection transforms.
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n");
WRITE(p, " float4 outPos = depthRoundZVP(mul(viewPos, u_proj));\n");
} else {
WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n");
WRITE(p, " float4 outPos = mul(viewPos, u_proj);\n");
}
}
if (lang != HLSL_DX9 && guardBandCulling) {
WRITE(p, " float2 projPos = outPos.xy / outPos.w;\n");
WRITE(p, " if (abs(projPos.x) > %f || abs(projPos.y) > %f) outPos.w = nanValue;\n", guardBand, guardBand);
}
WRITE(p, " Out.gl_Position = outPos;\n");
// TODO: Declare variables for dots for shade mapping if needed.