Skip to content

Commit

Permalink
GS: Modify clamp behaviour on large specified texture sizes
Browse files Browse the repository at this point in the history
Add temp logging
  • Loading branch information
refractionpcsx2 committed Oct 8, 2022
1 parent cadc49d commit 6fc1202
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 58 deletions.
34 changes: 28 additions & 6 deletions pcsx2/GS/GSDrawingContext.cpp
Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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);
Expand Down
102 changes: 56 additions & 46 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Expand Up @@ -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<u16>(context->CLAMP.MINU, tw - 1);
gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min<u16>(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<u16>(context->CLAMP.MINV, th - 1);
gd.t.max.U16[4] = gd.t.minmax.U16[3] = std::min<u16>(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();
Expand Down
21 changes: 15 additions & 6 deletions pcsx2/GS/Renderers/SW/GSRendererSW.cpp
Expand Up @@ -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:
Expand All @@ -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<u16>(context->CLAMP.MINU, tw - 1);
gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min<u16>(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:
Expand All @@ -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<u16>(context->CLAMP.MINV, th - 1);
gd.t.max.U16[4] = gd.t.minmax.U16[3] = std::min<u16>(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:
Expand Down

0 comments on commit 6fc1202

Please sign in to comment.