diff --git a/core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp b/core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp index 1e0f0044b1..06c5c7bf53 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp +++ b/core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp @@ -196,6 +196,7 @@ unsigned long long CodeOffset(const void* address); // calls FlushGpuWrites itself. void SetFlushHook(void (*hook)(std::uint64_t address, std::size_t bytes)); void SetReadGuard(void (*guard)(std::uint64_t address, std::size_t bytes)); +void GuardRead(std::uint64_t address, std::size_t bytes); void FlushGpuWrites(std::uint64_t address, std::size_t bytes); // Moves with every ForgetPages call (the libc invalidator: memory unmapped or re-registered): odd // while the call stores its page states, moved past it after, so a reader that loads an even diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp index 3ce4e76b81..c1801c0d85 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp @@ -2234,13 +2234,17 @@ void SetReadGuard(void (*guard)(std::uint64_t address, std::size_t bytes)) { GuestArena::GuestArenaSetHostReadHook_nid_no_patch(&PrepareHostRead); } +void GuardRead(std::uint64_t address, std::size_t bytes) { + if (const auto guard = readGuard.load(std::memory_order_acquire)) guard(address, bytes); +} + void FlushGpuWrites(std::uint64_t address, std::size_t bytes) { if (const auto hook = flushHook.load(std::memory_order_acquire)) hook(address, bytes); } void Read(std::uint64_t address, std::span destination, std::size_t alignment) { if (destination.empty()) return; - if (const auto guard = readGuard.load(std::memory_order_acquire)) guard(address, destination.size()); + GuardRead(address, destination.size()); FlushGpuWrites(address, destination.size()); const TimedAccess timed(CounterRead, destination.size()); CountReadCaller(__builtin_return_address(0)); @@ -2287,7 +2291,7 @@ void copyCommitted(std::uint64_t address, std::span destination) { void ReadCommitted(std::uint64_t address, std::span destination) { if (destination.empty()) return; - if (const auto guard = readGuard.load(std::memory_order_acquire)) guard(address, destination.size()); + GuardRead(address, destination.size()); FlushGpuWrites(address, destination.size()); const TimedAccess timed(CounterRead, destination.size()); CountReadCaller(__builtin_return_address(0)); @@ -2296,7 +2300,7 @@ void ReadCommitted(std::uint64_t address, std::span destination) { void ReadCommittedUnsynced(std::uint64_t address, std::span destination) { if (destination.empty()) return; - if (const auto guard = readGuard.load(std::memory_order_acquire)) guard(address, destination.size()); + GuardRead(address, destination.size()); const TimedAccess timed(CounterRead, destination.size()); CountReadCaller(__builtin_return_address(0)); copyCommitted(address, destination); diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/ShaderMemory.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/ShaderMemory.cpp index 360fdf5500..253d832b7c 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/ShaderMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/ShaderMemory.cpp @@ -228,6 +228,7 @@ ShaderMemory::Page& ShaderMemory::page(std::uint64_t base) { return page; } const auto started = CaptureProfiled() ? std::chrono::steady_clock::now() : std::chrono::steady_clock::time_point{}; + GuestMemory::GuardRead(base, PageBytes); GuestMemory::FlushGpuWrites(base, PageBytes); if (CaptureProfiled()) CaptureTotals().pageReadNanoseconds += NanosecondsSince(started); page.lazy = true; @@ -289,6 +290,7 @@ bool ShaderMemory::read(void* context, std::uint64_t address, std::uint32_t* val word = waited; } } else if (policy == PendingWrite::Raw || policy == PendingWrite::VerifyRaw) { + GuestMemory::GuardRead(address, sizeof(word)); std::memcpy(&word, reinterpret_cast(address), sizeof(word)); ++CaptureTotals().wordsRaw; if (policy == PendingWrite::VerifyRaw) { diff --git a/core/libs/prx/libSceAgcDriver/tests/Recorder.cpp b/core/libs/prx/libSceAgcDriver/tests/Recorder.cpp index 56680436b6..65f350d63b 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Recorder.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Recorder.cpp @@ -38,6 +38,7 @@ #include "VertexRange_vert_spv.h" #include "VertexRangeProducer_frag_spv.h" #include "prx/libSceAgcDriver/Graphics/include/ColorTargetTransfer.hpp" +#include "BdaAbi.hpp" #include #ifdef _WIN32 #ifndef NOMINMAX @@ -7037,6 +7038,31 @@ void multisampleGuestAccessTests(const Device& device, Recorder& recorder) { refused([&] { AgcDriver::GuestMemory::ReadCommitted(address + 256u, texels); }, "a CPU read", "a committed CPU read"); refused([&] { AgcDriver::GuestMemory::ReadCommittedUnsynced(address + 256u, texels); }, "a CPU read", "a committed CPU read without the flush hook"); refused([&] { RequireNoMultisampleTarget(address, 64u, "a DMA copy"); }, "a DMA copy", "a DMA copy"); + const auto captureSrt = [](std::uint64_t srt, AgcDriver::ShaderMemory::PendingWriteQuery pendingWrite) { + static constexpr std::array code{0xf4080100u, 0xfa000000u, 0xbf8cc07fu, 0xe0700000u, 0x80010000u, 0xbf810000u}; + const std::array userData{static_cast(srt), static_cast(srt >> 32u)}; + ShaderRecompiler::RecompileRequest request{}; + request.shader = {ShaderRecompiler::ShaderStage::Compute, 0x24000u, code, 0, {}}; + request.context.waveSize = 32u; + request.context.userDataBaseRegister = 0; + request.context.userData = userData; + request.context.compute = ShaderRecompiler::ShaderComputeStageInfo{{32u, 1u, 1u}, 0u, {false, false, false}, false, 1u}; + request.target.vulkanVersion = 0x00401000u; + request.target.spirvVersion = 0x00010300u; + request.target.subgroupSize = 32; + request.target.bdaAbiVersion = ShaderRecompiler::BdaAbi::Version; + request.layout.pushConstantSizeBytes = 128; + AgcDriver::ShaderMemory memory({}, pendingWrite); + static_cast(memory.Capture(request)); + }; + refused([&] { captureSrt(address + 256u, nullptr); }, "a CPU read", "a shader capture"); + captureSrt(address + 4u * 65536u + 256u, nullptr); + refused([&] { captureSrt(address + 256u, nullptr); }, "a CPU read", "a shader capture on a pooled page"); + const auto raw = [](std::uint64_t, std::size_t, std::span) { return AgcDriver::ShaderMemory::PendingWrite::Raw; }; + const auto synced = [](std::uint64_t, std::size_t, std::span) { return AgcDriver::ShaderMemory::PendingWrite::Sync; }; + refused([&] { captureSrt(address + 256u, raw); }, "a CPU read", "a shader capture's raw word read"); + refused([&] { captureSrt(address + 256u, synced); }, "a CPU read", "a shader capture's synced word read"); + captureSrt(address + 4u * 65536u + 256u, raw); ShaderRecompiler::RecompileResult program; ShaderRecompiler::DescriptorBinding binding; binding.kind = ShaderRecompiler::DescriptorKind::SampledImage;