More devtools stuff (#1637)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions

* 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:
Vinicius Rangel 2024-12-01 15:34:29 -03:00 committed by GitHub
parent f658fc58d1
commit 0835dc71b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 491 additions and 65 deletions

View file

@ -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.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.h
src/core/devtools/widget/reg_view.cpp
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.h
)

View file

@ -47,6 +47,7 @@ static std::string backButtonBehavior = "left";
static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isDebugDump = false;
static bool isShaderDebug = false;
static bool isShowSplash = false;
static bool isAutoUpdate = false;
static bool isNullGpu = false;
@ -159,6 +160,10 @@ bool debugDump() {
return isDebugDump;
}
bool collectShadersForDebug() {
return isShaderDebug;
}
bool showSplash() {
return isShowSplash;
}
@ -235,6 +240,10 @@ void setDebugDump(bool enable) {
isDebugDump = enable;
}
void setCollectShaderForDebug(bool enable) {
isShaderDebug = enable;
}
void setShowSplash(bool enable) {
isShowSplash = enable;
}
@ -571,6 +580,7 @@ void load(const std::filesystem::path& path) {
const toml::value& debug = data.at("Debug");
isDebugDump = toml::find_or<bool>(debug, "DebugDump", false);
isShaderDebug = toml::find_or<bool>(debug, "CollectShader", false);
}
if (data.contains("GUI")) {
@ -662,6 +672,7 @@ void save(const std::filesystem::path& path) {
data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
data["Debug"]["DebugDump"] = isDebugDump;
data["Debug"]["CollectShader"] = isShaderDebug;
data["GUI"]["theme"] = mw_themes;
data["GUI"]["iconSize"] = m_icon_size;
data["GUI"]["sliderPos"] = m_slider_pos;
@ -717,6 +728,7 @@ void setDefaultValues() {
useSpecialPad = false;
specialPadClass = 1;
isDebugDump = false;
isShaderDebug = false;
isShowSplash = false;
isAutoUpdate = false;
isNullGpu = false;

View file

@ -37,6 +37,7 @@ u32 getScreenHeight();
s32 getGpuId();
bool debugDump();
bool collectShadersForDebug();
bool showSplash();
bool autoUpdate();
bool nullGpu();
@ -47,6 +48,7 @@ bool isRdocEnabled();
u32 vblankDiv();
void setDebugDump(bool enable);
void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setNullGpu(bool enable);

View file

@ -157,7 +157,7 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
if (is_compute) {
dump.is_compute = true;
const auto& cs = dump.regs.cs_program;
dump.cs_data = ComputerShaderDump{
dump.cs_data = PipelineComputerProgramDump{
.cs_program = cs,
.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);
if (stage->address_lo != 0) {
auto code = stage->Code();
dump.stages[i] = ShaderDump{
dump.stages[i] = PipelineShaderProgramDump{
.user_data = *stage,
.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);
}

View file

@ -30,7 +30,8 @@ namespace Core::Devtools {
class Layer;
namespace Widget {
class FrameGraph;
}
class ShaderList;
} // namespace Widget
} // namespace Core::Devtools
namespace DebugStateType {
@ -49,12 +50,12 @@ struct QueueDump {
uintptr_t base_addr;
};
struct ShaderDump {
struct PipelineShaderProgramDump {
Vulkan::Liverpool::ShaderProgram user_data{};
std::vector<u32> code{};
};
struct ComputerShaderDump {
struct PipelineComputerProgramDump {
Vulkan::Liverpool::ComputeProgram cs_program{};
std::vector<u32> code{};
};
@ -63,8 +64,8 @@ struct RegDump {
bool is_compute{false};
static constexpr size_t MaxShaderStages = 5;
Vulkan::Liverpool::Regs regs{};
std::array<ShaderDump, MaxShaderStages> stages{};
ComputerShaderDump cs_data{};
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
PipelineComputerProgramDump cs_data{};
};
struct FrameDump {
@ -73,9 +74,41 @@ struct FrameDump {
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 {
friend class Core::Devtools::Layer;
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::vector<ThreadID> guest_threads{};
@ -94,7 +127,7 @@ class DebugStateImpl {
std::shared_mutex frame_dump_list_mutex;
std::vector<FrameDump> frame_dump_list{};
std::queue<std::string> debug_message_popup;
std::vector<ShaderDump> shader_dump_list{};
public:
void ShowDebugMessage(std::string message) {
@ -152,6 +185,9 @@ public:
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
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

View file

@ -289,6 +289,16 @@ const char* GetContextRegName(u32 reg_offset) {
return "mmSPI_PS_INPUT_CNTL_2";
case 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:
break;
}

View file

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "layer.h"
#include <imgui.h>
#include "common/config.h"
@ -9,11 +11,12 @@
#include "core/debug_state.h"
#include "imgui/imgui_std.h"
#include "imgui_internal.h"
#include "layer.h"
#include "options.h"
#include "video_core/renderer_vulkan/vk_presenter.h"
#include "widget/frame_dump.h"
#include "widget/frame_graph.h"
#include "widget/memory_map.h"
#include "widget/shader_list.h"
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 Widget::MemoryMapViewer memory_map;
static Widget::ShaderList shader_list;
// clang-format off
static std::string help_text =
#include "help.txt"
@ -63,6 +69,7 @@ void L::DrawMenuBar() {
}
if (BeginMenu("GPU Tools")) {
MenuItem("Show frame info", nullptr, &frame_graph.is_open);
MenuItem("Show loaded shaders", nullptr, &shader_list.open);
if (BeginMenu("Dump frames")) {
SliderInt("Count", &dump_frame_count, 1, 5);
if (MenuItem("Dump", "Ctrl+Alt+F9", nullptr, !DebugState.DumpingCurrentFrame())) {
@ -81,6 +88,12 @@ void L::DrawMenuBar() {
}
ImGui::EndMenu();
}
if (BeginMenu("Debug")) {
if (MenuItem("Memory map")) {
memory_map.open = true;
}
ImGui::EndMenu();
}
EndMainMenuBar();
}
@ -175,19 +188,29 @@ void L::DrawAdvanced() {
bool close_popup_options = true;
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
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;
if (just_opened_options) {
just_opened_options = false;
auto s = Options.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
disassembly_cli[s] = '\0';
auto s = Options.disassembler_cli_isa.copy(disassembler_cli_isa,
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;
}
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
InputText("Shader isa disassembler: ", disassembler_cli_isa, sizeof(disassembler_cli_isa));
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);
if (IsItemHovered()) {
@ -196,7 +219,8 @@ void L::DrawAdvanced() {
}
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;
SaveIniSettingsToDisk(io.IniFilename);
CloseCurrentPopup();
@ -219,6 +243,13 @@ void L::DrawAdvanced() {
EndPopup();
}
if (memory_map.open) {
memory_map.Draw();
}
if (shader_list.open) {
shader_list.Draw();
}
}
void L::DrawSimple() {

View file

@ -12,8 +12,12 @@ TOptions Options;
void LoadOptionsConfig(const char* line) {
char str[512];
int i;
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
Options.disassembly_cli = str;
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
Options.disassembler_cli_isa = str;
return;
}
if (sscanf(line, "disassembler_cli_spv=%511[^\n]", str) == 1) {
Options.disassembler_cli_spv = str;
return;
}
if (sscanf(line, "frame_dump_render_on_collapse=%d", &i) == 1) {
@ -23,7 +27,8 @@ void LoadOptionsConfig(const char* line) {
}
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);
}

View file

@ -10,7 +10,8 @@ struct ImGuiTextBuffer;
namespace Core::Devtools {
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};
};

View file

@ -1306,7 +1306,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
if (batch.id == batch_bp) { // highlight batch at breakpoint
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});
}
@ -1459,7 +1459,7 @@ void CmdListViewer::Draw(bool only_batches_view) {
}
}
if (batch.id == highlight_batch) {
if (batch.id == highlight_batch && !group_batches) {
PopStyleColor();
}

View file

@ -3,6 +3,7 @@
#pragma once
#include <filesystem>
#include <string>
#include <type_traits>
#include <variant>
@ -10,9 +11,16 @@
#include <magic_enum.hpp>
#include "common/bit_field.h"
#include "common/io_file.h"
#include "common/types.h"
#include "core/debug_state.h"
#include "video_core/amdgpu/pm4_opcodes.h"
#if defined(_WIN32)
#define popen _popen
#define pclose _pclose
#endif
namespace Core::Devtools::Widget {
/*
* 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

View 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

View 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

View file

@ -25,21 +25,6 @@ using magic_enum::enum_name;
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 {
void RegView::ProcessShader(int shader_id) {
@ -54,38 +39,12 @@ void RegView::ProcessShader(int shader_id) {
user_data = s.user_data.user_data;
}
std::string shader_dis;
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);
}
}
std::string shader_dis = RunDisassembler(Options.disassembler_cli_isa, shader_code);
MemoryEditor hex_view;
hex_view.Open = true;
hex_view.ReadOnly = true;
hex_view.Cols = 8;
hex_view.Cols = 16;
hex_view.OptShowAscii = false;
hex_view.OptShowOptions = false;
@ -376,7 +335,9 @@ void RegView::Draw() {
if (!shader) {
Text("Stage not selected");
} 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();

View 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

View 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

View file

@ -20,6 +20,10 @@ namespace Libraries::Kernel {
struct OrbisQueryInfo;
}
namespace Core::Devtools::Widget {
class MemoryMapViewer;
}
namespace Core {
enum class MemoryProt : u32 {
@ -257,6 +261,8 @@ private:
size_t total_flexible_size{};
size_t flexible_usage{};
Vulkan::Rasterizer* rasterizer{};
friend class ::Core::Devtools::Widget::MemoryMapViewer;
};
using Memory = Common::Singleton<MemoryManager>;

View file

@ -7,6 +7,7 @@
#include "common/hash.h"
#include "common/io_file.h"
#include "common/path_util.h"
#include "core/debug_state.h"
#include "shader_recompiler/backend/spirv/emit_spirv.h"
#include "shader_recompiler/info.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 name = fmt::format("{}_{:#x}_{}", info.stage, info.pgm_hash, perm_idx);
Vulkan::SetObjectName(instance.GetDevice(), module, name);
if (Config::collectShadersForDebug()) {
DebugState.CollectShader(name, spv, code);
}
return module;
}