diff --git a/core/libs/prx/libSceAgcDriver/Execution/include/QueueState.hpp b/core/libs/prx/libSceAgcDriver/Execution/include/QueueState.hpp index 588a447e8..4e9743773 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/include/QueueState.hpp +++ b/core/libs/prx/libSceAgcDriver/Execution/include/QueueState.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -192,11 +193,12 @@ struct Predication { }; struct QueueState { + static constexpr std::size_t ConstantRamWords = 0x3000; Registers shader; Registers context = InitialContextRegisters(); Registers userConfig{{0x24a, 0}, {0x24b, 0}}; std::optional savedContext; - std::array constantRam{}; + std::vector constantRam; std::uint64_t indexBase = 0; std::uint64_t drawIndirectBase = 0; std::uint64_t dispatchIndirectBase = 0; @@ -209,6 +211,17 @@ struct QueueState { void ClearContext() { context = InitialContextRegisters(); } + + std::span ConstantRam() const { + static const std::array unwritten{}; + if (constantRam.empty()) return unwritten; + return constantRam; + } + + std::span WritableConstantRam() { + if (constantRam.empty()) constantRam.resize(ConstantRamWords); + return constantRam; + } }; } diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp index 2b8fbede8..f3b0dea8f 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp @@ -610,8 +610,8 @@ std::optional ResolveStore(std::span packet, co return StoreWrite{destination, {}, dmaSourceBytes(packet)}; } case 0x83: { - if (packet.size() < 5 || packet[1] / 4 > queue.constantRam.size() || packet[2] > queue.constantRam.size() - packet[1] / 4) return std::nullopt; - const auto words = std::span(queue.constantRam).subspan(packet[1] / 4, packet[2]); + if (packet.size() < 5 || packet[1] / 4 > QueueState::ConstantRamWords || packet[2] > QueueState::ConstantRamWords - packet[1] / 4) return std::nullopt; + const auto words = queue.ConstantRam().subspan(packet[1] / 4, packet[2]); if (words.size_bytes() > limit) return std::nullopt; // A view of the queue's constant RAM: valid until the next CONST_RAM write on this queue, // which is a later packet of the same worker. @@ -913,10 +913,10 @@ void Execute(std::span packet, QueueState& queue) { return; } case 0x81: - std::copy(packet.begin() + 2, packet.end(), queue.constantRam.begin() + packet[1] / 4); + std::copy(packet.begin() + 2, packet.end(), queue.WritableConstantRam().begin() + packet[1] / 4); return; case 0x83: - GuestMemory::Write(address(packet[3], packet[4]), std::as_bytes(std::span(queue.constantRam).subspan(packet[1] / 4, packet[2])), 4); + GuestMemory::Write(address(packet[3], packet[4]), std::as_bytes(queue.ConstantRam().subspan(packet[1] / 4, packet[2])), 4); return; case 0x45: { std::uint32_t value = 0; diff --git a/core/libs/prx/libSceAgcDriver/tests/Pm4.cpp b/core/libs/prx/libSceAgcDriver/tests/Pm4.cpp index ec1e130ab..74b7c1c60 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Pm4.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Pm4.cpp @@ -364,9 +364,14 @@ void testMemory() { check(data[0] == 81 && data[1] == 82, "WRITE_DATA to memory from the graphics queue failed"); expectFailure([&] { AgcDriver::Pm4::Validate(makePacket(0x37, {0x08000100, low(data.data()), high(data.data()), 71}), 0); }, "reserved"); expectFailure([&] { AgcDriver::Pm4::Validate(makePacket(0x37, {0x80000100, low(data.data()), high(data.data()), 51}), 0); }, "engine"); + execute(state, makePacket(0x83, {0xbff8, 2, low(data.data()), high(data.data())})); + check(data[0] == 0 && data[1] == 0, "unwritten constant RAM is not zero"); execute(state, makePacket(0x81, {4, 31, 32})); execute(state, makePacket(0x83, {4, 2, low(data.data()), high(data.data())})); check(data[0] == 31 && data[1] == 32, "constant RAM round trip failed"); + auto copied = state; + execute(copied, makePacket(0x83, {0, 3, low(data.data()), high(data.data())})); + check(data[0] == 0 && data[1] == 31 && data[2] == 32, "a copied queue state lost its constant RAM"); expectFailure([&] { execute(state, makePacket(0x81, {0xbffc, 1, 2})); }, "overflow"); expectFailure([&] { execute(state, makePacket(0x40, {0x10105, 0, 0, low(data.data()), high(data.data())})); }, "64-bit immediate"); }