mirror of https://github.com/PCSX2/pcsx2.git
Merge 7f8985124b
into bf8693a7e8
This commit is contained in:
commit
8a92a8b73f
|
@ -1677,48 +1677,9 @@ void GSState::FlushPrim()
|
||||||
|
|
||||||
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||||
|
|
||||||
// Texel coordinate rounding
|
|
||||||
// Helps Manhunt (lights shining through objects).
|
|
||||||
// Can help with some alignment issues when upscaling too, and is for both Software and Hardware renderers.
|
|
||||||
// Sometimes hardware doesn't get affected, likely due to the difference in how GPU's handle textures (Persona minimap).
|
|
||||||
if (PRIM->TME && (GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS || m_vt.m_eq.z))
|
if (PRIM->TME && (GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS || m_vt.m_eq.z))
|
||||||
{
|
{
|
||||||
if (!PRIM->FST) // STQ's
|
TexelCoordinateRounding();
|
||||||
{
|
|
||||||
const bool is_sprite = GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
|
|
||||||
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounding down (from hardware tests).
|
|
||||||
for (int i = m_index.tail - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
GSVertex* v = &m_vertex.buff[m_index.buff[i]];
|
|
||||||
|
|
||||||
// Only Q on the second vertex is valid
|
|
||||||
if (!(i & 1) && is_sprite)
|
|
||||||
v->RGBAQ.Q = m_vertex.buff[m_index.buff[i + 1]].RGBAQ.Q;
|
|
||||||
|
|
||||||
int T = std::bit_cast<int>(v->ST.T);
|
|
||||||
int Q = std::bit_cast<int>(v->RGBAQ.Q);
|
|
||||||
int S = std::bit_cast<int>(v->ST.S);
|
|
||||||
const int expS = (S >> 23) & 0xff;
|
|
||||||
const int expT = (T >> 23) & 0xff;
|
|
||||||
const int expQ = (Q >> 23) & 0xff;
|
|
||||||
int max_exp = std::max(expS, expQ);
|
|
||||||
|
|
||||||
u32 mask = CalcMask(expS, max_exp);
|
|
||||||
S &= ~mask;
|
|
||||||
v->ST.S = std::bit_cast<float>(S);
|
|
||||||
max_exp = std::max(expT, expQ);
|
|
||||||
mask = CalcMask(expT, max_exp);
|
|
||||||
T &= ~mask;
|
|
||||||
v->ST.T = std::bit_cast<float>(T);
|
|
||||||
Q &= ~0xff;
|
|
||||||
|
|
||||||
if (!is_sprite || (i & 1))
|
|
||||||
v->RGBAQ.Q = std::bit_cast<float>(Q);
|
|
||||||
|
|
||||||
m_vt.m_min.t.x = std::min(m_vt.m_min.t.x, (v->ST.S / v->RGBAQ.Q) * (1 << m_context->TEX0.TW));
|
|
||||||
m_vt.m_min.t.y = std::min(m_vt.m_min.t.y, (v->ST.T / v->RGBAQ.Q) * (1 << m_context->TEX0.TH));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip draw if Z test is enabled, but set to fail all pixels.
|
// Skip draw if Z test is enabled, but set to fail all pixels.
|
||||||
|
@ -3831,8 +3792,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||||
|
|
||||||
u8 uses_border = 0;
|
u8 uses_border = 0;
|
||||||
|
|
||||||
if (m_vt.m_max.t.x >= FLT_MAX || m_vt.m_min.t.x <= -FLT_MAX ||
|
if (m_vt.m_max.t.x >= 2047.0f || m_vt.m_min.t.x <= -2047.0f ||
|
||||||
m_vt.m_max.t.y >= FLT_MAX || m_vt.m_min.t.y <= -FLT_MAX)
|
m_vt.m_max.t.y >= 2047.0f || m_vt.m_min.t.y <= -2047.0f)
|
||||||
{
|
{
|
||||||
// If any of the min/max values are +-FLT_MAX we can't rely on them
|
// If any of the min/max values are +-FLT_MAX we can't rely on them
|
||||||
// so just assume full texture.
|
// so just assume full texture.
|
||||||
|
@ -4009,6 +3970,61 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||||
return { vr, uses_border };
|
return { vr, uses_border };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Texel coordinate rounding
|
||||||
|
// Helps Manhunt (lights shining through objects).
|
||||||
|
// Can help with some alignment issues when upscaling too, and is for both Software and Hardware renderers.
|
||||||
|
// Sometimes hardware doesn't get affected, likely due to the difference in how GPU's handle textures (Persona minimap).
|
||||||
|
void GSState::TexelCoordinateRounding()
|
||||||
|
{
|
||||||
|
if (!PRIM->FST) // STQ's
|
||||||
|
{
|
||||||
|
const bool is_sprite = GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
|
||||||
|
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounding down (from hardware tests).
|
||||||
|
for (int i = m_index.tail - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
GSVertex* v = &m_vertex.buff[m_index.buff[i]];
|
||||||
|
|
||||||
|
// Only Q on the second vertex is valid
|
||||||
|
if (!(i & 1) && is_sprite)
|
||||||
|
v->RGBAQ.Q = m_vertex.buff[m_index.buff[i + 1]].RGBAQ.Q;
|
||||||
|
|
||||||
|
int T = std::bit_cast<int>(v->ST.T);
|
||||||
|
int Q = std::bit_cast<int>(v->RGBAQ.Q);
|
||||||
|
int S = std::bit_cast<int>(v->ST.S);
|
||||||
|
const int expS = (S >> 23) & 0xff;
|
||||||
|
const int expT = (T >> 23) & 0xff;
|
||||||
|
const int expQ = (Q >> 23) & 0xff;
|
||||||
|
int max_exp = std::max(expS, expQ);
|
||||||
|
|
||||||
|
u32 mask = CalcMask(expS, max_exp);
|
||||||
|
S &= ~mask;
|
||||||
|
v->ST.S = std::bit_cast<float>(S);
|
||||||
|
max_exp = std::max(expT, expQ);
|
||||||
|
mask = CalcMask(expT, max_exp);
|
||||||
|
T &= ~mask;
|
||||||
|
v->ST.T = std::bit_cast<float>(T);
|
||||||
|
Q &= ~0xff;
|
||||||
|
|
||||||
|
if (!is_sprite || (i & 1))
|
||||||
|
v->RGBAQ.Q = std::bit_cast<float>(Q);
|
||||||
|
|
||||||
|
float U = (v->ST.S / v->RGBAQ.Q) * (1 << m_context->TEX0.TW);
|
||||||
|
float V = (v->ST.T / v->RGBAQ.Q) * (1 << m_context->TEX0.TH);
|
||||||
|
|
||||||
|
m_vt.m_min.t.x = std::isnan(U) ? m_vt.m_min.t.x : std::min(m_vt.m_min.t.x, U);
|
||||||
|
m_vt.m_min.t.y = std::isnan(V) ? m_vt.m_min.t.y : std::min(m_vt.m_min.t.y, V);
|
||||||
|
m_vt.m_max.t.x = std::isnan(U) ? m_vt.m_max.t.x : std::max(m_vt.m_max.t.x, U);
|
||||||
|
m_vt.m_max.t.y = std::isnan(V) ? m_vt.m_max.t.y : std::max(m_vt.m_max.t.y, V);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the min/max UV values to the min/max valid UV values.
|
||||||
|
// This is needed in certain cases where buggy GS input results
|
||||||
|
// in huge floating points values for ST.
|
||||||
|
m_vt.m_min.t = m_vt.m_min.t.min(GSVector4(2047.0f)).max(GSVector4(-2047.0f)).xyzw(m_vt.m_min.t);
|
||||||
|
m_vt.m_max.t = m_vt.m_max.t.min(GSVector4(2047.0f)).max(GSVector4(-2047.0f)).xyzw(m_vt.m_max.t);
|
||||||
|
}
|
||||||
|
|
||||||
void GSState::CalcAlphaMinMax(const int tex_alpha_min, const int tex_alpha_max)
|
void GSState::CalcAlphaMinMax(const int tex_alpha_min, const int tex_alpha_max)
|
||||||
{
|
{
|
||||||
if (m_vt.m_alpha.valid && tex_alpha_min == 0 && tex_alpha_max == 255)
|
if (m_vt.m_alpha.valid && tex_alpha_min == 0 && tex_alpha_max == 255)
|
||||||
|
|
|
@ -190,6 +190,7 @@ protected:
|
||||||
bool IsCoverageAlpha();
|
bool IsCoverageAlpha();
|
||||||
void CalcAlphaMinMax(const int tex_min, const int tex_max);
|
void CalcAlphaMinMax(const int tex_min, const int tex_max);
|
||||||
void CorrectATEAlphaMinMax(const u32 atst, const int aref);
|
void CorrectATEAlphaMinMax(const u32 atst, const int aref);
|
||||||
|
void TexelCoordinateRounding();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct GSUploadQueue
|
struct GSUploadQueue
|
||||||
|
|
|
@ -138,20 +138,36 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
|
||||||
|
|
||||||
stq0 = st.xyww(primclass == GS_SPRITE_CLASS ? stq1 : stq0);
|
stq0 = st.xyww(primclass == GS_SPRITE_CLASS ? stq1 : stq0);
|
||||||
stq1 = st.zwww(stq1);
|
stq1 = st.zwww(stq1);
|
||||||
|
|
||||||
|
// Check for NaNs
|
||||||
|
GSVector4 temp_min = stq0.min(stq1);
|
||||||
|
GSVector4 temp_max = stq0.max(stq1);
|
||||||
|
temp_min.x = std::isnan(temp_min.x) ? s_minmax.x : temp_min.x;
|
||||||
|
temp_min.y = std::isnan(temp_min.y) ? s_minmax.x : temp_min.y;
|
||||||
|
temp_max.x = std::isnan(temp_max.x) ? s_minmax.y : temp_max.x;
|
||||||
|
temp_max.y = std::isnan(temp_max.y) ? s_minmax.y : temp_max.y;
|
||||||
|
|
||||||
tmin = tmin.min(stq0.min(stq1));
|
tmin = tmin.min(temp_min);
|
||||||
tmax = tmax.max(stq0.max(stq1));
|
tmax = tmax.max(temp_max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GSVector4i uv0(v0.m[1]);
|
GSVector4i uv0(v0.m[1]);
|
||||||
GSVector4i uv1(v1.m[1]);
|
GSVector4i uv1(v1.m[1]);
|
||||||
|
|
||||||
GSVector4 st0 = GSVector4(uv0.uph16()).xyxy();
|
GSVector4 st0 = GSVector4(uv0.uph16());
|
||||||
GSVector4 st1 = GSVector4(uv1.uph16()).xyxy();
|
GSVector4 st1 = GSVector4(uv1.uph16());
|
||||||
|
|
||||||
tmin = tmin.min(st0.min(st1));
|
// Check for NaNs
|
||||||
tmax = tmax.max(st0.max(st1));
|
GSVector4 temp_min = st0.min(st1);
|
||||||
|
GSVector4 temp_max = st0.max(st1);
|
||||||
|
temp_min.x = std::isnan(temp_min.x) ? s_minmax.x : temp_min.x;
|
||||||
|
temp_min.y = std::isnan(temp_min.y) ? s_minmax.x : temp_min.y;
|
||||||
|
temp_max.x = std::isnan(temp_max.x) ? s_minmax.y : temp_max.x;
|
||||||
|
temp_max.y = std::isnan(temp_max.y) ? s_minmax.y : temp_max.y;
|
||||||
|
|
||||||
|
tmin = tmin.min(temp_min.xyxy());
|
||||||
|
tmax = tmax.max(temp_max.xyxy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +262,12 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
|
||||||
|
|
||||||
vt.m_min.t = tmin * s;
|
vt.m_min.t = tmin * s;
|
||||||
vt.m_max.t = tmax * s;
|
vt.m_max.t = tmax * s;
|
||||||
|
|
||||||
|
// Clamp the min/max UV values to the min/max valid UV values.
|
||||||
|
// This is needed in certain cases where buggy GS input results
|
||||||
|
// in huge floating points values for ST.
|
||||||
|
vt.m_min.t = vt.m_min.t.min(GSVector4(2047.0f)).max(GSVector4(-2047.0f)).xyzw(vt.m_min.t);
|
||||||
|
vt.m_max.t = vt.m_max.t.min(GSVector4(2047.0f)).max(GSVector4(-2047.0f)).xyzw(vt.m_max.t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue