GS/HW: Clamp draw rect to unscaled, not scaled coordinates

Fixes broken shuffle effect in Haunting Ground when upscale is set above
1x.
This commit is contained in:
Connor McLaughlin 2022-08-06 14:42:40 +10:00 committed by refractionpcsx2
parent 60714b5ca4
commit bcc4548f7b
3 changed files with 15 additions and 6 deletions

View File

@ -736,7 +736,7 @@ GSVector2 GSRendererHW::GetTextureScaleFactor()
return GSVector2(f_upscale, f_upscale);
}
GSVector2i GSRendererHW::GetTargetSize()
GSVector2i GSRendererHW::GetTargetSize(GSVector2i* unscaled_size)
{
// Don't blindly expand out to the scissor size if we're not drawing to it.
// e.g. Burnout 3, God of War II, etc.
@ -761,6 +761,11 @@ GSVector2i GSRendererHW::GetTargetSize()
const u32 width = m_context->FRAME.FBW * 64u;
const u32 height = m_tc->GetTargetHeight(m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, min_height);
if (unscaled_size)
{
unscaled_size->x = static_cast<int>(width);
unscaled_size->y = static_cast<int>(height);
}
GL_INS("Target size for %x %u %u: %ux%u", m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, width, height);
@ -1581,7 +1586,11 @@ void GSRendererHW::Draw()
// The rectangle of the draw
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
const GSVector2i t_size = GetTargetSize();
GSVector2i unscaled_size;
const GSVector2i t_size = GetTargetSize(&unscaled_size);
// Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area.
m_r = m_r.rintersect(GSVector4i(0, 0, unscaled_size.x, unscaled_size.y));
TEX0.TBP0 = context->FRAME.Block();
TEX0.TBW = context->FRAME.FBW;
@ -1613,9 +1622,6 @@ void GSRendererHW::Draw()
const int new_w = std::max(t_size.x, std::max(rt ? rt->m_texture->GetWidth() : 0, ds ? ds->m_texture->GetWidth() : 0));
const int new_h = std::max(t_size.y, std::max(rt ? rt->m_texture->GetHeight() : 0, ds ? ds->m_texture->GetHeight() : 0));
// Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area.
m_r = m_r.rintersect(GSVector4i(0, 0, new_w, new_h));
if (rt)
{
pxAssert(rt->m_texture->GetScale() == up_s);

View File

@ -186,7 +186,7 @@ public:
void MergeSprite(GSTextureCache::Source* tex);
GSVector2 GetTextureScaleFactor() override;
GSVector2i GetOutputSize(int real_h);
GSVector2i GetTargetSize();
GSVector2i GetTargetSize(GSVector2i* unscaled_size = nullptr);
void Reset(bool hardware_reset) override;
void UpdateSettings(const Pcsx2Config::GSOptions& old_config) override;

View File

@ -2548,6 +2548,9 @@ void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect)
m_valid = m_valid.runion(rect);
// Block of the bottom right texel of the validity rectangle, last valid block of the texture
// TODO: This is not correct when the PSM changes. e.g. a 512x448 target being shuffled will become 512x896 temporarily, and
// at the moment, we blow the valid rect out to twice the size. The only thing stopping everything breaking is the fact
// that we clamp the draw rect to the target size in GSRendererHW::Draw().
m_end_block = GSLocalMemory::m_psm[m_TEX0.PSM].info.bn(m_valid.z - 1, m_valid.w - 1, m_TEX0.TBP0, m_TEX0.TBW); // Valid only for color formats
// GL_CACHE("UpdateValidity (0x%x->0x%x) from R:%d,%d Valid: %d,%d", m_TEX0.TBP0, m_end_block, rect.z, rect.w, m_valid.z, m_valid.w);