From 6fc1202c2894bbde2b12f3dbfb42b04073367825 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Tue, 4 Oct 2022 22:53:22 +0100 Subject: [PATCH] GS: Modify clamp behaviour on large specified texture sizes Add temp logging --- pcsx2/GS/GSDrawingContext.cpp | 34 +++++++-- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 102 ++++++++++++++----------- pcsx2/GS/Renderers/SW/GSRendererSW.cpp | 21 +++-- 3 files changed, 99 insertions(+), 58 deletions(-) diff --git a/pcsx2/GS/GSDrawingContext.cpp b/pcsx2/GS/GSDrawingContext.cpp index bcb71e91cfa89..a73b50b02346c 100644 --- a/pcsx2/GS/GSDrawingContext.cpp +++ b/pcsx2/GS/GSDrawingContext.cpp @@ -20,10 +20,17 @@ static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv) { - // return max possible texcoord - + // return max possible texcoord. int uv = br; + // Confirmed on hardware if the size exceeds 1024, it basically gets masked so you end up with a 1x1 pixel (Except Region Clamp). + if (limit > 1024) + { + if (wm != CLAMP_REGION_CLAMP) // TEMPLOG + Console.Warning("Masking TEX0 to 1x1 was %d", limit + 1); + limit = 0; + } + if (wm == CLAMP_CLAMP) { if (uv > limit) @@ -45,10 +52,14 @@ static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv) } else if (wm == CLAMP_REGION_REPEAT) { + // REGION_REPEAT adhears to the original texture size, even if offset outside the texture (with MAXUV). + if (limit < minuv) // TEMPLOG + Console.Warning("Limiting minuv, limit %x minuv from %x to %x", limit, minuv, minuv & limit); + minuv &= limit; if (tl < 0) - uv = minuv | maxuv; // wrap around, just use (any & mask) | fix + uv = minuv | maxuv; // wrap around, just use (any & mask) | fix. else - uv = std::min(uv, minuv) | maxuv; // (any & mask) cannot be larger than mask, select br if that is smaller (not br & mask because there might be a larger value between tl and br when &'ed with the mask) + uv = std::min(uv, minuv) | maxuv; // (any & mask) cannot be larger than mask, select br if that is smaller (not br & mask because there might be a larger value between tl and br when &'ed with the mask). } return uv; @@ -122,8 +133,13 @@ GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(const GSVector4& st, bool linear, GIFRegTEX0 res = TEX0; - res.TW = std::clamp(tw, 0, 10); - res.TH = std::clamp(th, 0, 10); + if (tw > 10) // TEMPLOG + Console.Warning("Limiting Width to 1"); + if (th > 10) // TEMPLOG + Console.Warning("Limiting Height to 1"); + + res.TW = tw > 10 ? 0 : tw; + res.TH = th > 10 ? 0 : th; if (GSConfig.Renderer == GSRendererType::SW && (TEX0.TW != res.TW || TEX0.TH != res.TH)) { @@ -153,6 +169,12 @@ void GSDrawingContext::ComputeFixedTEX0(const GSVector4& st) int maxu = (int)CLAMP.MAXU; int maxv = (int)CLAMP.MAXV; + if (wms != CLAMP_REGION_CLAMP) + tw = tw > 10 ? 0 : tw; + + if (wmt != CLAMP_REGION_CLAMP) + th = th > 10 ? 0 : th; + GSVector4i uv = GSVector4i(st.floor().xyzw(st.ceil())); uv.x = findmax(uv.x, uv.z, (1 << tw) - 1, wms, minu, maxu); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 3816b038100b7..1810582d99c24 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -4074,59 +4074,69 @@ bool GSRendererHW::SwPrimRender() } } - const u16 tw = 1u << TEX0.TW; - const u16 th = 1u << TEX0.TH; + u16 tw = 1u << TEX0.TW; + u16 th = 1u << TEX0.TH; + + if (tw > 1024) + tw = 1; + + if (th > 1024) + th = 1; switch (context->CLAMP.WMS) { - case CLAMP_REPEAT: - gd.t.min.U16[0] = gd.t.minmax.U16[0] = tw - 1; - gd.t.max.U16[0] = gd.t.minmax.U16[2] = 0; - gd.t.mask.U32[0] = 0xffffffff; - break; - case CLAMP_CLAMP: - gd.t.min.U16[0] = gd.t.minmax.U16[0] = 0; - gd.t.max.U16[0] = gd.t.minmax.U16[2] = tw - 1; - gd.t.mask.U32[0] = 0; - break; - case CLAMP_REGION_CLAMP: - gd.t.min.U16[0] = gd.t.minmax.U16[0] = std::min(context->CLAMP.MINU, tw - 1); - gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min(context->CLAMP.MAXU, tw - 1); - gd.t.mask.U32[0] = 0; - break; - case CLAMP_REGION_REPEAT: - gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU & (tw - 1); - gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU & (tw - 1); - gd.t.mask.U32[0] = 0xffffffff; - break; - default: - __assume(0); + case CLAMP_REPEAT: + gd.t.min.U16[0] = gd.t.minmax.U16[0] = tw - 1; + gd.t.max.U16[0] = gd.t.minmax.U16[2] = 0; + gd.t.mask.U32[0] = 0xffffffff; + break; + case CLAMP_CLAMP: + gd.t.min.U16[0] = gd.t.minmax.U16[0] = 0; + gd.t.max.U16[0] = gd.t.minmax.U16[2] = tw - 1; + gd.t.mask.U32[0] = 0; + break; + case CLAMP_REGION_CLAMP: + // REGION_CLAMP ignores the actual texture size + gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU; + gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU; + gd.t.mask.U32[0] = 0; + break; + case CLAMP_REGION_REPEAT: + // MINU is restricted to MINU or texture size, whichever is smaller, MAXU is an offset in the texture. + gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU & (tw - 1); + gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU; + gd.t.mask.U32[0] = 0xffffffff; + break; + default: + __assume(0); } switch (context->CLAMP.WMT) { - case CLAMP_REPEAT: - gd.t.min.U16[4] = gd.t.minmax.U16[1] = th - 1; - gd.t.max.U16[4] = gd.t.minmax.U16[3] = 0; - gd.t.mask.U32[2] = 0xffffffff; - break; - case CLAMP_CLAMP: - gd.t.min.U16[4] = gd.t.minmax.U16[1] = 0; - gd.t.max.U16[4] = gd.t.minmax.U16[3] = th - 1; - gd.t.mask.U32[2] = 0; - break; - case CLAMP_REGION_CLAMP: - gd.t.min.U16[4] = gd.t.minmax.U16[1] = std::min(context->CLAMP.MINV, th - 1); - gd.t.max.U16[4] = gd.t.minmax.U16[3] = std::min(context->CLAMP.MAXV, th - 1); // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) - gd.t.mask.U32[2] = 0; - break; - case CLAMP_REGION_REPEAT: - gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV & (th - 1); // skygunner main menu water texture 64x64, MINV = 127 - gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV & (th - 1); - gd.t.mask.U32[2] = 0xffffffff; - break; - default: - __assume(0); + case CLAMP_REPEAT: + gd.t.min.U16[4] = gd.t.minmax.U16[1] = th - 1; + gd.t.max.U16[4] = gd.t.minmax.U16[3] = 0; + gd.t.mask.U32[2] = 0xffffffff; + break; + case CLAMP_CLAMP: + gd.t.min.U16[4] = gd.t.minmax.U16[1] = 0; + gd.t.max.U16[4] = gd.t.minmax.U16[3] = th - 1; + gd.t.mask.U32[2] = 0; + break; + case CLAMP_REGION_CLAMP: + // REGION_CLAMP ignores the actual texture size + gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV; + gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV; // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) + gd.t.mask.U32[2] = 0; + break; + case CLAMP_REGION_REPEAT: + // MINV is restricted to MINV or texture size, whichever is smaller, MAXV is an offset in the texture. + gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV & (th - 1); // skygunner main menu water texture 64x64, MINV = 127 + gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV; + gd.t.mask.U32[2] = 0xffffffff; + break; + default: + __assume(0); } gd.t.min = gd.t.min.xxxxlh(); diff --git a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp index b46889f19e037..4aaa583887365 100644 --- a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp +++ b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp @@ -1211,6 +1211,11 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) u16 tw = 1u << TEX0.TW; u16 th = 1u << TEX0.TH; + if (tw > 1024) + tw = 1; + if (th > 1024) + th = 1; + switch (context->CLAMP.WMS) { case CLAMP_REPEAT: @@ -1224,13 +1229,15 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) gd.t.mask.U32[0] = 0; break; case CLAMP_REGION_CLAMP: - gd.t.min.U16[0] = gd.t.minmax.U16[0] = std::min(context->CLAMP.MINU, tw - 1); - gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min(context->CLAMP.MAXU, tw - 1); + // REGION_CLAMP ignores the actual texture size + gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU; + gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU; gd.t.mask.U32[0] = 0; break; case CLAMP_REGION_REPEAT: + // MINU is restricted to MINU or texture size, whichever is smaller, MAXU is an offset in the texture (Can be bigger than the texture). gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU & (tw - 1); - gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU & (tw - 1); + gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU; gd.t.mask.U32[0] = 0xffffffff; break; default: @@ -1250,13 +1257,15 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data) gd.t.mask.U32[2] = 0; break; case CLAMP_REGION_CLAMP: - gd.t.min.U16[4] = gd.t.minmax.U16[1] = std::min(context->CLAMP.MINV, th - 1); - gd.t.max.U16[4] = gd.t.minmax.U16[3] = std::min(context->CLAMP.MAXV, th - 1); // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) + // REGION_CLAMP ignores the actual texture size + gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV; + gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV; // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) gd.t.mask.U32[2] = 0; break; case CLAMP_REGION_REPEAT: + // MINV is restricted to MINV or texture size, whichever is smaller, MAXV is an offset in the texture (Can be bigger than the texture). gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV & (th - 1); // skygunner main menu water texture 64x64, MINV = 127 - gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV & (th - 1); + gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV; gd.t.mask.U32[2] = 0xffffffff; break; default: