diff --git a/GPU/Common/DepalettizeCommon.h b/GPU/Common/DepalettizeCommon.h index 110d9f2f0636..3c987aa6241a 100644 --- a/GPU/Common/DepalettizeCommon.h +++ b/GPU/Common/DepalettizeCommon.h @@ -40,7 +40,8 @@ class DepalTexture { public: Draw::Texture *texture; int lastFrame; - int rampLength; // How many entries are continuously growing from entry 0. + // How many entries are continuously growing (each value larger than the previous) from entry 0. + int rampLength; }; // Caches both shaders and palette textures. diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index a38e70fd5c69..f278363e5f1f 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -602,6 +602,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } else { WRITE(p, " 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. 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"); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 3ece2359f849..67810e5f8879 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1852,6 +1852,31 @@ bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferFormat) { } } +// If the palette is detected as a smooth ramp, we can interpolate for higher color precision. +// But we only do it if the mask/shift exactly matches a color channel, else something different might be going +// on and we definitely don't want to interpolate. +// Great enhancement for Test Drive. +static bool CanUseSmoothDepal(const GPUgstate &gstate, GEBufferFormat framebufferFormat, int rampLength) { + if (gstate.getClutIndexStartPos() == 0 && + gstate.getClutIndexMask() <= rampLength) { + switch (framebufferFormat) { + case GE_FORMAT_565: + if (gstate.getClutIndexShift() == 0 || gstate.getClutIndexShift() == 11) { + return gstate.getClutIndexMask() == 0x1F; + } else if (gstate.getClutIndexShift() == 5) { + return gstate.getClutIndexMask() == 0x3F; + } + break; + case GE_FORMAT_5551: + if (gstate.getClutIndexShift() == 0 || gstate.getClutIndexShift() == 5 || gstate.getClutIndexShift() == 10) { + return gstate.getClutIndexMask() == 0x1F; + } + break; + } + } + return false; +} + void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel) { DepalShader *depalShader = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; @@ -1894,7 +1919,8 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Since we started/ended render passes, might need these. gstate_c.Dirty(DIRTY_DEPAL); - gstate_c.SetUseShaderDepal(true, gstate.getClutIndexStartPos() == 0 && gstate.getClutIndexMask() <= clutTexture.rampLength); + + gstate_c.SetUseShaderDepal(true, CanUseSmoothDepal(gstate, framebuffer->drawnFormat, clutTexture.rampLength)); gstate_c.depalFramebufferFormat = framebuffer->drawnFormat; const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor;