shader: bound material selectors by proven one-wave LDS append lists

This commit is contained in:
nmzik
2026-10-12 19:44:05 +02:00
parent d692d8ee08
commit 0e9c77b0a2
8 changed files with 630 additions and 68 deletions
@@ -3,6 +3,7 @@
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include <algorithm>
#include <span>
namespace Libs::Graphics::ShaderRecompiler::IR {
@@ -49,6 +50,48 @@ void CompileSrtWalker(ResourcePlan& program);
// Uses the strict reader for values that affect shader specialization.
SrtRuntime CleanRuntime(SrtRuntime runtime);
// Nonnegative affine coefficients: element zero is constant, remaining elements are
// caller-selected leaves. Runtime range proofs must additionally exclude U32 wrap.
template <size_t Size>
std::optional<std::array<uint64_t, Size>> AffineIndex(
Value value, const auto& resolve, const auto& leaf, uint32_t depth = 0) {
value = resolve(value);
if (depth > 32u || value.GetType() != Type::U32) return {};
std::array<uint64_t, Size> result {};
if (value.IsImmediate()) {
result[0] = value.U32();
return result;
}
if (const auto index = leaf(value)) {
result[*index] = 1u;
return result;
}
const auto* inst = value.TryInstruction();
if (inst == nullptr) return {};
const auto op = inst->GetOpcode();
if (op != ValueOpcode::IAdd32 && op != ValueOpcode::IMul32 &&
op != ValueOpcode::ShiftLeftLogical32) return {};
auto left = AffineIndex<Size>(inst->Arg(0), resolve, leaf, depth + 1u);
auto right = AffineIndex<Size>(inst->Arg(1), resolve, leaf, depth + 1u);
if (!left || !right) return {};
const auto constant = [](const auto& coefficients) {
return std::ranges::all_of(std::span(coefficients).subspan(1u),
[](uint64_t coefficient) { return coefficient == 0u; });
};
if (op == ValueOpcode::IMul32 && !constant(*right)) std::swap(left, right);
if (op != ValueOpcode::IAdd32 && !constant(*right)) return {};
if (op == ValueOpcode::ShiftLeftLogical32) {
if ((*right)[0] >= 32u) return {};
(*right)[0] = uint64_t {1} << (*right)[0];
}
for (size_t index = 0; index < Size; ++index) {
(*left)[index] = op == ValueOpcode::IAdd32
? (*left)[index] + (*right)[index] : (*left)[index] * (*right)[0];
if ((*left)[index] > UINT32_MAX) return {};
}
return left;
}
// One memoized evaluation session shared by the entire shader resource refresh.
class SrtWalker {
public: