[debug,dump] new dump folder/naming standard for guest/spirv shaders and macros

This commit is contained in:
xbzk 2026-05-26 23:27:39 -03:00
parent f28e438b0d
commit 38b4830ab0
8 changed files with 51 additions and 42 deletions

View File

@ -212,6 +212,16 @@ bool IsNceEnabled() {
return is_nce_enabled;
}
static u64 current_program_id = 0;
void SetCurrentProgramID(u64 program_id) {
current_program_id = program_id;
}
u64 GetCurrentProgramID() {
return current_program_id;
}
bool IsDockedMode() {
return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
}

View File

@ -869,6 +869,9 @@ bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit);
bool IsNceEnabled();
void SetCurrentProgramID(u64 program_id);
u64 GetCurrentProgramID();
bool IsOpenGL();
bool IsDockedMode();

View File

@ -326,6 +326,9 @@ struct System::Impl {
LOG_INFO(Core, "Loading {} ({:016X}) ...", name, params.program_id);
// Expose program id to dump sites and other global readers.
Settings::SetCurrentProgramID(params.program_id);
// Track launch time for frontend launches
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);

View File

@ -302,24 +302,22 @@ bool IsActive() noexcept {
return Settings::values.gpu_log_level.GetValue() != Settings::GpuLogLevel::Off;
}
void DumpSpirvShader(const std::string& shader_name, std::span<const u32> spirv_code) {
void DumpSpirvShader(u64 shader_hash, std::span<const u32> spirv_code) {
if (spirv_code.empty()) {
return;
}
using namespace Common::FS;
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
const auto shaders_dir = log_dir / "shaders";
const auto& dump_dir = GetEdenPath(EdenPath::DumpDir);
// Ensure parent + shaders/ exist once. CreateDir is idempotent — guarded just to
// skip the syscall on subsequent dumps.
static std::once_flag dirs_flag;
std::call_once(dirs_flag, [&log_dir, &shaders_dir]() {
[[maybe_unused]] const bool log_dir_created = CreateDir(log_dir);
[[maybe_unused]] const bool shaders_dir_created = CreateDir(shaders_dir);
// Ensure DumpDir exists once. CreateDir is idempotent, so guarded to skip the syscall.
static std::once_flag dump_dir_flag;
std::call_once(dump_dir_flag, [&dump_dir]() {
[[maybe_unused]] const bool created = CreateDir(dump_dir);
});
const auto shader_path = shaders_dir / fmt::format("{}.spv", shader_name);
const auto shader_path = dump_dir / fmt::format("{:016x}_{:016x}.spv",
Settings::GetCurrentProgramID(), shader_hash);
Common::FS::IOFile shader_file(shader_path, FileAccessMode::Write, FileType::BinaryFile);
if (!shader_file.IsOpen()) {
LOG_WARNING(Render_Vulkan, "[Shader Dump] Failed to open {}", shader_path.string());

View File

@ -184,7 +184,7 @@ private:
[[nodiscard]] bool IsActive() noexcept;
void DumpSpirvShader(const std::string& shader_name, std::span<const u32> spirv_code);
void DumpSpirvShader(u64 shader_hash, std::span<const u32> spirv_code);
// Helper to get stage name from index
inline const char* GetShaderStageName(size_t stage_index) {

View File

@ -1329,22 +1329,14 @@ Macro::Opcode MacroJITx64Impl::GetOpCode() const {
#endif
static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
const auto base_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
const auto macro_dir{base_dir / "macros"};
if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
const auto dump_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
if (!Common::FS::CreateDir(dump_dir)) {
LOG_ERROR(Common_Filesystem, "Failed to create dump directory");
return;
}
auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
if (decompiled) {
auto new_name{macro_dir / fmt::format("decompiled_{:016x}.macro", hash)};
if (Common::FS::Exists(name)) {
(void)Common::FS::RenameFile(name, new_name);
return;
}
name = new_name;
}
const char* const variant_suffix = decompiled ? "jit" : "raw";
const auto name{dump_dir / fmt::format("{:016x}_{:016x}_{}.macro",
Settings::GetCurrentProgramID(), hash, variant_suffix)};
std::fstream macro_file(name, std::ios::out | std::ios::binary);
if (!macro_file) {

View File

@ -797,7 +797,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
GPU::Logging::GPULogger::GetInstance().LogShaderCompilation(shader_name, shader_info);
}
if (should_dump) {
GPU::Logging::DumpSpirvShader(shader_name, std::span<const u32>(code.data(), code.size()));
GPU::Logging::DumpSpirvShader(key.unique_hashes[index],
std::span<const u32>(code.data(), code.size()));
}
}
@ -920,7 +921,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
GPU::Logging::GPULogger::GetInstance().LogShaderCompilation(shader_name, shader_info);
}
if (should_dump) {
GPU::Logging::DumpSpirvShader(shader_name, std::span<const u32>(code.data(), code.size()));
GPU::Logging::DumpSpirvShader(key.unique_hash,
std::span<const u32>(code.data(), code.size()));
}
}

View File

@ -18,6 +18,7 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging.h"
#include "common/settings.h"
#include <ranges>
#include "shader_recompiler/environment.h"
#include "video_core/engines/kepler_compute.h"
@ -73,36 +74,36 @@ static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture
static std::string_view StageToPrefix(Shader::Stage stage) {
switch (stage) {
case Shader::Stage::VertexB:
return "VB";
return "vs";
case Shader::Stage::TessellationControl:
return "TC";
return "tc";
case Shader::Stage::TessellationEval:
return "TE";
return "te";
case Shader::Stage::Geometry:
return "GS";
return "gs";
case Shader::Stage::Fragment:
return "FS";
return "fs";
case Shader::Stage::Compute:
return "CS";
return "cs";
case Shader::Stage::VertexA:
return "VA";
return "va";
default:
return "UK";
return "uk";
}
}
static void DumpImpl(u64 pipeline_hash, u64 shader_hash, std::span<const u64> code,
static void DumpImpl(u64 /*pipeline_hash*/, u64 shader_hash, std::span<const u64> code,
[[maybe_unused]] u32 read_highest, [[maybe_unused]] u32 read_lowest,
u32 initial_offset, Shader::Stage stage) {
const auto shader_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
const auto base_dir{shader_dir / "shaders"};
if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) {
LOG_ERROR(Common_Filesystem, "Failed to create shader dump directories");
const auto dump_dir{Common::FS::GetEdenPath(Common::FS::EdenPath::DumpDir)};
if (!Common::FS::CreateDir(dump_dir)) {
LOG_ERROR(Common_Filesystem, "Failed to create dump directory");
return;
}
const auto prefix = StageToPrefix(stage);
const auto name{base_dir /
fmt::format("{:016x}_{}_{:016x}.ash", pipeline_hash, prefix, shader_hash)};
const auto name{dump_dir /
fmt::format("{:016x}_{:016x}_{}.ash",
Settings::GetCurrentProgramID(), shader_hash, prefix)};
std::fstream shader_file(name, std::ios::out | std::ios::binary);
ASSERT(initial_offset % sizeof(u64) == 0);
const size_t jump_index = initial_offset / sizeof(u64);