GS: Modify clamp behaviour on large specified texture sizes

Add temp logging
This commit is contained in:
refractionpcsx2 2022-10-04 22:53:22 +01:00
parent f70da4b33e
commit 96071e157a
3 changed files with 99 additions and 58 deletions

View File

@ -20,10 +20,17 @@
static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv) 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; 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 (wm == CLAMP_CLAMP)
{ {
if (uv > limit) 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) 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) if (tl < 0)
uv = minuv | maxuv; // wrap around, just use (any & mask) | fix uv = minuv | maxuv; // wrap around, just use (any & mask) | fix.
else 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; return uv;
@ -122,8 +133,13 @@ GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(const GSVector4& st, bool linear,
GIFRegTEX0 res = TEX0; GIFRegTEX0 res = TEX0;
res.TW = std::clamp(tw, 0, 10); if (tw > 10) // TEMPLOG
res.TH = std::clamp(th, 0, 10); 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)) 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 maxu = (int)CLAMP.MAXU;
int maxv = (int)CLAMP.MAXV; 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())); GSVector4i uv = GSVector4i(st.floor().xyzw(st.ceil()));
uv.x = findmax(uv.x, uv.z, (1 << tw) - 1, wms, minu, maxu); uv.x = findmax(uv.x, uv.z, (1 << tw) - 1, wms, minu, maxu);

View File

@ -4074,59 +4074,69 @@ bool GSRendererHW::SwPrimRender()
} }
} }
const u16 tw = 1u << TEX0.TW; u16 tw = 1u << TEX0.TW;
const u16 th = 1u << TEX0.TH; u16 th = 1u << TEX0.TH;
if (tw > 1024)
tw = 1;
if (th > 1024)
th = 1;
switch (context->CLAMP.WMS) switch (context->CLAMP.WMS)
{ {
case CLAMP_REPEAT: case CLAMP_REPEAT:
gd.t.min.U16[0] = gd.t.minmax.U16[0] = tw - 1; 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.max.U16[0] = gd.t.minmax.U16[2] = 0;
gd.t.mask.U32[0] = 0xffffffff; gd.t.mask.U32[0] = 0xffffffff;
break; break;
case CLAMP_CLAMP: case CLAMP_CLAMP:
gd.t.min.U16[0] = gd.t.minmax.U16[0] = 0; 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.max.U16[0] = gd.t.minmax.U16[2] = tw - 1;
gd.t.mask.U32[0] = 0; gd.t.mask.U32[0] = 0;
break; break;
case CLAMP_REGION_CLAMP: case CLAMP_REGION_CLAMP:
gd.t.min.U16[0] = gd.t.minmax.U16[0] = std::min<u16>(context->CLAMP.MINU, tw - 1); // REGION_CLAMP ignores the actual texture size
gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min<u16>(context->CLAMP.MAXU, tw - 1); gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU;
gd.t.mask.U32[0] = 0; gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU;
break; gd.t.mask.U32[0] = 0;
case CLAMP_REGION_REPEAT: break;
gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU & (tw - 1); case CLAMP_REGION_REPEAT:
gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU & (tw - 1); // MINU is restricted to MINU or texture size, whichever is smaller, MAXU is an offset in the texture.
gd.t.mask.U32[0] = 0xffffffff; gd.t.min.U16[0] = gd.t.minmax.U16[0] = context->CLAMP.MINU & (tw - 1);
break; gd.t.max.U16[0] = gd.t.minmax.U16[2] = context->CLAMP.MAXU;
default: gd.t.mask.U32[0] = 0xffffffff;
__assume(0); break;
default:
__assume(0);
} }
switch (context->CLAMP.WMT) switch (context->CLAMP.WMT)
{ {
case CLAMP_REPEAT: case CLAMP_REPEAT:
gd.t.min.U16[4] = gd.t.minmax.U16[1] = th - 1; 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.max.U16[4] = gd.t.minmax.U16[3] = 0;
gd.t.mask.U32[2] = 0xffffffff; gd.t.mask.U32[2] = 0xffffffff;
break; break;
case CLAMP_CLAMP: case CLAMP_CLAMP:
gd.t.min.U16[4] = gd.t.minmax.U16[1] = 0; 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.max.U16[4] = gd.t.minmax.U16[3] = th - 1;
gd.t.mask.U32[2] = 0; gd.t.mask.U32[2] = 0;
break; break;
case CLAMP_REGION_CLAMP: case CLAMP_REGION_CLAMP:
gd.t.min.U16[4] = gd.t.minmax.U16[1] = std::min<u16>(context->CLAMP.MINV, th - 1); // REGION_CLAMP ignores the actual texture size
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.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV;
gd.t.mask.U32[2] = 0; 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)
break; gd.t.mask.U32[2] = 0;
case CLAMP_REGION_REPEAT: break;
gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV & (th - 1); // skygunner main menu water texture 64x64, MINV = 127 case CLAMP_REGION_REPEAT:
gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV & (th - 1); // MINV is restricted to MINV or texture size, whichever is smaller, MAXV is an offset in the texture.
gd.t.mask.U32[2] = 0xffffffff; gd.t.min.U16[4] = gd.t.minmax.U16[1] = context->CLAMP.MINV & (th - 1); // skygunner main menu water texture 64x64, MINV = 127
break; gd.t.max.U16[4] = gd.t.minmax.U16[3] = context->CLAMP.MAXV;
default: gd.t.mask.U32[2] = 0xffffffff;
__assume(0); break;
default:
__assume(0);
} }
gd.t.min = gd.t.min.xxxxlh(); gd.t.min = gd.t.min.xxxxlh();

View File

@ -1211,6 +1211,11 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
u16 tw = 1u << TEX0.TW; u16 tw = 1u << TEX0.TW;
u16 th = 1u << TEX0.TH; u16 th = 1u << TEX0.TH;
if (tw > 1024)
tw = 1;
if (th > 1024)
th = 1;
switch (context->CLAMP.WMS) switch (context->CLAMP.WMS)
{ {
case CLAMP_REPEAT: case CLAMP_REPEAT:
@ -1224,13 +1229,15 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
gd.t.mask.U32[0] = 0; gd.t.mask.U32[0] = 0;
break; break;
case CLAMP_REGION_CLAMP: case CLAMP_REGION_CLAMP:
gd.t.min.U16[0] = gd.t.minmax.U16[0] = std::min<u16>(context->CLAMP.MINU, tw - 1); // REGION_CLAMP ignores the actual texture size
gd.t.max.U16[0] = gd.t.minmax.U16[2] = std::min<u16>(context->CLAMP.MAXU, tw - 1); 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; gd.t.mask.U32[0] = 0;
break; break;
case CLAMP_REGION_REPEAT: 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.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; gd.t.mask.U32[0] = 0xffffffff;
break; break;
default: default:
@ -1250,13 +1257,15 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
gd.t.mask.U32[2] = 0; gd.t.mask.U32[2] = 0;
break; break;
case CLAMP_REGION_CLAMP: case CLAMP_REGION_CLAMP:
gd.t.min.U16[4] = gd.t.minmax.U16[1] = std::min<u16>(context->CLAMP.MINV, th - 1); // REGION_CLAMP ignores the actual texture size
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.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; gd.t.mask.U32[2] = 0;
break; break;
case CLAMP_REGION_REPEAT: 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.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; gd.t.mask.U32[2] = 0xffffffff;
break; break;
default: default: