diff --git a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp index b8111b9c6..4c23a8014 100644 --- a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp +++ b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourcePlan.hpp @@ -1,6 +1,7 @@ #ifndef CORE_SHADER_RECOMPILIER_INTERMEDIATEREPRESENTATION_INCLUDE_INTERMEDIATEREPRESENTATION_IRMETADATA_RESOURCEPLAN_HPP #define CORE_SHADER_RECOMPILIER_INTERMEDIATEREPRESENTATION_INCLUDE_INTERMEDIATEREPRESENTATION_IRMETADATA_RESOURCEPLAN_HPP +#include "IntermediateRepresentation/IrBlock.hpp" #include "IntermediateRepresentation/IrValue.hpp" #include "IntermediateRepresentation/IrMetadata/ControlFlowInfo.hpp" #include "IntermediateRepresentation/IrMetadata/DescriptorBinding.hpp" @@ -55,6 +56,7 @@ struct IrResourcePlan { std::uint32_t userDataBase = 0; std::uint32_t userDataCount = 64; std::vector> valueStorage; + std::vector> blockStorage; std::vector memoryInfo; std::vector descriptorSources; std::vector controlFlow; diff --git a/core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp b/core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp index 73ffff561..3ef05a961 100644 --- a/core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp +++ b/core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -794,6 +795,68 @@ void ResourceMaterializer::Apply(IrProgram& program, const ResourceSpecializatio resources.memoryInfo = std::move(memoryInfo); } +namespace { + +void ownPlanValues(IrResourcePlan& plan) { + std::vector roots; + for (auto& source : plan.descriptorSources) { + for (auto& dword : source.dwords) roots.push_back(&dword); + } + for (auto& read : plan.srtReads) roots.push_back(&read.value); + for (auto& block : plan.controlFlow) roots.push_back(&block.condition); + for (auto& value : plan.uniformFill.values) roots.push_back(&value); + + std::unordered_map clones; + std::vector order; + std::vector pending; + for (const auto* root : roots) { + if (*root != nullptr) pending.push_back(*root); + } + while (!pending.empty()) { + const auto* value = pending.back(); + pending.pop_back(); + if (!clones.emplace(value, nullptr).second) continue; + order.push_back(value); + for (const auto* argument : value->Arguments()) { + if (argument != nullptr) pending.push_back(argument); + } + } + for (const auto* value : order) { + auto clone = std::make_unique(value->Opcode(), value->Type(), value->Id()); + clone->SetFlags(value->Flags()); + if (value->HasImmediate()) clone->SetImmediateU64(value->ImmediateU64()); + clone->SetRegister(value->Register()); + clones[value] = clone.get(); + plan.valueStorage.push_back(std::move(clone)); + } + std::unordered_map blocks; + const auto blockFor = [&](const IrBlock* block) { + auto& clone = blocks[block]; + if (clone == nullptr) { + plan.blockStorage.push_back(std::make_unique(block->Id())); + clone = plan.blockStorage.back().get(); + } + return clone; + }; + for (const auto* value : order) { + auto* clone = clones.at(value); + for (std::size_t index = 0; index < value->ArgumentCount(); index++) { + const auto* argument = value->Argument(index); + auto* mapped = argument == nullptr ? nullptr : clones.at(argument); + if (value->IsPhi()) { + clone->AddPhiOperand(blockFor(value->PhiBlock(index)), mapped); + } else { + clone->AddArgument(mapped); + } + } + } + for (auto* root : roots) { + if (*root != nullptr) *root = clones.at(*root); + } +} + +} + IrResourcePlan ResourceMaterializer::ExtractPlan(const IrProgram& program) const { const IrResourcePlan& source = program.Resources(); if (!source.resourceTrackingComplete || !source.srtPlanComplete) { @@ -814,6 +877,7 @@ IrResourcePlan ResourceMaterializer::ExtractPlan(const IrProgram& program) const plan.resourceTrackingComplete = source.resourceTrackingComplete; plan.info = source.info; plan.uniformFill = source.uniformFill; + ownPlanValues(plan); const auto addSource = [&plan](std::uint32_t index) { if (index >= plan.descriptorSources.size()) { throw std::runtime_error("ResourceMaterializer::ExtractPlan resource references an unknown descriptor source"); diff --git a/core/shader/recompiler/Recompiler.cpp b/core/shader/recompiler/Recompiler.cpp index 78aa9b05c..a3f948b2b 100644 --- a/core/shader/recompiler/Recompiler.cpp +++ b/core/shader/recompiler/Recompiler.cpp @@ -188,6 +188,7 @@ struct SourceEntry { // rethrown: the front end ran every pass before failing, ~13 ms per dispatch of a shader the // title issues every frame (0x1048947300 at the intro video). APS5_NO_FAILURE_MEMO=1 rebuilds. std::exception_ptr planFailure; + std::unique_ptr program; std::vector> variants; // The result memo, most recently used first, at most ResultMemoEntries (under mutex). std::list memo; @@ -197,15 +198,14 @@ struct SourceEntry { namespace { struct ResourceProgram { - explicit ResourceProgram(const RecompileRequest& request) : program(PrepareResourceProgram(request)), plan(ResourceMaterializer{}.ExtractPlan(program)) {} + explicit ResourceProgram(const RecompileRequest& request) : program(std::make_unique(PrepareResourceProgram(request))), plan(std::make_shared(ResourceMaterializer{}.ExtractPlan(*program))) {} - IrProgram program; - IrResourcePlan plan; + std::unique_ptr program; + std::shared_ptr plan; }; std::shared_ptr makeResourcePlan(const RecompileRequest& request) { - const auto resource = std::make_shared(request); - return std::shared_ptr(resource, &resource->plan); + return ResourceProgram(request).plan; } struct SourceKeyHash { @@ -263,7 +263,9 @@ std::shared_ptr getSource(const RecompileRequest& request) { static const bool memoFailures = std::getenv("APS5_NO_FAILURE_MEMO") == nullptr; if (memoFailures && source->planFailure) std::rethrow_exception(source->planFailure); try { - source->plan = makeResourcePlan(request); + ResourceProgram resource(request); + source->plan = std::move(resource.plan); + source->program = std::move(resource.program); } catch (...) { if (memoFailures) source->planFailure = std::current_exception(); throw; @@ -389,10 +391,12 @@ std::shared_ptr findOrCompileVariant(SourceEntry& source, } } if (variant == nullptr) { - auto program = PrepareResourceProgram(request); + auto program = source.program != nullptr ? std::move(*source.program) : PrepareResourceProgram(request); + source.program.reset(); variant = std::make_shared(compileVariant(request, std::move(program), snapshot, specialization)); if (disk) ShaderDiskCache::Store(std::move(diskKey), variant); } + source.program.reset(); source.variants.push_back(variant); return variant; }