From 5bab8af38f2df25a727daa3c84f0054c8a34c2ae Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 11 May 2023 23:11:37 +1000 Subject: [PATCH] GS/HW: Rename and improve dirty alpha to valid alpha --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 16 ++++++++++++++-- pcsx2/GS/Renderers/HW/GSRendererHW.h | 2 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 22 +++++++++++++--------- pcsx2/GS/Renderers/HW/GSTextureCache.h | 9 ++++++++- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index efe07465f1..ddedb10b70 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -2069,10 +2069,15 @@ void GSRendererHW::Draw() rt->m_TEX0 = FRAME_TEX0; rt->m_TEX0.TBW = std::max(width, FRAME_TEX0.TBW); } + + rt->UpdateValidAlpha(FRAME_TEX0.PSM, fm); } if (ds) + { ds->m_TEX0 = ZBUF_TEX0; + ds->UpdateValidAlpha(ZBUF_TEX0.PSM, zm); + } } else if (!m_texture_shuffle) { @@ -2082,11 +2087,14 @@ void GSRendererHW::Draw() { rt->m_TEX0.TBW = std::max(rt->m_TEX0.TBW, FRAME_TEX0.TBW); rt->m_TEX0.PSM = FRAME_TEX0.PSM; + + rt->UpdateValidAlpha(FRAME_TEX0.PSM, fm); } if (ds) { ds->m_TEX0.TBW = std::max(ds->m_TEX0.TBW, ZBUF_TEX0.TBW); ds->m_TEX0.PSM = ZBUF_TEX0.PSM; + ds->UpdateValidAlpha(ZBUF_TEX0.PSM, zm); } } if (rt) @@ -2581,7 +2589,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds) } } -void GSRendererHW::EmulateTextureShuffleAndFbmask() +void GSRendererHW::EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt) { // Uncomment to disable texture shuffle emulation. // m_texture_shuffle = false; @@ -2713,6 +2721,10 @@ void GSRendererHW::EmulateTextureShuffleAndFbmask() m_conf.ps.fbmask = 0; } + // Set dirty alpha on target, but only if we're actually writing to it. + if (rt) + rt->m_valid_alpha |= m_conf.colormask.wa; + // Once we draw the shuffle, no more buffering. m_split_texture_shuffle_pages = 0; m_split_texture_shuffle_pages_high = 0; @@ -4230,7 +4242,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta else m_prim_overlap = PRIM_OVERLAP_UNKNOW; - EmulateTextureShuffleAndFbmask(); + EmulateTextureShuffleAndFbmask(rt); // DATE: selection of the algorithm. Must be done before blending because GL42 is not compatible with blending if (DATE) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index bc0a6eb6e4..9275bc4d0c 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -76,7 +76,7 @@ private: void ResetStates(); void SetupIA(float target_scale, float sx, float sy); - void EmulateTextureShuffleAndFbmask(); + void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt); bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only); void EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 4c4393e472..5633b06ef4 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -773,7 +773,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con // because of the previous draw call format // // Solution: consider the RT as 32 bits if the alpha was used in the past - const u32 t_psm = (t->m_dirty_alpha) ? t->m_TEX0.PSM & ~0x1 : t->m_TEX0.PSM; + // 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); bool rect_clean = GSUtil::HasSameSwizzleBits(psm, t_psm); if (rect_clean && bp >= t->m_TEX0.TBP0 && bp < t->UnwrappedEndBlock() && !t->m_dirty.empty() && @@ -1316,9 +1317,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe dst->m_scale = scale; dst->m_unscaled_size = new_size; } - - if (!is_frame) - dst->m_dirty_alpha |= (psm_s.trbpp == 32 && (fbmask & 0xFF000000) != 0xFF000000) || (psm_s.trbpp == 16); } else if (!is_frame && !GSConfig.UserHacks_DisableDepthSupport) { @@ -1509,7 +1507,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe dst->m_used |= used; if (is_frame) - dst->m_dirty_alpha = false; + dst->m_valid_alpha = false; dst->readbacks_since_draw = 0; @@ -1938,7 +1936,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r if (rgba._u32 == 0x8 && t->m_TEX0.PSM == PSMCT32) { t->m_TEX0.PSM = PSMCT24; - t->m_dirty_alpha = false; + t->m_valid_alpha = false; ++i; } else @@ -1964,7 +1962,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r // the texture cache. Otherwise it will generate a wrong // hit on the texture cache. // Game: Conflict - Desert Storm (flickering) - t->m_dirty_alpha = false; + t->m_valid_alpha = false; } ++i; @@ -2645,7 +2643,7 @@ GSTextureCache::Target* GSTextureCache::GetTargetWithSharedBits(u32 BP, u32 PSM) for (auto it = rts.begin(); it != rts.end(); ++it) // Iterate targets from MRU to LRU. { Target* t = *it; - const u32 t_psm = (t->m_dirty_alpha) ? t->m_TEX0.PSM & ~0x1 : t->m_TEX0.PSM; + const u32 t_psm = (t->m_valid_alpha) ? t->m_TEX0.PSM & ~0x1 : t->m_TEX0.PSM; if (GSUtil::HasSharedBits(BP, PSM, t->m_TEX0.TBP0, t_psm)) return t; } @@ -4348,7 +4346,6 @@ GSTextureCache::Target::Target(const GIFRegTEX0& TEX0, const int type) { m_TEX0 = TEX0; m_32_bits_fmt |= (GSLocalMemory::m_psm[TEX0.PSM].trbpp != 16); - m_dirty_alpha = GSLocalMemory::m_psm[TEX0.PSM].trbpp != 24; } GSTextureCache::Target::~Target() @@ -4506,6 +4503,13 @@ void GSTextureCache::Target::UpdateIfDirtyIntersects(const GSVector4i& rc) break; } } + +void GSTextureCache::Target::UpdateValidAlpha(u32 psm, u32 fbmsk) +{ + const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[psm]; + m_valid_alpha |= (psm_s.trbpp == 32 && (fbmsk & 0xFF000000) != 0xFF000000) || (psm_s.trbpp == 16); +} + void GSTextureCache::Target::ResizeDrawn(const GSVector4i& rect) { m_drawn_since_read = m_drawn_since_read.rintersect(rect); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 05bdf5207d..7dd5a65d06 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -208,7 +208,11 @@ public: { public: const int m_type = 0; - bool m_dirty_alpha = true; + + // Valid alpha means "we have rendered to the alpha channel of this target". + // A false value means that the alpha in local memory is still valid/up-to-date. + bool m_valid_alpha = false; + bool m_is_frame = false; bool m_used = false; float OffsetHack_modxy = 0.0f; @@ -233,6 +237,9 @@ public: /// Updates the target, if the dirty area intersects with the specified rectangle. void UpdateIfDirtyIntersects(const GSVector4i& rc); + /// Updates the valid alpha flag, based on PSM and fbmsk. + void UpdateValidAlpha(u32 psm, u32 fbmsk); + /// Resizes target texture, DOES NOT RESCALE. bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true); };