shader: bound waterfall buffer descriptors with same-lane guards

Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
nmzik
2026-10-15 12:14:28 +02:00
parent b4406b0467
commit 232e2f2593
3 changed files with 255 additions and 8 deletions
@@ -1956,18 +1956,25 @@ private:
});
}
Value UnsignedImageBound(Value key, const Inst& handle) const {
Value UnsignedResourceBound(Value key, const Inst& handle) const {
Value bound;
for (const auto& use: handle.Uses()) {
const auto& image = *use.user;
const auto op = image.GetOpcode();
const auto& access = *use.user;
const auto op = access.GetOpcode();
if (use.operand != 0u || (op != ValueOpcode::ImageSampleRaw &&
op != ValueOpcode::ImageGatherRaw && op != ValueOpcode::ImageRead)) return {};
// The image's own EXEC predicate proves the range for every accessing lane;
op != ValueOpcode::ImageGatherRaw && op != ValueOpcode::ImageRead &&
!IndirectBufferAccess(access))) return {};
// The access's own EXEC predicate proves the range for every accessing lane;
// an EXEC-nonzero branch alone only proves that some lane is active.
const auto active = image.Arg(image.NumArgs() - 1u);
const auto active = access.Arg(access.NumArgs() - 1u);
auto candidate = UnsignedBound(active, key);
if (candidate.IsEmpty()) candidate = UnsignedBoundOnEntry(key, image.Parent(), false, active);
if (candidate.IsEmpty()) candidate = UnsignedBoundOnEntry(key, access.Parent(), false, active);
if (candidate.IsEmpty()) {
// A waterfall key inherits the local value's bound only where this same
// EXEC predicate proves both their equality and the local range.
const auto local = EqualLocalKey(active, key);
if (!local.IsEmpty()) candidate = UnsignedBound(active, local, true, false, active);
}
if (candidate.IsEmpty() ||
!ValidateRuntimeValue(m_program, candidate, RuntimeValueType::Integer)) return {};
if (bound.IsEmpty()) bound = candidate;
@@ -2881,7 +2888,7 @@ private:
plan.retain_reads |= table_source.dword_count == 4u;
} else if (table_source.dword_count == 2u) {
auto guarded_count = UnsignedBoundOnEntry(key, handle.Parent());
if (guarded_count.IsEmpty()) guarded_count = UnsignedImageBound(key, handle);
if (guarded_count.IsEmpty()) guarded_count = UnsignedResourceBound(key, handle);
// A runtime count can describe fewer rows than the mask's static bit range.
if (guarded_count.IsEmpty()) guarded_count = UnsignedBoundOnEntry(key, handle.Parent(), true);
if (!guarded_count.IsEmpty()) {
@@ -3104,6 +3111,13 @@ private:
return finish();
}
if (!legacy_store) {
if (!plan.split_offsets) {
const auto count = UnsignedResourceBound(key, handle);
if (!count.IsEmpty()) {
indirect.key_count = count;
return finish();
}
}
if (table_source.dword_count == 2u && !plan.split_offsets) {
const auto maximum = SelectorMaximum(key);
if (maximum >= MaxIndirectDescriptorProbes) return false;