Skip to content

Commit aa72143

Browse files
devtools: patch shader at runtime
1 parent 56d9eb3 commit aa72143

File tree

11 files changed

+171
-60
lines changed

11 files changed

+171
-60
lines changed

src/core/debug_state.cpp

Lines changed: 4 additions & 3 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, std::span<const u32> patch_spv) {
182-
shader_dump_list.emplace_back(name, std::vector<u32>{spv.begin(), spv.end()},
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) {
183+
shader_dump_list.emplace_back(name, module, std::vector<u32>{spv.begin(), spv.end()},
183184
std::vector<u32>{raw_code.begin(), raw_code.end()},
184185
std::vector<u32>{patch_spv.begin(), patch_spv.end()});
185186
}

src/core/debug_state.h

Lines changed: 12 additions & 7 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,26 +76,30 @@ struct FrameDump {
7676

7777
struct ShaderDump {
7878
std::string name;
79+
vk::ShaderModule module;
7980

8081
std::vector<u32> spv;
8182
std::vector<u32> isa;
8283

8384
std::vector<u32> patch_spv;
8485
std::string patch_source{};
8586

87+
bool loaded_data = false;
88+
bool is_patched = false;
8689
std::string cache_spv_disasm{};
8790
std::string cache_isa_disasm{};
8891
std::string cache_patch_disasm{};
8992

90-
ShaderDump(std::string name, std::vector<u32> spv, std::vector<u32> isa,
91-
std::vector<u32> patch_spv)
92-
: name(std::move(name)), spv(std::move(spv)), isa(std::move(isa)),
93+
ShaderDump(std::string name, vk::ShaderModule module, std::vector<u32> spv,
94+
std::vector<u32> isa, std::vector<u32> patch_spv)
95+
: name(std::move(name)), module(module), spv(std::move(spv)), isa(std::move(isa)),
9396
patch_spv(std::move(patch_spv)) {}
9497

9598
ShaderDump(const ShaderDump& other) = delete;
9699
ShaderDump(ShaderDump&& other) noexcept
97-
: name{std::move(other.name)}, spv{std::move(other.spv)}, isa{std::move(other.isa)},
98-
patch_spv{std::move(other.patch_spv)}, patch_source{std::move(other.patch_source)},
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)},
99103
cache_spv_disasm{std::move(other.cache_spv_disasm)},
100104
cache_isa_disasm{std::move(other.cache_isa_disasm)},
101105
cache_patch_disasm{std::move(other.cache_patch_disasm)} {}
@@ -104,6 +108,7 @@ struct ShaderDump {
104108
if (this == &other)
105109
return *this;
106110
name = std::move(other.name);
111+
module = std::move(other.module);
107112
spv = std::move(other.spv);
108113
isa = std::move(other.isa);
109114
patch_spv = std::move(other.patch_spv);
@@ -198,7 +203,7 @@ class DebugStateImpl {
198203
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
199204
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
200205

201-
void CollectShader(const std::string& name, std::span<const u32> spv,
206+
void CollectShader(const std::string& name, vk::ShaderModule module, std::span<const u32> spv,
202207
std::span<const u32> raw_code, std::span<const u32> patch_spv);
203208
};
204209
} // namespace DebugStateType

src/core/devtools/widget/shader_list.cpp

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "imgui/imgui_std.h"
1717
#include "sdl_window.h"
1818
#include "video_core/renderer_vulkan/vk_presenter.h"
19+
#include "video_core/renderer_vulkan/vk_rasterizer.h"
1920

2021
extern std::unique_ptr<Vulkan::Presenter> presenter;
2122

@@ -35,9 +36,20 @@ ShaderList::Selection::~Selection() {
3536
presenter->GetWindow().ReleaseKeyboard();
3637
}
3738

39+
void ShaderList::Selection::ReloadShader(DebugStateType::ShaderDump& value) {
40+
auto& spv = value.is_patched ? value.patch_spv : value.spv;
41+
if (spv.empty()) {
42+
return;
43+
}
44+
auto& cache = presenter->GetRasterizer().GetPipelineCache();
45+
if (const auto m = cache.ReplaceShader(value.module, spv); m) {
46+
value.module = *m;
47+
}
48+
}
49+
3850
bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
39-
if (!loaded_data) {
40-
loaded_data = true;
51+
if (!value.loaded_data) {
52+
value.loaded_data = true;
4153
if (value.cache_isa_disasm.empty()) {
4254
value.cache_isa_disasm = RunDisassembler(Options.disassembler_cli_isa, value.isa);
4355
}
@@ -58,12 +70,11 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
5870
std::string{std::istreambuf_iterator{file}, std::istreambuf_iterator<char>{}};
5971
}
6072

61-
if (value.patch_spv.empty()) { // No patch
62-
showing_patch = false;
73+
value.is_patched = !value.patch_spv.empty();
74+
if (!value.is_patched) { // No patch
6375
isa_editor.SetText(value.cache_isa_disasm);
6476
glsl_editor.SetText(value.cache_spv_disasm);
6577
} else {
66-
showing_patch = true;
6778
isa_editor.SetText(value.cache_patch_disasm);
6879
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
6980
glsl_editor.SetText(value.patch_source);
@@ -73,31 +84,36 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
7384

7485
char name[64];
7586
snprintf(name, sizeof(name), "Shader %s", value.name.c_str());
87+
SetNextWindowSize({450.0f, 600.0f}, ImGuiCond_FirstUseEver);
7688
if (!Begin(name, &open, ImGuiWindowFlags_NoNav)) {
7789
End();
7890
return open;
7991
}
8092

8193
Text("%s", value.name.c_str());
8294
SameLine(0.0f, 7.0f);
83-
if (Checkbox("Enable patch", &showing_patch)) {
84-
if (showing_patch) {
95+
if (Checkbox("Enable patch", &value.is_patched)) {
96+
if (value.is_patched) {
8597
if (value.patch_source.empty()) {
8698
value.patch_source = value.cache_spv_disasm;
8799
}
88100
isa_editor.SetText(value.cache_patch_disasm);
89101
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::SPIRV());
90102
glsl_editor.SetText(value.patch_source);
91103
glsl_editor.SetReadOnly(false);
104+
if (!value.patch_spv.empty()) {
105+
ReloadShader(value);
106+
}
92107
} else {
93108
isa_editor.SetText(value.cache_isa_disasm);
94109
isa_editor.SetLanguageDefinition(TextEditor::LanguageDefinition());
95110
glsl_editor.SetText(value.cache_spv_disasm);
96111
glsl_editor.SetReadOnly(true);
112+
ReloadShader(value);
97113
}
98114
}
99115

100-
if (showing_patch) {
116+
if (value.is_patched) {
101117
if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL",
102118
ImGuiComboFlags_WidthFitPreview)) {
103119
if (Selectable("GLSL")) {
@@ -121,7 +137,7 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
121137
}
122138
}
123139

124-
if (showing_patch) {
140+
if (value.is_patched) {
125141
bool save = false;
126142
bool compile = false;
127143
SameLine(0.0f, 3.0f);
@@ -172,14 +188,15 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
172188
res);
173189
} else {
174190
isa_editor.SetText(value.cache_patch_disasm);
191+
ReloadShader(value);
175192
}
176193
}
177194
}
178195
}
179196
}
180197

181198
if (showing_bin) {
182-
isa_editor.Render(showing_patch ? "SPIRV" : "ISA", GetContentRegionAvail());
199+
isa_editor.Render(value.is_patched ? "SPIRV" : "ISA", GetContentRegionAvail());
183200
} else {
184201
glsl_editor.Render("GLSL", GetContentRegionAvail());
185202
}
@@ -189,6 +206,16 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
189206
}
190207

191208
void ShaderList::Draw() {
209+
for (auto it = open_shaders.begin(); it != open_shaders.end();) {
210+
auto& selection = *it;
211+
auto& shader = DebugState.shader_dump_list[selection.index];
212+
if (!selection.DrawShader(shader)) {
213+
it = open_shaders.erase(it);
214+
} else {
215+
++it;
216+
}
217+
}
218+
192219
SetNextWindowSize({500.0f, 600.0f}, ImGuiCond_FirstUseEver);
193220
if (!Begin("Shader list", &open)) {
194221
End();
@@ -201,20 +228,16 @@ void ShaderList::Draw() {
201228
return;
202229
}
203230

204-
for (auto it = open_shaders.begin(); it != open_shaders.end();) {
205-
auto& selection = *it;
206-
auto& shader = DebugState.shader_dump_list[selection.index];
207-
if (!selection.DrawShader(shader)) {
208-
it = open_shaders.erase(it);
209-
} else {
210-
++it;
211-
}
212-
}
213-
214231
auto width = GetContentRegionAvail().x;
215232
int i = 0;
216233
for (const auto& shader : DebugState.shader_dump_list) {
217-
if (ButtonEx(shader.name.c_str(), {width, 20.0f}, ImGuiButtonFlags_NoHoveredOnFocus)) {
234+
char name[128];
235+
if (shader.patch_spv.empty()) {
236+
snprintf(name, sizeof(name), "%s", shader.name.c_str());
237+
} else {
238+
snprintf(name, sizeof(name), "%s (PATCH)", shader.name.c_str());
239+
}
240+
if (ButtonEx(name, {width, 20.0f}, ImGuiButtonFlags_NoHoveredOnFocus)) {
218241
open_shaders.emplace_back(i);
219242
}
220243
i++;

src/core/devtools/widget/shader_list.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ namespace Core::Devtools::Widget {
1212

1313
class ShaderList {
1414
struct Selection {
15+
explicit Selection(int index);
16+
~Selection();
17+
18+
void ReloadShader(DebugStateType::ShaderDump& value);
19+
20+
bool DrawShader(DebugStateType::ShaderDump& value);
21+
1522
int index;
1623
TextEditor isa_editor{};
1724
TextEditor glsl_editor{};
1825
bool open = true;
19-
bool loaded_data = false;
2026
bool showing_bin = false;
21-
bool showing_patch = false;
2227

2328
std::filesystem::path patch_path;
2429
std::filesystem::path patch_bin_path;
25-
26-
explicit Selection(int index);
27-
~Selection();
28-
29-
bool DrawShader(DebugStateType::ShaderDump& value);
3030
};
3131

3232
std::vector<Selection> open_shaders{};

src/video_core/renderer_vulkan/vk_compute_pipeline.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Vulkan {
1313

1414
ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler_,
1515
DescriptorHeap& desc_heap_, vk::PipelineCache pipeline_cache,
16-
u64 compute_key_, const Shader::Info& info_,
16+
ComputePipelineKey compute_key_, const Shader::Info& info_,
1717
vk::ShaderModule module)
1818
: Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache, true}, compute_key{compute_key_} {
1919
auto& info = stages[int(Shader::Stage::Compute)];

src/video_core/renderer_vulkan/vk_compute_pipeline.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,33 @@ class Instance;
1717
class Scheduler;
1818
class DescriptorHeap;
1919

20+
struct ComputePipelineKey {
21+
size_t value;
22+
23+
friend bool operator==(const ComputePipelineKey& lhs, const ComputePipelineKey& rhs) {
24+
return lhs.value == rhs.value;
25+
}
26+
friend bool operator!=(const ComputePipelineKey& lhs, const ComputePipelineKey& rhs) {
27+
return !(lhs == rhs);
28+
}
29+
};
30+
2031
class ComputePipeline : public Pipeline {
2132
public:
2233
ComputePipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
23-
vk::PipelineCache pipeline_cache, u64 compute_key, const Shader::Info& info,
24-
vk::ShaderModule module);
34+
vk::PipelineCache pipeline_cache, ComputePipelineKey compute_key,
35+
const Shader::Info& info, vk::ShaderModule module);
2536
~ComputePipeline();
2637

2738
private:
28-
u64 compute_key;
39+
ComputePipelineKey compute_key;
2940
};
3041

3142
} // namespace Vulkan
43+
44+
template <>
45+
struct std::hash<Vulkan::ComputePipelineKey> {
46+
std::size_t operator()(const Vulkan::ComputePipelineKey& key) const noexcept {
47+
return std::hash<size_t>{}(key.value);
48+
}
49+
};

src/video_core/renderer_vulkan/vk_graphics_pipeline.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
22
// SPDX-License-Identifier: GPL-2.0-or-later
33

4+
#pragma once
5+
46
#include <xxhash.h>
57

68
#include "common/types.h"

0 commit comments

Comments
 (0)