From 9bd8b11bf8a5019b74e03cbb75b9366ca1af7e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 11 Sep 2022 13:27:17 +0200 Subject: [PATCH] Implement shader depal for D3D11. --- Common/GPU/ShaderWriter.cpp | 35 +++++++++++++++ Common/GPU/ShaderWriter.h | 2 + GPU/Common/FragmentShaderGenerator.cpp | 62 ++++++++++++++------------ GPU/Common/TextureCacheCommon.cpp | 1 - GPU/D3D11/D3D11Util.cpp | 5 ++- GPU/D3D11/TextureCacheD3D11.cpp | 5 ++- GPU/GLES/ShaderManagerGLES.cpp | 14 +++--- 7 files changed, 84 insertions(+), 40 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 0332e4d346..62d5760408 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -24,6 +24,7 @@ const char * const hlsl_preamble_fs = "#define vec4 float4\n" "#define uvec3 uint3\n" "#define uvec4 uint4\n" +"#define ivec2 int2\n" "#define ivec3 int3\n" "#define ivec4 int4\n" "#define mat4 float4x4\n" @@ -424,6 +425,40 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv return *this; } +ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) { + switch (lang_.shaderLanguage) { + case HLSL_D3D11: + F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY); + break; + case HLSL_D3D9: + // Not supported, we do a normal sample here to not crash or something + F("tex2D(%s, %s)", sampName, uv); + break; + default: + // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. + F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY); + break; + } + return *this; +} + +ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) { + switch (lang_.shaderLanguage) { + case HLSL_D3D11: + F("%s.Load(ivec3(%s, %d))", sampName, uv, level); + break; + case HLSL_D3D9: + // Not supported, we return a bad value + C("float4(1.0, 0.0, 1.0, 1.0)"); + break; + default: + // Note: we ignore the sampler. make sure you bound samplers to the textures correctly. + F("texelFetch(%s, %s, %d)", lang_.texture, sampName, uv, level); + break; + } + return *this; +} + ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *texName) { switch (lang_.shaderLanguage) { case HLSL_D3D11: diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 7464ebc652..f6a04c828b 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -78,6 +78,8 @@ public: void ConstFloat(const char *name, float value); ShaderWriter &SampleTexture2D(const char *texName, const char *uv); + ShaderWriter &SampleTexture2DOffset(const char *texName, const char *uv, int offX, int offY); + ShaderWriter &LoadTexture2D(const char *texName, const char *integer_uv, int level); ShaderWriter &GetTextureSize(const char *szVariable, const char *texName); // Simple shaders with no special tricks. diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index db1d886b1f..feec43ff75 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -221,7 +221,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "float u_mipBias : register(c%i);\n", CONST_PS_MIPBIAS); } } else { - WRITE(p, "SamplerState samp : register(s0);\n"); + WRITE(p, "SamplerState texSamp : register(s0);\n"); if (texture3D) { WRITE(p, "Texture3D tex : register(t0);\n"); } else { @@ -231,6 +231,12 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu // No sampler required, we Load WRITE(p, "Texture2D fbotex : register(t1);\n"); } + + if (shaderDepal) { + WRITE(p, "SamplerState palSamp : register(s3);\n"); + WRITE(p, "Texture2D pal : register(t3);\n"); + } + WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr); if (shaderDepal) { @@ -561,15 +567,15 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (compat.shaderLanguage == HLSL_D3D11) { if (texture3D) { if (doTextureProjection) { - WRITE(p, " vec4 t = tex.Sample(samp, vec3(v_texcoord.xy / v_texcoord.z, u_mipBias))%s;\n", bgraTexture ? ".bgra" : ""); + WRITE(p, " vec4 t = tex.Sample(texSamp, vec3(v_texcoord.xy / v_texcoord.z, u_mipBias))%s;\n", bgraTexture ? ".bgra" : ""); } else { - WRITE(p, " vec4 t = tex.Sample(samp, vec3(%s.xy, u_mipBias))%s;\n", texcoord, bgraTexture ? ".bgra" : ""); + WRITE(p, " vec4 t = tex.Sample(texSamp, vec3(%s.xy, u_mipBias))%s;\n", texcoord, bgraTexture ? ".bgra" : ""); } } else { if (doTextureProjection) { - WRITE(p, " vec4 t = tex.Sample(samp, v_texcoord.xy / v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : ""); + WRITE(p, " vec4 t = tex.Sample(texSamp, v_texcoord.xy / v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : ""); } else { - WRITE(p, " vec4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : ""); + WRITE(p, " vec4 t = tex.Sample(texSamp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : ""); } } } else if (compat.shaderLanguage == HLSL_D3D9) { @@ -608,28 +614,28 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu if (doTextureProjection) { // We don't use textureProj because we need better control and it's probably not much of a savings anyway. // However it is good for precision on older hardware like PowerVR. - WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord); + p.F(" vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord); } else { - WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); + p.F(" vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); } // Restrictions on this are checked before setting the smoothed flag. // Only RGB565 and RGBA5551 are supported, and only the specific shifts hitting the // channels directly. // Also, since we know the CLUT is smooth, we do not need to do the bilinear filter manually, we can just // lookup with the filtered value once. - WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord); - WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n"); - WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3U;\n"); - WRITE(p, " float index0 = t.r;\n"); - WRITE(p, " float factor = 31.0 / 256.0;\n"); - WRITE(p, " if (depalFmt == 0u) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh. - WRITE(p, " if (depalShift == 5u) { index0 = t.g; factor = 63.0 / 256.0; }\n"); - WRITE(p, " else if (depalShift == 11u) { index0 = t.b; }\n"); - WRITE(p, " } else {\n"); - WRITE(p, " if (depalShift == 5u) { index0 = t.g; }\n"); - WRITE(p, " else if (depalShift == 10u) { index0 = t.b; }\n"); - WRITE(p, " }\n"); - WRITE(p, " t = %s(pal, vec2(index0 * factor, 0.0));\n", compat.texture); + p.F(" vec4 t = ").SampleTexture2D("tex", "uv").C(";\n"); + p.C(" uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n"); + p.C(" uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3U;\n"); + p.C(" float index0 = t.r;\n"); + p.C(" float factor = 31.0 / 256.0;\n"); + p.C(" if (depalFmt == 0u) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh. + p.C(" if (depalShift == 5u) { index0 = t.g; factor = 63.0 / 256.0; }\n"); + p.C(" else if (depalShift == 11u) { index0 = t.b; }\n"); + p.C(" } else {\n"); + p.C(" if (depalShift == 5u) { index0 = t.g; }\n"); + p.C(" else if (depalShift == 10u) { index0 = t.b; }\n"); + p.C(" }\n"); + p.F(" t = ").SampleTexture2D("pal", "vec2(index0 * factor, 0.0)").C(";\n"); } else { if (doTextureProjection) { // We don't use textureProj because we need better control and it's probably not much of a savings anyway. @@ -648,10 +654,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " } else {\n"); WRITE(p, " uv_round = uv;\n"); WRITE(p, " }\n"); - WRITE(p, " highp vec4 t = %s(tex, uv_round);\n", compat.texture); - WRITE(p, " highp vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", compat.texture); - WRITE(p, " highp vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", compat.texture); - WRITE(p, " highp vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", compat.texture); + p.C(" highp vec4 t = ").SampleTexture2D("tex", "uv_round").C(";\n"); + p.C(" highp vec4 t1 = ").SampleTexture2DOffset("tex", "uv_round", 1, 0).C(";\n"); + p.C(" highp vec4 t2 = ").SampleTexture2DOffset("tex", "uv_round", 0, 1).C(";\n"); + p.C(" highp vec4 t3 = ").SampleTexture2DOffset("tex", "uv_round", 1, 1).C(";\n"); WRITE(p, " uint depalMask = (u_depal_mask_shift_off_fmt & 0xFFU);\n"); WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n"); WRITE(p, " uint depalOffset = ((u_depal_mask_shift_off_fmt >> 16) & 0xFFU) << 4;\n"); @@ -708,14 +714,14 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " break;\n"); WRITE(p, " };\n"); WRITE(p, " index0 = ((index0 >> depalShift) & depalMask) | depalOffset;\n"); - WRITE(p, " t = texelFetch(pal, ivec2(index0, 0), 0);\n"); + p.C(" t = ").LoadTexture2D("pal", "ivec2(index0, 0)", 0).C(";\n"); WRITE(p, " if (bilinear && !(index0 == index1 && index1 == index2 && index2 == index3)) {\n"); WRITE(p, " index1 = ((index1 >> depalShift) & depalMask) | depalOffset;\n"); WRITE(p, " index2 = ((index2 >> depalShift) & depalMask) | depalOffset;\n"); WRITE(p, " index3 = ((index3 >> depalShift) & depalMask) | depalOffset;\n"); - WRITE(p, " t1 = texelFetch(pal, ivec2(index1, 0), 0);\n"); - WRITE(p, " t2 = texelFetch(pal, ivec2(index2, 0), 0);\n"); - WRITE(p, " t3 = texelFetch(pal, ivec2(index3, 0), 0);\n"); + p.C(" t1 = ").LoadTexture2D("pal", "ivec2(index1, 0)", 0).C(";\n"); + p.C(" t2 = ").LoadTexture2D("pal", "ivec2(index2, 0)", 0).C(";\n"); + p.C(" t3 = ").LoadTexture2D("pal", "ivec2(index3, 0)", 0).C(";\n"); WRITE(p, " t = mix(t, t1, fraction.x);\n"); WRITE(p, " t2 = mix(t2, t3, fraction.x);\n"); WRITE(p, " t = mix(t, t2, fraction.y);\n"); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index b5abfbde59..cefc86f4c5 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1924,7 +1924,6 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // TODO: Implement shader depal in the fragment shader generator for D3D11 at least. switch (draw_->GetShaderLanguageDesc().shaderLanguage) { - case ShaderLanguage::HLSL_D3D11: case ShaderLanguage::HLSL_D3D9: useShaderDepal = false; break; diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index d8a68c5f14..9fd4c64a48 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -26,13 +26,14 @@ std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeS std::string errors; if (errorMsgs) { errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); + std::string numberedCode = LineNumberString(code); if (SUCCEEDED(result)) { WARN_LOG(G3D, "%s: %s", "warnings", errors.c_str()); } else { - ERROR_LOG(G3D, "%s: %s", "errors", errors.c_str()); + ERROR_LOG(G3D, "%s: %s\n\n%s", "errors", errors.c_str(), numberedCode.c_str()); } - OutputDebugStringA(LineNumberString(code).c_str()); OutputDebugStringA(errors.c_str()); + OutputDebugStringA(numberedCode.c_str()); errorMsgs->Release(); } if (compiledCode) { diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 2563825ea1..c656f3d7dd 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -180,8 +180,8 @@ void TextureCacheD3D11::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { void TextureCacheD3D11::ForgetLastTexture() { InvalidateLastTexture(); - ID3D11ShaderResourceView *nullTex[2]{}; - context_->PSSetShaderResources(0, 2, nullTex); + ID3D11ShaderResourceView *nullTex[4]{}; + context_->PSSetShaderResources(0, 4, nullTex); } void TextureCacheD3D11::InvalidateLastTexture() { @@ -258,6 +258,7 @@ void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) { SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry); ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey); context_->PSSetSamplers(0, 1, &state); + gstate_c.SetUseShaderDepal(false, false); } void TextureCacheD3D11::ApplySamplingParams(const SamplerCacheKey &key) { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 2780fa7799..69bd1384ca 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -184,13 +184,13 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, availableUniforms = vs->GetUniformMask() | fs->GetUniformMask(); std::vector initialize; - initialize.push_back({ &u_tex, 0, 0 }); - initialize.push_back({ &u_fbotex, 0, 1 }); - initialize.push_back({ &u_testtex, 0, 2 }); - initialize.push_back({ &u_pal, 0, 3 }); // CLUT - initialize.push_back({ &u_tess_points, 0, 4 }); // Control Points - initialize.push_back({ &u_tess_weights_u, 0, 5 }); - initialize.push_back({ &u_tess_weights_v, 0, 6 }); + initialize.push_back({ &u_tex, 0, TEX_SLOT_PSP_TEXTURE }); + initialize.push_back({ &u_fbotex, 0, TEX_SLOT_SHADERBLEND_SRC }); + initialize.push_back({ &u_testtex, 0, TEX_SLOT_ALPHATEST }); + initialize.push_back({ &u_pal, 0, TEX_SLOT_CLUT }); // CLUT + initialize.push_back({ &u_tess_points, 0, TEX_SLOT_SPLINE_POINTS }); // Control Points + initialize.push_back({ &u_tess_weights_u, 0, TEX_SLOT_SPLINE_WEIGHTS_U }); + initialize.push_back({ &u_tess_weights_v, 0, TEX_SLOT_SPLINE_WEIGHTS_V }); bool useDualSource = (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0; bool useClip0 = VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE);