shader: keep unbounded material selectors on bounded GPU heaps

This commit is contained in:
nmzik
2026-10-13 09:19:43 +02:00
parent 735a229236
commit f57d2c0965
2 changed files with 15 additions and 7 deletions
@@ -2103,7 +2103,7 @@ private:
} }
bool MatchScalarMaterialKey(Value key, DescriptorSource::IndirectDescriptor& indirect, bool MatchScalarMaterialKey(Value key, DescriptorSource::IndirectDescriptor& indirect,
DescriptorSource& material_source) { DescriptorSource& material_source, bool require_bound) {
DescriptorSource::IndirectDescriptor::SelectorRead selector; DescriptorSource::IndirectDescriptor::SelectorRead selector;
const auto* read = SelectorReadValue(key, Value(true), selector); const auto* read = SelectorReadValue(key, Value(true), selector);
if (read == nullptr) return false; if (read == nullptr) return false;
@@ -2160,6 +2160,9 @@ private:
offset = static_cast<uint32_t>(affine.offset % divisor) & ~3u; offset = static_cast<uint32_t>(affine.offset % divisor) & ~3u;
} }
} }
// A bounded image heap already supports GPU selection. Only enumerate a
// narrower proven selector domain instead of scanning unrelated material data.
if (require_bound && count.IsEmpty() && !rows) return false;
if (!MakeRuntimeTableSource(*read, material_source)) return false; if (!MakeRuntimeTableSource(*read, material_source)) return false;
selector.source = InternSource(material_source); selector.source = InternSource(material_source);
selector.stride = stride; selector.stride = stride;
@@ -2635,7 +2638,8 @@ private:
// only the image handle is projected onto the bounded workgroup key. // only the image handle is projected onto the bounded workgroup key.
plan.retain_reads = true; plan.retain_reads = true;
} else if (!plan.table_indexed && } else if (!plan.table_indexed &&
MatchScalarMaterialKey(key, indirect, material_source)) { MatchScalarMaterialKey(key, indirect, material_source,
table_source.dword_count == 4u)) {
// Keep live descriptor payloads, but project descriptor-only SMEM onto // Keep live descriptor payloads, but project descriptor-only SMEM onto
// the GPU key using the same plan as other indirect image reads. // the GPU key using the same plan as other indirect image reads.
plan.retain_reads |= table_source.dword_count == 4u; plan.retain_reads |= table_source.dword_count == 4u;
+9 -5
View File
@@ -278,14 +278,17 @@ MakeIndirectImageFixture(bool malformed, uint32_t table_stride = 32, uint32_t ta
return fixture; return fixture;
} }
void TestInvariantIndirectImageMaterialization() { void TestInvariantIndirectImageMaterialization(bool nested) {
auto fixture = MakeIndirectImageFixture(false, 48u, 0u, 16u, true); auto fixture = MakeIndirectImageFixture(false, 48u, 0u, 16u, nested);
fixture->PlanAndTrack(); fixture->PlanAndTrack();
auto plan = ExtractResourcePlan(fixture->program); auto plan = ExtractResourcePlan(fixture->program);
EliminateDeadCode(fixture->program.blocks); EliminateDeadCode(fixture->program.blocks);
ValidateProgram(fixture->program, true); ValidateProgram(fixture->program, true);
const auto &source = *plan.descriptor_sources[plan.info.images[0].source].indirect_descriptor; const auto &source = *plan.descriptor_sources[plan.info.images[0].source].indirect_descriptor;
Check(!source.selector && fixture->program.info.buffers.size() == 3u, Check(!source.selector && fixture->program.info.buffers.size() == (nested ? 3u : 2u) &&
std::ranges::any_of(*fixture->block, [](const Inst &inst) {
return inst.GetOpcode() == ValueOpcode::ReadConstBuffer;
}),
"bounded image table retained CPU selector traversal or lost live loads"); "bounded image table retained CPU selector traversal or lost live loads");
std::array<uint32_t, 8> descriptor{}; std::array<uint32_t, 8> descriptor{};
descriptor[0] = 0x20u; descriptor[0] = 0x20u;
@@ -293,7 +296,7 @@ void TestInvariantIndirectImageMaterialization() {
descriptor[2] = 3u | (3u << 14u); descriptor[2] = 3u | (3u << 14u);
descriptor[3] = Libs::Graphics::DstSel(4, 5, 6, 7) | descriptor[3] = Libs::Graphics::DstSel(4, 5, 6, 7) |
(static_cast<uint32_t>(Libs::Graphics::Prospero::ImageType::kColor2D) << 28u); (static_cast<uint32_t>(Libs::Graphics::Prospero::ImageType::kColor2D) << 28u);
std::array<uint32_t, 16> data{0x3000u, 16u << 16u, 0x200000u, 0u, std::array<uint32_t, 16> data{0x3000u, 4u << 16u, 0x100000u, 0u,
0x2000u, 48u << 16u, 3u, 0u}; 0x2000u, 48u << 16u, 3u, 0u};
std::copy_n(data.begin(), 4u, data.begin() + 12u); std::copy_n(data.begin(), 4u, data.begin() + 12u);
LinearTestMemory memory; LinearTestMemory memory;
@@ -5793,7 +5796,8 @@ int main() {
Run("FMASK load specialization", TestFmaskLoadSpecialization); Run("FMASK load specialization", TestFmaskLoadSpecialization);
Run("gather LOD sampler validation", TestGatherLodSamplerValidation); Run("gather LOD sampler validation", TestGatherLodSamplerValidation);
Run("dynamic storage mips", TestDynamicStorageMipTracking); Run("dynamic storage mips", TestDynamicStorageMipTracking);
Run("invariant indirect images", TestInvariantIndirectImageMaterialization); Run("invariant indirect images", [] { TestInvariantIndirectImageMaterialization(true); });
Run("unbounded material image keys", [] { TestInvariantIndirectImageMaterialization(false); });
Run("bounded image view eligibility", TestBoundedImageViewEligibility); Run("bounded image view eligibility", TestBoundedImageViewEligibility);
Run("waterfall image table", TestWaterfallImageTable); Run("waterfall image table", TestWaterfallImageTable);
Run("guarded direct image table", TestGuardedDirectImageTable); Run("guarded direct image table", TestGuardedDirectImageTable);