Implement shader depal for D3D11.

This commit is contained in:
Henrik Rydgård
2022-09-11 13:27:17 +02:00
parent 35c9cbd6b0
commit 9bd8b11bf8
7 changed files with 84 additions and 40 deletions
+35
View File
@@ -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:
+2
View File
@@ -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.
+34 -28
View File
@@ -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<vec4> 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<vec4> fbotex : register(t1);\n");
}
if (shaderDepal) {
WRITE(p, "SamplerState palSamp : register(s3);\n");
WRITE(p, "Texture2D<vec4> 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");
-1
View File
@@ -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;
+3 -2
View File
@@ -26,13 +26,14 @@ std::vector<uint8_t> 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) {
+3 -2
View File
@@ -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) {
+7 -7
View File
@@ -184,13 +184,13 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
availableUniforms = vs->GetUniformMask() | fs->GetUniformMask();
std::vector<GLRProgram::Initializer> 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);