Merge pull request #3420 from gookie-dev/perf/agc-lazy-constant-ram

perf(agc): allocate a queue's constant RAM on its first write
This commit is contained in:
Adrià 2026-10-11 12:23:06 +02:00 committed by GitHub
commit 8fcd352f04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 23 additions and 5 deletions

View File

@ -11,6 +11,7 @@
#include <map>
#include <array>
#include <optional>
#include <span>
#include <string>
#include <vector>
@ -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<Registers> savedContext;
std::array<std::uint32_t, 0x3000> constantRam{};
std::vector<std::uint32_t> 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<const std::uint32_t> ConstantRam() const {
static const std::array<std::uint32_t, ConstantRamWords> unwritten{};
if (constantRam.empty()) return unwritten;
return constantRam;
}
std::span<std::uint32_t> WritableConstantRam() {
if (constantRam.empty()) constantRam.resize(ConstantRamWords);
return constantRam;
}
};
}

View File

@ -610,8 +610,8 @@ std::optional<StoreWrite> ResolveStore(std::span<const std::uint32_t> 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<const std::uint32_t>(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<const std::uint32_t> 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;

View File

@ -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");
}