diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index fda8d53639..4d74670013 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -685,7 +685,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } WRITE(p, " vec2 tsize = vec2(textureSize(tex, 0).xy);\n"); WRITE(p, " vec2 fraction;\n"); - WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 0x2Fu) != 0x0u;\n"); + WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 0x1Fu) != 0x0u;\n"); WRITE(p, " if (bilinear) {\n"); WRITE(p, " uv_round = uv * tsize - vec2(0.5, 0.5);\n"); WRITE(p, " fraction = fract(uv_round);\n"); @@ -694,6 +694,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, " uv_round = uv;\n"); WRITE(p, " }\n"); + // TODO: Use fetch here when possible. 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"); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 211b6843a0..e56122ad26 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -944,7 +944,7 @@ Draw2DPipeline *FramebufferManagerCommon::GetReinterpretPipeline(GEBufferFormat Draw2DPipeline *pipeline = reinterpretFromTo_[(int)from][(int)to]; if (!pipeline) { - pipeline = draw2D_.Create2DPipeline([=](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo { + pipeline = draw2D_.Create2DPipeline([from, to](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo { return GenerateReinterpretFragmentShader(shaderWriter, from, to); }); reinterpretFromTo_[(int)from][(int)to] = pipeline; diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 5c75c79b9a..a382b59f0b 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -193,9 +193,24 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe int indexOffset = gstate.getClutIndexStartPos() >> 4; int format = gstate_c.depalTextureFormat; uint32_t val = BytesToUint32(indexMask, indexShift, indexOffset, format); - // Poke in a bilinear filter flag in the top bit. - if (gstate.isMagnifyFilteringEnabled()) + // NOTE: This must follow similar logic to TextureCacheCommon::GetSamplingParams - + // maybe we can share it somehow. + // TOOD: Handle replaced textures. + bool bilinear = gstate.isMagnifyFilteringEnabled() && !gstate_c.pixelMapped; + switch (g_Config.iTexFiltering) { + case TEX_FILTER_FORCE_NEAREST: + bilinear = false; + break; + case TEX_FILTER_FORCE_LINEAR: + bilinear = true; + break; + default: + break; + } + if (bilinear) { + // Poke in a bilinear filter flag in the top bit. val |= 0x80000000; + } ub->depal_mask_shift_off_fmt = val; } } diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 0bd6347ae4..fa069d030b 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -669,7 +669,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (hasClutGPU) { WARN_LOG_N_TIMES(clutUseRender, 5, Log::G3D, "Using texture with dynamic CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); - entry->status |= TexStatus::CLUT_GPU; + entry->status |= TexStatus::CLUT_GPU | TexStatus::CLUT8_INDEXED; } if (hasClut && clutRenderAddress_ == 0xFFFFFFFF) { @@ -691,6 +691,8 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { } nextNeedsChange_ = false; + } else { + // We had an entry already, modify it. } // We have to decode it, let's setup the cache entry first. @@ -704,6 +706,14 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { entry->cluthash = cluthash; + /* + if (entry->maxLevel == 0 && (entry->format == GE_TFMT_CLUT8 || entry->format == GE_TFMT_CLUT4) && + !(entry->status & TexStatus::TO_REPLACE) && !(entry->status & TexStatus::TO_SCALE) && !(entry->status & TexStatus::RELIABLE)) { + // Experiment with CLUT8 decoding for regular textures. + entry->status |= TexStatus::CLUT8_INDEXED; + } + */ + gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0); @@ -720,7 +730,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { nextTexture_ = entry; nextFramebufferTexture_ = nullptr; nextNeedsRehash_ = true; - // We still need to rebuild, to allocate a texture. But we'll bail early. nextNeedsRebuild_ = true; return entry; } @@ -2216,16 +2225,16 @@ void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) { } gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0); + entry->lastFrame = gpuStats.totals.numFlips; if (entry->status & TexStatus::CLUT_GPU) { + _dbg_assert_(entry->status & TexStatus::CLUT8_INDEXED); // Special process. - ApplyTextureDepal(entry); - entry->lastFrame = gpuStats.totals.numFlips; + ApplyTextureDepalFramebufferCLUT(entry); gstate_c.SetTextureSolidAlpha(false); gstate_c.SetTextureIs3D(false); gstate_c.SetTextureIsArray(false); gstate_c.SetTextureIsBGRA(false); } else { - entry->lastFrame = gpuStats.totals.numFlips; if (doBind) { BindTexture(entry, flatZ); } @@ -2233,7 +2242,15 @@ void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) { gstate_c.SetTextureIs3D((entry->status & TexStatus::IS_3D) != 0); gstate_c.SetTextureIsArray(false); gstate_c.SetTextureIsBGRA((entry->status & TexStatus::BGRA) != 0); - gstate_c.SetShaderDepal(ShaderDepalMode::OFF); + if (entry->status & TexStatus::CLUT8_INDEXED) { + bool smoothedDepal = false; + u32 depthUpperBits = 0; + ClutTexture clutTexture = clutTextureCache_.GetClutTexture(gstate.getClutPaletteFormat(), clutHash_, clutBuf_); + BindAsClutTexture(clutTexture.texture, false); + gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8); + } else { + gstate_c.SetShaderDepal(ShaderDepalMode::OFF); + } } } @@ -2474,7 +2491,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer } // Applies depal to a normal (non-framebuffer) texture, pre-decoded to CLUT8 format. -void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) { +void TextureCacheCommon::ApplyTextureDepalFramebufferCLUT(TexCacheEntry *entry) { uint32_t clutMode = gstate.clutformat & 0xFFFFFF; switch (entry->format) { @@ -2881,7 +2898,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt } bool canReplace = !isPPGETexture; - if (entry->status & TexStatus::CLUT_GPU) { + if (entry->status & TexStatus::CLUT8_INDEXED) { _dbg_assert_(entry->format == GE_TFMT_CLUT4 || entry->format == GE_TFMT_CLUT8); plan.decodeToClut8 = true; // We only support 1 mip level when doing CLUT on GPU for now. @@ -3001,7 +3018,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, s if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || dstFmt == Draw::DataFormat::R8G8B8A8_UNORM) { texDecFlags |= TexDecodeFlags::EXPAND32; } - if (entry.status & (TexStatus::CLUT_GPU | TexStatus::CLUT8_INDEXED)) { + if (entry.status & TexStatus::CLUT8_INDEXED) { _dbg_assert_(entry.format == GE_TFMT_CLUT4 || entry.format == GE_TFMT_CLUT8); texDecFlags |= TexDecodeFlags::TO_CLUT8; } @@ -3080,6 +3097,9 @@ std::string TexStatusToString(TexStatus status) { if (status & TexStatus::CLUT_GPU) { result += "CLUT_GPU "; } + if (status & TexStatus::CLUT8_INDEXED) { + result += "CLUT8_INDEXED "; + } if (status & TexStatus::FORCE_REBUILD) { result += "FORCE_REBUILD "; } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 8804620089..98ccdc724f 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -404,7 +404,7 @@ protected: void Decimate(TexCacheEntry *exceptThisOne, bool forcePressure); // forcePressure defaults to false. void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel); - void ApplyTextureDepal(TexCacheEntry *entry); + void ApplyTextureDepalFramebufferCLUT(TexCacheEntry *entry); void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete); virtual void BuildTexture(TexCacheEntry *const entry) = 0; diff --git a/GPU/GeConstants.cpp b/GPU/GeConstants.cpp index 6cb9bfd361..ce0037cd6b 100644 --- a/GPU/GeConstants.cpp +++ b/GPU/GeConstants.cpp @@ -287,6 +287,7 @@ const char *GeBufferFormatToString(GEBufferFormat fmt) { case GE_FORMAT_565: return "565"; case GE_FORMAT_8888: return "8888"; case GE_FORMAT_DEPTH16: return "DEPTH16"; + case GE_FORMAT_CLUT8: return "CLUT8"; default: return "N/A"; } } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index e0852bbd6c..43f3b82b23 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -958,7 +958,7 @@ void TextureCacheVulkan::LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *w if (!gstate_c.Use(GPU_USE_16BIT_FORMATS) || scaleFactor > 1 || dstFmt == VULKAN_8888_FORMAT) { texDecFlags |= TexDecodeFlags::EXPAND32; } - if (entry.status & TexStatus::CLUT_GPU) { + if (entry.status & TexStatus::CLUT8_INDEXED) { texDecFlags |= TexDecodeFlags::TO_CLUT8; }