From 61f344dd664a6732397ee90c59673966b038fa6d Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 11 May 2023 22:33:50 +1000 Subject: [PATCH] GS/HW: Handle texture shuffles using region repeat Ace Combat 04 reads RG, writes to RGBA by setting a MINU of 1015. --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 5f9433181f..efe07465f1 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -360,6 +360,20 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba) tex_pos &= 0xFF; read_ba = (tex_pos > 112 && tex_pos < 144); + // Another way of selecting whether to read RG/BA is to use region repeat. + // Ace Combat 04 reads RG, writes to RGBA by setting a MINU of 1015. + if (m_cached_ctx.CLAMP.WMS == CLAMP_REGION_REPEAT) + { + GL_INS("REGION_REPEAT clamp with texture shuffle, FBMSK=%08x, MINU=%u, MINV=%u, MAXU=%u, MAXV=%u", + m_cached_ctx.FRAME.FBMSK, m_cached_ctx.CLAMP.MINU, m_cached_ctx.CLAMP.MINV, m_cached_ctx.CLAMP.MAXU, + m_cached_ctx.CLAMP.MAXV); + + // offset coordinates swap around RG/BA. + const bool invert = read_ba; // (tex_pos > 112 && tex_pos < 144), i.e. 8 fixed point + const u32 minu = (m_cached_ctx.CLAMP.MINU & 8) ^ (invert ? 8 : 0); + read_ba = ((minu & 8) != 0); + } + if (m_split_texture_shuffle_pages > 0) { // Input vertices might be bad, so rewrite them. @@ -2628,7 +2642,19 @@ void GSRendererHW::EmulateTextureShuffleAndFbmask() const u32 fbmask = ((m >> 3) & 0x1F) | ((m >> 6) & 0x3E0) | ((m >> 9) & 0x7C00) | ((m >> 16) & 0x8000); // r = rb mask, g = ga mask const GSVector2i rb_ga_mask = GSVector2i(fbmask & 0xFF, (fbmask >> 8) & 0xFF); - m_conf.colormask.wrgba = 0; + + // Ace Combat 04 sets FBMSK to 0 for the shuffle, duplicating RG across RGBA. + // Given how touchy texture shuffles are, I'm not ready to make it 100% dependent on the real FBMSK yet. + // TODO: Remove this if, and see what breaks. + if (fbmask != 0) + { + m_conf.colormask.wrgba = 0; + } + else + { + m_conf.colormask.wr = m_conf.colormask.wg = (rb_ga_mask.r != 0xFF); + m_conf.colormask.wb = m_conf.colormask.wa = (rb_ga_mask.g != 0xFF); + } // 2 Select the new mask if (rb_ga_mask.r != 0xFF)