From 44c8de5be953d9e4849a1bf49305f51fa1fbe1e3 Mon Sep 17 00:00:00 2001 From: psucien Date: Sat, 1 Jun 2024 15:16:39 +0200 Subject: [PATCH] libraries: gnmdriver: an option to dump application command lists --- src/common/config.cpp | 7 ++++ src/common/config.h | 1 + src/common/path_util.cpp | 1 + src/common/path_util.h | 2 ++ src/core/libraries/gnmdriver/gnmdriver.cpp | 38 +++++++++++++++++++++- 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 2da0844ec..b7d99bbf0 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -20,6 +20,7 @@ static bool isLibc = true; static bool isShowSplash = false; static bool isNullGpu = false; static bool shouldDumpShaders = false; +static bool shouldDumpPM4 = false; bool isLleLibc() { return isLibc; @@ -64,6 +65,10 @@ bool dumpShaders() { return shouldDumpShaders; } +bool dumpPM4() { + return shouldDumpPM4; +} + void load(const std::filesystem::path& path) { // If the configuration file does not exist, create it and return std::error_code error; @@ -102,6 +107,7 @@ void load(const std::filesystem::path& path) { gpuId = toml::find_or(gpu, "gpuId", 0); isNullGpu = toml::find_or(gpu, "nullGpu", false); shouldDumpShaders = toml::find_or(gpu, "dumpShaders", false); + shouldDumpPM4 = toml::find_or(gpu, "dumpPM4", false); } } if (data.contains("Debug")) { @@ -149,6 +155,7 @@ void save(const std::filesystem::path& path) { data["GPU"]["screenHeight"] = screenHeight; data["GPU"]["nullGpu"] = isNullGpu; data["GPU"]["dumpShaders"] = shouldDumpShaders; + data["GPU"]["dumpPM4"] = shouldDumpPM4; data["Debug"]["DebugDump"] = isDebugDump; data["LLE"]["libc"] = isLibc; diff --git a/src/common/config.h b/src/common/config.h index 8a8db4517..539253795 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -23,5 +23,6 @@ bool isLleLibc(); bool showSplash(); bool nullGpu(); bool dumpShaders(); +bool dumpPM4(); }; // namespace Config diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 35ac44481..7210f2122 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -35,6 +35,7 @@ static auto UserPaths = [] { create_path(PathType::LogDir, user_dir / LOG_DIR); create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR); create_path(PathType::ShaderDir, user_dir / SHADER_DIR); + create_path(PathType::PM4Dir, user_dir / PM4_DIR); create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR); create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR); diff --git a/src/common/path_util.h b/src/common/path_util.h index ea457040a..d7664871c 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -13,6 +13,7 @@ enum class PathType { LogDir, // Where log files are stored. ScreenshotsDir, // Where screenshots are stored. ShaderDir, // Where shaders are stored. + PM4Dir, // Where command lists are stored. SaveDataDir, // Where guest save data is stored. SysModuleDir, // Where system modules are stored. }; @@ -23,6 +24,7 @@ constexpr auto PORTABLE_DIR = "user"; constexpr auto LOG_DIR = "log"; constexpr auto SCREENSHOTS_DIR = "screenshots"; constexpr auto SHADER_DIR = "shader"; +constexpr auto PM4_DIR = "pm4"; constexpr auto SAVEDATA_DIR = "savedata"; constexpr auto SYSMODULES_DIR = "sys_modules"; diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 9b351c3c4..4e43544ae 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include "common/config.h" #include "common/logging/log.h" +#include "common/path_util.h" #include "core/libraries/error_codes.h" #include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/libs.h" @@ -28,6 +30,21 @@ static constexpr bool g_fair_hw_init = false; // In case if `submitDone` is issued we need to block submissions until GPU idle static u32 submission_lock{}; +static u64 frames_submitted{}; // frame counter + +static void DumpCommandList(std::span cmd_list, const std::string& postfix) { + using namespace Common::FS; + const auto dump_dir = GetUserPath(PathType::PM4Dir); + if (!std::filesystem::exists(dump_dir)) { + std::filesystem::create_directories(dump_dir); + } + if (cmd_list.empty()) { + return; + } + const auto filename = std::format("{:08}_{}", frames_submitted, postfix); + const auto file = IOFile{dump_dir / filename, FileAccessMode::Write}; + file.WriteSpan(cmd_list); +} // Write a special ending NOP packet with N DWs data block template @@ -1439,7 +1456,25 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[ const auto dcb_size_dw = dcb_sizes_in_bytes[cbpair] >> 2; const auto ccb_size_dw = ccb_size_in_bytes >> 2; - liverpool->SubmitGfx({dcb_gpu_addrs[cbpair], dcb_size_dw}, {ccb, ccb_size_dw}); + const auto& dcb_span = std::span{dcb_gpu_addrs[cbpair], dcb_size_dw}; + const auto& ccb_span = std::span{ccb, ccb_size_dw}; + + if (Config::dumpPM4()) { + static auto last_frame_num = frames_submitted; + static u32 seq_num{}; + if (last_frame_num == frames_submitted) { + ++seq_num; + } else { + last_frame_num = frames_submitted; + seq_num = 0u; + } + + // File name format is: __ + DumpCommandList(dcb_span, std::format("dcb_{}_{}", seq_num, cbpair)); + DumpCommandList(ccb_span, std::format("ccb_{}_{}", seq_num, cbpair)); + } + + liverpool->SubmitGfx(dcb_span, ccb_span); } return ORBIS_OK; @@ -1456,6 +1491,7 @@ int PS4_SYSV_ABI sceGnmSubmitDone() { submission_lock = true; } liverpool->NotifySubmitDone(); + ++frames_submitted; return ORBIS_OK; }