diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 27f21410fc..9bef8e74ff 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -4291,7 +4291,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c if (m_conf.tex == m_conf.rt) { // Can we read the framebuffer directly? (i.e. sample location matches up). - if (CanUseTexIsFB(rt, tex)) + if (CanUseTexIsFB(rt, tex, tmm)) { m_conf.tex = nullptr; m_conf.ps.tex_is_fb = true; @@ -4438,7 +4438,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c m_conf.tex = src_copy; } -bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex) const +bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex, + const TextureMinMaxResult& tmm) const { // Minimum blending or no barriers -> we can't use tex-is-fb. if (GSConfig.AccurateBlendingUnit == AccBlendLevel::Minimum || !g_gs_device->Features().texture_barrier) @@ -4454,6 +4455,36 @@ bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextu return true; } + static constexpr auto check_clamp = [](u32 clamp, u32 min, u32 max, s32 tmin, s32 tmax) { + if (clamp == CLAMP_REGION_CLAMP) + { + if (tmin < static_cast(min) || tmax > static_cast(max + 1)) + { + GL_CACHE("Can't use tex-is-fb because of REGION_CLAMP [%d, %d] with TMM of [%d, %d]", min, max, tmin, tmax); + return false; + } + } + else if (clamp == CLAMP_REGION_REPEAT) + { + const u32 req_tbits = (tmax > 1) ? static_cast(Common::NextPow2(tmax - 1) - 1) : 0x1; + if ((min & req_tbits) != req_tbits) + { + GL_CACHE("Can't use tex-is-fb because of REGION_REPEAT [%d, %d] with TMM of [%d, %d] and tbits of %d", + min, max, tmin, tmax, req_tbits); + return false; + } + } + + return true; + }; + if (!check_clamp( + m_cached_ctx.CLAMP.WMS, m_cached_ctx.CLAMP.MINU, m_cached_ctx.CLAMP.MAXU, tmm.coverage.x, tmm.coverage.z) || + !check_clamp( + m_cached_ctx.CLAMP.WMT, m_cached_ctx.CLAMP.MINV, m_cached_ctx.CLAMP.MAXV, tmm.coverage.y, tmm.coverage.w)) + { + return false; + } + // Texture is actually the frame buffer. Stencil emulation to compute shadow (Jak series/tri-ace game) // Will hit the "m_ps_sel.tex_is_fb = 1" path in the draw if (m_vt.m_primclass == GS_TRIANGLE_CLASS) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index b139828820..43912952b4 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -93,7 +93,8 @@ private: void HandleTextureHazards(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds, const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region, bool& target_region, GSVector2i& unscaled_size, float& scale, GSTexture*& src_copy); - bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex) const; + bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex, + const TextureMinMaxResult& tmm) const; void EmulateZbuffer(const GSTextureCache::Target* ds); void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);