diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index bcc68ce9b9..56a389adc9 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -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(width); + unscaled_size->y = static_cast(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); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index ce2d71339b..d4f42c41d4 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -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; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 2730a75f57..886e5f462f 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -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);