shader: remove recompiler error-string propagation

This commit is contained in:
nmzik
2026-08-31 05:30:18 +04:00
parent 13533bd053
commit af8aecfdde
47 changed files with 2040 additions and 3253 deletions
@@ -1,7 +1,7 @@
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
#include "common/assert.h"
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include "graphics/shader/shader.h"
#include <algorithm>
#include <bit>
@@ -120,10 +120,10 @@ class RuntimeValidator {
public:
explicit RuntimeValidator(const Program& program): m_program(program) {}
bool Run(Value value, std::string& reason) { return Validate(value, reason); }
bool Run(Value value) { return Validate(value); }
private:
bool Validate(Value value, std::string& reason) {
bool Validate(Value value) {
value = value.Resolve();
const auto* inst = value.TryInstruction();
if (inst == nullptr) {
@@ -133,14 +133,10 @@ private:
case Type::U16:
case Type::U32:
case Type::U64: return true;
default:
reason = fmt::format("contains a non-integer immediate of type {}",
TypeName(value.GetType()));
return false;
default: return false;
}
}
if (!m_visiting.insert(inst).second) {
reason = fmt::format("contains a cyclic {} value", ValueOpcodeName(inst->GetOpcode()));
return false;
}
const auto finish = [&](bool valid) {
@@ -151,25 +147,21 @@ private:
if (op == ValueOpcode::UndefU1 || op == ValueOpcode::UndefU8 ||
op == ValueOpcode::UndefU16 || op == ValueOpcode::UndefU32 ||
op == ValueOpcode::UndefU64 || op == ValueOpcode::Void) {
reason = fmt::format("contains {}", ValueOpcodeName(op));
return finish(false);
}
if (op == ValueOpcode::GetUserData) {
if (inst->NumArgs() != 1 || inst->Arg(0).GetType() != Type::ScalarReg) {
reason = "contains a malformed GetUserData";
return finish(false);
}
const auto reg = RegIndex(inst->Arg(0).ScalarRegister());
if (reg < m_program.user_data_base ||
reg - m_program.user_data_base >= m_program.user_data_count) {
reason = fmt::format("references unavailable user SGPR {}", reg);
return finish(false);
}
return finish(true);
}
if (op == ValueOpcode::GetShaderBase) {
if (inst->NumArgs() != 0) {
reason = "contains a malformed GetShaderBase";
return finish(false);
}
return finish(true);
@@ -177,14 +169,12 @@ private:
if (op == ValueOpcode::Phi) {
const auto invariant = ResolveInvariantPhi(m_program, value);
if (invariant.IsEmpty()) {
reason = "contains a control-dependent phi";
return finish(false);
}
return finish(Validate(invariant, reason));
return finish(Validate(invariant));
}
if (op == ValueOpcode::GetSrtResource) {
if (inst->NumArgs() != 0) {
reason = "contains a malformed GetSrtResource";
return finish(false);
}
return finish(true);
@@ -196,7 +186,6 @@ private:
ValueOpcode::GetSrtResource ||
!slot.IsImmediate() || slot.GetType() != Type::U32 ||
slot.U32() >= m_program.srt_reads.size()) {
reason = "contains a malformed flattened SRT read";
return finish(false);
}
} else if (op == ValueOpcode::LoadAddressU32 || op == ValueOpcode::ReadConstBuffer) {
@@ -206,13 +195,11 @@ private:
const auto* handle = inst->NumArgs() != 0 ? inst->Arg(0).ResolveInstruction() : nullptr;
if (!IsRawRead(m_program, *inst) || handle == nullptr ||
handle->GetOpcode() != expected) {
reason = fmt::format("contains a non-scalar {}", ValueOpcodeName(op));
return finish(false);
}
} else if (op == ValueOpcode::CompositeExtractU64) {
const auto index = inst->NumArgs() == 2 ? inst->Arg(1).Resolve() : Value {};
if (!index.IsImmediate() || index.GetType() != Type::U32 || index.U32() >= 2u) {
reason = "contains an invalid U64 component index";
return finish(false);
}
} else if (op == ValueOpcode::CompositeExtractU32x2) {
@@ -222,7 +209,6 @@ private:
index.U32() >= 2u ||
(source->GetOpcode() != ValueOpcode::CompositeConstructU32x2 &&
source->GetOpcode() != ValueOpcode::IAddCarry32)) {
reason = "contains an unsupported composite runtime source";
return finish(false);
}
}
@@ -233,17 +219,14 @@ private:
: op == ValueOpcode::GetSamplerResource ? 4u
: 2u;
if (inst->NumArgs() != expected) {
reason = fmt::format("contains a malformed {}", ValueOpcodeName(op));
return finish(false);
}
} else if (op != ValueOpcode::ReadConst && op != ValueOpcode::ReadConstBuffer &&
op != ValueOpcode::LoadAddressU32 && !IsRuntimeIntegerOp(op)) {
reason =
fmt::format("contains unsupported or control-dependent {}", ValueOpcodeName(op));
return finish(false);
}
for (size_t index = 0; index < inst->NumArgs(); index++) {
if (!Validate(inst->Arg(index), reason)) {
if (!Validate(inst->Arg(index))) {
return finish(false);
}
}
@@ -258,7 +241,7 @@ class PlanBuilder {
public:
explicit PlanBuilder(Program& program): m_program(program) {}
bool Run(std::string* error) {
void Run() {
m_program.srt_reads.clear();
m_program.dynamic_reads.clear();
for (auto* block: m_program.blocks) {
@@ -273,34 +256,29 @@ public:
(op == ValueOpcode::ReadConstBuffer &&
kind == ResourceKind::ScalarAddress);
if (crosswired) {
return Fail(flags.pc, error,
fmt::format("{} has incompatible scalar memory metadata",
ValueOpcodeName(op)));
Fail(flags.pc,
fmt::format("{} has incompatible scalar memory metadata",
ValueOpcodeName(op)));
}
}
}
if (IsDescriptorHandle(inst.GetOpcode())) {
for (size_t index = 0; index < inst.NumArgs(); index++) {
if (!Collect(inst.Arg(index), 0, error)) {
return false;
}
Collect(inst.Arg(index), 0);
}
}
}
}
for (auto* block: m_program.blocks) {
for (auto& inst: *block) {
std::string reason;
if (inst.GetOpcode() == ValueOpcode::LoadAddressU32 && IsRawRead(m_program, inst) &&
inst.Arg(1).Resolve().IsImmediate() &&
ValidateRuntimeValue(m_program, Value(&inst), reason) &&
!Collect(Value(&inst), inst.Flags<MemoryFlags>().pc, error)) {
return false;
ValidateRuntimeValue(m_program, Value(&inst))) {
Collect(Value(&inst), inst.Flags<MemoryFlags>().pc);
}
}
}
PatchReads();
return true;
}
private:
@@ -310,18 +288,20 @@ private:
bool keep = false;
};
bool Fail(uint32_t pc, std::string* error, const std::string& message) const {
return ShaderError::Fail(error, Diagnostic(m_program, pc, message));
[[noreturn]] void Fail(uint32_t pc, const std::string& message) const {
const auto diagnostic = Diagnostic(m_program, pc, message);
EXIT("shader SRT planning failed: %s", diagnostic.c_str());
std::abort();
}
bool Collect(Value value, uint32_t use_pc, std::string* error) {
void Collect(Value value, uint32_t use_pc) {
value = value.Resolve();
if (value.IsImmediate()) {
return true;
return;
}
auto* inst = value.TryInstruction();
if (inst == nullptr) {
return Fail(use_pc, error, "invalid typed planning value");
Fail(use_pc, "invalid typed planning value");
}
const auto cycle = std::ranges::find(m_visiting, inst);
if (cycle != m_visiting.end()) {
@@ -329,44 +309,40 @@ private:
return value->GetOpcode() == ValueOpcode::Phi;
});
if (contains_phi) {
return true;
return;
}
return Fail(use_pc, error,
fmt::format("cyclic typed planning value {} without a phi",
ValueOpcodeName(inst->GetOpcode())));
Fail(use_pc, fmt::format("cyclic typed planning value {} without a phi",
ValueOpcodeName(inst->GetOpcode())));
}
if (std::ranges::find(m_visited, inst) != m_visited.end()) {
return true;
return;
}
m_visiting.push_back(inst);
for (size_t index = 0; index < inst->NumArgs(); index++) {
if (!Collect(inst->Arg(index), use_pc, error)) {
return false;
}
Collect(inst->Arg(index), use_pc);
}
m_visiting.pop_back();
m_visited.push_back(inst);
if (!IsRawRead(m_program, *inst)) {
return true;
return;
}
const auto offset = inst->Arg(1).Resolve();
if (!offset.IsImmediate() || offset.GetType() != Type::U32) {
if (std::ranges::find(m_program.dynamic_reads, value) == m_program.dynamic_reads.end()) {
if (std::ranges::find(m_program.dynamic_reads, value) ==
m_program.dynamic_reads.end()) {
m_program.dynamic_reads.push_back(value);
}
return true;
return;
}
use_pc = inst->Flags<MemoryFlags>().pc;
for (uint32_t slot = 0; slot < m_program.srt_reads.size(); slot++) {
if (EquivalentValue(m_program, value, m_program.srt_reads[slot].value)) {
m_patches.push_back({inst, slot, false});
return true;
return;
}
}
const auto slot = static_cast<uint32_t>(m_program.srt_reads.size());
m_program.srt_reads.push_back({value, slot, use_pc});
m_program.srt_reads.push_back({value, slot});
m_patches.push_back({inst, slot, true});
return true;
}
void PatchReads() {
@@ -411,14 +387,12 @@ class Evaluator {
public:
Evaluator(const Program& program, const SrtRuntime& runtime,
std::span<const uint8_t> clean_flat_slots = {}, Evaluator* clean_evaluator = nullptr)
: m_program(program), m_runtime(runtime),
m_clean_flat_slots(clean_flat_slots), m_clean_evaluator(clean_evaluator) {}
: m_program(program), m_runtime(runtime), m_clean_flat_slots(clean_flat_slots),
m_clean_evaluator(clean_evaluator) {}
void SetUsePc(uint32_t pc) { m_use_pc = pc; }
bool Evaluate(Value value, uint32_t& result, std::string* error) {
bool Evaluate(Value value, uint32_t& result) {
uint64_t wide = 0;
if (!EvaluateWide(value, wide, error)) {
if (!EvaluateWide(value, wide)) {
return false;
}
result = static_cast<uint32_t>(wide);
@@ -426,11 +400,7 @@ public:
}
private:
bool Fail(std::string* error, const std::string& message) const {
return ShaderError::Fail(error, Diagnostic(m_program, m_use_pc, message));
}
bool EvaluateWide(Value value, uint64_t& result, std::string* error) {
bool EvaluateWide(Value value, uint64_t& result) {
value = value.Resolve();
if (value.IsImmediate()) {
switch (value.GetType()) {
@@ -439,23 +409,23 @@ private:
case Type::U16: result = value.U16(); return true;
case Type::U32: result = value.U32(); return true;
case Type::U64: result = value.U64(); return true;
default: return Fail(error, "non-integer immediate in runtime expression");
default: return false;
}
}
auto* inst = value.TryInstruction();
if (inst == nullptr) {
return Fail(error, "invalid typed runtime value");
return false;
}
if (const auto found = m_cache.find(inst); found != m_cache.end()) {
result = found->second;
return true;
}
if (std::ranges::find(m_visiting, inst) != m_visiting.end()) {
return Fail(error, "cyclic typed runtime value");
return false;
}
m_visiting.push_back(inst);
uint64_t out = 0;
if (!EvaluateInst(*inst, out, error)) {
if (!EvaluateInst(*inst, out)) {
return false;
}
m_visiting.pop_back();
@@ -464,28 +434,27 @@ private:
return true;
}
bool Arg(const Inst& inst, size_t index, uint64_t& result, std::string* error) {
return EvaluateWide(inst.Arg(index), result, error);
bool Arg(const Inst& inst, size_t index, uint64_t& result) {
return EvaluateWide(inst.Arg(index), result);
}
bool EvaluatePhi(const Inst& inst, uint64_t& result, std::string* error) {
bool EvaluatePhi(const Inst& inst, uint64_t& result) {
const auto value = ResolveInvariantPhi(m_program, Value(const_cast<Inst*>(&inst)));
return !value.IsEmpty() ? EvaluateWide(value, result, error)
: Fail(error, "typed phi has runtime-dependent values");
return !value.IsEmpty() && EvaluateWide(value, result);
}
bool EvaluateExtract(const Inst& inst, uint64_t& result, std::string* error) {
bool EvaluateExtract(const Inst& inst, uint64_t& result) {
const auto index = inst.Arg(1).Resolve();
if (!index.IsImmediate() || index.GetType() != Type::U32) {
return Fail(error, "dynamic composite extract in runtime expression");
return false;
}
const auto component = index.U32();
if (component >= 2u) {
return Fail(error, "unsupported composite runtime source");
return false;
}
if (inst.GetOpcode() == ValueOpcode::CompositeExtractU64) {
uint64_t packed = 0;
if (!Arg(inst, 0, packed, error)) {
if (!Arg(inst, 0, packed)) {
return false;
}
result = static_cast<uint32_t>(packed >> (component * 32u));
@@ -493,15 +462,15 @@ private:
}
const auto* source = inst.Arg(0).ResolveInstruction();
if (source == nullptr) {
return Fail(error, "unsupported composite runtime source");
return false;
}
if (source->GetOpcode() == ValueOpcode::CompositeConstructU32x2) {
return EvaluateWide(source->Arg(component), result, error);
return EvaluateWide(source->Arg(component), result);
}
if (source->GetOpcode() == ValueOpcode::IAddCarry32) {
uint64_t lhs = 0;
uint64_t rhs = 0;
if (!Arg(*source, 0, lhs, error) || !Arg(*source, 1, rhs, error)) {
if (!Arg(*source, 0, lhs) || !Arg(*source, 1, rhs)) {
return false;
}
const auto sum =
@@ -510,24 +479,23 @@ private:
component == 0u ? static_cast<uint32_t>(sum) : static_cast<uint32_t>(sum >> 32u);
return true;
}
return Fail(error, "unsupported composite runtime source");
return false;
}
bool EvaluateRawRead(const Inst& inst, uint64_t& result, std::string* error) {
bool EvaluateRawRead(const Inst& inst, uint64_t& result) {
const auto flags = inst.Flags<MemoryFlags>();
if (flags.index >= m_program.memory_info.size()) {
return Fail(error, "raw scalar read has invalid metadata");
return false;
}
const auto& mem = m_program.memory_info[flags.index];
const auto* handle = inst.Arg(0).ResolveInstruction();
if (handle == nullptr) {
return Fail(error, "raw scalar read has no descriptor handle");
return false;
}
uint64_t low = 0;
uint64_t high = 0;
uint64_t offset = 0;
if (!Arg(*handle, 0, low, error) || !Arg(*handle, 1, high, error) ||
!Arg(inst, 1, offset, error)) {
if (!Arg(*handle, 0, low) || !Arg(*handle, 1, high) || !Arg(inst, 1, offset)) {
return false;
}
const auto base = ((high << 32u) | static_cast<uint32_t>(low)) & AddressMask;
@@ -536,12 +504,11 @@ private:
if (inst.GetOpcode() == ValueOpcode::ReadConstBuffer) {
uint64_t records = 0;
uint64_t word3 = 0;
if (handle->NumArgs() != 4u || !Arg(*handle, 2, records, error) ||
!Arg(*handle, 3, word3, error)) {
return Fail(error, "constant-buffer descriptor has invalid width");
if (handle->NumArgs() != 4u || !Arg(*handle, 2, records) || !Arg(*handle, 3, word3)) {
return false;
}
if (immediate < 0) {
return Fail(error, "constant-buffer read has a negative immediate offset");
return false;
}
const auto byte_offset =
static_cast<uint64_t>(immediate) + static_cast<uint32_t>(offset);
@@ -551,21 +518,20 @@ private:
? static_cast<uint64_t>(static_cast<uint32_t>(records))
: static_cast<uint64_t>(stride) * static_cast<uint32_t>(records);
if (aligned > size || size - aligned < sizeof(uint32_t)) {
return Fail(
error, fmt::format("constant-buffer offset {} exceeds size {}", aligned, size));
return false;
}
address = ((base & ~uint64_t {3}) + byte_offset) & ~uint64_t {3};
} else {
const auto relative = (immediate & ~int64_t {3}) +
static_cast<int64_t>(static_cast<uint32_t>(offset) & ~3u);
if (!AddSignedAddress(base & ~uint64_t {3}, relative, address)) {
return Fail(error, "raw scalar read is outside the 48-bit address space");
return false;
}
}
uint32_t word = 0;
if (m_runtime.read_memory != nullptr) {
if (!m_runtime.read_memory(m_runtime.userdata, address, &word)) {
return Fail(error, fmt::format("constant read failed at 0x{:016x}", address));
return false;
}
} else {
std::memcpy(&word, reinterpret_cast<const void*>(address), sizeof(word));
@@ -574,28 +540,28 @@ private:
return true;
}
bool EvaluateInst(const Inst& inst, uint64_t& result, std::string* error) {
bool EvaluateInst(const Inst& inst, uint64_t& result) {
uint64_t a = 0;
uint64_t b = 0;
uint64_t c = 0;
const auto binary = [&]() { return Arg(inst, 0, a, error) && Arg(inst, 1, b, error); };
const auto binary = [&]() { return Arg(inst, 0, a) && Arg(inst, 1, b); };
const auto ternary = [&]() {
return Arg(inst, 0, a, error) && Arg(inst, 1, b, error) && Arg(inst, 2, c, error);
return Arg(inst, 0, a) && Arg(inst, 1, b) && Arg(inst, 2, c);
};
switch (inst.GetOpcode()) {
case ValueOpcode::GetUserData: {
const auto reg = RegIndex(inst.Arg(0).ScalarRegister());
if (reg < m_program.user_data_base ||
reg - m_program.user_data_base >= m_runtime.user_data.size()) {
return Fail(error, fmt::format("user SGPR {} is unavailable", reg));
return false;
}
result = m_runtime.user_data[reg - m_program.user_data_base];
return true;
}
case ValueOpcode::GetShaderBase: result = m_runtime.shader_base; return true;
case ValueOpcode::Phi: return EvaluatePhi(inst, result, error);
case ValueOpcode::Phi: return EvaluatePhi(inst, result);
case ValueOpcode::CompositeExtractU64:
case ValueOpcode::CompositeExtractU32x2: return EvaluateExtract(inst, result, error);
case ValueOpcode::CompositeExtractU32x2: return EvaluateExtract(inst, result);
case ValueOpcode::CompositeConstructU64:
if (!binary()) {
return false;
@@ -607,20 +573,19 @@ private:
const auto slot = inst.Arg(1).Resolve();
if (!slot.IsImmediate() || slot.GetType() != Type::U32 ||
slot.U32() >= m_program.srt_reads.size()) {
return Fail(error, "invalid flattened SRT index");
return false;
}
if (slot.U32() < m_clean_flat_slots.size() &&
m_clean_flat_slots[slot.U32()] != 0u && m_clean_evaluator != nullptr) {
m_clean_evaluator->SetUsePc(m_use_pc);
return m_clean_evaluator->EvaluateWide(m_program.srt_reads[slot.U32()].value,
result, error);
result);
}
return EvaluateWide(m_program.srt_reads[slot.U32()].value, result, error);
return EvaluateWide(m_program.srt_reads[slot.U32()].value, result);
}
case ValueOpcode::LoadAddressU32:
case ValueOpcode::ReadConstBuffer:
if (IsRawRead(m_program, inst)) {
return EvaluateRawRead(inst, result, error);
return EvaluateRawRead(inst, result);
}
break;
case ValueOpcode::IAdd32:
@@ -690,7 +655,7 @@ private:
}
return false;
case ValueOpcode::BitwiseNot32:
if (Arg(inst, 0, a, error)) {
if (Arg(inst, 0, a)) {
result = ~static_cast<uint32_t>(a);
return true;
}
@@ -737,7 +702,7 @@ private:
const auto offset = static_cast<uint32_t>(b);
const auto width = static_cast<uint32_t>(c);
if (offset > 32u || width > 32u - offset) {
return Fail(error, "invalid unsigned bit-field range");
return false;
}
const auto mask = width == 32u ? UINT32_MAX
: width == 0u ? 0u
@@ -751,7 +716,7 @@ private:
const auto offset = static_cast<uint32_t>(b);
const auto width = static_cast<uint32_t>(c);
if (offset > 32u || width > 32u - offset) {
return Fail(error, "invalid signed bit-field range");
return false;
}
if (width == 0u) {
result = 0;
@@ -768,13 +733,13 @@ private:
return false;
case ValueOpcode::BitFieldInsert: {
uint64_t d = 0;
if (!ternary() || !Arg(inst, 3, d, error)) {
if (!ternary() || !Arg(inst, 3, d)) {
return false;
}
const auto offset = static_cast<uint32_t>(c);
const auto width = static_cast<uint32_t>(d);
if (offset > 32u || width > 32u - offset) {
return Fail(error, "invalid inserted bit-field range");
return false;
}
if (width == 0u) {
result = static_cast<uint32_t>(a);
@@ -836,7 +801,7 @@ private:
}
return false;
case ValueOpcode::LogicalNot:
if (Arg(inst, 0, a, error)) {
if (Arg(inst, 0, a)) {
result = a == 0u;
return true;
}
@@ -845,18 +810,16 @@ private:
case ValueOpcode::UndefU8:
case ValueOpcode::UndefU16:
case ValueOpcode::UndefU32:
case ValueOpcode::UndefU64: return Fail(error, "undefined typed runtime value");
case ValueOpcode::UndefU64: return false;
default: break;
}
return Fail(error, fmt::format("unsupported typed runtime opcode {}",
ValueOpcodeName(inst.GetOpcode())));
return false;
}
const Program& m_program;
const SrtRuntime& m_runtime;
std::span<const uint8_t> m_clean_flat_slots;
Evaluator* m_clean_evaluator = nullptr;
uint32_t m_use_pc = 0;
std::unordered_map<const Inst*, uint64_t> m_cache;
std::vector<const Inst*> m_visiting;
};
@@ -872,18 +835,12 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
std::span<const DescriptorSourceRequest> requests,
const SrtRuntime& runtime, std::vector<DescriptorValue>& results,
std::vector<uint32_t>& flat, bool evaluate_flat,
std::span<const uint8_t> clean_flat_slots, std::string* error) {
std::span<const uint8_t> clean_flat_slots) {
if (!program.srt_plan_complete) {
if (error != nullptr) {
*error = Diagnostic(program, 0, "typed SRT plan is not ready");
}
return false;
}
if (std::ranges::any_of(clean_flat_slots, [](uint8_t clean) { return clean != 0u; }) &&
runtime.read_specialization_memory == nullptr) {
if (error != nullptr) {
*error = Diagnostic(program, 0, "clean flattened SRT read has no memory reader");
}
return false;
}
SrtRuntime clean_runtime = runtime;
@@ -895,17 +852,12 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
for (const auto& request: requests) {
const auto* source = Source(program, request.source);
if (source == nullptr) {
if (error != nullptr) {
*error = Diagnostic(program, request.use_pc,
fmt::format("invalid descriptor source {}", request.source));
}
return false;
}
evaluator.SetUsePc(request.use_pc);
DescriptorValue value;
value.dword_count = source->dword_count;
for (uint32_t index = 0; index < source->dword_count; index++) {
if (!evaluator.Evaluate(source->dwords[index], value.dwords[index], error)) {
if (!evaluator.Evaluate(source->dwords[index], value.dwords[index])) {
return false;
}
}
@@ -918,9 +870,8 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
const bool clean = read.flat_offset < clean_flat_slots.size() &&
clean_flat_slots[read.flat_offset] != 0u;
auto& selected = clean ? clean_evaluator : evaluator;
selected.SetUsePc(read.use_pc);
if (read.flat_offset >= flattened.size() ||
!selected.Evaluate(read.value, flattened[read.flat_offset], error)) {
!selected.Evaluate(read.value, flattened[read.flat_offset])) {
return false;
}
}
@@ -934,31 +885,24 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
} // namespace
bool ValidateRuntimeValue(const Program& program, Value value, std::string& reason) {
return RuntimeValidator(program).Run(value, reason);
bool ValidateRuntimeValue(const Program& program, Value value) {
return RuntimeValidator(program).Run(value);
}
bool BuildSrtPlan(Program& program, std::string* error) {
void BuildSrtPlan(Program& program) {
if (program.resource_tracking_complete) {
if (error != nullptr) {
*error = "cannot rebuild SRT after resource tracking";
}
return false;
EXIT("shader SRT planning failed: cannot rebuild SRT after resource tracking");
}
program.srt_plan_complete = false;
if (!PlanBuilder(program).Run(error)) {
return false;
}
PlanBuilder(program).Run();
program.srt_plan_complete = true;
return true;
}
bool EvaluateDescriptorSource(const Program& program, uint32_t source, uint32_t use_pc,
const SrtRuntime& runtime, DescriptorValue& result,
std::string* error) {
const DescriptorSourceRequest request {source, use_pc};
bool EvaluateDescriptorSource(const Program& program, uint32_t source, const SrtRuntime& runtime,
DescriptorValue& result) {
const DescriptorSourceRequest request {source};
std::vector<DescriptorValue> results;
if (!EvaluateDescriptorSources(program, std::span {&request, 1}, runtime, results, error)) {
if (!EvaluateDescriptorSources(program, std::span {&request, 1}, runtime, results)) {
return false;
}
result = results.front();
@@ -967,26 +911,23 @@ bool EvaluateDescriptorSource(const Program& program, uint32_t source, uint32_t
bool EvaluateDescriptorSources(const Program& program,
std::span<const DescriptorSourceRequest> requests,
const SrtRuntime& runtime, std::vector<DescriptorValue>& results,
std::string* error) {
const SrtRuntime& runtime, std::vector<DescriptorValue>& results) {
std::vector<uint32_t> ignored;
return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, ignored, false, {},
error);
return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, ignored, false, {});
}
bool EvaluateRuntimeSources(const Program& program,
std::span<const DescriptorSourceRequest> requests,
const SrtRuntime& runtime, std::vector<DescriptorValue>& results,
std::vector<uint32_t>& flat, std::span<const uint8_t> clean_flat_slots,
std::string* error) {
std::vector<uint32_t>& flat,
std::span<const uint8_t> clean_flat_slots) {
return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, flat, true,
clean_flat_slots, error);
clean_flat_slots);
}
bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector<uint32_t>& flat,
std::string* error) {
bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector<uint32_t>& flat) {
std::vector<DescriptorValue> ignored;
return EvaluateRuntimeSources(program, {}, runtime, ignored, flat, {}, error);
return EvaluateRuntimeSources(program, {}, runtime, ignored, flat, {});
}
} // namespace Libs::Graphics::ShaderRecompiler::IR