Refresh cached resources in one SRT walk

This commit is contained in:
nmzik
2026-09-23 10:41:03 +04:00
parent d6dac92da1
commit 13fcb3a133
16 changed files with 977 additions and 1111 deletions
+2 -8
View File
@@ -219,19 +219,13 @@ void TestUnbasedFlatCacheHitMaterializes() {
"unbased FLAT plan produced unexpected descriptors");
}
void TestFailedMaterializationPreservesPriorStage() {
void TestFailedMaterializationRejectsStage() {
using namespace Libs::Graphics::ShaderRecompiler::IR;
auto plan = UserDataBufferPlan();
ResourceSnapshot snapshot;
snapshot.user_data.push_back(0xfeedbeefu);
ResourceSpecialization specialization;
specialization.buffers.push_back({.packed_stride = 7});
Check(!MaterializeResources(plan, {}, snapshot, specialization),
"missing runtime user data did not reject the cached stage");
Check(snapshot.user_data == std::vector<uint32_t>{0xfeedbeefu} &&
specialization.buffers.size() == 1 &&
specialization.buffers[0].packed_stride == 7,
"failed cache materialization changed its destinations");
}
void TestMixedSamplerDuplicatesTheCorrectSnapshot() {
@@ -268,7 +262,7 @@ int main() {
TestMappedSrtUsesDirectReaderByDefault();
TestIntegerRuntimeValueFollowsSrtReads();
TestUnbasedFlatCacheHitMaterializes();
TestFailedMaterializationPreservesPriorStage();
TestFailedMaterializationRejectsStage();
TestMixedSamplerDuplicatesTheCorrectSnapshot();
std::puts("ResourceMaterializationTests: all cases passed");
return 0;
+75 -82
View File
@@ -30,14 +30,6 @@ void Check(bool condition, const char *message) {
}
}
bool SameResourceSnapshot(const ResourceSnapshot &lhs,
const ResourceSnapshot &rhs) {
return lhs.buffers == rhs.buffers && lhs.images == rhs.images &&
lhs.samplers == rhs.samplers &&
lhs.flattened_srt == rhs.flattened_srt &&
lhs.user_data == rhs.user_data && lhs.uniform_fill == rhs.uniform_fill;
}
template <typename F>
void CheckFatal(F &&function, std::string_view expected, const char *message) {
try {
@@ -162,6 +154,8 @@ struct LinearTestMemory {
uint64_t base = 0x1000;
std::vector<uint32_t> words = std::vector<uint32_t>(0x2200 / 4);
uint64_t fail_address = UINT64_MAX;
uint64_t watched_address = UINT64_MAX;
uint32_t watched_reads = 0;
};
bool ReadLinearTestMemory(void *userdata, uint64_t address, uint32_t *value) {
@@ -172,6 +166,7 @@ bool ReadLinearTestMemory(void *userdata, uint64_t address, uint32_t *value) {
return false;
}
*value = memory->words[(address - memory->base) / sizeof(uint32_t)];
if (address == memory->watched_address) ++memory->watched_reads;
return true;
}
@@ -318,14 +313,10 @@ void TestInvariantIndirectImageMaterialization() {
snapshot.images[0].dwords.begin()),
"invariant indirect image table did not materialize");
const auto prior_snapshot = snapshot;
const auto prior_specialization = specialization;
memory.fail_address = 0x1004u;
Check(!MaterializeResources(resource_plan, runtime, snapshot,
specialization) &&
SameResourceSnapshot(snapshot, prior_snapshot) &&
specialization == prior_specialization,
"rejected planning memory read mutated the snapshot");
specialization),
"unreadable material-table selector was accepted");
memory.fail_address = UINT64_MAX;
memory.words[(0x1000u - memory.base + 36u) / 4u] = 1u;
@@ -433,15 +424,36 @@ void TestInvariantIndirectImageMaterialization() {
.userdata = &memory,
.read_specialization_memory =
ReadLinearTestMemory};
const auto memory_backed_prior_snapshot = snapshot;
const auto memory_backed_prior_specialization = specialization;
Check(!MaterializeResources(memory_backed_plan, memory_backed_runtime,
snapshot, specialization) &&
SameResourceSnapshot(snapshot, memory_backed_prior_snapshot) &&
specialization == memory_backed_prior_specialization,
"rejected indirect table descriptor read mutated the snapshot");
snapshot, specialization),
"unreadable indirect table descriptor was accepted");
memory.fail_address = UINT64_MAX;
memory.watched_address = 0x3100u;
memory.watched_reads = 0;
Check(MaterializeResources(memory_backed_plan, memory_backed_runtime,
snapshot, specialization) && memory.watched_reads == 1u,
"descriptor, flattened SRT and indirect-table roots repeated a clean pointer read");
const auto* buffer_storage = snapshot.buffers.data();
const auto* image_storage = snapshot.images.data();
const auto* flat_storage = snapshot.flattened_srt.data();
const auto* user_data_storage = snapshot.user_data.data();
const auto* buffer_specialization_storage = specialization.buffers.data();
const auto* image_specialization_storage = specialization.images.data();
const auto old_address = snapshot.images[0].dwords[0];
memory.words[(0x2000u - memory.base) / 4u] += 0x100u;
memory.watched_reads = 0;
Check(MaterializeResources(memory_backed_plan, memory_backed_runtime,
snapshot, specialization) && memory.watched_reads == 1u &&
snapshot.images[0].dwords[0] == old_address + 0x100u,
"cache refresh reused stale table contents or repeated its clean pointer read");
Check(snapshot.buffers.data() == buffer_storage && snapshot.images.data() == image_storage &&
snapshot.flattened_srt.data() == flat_storage &&
snapshot.user_data.data() == user_data_storage &&
specialization.buffers.data() == buffer_specialization_storage &&
specialization.images.data() == image_specialization_storage,
"a same-shape refresh discarded the runtime output storage");
auto malformed = MakeIndirectImageFixture(true);
BuildSrtPlan(malformed->program);
CheckFatal([&] { TrackResources(malformed->program); }, "not a valid runtime value",
@@ -528,13 +540,9 @@ void TestUniformScalarBufferImage() {
memory.words[0x44u / 4u] = 0u;
memory.words[0x1010u / 4u] = 0x30u;
Check(materializes(0x30u), "changed scalar table memory reused the previous image descriptor");
const auto prior_snapshot = snapshot;
const auto prior_specialization = specialization;
memory.fail_address = 0x1044u;
Check(!MaterializeResources(plan, runtime, snapshot, specialization) &&
SameResourceSnapshot(snapshot, prior_snapshot) &&
specialization == prior_specialization,
"unavailable nested image table partially changed the resource snapshot");
Check(!MaterializeResources(plan, runtime, snapshot, specialization),
"unavailable nested image table was accepted");
}
void TestComputeBufferFill() {
@@ -631,6 +639,12 @@ void TestComputeBufferFill() {
snapshot.uniform_fill.value ==
(options.scalar ? 0x40404040u : 0u),
"fill proof lost address coverage or the actual stored scalar");
if (options.scalar && options.clean) {
Check(MaterializeResources(plan,
{.user_data = userdata, .read_memory = Read, .userdata = &memory},
snapshot, specialization) && snapshot.uniform_fill.words == 0,
"an unavailable clean value retained a previous uniform fill");
}
}
};
Run({});
@@ -749,12 +763,12 @@ void TestRuntimeUnsignedMinDescriptor() {
SrtRuntime runtime{.user_data = user_data};
DescriptorValue value;
const auto source = fixture.program.info.buffers[0].source;
Check(EvaluateDescriptorSource(fixture.program, source, runtime, value) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(source, value) &&
value.dwords[3] == 0x100u,
"runtime descriptor unsigned minimum did not clamp its first operand");
user_data[0] = 0x80u;
Check(
EvaluateDescriptorSource(fixture.program, source, runtime, value) &&
SrtWalker(fixture.program, runtime).EvaluateDescriptor(source, value) &&
value.dwords[3] == 0x80u,
"runtime descriptor unsigned minimum did not preserve its first operand");
}
@@ -865,7 +879,7 @@ void TestSampleAdjustSamplerScratch() {
std::array<uint32_t, 4> user_data{4u, 1u, 2u, 0x80000abcu};
SrtRuntime runtime{.user_data = user_data};
DescriptorValue descriptor;
Check(EvaluateDescriptorSource(fixture.program, source, runtime, descriptor) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(source, descriptor) &&
descriptor.dwords[3] == 0x80000abcu,
"SampleAdjust canonicalization lost sampler border fields");
@@ -972,13 +986,11 @@ void TestFmaskLoadSpecialization() {
"FMASK load did not lower to a value vector");
result = vector->Arg(0);
uint32_t value = 0;
Check(EvaluateUniformValues(fixture.program, {&result, 1},
{.user_data = user_data}, {&value, 1}) &&
Check(SrtWalker(fixture.program, {.user_data = user_data}).Evaluate(result, value) &&
value == 0x76543210u,
"FMASK load did not return the native sample-to-fragment mapping");
user_data[8] = 1;
Check(EvaluateUniformValues(fixture.program, {&result, 1},
{.user_data = user_data}, {&value, 1}) &&
Check(SrtWalker(fixture.program, {.user_data = user_data}).Evaluate(result, value) &&
value == 0u,
"inactive FMASK load did not preserve the execution mask");
ShaderComputeInputInfo compute{};
@@ -1128,13 +1140,9 @@ void TestDynamicStorageMipTracking() {
changed_user_data[3] =
(changed_user_data[3] & ~((0xfu << 12u) | (0xfu << 16u))) |
(4u << 12u) | (3u << 16u);
const auto valid_snapshot = changed_snapshot;
const auto valid_specialization = changed_specialization;
Check(!MaterializeResources(resource_plan, {.user_data = changed_user_data},
changed_snapshot, changed_specialization) &&
SameResourceSnapshot(changed_snapshot, valid_snapshot) &&
changed_specialization == valid_specialization,
"an inverted dynamic storage mip range was accepted or mutated output");
changed_snapshot, changed_specialization),
"an inverted dynamic storage mip range was accepted");
}
void TestSrtFlatteningAndRuntimeMemoization() {
@@ -1175,53 +1183,37 @@ void TestSrtFlatteningAndRuntimeMemoization() {
SrtRuntime runtime{.user_data = user_data,
.read_memory = ReadTestMemory,
.userdata = &memory};
std::vector<DescriptorValue> descriptors;
DescriptorValue descriptor;
std::vector<uint32_t> flat;
std::vector<uint8_t> active_sources;
const uint32_t request = fixture.program.info.buffers[0].source;
Check(EvaluateRuntimeSources(fixture.program, std::span{&request, 1}, runtime,
descriptors, flat, {}, active_sources),
"typed runtime source evaluation failed");
Check(descriptors.size() == 1 && descriptors[0].dwords[0] == 0xdeadbeefu &&
const auto refresh = [&](const ResourcePlan& plan) {
SrtWalker walker(plan, runtime);
return walker.EvaluateDescriptor(request, descriptor) && walker.RefreshFlatBuffer(flat);
};
Check(refresh(fixture.program), "typed runtime source evaluation failed");
Check(descriptor.dwords[0] == 0xdeadbeefu &&
flat == std::vector<uint32_t>{0xdeadbeefu} && memory.reads == 1,
"descriptor and flat SRT evaluation did not share one memoized read");
memory.reads = 0;
memory.words[1] = 0x12345678u;
Check(EvaluateRuntimeSources(fixture.program, std::span{&request, 1}, runtime,
descriptors, flat, {}, active_sources) &&
descriptors[0].dwords[0] == 0x12345678u &&
Check(refresh(fixture.program) && descriptor.dwords[0] == 0x12345678u &&
flat == std::vector<uint32_t>{0x12345678u} && memory.reads == 1,
"repeated runtime evaluation reused stale scalar memory");
memory.reads = 0;
memory.fail_after = 0;
descriptors = {{{1u}, 1u}};
flat = {2u};
active_sources = {3u};
Check(!EvaluateRuntimeSources(fixture.program, std::span{&request, 1},
runtime, descriptors, flat, {}, active_sources) &&
descriptors == std::vector<DescriptorValue>{{{1u}, 1u}} &&
flat == std::vector<uint32_t>{2u} &&
active_sources == std::vector<uint8_t>{3u},
"runtime evaluation failure was not transactional");
Check(!refresh(fixture.program), "unavailable scalar memory was accepted");
memory.fail_after = UINT32_MAX;
Check(EvaluateRuntimeSources(fixture.program, std::span{&request, 1}, runtime,
descriptors, flat, {}, active_sources) &&
descriptors[0].dwords[0] == 0x12345678u && memory.reads == 1,
Check(refresh(fixture.program) && descriptor.dwords[0] == 0x12345678u && memory.reads == 1,
"failed runtime evaluation left a value marked as visiting");
auto detached = ExtractResourcePlan(fixture.program);
Check(EvaluateRuntimeSources(detached, std::span{&request, 1}, runtime,
descriptors, flat, {}, active_sources),
"detached resource plan did not evaluate");
Check(refresh(detached), "detached resource plan did not evaluate");
auto moved = std::move(detached);
memory.reads = 0;
memory.words[1] = 0x87654321u;
Check(EvaluateRuntimeSources(moved, std::span{&request, 1}, runtime,
descriptors, flat, {}, active_sources) &&
descriptors[0].dwords[0] == 0x87654321u && memory.reads == 1,
Check(refresh(moved) && descriptor.dwords[0] == 0x87654321u && memory.reads == 1,
"moving a cached resource plan lost its evaluation state");
ShaderComputeInputInfo compute{};
@@ -1262,8 +1254,7 @@ void TestDynamicSrtReadRemainsExplicit() {
.read_memory = ReadTestMemory,
.userdata = &memory};
DescriptorValue value;
Check(EvaluateDescriptorSource(fixture.program,
fixture.program.info.buffers[0].source, runtime, value) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(fixture.program.info.buffers[0].source, value) &&
value.dwords[0] == 0xabcdef01u && memory.reads == 1,
"dynamic typed scalar descriptor source was not evaluated");
@@ -1438,7 +1429,8 @@ void TestConditionalSamplerPhi() {
const uint32_t first = (flag < 0) != reverse ? 480 / 4 : 448 / 4;
memory.fail_address = 0x1000 + (first == 448 / 4 ? 480u : 448u);
DescriptorValue selected;
Check(EvaluateDescriptorSource(plan, source, runtime, selected),
SrtWalker clean(plan, CleanRuntime(runtime));
Check(SrtWalker(plan, runtime, {}, &clean).EvaluateDescriptor(source, selected),
"conditional sampler did not survive detached plan lifetime");
for (uint32_t word = 0; word < 4; ++word) {
Check(selected.dwords[word] == memory.words[first + word],
@@ -1448,13 +1440,17 @@ void TestConditionalSamplerPhi() {
DescriptorValue selected;
auto no_clean_reader = runtime;
no_clean_reader.read_specialization_memory = nullptr;
Check(
!EvaluateDescriptorSource(plan, source, no_clean_reader, selected),
"conditional sampler used unchecked memory for its predicate");
{
SrtWalker clean(plan, CleanRuntime(no_clean_reader));
Check(!SrtWalker(plan, no_clean_reader, {}, &clean).EvaluateDescriptor(source, selected),
"conditional sampler used unchecked memory for its predicate");
}
memory.fail_address = 0x2000 + 196;
Check(!EvaluateDescriptorSource(plan, source, runtime, selected),
"conditional sampler ignored unavailable coherent predicate "
"memory");
{
SrtWalker clean(plan, CleanRuntime(runtime));
Check(!SrtWalker(plan, runtime, {}, &clean).EvaluateDescriptor(source, selected),
"conditional sampler ignored unavailable coherent predicate memory");
}
}
}
CheckFatal([&] { ConditionalSamplerPlan(diamond, false, false, true); },
@@ -1511,8 +1507,7 @@ void TestInvariantLoopPhi() {
std::array<uint32_t, 1> user_data{0x12345678u};
SrtRuntime runtime{.user_data = user_data};
DescriptorValue descriptor;
Check(EvaluateDescriptorSource(fixture.program,
fixture.program.info.buffers[0].source, runtime, descriptor) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(fixture.program.info.buffers[0].source, descriptor) &&
descriptor.dwords[0] == user_data[0],
"loop-invariant descriptor phi was not evaluated through typed SSA");
}
@@ -1738,11 +1733,9 @@ void TestConditionalBufferMaterialization() {
runtime.user_data = std::span(user_data).first(4);
Check(MaterializeResources(plan, runtime, snapshot, specialization),
"untaken branch evaluated its unavailable descriptor");
const auto prior = snapshot;
memory.words[0] = 1;
Check(!MaterializeResources(plan, runtime, snapshot, specialization) &&
SameResourceSnapshot(snapshot, prior),
"taken branch accepted an unavailable descriptor or changed the snapshot");
Check(!MaterializeResources(plan, runtime, snapshot, specialization),
"taken branch accepted an unavailable descriptor");
runtime.user_data = user_data;
const auto CheckActive = [&] {
+16 -23
View File
@@ -122,7 +122,7 @@ void TestImmediateFlatteningAndGvn() {
TestMemory memory_image{{{0x1020u, 0xfeedbeefu}}};
SrtRuntime runtime{.read_memory = ReadMemory, .userdata = &memory_image};
std::vector<uint32_t> flat;
Check(WalkSrt(fixture.program, runtime, flat), "flattened SRT walk failed");
Check(SrtWalker(fixture.program, runtime).RefreshFlatBuffer(flat), "flattened SRT walk failed");
Check(flat == std::vector<uint32_t>{0xfeedbeefu} && memory_image.reads == 1,
"flattened SRT did not evaluate its canonical read once");
}
@@ -139,7 +139,7 @@ void TestRawScalarComponentAlignment() {
TestMemory memory_image{{{0x1000u, 0x12345678u}}};
SrtRuntime runtime{.read_memory = ReadMemory, .userdata = &memory_image};
std::vector<uint32_t> flat;
Check(WalkSrt(fixture.program, runtime, flat), "raw scalar SRT walk failed");
Check(SrtWalker(fixture.program, runtime).RefreshFlatBuffer(flat), "raw scalar SRT walk failed");
Check(
flat == std::vector<uint32_t>{0x12345678u} && memory_image.reads == 1,
"raw scalar base, immediate, and offset were not aligned independently");
@@ -195,7 +195,7 @@ void TestNestedSrtWalk() {
TestMemory memory_image{{{0x1000u, 0x2000u}, {0x2000u, 0xabcdef01u}}};
SrtRuntime runtime{.read_memory = ReadMemory, .userdata = &memory_image};
std::vector<uint32_t> flat;
Check(WalkSrt(fixture.program, runtime, flat), "nested SRT walk failed");
Check(SrtWalker(fixture.program, runtime).RefreshFlatBuffer(flat), "nested SRT walk failed");
Check(flat == std::vector<uint32_t>({0x2000u, 0xabcdef01u}),
"nested typed SRT reads were not evaluated in dependency order");
}
@@ -218,7 +218,7 @@ void TestShaderBaseAndUserData() {
SrtRuntime runtime{.user_data = user_data,
.shader_base = 0x12345678abcdef00ull};
DescriptorValue result;
Check(EvaluateDescriptorSource(fixture.program, 0, runtime, result),
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(0, result),
"shader-relative descriptor evaluation failed");
Check(result.dword_count == 3 && result.dwords[0] == 0xabcdef00u &&
result.dwords[1] == 0x12345678u && result.dwords[2] == 0x24u,
@@ -243,7 +243,7 @@ void TestCarryAndBitFields() {
{.dwords = {low, high, inserted, sign}, .dword_count = 4});
DescriptorValue result;
Check(EvaluateDescriptorSource(fixture.program, 0, {}, result),
Check(SrtWalker(fixture.program, {}).EvaluateDescriptor(0, result),
"carry and bit-field descriptor evaluation failed");
Check(result.dwords[0] == 1u && result.dwords[1] == 1u &&
result.dwords[2] == 0x89abcdefu && result.dwords[3] == 0xffffffffu,
@@ -267,14 +267,11 @@ void TestInvariantAndDivergentPhi() {
{.dwords = {Value(&divergent)}, .dword_count = 1});
DescriptorValue result;
Check(EvaluateDescriptorSource(fixture.program, 0, {}, result) &&
Check(SrtWalker(fixture.program, {}).EvaluateDescriptor(0, result) &&
result.dwords[0] == 7u,
"loop-invariant typed phi was rejected");
result.dword_count = 4;
result.dwords[0] = 0xdeadbeefu;
Check(!EvaluateDescriptorSource(fixture.program, 1, {}, result) &&
result.dword_count == 4 && result.dwords[0] == 0xdeadbeefu,
"divergent phi did not fail transactionally");
Check(!SrtWalker(fixture.program, {}).EvaluateDescriptor(1, result),
"divergent phi was accepted");
}
void TestControlDependentStandaloneLoadStaysTyped() {
@@ -314,7 +311,7 @@ void TestRuntime64BitDescriptorOps() {
{.dwords = {low, high}, .dword_count = 2});
DescriptorValue result;
Check(EvaluateDescriptorSource(fixture.program, 0, {}, result) &&
Check(SrtWalker(fixture.program, {}).EvaluateDescriptor(0, result) &&
result.dwords[0] == 0xabcdu && result.dwords[1] == 0x1235u,
"64-bit typed descriptor arithmetic evaluation is incorrect");
}
@@ -389,11 +386,11 @@ void TestUniformFirstLaneSamplerLod() {
user_data[6] = 3u;
SrtRuntime runtime{.user_data = user_data};
DescriptorValue result;
Check(EvaluateDescriptorSource(fixture.program, 0, runtime, result) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(0, result) &&
result.dwords[0] == 0x00300300u,
"uniform sampler LOD evaluated incorrectly");
user_data[6] = 20u;
Check(EvaluateDescriptorSource(fixture.program, 0, runtime, result) &&
Check(SrtWalker(fixture.program, runtime).EvaluateDescriptor(0, result) &&
result.dwords[0] == 0x00ffffffu,
"uniform sampler LOD clamp evaluated incorrectly");
}
@@ -455,7 +452,7 @@ void TestConstantBufferBounds() {
TestMemory memory_image{{{0x300cu, 0xa5a5a5a5u}}};
SrtRuntime runtime{.read_memory = ReadMemory, .userdata = &memory_image};
std::vector<uint32_t> flat;
Check(WalkSrt(fixture.program, runtime, flat) &&
Check(SrtWalker(fixture.program, runtime).RefreshFlatBuffer(flat) &&
flat == std::vector<uint32_t>{0xa5a5a5a5u},
"constant-buffer SRT walk failed");
@@ -470,10 +467,8 @@ void TestConstantBufferBounds() {
overflow.Emit(ValueOpcode::GetBufferResource,
{overflow_read, Value(0u), Value(16u), Value(0u)});
overflow.Plan();
flat = {0x55u};
Check(!WalkSrt(overflow.program, runtime, flat) &&
flat == std::vector<uint32_t>{0x55u},
"out-of-bounds constant-buffer walk was not transactional");
Check(!SrtWalker(overflow.program, runtime).RefreshFlatBuffer(flat),
"out-of-bounds constant-buffer walk was accepted");
}
void TestReadLaneElimination() {
@@ -560,10 +555,8 @@ void TestUndefinedRuntimeValueFails() {
fixture.program.descriptor_sources.push_back(
{.dwords = {undef}, .dword_count = 1});
DescriptorValue result;
result.dword_count = 3;
Check(!EvaluateDescriptorSource(fixture.program, 0, {}, result) &&
result.dword_count == 3,
"undefined typed descriptor source did not fail transactionally");
Check(!SrtWalker(fixture.program, {}).EvaluateDescriptor(0, result),
"undefined typed descriptor source was accepted");
}
} // namespace
+72 -54
View File
@@ -1325,12 +1325,15 @@ void CheckRectListShaders() {
ShaderVertexInputInfo vertex{};
ShaderRecompiler::IR::CompiledShaderInfo vertex_program{.param_export_mask = 1u};
ShaderRecompiler::IR::ResourceSnapshot empty_snapshot;
vertex.stage.program = &vertex_program;
vertex.stage.resources = &empty_snapshot;
ShaderPixelInputInfo pixel{};
pixel.input_num = 2;
pixel.interpolator_settings[0] = 0x400u;
pixel.interpolator_settings[1] = 0;
pixel.stage.program = &program;
pixel.stage.resources = &empty_snapshot;
std::vector<uint32_t> perspective_specialization;
BuildStageStaticKey(pixel, perspective_specialization);
pixel.ps_no_perspective = true;
@@ -1967,10 +1970,12 @@ public:
pixel_program.bindings.push_data_start_dword = 0;
pixel_program.bindings.user_data_registers = {0, 1};
pixel_program.bindings.memory_offset_dword = 2;
ShaderStageRuntime vertex_runtime{.program = &vertex_program};
vertex_runtime.resources.user_data = {0x11111111u, 0x22222222u};
ShaderStageRuntime pixel_runtime{.program = &pixel_program};
pixel_runtime.resources.user_data = {0x33333333u, 0x44444444u};
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
vertex_snapshot.user_data = {0x11111111u, 0x22222222u};
ShaderStageRuntime vertex_runtime{&vertex_program, &vertex_snapshot};
ShaderRecompiler::IR::ResourceSnapshot pixel_snapshot;
pixel_snapshot.user_data = {0x33333333u, 0x44444444u};
ShaderStageRuntime pixel_runtime{&pixel_program, &pixel_snapshot};
auto vertex = context.GetRenderExecutor().PrepareBindings(vertex_runtime);
auto pixel = context.GetRenderExecutor().PrepareBindings(pixel_runtime);
@@ -4498,7 +4503,8 @@ public:
"test HTile entries were not registered in their initial state");
const auto MakeInput = [](uint64_t address, bool read, bool written,
ShaderRecompiler::IR::CompiledShaderInfo &program) {
ShaderRecompiler::IR::CompiledShaderInfo &program,
ShaderRecompiler::IR::ResourceSnapshot &snapshot) {
program.stage = ShaderType::Compute;
ShaderRecompiler::IR::BufferResource resource{};
resource.read = read;
@@ -4519,14 +4525,17 @@ public:
std::copy_n(descriptor.fields, value.dword_count, value.dwords.begin());
ShaderComputeInputInfo input{};
input.stage.program = &program;
input.stage.resources.buffers.push_back(value);
snapshot.buffers.push_back(value);
input.stage.resources = &snapshot;
return input;
};
auto &executor = context.GetRenderExecutor();
auto &command = scheduler.Current();
ShaderRecompiler::IR::CompiledShaderInfo read_only_program{};
ShaderRecompiler::IR::ResourceSnapshot read_only_snapshot;
const auto read_only_input =
MakeInput(read_only_meta, true, false, read_only_program);
MakeInput(read_only_meta, true, false, read_only_program,
read_only_snapshot);
const bool read_only_consumed =
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
executor, read_only_input, command);
@@ -4536,8 +4545,10 @@ public:
"a metadata read-only dispatch changed logical clear state");
ShaderRecompiler::IR::CompiledShaderInfo read_write_program{};
ShaderRecompiler::IR::ResourceSnapshot read_write_snapshot;
const auto read_write_input =
MakeInput(read_write_meta, true, true, read_write_program);
MakeInput(read_write_meta, true, true, read_write_program,
read_write_snapshot);
const bool read_write_consumed =
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
executor, read_write_input, command);
@@ -4547,8 +4558,10 @@ public:
"a metadata read/modify/write dispatch was replaced by a clear");
ShaderRecompiler::IR::CompiledShaderInfo write_only_program{};
ShaderRecompiler::IR::ResourceSnapshot write_only_snapshot;
const auto write_only_input =
MakeInput(write_only_meta, false, true, write_only_program);
MakeInput(write_only_meta, false, true, write_only_program,
write_only_snapshot);
const bool write_only_consumed =
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
executor, write_only_input, command);
@@ -9891,8 +9904,9 @@ public:
ShaderBufferResource buffer_descriptor{};
buffer_descriptor.UpdateAddress48(buffer_address);
buffer_descriptor.fields[2] = 0x8000;
ShaderStageRuntime buffer_runtime{.program = &buffer_program};
auto &value = buffer_runtime.resources.buffers.emplace_back();
ShaderRecompiler::IR::ResourceSnapshot buffer_snapshot;
ShaderStageRuntime buffer_runtime{&buffer_program, &buffer_snapshot};
auto &value = buffer_snapshot.buffers.emplace_back();
std::memcpy(value.dwords.data(), buffer_descriptor.fields,
sizeof(buffer_descriptor.fields));
value.dword_count = 4;
@@ -9962,7 +9976,7 @@ public:
null_info.stage = null_program.stage;
null_info.info = std::move(null_program.info);
null_info.bindings = std::move(null_program.bindings);
ShaderStageRuntime null_runtime{&null_info, std::move(null_snapshot)};
ShaderStageRuntime null_runtime{&null_info, &null_snapshot};
auto null_bindings = executor.PrepareBindings(null_runtime);
executor.RebindImages(null_bindings);
Require(name, "null descriptor count",
@@ -10161,7 +10175,7 @@ public:
mipped_storage_descriptor,
overwide_mipped_storage_descriptor,
overwide_mipped_storage_descriptor};
ShaderStageRuntime mipped_runtime{&mipped_program, std::move(mipped_snapshot)};
ShaderStageRuntime mipped_runtime{&mipped_program, &mipped_snapshot};
mipped_prepared.runtime = &mipped_runtime;
mipped_prepared.images.push_back(
std::move(plain_mipped_storage_binding));
@@ -10468,8 +10482,7 @@ public:
storage_info.stage = storage_program.stage;
storage_info.info = std::move(storage_program.info);
storage_info.bindings = std::move(storage_program.bindings);
ShaderStageRuntime storage_runtime{&storage_info,
std::move(storage_snapshot)};
ShaderStageRuntime storage_runtime{&storage_info, &storage_snapshot};
auto storage_discovery = executor.PrepareBindings(storage_runtime);
const auto storage_id = storage_discovery.images[0].image_id;
Require(name, "storage prefetch purity",
@@ -10499,8 +10512,7 @@ public:
sampled_info.stage = sampled_program.stage;
sampled_info.info = std::move(sampled_program.info);
sampled_info.bindings = std::move(sampled_program.bindings);
ShaderStageRuntime sampled_runtime{&sampled_info,
std::move(sampled_snapshot)};
ShaderStageRuntime sampled_runtime{&sampled_info, &sampled_snapshot};
constexpr uint64_t ordered_sampled_address = base + 0x10000;
const uint32_t ordered_sampled_value = 0x89abcdefu;
@@ -10521,7 +10533,7 @@ public:
ShaderRecompiler::IR::ResourceSnapshot ordered_snapshot{};
ordered_snapshot.images.push_back(ordered_descriptor);
ShaderStageRuntime ordered_sampled_runtime{sampled_runtime.program,
std::move(ordered_snapshot)};
&ordered_snapshot};
auto ordered_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings(
executor, storage_runtime, ordered_sampled_runtime, true);
const auto ordered_sampled_id =
@@ -10669,7 +10681,8 @@ public:
split_program.info = std::move(split_ir.info);
split_program.bindings = std::move(split_ir.bindings);
PreparedBindings split_bindings{};
ShaderStageRuntime split_runtime{.program = &split_program};
ShaderRecompiler::IR::ResourceSnapshot split_snapshot;
ShaderStageRuntime split_runtime{&split_program, &split_snapshot};
split_bindings.runtime = &split_runtime;
split_bindings.images.push_back(
{split_id, texture_cache.FindTexture(split_id, split_storage_desc),
@@ -10993,10 +11006,10 @@ public:
registers.SetDepthControl(bounds_control);
registers.SetRenderControl({});
registers.SetDepthClearValue(0.375f);
ShaderStageRuntime bounds_vertex{&vertex_sampled_info, {}};
ShaderStageRuntime bounds_pixel{&sampled_info, {}};
bounds_vertex.resources.images.push_back(sampled_depth_value);
bounds_pixel.resources.images.push_back(sampled_depth_value);
ShaderRecompiler::IR::ResourceSnapshot bounds_snapshot;
bounds_snapshot.images.push_back(sampled_depth_value);
ShaderStageRuntime bounds_vertex{&vertex_sampled_info, &bounds_snapshot};
ShaderStageRuntime bounds_pixel{&sampled_info, &bounds_snapshot};
const auto depth_texels = depth_only.desc.info.extent.width *
depth_only.desc.info.extent.height;
const auto depth_bytes = depth_texels * sizeof(uint32_t);
@@ -11341,10 +11354,12 @@ public:
std::end(shared_depth_descriptor.fields),
shared_depth_value.dwords.begin());
shared_depth_value.dword_count = 8;
ShaderStageRuntime shared_depth_vertex{&vertex_sampled_info, {}};
ShaderStageRuntime shared_depth_pixel{&sampled_info, {}};
shared_depth_vertex.resources.images.push_back(shared_depth_value);
shared_depth_pixel.resources.images.push_back(shared_depth_value);
ShaderRecompiler::IR::ResourceSnapshot shared_depth_snapshot;
shared_depth_snapshot.images.push_back(shared_depth_value);
ShaderStageRuntime shared_depth_vertex{&vertex_sampled_info,
&shared_depth_snapshot};
ShaderStageRuntime shared_depth_pixel{&sampled_info,
&shared_depth_snapshot};
for (const bool stencil_write : {true, false}) {
registers.SetDepthRenderTarget(phased_depth_target);
registers.SetRenderControl({});
@@ -11486,8 +11501,7 @@ public:
array_descriptor.dword_count = 8;
ShaderRecompiler::IR::ResourceSnapshot array_snapshot{};
array_snapshot.images.push_back(array_descriptor);
ShaderStageRuntime array_runtime{&array_program,
std::move(array_snapshot)};
ShaderStageRuntime array_runtime{&array_program, &array_snapshot};
auto array_binding = executor.PrepareBindings(array_runtime);
executor.RebindImages(array_binding);
@@ -11572,8 +11586,9 @@ public:
descriptor.fields[1] |= 4u << 16u;
descriptor.fields[2] = buffer_size / sizeof(uint32_t);
descriptor.fields[3] = 0x00014004u;
ShaderStageRuntime buffer_runtime{.program = &buffer_program};
auto &value = buffer_runtime.resources.buffers.emplace_back();
ShaderRecompiler::IR::ResourceSnapshot buffer_snapshot;
ShaderStageRuntime buffer_runtime{&buffer_program, &buffer_snapshot};
auto &value = buffer_snapshot.buffers.emplace_back();
std::memcpy(value.dwords.data(), descriptor.fields, sizeof(descriptor.fields));
value.dword_count = 4;
auto buffer_bindings = executor.PrepareBindings(buffer_runtime);
@@ -11660,7 +11675,7 @@ public:
ShaderRecompiler::IR::ResourceSnapshot colliding_msaa_snapshot{};
colliding_msaa_snapshot.images.push_back(colliding_msaa_descriptor);
ShaderStageRuntime colliding_msaa_runtime{
&colliding_msaa_program, std::move(colliding_msaa_snapshot)};
&colliding_msaa_program, &colliding_msaa_snapshot};
auto colliding_msaa_binding =
executor.PrepareBindings(colliding_msaa_runtime);
executor.RebindImages(colliding_msaa_binding);
@@ -11719,7 +11734,7 @@ public:
msaa_program.info.images.push_back(msaa_resource);
ShaderRecompiler::IR::ResourceSnapshot msaa_snapshot{};
msaa_snapshot.images.push_back(msaa_descriptor);
ShaderStageRuntime msaa_runtime{&msaa_program, std::move(msaa_snapshot)};
ShaderStageRuntime msaa_runtime{&msaa_program, &msaa_snapshot};
auto msaa_binding = executor.PrepareBindings(msaa_runtime);
executor.RebindImages(msaa_binding);
const auto &resolved_msaa = msaa_binding.images[0];
@@ -11758,8 +11773,7 @@ public:
msaa_array_program.info.images.push_back(msaa_array_resource);
ShaderRecompiler::IR::ResourceSnapshot msaa_array_snapshot{};
msaa_array_snapshot.images.push_back(msaa_array_descriptor);
ShaderStageRuntime msaa_array_runtime{&msaa_array_program,
std::move(msaa_array_snapshot)};
ShaderStageRuntime msaa_array_runtime{&msaa_array_program, &msaa_array_snapshot};
auto msaa_array_binding = executor.PrepareBindings(msaa_array_runtime);
executor.RebindImages(msaa_array_binding);
const auto &resolved_msaa_array = msaa_array_binding.images[0];
@@ -12022,7 +12036,7 @@ public:
descriptor.dwords.begin());
descriptor.dword_count = 8;
snapshot.images.push_back(descriptor);
ShaderStageRuntime runtime{&program, std::move(snapshot)};
ShaderStageRuntime runtime{&program, &snapshot};
auto prepared = context.GetRenderExecutor().PrepareBindings(runtime);
const auto sampled_stencil_id = prepared.images[0].image_id;
@@ -12103,6 +12117,8 @@ public:
auto stencil_translated = ShaderRecompiler::TranslateProgram(stencil_shader, stencil_options);
auto stencil_plan = ShaderRecompiler::IR::ExtractResourcePlan(stencil_translated.program);
ShaderRecompiler::IR::ResourceSpecialization stencil_specialization;
ShaderRecompiler::IR::ResourceSnapshot stencil_snapshot;
stencil_compute.stage.resources = &stencil_snapshot;
Require(name, "stencil fill materialization",
ShaderRecompiler::IR::MaterializeResources(stencil_plan,
{.user_data = stencil_userdata, .userdata = &stencil_byte,
@@ -12110,7 +12126,7 @@ public:
if (address != reinterpret_cast<uint64_t>(data)) return false;
*word = *static_cast<uint32_t *>(data);
return true;
}}, stencil_compute.stage.resources, stencil_specialization),
}}, stencil_snapshot, stencil_specialization),
"captured stencil shader could not resolve its clear byte");
ShaderRecompiler::IR::ApplyResourceSpecialization(stencil_translated.program,
stencil_specialization);
@@ -12129,7 +12145,7 @@ public:
!RenderExecutorTestAccess::TryConsumeComputeImageClear(executor, stencil_compute,
scheduler.Current(), 2, 1, 1, 0x41u),
"incomplete or excessive stencil dispatch was consumed");
auto &stencil_source = stencil_compute.stage.resources.buffers[0];
auto &stencil_source = stencil_snapshot.buffers[0];
const auto clean_source = stencil_source;
stencil_source.dwords[0] = static_cast<uint32_t>(stencil_address);
stencil_source.dwords[1] = static_cast<uint32_t>(stencil_address >> 32) | (4u << 16);
@@ -13068,7 +13084,9 @@ public:
pixel_program.info = fragment.program.info;
pixel_program.bindings = fragment.program.bindings;
ShaderVertexInputInfo vertex{};
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
vertex.stage.program = &vertex_program;
vertex.stage.resources = &vertex_snapshot;
vertex.resources_num = 2;
vertex.buffers_num = 1;
vertex.buffers[0].stride = 6 * sizeof(float);
@@ -13086,7 +13104,7 @@ public:
}
ShaderPixelInputInfo pixel{};
pixel.stage.program = &pixel_program;
pixel.stage.resources = std::move(fragment.resources);
pixel.stage.resources = &fragment.resources;
RenderColorInfo color{};
color.desc.type = BindingType::RenderTarget;
@@ -27901,8 +27919,8 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
const auto code = MakeCode();
auto positive = Compile(code);
compute.stage.resources = positive;
auto runtime_resources = positive;
compute.stage.resources = &runtime_resources;
ShaderBufferResource descriptor{};
u32 packed_clear = 0;
uint64_t size = 0;
@@ -27915,19 +27933,19 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
auto wrong_index = code;
wrong_index[0] = (wrong_index[0] & ~(0x3ffu << 16u)) | (0x347u << 16u);
compute.stage.resources = Compile(wrong_index);
runtime_resources = Compile(wrong_index);
Require("Ps5GameExampleImageClear", "add-before-shift address",
!ResolveComputeBufferFill(compute, 64, 1, 1, 0x61u, descriptor,
packed_clear, size),
"V_ADD_LSHL was mistaken for V_LSHL_ADD contiguous coverage");
user_data[7] ^= 1u;
compute.stage.resources = Compile(code);
runtime_resources = Compile(code);
Require("Ps5GameExampleImageClear", "non-repeated clear",
!ResolveComputeBufferFill(compute, 64, 1, 1, 0x61u, descriptor,
packed_clear, size),
"non-uniform uint4 data was replaced with a color clear");
compute.stage.resources = positive;
runtime_resources = positive;
compute.dispatch_threads_num[0] = 32;
Require("Ps5GameExampleImageClear", "partial dispatch",
!ResolveComputeBufferFill(compute, 32, 1, 1, 0x61u, descriptor,
@@ -27946,7 +27964,7 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
scalar_code.push_back(EncodeMubuf1(1, 0, 0));
AppendEnd(&scalar_code);
auto scalar = Compile(scalar_code);
compute.stage.resources = scalar;
runtime_resources = scalar;
Require("Ps5GameExampleImageClear", "inline scalar fill",
ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size) &&
@@ -27958,13 +27976,13 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
packed_clear, size),
"excess invocation coverage was accepted as a fill");
auto alias = scalar.buffers.front();
compute.stage.resources.buffers.push_back(alias);
runtime_resources.buffers.push_back(alias);
Require("Ps5GameExampleImageClear", "aliased scalar input",
!ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size),
"a scalar read aliasing the destination was accepted as uniform");
compute.stage.resources = scalar;
compute.stage.resources.buffers[0].dwords[3] =
runtime_resources = scalar;
runtime_resources.buffers[0].dwords[3] =
(static_cast<u32>(Prospero::BufferFormat::k32Float) << 12u) | 0x204u;
Require("Ps5GameExampleImageClear", "wrong store format",
!ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
@@ -27973,14 +27991,14 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
// A body change preserving every descriptor and dispatch field must change
// the result.
scalar_code[2] = EncodeVop1(0x01u, 1, InlineU32(7));
compute.stage.resources = Compile(scalar_code);
runtime_resources = Compile(scalar_code);
Require("Ps5GameExampleImageClear", "changed store value",
ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size) &&
packed_clear == 7u,
"clear recognition ignored the shader's actual stored value");
scalar_code[2] = EncodeVop1(0x01u, 1, Vgpr(0));
compute.stage.resources = Compile(scalar_code);
runtime_resources = Compile(scalar_code);
Require("Ps5GameExampleImageClear", "varying store value",
!ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size),
@@ -28002,14 +28020,14 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
AppendEnd(&scalar_code);
clean_scalar = true;
auto loaded = Compile(scalar_code);
compute.stage.resources = loaded;
runtime_resources = loaded;
Require("Ps5GameExampleImageClear", "scalar-loaded fill",
ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size) &&
packed_clear == scalar_clear && descriptor.Base48() == 0x200000u,
"GTA3's scalar input was confused with its destination");
clean_scalar = false;
compute.stage.resources = Compile(scalar_code);
runtime_resources = Compile(scalar_code);
Require("Ps5GameExampleImageClear", "unavailable clean scalar",
!ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
packed_clear, size),
@@ -28303,7 +28321,7 @@ void CheckEmbeddedFetchVertexOffset() {
program.user_data_base = result.program.user_data_base;
program.info.vertex_offset_sgpr = result.program.info.vertex_offset_sgpr;
vertex.stage.program = &program;
vertex.stage.resources = result.resources;
vertex.stage.resources = &result.resources;
return ResolveDrawOffsets(index_offset, vertex).first;
};
@@ -28315,7 +28333,7 @@ void CheckEmbeddedFetchVertexOffset() {
program.info.instance_offset_sgpr =
result.program.info.instance_offset_sgpr;
vertex.stage.program = &program;
vertex.stage.resources = result.resources;
vertex.stage.resources = &result.resources;
return ResolveDrawOffsets(0, vertex).second;
};
+14 -23
View File
@@ -158,9 +158,11 @@ void CompilePixelRuntime(const ShaderParams &params,
options.input_info.pixel = &input_info;
auto result = RecompileForTest(params.code, options);
static std::deque<ShaderRecompiler::IR::CompiledShaderInfo> programs;
static std::deque<ShaderRecompiler::IR::ResourceSnapshot> resources;
programs.push_back(std::move(result.program).TakeCompiledInfo());
input_info.stage.program = &programs.back();
input_info.stage.resources = std::move(result.resources);
resources.push_back(std::move(result.resources));
input_info.stage.resources = &resources.back();
}
template <typename InputInfo>
@@ -1154,20 +1156,17 @@ void TestNativeShaderResourceDependencies() {
.info = program.info,
.bindings = program.bindings,
};
ShaderStageRuntime runtime{.program = &compiled, .resources = resources};
ShaderStageRuntime runtime{.program = &compiled, .resources = &resources};
Check(HasShaderBufferWrites(runtime),
"graphics/compute write predicate lost nonempty written buffers");
set_buffer(0, 0, 16, 3);
set_buffer(2, 0x2000, 0, 0);
runtime.resources = resources;
Check(!HasShaderBufferWrites(runtime),
"graphics/compute write predicate included null, empty, or read-only buffers");
set_buffer(2, 0x2000, 0, 64);
runtime.resources = resources;
Check(HasShaderBufferWrites(runtime),
"graphics/compute write predicate lost a byte-addressed buffer");
set_buffer(2, 0x2000, 0x3FFF, UINT32_MAX);
runtime.resources = resources;
Check(HasShaderBufferWrites(runtime),
"graphics/compute write predicate lost a maximum-size strided buffer");
@@ -9669,10 +9668,8 @@ void TestMergedShaderUserDataSnapshot() {
.read_memory = ReadHostTestMemory};
IR::DescriptorValue front_descriptor, back_descriptor;
const auto &table = params == &first ? first_table : second_table;
Check(IR::EvaluateDescriptorSource(program, program.info.buffers[0].source,
runtime, front_descriptor) &&
IR::EvaluateDescriptorSource(program, program.info.buffers[1].source,
runtime, back_descriptor) &&
Check(IR::SrtWalker(program, runtime).EvaluateDescriptor(program.info.buffers[0].source, front_descriptor) &&
IR::SrtWalker(program, runtime).EvaluateDescriptor(program.info.buffers[1].source, back_descriptor) &&
std::equal(params->user_data.begin() + 8, params->user_data.end(),
front_descriptor.dwords.begin()) &&
std::equal(table.begin(), table.end(), back_descriptor.dwords.begin()),
@@ -12281,8 +12278,7 @@ void TestTypedDescriptorRealCarryAndScalarLoads() {
ShaderRecompiler::IR::SrtRuntime carry_runtime{carry_user_data, shader_base,
nullptr, nullptr};
ShaderRecompiler::IR::DescriptorValue carry_value;
Check(ShaderRecompiler::IR::EvaluateDescriptorSource(
carry_ir, carry_source_index, carry_runtime, carry_value) &&
Check(ShaderRecompiler::IR::SrtWalker(carry_ir, carry_runtime).EvaluateDescriptor(carry_source_index, carry_value) &&
carry_value.dwords[0] == static_cast<uint32_t>(expected_pc) &&
carry_value.dwords[1] == static_cast<uint32_t>(expected_pc >> 32u),
"S_GETPC shader-base or add/addc carry evaluation was incorrect");
@@ -12355,9 +12351,7 @@ void TestTypedDescriptorRealCarryAndScalarLoads() {
TypedDescriptorSource(inline_sampler_ir,
inline_sampler_ir.info.samplers[0].source) !=
nullptr &&
ShaderRecompiler::IR::EvaluateDescriptorSource(
inline_sampler_ir, inline_sampler_ir.info.samplers[0].source,
runtime, sampler) &&
ShaderRecompiler::IR::SrtWalker(inline_sampler_ir, runtime).EvaluateDescriptor(inline_sampler_ir.info.samplers[0].source, sampler) &&
sampler.dwords[0] == 0 && sampler.dwords[1] == 0x00fff000u &&
sampler.dwords[2] == 0x09500000u && sampler.dwords[3] == 0,
"real inline sampler construction was unresolved or evaluated "
@@ -12393,7 +12387,7 @@ void TestSrtWalkerRealSmemTranslation() {
std::vector<uint32_t> flat;
const ShaderRecompiler::IR::SrtRuntime runtime{user_data, 0, ReadSrtHostDword,
nullptr};
const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat);
const auto walked = ShaderRecompiler::IR::SrtWalker(ir, runtime).RefreshFlatBuffer(flat);
Check(walked, "SRT walk failed");
Check(flat.size() == table.size() &&
std::equal(flat.begin(), flat.end(), table.begin()),
@@ -12422,7 +12416,7 @@ void TestSrtWalkerVccBaseTranslation() {
const ShaderRecompiler::IR::SrtRuntime runtime{user_data, 0, ReadSrtHostDword,
nullptr};
std::vector<uint32_t> flat;
Check(ShaderRecompiler::IR::WalkSrt(ir, runtime, flat), "SRT walk failed");
Check(ShaderRecompiler::IR::SrtWalker(ir, runtime).RefreshFlatBuffer(flat), "SRT walk failed");
Check(flat.size() == table.size() &&
std::equal(flat.begin(), flat.end(), table.begin()),
"typed SSA lost an SMEM base copied through VCC");
@@ -12450,18 +12444,15 @@ void TestSrtWalkerRealSBufferTranslation() {
std::vector<uint32_t> flat;
const ShaderRecompiler::IR::SrtRuntime runtime{user_data, 0, ReadSrtHostDword,
nullptr};
const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat);
const auto walked = ShaderRecompiler::IR::SrtWalker(ir, runtime).RefreshFlatBuffer(flat);
Check(walked, "SRT walk failed");
Check(flat.size() == 4 &&
std::equal(flat.begin(), flat.end(), table.begin() + 1),
"real S_BUFFER_LOAD walk used the wrong final alignment");
user_data[10] = 4 * sizeof(uint32_t);
const auto flat_before_failure = flat;
const auto bounds_walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat);
const auto bounds_walked = ShaderRecompiler::IR::SrtWalker(ir, runtime).RefreshFlatBuffer(flat);
Check(!bounds_walked, "real S_BUFFER_LOAD walk ignored descriptor bounds");
Check(flat == flat_before_failure,
"failed real S_BUFFER_LOAD walk changed the prior flat snapshot");
CheckFlattenedReadSlots(
ir, 4, "real S_BUFFER_LOAD patch used the wrong flat offsets");
@@ -12475,7 +12466,7 @@ void TestSrtWalkerRealSBufferTranslation() {
static_cast<uint32_t>(std::size(negative_shader)),
negative_ir);
user_data[10] = sizeof(table);
Check(!ShaderRecompiler::IR::WalkSrt(negative_ir, runtime, flat),
Check(!ShaderRecompiler::IR::SrtWalker(negative_ir, runtime).RefreshFlatBuffer(flat),
"real S_BUFFER_LOAD walk accepted a negative immediate");
}
@@ -12514,7 +12505,7 @@ void TestScalarMemorySourcesCapturedBeforeWrites() {
const ShaderRecompiler::IR::SrtRuntime runtime{
user_data, 0, ReadSrtHostRangeDword, &range};
std::vector<uint32_t> flat;
Check(ShaderRecompiler::IR::WalkSrt(ir, runtime, flat), "SRT walk failed");
Check(ShaderRecompiler::IR::SrtWalker(ir, runtime).RefreshFlatBuffer(flat), "SRT walk failed");
Check(flat.size() == table.size() &&
std::equal(flat.begin(), flat.end(), table.begin()),
"overlapping scalar-memory load did not capture its sources before "