From fc2334f4fabfd3b9d63ad6bfd46e5a4d4872e199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 4 Jan 2023 12:05:40 +0100 Subject: [PATCH] Inject zero texcoords to avoid needing separate vshaders for UV-less formats. Make injecting a dummy UV into an option on the vertex decoder --- GPU/Common/DrawEngineCommon.cpp | 1 + GPU/Common/ShaderId.cpp | 3 - GPU/Common/ShaderId.h | 1 - GPU/Common/VertexDecoderArm.cpp | 8 +++ GPU/Common/VertexDecoderArm64.cpp | 8 +++ GPU/Common/VertexDecoderCommon.cpp | 13 +++- GPU/Common/VertexDecoderCommon.h | 5 ++ GPU/Common/VertexDecoderX86.cpp | 7 +++ GPU/Common/VertexShaderGenerator.cpp | 90 +++++++++++----------------- unittest/TestVertexJit.cpp | 13 ++-- 10 files changed, 81 insertions(+), 68 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 139d47613c..374ef99643 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -39,6 +39,7 @@ DrawEngineCommon::DrawEngineCommon() : decoderMap_(16) { decJitCache_ = new VertexDecoderJitCache(); transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + decOptions_.injectDummyUVIfMissing = true; } DrawEngineCommon::~DrawEngineCommon() { diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index cc9875a6ef..aff056db2a 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -19,7 +19,6 @@ std::string VertexShaderDesc(const VShaderID &id) { if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR "; if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX "; if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C "; - if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T "; if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N "; if (id.Bit(VS_BIT_LMODE)) desc << "LM "; if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN "; @@ -76,7 +75,6 @@ void ComputeVertexShaderID(VShaderID *id_out, VertexDecoder *vertexDecoder, bool bool vtypeHasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool vtypeHasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0; - bool vtypeHasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0; bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER; bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE; @@ -147,7 +145,6 @@ void ComputeVertexShaderID(VShaderID *id_out, VertexDecoder *vertexDecoder, bool } id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed()); - id.SetBit(VS_BIT_HAS_TEXCOORD, vtypeHasTexcoord); if (useHWTessellation) { id.SetBit(VS_BIT_BEZIER, doBezier); diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 406d12931c..dbc6463d7b 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -20,7 +20,6 @@ enum VShaderBit : uint8_t { VS_BIT_USE_HW_TRANSFORM = 8, VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform VS_BIT_NORM_REVERSE = 10, - VS_BIT_HAS_TEXCOORD = 11, VS_BIT_HAS_COLOR_TESS = 12, // 1 bit VS_BIT_HAS_TEXCOORD_TESS = 13, // 1 bit VS_BIT_NORM_REVERSE_TESS = 14, // 1 bit diff --git a/GPU/Common/VertexDecoderArm.cpp b/GPU/Common/VertexDecoderArm.cpp index ed57fd89cc..b3e655c421 100644 --- a/GPU/Common/VertexDecoderArm.cpp +++ b/GPU/Common/VertexDecoderArm.cpp @@ -109,6 +109,8 @@ static const JitLookup jitLookup[] = { {&VertexDecoder::Step_WeightsU16Skin, &VertexDecoderJitCache::Jit_WeightsU16Skin}, {&VertexDecoder::Step_WeightsFloatSkin, &VertexDecoderJitCache::Jit_WeightsFloatSkin}, + {&VertexDecoder::Step_TcDefault, &VertexDecoderJitCache::Jit_TcDefault}, + {&VertexDecoder::Step_TcFloat, &VertexDecoderJitCache::Jit_TcFloat}, {&VertexDecoder::Step_TcU8ToFloat, &VertexDecoderJitCache::Jit_TcU8ToFloat}, {&VertexDecoder::Step_TcU16ToFloat, &VertexDecoderJitCache::Jit_TcU16ToFloat}, @@ -487,6 +489,12 @@ void VertexDecoderJitCache::Jit_WeightsFloatSkin() { Jit_ApplyWeights(); } +void VertexDecoderJitCache::Jit_TcDefault() { + MOVI(tempReg1, 0); + STR(tempReg1, dstReg, dec_->decFmt.uvoff); + STR(tempReg1, dstReg, dec_->decFmt.uvoff + 4); +} + void VertexDecoderJitCache::Jit_TcFloat() { LDR(tempReg1, srcReg, dec_->tcoff); LDR(tempReg2, srcReg, dec_->tcoff + 4); diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index 9743b3dc52..dda739033d 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -40,6 +40,7 @@ static const ARM64Reg dstReg = X1; static const ARM64Reg counterReg = W2; static const ARM64Reg tempReg1 = W3; +static const ARM64Reg tempReg1_64 = X3; static const ARM64Reg tempRegPtr = X3; static const ARM64Reg tempReg2 = W4; static const ARM64Reg tempReg3 = W5; @@ -86,6 +87,8 @@ static const JitLookup jitLookup[] = { {&VertexDecoder::Step_WeightsU16Skin, &VertexDecoderJitCache::Jit_WeightsU16Skin}, {&VertexDecoder::Step_WeightsFloatSkin, &VertexDecoderJitCache::Jit_WeightsFloatSkin}, + {&VertexDecoder::Step_TcDefault, &VertexDecoderJitCache::Jit_TcDefault}, + {&VertexDecoder::Step_TcFloat, &VertexDecoderJitCache::Jit_TcFloat}, {&VertexDecoder::Step_TcU8ToFloat, &VertexDecoderJitCache::Jit_TcU8ToFloat}, {&VertexDecoder::Step_TcU16ToFloat, &VertexDecoderJitCache::Jit_TcU16ToFloat}, @@ -592,6 +595,11 @@ void VertexDecoderJitCache::Jit_TcU16ThroughToFloat() { fp.STUR(64, neonScratchRegD, dstReg, dec_->decFmt.uvoff); } +void VertexDecoderJitCache::Jit_TcDefault() { + MOVI2R(tempReg1_64, 0); + STR(INDEX_UNSIGNED, tempReg1, dstReg, dec_->decFmt.uvoff); +} + void VertexDecoderJitCache::Jit_TcFloatThrough() { LDP(INDEX_SIGNED, tempReg1, tempReg2, srcReg, dec_->tcoff); STP(INDEX_SIGNED, tempReg1, tempReg2, dstReg, dec_->decFmt.uvoff); diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp index 673fdbf2a6..de80dbaeac 100644 --- a/GPU/Common/VertexDecoderCommon.cpp +++ b/GPU/Common/VertexDecoderCommon.cpp @@ -270,9 +270,15 @@ void VertexDecoder::Step_WeightsFloatSkin() const { ComputeSkinMatrix(wdata); } +void VertexDecoder::Step_TcDefault() const +{ + uint64_t *uv = (uint64_t *)(decoded_ + decFmt.uvoff); + // Write two zero floats in one instruction. + *uv = 0; +} + void VertexDecoder::Step_TcU8ToFloat() const { - // u32 to write two bytes of zeroes for free. float *uv = (float *)(decoded_ + decFmt.uvoff); const u8 *uvdata = (const u8*)(ptr_ + tcoff); uv[0] = uvdata[0] * (1.0f / 128.0f); @@ -1163,6 +1169,11 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options, decFmt.uvfmt = DEC_FLOAT_2; } + decFmt.uvoff = decOff; + decOff += DecFmtSize(decFmt.uvfmt); + } else if (options.injectDummyUVIfMissing) { + steps_[numSteps_++] = &VertexDecoder::Step_TcDefault; + decFmt.uvfmt = DEC_FLOAT_2; decFmt.uvoff = decOff; decOff += DecFmtSize(decFmt.uvfmt); } diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 6a1c6d7360..60591c9026 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -324,6 +324,7 @@ struct VertexDecoderOptions { bool expandAllWeightsToFloat; bool expand8BitNormalsToFloat; bool applySkinInDecode; + bool injectDummyUVIfMissing; }; class VertexDecoder { @@ -353,6 +354,8 @@ public: void Step_WeightsU16Skin() const; void Step_WeightsFloatSkin() const; + void Step_TcDefault() const; + void Step_TcU8ToFloat() const; void Step_TcU16ToFloat() const; void Step_TcFloat() const; @@ -510,6 +513,8 @@ public: void Jit_WeightsU16Skin(); void Jit_WeightsFloatSkin(); + void Jit_TcDefault(); + void Jit_TcU8ToFloat(); void Jit_TcU16ToFloat(); void Jit_TcFloat(); diff --git a/GPU/Common/VertexDecoderX86.cpp b/GPU/Common/VertexDecoderX86.cpp index 3340961f8e..4c7c522547 100644 --- a/GPU/Common/VertexDecoderX86.cpp +++ b/GPU/Common/VertexDecoderX86.cpp @@ -103,6 +103,8 @@ static const JitLookup jitLookup[] = { {&VertexDecoder::Step_WeightsU8ToFloat, &VertexDecoderJitCache::Jit_WeightsU8ToFloat}, {&VertexDecoder::Step_WeightsU16ToFloat, &VertexDecoderJitCache::Jit_WeightsU16ToFloat}, + {&VertexDecoder::Step_TcDefault, &VertexDecoderJitCache::Jit_TcDefault}, + {&VertexDecoder::Step_TcFloat, &VertexDecoderJitCache::Jit_TcFloat}, {&VertexDecoder::Step_TcU8ToFloat, &VertexDecoderJitCache::Jit_TcU8ToFloat}, {&VertexDecoder::Step_TcU16ToFloat, &VertexDecoderJitCache::Jit_TcU16ToFloat}, @@ -721,6 +723,11 @@ void VertexDecoderJitCache::Jit_WeightsFloatSkin() { } } +void VertexDecoderJitCache::Jit_TcDefault() { + PXOR(XMM3, R(XMM3)); + MOVQ_xmm(MDisp(dstReg, dec_->decFmt.uvoff), XMM3); +} + void VertexDecoderJitCache::Jit_TcU8ToFloat() { Jit_AnyU8ToFloat(dec_->tcoff, 16); MOVQ_xmm(MDisp(dstReg, dec_->decFmt.uvoff), XMM3); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 1358195dee..cd15e1e1b6 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -186,7 +186,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); bool hasColor = id.Bit(VS_BIT_HAS_COLOR) || !useHWTransform; bool hasNormal = id.Bit(VS_BIT_HAS_NORMAL) && useHWTransform; - bool hasTexcoord = id.Bit(VS_BIT_HAS_TEXCOORD) || !useHWTransform; bool flipNormal = id.Bit(VS_BIT_NORM_REVERSE); int ls0 = id.Bits(VS_BIT_LS0, 2); int ls1 = id.Bits(VS_BIT_LS1, 2); @@ -270,14 +269,13 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (!useHWTransform) WRITE(p, "layout (location = %d) in float fog;\n", (int)PspAttributeLocation::NORMAL); - if (hasTexcoord) { - if (!useHWTransform && doTextureTransform && !isModeThrough) { - WRITE(p, "layout (location = %d) in vec3 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); - texCoordInVec3 = true; - } else { - WRITE(p, "layout (location = %d) in vec2 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); - } + if (!useHWTransform && doTextureTransform && !isModeThrough) { + WRITE(p, "layout (location = %d) in vec3 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); + texCoordInVec3 = true; + } else { + WRITE(p, "layout (location = %d) in vec2 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); } + if (hasColor) { WRITE(p, "layout (location = %d) in vec4 color0;\n", (int)PspAttributeLocation::COLOR0); if (lmode && !useHWTransform) // only software transform supplies color1 as vertex data @@ -379,9 +377,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (enableBones) { WRITE(p, " %s", boneWeightAttrDeclHLSL[numBoneWeights]); } - if (hasTexcoord) { - WRITE(p, " vec2 texcoord : TEXCOORD0;\n"); - } + WRITE(p, " vec2 texcoord : TEXCOORD0;\n"); if (hasColor) { WRITE(p, " vec4 color0 : COLOR0;\n"); } @@ -393,13 +389,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } else { WRITE(p, "struct VS_IN {\n"); WRITE(p, " vec4 position : POSITION;\n"); - if (hasTexcoord) { - if (doTextureTransform && !isModeThrough) { - texCoordInVec3 = true; - WRITE(p, " vec3 texcoord : TEXCOORD0;\n"); - } else { - WRITE(p, " vec2 texcoord : TEXCOORD0;\n"); - } + if (doTextureTransform && !isModeThrough) { + texCoordInVec3 = true; + WRITE(p, " vec3 texcoord : TEXCOORD0;\n"); + } else { + WRITE(p, " vec2 texcoord : TEXCOORD0;\n"); } if (hasColor) { WRITE(p, " vec4 color0 : COLOR0;\n"); @@ -465,15 +459,13 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag *attrMask |= 1 << ATTR_NORMAL; } - if (hasTexcoord) { - if (!useHWTransform && doTextureTransform && !isModeThrough) { - WRITE(p, "%s vec3 texcoord;\n", compat.attribute); - texCoordInVec3 = true; - } else { - WRITE(p, "%s vec2 texcoord;\n", compat.attribute); - } - *attrMask |= 1 << ATTR_TEXCOORD; + if (!useHWTransform && doTextureTransform && !isModeThrough) { + WRITE(p, "%s vec3 texcoord;\n", compat.attribute); + texCoordInVec3 = true; + } else { + WRITE(p, "%s vec2 texcoord;\n", compat.attribute); } + *attrMask |= 1 << ATTR_TEXCOORD; if (hasColor) { WRITE(p, "%s lowp vec4 color0;\n", compat.attribute); @@ -783,12 +775,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } else if (compat.shaderLanguage == HLSL_D3D9 || compat.shaderLanguage == HLSL_D3D11) { WRITE(p, "VS_OUT main(VS_IN In) {\n"); WRITE(p, " VS_OUT Out;\n"); - if (hasTexcoord) { - if (texCoordInVec3) { - WRITE(p, " vec3 texcoord = In.texcoord;\n"); - } else { - WRITE(p, " vec2 texcoord = In.texcoord;\n"); - } + if (texCoordInVec3) { + WRITE(p, " vec3 texcoord = In.texcoord;\n"); + } else { + WRITE(p, " vec2 texcoord = In.texcoord;\n"); } if (hasColor) { WRITE(p, " vec4 color0 = In.color0;\n"); @@ -1204,23 +1194,15 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag case GE_TEXMAP_TEXTURE_COORDS: // Scale-offset. Easy. case GE_TEXMAP_UNKNOWN: // Not sure what this is, but Riviera uses it. Treating as coords works. if (scaleUV) { - if (hasTexcoord) { - if (doBezier || doSpline) - WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); - else - WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n", compat.vsOutPrefix); - } else { - WRITE(p, " %sv_texcoord = splat3(0.0);\n", compat.vsOutPrefix); - } + if (doBezier || doSpline) + WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); + else + WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n", compat.vsOutPrefix); } else { - if (hasTexcoord) { - if (doBezier || doSpline) - WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); - else - WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); - } else { - WRITE(p, " %sv_texcoord = vec3(u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); - } + if (doBezier || doSpline) + WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); + else + WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix); } break; @@ -1237,14 +1219,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag case GE_PROJMAP_UV: // Use unscaled UV as source { // prescale is false here. - if (hasTexcoord) { - if (doBezier || doSpline) - temp_tc = "vec4(tess.tex.xy, 0.0, 1.0)"; - else - temp_tc = "vec4(texcoord.xy, 0.0, 1.0)"; - } else { - temp_tc = "vec4(0.0, 0.0, 0.0, 1.0)"; - } + if (doBezier || doSpline) + temp_tc = "vec4(tess.tex.xy, 0.0, 1.0)"; + else + temp_tc = "vec4(texcoord.xy, 0.0, 1.0)"; } break; case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized transformed normal as source diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index 12dad2f5aa..a9df8d9baa 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -32,8 +32,7 @@ class VertexDecoderTestHarness { static const int ROUNDS = 200; public: - VertexDecoderTestHarness() - : dec_(nullptr), needsReset_(true), dstPos_(0), assertFailed_(false) { + VertexDecoderTestHarness() { src_ = new u8[BUFFER_SIZE]; dst_ = new u8[BUFFER_SIZE]; cache_ = new VertexDecoderJitCache(); @@ -285,13 +284,13 @@ private: u8 *dst_; VertexDecoderJitCache *cache_; VertexDecoderOptions options_; - VertexDecoder *dec_; + VertexDecoder *dec_ = nullptr; int indexLowerBound_; int indexUpperBound_; - bool needsReset_; - size_t srcPos_; - size_t dstPos_; - bool assertFailed_; + bool needsReset_ = true; + size_t srcPos_ = 0; + size_t dstPos_ = 0; + bool assertFailed_ = false; }; static bool TestVertex8() {