mirror of https://github.com/PCSX2/pcsx2.git
GS-TC: Fix bugs with target resize and borders in texture min max
This commit is contained in:
parent
1175bd822c
commit
d880f8cde5
|
@ -3484,6 +3484,12 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||||
if (linear)
|
if (linear)
|
||||||
{
|
{
|
||||||
st += GSVector4(-0.5f, 0.5f).xxyy();
|
st += GSVector4(-0.5f, 0.5f).xxyy();
|
||||||
|
|
||||||
|
// If it's the start of the texture and our little adjustment is all that pushed it over, clamp it to 0.
|
||||||
|
// This stops the border check failing when using repeat but needed less than the full texture
|
||||||
|
// since this was making it take the full texture even though it wasn't needed.
|
||||||
|
if (((m_vt.m_min.t == GSVector4::zero()).mask() & 0x3) == 0x3)
|
||||||
|
st = st.max(GSVector4::zero());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1957,9 +1957,9 @@ void GSRendererHW::Draw()
|
||||||
GL_CACHE("Estimated texture region: %u,%u -> %u,%u", MIP_CLAMP.MINU, MIP_CLAMP.MINV, MIP_CLAMP.MAXU + 1,
|
GL_CACHE("Estimated texture region: %u,%u -> %u,%u", MIP_CLAMP.MINU, MIP_CLAMP.MINV, MIP_CLAMP.MAXU + 1,
|
||||||
MIP_CLAMP.MAXV + 1);
|
MIP_CLAMP.MAXV + 1);
|
||||||
}
|
}
|
||||||
|
const bool possible_shuffle = m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 || IsPossibleChannelShuffle();
|
||||||
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage) :
|
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle) :
|
||||||
g_texture_cache->LookupSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr);
|
g_texture_cache->LookupSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, possible_shuffle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate size based on the scissor rectangle and height cache.
|
// Estimate size based on the scissor rectangle and height cache.
|
||||||
|
|
|
@ -149,6 +149,30 @@ void GSTextureCache::AddDirtyRectTarget(Target* target, GSVector4i rect, u32 psm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GSTextureCache::ResizeTarget(Target* t, GSVector4i rect, u32 tbp, u32 psm, u32 tbw)
|
||||||
|
{
|
||||||
|
// Valid area isn't the whole texture anyway, no point in expanding.
|
||||||
|
if (t->m_valid.z < t->m_unscaled_size.x || t->m_valid.w < t->m_unscaled_size.y)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const GSVector2i size_delta = { std::max(0, (rect.z - t->m_valid.z)), std::max(0, (rect.w - t->m_valid.w)) };
|
||||||
|
// If it's 1 row, it's probably the texture bounds accounting for bilinear, ignore it.
|
||||||
|
if (size_delta.x > 1 || size_delta.y > 1)
|
||||||
|
{
|
||||||
|
RGBAMask rgba;
|
||||||
|
rgba._u32 = GSUtil::GetChannelMask(t->m_TEX0.PSM);
|
||||||
|
// Dirty the expanded areas.
|
||||||
|
AddDirtyRectTarget(t, GSVector4i(t->m_valid.x, t->m_valid.w, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w + std::max(0, size_delta.y)), t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||||
|
AddDirtyRectTarget(t, GSVector4i(t->m_valid.z, t->m_valid.y, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w), t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||||
|
const GSVector4i valid_rect = { t->m_valid.x, t->m_valid.y, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w + std::max(0, size_delta.y) };
|
||||||
|
t->UpdateValidity(valid_rect);
|
||||||
|
t->UpdateValidBits(GSLocalMemory::m_psm[t->m_TEX0.PSM].fmsk);
|
||||||
|
GetTargetSize(tbp, tbw, psm, t->m_valid.z, t->m_valid.w);
|
||||||
|
const int new_w = std::max(t->m_unscaled_size.x, t->m_valid.z);
|
||||||
|
const int new_h = std::max(t->m_unscaled_size.y, t->m_valid.w);
|
||||||
|
t->ResizeTexture(new_w, new_h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GSTextureCache::CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 dbp, u32 dpsm, u32 dbw)
|
bool GSTextureCache::CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 dbp, u32 dpsm, u32 dbw)
|
||||||
|
@ -550,7 +574,7 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, bool palette)
|
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, bool palette)
|
||||||
{
|
{
|
||||||
if (GSConfig.UserHacks_DisableDepthSupport)
|
if (GSConfig.UserHacks_DisableDepthSupport)
|
||||||
{
|
{
|
||||||
|
@ -707,7 +731,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is a bit of a worry, since it could load junk from local memory... but it's better than skipping the draw.
|
// This is a bit of a worry, since it could load junk from local memory... but it's better than skipping the draw.
|
||||||
return LookupSource(TEX0, TEXA, CLAMP, r, nullptr);
|
return LookupSource(TEX0, TEXA, CLAMP, r, nullptr, possible_shuffle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(src->m_texture);
|
ASSERT(src->m_texture);
|
||||||
|
@ -716,7 +740,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod)
|
GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle)
|
||||||
{
|
{
|
||||||
GL_CACHE("TC: Lookup Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z, r.w, TEX0.TBP0, psm_str(TEX0.PSM), TEX0.TBW, TEX0.CBP, 1 << TEX0.TW, 1 << TEX0.TH);
|
GL_CACHE("TC: Lookup Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z, r.w, TEX0.TBP0, psm_str(TEX0.PSM), TEX0.TBW, TEX0.CBP, 1 << TEX0.TW, 1 << TEX0.TH);
|
||||||
|
|
||||||
|
@ -789,10 +813,11 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||||
// We can render to the target as C32, but mask alpha, in which case, pretend like it doesn't have any.
|
// We can render to the target as C32, but mask alpha, in which case, pretend like it doesn't have any.
|
||||||
const u32 t_psm = t->m_valid_alpha ? t->m_TEX0.PSM & ~0x1 : ((t->m_TEX0.PSM == PSMCT32) ? PSMCT24 : t->m_TEX0.PSM);
|
const u32 t_psm = t->m_valid_alpha ? t->m_TEX0.PSM & ~0x1 : ((t->m_TEX0.PSM == PSMCT32) ? PSMCT24 : t->m_TEX0.PSM);
|
||||||
bool rect_clean = GSUtil::HasSameSwizzleBits(psm, t_psm);
|
bool rect_clean = GSUtil::HasSameSwizzleBits(psm, t_psm);
|
||||||
|
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
|
||||||
if (rect_clean && bp >= t->m_TEX0.TBP0 && bp < t->UnwrappedEndBlock() && !t->m_dirty.empty() &&
|
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
|
||||||
(std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
|
const bool tex_overlaps = bp >= t->m_TEX0.TBP0 && bp < t->UnwrappedEndBlock();
|
||||||
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX()))
|
const bool real_fmt_match = (GSLocalMemory::m_psm[psm].trbpp == 16) == (t->m_32_bits_fmt == false);
|
||||||
|
if (rect_clean && tex_overlaps && !t->m_dirty.empty() && width_match)
|
||||||
{
|
{
|
||||||
GSVector4i new_rect = r;
|
GSVector4i new_rect = r;
|
||||||
bool partial = false;
|
bool partial = false;
|
||||||
|
@ -871,31 +896,24 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||||
const u32 channels = t->m_dirty.GetDirtyChannels() & channel_mask;
|
const u32 channels = t->m_dirty.GetDirtyChannels() & channel_mask;
|
||||||
|
|
||||||
// If the source is reading the rt, make sure it's big enough.
|
// If the source is reading the rt, make sure it's big enough.
|
||||||
if (t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM))
|
if (!possible_shuffle && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && real_fmt_match)
|
||||||
{
|
{
|
||||||
const GSVector2i size_delta = { (new_rect.z - t->m_valid.z), (new_rect.w - t->m_valid.w) };
|
if (t->Overlaps(bp, bw, psm, new_rect))
|
||||||
if (size_delta.x > 0 || size_delta.y > 0)
|
ResizeTarget(t, new_rect, bp, psm, bw);
|
||||||
{
|
|
||||||
RGBAMask rgba;
|
|
||||||
rgba._u32 = GSUtil::GetChannelMask(t->m_TEX0.PSM);
|
|
||||||
// Dirty the expanded areas.
|
|
||||||
AddDirtyRectTarget(t, GSVector4i(t->m_valid.x, t->m_valid.w, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w + std::max(0, size_delta.y)), t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
|
||||||
AddDirtyRectTarget(t, GSVector4i(t->m_valid.z, t->m_valid.y, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w + std::max(0, size_delta.y)), t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
|
||||||
const GSVector4i valid_rect = { t->m_valid.x, t->m_valid.y, t->m_valid.z + std::max(0, size_delta.x), t->m_valid.w + std::max(0, size_delta.y) };
|
|
||||||
t->UpdateValidity(valid_rect);
|
|
||||||
t->UpdateValidBits(GSLocalMemory::m_psm[t->m_TEX0.PSM].fmsk);
|
|
||||||
GetTargetSize(TEX0.TBP0, TEX0.TBW, TEX0.PSM, t->m_valid.z, t->m_valid.w);
|
|
||||||
const int new_w = std::max(t->m_unscaled_size.x, t->m_valid.z);
|
|
||||||
const int new_h = std::max(t->m_unscaled_size.y, t->m_valid.w);
|
|
||||||
t->ResizeTexture(new_w, new_h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If not all channels are clean/dirty or only part of the rect is dirty, we need to update the target.
|
// If not all channels are clean/dirty or only part of the rect is dirty, we need to update the target.
|
||||||
if (((channels & channel_mask) != channel_mask || partial))
|
if (((channels & channel_mask) != channel_mask || partial))
|
||||||
t->Update(false);
|
t->Update(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
rect_clean = t->m_dirty.empty();
|
rect_clean = t->m_dirty.empty();
|
||||||
|
if (!possible_shuffle && rect_clean && bp == t->m_TEX0.TBP0 && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && width_match && real_fmt_match)
|
||||||
|
{
|
||||||
|
if(t->Overlaps(bp, bw, psm, r))
|
||||||
|
ResizeTarget(t, r, bp, psm, bw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bool t_clean = ((t->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(psm)) == 0) || rect_clean;
|
const bool t_clean = ((t->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(psm)) == 0) || rect_clean;
|
||||||
|
|
||||||
|
@ -1117,11 +1135,11 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||||
GIFRegTEX0 depth_TEX0;
|
GIFRegTEX0 depth_TEX0;
|
||||||
depth_TEX0.U32[0] = TEX0.U32[0] | (0x30u << 20u);
|
depth_TEX0.U32[0] = TEX0.U32[0] | (0x30u << 20u);
|
||||||
depth_TEX0.U32[1] = TEX0.U32[1];
|
depth_TEX0.U32[1] = TEX0.U32[1];
|
||||||
return LookupDepthSource(depth_TEX0, TEXA, CLAMP, r);
|
return LookupDepthSource(depth_TEX0, TEXA, CLAMP, r, possible_shuffle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return LookupDepthSource(TEX0, TEXA, CLAMP, r, true);
|
return LookupDepthSource(TEX0, TEXA, CLAMP, r, possible_shuffle, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,6 +438,7 @@ public:
|
||||||
void RemoveAll();
|
void RemoveAll();
|
||||||
void ReadbackAll();
|
void ReadbackAll();
|
||||||
void AddDirtyRectTarget(Target* target, GSVector4i rect, u32 psm, u32 bw, RGBAMask rgba, bool req_linear = false);
|
void AddDirtyRectTarget(Target* target, GSVector4i rect, u32 psm, u32 bw, RGBAMask rgba, bool req_linear = false);
|
||||||
|
void ResizeTarget(Target* t, GSVector4i rect, u32 tbp, u32 psm, u32 tbw);
|
||||||
bool FullRectDirty(Target* target);
|
bool FullRectDirty(Target* target);
|
||||||
bool CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 dbp, u32 dpsm, u32 dbw);
|
bool CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 dbp, u32 dpsm, u32 dbw);
|
||||||
GSVector4i TranslateAlignedRectByPage(Target* t, u32 sbp, u32 spsm, u32 sbw, GSVector4i src_r, bool is_invalidation = false);
|
GSVector4i TranslateAlignedRectByPage(Target* t, u32 sbp, u32 spsm, u32 sbw, GSVector4i src_r, bool is_invalidation = false);
|
||||||
|
@ -446,8 +447,8 @@ public:
|
||||||
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
|
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);
|
||||||
std::shared_ptr<Palette> LookupPaletteObject(u16 pal, bool need_gs_texture);
|
std::shared_ptr<Palette> LookupPaletteObject(u16 pal, bool need_gs_texture);
|
||||||
|
|
||||||
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod);
|
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const GSVector2i* lod, const bool possible_shuffle);
|
||||||
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, bool palette = false);
|
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, bool palette = false);
|
||||||
|
|
||||||
Target* FindTargetOverlap(u32 bp, u32 end_block, int type, int psm);
|
Target* FindTargetOverlap(u32 bp, u32 end_block, int type, int psm);
|
||||||
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
|
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
|
||||||
|
|
Loading…
Reference in New Issue