From f57d2c096589bb32a4357b3b898f59fdce152de4 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 13 Oct 2026 09:19:43 +0200 Subject: [PATCH] shader: keep unbounded material selectors on bounded GPU heaps --- .../recompiler/ir/passes/ResourceTracking.cpp | 8 ++++++-- tests/ResourceTrackingTests.cpp | 14 +++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp index 87ed1b378..758bab95a 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp @@ -2103,7 +2103,7 @@ private: } bool MatchScalarMaterialKey(Value key, DescriptorSource::IndirectDescriptor& indirect, - DescriptorSource& material_source) { + DescriptorSource& material_source, bool require_bound) { DescriptorSource::IndirectDescriptor::SelectorRead selector; const auto* read = SelectorReadValue(key, Value(true), selector); if (read == nullptr) return false; @@ -2160,6 +2160,9 @@ private: offset = static_cast(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; selector.source = InternSource(material_source); selector.stride = stride; @@ -2635,7 +2638,8 @@ private: // only the image handle is projected onto the bounded workgroup key. plan.retain_reads = true; } 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 // the GPU key using the same plan as other indirect image reads. plan.retain_reads |= table_source.dword_count == 4u; diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index f3b346f9a..0f9f927c7 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -278,14 +278,17 @@ MakeIndirectImageFixture(bool malformed, uint32_t table_stride = 32, uint32_t ta return fixture; } -void TestInvariantIndirectImageMaterialization() { - auto fixture = MakeIndirectImageFixture(false, 48u, 0u, 16u, true); +void TestInvariantIndirectImageMaterialization(bool nested) { + auto fixture = MakeIndirectImageFixture(false, 48u, 0u, 16u, nested); fixture->PlanAndTrack(); auto plan = ExtractResourcePlan(fixture->program); EliminateDeadCode(fixture->program.blocks); ValidateProgram(fixture->program, true); 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"); std::array descriptor{}; descriptor[0] = 0x20u; @@ -293,7 +296,7 @@ void TestInvariantIndirectImageMaterialization() { descriptor[2] = 3u | (3u << 14u); descriptor[3] = Libs::Graphics::DstSel(4, 5, 6, 7) | (static_cast(Libs::Graphics::Prospero::ImageType::kColor2D) << 28u); - std::array data{0x3000u, 16u << 16u, 0x200000u, 0u, + std::array data{0x3000u, 4u << 16u, 0x100000u, 0u, 0x2000u, 48u << 16u, 3u, 0u}; std::copy_n(data.begin(), 4u, data.begin() + 12u); LinearTestMemory memory; @@ -5793,7 +5796,8 @@ int main() { Run("FMASK load specialization", TestFmaskLoadSpecialization); Run("gather LOD sampler validation", TestGatherLodSamplerValidation); 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("waterfall image table", TestWaterfallImageTable); Run("guarded direct image table", TestGuardedDirectImageTable);