diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 5cb2d71dc5..9b582f1c2a 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -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; } diff --git a/src/common/settings.h b/src/common/settings.h index 75214a1064..bbe4234918 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -869,6 +869,9 @@ bool IsFastmemEnabled(); void SetNceEnabled(bool is_64bit); bool IsNceEnabled(); +void SetCurrentProgramID(u64 program_id); +u64 GetCurrentProgramID(); + bool IsOpenGL(); bool IsDockedMode(); diff --git a/src/core/core.cpp b/src/core/core.cpp index e730b808e0..2a7af265f5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -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); diff --git a/src/video_core/gpu_logging/gpu_logging.cpp b/src/video_core/gpu_logging/gpu_logging.cpp index b4e93d16cf..72e48e4996 100644 --- a/src/video_core/gpu_logging/gpu_logging.cpp +++ b/src/video_core/gpu_logging/gpu_logging.cpp @@ -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 spirv_code) { +void DumpSpirvShader(u64 shader_hash, std::span 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()); diff --git a/src/video_core/gpu_logging/gpu_logging.h b/src/video_core/gpu_logging/gpu_logging.h index d76859d0c3..b16988ed0b 100644 --- a/src/video_core/gpu_logging/gpu_logging.h +++ b/src/video_core/gpu_logging/gpu_logging.h @@ -184,7 +184,7 @@ private: [[nodiscard]] bool IsActive() noexcept; -void DumpSpirvShader(const std::string& shader_name, std::span spirv_code); +void DumpSpirvShader(u64 shader_hash, std::span spirv_code); // Helper to get stage name from index inline const char* GetShaderStageName(size_t stage_index) { diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index dbf011860e..dbef3637c3 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -1329,22 +1329,14 @@ Macro::Opcode MacroJITx64Impl::GetOpCode() const { #endif static void Dump(u64 hash, std::span 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) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 6ca553f010..7a5abe46cc 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -797,7 +797,8 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( GPU::Logging::GPULogger::GetInstance().LogShaderCompilation(shader_name, shader_info); } if (should_dump) { - GPU::Logging::DumpSpirvShader(shader_name, std::span(code.data(), code.size())); + GPU::Logging::DumpSpirvShader(key.unique_hashes[index], + std::span(code.data(), code.size())); } } @@ -920,7 +921,8 @@ std::unique_ptr PipelineCache::CreateComputePipeline( GPU::Logging::GPULogger::GetInstance().LogShaderCompilation(shader_name, shader_info); } if (should_dump) { - GPU::Logging::DumpSpirvShader(shader_name, std::span(code.data(), code.size())); + GPU::Logging::DumpSpirvShader(key.unique_hash, + std::span(code.data(), code.size())); } } diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 5f5633d4d1..5991682644 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -18,6 +18,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging.h" +#include "common/settings.h" #include #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 code, +static void DumpImpl(u64 /*pipeline_hash*/, u64 shader_hash, std::span 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);