shader: link scalar leaf calls only for SWAPPC programs

Co-authored-by: Behzad <behzadkhan1736@gmail.com>
This commit is contained in:
nmzik
2026-10-09 16:09:36 +02:00
parent 165cd884ca
commit 1818aae562
14 changed files with 663 additions and 86 deletions
@@ -217,17 +217,20 @@ struct PipelineCache::ProgramCache {
};
struct Permutation {
std::vector<uint32_t> function_code;
ShaderRecompiler::IR::ResourceSpecialization specialization;
ShaderRecompiler::IR::CompiledShaderInfo program;
ShaderProgram handle;
};
struct SourceEntry {
explicit SourceEntry(ShaderRecompiler::IR::ResourcePlan plan)
: resource_plan(std::move(plan)) {
SourceEntry(ShaderRecompiler::IR::ResourcePlan plan,
std::unique_ptr<ShaderRecompiler::ShaderSource> call_source)
: call_source(std::move(call_source)), resource_plan(std::move(plan)) {
permutations.reserve(8);
}
std::unique_ptr<ShaderRecompiler::ShaderSource> call_source;
ShaderRecompiler::IR::ResourcePlan resource_plan;
ShaderRecompiler::IR::ResourceSnapshot resources;
ShaderRecompiler::IR::ResourceSpecialization specialization;
@@ -256,7 +259,8 @@ struct PipelineCache::ProgramCache {
const ShaderRecompiler::CompileOptions& options,
ShaderRecompiler::TranslateResult translated,
ShaderRecompiler::IR::ResourceSpecialization specialization,
uint32_t push_data_start_dword) {
uint32_t push_data_start_dword,
std::span<const uint32_t> function_code) {
auto result = ShaderRecompiler::CompileProgram(std::move(translated), options,
specialization, push_data_start_dword);
if (!ValidateShaderSpirv(options.dump_label, options.shader_hash, result.spirv)) {
@@ -273,6 +277,7 @@ struct PipelineCache::ProgramCache {
static_cast<uint64_t>(result.spirv.size()), options.wave_size);
}
return {
.function_code = {function_code.begin(), function_code.end()},
.specialization = std::move(specialization),
.program = std::move(result.program).TakeCompiledInfo(),
.handle = {.id = ++next_shader_id, .module = module},
@@ -307,21 +312,33 @@ struct PipelineCache::ProgramCache {
if constexpr (std::is_same_v<InputInfo, ShaderComputeInputInfo>) {
runtime.workgroup_counts = input_info.workgroup_counts;
}
if (entry != programs.end()) {
bool source_changed = false;
const auto function_code = [](const std::unique_ptr<ShaderRecompiler::ShaderSource>& source) {
return source ? std::span<const uint32_t>(source->linked->code).subspan(source->code.size())
: std::span<const uint32_t>{};
};
if (entry != programs.end() && entry->second.call_source) {
auto& cached = entry->second;
const auto revision = cached.call_source->revision;
ShaderRecompiler::RefreshShaderSource(*cached.call_source, runtime);
source_changed = revision != cached.call_source->revision;
cached.resource_plan.source_reads = cached.call_source->reads;
}
const auto matches = [&](const Permutation& candidate) {
const auto& layout = candidate.program.bindings;
return layout.push_data_start_dword == ShaderRecompiler::IR::PushData::StartFor(
push_data_cursor, layout.ShaderDataDwords()) &&
candidate.specialization == entry->second.specialization &&
(!entry->second.call_source || std::ranges::equal(
candidate.function_code, function_code(entry->second.call_source)));
};
if (entry != programs.end() && !source_changed) {
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
entry->second.resource_plan, runtime, entry->second.resources,
entry->second.specialization));
if (const auto permutation = std::ranges::find_if(
entry->second.permutations, [&](const Permutation& candidate) {
const auto& layout = candidate.program.bindings;
return layout.push_data_start_dword ==
ShaderRecompiler::IR::PushData::StartFor(
push_data_cursor, layout.ShaderDataDwords()) &&
candidate.specialization == entry->second.specialization;
});
if (const auto permutation = std::ranges::find_if(entry->second.permutations, matches);
permutation != entry->second.permutations.end()) {
input_info.stage = {.program = &permutation->program,
.resources = &entry->second.resources};
input_info.stage = {.program = &permutation->program, .resources = &entry->second.resources};
permutation->program.bindings.AdvancePushData(push_data_cursor);
return permutation->handle;
}
@@ -368,16 +385,41 @@ struct PipelineCache::ProgramCache {
options.wave_size = input_info.wave_size;
}
DumpShaderOriginal(stage_name, options.shader_hash, params.code);
auto translated = ShaderRecompiler::TranslateProgram(params.code, options);
ShaderRecompiler::ShaderSource source;
if (entry == programs.end()) source = ShaderRecompiler::PrepareShaderSource(params.code, options);
auto* current = entry == programs.end() ? &source : entry->second.call_source.get();
ShaderRecompiler::TranslateResult translated;
if (current != nullptr) {
const auto& decoded = entry == programs.end()
? ShaderRecompiler::RefreshShaderSource(*current, runtime)
: current->linked->decoded;
translated = ShaderRecompiler::TranslateProgram(decoded, options);
translated.program.source_reads = current->reads;
} else {
translated = ShaderRecompiler::TranslateProgram(params.code, options);
}
if (entry == programs.end()) {
auto retained = source.call ? std::make_unique<ShaderRecompiler::ShaderSource>(std::move(source)) : nullptr;
entry = programs.try_emplace(lookup_key,
ShaderRecompiler::IR::ExtractResourcePlan(translated.program)).first;
ShaderRecompiler::IR::ExtractResourcePlan(translated.program), std::move(retained)).first;
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
entry->second.resource_plan, runtime, entry->second.resources,
entry->second.specialization));
} else if (source_changed) {
entry->second.resource_plan = ShaderRecompiler::IR::ExtractResourcePlan(translated.program);
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
entry->second.resource_plan, runtime, entry->second.resources,
entry->second.specialization));
if (const auto permutation = std::ranges::find_if(entry->second.permutations, matches);
permutation != entry->second.permutations.end()) {
input_info.stage = {.program = &permutation->program, .resources = &entry->second.resources};
permutation->program.bindings.AdvancePushData(push_data_cursor);
return permutation->handle;
}
}
entry->second.permutations.push_back(CompilePermutation(
stage_name, options, std::move(translated), entry->second.specialization, push_data_cursor));
stage_name, options, std::move(translated), entry->second.specialization, push_data_cursor,
function_code(entry->second.call_source)));
const auto& permutation = entry->second.permutations.back();
input_info.stage = {.program = &permutation.program, .resources = &entry->second.resources};
permutation.program.bindings.AdvancePushData(push_data_cursor);