Skip to content

Commit f1b23c6

Browse files
Devtools - Shader editing (shadps4-emu#1705)
* devtools: shader editing and compiling * devtools: patch shader at runtime * devtools: shader editing load patch even with config disabled
1 parent f623613 commit f1b23c6

19 files changed

+465
-102
lines changed

src/common/string_util.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ std::vector<std::string> SplitString(const std::string& str, char delimiter) {
3737
return output;
3838
}
3939

40+
std::string_view U8stringToString(std::u8string_view u8str) {
41+
return std::string_view{reinterpret_cast<const char*>(u8str.data()), u8str.size()};
42+
}
43+
4044
#ifdef _WIN32
4145
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
4246
const auto size =

src/common/string_util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ void ToLowerInPlace(std::string& str);
1616

1717
std::vector<std::string> SplitString(const std::string& str, char delimiter);
1818

19+
std::string_view U8stringToString(std::u8string_view u8str);
20+
1921
#ifdef _WIN32
2022
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
2123
[[nodiscard]] std::wstring UTF8ToUTF16W(std::string_view str);

src/core/debug_state.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,10 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
177177
}
178178
}
179179

180-
void DebugStateImpl::CollectShader(const std::string& name, std::span<const u32> spv,
181-
std::span<const u32> raw_code) {
182-
shader_dump_list.emplace_back(name, std::vector<u32>{spv.begin(), spv.end()},
183-
std::vector<u32>{raw_code.begin(), raw_code.end()});
184-
std::ranges::sort(shader_dump_list, {}, &ShaderDump::name);
180+
void DebugStateImpl::CollectShader(const std::string& name, vk::ShaderModule module,
181+
std::span<const u32> spv, std::span<const u32> raw_code,
182+
std::span<const u32> patch_spv, bool is_patched) {
183+
shader_dump_list.emplace_back(name, module, std::vector<u32>{spv.begin(), spv.end()},
184+
std::vector<u32>{raw_code.begin(), raw_code.end()},
185+
std::vector<u32>{patch_spv.begin(), patch_spv.end()}, is_patched);
185186
}

src/core/debug_state.h

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
#include "common/types.h"
1414
#include "video_core/amdgpu/liverpool.h"
15-
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
15+
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
1616

1717
#ifdef _WIN32
1818
#ifndef WIN32_LEAN_AND_MEAN
@@ -76,29 +76,46 @@ struct FrameDump {
7676

7777
struct ShaderDump {
7878
std::string name;
79+
vk::ShaderModule module;
80+
7981
std::vector<u32> spv;
80-
std::vector<u32> raw_code;
82+
std::vector<u32> isa;
83+
84+
std::vector<u32> patch_spv;
85+
std::string patch_source{};
8186

87+
bool loaded_data = false;
88+
bool is_patched = false;
8289
std::string cache_spv_disasm{};
83-
std::string cache_raw_disasm{};
90+
std::string cache_isa_disasm{};
91+
std::string cache_patch_disasm{};
8492

85-
ShaderDump(std::string name, std::vector<u32> spv, std::vector<u32> raw_code)
86-
: name(std::move(name)), spv(std::move(spv)), raw_code(std::move(raw_code)) {}
93+
ShaderDump(std::string name, vk::ShaderModule module, std::vector<u32> spv,
94+
std::vector<u32> isa, std::vector<u32> patch_spv, bool is_patched)
95+
: name(std::move(name)), module(module), spv(std::move(spv)), isa(std::move(isa)),
96+
patch_spv(std::move(patch_spv)), is_patched(is_patched) {}
8797

8898
ShaderDump(const ShaderDump& other) = delete;
8999
ShaderDump(ShaderDump&& other) noexcept
90-
: name{std::move(other.name)}, spv{std::move(other.spv)},
91-
raw_code{std::move(other.raw_code)}, cache_spv_disasm{std::move(other.cache_spv_disasm)},
92-
cache_raw_disasm{std::move(other.cache_raw_disasm)} {}
100+
: name{std::move(other.name)}, module{std::move(other.module)}, spv{std::move(other.spv)},
101+
isa{std::move(other.isa)}, patch_spv{std::move(other.patch_spv)},
102+
patch_source{std::move(other.patch_source)},
103+
cache_spv_disasm{std::move(other.cache_spv_disasm)},
104+
cache_isa_disasm{std::move(other.cache_isa_disasm)},
105+
cache_patch_disasm{std::move(other.cache_patch_disasm)} {}
93106
ShaderDump& operator=(const ShaderDump& other) = delete;
94107
ShaderDump& operator=(ShaderDump&& other) noexcept {
95108
if (this == &other)
96109
return *this;
97110
name = std::move(other.name);
111+
module = std::move(other.module);
98112
spv = std::move(other.spv);
99-
raw_code = std::move(other.raw_code);
113+
isa = std::move(other.isa);
114+
patch_spv = std::move(other.patch_spv);
115+
patch_source = std::move(other.patch_source);
100116
cache_spv_disasm = std::move(other.cache_spv_disasm);
101-
cache_raw_disasm = std::move(other.cache_raw_disasm);
117+
cache_isa_disasm = std::move(other.cache_isa_disasm);
118+
cache_patch_disasm = std::move(other.cache_patch_disasm);
102119
return *this;
103120
}
104121
};
@@ -186,8 +203,9 @@ class DebugStateImpl {
186203
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
187204
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
188205

189-
void CollectShader(const std::string& name, std::span<const u32> spv,
190-
std::span<const u32> raw_code);
206+
void CollectShader(const std::string& name, vk::ShaderModule module, std::span<const u32> spv,
207+
std::span<const u32> raw_code, std::span<const u32> patch_spv,
208+
bool is_patched);
191209
};
192210
} // namespace DebugStateType
193211

src/core/devtools/options.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ struct ImGuiTextBuffer;
1010
namespace Core::Devtools {
1111

1212
struct TOptions {
13-
std::string disassembler_cli_isa{"clrxdisasm --raw \"{src}\""};
14-
std::string disassembler_cli_spv{"spirv-cross -V \"{src}\""};
13+
std::string disassembler_cli_isa{"clrxdisasm --raw {src}"};
14+
std::string disassembler_cli_spv{"spirv-cross -V {src}"};
1515
bool frame_dump_render_on_collapse{false};
1616
};
1717

src/core/devtools/widget/common.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
117117
inline std::optional<std::string> exec_cli(const char* cli) {
118118
std::array<char, 64> buffer{};
119119
std::string output;
120-
const auto f = popen(cli, "r");
120+
const auto f = popen(cli, "rt");
121121
if (!f) {
122122
pclose(f);
123123
return {};
@@ -129,31 +129,44 @@ inline std::optional<std::string> exec_cli(const char* cli) {
129129
return output;
130130
}
131131

132-
inline std::string RunDisassembler(const std::string& disassembler_cli,
133-
const std::vector<u32>& shader_code) {
132+
template <typename T>
133+
inline std::string RunDisassembler(const std::string& disassembler_cli, const T& shader_code,
134+
bool* success = nullptr) {
134135
std::string shader_dis;
135136

136137
if (disassembler_cli.empty()) {
137138
shader_dis = "No disassembler set";
139+
if (success) {
140+
*success = false;
141+
}
138142
} else {
139143
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
140144

141145
constexpr std::string_view src_arg = "{src}";
142-
std::string cli = disassembler_cli;
146+
std::string cli = disassembler_cli + " 2>&1";
143147
const auto pos = cli.find(src_arg);
144148
if (pos == std::string::npos) {
145-
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument\n" +
146-
disassembler_cli);
149+
shader_dis = "Disassembler CLI does not contain {src} argument";
150+
if (success) {
151+
*success = false;
152+
}
147153
} else {
148154
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
149155
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
150156
file.Write(shader_code);
151157
file.Close();
152158

153159
auto result = exec_cli(cli.c_str());
154-
shader_dis = result.value_or("Could not disassemble shader");
155-
if (shader_dis.empty()) {
156-
shader_dis = "Disassembly empty or failed";
160+
if (result) {
161+
shader_dis = result.value();
162+
if (success) {
163+
*success = true;
164+
}
165+
} else {
166+
if (success) {
167+
*success = false;
168+
}
169+
shader_dis = "Could not disassemble shader";
157170
}
158171

159172
std::filesystem::remove(bin_path);

0 commit comments

Comments
 (0)