fix(agc): retain shader memory region vectors

This commit is contained in:
MarcZX10 committed 2026-10-19 06:27:51 +00:00
1 parent 63e4a63804
commit 55a3eeb074
2 files changed
+43 -22

No files matched your search

@@ -826,7 +826,8 @@ void verifyOutOfRangeConstantReads() {
require(plan->info.images.size() == 2u && plan->info.samplers.size() == 1u, "out-of-range s_buffer_load: the two T#s were not planned as one image each");
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(request);
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
static_cast<void>(Recompile(request, *capture));
const auto holds = [&](const std::array<std::uint32_t, 8>& words) {
return std::ranges::any_of(capture->snapshot.images, [&](const DescriptorValue& value) {
@@ -1001,8 +1002,10 @@ void verifyGuardedDescriptorSources() {
fill(valid, mode);
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(storeRequest);
storeRequest.context.memory = memory.Regions();
return Recompile(storeRequest, *capture);
const auto memoryRegions = memory.Regions();
auto compileRequest = storeRequest;
compileRequest.context.memory = memoryRegions;
return Recompile(compileRequest, *capture);
};
const auto storePlan = GetResourcePlan(storeRequest);
require(storePlan->info.images.size() == 2u && storePlan->descriptorSources.size() == 1u, "guarded images: the two stores were not planned as two images of one T#");
@@ -3506,7 +3509,8 @@ void verifyDescriptorPhis() {
require(plan->info.images.size() == images && plan->info.samplers.size() == samplers && plan->info.sampledPairs.size() == 2u, "descriptor Phi: the edges were not given one resource each");
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(request);
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
const auto compiled = Recompile(request, *capture);
require(countOps(compiled->spirv, OpImageSampleExplicitLod) == 2u, "descriptor Phi: the specialized SPIR-V does not sample once per edge");
#if ANYPS5_ENABLE_SPIRV_TOOLS
@@ -3537,7 +3541,8 @@ void verifyDescriptorPhis() {
auto twoLane = makeRequest(samplerCode, 64u);
AgcDriver::ShaderMemory twoLaneMemory({});
const auto twoLaneCapture = twoLaneMemory.Capture(twoLane);
twoLane.context.memory = twoLaneMemory.Regions();
const auto twoLaneRegions = twoLaneMemory.Regions();
twoLane.context.memory = twoLaneRegions;
require(countOps(Recompile(twoLane, *twoLaneCapture)->spirv, OpImageSampleExplicitLod) == 4u, "descriptor Phi: the specialized two-lane SPIR-V does not sample once per edge and half");
auto dynamic = makeRequest(dynamicCode);
@@ -3559,7 +3564,8 @@ void verifyDescriptorPhis() {
require(sequentialPlan->info.images.size() == 2u && sequentialPlan->info.samplers.size() == 2u, "descriptor Phi: a T# and an S# chosen in separate blocks were not split into their SRT descriptors");
AgcDriver::ShaderMemory sequentialMemory({});
const auto sequentialCapture = sequentialMemory.Capture(sequential);
sequential.context.memory = sequentialMemory.Regions();
const auto sequentialRegions = sequentialMemory.Regions();
sequential.context.memory = sequentialRegions;
static_cast<void>(Recompile(sequential, *sequentialCapture));
const auto planRestoredSampler = [&](std::span<const std::uint32_t> code, const char* message) {
@@ -3568,7 +3574,8 @@ void verifyDescriptorPhis() {
require(plan->info.samplers.size() == 1u && plan->info.sampledPairs.size() == 1u, message);
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(request);
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
static_cast<void>(Recompile(request, *capture));
};
std::vector<std::uint32_t> restoredSamplerCode{0xf40c0200u, 0xfa000000u, 0xf4080500u, 0xfa000020u, 0xf4080600u, 0xfa000040u, 0xbe930380u, 0xbf8cc07fu, 0xf09c0f08u, 0x00a20400u, 0xbe900380u, 0xbe910380u, 0xbe9c0414u, 0xbe9e0416u, 0xbf068011u, 0xbf850001u, 0x80128112u, 0xbe94041cu, 0xbe96041eu, 0x80118111u, 0xbf0a8211u, 0xbf85fff6u, 0xf09c0f08u, 0x00a20000u, 0x80108110u, 0xbf0a8210u, 0xbf85fff0u, 0x80138113u, 0xbf0a8213u, 0xbf85ffecu, 0xbf8c3f70u, 0xe0700000u, 0x80060000u, 0xe0700000u, 0x80060400u, 0x7d880090u, 0xbea23c6au, 0x4a020081u, 0xe0700000u, 0x80060100u, 0xbf810000u};
@@ -3742,7 +3749,8 @@ void verifyLaneSelectedDescriptors() {
require(plan->info.images.size() == 2u && plan->info.samplers.size() == 1u, "lane-selected T#: the T#s selected per lane were not planned as one image each");
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(request);
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
static_cast<void>(Recompile(request, *capture));
const auto holds = [&](const std::array<std::uint32_t, 8>& words) {
return std::ranges::any_of(capture->snapshot.images, [&](const DescriptorValue& value) {
@@ -3788,7 +3796,8 @@ void verifyProgramCounterRelativeData() {
};
AgcDriver::ShaderMemory memory({});
static_cast<void>(memory.Capture(request));
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
const auto first = Recompile(request);
require(dataBase(first) == codeAddress + 56u, "program counter data: the V# does not name the data at the shader's address");
auto relocated = request;
@@ -5457,7 +5466,8 @@ void verifyComputedTexelOffsets() {
request.useCache = false;
AgcDriver::ShaderMemory memory({});
static_cast<void>(memory.Capture(request));
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
return Recompile(request).spirv;
};
const auto sampleOperands = [](std::span<const std::uint32_t> words) {
@@ -5507,7 +5517,8 @@ void verifyShaderClockScopes() {
request.useCache = false;
AgcDriver::ShaderMemory memory({});
static_cast<void>(memory.Capture(request));
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
const auto words = Recompile(request).spirv;
std::map<std::uint32_t, std::uint32_t> constants;
std::vector<std::uint32_t> scopeIds;
@@ -5821,7 +5832,8 @@ void verifyUnnormalizedSamplers() {
request.layout.pushConstantSizeBytes = 128;
AgcDriver::ShaderMemory memory({});
static_cast<void>(memory.Capture(request));
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
return Recompile(request);
};
const auto flags = [](const RecompileResult& result, DescriptorRole role) {
@@ -6244,7 +6256,8 @@ void verifyTwoLaneUniformValues() {
request.layout.pushConstantSizeBytes = 128;
AgcDriver::ShaderMemory memory({});
const auto capture = memory.Capture(request);
request.context.memory = memory.Regions();
const auto memoryRegions = memory.Regions();
request.context.memory = memoryRegions;
const auto words = Recompile(request, *capture)->spirv;
std::size_t count = 0;
for (std::size_t cursor = 5; cursor < words.size();) {
@@ -6825,7 +6838,8 @@ void verifyGuardedNullPointers() {
const auto valid = validMemory.Capture(branch.request);
require(valid->snapshot.srtPoison.empty() && valid->plan->guardedSrtSlots.size() == 1u && slotPc(*valid->plan, valid->plan->guardedSrtSlots[0]) == 0x2cu && GuardRecords(*valid), "guarded pointer: a mapped nested pointer was poisoned, or its read has no guard");
require(valid->snapshot.flattenedSrt.at(valid->plan->guardedSrtSlots[0]) == payload, "guarded pointer: a mapped nested read does not hold its word");
branch.request.context.memory = validMemory.Regions();
const auto validRegions = validMemory.Regions();
branch.request.context.memory = validRegions;
const auto validResult = Recompile(branch.request, *valid);
require(validResult->poisonedSrtReads == 0u && faultBinding(*validResult) && validResult->bdaAbiVersion == BdaAbi::Version, "guarded pointer: a guarded program has no fault buffer");
@@ -6867,20 +6881,23 @@ void verifyGuardedNullPointers() {
const bool throughPointer = own == 0x38u && poison.address == unmapped;
require(poison.pc == 0x2cu && (pointerWord || throughPointer), "guarded pointer: a derived poison does not name the inaccessible read");
}
chain.request.context.memory = chainMemory.Regions();
const auto chainRegions = chainMemory.Regions();
chain.request.context.memory = chainRegions;
const auto chainResult = Recompile(chain.request, *chained);
indirect = 0;
point(static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(&indirect)));
AgcDriver::ShaderMemory nullChainMemory({});
const auto nullChain = nullChainMemory.Capture(chain.request);
require(nullChain->snapshot.srtPoison.size() == 1u && nullChain->snapshot.srtPoison[0].pc == 0x38u && nullChain->snapshot.srtPoison[0].address == 0u && GuardRecords(*nullChain), "guarded pointer: a null pointer read from memory did not poison the read through it");
chain.request.context.memory = nullChainMemory.Regions();
const auto nullChainRegions = nullChainMemory.Regions();
chain.request.context.memory = nullChainRegions;
const auto nullChainResult = Recompile(chain.request, *nullChain);
indirect = payloadAddress;
AgcDriver::ShaderMemory mappedChainMemory({});
const auto mappedChain = mappedChainMemory.Capture(chain.request);
require(mappedChain->snapshot.srtPoison.empty() && mappedChain->plan->guardedSrtSlots.size() == 3u && GuardRecords(*mappedChain), "guarded pointer: a mapped pointer chain was poisoned, or its reads have no guards");
chain.request.context.memory = mappedChainMemory.Regions();
const auto mappedChainRegions = mappedChainMemory.Regions();
chain.request.context.memory = mappedChainRegions;
const auto mappedChainResult = Recompile(chain.request, *mappedChain);
require(chainResult->poisonedSrtReads == 3u && nullChainResult->poisonedSrtReads == 1u && mappedChainResult->poisonedSrtReads == 0u, "guarded pointer: a chain result does not count its poisoned reads");
require(samePipeline(*chainResult, *mappedChainResult) && samePipeline(*nullChainResult, *mappedChainResult), "guarded pointer: a chain's poison changed the variant, the specialization or the module");
@@ -6903,7 +6920,8 @@ void verifyGuardedNullPointers() {
AgcDriver::ShaderMemory zeroMemory({});
const auto zeroCapture = zeroMemory.Capture(descriptor.request);
require(zeroCapture->snapshot.srtPoison.empty() && zeroBuffer(*zeroCapture) && GuardRecords(*zeroCapture), "guarded pointer: a zero V# read from mapped memory was poisoned or not read");
descriptor.request.context.memory = zeroMemory.Regions();
const auto zeroRegions = zeroMemory.Regions();
descriptor.request.context.memory = zeroRegions;
const auto zeroResult = Recompile(descriptor.request, *zeroCapture);
for (const auto pointer : {std::uint64_t{0}, unmapped}) {
point(pointer);
@@ -6959,7 +6977,8 @@ void verifyGuardedNullPointers() {
const auto rootlessCapture = rootlessMemory.Capture(rootless.request);
require(rootlessCapture->snapshot.nullRootReads != 0u && GuardRecords(*rootlessCapture), "guarded pointer: reads through a null user-data pointer were not counted");
require(std::all_of(rootlessCapture->snapshot.buffers.begin(), rootlessCapture->snapshot.buffers.end(), [](const DescriptorValue& value) { return std::all_of(value.dwords.begin(), value.dwords.end(), [](std::uint32_t word) { return word == 0u; }); }), "guarded pointer: a V# read through a null user-data pointer is not zero");
rootless.request.context.memory = rootlessMemory.Regions();
const auto rootlessRegions = rootlessMemory.Regions();
rootless.request.context.memory = rootlessRegions;
const auto rootlessResult = Recompile(rootless.request, *rootlessCapture);
require(rootlessResult->poisonedSrtReads >= rootlessCapture->snapshot.nullRootReads, "guarded pointer: a capture through a null user-data pointer is cacheable");
point(0u);
@@ -7449,7 +7468,8 @@ int main(int argc, char** argv) {
const auto changedCapture = changedMemory.Capture(request);
auto changed = updated;
changed.useCache = true;
changed.context.memory = changedMemory.Regions();
const auto changedRegions = changedMemory.Regions();
changed.context.memory = changedRegions;
auto before = updated;
before.useCache = true;
before.context.memory = updatedRegions;
@@ -7512,7 +7532,8 @@ int main(int argc, char** argv) {
AgcDriver::ShaderMemory nullRoot({});
const auto nullRootCapture = nullRoot.Capture(request);
require(nullRootCapture->snapshot.nullRootReads != 0u, "reads through a null user-data pointer were not counted");
request.context.memory = nullRoot.Regions();
const auto nullRootRegions = nullRoot.Regions();
request.context.memory = nullRootRegions;
require(Recompile(request, *nullRootCapture)->poisonedSrtReads >= nullRootCapture->snapshot.nullRootReads, "a capture through a null user-data pointer is cacheable");
std::cout << "Shader memory capture, strict validation and deterministic replay passed\n";
return 0;
@@ -131,7 +131,7 @@ Captured Capture(std::byte* table) {
result.memory = std::make_unique<AgcDriver::ShaderMemory>(std::span<const MemoryRegion>{});
result.capture = result.memory->Capture(request);
result.regions = result.memory->TakeRecentRegions();
request.context.memory = result.memory->Regions();
request.context.memory = result.regions;
result.compiled = Recompile(request, *result.capture);
return result;
}