mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
perf(recompiler): report which user-data words a resource capture only reads through
The SRT evaluator records every raw read with the user-data word its address is based on, and marks a word used as a plain value. The result also names the user-data word behind each shader-data dword. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
940eba9a26
commit
553690c0d3
8 files changed
+46
-3
No files matched your search
@@ -19,6 +19,7 @@ struct BindingAllocationResult : CompiledBindingLayout {
|
||||
std::vector<PipelineSpecializationConstant> specialization;
|
||||
std::vector<DescriptorBinding> bindings;
|
||||
std::vector<std::byte> pushConstants;
|
||||
std::vector<std::uint32_t> shaderDataUserWords;
|
||||
};
|
||||
|
||||
class BindingAllocator {
|
||||
|
||||
@@ -38,6 +38,7 @@ struct ResourceCapture {
|
||||
// The walk's read addresses when the plan has pure flat slots (the leaf of each pure slot,
|
||||
// and every other read sorted and deduplicated); empty otherwise.
|
||||
SrtReadTrace readTrace;
|
||||
SrtUserDataUse userDataUse;
|
||||
// APS5_PROFILE_DRAW: what CaptureResources spent resolving the source (the stage inputs, the
|
||||
// key over the code, the plan) before the walk.
|
||||
std::uint64_t sourceNanoseconds = 0;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define CORE_SHADER_RECOMPILIER_OPTIMIZATION_INCLUDE_OPTIMIZATION_SRTWALKER_HPP
|
||||
|
||||
#include "IntermediateRepresentation/IrProgram.hpp"
|
||||
#include "UserDataUse.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
@@ -35,6 +36,7 @@ struct SrtRuntime {
|
||||
SrtMemoryProbe accessible = nullptr;
|
||||
SrtMemoryProbe pendingWrite = nullptr;
|
||||
SrtMemoryBulkReader readWords = nullptr;
|
||||
SrtUserDataUse* userDataUse = nullptr;
|
||||
};
|
||||
|
||||
enum class RuntimeValueType {
|
||||
|
||||
@@ -525,6 +525,10 @@ void DescriptorBindingBuilder::Populate(BindingAllocationResult& allocation, con
|
||||
const auto& layout = compiled.layout;
|
||||
const bool needsShaderData = layout.UsesPushData() || plan.storageData;
|
||||
auto shaderData = needsShaderData ? ShaderDataDwordsFor(layout, userDataBase, snapshot, partialThreads, plan.imageMetadata, plan.runtimeState) : std::vector<std::uint32_t>{};
|
||||
allocation.shaderDataUserWords.clear();
|
||||
if (needsShaderData) {
|
||||
for (const auto reg : layout.userDataRegisters) allocation.shaderDataUserWords.push_back(reg - userDataBase);
|
||||
}
|
||||
std::vector<DescriptorBinding> bindings;
|
||||
bindings.reserve(plan.bindings.size());
|
||||
std::size_t writtenHere = 0;
|
||||
|
||||
@@ -194,7 +194,18 @@ bool BasicEvaluator<TNode>::EvaluateRawRead(const TNode& inst, std::uint64_t& re
|
||||
std::uint64_t low = 0;
|
||||
std::uint64_t high = 0;
|
||||
std::uint64_t offset = 0;
|
||||
if (!Arg(handle, 0, low) || !Arg(handle, 1, high) || !Arg(inst, 1, offset)) {
|
||||
std::int32_t origin = -1;
|
||||
const auto baseWord = [&] {
|
||||
const TNode source = handle.Argument(0);
|
||||
if (_runtime.userDataUse == nullptr || source.HasImmediate() || source.Opcode() != IrOpcode::GetUserData) return Arg(handle, 0, low);
|
||||
const auto reg = RegIndex(static_cast<ScalarReg>(source.Argument(0).RegisterIndex()));
|
||||
if (reg < _program.userDataBase || reg - _program.userDataBase >= _runtime.userData.size() || reg - _program.userDataBase >= SrtUserDataUse::TrackedWords) return Arg(handle, 0, low);
|
||||
origin = static_cast<std::int32_t>(reg - _program.userDataBase);
|
||||
low = _runtime.userData[reg - _program.userDataBase];
|
||||
_runtime.userDataUse->asBase |= std::uint64_t {1} << origin;
|
||||
return true;
|
||||
};
|
||||
if (!baseWord() || !Arg(handle, 1, high) || !Arg(inst, 1, offset)) {
|
||||
return false;
|
||||
}
|
||||
const auto base = ((high << 32u) | static_cast<std::uint32_t>(low)) & AddressMask;
|
||||
@@ -229,6 +240,7 @@ bool BasicEvaluator<TNode>::EvaluateRawRead(const TNode& inst, std::uint64_t& re
|
||||
result = 0;
|
||||
return true;
|
||||
}
|
||||
if (_runtime.userDataUse != nullptr) _runtime.userDataUse->reads.emplace_back(address, origin);
|
||||
if (_inaccessible != nullptr && _runtime.accessible != nullptr && !_runtime.accessible(_runtime.userContext, address, sizeof(std::uint32_t)) && LoadedFromMemory(*handle.Value())) {
|
||||
*_inaccessible = {inst.Value(), address};
|
||||
return false;
|
||||
@@ -407,6 +419,7 @@ bool BasicEvaluator<TNode>::EvaluateInst(const TNode& inst, std::uint64_t& resul
|
||||
if (reg < _program.userDataBase || reg - _program.userDataBase >= _runtime.userData.size()) {
|
||||
return false;
|
||||
}
|
||||
if (_runtime.userDataUse != nullptr) _runtime.userDataUse->asValue |= reg - _program.userDataBase < SrtUserDataUse::TrackedWords ? std::uint64_t {1} << (reg - _program.userDataBase) : ~std::uint64_t {0};
|
||||
result = _runtime.userData[reg - _program.userDataBase];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -992,6 +992,7 @@ RecompileResult materializeResult(const CompiledVariant& variant, const Recompil
|
||||
std::copy_n(runtimeSelectors.begin(), layout.runtimeStateDwords, data->guestDescriptor.begin() + first);
|
||||
}
|
||||
}
|
||||
result.shaderDataUserWords = std::move(bindings.shaderDataUserWords);
|
||||
result.poisonedSrtReads = static_cast<std::uint32_t>(snapshot.srtPoison.size()) + snapshot.nullRootReads;
|
||||
if (!tables.map.empty()) {
|
||||
result.imageTablePoison.reserve(tables.poison.size());
|
||||
@@ -1326,11 +1327,12 @@ namespace {
|
||||
// traced into the capture (ResourceCapture::readTrace).
|
||||
void materializeCapture(ResourceCapture& capture, const SrtRuntime& runtime) {
|
||||
const auto& plan = *capture.plan;
|
||||
SrtRuntime traced = runtime;
|
||||
traced.userDataUse = &capture.userDataUse;
|
||||
if (std::none_of(plan.pureFlatSlots.begin(), plan.pureFlatSlots.end(), [](std::uint8_t pure) { return pure != 0u; })) {
|
||||
ResourceMaterializer{}.Materialize(plan, runtime, capture.snapshot);
|
||||
ResourceMaterializer{}.Materialize(plan, traced, capture.snapshot);
|
||||
return;
|
||||
}
|
||||
SrtRuntime traced = runtime;
|
||||
traced.readTrace = &capture.readTrace;
|
||||
ResourceMaterializer{}.Materialize(plan, traced, capture.snapshot);
|
||||
auto& other = capture.readTrace.otherReads;
|
||||
|
||||
@@ -579,6 +579,7 @@ struct ShaderInvocation {
|
||||
struct RecompileResult : CompiledShaderArtifact, ShaderInvocation {
|
||||
bool cacheHit = false;
|
||||
std::uint32_t workgroupMemoryDwords = 0;
|
||||
std::vector<std::uint32_t> shaderDataUserWords;
|
||||
[[nodiscard]] std::uint64_t PipelineVariantId() const { return specializationId != 0 ? specializationId : variantId; }
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef CORE_SHADER_RECOMPILER_USERDATAUSE_HPP
|
||||
#define CORE_SHADER_RECOMPILER_USERDATAUSE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ShaderRecompiler {
|
||||
|
||||
struct SrtUserDataUse {
|
||||
static constexpr std::uint32_t TrackedWords = 64;
|
||||
std::uint64_t asBase = 0;
|
||||
std::uint64_t asValue = 0;
|
||||
std::vector<std::pair<std::uint64_t, std::int32_t>> reads;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user