From e351f03cdf9371f63423fdda1ff168e0daff6966 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 26 Mar 2025 00:55:40 -0500 Subject: [PATCH] VideoCommon: Fix out-of-bounds and disabled EFB access. --- Source/Core/Core/PowerPC/MMU.cpp | 22 ++------- Source/Core/VideoBackends/Null/NullGfx.cpp | 2 +- Source/Core/VideoBackends/Null/NullGfx.h | 2 +- .../VideoBackends/Software/SWEfbInterface.cpp | 2 +- .../VideoBackends/Software/SWEfbInterface.h | 2 +- Source/Core/VideoCommon/EFBInterface.cpp | 47 +++++++++++++++++-- Source/Core/VideoCommon/EFBInterface.h | 7 ++- 7 files changed, 55 insertions(+), 29 deletions(-) diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index a9fd5ede4b..58f668d006 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -47,9 +47,7 @@ #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" -#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/EFBInterface.h" -#include "VideoCommon/Statistics.h" namespace PowerPC { @@ -111,18 +109,12 @@ static u32 EFB_Read(const u32 addr) } else if (addr & 0x00400000) { - var = AsyncRequests::GetInstance()->PushBlockingEvent([&] { - INCSTAT(g_stats.this_frame.num_efb_peeks); - return g_efb_interface->PeekDepth(x, y); - }); + var = g_efb_interface->PeekDepth(x, y); DEBUG_LOG_FMT(MEMMAP, "EFB Z Read @ {}, {}\t= {:#010x}", x, y, var); } else { - var = AsyncRequests::GetInstance()->PushBlockingEvent([&] { - INCSTAT(g_stats.this_frame.num_efb_peeks); - return g_efb_interface->PeekColor(x, y); - }); + var = g_efb_interface->PeekColor(x, y); DEBUG_LOG_FMT(MEMMAP, "EFB Color Read @ {}, {}\t= {:#010x}", x, y, var); } @@ -142,18 +134,12 @@ static void EFB_Write(u32 data, u32 addr) } else if (addr & 0x00400000) { - AsyncRequests::GetInstance()->PushEvent([x, y, data] { - INCSTAT(g_stats.this_frame.num_efb_pokes); - g_efb_interface->PokeDepth(x, y, data); - }); + g_efb_interface->PokeDepth(x, y, data); DEBUG_LOG_FMT(MEMMAP, "EFB Z Write {:08x} @ {}, {}", data, x, y); } else { - AsyncRequests::GetInstance()->PushEvent([x, y, data] { - INCSTAT(g_stats.this_frame.num_efb_pokes); - g_efb_interface->PokeColor(x, y, data); - }); + g_efb_interface->PokeColor(x, y, data); DEBUG_LOG_FMT(MEMMAP, "EFB Color Write {:08x} @ {}, {}", data, x, y); } } diff --git a/Source/Core/VideoBackends/Null/NullGfx.cpp b/Source/Core/VideoBackends/Null/NullGfx.cpp index ab60339d0b..61822d3c83 100644 --- a/Source/Core/VideoBackends/Null/NullGfx.cpp +++ b/Source/Core/VideoBackends/Null/NullGfx.cpp @@ -108,7 +108,7 @@ u32 NullEFBInterface::PeekColorInternal(u16 x, u16 y) return 0; } -u32 NullEFBInterface::PeekDepth(u16 x, u16 y) +u32 NullEFBInterface::PeekDepthInternal(u16 x, u16 y) { return 0; } diff --git a/Source/Core/VideoBackends/Null/NullGfx.h b/Source/Core/VideoBackends/Null/NullGfx.h index 43d20a45a2..a84b3743d4 100644 --- a/Source/Core/VideoBackends/Null/NullGfx.h +++ b/Source/Core/VideoBackends/Null/NullGfx.h @@ -46,7 +46,7 @@ class NullEFBInterface final : public EFBInterfaceBase void PokeDepth(u16 x, u16 y, u32 depth) override; u32 PeekColorInternal(u16 x, u16 y) override; - u32 PeekDepth(u16 x, u16 y) override; + u32 PeekDepthInternal(u16 x, u16 y) override; }; } // namespace Null diff --git a/Source/Core/VideoBackends/Software/SWEfbInterface.cpp b/Source/Core/VideoBackends/Software/SWEfbInterface.cpp index e534fab1c5..1e322a528e 100644 --- a/Source/Core/VideoBackends/Software/SWEfbInterface.cpp +++ b/Source/Core/VideoBackends/Software/SWEfbInterface.cpp @@ -742,7 +742,7 @@ u32 SWEFBInterface::PeekColorInternal(u16 x, u16 y) return value; } -u32 SWEFBInterface::PeekDepth(u16 x, u16 y) +u32 SWEFBInterface::PeekDepthInternal(u16 x, u16 y) { return EfbInterface::GetDepth(x, y); } diff --git a/Source/Core/VideoBackends/Software/SWEfbInterface.h b/Source/Core/VideoBackends/Software/SWEfbInterface.h index 5f866ad227..1182d3b5e0 100644 --- a/Source/Core/VideoBackends/Software/SWEfbInterface.h +++ b/Source/Core/VideoBackends/Software/SWEfbInterface.h @@ -69,6 +69,6 @@ class SWEFBInterface final : public EFBInterfaceBase void PokeDepth(u16 x, u16 y, u32 depth) override; u32 PeekColorInternal(u16 x, u16 y) override; - u32 PeekDepth(u16 x, u16 y) override; + u32 PeekDepthInternal(u16 x, u16 y) override; }; } // namespace SW diff --git a/Source/Core/VideoCommon/EFBInterface.cpp b/Source/Core/VideoCommon/EFBInterface.cpp index 9b88a58d0d..6ce256ff47 100644 --- a/Source/Core/VideoCommon/EFBInterface.cpp +++ b/Source/Core/VideoCommon/EFBInterface.cpp @@ -14,8 +14,10 @@ #include "Core/ConfigManager.h" #include "Core/System.h" +#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/PixelEngine.h" +#include "VideoCommon/Statistics.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -24,6 +26,11 @@ std::unique_ptr g_efb_interface; EFBInterfaceBase::~EFBInterfaceBase() = default; +bool EFBInterfaceBase::ShouldSkipAccess(u16 x, u16 y) const +{ + return !g_ActiveConfig.bEFBAccessEnable || x >= EFB_WIDTH || y >= EFB_HEIGHT; +} + void HardwareEFBInterface::ReinterpretPixelData(EFBReinterpretType convtype) { g_framebuffer_manager->ReinterpretPixelData(convtype); @@ -31,7 +38,10 @@ void HardwareEFBInterface::ReinterpretPixelData(EFBReinterpretType convtype) u32 HardwareEFBInterface::PeekColorInternal(u16 x, u16 y) { - u32 color = g_framebuffer_manager->PeekEFBColor(x, y); + u32 color = AsyncRequests::GetInstance()->PushBlockingEvent([&] { + INCSTAT(g_stats.this_frame.num_efb_peeks); + return g_framebuffer_manager->PeekEFBColor(x, y); + }); // a little-endian value is expected to be returned color = ((color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000)); @@ -54,6 +64,9 @@ u32 HardwareEFBInterface::PeekColorInternal(u16 x, u16 y) u32 EFBInterfaceBase::PeekColor(u16 x, u16 y) { + if (ShouldSkipAccess(x, y)) + return 0; + u32 color = PeekColorInternal(x, y); // check what to do with the alpha channel (GX_PokeAlphaRead) @@ -78,10 +91,14 @@ u32 EFBInterfaceBase::PeekColor(u16 x, u16 y) } } -u32 HardwareEFBInterface::PeekDepth(u16 x, u16 y) +u32 HardwareEFBInterface::PeekDepthInternal(u16 x, u16 y) { + float depth = AsyncRequests::GetInstance()->PushBlockingEvent([&] { + INCSTAT(g_stats.this_frame.num_efb_peeks); + return g_framebuffer_manager->PeekEFBDepth(x, y); + }); + // Depth buffer is inverted for improved precision near far plane - float depth = g_framebuffer_manager->PeekEFBDepth(x, y); if (!g_backend_info.bSupportsReversedDepthRange) depth = 1.0f - depth; @@ -105,22 +122,42 @@ u32 HardwareEFBInterface::PeekDepth(u16 x, u16 y) return z24depth; } +u32 EFBInterfaceBase::PeekDepth(u16 x, u16 y) +{ + if (ShouldSkipAccess(x, y)) + return 0; + + return PeekDepthInternal(x, y); +} + void HardwareEFBInterface::PokeColor(u16 x, u16 y, u32 poke_data) { + if (ShouldSkipAccess(x, y)) + return; + // Convert to expected format (BGRA->RGBA) // TODO: Check alpha, depending on mode? const u32 color = ((poke_data & 0xFF00FF00) | ((poke_data >> 16) & 0xFF) | ((poke_data << 16) & 0xFF0000)); - g_framebuffer_manager->PokeEFBColor(x, y, color); + AsyncRequests::GetInstance()->PushEvent([x, y, color] { + INCSTAT(g_stats.this_frame.num_efb_pokes); + g_framebuffer_manager->PokeEFBColor(x, y, color); + }); } void HardwareEFBInterface::PokeDepth(u16 x, u16 y, u32 poke_data) { + if (ShouldSkipAccess(x, y)) + return; + // Convert to floating-point depth. float depth = float(poke_data & 0xFFFFFF) / 16777216.0f; if (!g_backend_info.bSupportsReversedDepthRange) depth = 1.0f - depth; - g_framebuffer_manager->PokeEFBDepth(x, y, depth); + AsyncRequests::GetInstance()->PushEvent([x, y, depth] { + INCSTAT(g_stats.this_frame.num_efb_pokes); + g_framebuffer_manager->PokeEFBDepth(x, y, depth); + }); } diff --git a/Source/Core/VideoCommon/EFBInterface.h b/Source/Core/VideoCommon/EFBInterface.h index a3ee947dd9..414b84c436 100644 --- a/Source/Core/VideoCommon/EFBInterface.h +++ b/Source/Core/VideoCommon/EFBInterface.h @@ -20,10 +20,13 @@ public: virtual void PokeDepth(u16 x, u16 y, u32 depth) = 0; u32 PeekColor(u16 x, u16 y); - virtual u32 PeekDepth(u16 x, u16 y) = 0; + u32 PeekDepth(u16 x, u16 y); protected: + bool ShouldSkipAccess(u16 x, u16 y) const; + virtual u32 PeekColorInternal(u16 x, u16 y) = 0; + virtual u32 PeekDepthInternal(u16 x, u16 y) = 0; }; class HardwareEFBInterface final : public EFBInterfaceBase @@ -34,7 +37,7 @@ class HardwareEFBInterface final : public EFBInterfaceBase void PokeDepth(u16 x, u16 y, u32 depth) override; u32 PeekColorInternal(u16 x, u16 y) override; - u32 PeekDepth(u16 x, u16 y) override; + u32 PeekDepthInternal(u16 x, u16 y) override; }; extern std::unique_ptr g_efb_interface;