mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-30 18:18:32 +00:00
More devtools stuff (#1637)
* devtools: memory map viewer * devtools: batch highlight only for non-group viewer * devtools: fix not showing entire user data * devtools: shader debug viewer * devtools: add more reg naming
This commit is contained in:
parent
f658fc58d1
commit
0835dc71b3
CMakeLists.txt
src
common
core
video_core/renderer_vulkan
|
@ -435,10 +435,14 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||||
src/core/devtools/widget/frame_graph.cpp
|
src/core/devtools/widget/frame_graph.cpp
|
||||||
src/core/devtools/widget/frame_graph.h
|
src/core/devtools/widget/frame_graph.h
|
||||||
src/core/devtools/widget/imgui_memory_editor.h
|
src/core/devtools/widget/imgui_memory_editor.h
|
||||||
|
src/core/devtools/widget/memory_map.cpp
|
||||||
|
src/core/devtools/widget/memory_map.h
|
||||||
src/core/devtools/widget/reg_popup.cpp
|
src/core/devtools/widget/reg_popup.cpp
|
||||||
src/core/devtools/widget/reg_popup.h
|
src/core/devtools/widget/reg_popup.h
|
||||||
src/core/devtools/widget/reg_view.cpp
|
src/core/devtools/widget/reg_view.cpp
|
||||||
src/core/devtools/widget/reg_view.h
|
src/core/devtools/widget/reg_view.h
|
||||||
|
src/core/devtools/widget/shader_list.cpp
|
||||||
|
src/core/devtools/widget/shader_list.h
|
||||||
src/core/devtools/widget/text_editor.cpp
|
src/core/devtools/widget/text_editor.cpp
|
||||||
src/core/devtools/widget/text_editor.h
|
src/core/devtools/widget/text_editor.h
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,6 +47,7 @@ static std::string backButtonBehavior = "left";
|
||||||
static bool useSpecialPad = false;
|
static bool useSpecialPad = false;
|
||||||
static int specialPadClass = 1;
|
static int specialPadClass = 1;
|
||||||
static bool isDebugDump = false;
|
static bool isDebugDump = false;
|
||||||
|
static bool isShaderDebug = false;
|
||||||
static bool isShowSplash = false;
|
static bool isShowSplash = false;
|
||||||
static bool isAutoUpdate = false;
|
static bool isAutoUpdate = false;
|
||||||
static bool isNullGpu = false;
|
static bool isNullGpu = false;
|
||||||
|
@ -159,6 +160,10 @@ bool debugDump() {
|
||||||
return isDebugDump;
|
return isDebugDump;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool collectShadersForDebug() {
|
||||||
|
return isShaderDebug;
|
||||||
|
}
|
||||||
|
|
||||||
bool showSplash() {
|
bool showSplash() {
|
||||||
return isShowSplash;
|
return isShowSplash;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +240,10 @@ void setDebugDump(bool enable) {
|
||||||
isDebugDump = enable;
|
isDebugDump = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCollectShaderForDebug(bool enable) {
|
||||||
|
isShaderDebug = enable;
|
||||||
|
}
|
||||||
|
|
||||||
void setShowSplash(bool enable) {
|
void setShowSplash(bool enable) {
|
||||||
isShowSplash = enable;
|
isShowSplash = enable;
|
||||||
}
|
}
|
||||||
|
@ -571,6 +580,7 @@ void load(const std::filesystem::path& path) {
|
||||||
const toml::value& debug = data.at("Debug");
|
const toml::value& debug = data.at("Debug");
|
||||||
|
|
||||||
isDebugDump = toml::find_or<bool>(debug, "DebugDump", false);
|
isDebugDump = toml::find_or<bool>(debug, "DebugDump", false);
|
||||||
|
isShaderDebug = toml::find_or<bool>(debug, "CollectShader", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.contains("GUI")) {
|
if (data.contains("GUI")) {
|
||||||
|
@ -662,6 +672,7 @@ void save(const std::filesystem::path& path) {
|
||||||
data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
|
data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
|
||||||
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
|
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
|
||||||
data["Debug"]["DebugDump"] = isDebugDump;
|
data["Debug"]["DebugDump"] = isDebugDump;
|
||||||
|
data["Debug"]["CollectShader"] = isShaderDebug;
|
||||||
data["GUI"]["theme"] = mw_themes;
|
data["GUI"]["theme"] = mw_themes;
|
||||||
data["GUI"]["iconSize"] = m_icon_size;
|
data["GUI"]["iconSize"] = m_icon_size;
|
||||||
data["GUI"]["sliderPos"] = m_slider_pos;
|
data["GUI"]["sliderPos"] = m_slider_pos;
|
||||||
|
@ -717,6 +728,7 @@ void setDefaultValues() {
|
||||||
useSpecialPad = false;
|
useSpecialPad = false;
|
||||||
specialPadClass = 1;
|
specialPadClass = 1;
|
||||||
isDebugDump = false;
|
isDebugDump = false;
|
||||||
|
isShaderDebug = false;
|
||||||
isShowSplash = false;
|
isShowSplash = false;
|
||||||
isAutoUpdate = false;
|
isAutoUpdate = false;
|
||||||
isNullGpu = false;
|
isNullGpu = false;
|
||||||
|
|
|
@ -37,6 +37,7 @@ u32 getScreenHeight();
|
||||||
s32 getGpuId();
|
s32 getGpuId();
|
||||||
|
|
||||||
bool debugDump();
|
bool debugDump();
|
||||||
|
bool collectShadersForDebug();
|
||||||
bool showSplash();
|
bool showSplash();
|
||||||
bool autoUpdate();
|
bool autoUpdate();
|
||||||
bool nullGpu();
|
bool nullGpu();
|
||||||
|
@ -47,6 +48,7 @@ bool isRdocEnabled();
|
||||||
u32 vblankDiv();
|
u32 vblankDiv();
|
||||||
|
|
||||||
void setDebugDump(bool enable);
|
void setDebugDump(bool enable);
|
||||||
|
void setCollectShaderForDebug(bool enable);
|
||||||
void setShowSplash(bool enable);
|
void setShowSplash(bool enable);
|
||||||
void setAutoUpdate(bool enable);
|
void setAutoUpdate(bool enable);
|
||||||
void setNullGpu(bool enable);
|
void setNullGpu(bool enable);
|
||||||
|
|
|
@ -157,7 +157,7 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
if (is_compute) {
|
if (is_compute) {
|
||||||
dump.is_compute = true;
|
dump.is_compute = true;
|
||||||
const auto& cs = dump.regs.cs_program;
|
const auto& cs = dump.regs.cs_program;
|
||||||
dump.cs_data = ComputerShaderDump{
|
dump.cs_data = PipelineComputerProgramDump{
|
||||||
.cs_program = cs,
|
.cs_program = cs,
|
||||||
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||||
};
|
};
|
||||||
|
@ -167,7 +167,7 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
auto stage = regs.ProgramForStage(i);
|
auto stage = regs.ProgramForStage(i);
|
||||||
if (stage->address_lo != 0) {
|
if (stage->address_lo != 0) {
|
||||||
auto code = stage->Code();
|
auto code = stage->Code();
|
||||||
dump.stages[i] = ShaderDump{
|
dump.stages[i] = PipelineShaderProgramDump{
|
||||||
.user_data = *stage,
|
.user_data = *stage,
|
||||||
.code = std::vector<u32>{code.begin(), code.end()},
|
.code = std::vector<u32>{code.begin(), code.end()},
|
||||||
};
|
};
|
||||||
|
@ -176,3 +176,10 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::CollectShader(const std::string& name, std::span<const u32> spv,
|
||||||
|
std::span<const u32> raw_code) {
|
||||||
|
shader_dump_list.emplace_back(name, std::vector<u32>{spv.begin(), spv.end()},
|
||||||
|
std::vector<u32>{raw_code.begin(), raw_code.end()});
|
||||||
|
std::ranges::sort(shader_dump_list, {}, &ShaderDump::name);
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@ namespace Core::Devtools {
|
||||||
class Layer;
|
class Layer;
|
||||||
namespace Widget {
|
namespace Widget {
|
||||||
class FrameGraph;
|
class FrameGraph;
|
||||||
}
|
class ShaderList;
|
||||||
|
} // namespace Widget
|
||||||
} // namespace Core::Devtools
|
} // namespace Core::Devtools
|
||||||
|
|
||||||
namespace DebugStateType {
|
namespace DebugStateType {
|
||||||
|
@ -49,12 +50,12 @@ struct QueueDump {
|
||||||
uintptr_t base_addr;
|
uintptr_t base_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShaderDump {
|
struct PipelineShaderProgramDump {
|
||||||
Vulkan::Liverpool::ShaderProgram user_data{};
|
Vulkan::Liverpool::ShaderProgram user_data{};
|
||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ComputerShaderDump {
|
struct PipelineComputerProgramDump {
|
||||||
Vulkan::Liverpool::ComputeProgram cs_program{};
|
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
@ -63,8 +64,8 @@ struct RegDump {
|
||||||
bool is_compute{false};
|
bool is_compute{false};
|
||||||
static constexpr size_t MaxShaderStages = 5;
|
static constexpr size_t MaxShaderStages = 5;
|
||||||
Vulkan::Liverpool::Regs regs{};
|
Vulkan::Liverpool::Regs regs{};
|
||||||
std::array<ShaderDump, MaxShaderStages> stages{};
|
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
|
||||||
ComputerShaderDump cs_data{};
|
PipelineComputerProgramDump cs_data{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameDump {
|
struct FrameDump {
|
||||||
|
@ -73,9 +74,41 @@ struct FrameDump {
|
||||||
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ShaderDump {
|
||||||
|
std::string name;
|
||||||
|
std::vector<u32> spv;
|
||||||
|
std::vector<u32> raw_code;
|
||||||
|
|
||||||
|
std::string cache_spv_disasm{};
|
||||||
|
std::string cache_raw_disasm{};
|
||||||
|
|
||||||
|
ShaderDump(std::string name, std::vector<u32> spv, std::vector<u32> raw_code)
|
||||||
|
: name(std::move(name)), spv(std::move(spv)), raw_code(std::move(raw_code)) {}
|
||||||
|
|
||||||
|
ShaderDump(const ShaderDump& other) = delete;
|
||||||
|
ShaderDump(ShaderDump&& other) noexcept
|
||||||
|
: name{std::move(other.name)}, spv{std::move(other.spv)},
|
||||||
|
raw_code{std::move(other.raw_code)}, cache_spv_disasm{std::move(other.cache_spv_disasm)},
|
||||||
|
cache_raw_disasm{std::move(other.cache_raw_disasm)} {}
|
||||||
|
ShaderDump& operator=(const ShaderDump& other) = delete;
|
||||||
|
ShaderDump& operator=(ShaderDump&& other) noexcept {
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
name = std::move(other.name);
|
||||||
|
spv = std::move(other.spv);
|
||||||
|
raw_code = std::move(other.raw_code);
|
||||||
|
cache_spv_disasm = std::move(other.cache_spv_disasm);
|
||||||
|
cache_raw_disasm = std::move(other.cache_raw_disasm);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DebugStateImpl {
|
class DebugStateImpl {
|
||||||
friend class Core::Devtools::Layer;
|
friend class Core::Devtools::Layer;
|
||||||
friend class Core::Devtools::Widget::FrameGraph;
|
friend class Core::Devtools::Widget::FrameGraph;
|
||||||
|
friend class Core::Devtools::Widget::ShaderList;
|
||||||
|
|
||||||
|
std::queue<std::string> debug_message_popup;
|
||||||
|
|
||||||
std::mutex guest_threads_mutex{};
|
std::mutex guest_threads_mutex{};
|
||||||
std::vector<ThreadID> guest_threads{};
|
std::vector<ThreadID> guest_threads{};
|
||||||
|
@ -94,7 +127,7 @@ class DebugStateImpl {
|
||||||
std::shared_mutex frame_dump_list_mutex;
|
std::shared_mutex frame_dump_list_mutex;
|
||||||
std::vector<FrameDump> frame_dump_list{};
|
std::vector<FrameDump> frame_dump_list{};
|
||||||
|
|
||||||
std::queue<std::string> debug_message_popup;
|
std::vector<ShaderDump> shader_dump_list{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void ShowDebugMessage(std::string message) {
|
void ShowDebugMessage(std::string message) {
|
||||||
|
@ -152,6 +185,9 @@ public:
|
||||||
|
|
||||||
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
||||||
|
|
||||||
|
void CollectShader(const std::string& name, std::span<const u32> spv,
|
||||||
|
std::span<const u32> raw_code);
|
||||||
};
|
};
|
||||||
} // namespace DebugStateType
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,16 @@ const char* GetContextRegName(u32 reg_offset) {
|
||||||
return "mmSPI_PS_INPUT_CNTL_2";
|
return "mmSPI_PS_INPUT_CNTL_2";
|
||||||
case mmSPI_PS_INPUT_CNTL_3:
|
case mmSPI_PS_INPUT_CNTL_3:
|
||||||
return "mmSPI_PS_INPUT_CNTL_3";
|
return "mmSPI_PS_INPUT_CNTL_3";
|
||||||
|
case mmPA_SU_POLY_OFFSET_FRONT_SCALE:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_FRONT_SCALE";
|
||||||
|
case mmPA_SU_POLY_OFFSET_FRONT_OFFSET:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_FRONT_OFFSET";
|
||||||
|
case mmPA_SU_POLY_OFFSET_BACK_SCALE:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_BACK_SCALE";
|
||||||
|
case mmPA_SU_POLY_OFFSET_BACK_OFFSET:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_BACK_OFFSET";
|
||||||
|
case mmPA_SU_POLY_OFFSET_CLAMP:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_CLAMP";
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "layer.h"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
@ -9,11 +11,12 @@
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
#include "imgui/imgui_std.h"
|
#include "imgui/imgui_std.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "layer.h"
|
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "video_core/renderer_vulkan/vk_presenter.h"
|
#include "video_core/renderer_vulkan/vk_presenter.h"
|
||||||
#include "widget/frame_dump.h"
|
#include "widget/frame_dump.h"
|
||||||
#include "widget/frame_graph.h"
|
#include "widget/frame_graph.h"
|
||||||
|
#include "widget/memory_map.h"
|
||||||
|
#include "widget/shader_list.h"
|
||||||
|
|
||||||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||||
|
|
||||||
|
@ -35,6 +38,9 @@ static float debug_popup_timing = 3.0f;
|
||||||
|
|
||||||
static bool just_opened_options = false;
|
static bool just_opened_options = false;
|
||||||
|
|
||||||
|
static Widget::MemoryMapViewer memory_map;
|
||||||
|
static Widget::ShaderList shader_list;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static std::string help_text =
|
static std::string help_text =
|
||||||
#include "help.txt"
|
#include "help.txt"
|
||||||
|
@ -63,6 +69,7 @@ void L::DrawMenuBar() {
|
||||||
}
|
}
|
||||||
if (BeginMenu("GPU Tools")) {
|
if (BeginMenu("GPU Tools")) {
|
||||||
MenuItem("Show frame info", nullptr, &frame_graph.is_open);
|
MenuItem("Show frame info", nullptr, &frame_graph.is_open);
|
||||||
|
MenuItem("Show loaded shaders", nullptr, &shader_list.open);
|
||||||
if (BeginMenu("Dump frames")) {
|
if (BeginMenu("Dump frames")) {
|
||||||
SliderInt("Count", &dump_frame_count, 1, 5);
|
SliderInt("Count", &dump_frame_count, 1, 5);
|
||||||
if (MenuItem("Dump", "Ctrl+Alt+F9", nullptr, !DebugState.DumpingCurrentFrame())) {
|
if (MenuItem("Dump", "Ctrl+Alt+F9", nullptr, !DebugState.DumpingCurrentFrame())) {
|
||||||
|
@ -81,6 +88,12 @@ void L::DrawMenuBar() {
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
if (BeginMenu("Debug")) {
|
||||||
|
if (MenuItem("Memory map")) {
|
||||||
|
memory_map.open = true;
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,19 +188,29 @@ void L::DrawAdvanced() {
|
||||||
bool close_popup_options = true;
|
bool close_popup_options = true;
|
||||||
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
|
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
|
||||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) {
|
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
static char disassembly_cli[512];
|
static char disassembler_cli_isa[512];
|
||||||
|
static char disassembler_cli_spv[512];
|
||||||
static bool frame_dump_render_on_collapse;
|
static bool frame_dump_render_on_collapse;
|
||||||
|
|
||||||
if (just_opened_options) {
|
if (just_opened_options) {
|
||||||
just_opened_options = false;
|
just_opened_options = false;
|
||||||
auto s = Options.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
|
auto s = Options.disassembler_cli_isa.copy(disassembler_cli_isa,
|
||||||
disassembly_cli[s] = '\0';
|
sizeof(disassembler_cli_isa) - 1);
|
||||||
|
disassembler_cli_isa[s] = '\0';
|
||||||
|
s = Options.disassembler_cli_spv.copy(disassembler_cli_spv,
|
||||||
|
sizeof(disassembler_cli_spv) - 1);
|
||||||
|
disassembler_cli_spv[s] = '\0';
|
||||||
frame_dump_render_on_collapse = Options.frame_dump_render_on_collapse;
|
frame_dump_render_on_collapse = Options.frame_dump_render_on_collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
InputText("Shader isa disassembler: ", disassembler_cli_isa, sizeof(disassembler_cli_isa));
|
||||||
if (IsItemHovered()) {
|
if (IsItemHovered()) {
|
||||||
SetTooltip(R"(Command to disassemble shaders. Example "dis.exe" --raw "{src}")");
|
SetTooltip(R"(Command to disassemble shaders. Example: dis.exe --raw "{src}")");
|
||||||
|
}
|
||||||
|
InputText("Shader SPIRV disassembler: ", disassembler_cli_spv,
|
||||||
|
sizeof(disassembler_cli_spv));
|
||||||
|
if (IsItemHovered()) {
|
||||||
|
SetTooltip(R"(Command to disassemble shaders. Example: spirv-cross -V "{src}")");
|
||||||
}
|
}
|
||||||
Checkbox("Show frame dump popups even when collapsed", &frame_dump_render_on_collapse);
|
Checkbox("Show frame dump popups even when collapsed", &frame_dump_render_on_collapse);
|
||||||
if (IsItemHovered()) {
|
if (IsItemHovered()) {
|
||||||
|
@ -196,7 +219,8 @@ void L::DrawAdvanced() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Button("Save")) {
|
if (Button("Save")) {
|
||||||
Options.disassembly_cli = disassembly_cli;
|
Options.disassembler_cli_isa = disassembler_cli_isa;
|
||||||
|
Options.disassembler_cli_spv = disassembler_cli_spv;
|
||||||
Options.frame_dump_render_on_collapse = frame_dump_render_on_collapse;
|
Options.frame_dump_render_on_collapse = frame_dump_render_on_collapse;
|
||||||
SaveIniSettingsToDisk(io.IniFilename);
|
SaveIniSettingsToDisk(io.IniFilename);
|
||||||
CloseCurrentPopup();
|
CloseCurrentPopup();
|
||||||
|
@ -219,6 +243,13 @@ void L::DrawAdvanced() {
|
||||||
|
|
||||||
EndPopup();
|
EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memory_map.open) {
|
||||||
|
memory_map.Draw();
|
||||||
|
}
|
||||||
|
if (shader_list.open) {
|
||||||
|
shader_list.Draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawSimple() {
|
void L::DrawSimple() {
|
||||||
|
|
|
@ -12,8 +12,12 @@ TOptions Options;
|
||||||
void LoadOptionsConfig(const char* line) {
|
void LoadOptionsConfig(const char* line) {
|
||||||
char str[512];
|
char str[512];
|
||||||
int i;
|
int i;
|
||||||
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
|
||||||
Options.disassembly_cli = str;
|
Options.disassembler_cli_isa = str;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "disassembler_cli_spv=%511[^\n]", str) == 1) {
|
||||||
|
Options.disassembler_cli_spv = str;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sscanf(line, "frame_dump_render_on_collapse=%d", &i) == 1) {
|
if (sscanf(line, "frame_dump_render_on_collapse=%d", &i) == 1) {
|
||||||
|
@ -23,7 +27,8 @@ void LoadOptionsConfig(const char* line) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||||
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
|
||||||
|
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
|
||||||
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
|
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ struct ImGuiTextBuffer;
|
||||||
namespace Core::Devtools {
|
namespace Core::Devtools {
|
||||||
|
|
||||||
struct TOptions {
|
struct TOptions {
|
||||||
std::string disassembly_cli{};
|
std::string disassembler_cli_isa{"clrxdisasm --raw \"{src}\""};
|
||||||
|
std::string disassembler_cli_spv{"spirv-cross -V \"{src}\""};
|
||||||
bool frame_dump_render_on_collapse{false};
|
bool frame_dump_render_on_collapse{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1306,7 +1306,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||||
if (batch.id == batch_bp) { // highlight batch at breakpoint
|
if (batch.id == batch_bp) { // highlight batch at breakpoint
|
||||||
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
||||||
}
|
}
|
||||||
if (batch.id == highlight_batch) {
|
if (batch.id == highlight_batch && !group_batches) {
|
||||||
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,7 +1459,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch.id == highlight_batch) {
|
if (batch.id == highlight_batch && !group_batches) {
|
||||||
PopStyleColor();
|
PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
@ -10,9 +11,16 @@
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
|
#include "common/io_file.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
#include "video_core/amdgpu/pm4_opcodes.h"
|
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define popen _popen
|
||||||
|
#define pclose _pclose
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
/*
|
/*
|
||||||
* Generic PM4 header
|
* Generic PM4 header
|
||||||
|
@ -106,4 +114,53 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::optional<std::string> exec_cli(const char* cli) {
|
||||||
|
std::array<char, 64> buffer{};
|
||||||
|
std::string output;
|
||||||
|
const auto f = popen(cli, "r");
|
||||||
|
if (!f) {
|
||||||
|
pclose(f);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
while (fgets(buffer.data(), buffer.size(), f)) {
|
||||||
|
output += buffer.data();
|
||||||
|
}
|
||||||
|
pclose(f);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string RunDisassembler(const std::string& disassembler_cli,
|
||||||
|
const std::vector<u32>& shader_code) {
|
||||||
|
std::string shader_dis;
|
||||||
|
|
||||||
|
if (disassembler_cli.empty()) {
|
||||||
|
shader_dis = "No disassembler set";
|
||||||
|
} else {
|
||||||
|
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
||||||
|
|
||||||
|
constexpr std::string_view src_arg = "{src}";
|
||||||
|
std::string cli = disassembler_cli;
|
||||||
|
const auto pos = cli.find(src_arg);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument\n" +
|
||||||
|
disassembler_cli);
|
||||||
|
} else {
|
||||||
|
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||||
|
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||||
|
file.Write(shader_code);
|
||||||
|
file.Close();
|
||||||
|
|
||||||
|
auto result = exec_cli(cli.c_str());
|
||||||
|
shader_dis = result.value_or("Could not disassemble shader");
|
||||||
|
if (shader_dis.empty()) {
|
||||||
|
shader_dis = "Disassembly empty or failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::remove(bin_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader_dis;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
134
src/core/devtools/widget/memory_map.cpp
Normal file
134
src/core/devtools/widget/memory_map.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
#include "memory_map.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
bool MemoryMapViewer::Iterator::DrawLine() {
|
||||||
|
if (is_vma) {
|
||||||
|
if (vma.it == vma.end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto m = vma.it->second;
|
||||||
|
if (m.type == VMAType::Free) {
|
||||||
|
++vma.it;
|
||||||
|
return DrawLine();
|
||||||
|
}
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%zX", m.base);
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%zX", m.size);
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%s", magic_enum::enum_name(m.type).data());
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%s", magic_enum::enum_name(m.prot).data());
|
||||||
|
TableNextColumn();
|
||||||
|
if (m.is_exec) {
|
||||||
|
Text("X");
|
||||||
|
}
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%s", m.name.c_str());
|
||||||
|
++vma.it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (dmem.it == dmem.end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto m = dmem.it->second;
|
||||||
|
if (m.is_free) {
|
||||||
|
++dmem.it;
|
||||||
|
return DrawLine();
|
||||||
|
}
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%llX", m.base);
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%llX", m.size);
|
||||||
|
TableNextColumn();
|
||||||
|
auto type = static_cast<::Libraries::Kernel::MemoryTypes>(m.memory_type);
|
||||||
|
Text("%s", magic_enum::enum_name(type).data());
|
||||||
|
TableNextColumn();
|
||||||
|
Text("%d", m.is_pooled);
|
||||||
|
++dmem.it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryMapViewer::Draw() {
|
||||||
|
SetNextWindowSize({600.0f, 500.0f}, ImGuiCond_FirstUseEver);
|
||||||
|
if (!Begin("Memory map", &open)) {
|
||||||
|
End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem = Memory::Instance();
|
||||||
|
std::scoped_lock lck{mem->mutex};
|
||||||
|
|
||||||
|
{
|
||||||
|
bool next_showing_vma = showing_vma;
|
||||||
|
if (showing_vma) {
|
||||||
|
PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
|
}
|
||||||
|
if (Button("VMem")) {
|
||||||
|
next_showing_vma = true;
|
||||||
|
}
|
||||||
|
if (showing_vma) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
SameLine();
|
||||||
|
if (!showing_vma) {
|
||||||
|
PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
|
}
|
||||||
|
if (Button("DMem")) {
|
||||||
|
next_showing_vma = false;
|
||||||
|
}
|
||||||
|
if (!showing_vma) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
showing_vma = next_showing_vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator it{};
|
||||||
|
if (showing_vma) {
|
||||||
|
it.is_vma = true;
|
||||||
|
it.vma.it = mem->vma_map.begin();
|
||||||
|
it.vma.end = mem->vma_map.end();
|
||||||
|
} else {
|
||||||
|
it.is_vma = false;
|
||||||
|
it.dmem.it = mem->dmem_map.begin();
|
||||||
|
it.dmem.end = mem->dmem_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BeginTable("memory_view_table", showing_vma ? 6 : 4,
|
||||||
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg |
|
||||||
|
ImGuiTableFlags_SizingFixedFit)) {
|
||||||
|
if (showing_vma) {
|
||||||
|
TableSetupColumn("Address");
|
||||||
|
TableSetupColumn("Size");
|
||||||
|
TableSetupColumn("Type");
|
||||||
|
TableSetupColumn("Prot");
|
||||||
|
TableSetupColumn("Is Exec");
|
||||||
|
TableSetupColumn("Name");
|
||||||
|
} else {
|
||||||
|
TableSetupColumn("Address");
|
||||||
|
TableSetupColumn("Size");
|
||||||
|
TableSetupColumn("Type");
|
||||||
|
TableSetupColumn("Pooled");
|
||||||
|
}
|
||||||
|
TableHeadersRow();
|
||||||
|
|
||||||
|
while (it.DrawLine())
|
||||||
|
;
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
33
src/core/devtools/widget/memory_map.h
Normal file
33
src/core/devtools/widget/memory_map.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class MemoryMapViewer {
|
||||||
|
struct Iterator {
|
||||||
|
bool is_vma;
|
||||||
|
struct {
|
||||||
|
MemoryManager::DMemMap::iterator it;
|
||||||
|
MemoryManager::DMemMap::iterator end;
|
||||||
|
} dmem;
|
||||||
|
struct {
|
||||||
|
MemoryManager::VMAMap::iterator it;
|
||||||
|
MemoryManager::VMAMap::iterator end;
|
||||||
|
} vma;
|
||||||
|
|
||||||
|
bool DrawLine();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool showing_vma = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool open = false;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
|
@ -25,21 +25,6 @@ using magic_enum::enum_name;
|
||||||
|
|
||||||
constexpr auto depth_id = 0xF3;
|
constexpr auto depth_id = 0xF3;
|
||||||
|
|
||||||
static std::optional<std::string> exec_cli(const char* cli) {
|
|
||||||
std::array<char, 64> buffer{};
|
|
||||||
std::string output;
|
|
||||||
const auto f = popen(cli, "r");
|
|
||||||
if (!f) {
|
|
||||||
pclose(f);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
while (fgets(buffer.data(), buffer.size(), f)) {
|
|
||||||
output += buffer.data();
|
|
||||||
}
|
|
||||||
pclose(f);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
void RegView::ProcessShader(int shader_id) {
|
void RegView::ProcessShader(int shader_id) {
|
||||||
|
@ -54,38 +39,12 @@ void RegView::ProcessShader(int shader_id) {
|
||||||
user_data = s.user_data.user_data;
|
user_data = s.user_data.user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string shader_dis;
|
std::string shader_dis = RunDisassembler(Options.disassembler_cli_isa, shader_code);
|
||||||
|
|
||||||
if (Options.disassembly_cli.empty()) {
|
|
||||||
shader_dis = "No disassembler set";
|
|
||||||
} else {
|
|
||||||
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
|
||||||
|
|
||||||
constexpr std::string_view src_arg = "{src}";
|
|
||||||
std::string cli = Options.disassembly_cli;
|
|
||||||
const auto pos = cli.find(src_arg);
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument");
|
|
||||||
} else {
|
|
||||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
|
||||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
|
||||||
file.Write(shader_code);
|
|
||||||
file.Close();
|
|
||||||
|
|
||||||
auto result = exec_cli(cli.c_str());
|
|
||||||
shader_dis = result.value_or("Could not disassemble shader");
|
|
||||||
if (shader_dis.empty()) {
|
|
||||||
shader_dis = "Disassembly empty or failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::remove(bin_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryEditor hex_view;
|
MemoryEditor hex_view;
|
||||||
hex_view.Open = true;
|
hex_view.Open = true;
|
||||||
hex_view.ReadOnly = true;
|
hex_view.ReadOnly = true;
|
||||||
hex_view.Cols = 8;
|
hex_view.Cols = 16;
|
||||||
hex_view.OptShowAscii = false;
|
hex_view.OptShowAscii = false;
|
||||||
hex_view.OptShowOptions = false;
|
hex_view.OptShowOptions = false;
|
||||||
|
|
||||||
|
@ -376,7 +335,9 @@ void RegView::Draw() {
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
Text("Stage not selected");
|
Text("Stage not selected");
|
||||||
} else {
|
} else {
|
||||||
shader->hex_view.DrawContents(shader->user_data.data(), shader->user_data.size());
|
shader->hex_view.DrawContents(shader->user_data.data(),
|
||||||
|
shader->user_data.size() *
|
||||||
|
sizeof(Vulkan::Liverpool::UserData::value_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
|
|
95
src/core/devtools/widget/shader_list.cpp
Normal file
95
src/core/devtools/widget/shader_list.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "shader_list.h"
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "core/devtools/options.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
void ShaderList::DrawShader(DebugStateType::ShaderDump& value) {
|
||||||
|
if (!loaded_data) {
|
||||||
|
loaded_data = true;
|
||||||
|
if (value.cache_raw_disasm.empty()) {
|
||||||
|
value.cache_raw_disasm = RunDisassembler(Options.disassembler_cli_isa, value.raw_code);
|
||||||
|
}
|
||||||
|
isa_editor.SetText(value.cache_raw_disasm);
|
||||||
|
|
||||||
|
if (value.cache_spv_disasm.empty()) {
|
||||||
|
value.cache_spv_disasm = RunDisassembler(Options.disassembler_cli_spv, value.spv);
|
||||||
|
}
|
||||||
|
spv_editor.SetText(value.cache_spv_disasm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SmallButton("<-")) {
|
||||||
|
selected_shader = -1;
|
||||||
|
}
|
||||||
|
SameLine();
|
||||||
|
Text("%s", value.name.c_str());
|
||||||
|
SameLine(0.0f, 7.0f);
|
||||||
|
if (BeginCombo("Shader type", showing_isa ? "ISA" : "SPIRV", ImGuiComboFlags_WidthFitPreview)) {
|
||||||
|
if (Selectable("SPIRV")) {
|
||||||
|
showing_isa = false;
|
||||||
|
}
|
||||||
|
if (Selectable("ISA")) {
|
||||||
|
showing_isa = true;
|
||||||
|
}
|
||||||
|
EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showing_isa) {
|
||||||
|
isa_editor.Render("ISA", GetContentRegionAvail());
|
||||||
|
} else {
|
||||||
|
spv_editor.Render("SPIRV", GetContentRegionAvail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderList::ShaderList() {
|
||||||
|
isa_editor.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
isa_editor.SetReadOnly(true);
|
||||||
|
spv_editor.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
spv_editor.SetReadOnly(true);
|
||||||
|
spv_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::GLSL());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderList::Draw() {
|
||||||
|
SetNextWindowSize({500.0f, 600.0f}, ImGuiCond_FirstUseEver);
|
||||||
|
if (!Begin("Shader list", &open)) {
|
||||||
|
End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config::collectShadersForDebug()) {
|
||||||
|
DrawCenteredText("Enable 'CollectShader' in config to see shaders");
|
||||||
|
End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected_shader >= 0) {
|
||||||
|
DrawShader(DebugState.shader_dump_list[selected_shader]);
|
||||||
|
End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto width = GetContentRegionAvail().x;
|
||||||
|
int i = 0;
|
||||||
|
for (const auto& shader : DebugState.shader_dump_list) {
|
||||||
|
if (ButtonEx(shader.name.c_str(), {width, 20.0f}, ImGuiButtonFlags_NoHoveredOnFocus)) {
|
||||||
|
selected_shader = i;
|
||||||
|
loaded_data = false;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
28
src/core/devtools/widget/shader_list.h
Normal file
28
src/core/devtools/widget/shader_list.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "text_editor.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class ShaderList {
|
||||||
|
int selected_shader = -1;
|
||||||
|
TextEditor isa_editor{};
|
||||||
|
TextEditor spv_editor{};
|
||||||
|
bool loaded_data = false;
|
||||||
|
bool showing_isa = false;
|
||||||
|
|
||||||
|
void DrawShader(DebugStateType::ShaderDump& value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderList();
|
||||||
|
|
||||||
|
bool open = false;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
|
@ -20,6 +20,10 @@ namespace Libraries::Kernel {
|
||||||
struct OrbisQueryInfo;
|
struct OrbisQueryInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
class MemoryMapViewer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
enum class MemoryProt : u32 {
|
enum class MemoryProt : u32 {
|
||||||
|
@ -257,6 +261,8 @@ private:
|
||||||
size_t total_flexible_size{};
|
size_t total_flexible_size{};
|
||||||
size_t flexible_usage{};
|
size_t flexible_usage{};
|
||||||
Vulkan::Rasterizer* rasterizer{};
|
Vulkan::Rasterizer* rasterizer{};
|
||||||
|
|
||||||
|
friend class ::Core::Devtools::Widget::MemoryMapViewer;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Memory = Common::Singleton<MemoryManager>;
|
using Memory = Common::Singleton<MemoryManager>;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "common/io_file.h"
|
#include "common/io_file.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||||
#include "shader_recompiler/info.h"
|
#include "shader_recompiler/info.h"
|
||||||
#include "shader_recompiler/recompiler.h"
|
#include "shader_recompiler/recompiler.h"
|
||||||
|
@ -416,6 +417,9 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info,
|
||||||
const auto module = CompileSPV(spv, instance.GetDevice());
|
const auto module = CompileSPV(spv, instance.GetDevice());
|
||||||
const auto name = fmt::format("{}_{:#x}_{}", info.stage, info.pgm_hash, perm_idx);
|
const auto name = fmt::format("{}_{:#x}_{}", info.stage, info.pgm_hash, perm_idx);
|
||||||
Vulkan::SetObjectName(instance.GetDevice(), module, name);
|
Vulkan::SetObjectName(instance.GetDevice(), module, name);
|
||||||
|
if (Config::collectShadersForDebug()) {
|
||||||
|
DebugState.CollectShader(name, spv, code);
|
||||||
|
}
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue