mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
Refresh cached resources in one SRT walk
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 = [&] {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -158,9 +158,11 @@ void CompilePixelRuntime(const ShaderParams ¶ms,
|
||||
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 "
|
||||
|
||||
Reference in New Issue
Block a user