mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
shader: preserve source and IR before resource tracking failures
This commit is contained in:
@@ -29,7 +29,6 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <spirv-tools/libspirv.hpp>
|
#include <spirv-tools/libspirv.hpp>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <tuple>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <xxhash.h>
|
#include <xxhash.h>
|
||||||
@@ -116,33 +115,22 @@ void DumpShaderSpirv(const char* stage_name, uint64_t shader_hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DumpShaderOriginal(const char* stage_name, uint64_t shader_hash,
|
void DumpShaderOriginal(const char* stage_name, uint64_t shader_hash,
|
||||||
std::span<const uint32_t> code, const std::string& decoded_dump) {
|
std::span<const uint32_t> code) {
|
||||||
if (!Config::GraphicsDebugDumpEnabled()) {
|
if (!Config::GraphicsDebugDumpEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EXIT_IF(code.empty());
|
EXIT_IF(code.empty());
|
||||||
static std::atomic_int id = 0;
|
static std::atomic_int id = 0;
|
||||||
const auto base = Config::GetShaderLogFolder() / "original" /
|
const auto path = Config::GetShaderLogFolder() / "original" /
|
||||||
fmt::format("{:04d}_new_shader_{}_{:016x}", id++, stage_name, shader_hash);
|
fmt::format("{:04d}_new_shader_{}_{:016x}.bin", id++, stage_name, shader_hash);
|
||||||
Common::File::CreateDirectories(base.parent_path());
|
Common::File::CreateDirectories(path.parent_path());
|
||||||
for (const auto& [suffix, data, size]: {
|
|
||||||
std::tuple {".bin", static_cast<const void*>(code.data()), code.size_bytes()},
|
|
||||||
std::tuple {".rdna2", static_cast<const void*>(decoded_dump.data()),
|
|
||||||
decoded_dump.size()},
|
|
||||||
}) {
|
|
||||||
if (size == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto path = base;
|
|
||||||
path += suffix;
|
|
||||||
Common::File file(path);
|
Common::File file(path);
|
||||||
if (file.IsInvalid()) {
|
if (file.IsInvalid()) {
|
||||||
const auto path_text = Common::PathToString(path);
|
const auto path_text = Common::PathToString(path);
|
||||||
LOGF_COLOR(Log::Color::BrightRed, "Can't create file: %s\n", path_text.c_str());
|
LOGF_COLOR(Log::Color::BrightRed, "Can't create file: %s\n", path_text.c_str());
|
||||||
} else {
|
return;
|
||||||
file.Write(data, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
file.Write(code.data(), code.size_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValidateShaderSpirv(const char* label, uint64_t shader_hash,
|
bool ValidateShaderSpirv(const char* label, uint64_t shader_hash,
|
||||||
@@ -225,25 +213,13 @@ struct PipelineCache::ProgramCache {
|
|||||||
|
|
||||||
static constexpr std::size_t MaxStaticKeyWords = 13 + ShaderVertexInputInfo::RES_MAX * 13;
|
static constexpr std::size_t MaxStaticKeyWords = 13 + ShaderVertexInputInfo::RES_MAX * 13;
|
||||||
|
|
||||||
Permutation CompilePermutation(const ShaderParams& params,
|
Permutation CompilePermutation(const char* stage_name,
|
||||||
const ShaderRecompiler::CompileOptions& options,
|
const ShaderRecompiler::CompileOptions& options,
|
||||||
ShaderRecompiler::TranslateResult translated,
|
ShaderRecompiler::TranslateResult translated,
|
||||||
ShaderRecompiler::IR::ResourceSpecialization specialization,
|
ShaderRecompiler::IR::ResourceSpecialization specialization,
|
||||||
uint32_t push_data_start_dword) {
|
uint32_t push_data_start_dword) {
|
||||||
const char* stage_name = nullptr;
|
|
||||||
switch (options.stage) {
|
|
||||||
case ShaderType::Vertex: stage_name = "vs"; break;
|
|
||||||
case ShaderType::Mesh: stage_name = "ms"; break;
|
|
||||||
case ShaderType::Local: stage_name = "ls"; break;
|
|
||||||
case ShaderType::TessellationControl: stage_name = "hs"; break;
|
|
||||||
case ShaderType::TessellationEvaluation: stage_name = "ds"; break;
|
|
||||||
case ShaderType::Pixel: stage_name = "ps"; break;
|
|
||||||
case ShaderType::Compute: stage_name = "cs"; break;
|
|
||||||
default: EXIT("invalid pipeline shader stage\n");
|
|
||||||
}
|
|
||||||
auto result = ShaderRecompiler::CompileProgram(std::move(translated), options,
|
auto result = ShaderRecompiler::CompileProgram(std::move(translated), options,
|
||||||
specialization, push_data_start_dword);
|
specialization, push_data_start_dword);
|
||||||
DumpShaderOriginal(stage_name, options.shader_hash, params.code, result.decoded_dump);
|
|
||||||
if (!ValidateShaderSpirv(options.dump_label, options.shader_hash, result.spirv)) {
|
if (!ValidateShaderSpirv(options.dump_label, options.shader_hash, result.spirv)) {
|
||||||
DumpShaderSpirv(stage_name, options.shader_hash, result.spirv);
|
DumpShaderSpirv(stage_name, options.shader_hash, result.spirv);
|
||||||
EXIT("%s failed hash=0x%016" PRIx64 ": SPIR-V validation failed\n", options.dump_label,
|
EXIT("%s failed hash=0x%016" PRIx64 ": SPIR-V validation failed\n", options.dump_label,
|
||||||
@@ -321,14 +297,15 @@ struct PipelineCache::ProgramCache {
|
|||||||
stage_input.compute = &input_info;
|
stage_input.compute = &input_info;
|
||||||
}
|
}
|
||||||
const char* label = nullptr;
|
const char* label = nullptr;
|
||||||
|
const char* stage_name = nullptr;
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case ShaderType::Vertex: label = "ShaderRecompiler VS"; break;
|
case ShaderType::Vertex: label = "ShaderRecompiler VS"; stage_name = "vs"; break;
|
||||||
case ShaderType::Mesh: label = "ShaderRecompiler MS"; break;
|
case ShaderType::Mesh: label = "ShaderRecompiler MS"; stage_name = "ms"; break;
|
||||||
case ShaderType::Local: label = "ShaderRecompiler LS"; break;
|
case ShaderType::Local: label = "ShaderRecompiler LS"; stage_name = "ls"; break;
|
||||||
case ShaderType::TessellationControl: label = "ShaderRecompiler HS"; break;
|
case ShaderType::TessellationControl: label = "ShaderRecompiler HS"; stage_name = "hs"; break;
|
||||||
case ShaderType::TessellationEvaluation: label = "ShaderRecompiler DS"; break;
|
case ShaderType::TessellationEvaluation: label = "ShaderRecompiler DS"; stage_name = "ds"; break;
|
||||||
case ShaderType::Pixel: label = "ShaderRecompiler PS"; break;
|
case ShaderType::Pixel: label = "ShaderRecompiler PS"; stage_name = "ps"; break;
|
||||||
case ShaderType::Compute: label = "ShaderRecompiler CS"; break;
|
case ShaderType::Compute: label = "ShaderRecompiler CS"; stage_name = "cs"; break;
|
||||||
default: EXIT("invalid pipeline shader stage\n");
|
default: EXIT("invalid pipeline shader stage\n");
|
||||||
}
|
}
|
||||||
ShaderRecompiler::CompileOptions options;
|
ShaderRecompiler::CompileOptions options;
|
||||||
@@ -351,6 +328,7 @@ struct PipelineCache::ProgramCache {
|
|||||||
} else {
|
} else {
|
||||||
options.wave_size = input_info.wave_size;
|
options.wave_size = input_info.wave_size;
|
||||||
}
|
}
|
||||||
|
DumpShaderOriginal(stage_name, options.shader_hash, params.code);
|
||||||
auto translated = ShaderRecompiler::TranslateProgram(params.code, options);
|
auto translated = ShaderRecompiler::TranslateProgram(params.code, options);
|
||||||
if (translated.skip_dispatch) {
|
if (translated.skip_dispatch) {
|
||||||
entry = programs.try_emplace(lookup_key, ShaderRecompiler::IR::ResourcePlan {}).first;
|
entry = programs.try_emplace(lookup_key, ShaderRecompiler::IR::ResourcePlan {}).first;
|
||||||
@@ -365,7 +343,7 @@ struct PipelineCache::ProgramCache {
|
|||||||
entry->second.specialization));
|
entry->second.specialization));
|
||||||
}
|
}
|
||||||
entry->second.permutations.push_back(CompilePermutation(
|
entry->second.permutations.push_back(CompilePermutation(
|
||||||
params, options, std::move(translated), entry->second.specialization, push_data_cursor));
|
stage_name, options, std::move(translated), entry->second.specialization, push_data_cursor));
|
||||||
const auto& permutation = entry->second.permutations.back();
|
const auto& permutation = entry->second.permutations.back();
|
||||||
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);
|
permutation.program.bindings.AdvancePushData(push_data_cursor);
|
||||||
|
|||||||
@@ -623,13 +623,21 @@ TranslateResult TranslateProgram(std::span<const uint32_t> code, const CompileOp
|
|||||||
IR::EliminateDeadCode(ir.blocks);
|
IR::EliminateDeadCode(ir.blocks);
|
||||||
}
|
}
|
||||||
LowerTessellationMemory(ir, options);
|
LowerTessellationMemory(ir, options);
|
||||||
|
std::string cfg_dump;
|
||||||
|
if (options.dump_ir) {
|
||||||
|
cfg_dump = CFG::GraphToString(cfg);
|
||||||
|
if (options.early_dump) {
|
||||||
|
LOGF("%s native IR before resource tracking:\n%s", GetDumpLabel(options),
|
||||||
|
MakeIrDump(cfg_dump, ir).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
IR::TrackResources(ir, decoded, native_cfg);
|
IR::TrackResources(ir, decoded, native_cfg);
|
||||||
IR::EliminateDeadCode(ir.blocks);
|
IR::EliminateDeadCode(ir.blocks);
|
||||||
TranslateResult result;
|
TranslateResult result;
|
||||||
result.program = std::move(ir);
|
result.program = std::move(ir);
|
||||||
if (options.dump_ir) {
|
if (options.dump_ir) {
|
||||||
result.decoded_dump = std::move(decoded_dump);
|
result.decoded_dump = std::move(decoded_dump);
|
||||||
result.cfg_dump = CFG::GraphToString(cfg);
|
result.cfg_dump = std::move(cfg_dump);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user