mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: map debug SPIR-V blocks to native RDNA2 PCs
This commit is contained in:
@@ -394,6 +394,7 @@ struct PipelineCache::ProgramCache {
|
||||
options.back_code = params.back_code;
|
||||
options.dump_ir = Config::GetShaderLogDirection() != Config::LogDirection::Silent;
|
||||
options.early_dump = options.dump_ir;
|
||||
options.emit_debug_info = Config::GraphicsDebugDumpEnabled();
|
||||
options.dump_label = label;
|
||||
options.input_info = stage_input;
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@ CompileResult CompileProgram(TranslateResult translated, const CompileOptions& o
|
||||
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n",
|
||||
GetDumpLabel(options), StageName(ir.stage), ir.shader_hash);
|
||||
auto spirv = Spirv::EmitProgram(ir, options.input_info, push_data_start_dword,
|
||||
options.maintenance8_enabled);
|
||||
options.maintenance8_enabled, options.emit_debug_info);
|
||||
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram words=%" PRIu64
|
||||
" elapsed_ms=%" PRIu64 "\n",
|
||||
GetDumpLabel(options), StageName(ir.stage), ir.shader_hash,
|
||||
|
||||
@@ -21,6 +21,7 @@ struct CompileOptions {
|
||||
uint64_t shader_hash = 0;
|
||||
bool dump_ir = true;
|
||||
bool early_dump = false;
|
||||
bool emit_debug_info = false;
|
||||
bool maintenance8_enabled = false;
|
||||
const char* dump_label = nullptr;
|
||||
std::span<const uint32_t> user_data;
|
||||
|
||||
@@ -160,6 +160,14 @@ void Builder::AddEntryPoint(spv::ExecutionModel execution_model, uint32_t entry_
|
||||
AppendInstruction(m_entry_points, spv::OpEntryPoint, operands);
|
||||
}
|
||||
|
||||
uint32_t Builder::AddString(const char* text) {
|
||||
const auto id = AllocateId();
|
||||
std::vector<uint32_t> operands = {id};
|
||||
AppendString(operands, text);
|
||||
AppendInstruction(m_debug, spv::OpString, operands);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Builder::AddName(uint32_t target, const char* name) {
|
||||
std::vector<uint32_t> operands = {target};
|
||||
AppendString(operands, name);
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
AppendInstruction(m_execution_modes, spv::OpExecutionMode, entry_point, mode, operands...);
|
||||
}
|
||||
|
||||
uint32_t AddString(const char* text);
|
||||
void AddName(uint32_t target, const char* name);
|
||||
template <typename... Args>
|
||||
void AddAnnotation(spv::Op opcode, const Args&... operands) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
|
||||
@@ -203,7 +204,8 @@ void ValidateNativeProgram(const IR::Program& program, bool lds_storage) {
|
||||
} // namespace
|
||||
|
||||
std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo input_info,
|
||||
uint32_t push_data_start_dword, bool maintenance8_enabled) {
|
||||
uint32_t push_data_start_dword, bool maintenance8_enabled,
|
||||
bool emit_debug_info) {
|
||||
using namespace Emitter;
|
||||
|
||||
if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex &&
|
||||
@@ -219,6 +221,12 @@ std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo inp
|
||||
IR::ValidateProgram(program, true);
|
||||
program.bindings = {.push_data_start_dword = push_data_start_dword};
|
||||
EmitterState state(program, input_info, maintenance8_enabled);
|
||||
if (emit_debug_info) {
|
||||
char name[64];
|
||||
std::snprintf(name, sizeof(name), "rdna2-%016" PRIx64 "-block-byte-pc-plus-one",
|
||||
program.shader_hash);
|
||||
state.debug_source = state.builder.AddString(name);
|
||||
}
|
||||
const auto* workgroup = ShaderWorkgroupInput(program.stage, input_info);
|
||||
state.lane_count =
|
||||
workgroup != nullptr && program.wave_size == 64u && workgroup->host_subgroup_size == 32u
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
// Resets and writes backend IDs and descriptor indices; do not emit the same program concurrently.
|
||||
std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo input_info,
|
||||
uint32_t push_data_start_dword = 0,
|
||||
bool maintenance8_enabled = false);
|
||||
bool maintenance8_enabled = false,
|
||||
bool emit_debug_info = false);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ struct EmitterState {
|
||||
IR::Program& program;
|
||||
ShaderStageInputInfo input_info;
|
||||
bool maintenance8_enabled;
|
||||
uint32_t debug_source = 0;
|
||||
uint32_t void_type = 0;
|
||||
uint32_t bool_type = 0;
|
||||
uint32_t u32_type = 0;
|
||||
@@ -182,6 +183,11 @@ uint32_t TypeU32ElementPointer(EmitterState& state, spv::StorageClass storage_cl
|
||||
inline void EmitLabel(EmitterState& state, uint32_t label) {
|
||||
state.current_label = label;
|
||||
state.builder.AddFunction(spv::OpLabel, label);
|
||||
if (state.debug_source != 0 && state.current_block != nullptr) {
|
||||
// Source lines encode the containing native block's byte offset plus one.
|
||||
state.builder.AddFunction(spv::OpLine, state.debug_source,
|
||||
state.current_block->start_pc + 1u, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TypeId(EmitterState& state, IR::Type type);
|
||||
|
||||
@@ -348,6 +348,7 @@ void EmitDispatcherFunction(ValueEmitContext& ctx, const DispatcherFunctionState
|
||||
const auto initial_parent = state.current_label;
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.header_label);
|
||||
|
||||
state.current_block = nullptr;
|
||||
EmitLabel(state, dispatcher.header_label);
|
||||
const auto pc = state.builder.AllocateId();
|
||||
const auto next_pc = state.builder.AllocateId();
|
||||
@@ -383,6 +384,7 @@ void EmitDispatcherFunction(ValueEmitContext& ctx, const DispatcherFunctionState
|
||||
next_pc_words.push_back(state.current_label);
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.after_switch_label);
|
||||
}
|
||||
state.current_block = nullptr;
|
||||
EmitLabel(state, dispatcher.after_switch_label);
|
||||
state.builder.AddFunction(next_pc_words);
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.continue_label);
|
||||
@@ -747,6 +749,7 @@ void EmitProgram(EmitterState& state) {
|
||||
EmitStructuredFunction(ctx);
|
||||
}
|
||||
state.builder.AddFunction(spv::OpFunctionEnd);
|
||||
state.current_block = nullptr;
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
EmitMeshEntryPoint(state);
|
||||
}
|
||||
|
||||
@@ -15711,6 +15711,46 @@ void TestRepeatedExportsHaveOneInterface() {
|
||||
"repeated exports duplicated Position or its clipping-error plane");
|
||||
}
|
||||
|
||||
void CheckSpirvBlockSourceMapping(TestCompileResult &result) {
|
||||
using namespace ShaderRecompiler;
|
||||
const auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
Check(SpirvInstructionOpcodeCount(result.spirv, spv::OpString) == 0 &&
|
||||
SpirvInstructionOpcodeCount(result.spirv, spv::OpLine) == 0,
|
||||
"default emission unexpectedly contains source mapping");
|
||||
const auto mapped = Spirv::EmitProgram(result.program, options.input_info, 0,
|
||||
false, true);
|
||||
CheckSpirvBinaryValidates(mapped);
|
||||
uint32_t source = 0;
|
||||
uint32_t label = 0;
|
||||
size_t lines = 0;
|
||||
uint32_t previous = spv::OpNop;
|
||||
for (size_t at = 5; at < mapped.size();) {
|
||||
const auto op = mapped[at] & spv::OpCodeMask;
|
||||
if (op == spv::OpLabel) label = mapped[at + 1];
|
||||
if (op == spv::OpString) {
|
||||
source = mapped[at + 1];
|
||||
Check(std::string(reinterpret_cast<const char *>(&mapped[at + 2]))
|
||||
.find("-block-byte-pc-plus-one") != std::string::npos,
|
||||
"debug source filename does not identify block offset encoding");
|
||||
} else if (op == spv::OpLine) {
|
||||
Check(previous == spv::OpLabel && mapped[at + 1] == source &&
|
||||
mapped[at + 3] == 0 &&
|
||||
std::ranges::any_of(result.program.blocks, [&](const auto *block) {
|
||||
return block->Definition() == label &&
|
||||
mapped[at + 2] == block->start_pc + 1u;
|
||||
}),
|
||||
"debug source line does not identify a native block after its label");
|
||||
++lines;
|
||||
}
|
||||
previous = op;
|
||||
at += mapped[at] >> spv::WordCountShift;
|
||||
}
|
||||
Check(source != 0 && lines >= result.program.blocks.size(),
|
||||
"debug emission omitted native block source mapping");
|
||||
Check(Spirv::EmitProgram(result.program, options.input_info) == result.spirv,
|
||||
"debug re-emission changed the default binary");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
const auto compile = [](const char *name, std::span<const uint32_t> shader,
|
||||
const SpirvMetrics &budget,
|
||||
@@ -15755,7 +15795,7 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
EncodeSopp(0x02, 0xfffcu), // continue/backedge
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const auto structured_result = compile("structured-phi", structured_phi,
|
||||
auto structured_result = compile("structured-phi", structured_phi,
|
||||
{.words = 174,
|
||||
.instructions = 49,
|
||||
.phis = 1,
|
||||
@@ -15772,6 +15812,7 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
structured_metrics.loads == 0u && structured_metrics.stores == 0u,
|
||||
"structured Phi retained a spill variable or edge memory operation");
|
||||
CheckSpirvPhiParents(structured_result.spirv);
|
||||
CheckSpirvBlockSourceMapping(structured_result);
|
||||
const auto structured_repeat =
|
||||
compile("structured-phi-repeat", structured_phi,
|
||||
{.words = 174,
|
||||
@@ -15942,7 +15983,7 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
EncodeSopp(0x02, 0xfffeu), // B -> C
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const auto dispatcher_result = compile("dispatcher", dispatcher,
|
||||
auto dispatcher_result = compile("dispatcher", dispatcher,
|
||||
{.words = 255,
|
||||
.instructions = 70,
|
||||
.variables = 3,
|
||||
@@ -15963,6 +16004,7 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
SpirvInstructionOpcodeCount(dispatcher_result.spirv, 251u) == 1u,
|
||||
"dispatcher size fixture lost its two control Phis or switch");
|
||||
CheckSpirvPhiParents(dispatcher_result.spirv);
|
||||
CheckSpirvBlockSourceMapping(dispatcher_result);
|
||||
}
|
||||
|
||||
#include "ShaderRayTracingTests.inc"
|
||||
|
||||
Reference in New Issue
Block a user