mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-29 11:06:07 +00:00
Devtools improvements I (#1392)
Some checks are pending
Build and Release / get-info (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / reuse (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
Some checks are pending
Build and Release / get-info (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / reuse (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: fix showing entire depth instead of bits * devtools: show button for stage instead of menu bar - fix batch view dockspace not rendering when window collapsed * devtools: removed useless "Batch" collapse & don't collapse last batch * devtools: refactor DrawRow to templating * devtools: reg popup size adjusted to the content * devtools: better window names * devtools: regview layout compacted * devtools: option to show collapsed frame dump keep most popups open when selection changes best popup windows positioning * devtools: show compute shader regs * devtools: tips popup
This commit is contained in:
parent
877cda9b9a
commit
25de4d6b65
|
@ -81,7 +81,9 @@
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
template <std::size_t Position, std::size_t Bits, typename T>
|
template <std::size_t Position, std::size_t Bits, typename T>
|
||||||
struct BitField {
|
struct BitField {
|
||||||
private:
|
|
||||||
|
using Type = T;
|
||||||
|
|
||||||
// UnderlyingType is T for non-enum types and the underlying type of T if
|
// UnderlyingType is T for non-enum types and the underlying type of T if
|
||||||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||||
// former case to workaround compile errors which arise when using
|
// former case to workaround compile errors which arise when using
|
||||||
|
@ -92,7 +94,6 @@ private:
|
||||||
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
|
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
|
||||||
using StorageType = std::make_unsigned_t<UnderlyingType>;
|
using StorageType = std::make_unsigned_t<UnderlyingType>;
|
||||||
|
|
||||||
public:
|
|
||||||
/// Constants to allow limited introspection of fields if needed
|
/// Constants to allow limited introspection of fields if needed
|
||||||
static constexpr std::size_t position = Position;
|
static constexpr std::size_t position = Position;
|
||||||
static constexpr std::size_t bits = Bits;
|
static constexpr std::size_t bits = Bits;
|
||||||
|
|
|
@ -102,6 +102,10 @@ void DebugStateImpl::RequestFrameDump(s32 count) {
|
||||||
gnm_frame_dump_request_count = count;
|
gnm_frame_dump_request_count = count;
|
||||||
frame_dump_list.clear();
|
frame_dump_list.clear();
|
||||||
frame_dump_list.resize(count);
|
frame_dump_list.resize(count);
|
||||||
|
const auto f = gnm_frame_count.load() + 1;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
frame_dump_list[i].frame_id = f + i;
|
||||||
|
}
|
||||||
waiting_submit_pause = true;
|
waiting_submit_pause = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +143,7 @@ void DebugStateImpl::PushQueueDump(QueueDump dump) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
const AmdGpu::Liverpool::Regs& regs) {
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute) {
|
||||||
std::scoped_lock lock{frame_dump_list_mutex};
|
std::scoped_lock lock{frame_dump_list_mutex};
|
||||||
const auto it = waiting_reg_dumps.find(header_addr);
|
const auto it = waiting_reg_dumps.find(header_addr);
|
||||||
if (it == waiting_reg_dumps.end()) {
|
if (it == waiting_reg_dumps.end()) {
|
||||||
|
@ -150,6 +154,14 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
||||||
auto& dump = frame.regs[header_addr - base_addr];
|
auto& dump = frame.regs[header_addr - base_addr];
|
||||||
dump.regs = regs;
|
dump.regs = regs;
|
||||||
|
if (is_compute) {
|
||||||
|
dump.is_compute = true;
|
||||||
|
const auto& cs = dump.regs.cs_program;
|
||||||
|
dump.cs_data = ComputerShaderDump{
|
||||||
|
.cs_program = cs,
|
||||||
|
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
||||||
if (regs.stage_enable.IsStageEnabled(i)) {
|
if (regs.stage_enable.IsStageEnabled(i)) {
|
||||||
auto stage = regs.ProgramForStage(i);
|
auto stage = regs.ProgramForStage(i);
|
||||||
|
@ -163,3 +175,4 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,9 +36,9 @@ class FrameGraph;
|
||||||
namespace DebugStateType {
|
namespace DebugStateType {
|
||||||
|
|
||||||
enum class QueueType {
|
enum class QueueType {
|
||||||
acb,
|
dcb = 0,
|
||||||
dcb,
|
ccb = 1,
|
||||||
ccb,
|
acb = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QueueDump {
|
struct QueueDump {
|
||||||
|
@ -54,13 +54,21 @@ struct ShaderDump {
|
||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ComputerShaderDump {
|
||||||
|
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||||
|
std::vector<u32> code{};
|
||||||
|
};
|
||||||
|
|
||||||
struct RegDump {
|
struct RegDump {
|
||||||
|
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<ShaderDump, MaxShaderStages> stages{};
|
||||||
|
ComputerShaderDump cs_data{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameDump {
|
struct FrameDump {
|
||||||
|
u32 frame_id;
|
||||||
std::vector<QueueDump> queues;
|
std::vector<QueueDump> queues;
|
||||||
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
||||||
};
|
};
|
||||||
|
@ -143,7 +151,7 @@ public:
|
||||||
void PushQueueDump(QueueDump dump);
|
void PushQueueDump(QueueDump dump);
|
||||||
|
|
||||||
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);
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
||||||
};
|
};
|
||||||
} // namespace DebugStateType
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
|
8
src/core/devtools/help.txt
Normal file
8
src/core/devtools/help.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
R"(
|
||||||
|
* If you hold shift, you can move the window without docking it.
|
||||||
|
* You don't need to close every window you open. When a parent window is closed, all its children will be closed too.
|
||||||
|
* If you want to inspect or compare more than 1 frame dump without undocking, there's a option to keep showing opened popups even when in hide/minimize the frame dump window.
|
||||||
|
* To use the disassembly viewer, you need to set up a cli to use a external disassembler and use "{src}" as a placeholder for the source code file, e.g. dis.exe --some-opt "{src}"
|
||||||
|
)"
|
|
@ -31,6 +31,12 @@ static float debug_popup_timing = 3.0f;
|
||||||
|
|
||||||
static bool just_opened_options = false;
|
static bool just_opened_options = false;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static std::string help_text =
|
||||||
|
#include "help.txt"
|
||||||
|
;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
void L::DrawMenuBar() {
|
void L::DrawMenuBar() {
|
||||||
const auto& ctx = *GImGui;
|
const auto& ctx = *GImGui;
|
||||||
const auto& io = ctx.IO;
|
const auto& io = ctx.IO;
|
||||||
|
@ -38,6 +44,7 @@ void L::DrawMenuBar() {
|
||||||
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
bool open_popup_options = false;
|
bool open_popup_options = false;
|
||||||
|
bool open_popup_help = false;
|
||||||
|
|
||||||
if (BeginMainMenuBar()) {
|
if (BeginMainMenuBar()) {
|
||||||
if (BeginMenu("Options")) {
|
if (BeginMenu("Options")) {
|
||||||
|
@ -60,6 +67,7 @@ void L::DrawMenuBar() {
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
open_popup_options = MenuItem("Options");
|
open_popup_options = MenuItem("Options");
|
||||||
|
open_popup_help = MenuItem("Help & Tips");
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
|
@ -84,6 +92,9 @@ void L::DrawMenuBar() {
|
||||||
OpenPopup("GPU Tools Options");
|
OpenPopup("GPU Tools Options");
|
||||||
just_opened_options = true;
|
just_opened_options = true;
|
||||||
}
|
}
|
||||||
|
if (open_popup_help) {
|
||||||
|
OpenPopup("HelpTips");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawAdvanced() {
|
void L::DrawAdvanced() {
|
||||||
|
@ -154,25 +165,49 @@ void L::DrawAdvanced() {
|
||||||
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 disassembly_cli[512];
|
||||||
|
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.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
|
||||||
disassembly_cli[s] = '\0';
|
disassembly_cli[s] = '\0';
|
||||||
|
frame_dump_render_on_collapse = Options.frame_dump_render_on_collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
||||||
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}")");
|
||||||
}
|
}
|
||||||
|
Checkbox("Show frame dump popups even when collapsed", &frame_dump_render_on_collapse);
|
||||||
|
if (IsItemHovered()) {
|
||||||
|
SetTooltip("When a frame dump is collapsed, it will keep\n"
|
||||||
|
"showing all opened popups related to it");
|
||||||
|
}
|
||||||
|
|
||||||
if (Button("Save")) {
|
if (Button("Save")) {
|
||||||
Options.disassembly_cli = disassembly_cli;
|
Options.disassembly_cli = disassembly_cli;
|
||||||
|
Options.frame_dump_render_on_collapse = frame_dump_render_on_collapse;
|
||||||
SaveIniSettingsToDisk(io.IniFilename);
|
SaveIniSettingsToDisk(io.IniFilename);
|
||||||
CloseCurrentPopup();
|
CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
EndPopup();
|
EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BeginPopup("HelpTips", ImGuiWindowFlags_AlwaysAutoResize |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove)) {
|
||||||
|
CentralizeWindow();
|
||||||
|
|
||||||
|
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{10.0f});
|
||||||
|
PushTextWrapPos(600.0f);
|
||||||
|
|
||||||
|
const char* begin = help_text.data();
|
||||||
|
TextUnformatted(begin, begin + help_text.size());
|
||||||
|
|
||||||
|
PopTextWrapPos();
|
||||||
|
PopStyleVar();
|
||||||
|
|
||||||
|
EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawSimple() {
|
void L::DrawSimple() {
|
||||||
|
|
|
@ -11,14 +11,20 @@ TOptions Options;
|
||||||
|
|
||||||
void LoadOptionsConfig(const char* line) {
|
void LoadOptionsConfig(const char* line) {
|
||||||
char str[512];
|
char str[512];
|
||||||
|
int i;
|
||||||
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
||||||
Options.disassembly_cli = str;
|
Options.disassembly_cli = str;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (sscanf(line, "frame_dump_render_on_collapse=%d", &i) == 1) {
|
||||||
|
Options.frame_dump_render_on_collapse = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||||
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
||||||
|
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools
|
} // namespace Core::Devtools
|
||||||
|
|
|
@ -10,7 +10,8 @@ struct ImGuiTextBuffer;
|
||||||
namespace Core::Devtools {
|
namespace Core::Devtools {
|
||||||
|
|
||||||
struct TOptions {
|
struct TOptions {
|
||||||
std::string disassembly_cli;
|
std::string disassembly_cli{};
|
||||||
|
bool frame_dump_render_on_collapse{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TOptions Options;
|
extern TOptions Options;
|
||||||
|
|
|
@ -1173,7 +1173,7 @@ CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdListViewer::Draw() {
|
void CmdListViewer::Draw(bool only_batches_view) {
|
||||||
const auto& ctx = *GetCurrentContext();
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
|
||||||
if (batch_view.open) {
|
if (batch_view.open) {
|
||||||
|
@ -1188,6 +1188,10 @@ void CmdListViewer::Draw() {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (only_batches_view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cmdb_view.Open) {
|
if (cmdb_view.Open) {
|
||||||
MemoryEditor::Sizes s;
|
MemoryEditor::Sizes s;
|
||||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
@ -1228,7 +1232,7 @@ void CmdListViewer::Draw() {
|
||||||
Text("size : %04llX", cmdb_size);
|
Text("size : %04llX", cmdb_size);
|
||||||
Separator();
|
Separator();
|
||||||
|
|
||||||
if (TreeNode("Batches")) {
|
{
|
||||||
int tree_depth = 0;
|
int tree_depth = 0;
|
||||||
int tree_depth_show = 0;
|
int tree_depth_show = 0;
|
||||||
|
|
||||||
|
@ -1283,9 +1287,10 @@ void CmdListViewer::Draw() {
|
||||||
auto const* pm4_hdr =
|
auto const* pm4_hdr =
|
||||||
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
||||||
|
|
||||||
|
bool ignore_header = false;
|
||||||
char batch_hdr[128];
|
char batch_hdr[128];
|
||||||
if (batch.type == static_cast<AmdGpu::PM4ItOpcode>(0xFF)) {
|
if (batch.type == static_cast<AmdGpu::PM4ItOpcode>(0xFF)) {
|
||||||
snprintf(batch_hdr, sizeof(batch_hdr), "State batch");
|
ignore_header = true;
|
||||||
} else if (!batch.marker.empty()) {
|
} else if (!batch.marker.empty()) {
|
||||||
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s | %s",
|
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s | %s",
|
||||||
cmdb_addr + batch.start_addr, batch.id,
|
cmdb_addr + batch.start_addr, batch.id,
|
||||||
|
@ -1309,22 +1314,35 @@ void CmdListViewer::Draw() {
|
||||||
auto data = frame_dump->regs.at(batch.command_addr);
|
auto data = frame_dump->regs.at(batch.command_addr);
|
||||||
if (GetIO().KeyShift) {
|
if (GetIO().KeyShift) {
|
||||||
auto& pop = extra_batch_view.emplace_back();
|
auto& pop = extra_batch_view.emplace_back();
|
||||||
pop.SetData(data, batch_id);
|
pop.SetData(data, name, batch_id);
|
||||||
pop.open = true;
|
pop.open = true;
|
||||||
} else {
|
} else {
|
||||||
batch_view.SetData(data, batch_id);
|
if (batch_view.open &&
|
||||||
|
this->last_selected_batch == static_cast<int>(batch_id)) {
|
||||||
|
batch_view.open = false;
|
||||||
|
} else {
|
||||||
|
this->last_selected_batch = static_cast<int>(batch_id);
|
||||||
|
batch_view.SetData(data, name, batch_id);
|
||||||
|
if (!batch_view.open || !batch_view.moved) {
|
||||||
batch_view.open = true;
|
batch_view.open = true;
|
||||||
|
const auto pos = GetItemRectMax() + ImVec2{5.0f, 0.0f};
|
||||||
|
batch_view.SetPos(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool show_batch_content = true;
|
bool show_batch_content = true;
|
||||||
|
|
||||||
if (group_batches) {
|
if (group_batches && !ignore_header) {
|
||||||
show_batch_content =
|
show_batch_content =
|
||||||
CollapsingHeader(batch_hdr, ImGuiTreeNodeFlags_AllowOverlap);
|
CollapsingHeader(batch_hdr, ImGuiTreeNodeFlags_AllowOverlap);
|
||||||
SameLine(GetContentRegionAvail().x - 40.0f);
|
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||||
if (Button("->", {40.0f, 0.0f})) {
|
const char* text =
|
||||||
|
last_selected_batch == static_cast<int>(batch_id) && batch_view.open ? "X"
|
||||||
|
: "->";
|
||||||
|
if (Button(text, {40.0f, 0.0f})) {
|
||||||
open_batch_view();
|
open_batch_view();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1350,7 @@ void CmdListViewer::Draw() {
|
||||||
if (show_batch_content) {
|
if (show_batch_content) {
|
||||||
auto processed_size = 0ull;
|
auto processed_size = 0ull;
|
||||||
auto bb = ctx.LastItemData.Rect;
|
auto bb = ctx.LastItemData.Rect;
|
||||||
if (group_batches) {
|
if (group_batches && !ignore_header) {
|
||||||
Indent();
|
Indent();
|
||||||
}
|
}
|
||||||
auto const batch_sz = batch.end_addr - batch.start_addr;
|
auto const batch_sz = batch.end_addr - batch.start_addr;
|
||||||
|
@ -1354,7 +1372,12 @@ void CmdListViewer::Draw() {
|
||||||
if (!group_batches) {
|
if (!group_batches) {
|
||||||
if (IsDrawCall(op)) {
|
if (IsDrawCall(op)) {
|
||||||
SameLine(GetContentRegionAvail().x - 40.0f);
|
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||||
if (Button("->", {40.0f, 0.0f})) {
|
const char* text =
|
||||||
|
last_selected_batch == static_cast<int>(batch_id) &&
|
||||||
|
batch_view.open
|
||||||
|
? "X"
|
||||||
|
: "->";
|
||||||
|
if (Button(text, {40.0f, 0.0f})) {
|
||||||
open_batch_view();
|
open_batch_view();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1426,7 +1449,7 @@ void CmdListViewer::Draw() {
|
||||||
processed_size += processed_len;
|
processed_size += processed_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group_batches) {
|
if (group_batches && !ignore_header) {
|
||||||
Unindent();
|
Unindent();
|
||||||
};
|
};
|
||||||
bb = {{0.0f, bb.Max.y}, ctx.LastItemData.Rect.Max};
|
bb = {{0.0f, bb.Max.y}, ctx.LastItemData.Rect.Max};
|
||||||
|
@ -1450,8 +1473,6 @@ void CmdListViewer::Draw() {
|
||||||
PopID();
|
PopID();
|
||||||
|
|
||||||
highlight_batch = current_highlight_batch;
|
highlight_batch = current_highlight_batch;
|
||||||
|
|
||||||
TreePop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndChild();
|
EndChild();
|
||||||
|
|
|
@ -53,6 +53,8 @@ class CmdListViewer {
|
||||||
u32 highlight_batch{~0u};
|
u32 highlight_batch{~0u};
|
||||||
|
|
||||||
RegView batch_view;
|
RegView batch_view;
|
||||||
|
int last_selected_batch{-1};
|
||||||
|
|
||||||
std::vector<RegView> extra_batch_view;
|
std::vector<RegView> extra_batch_view;
|
||||||
|
|
||||||
static void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
static void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
@ -68,7 +70,7 @@ public:
|
||||||
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
|
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
|
||||||
uintptr_t base_addr = 0, std::string name = "");
|
uintptr_t base_addr = 0, std::string name = "");
|
||||||
|
|
||||||
void Draw();
|
void Draw(bool only_batches_view = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "common/bit_field.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "video_core/amdgpu/pm4_opcodes.h"
|
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic PM4 header
|
* Generic PM4 header
|
||||||
*/
|
*/
|
||||||
|
@ -57,16 +58,24 @@ void DrawRow(const char* text, const char* fmt, Args... args) {
|
||||||
ImGui::TextUnformatted(buf);
|
ImGui::TextUnformatted(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename V = u32>
|
template <typename T>
|
||||||
void DrawEnumRow(const char* text, T value) {
|
void DrawValueRow(const char* text, T value) {
|
||||||
DrawRow(text, "%X (%s)", V(value), magic_enum::enum_name(value).data());
|
if constexpr (std::is_enum_v<T>) {
|
||||||
|
return DrawRow(text, "%X (%s)", value, magic_enum::enum_name(value).data());
|
||||||
|
} else if constexpr (std::is_integral_v<T>) {
|
||||||
|
return DrawRow(text, "%X", value);
|
||||||
|
} else if constexpr (std::is_base_of_v<BitField<T::position, T::bits, typename T::Type>, T>) {
|
||||||
|
return DrawValueRow(text, value.Value());
|
||||||
|
} else {
|
||||||
|
static_assert(false, "Unsupported type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V, typename... Extra>
|
template <typename V, typename... Extra>
|
||||||
void DrawMultipleRow(const char* text, const char* fmt, V arg, Extra&&... extra_args) {
|
void DrawValueRowList(const char* text, V arg, Extra&&... extra_args) {
|
||||||
DrawRow(text, fmt, arg);
|
DrawValueRow(text, arg);
|
||||||
if constexpr (sizeof...(extra_args) > 0) {
|
if constexpr (sizeof...(extra_args) > 0) {
|
||||||
DrawMultipleRow(std::forward<Extra>(extra_args)...);
|
DrawValueRowList(std::forward<Extra>(extra_args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
#include "common/io_file.h"
|
#include "common/io_file.h"
|
||||||
|
#include "core/devtools/options.h"
|
||||||
#include "frame_dump.h"
|
#include "frame_dump.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "imgui_memory_editor.h"
|
#include "imgui_memory_editor.h"
|
||||||
|
@ -45,11 +46,14 @@ FrameDumpViewer::FrameDumpViewer(const FrameDump& _frame_dump)
|
||||||
selected_submit_num = 0;
|
selected_submit_num = 0;
|
||||||
selected_queue_num2 = 0;
|
selected_queue_num2 = 0;
|
||||||
|
|
||||||
|
has_queue_type.fill(false);
|
||||||
cmd_list_viewer.reserve(frame_dump->queues.size());
|
cmd_list_viewer.reserve(frame_dump->queues.size());
|
||||||
for (const auto& cmd : frame_dump->queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
const auto fname =
|
if (!cmd.data.empty()) {
|
||||||
fmt::format("{}_{}_{:02}_{:02}", id, magic_enum::enum_name(selected_queue_type),
|
has_queue_type[static_cast<s32>(cmd.type)] = true;
|
||||||
selected_submit_num, selected_queue_num2);
|
}
|
||||||
|
const auto fname = fmt::format("F{} {}_{:02}_{:02}", frame_dump->frame_id,
|
||||||
|
magic_enum::enum_name(cmd.type), cmd.submit_num, cmd.num2);
|
||||||
cmd_list_viewer.emplace_back(frame_dump.get(), cmd.data, cmd.base_addr, fname);
|
cmd_list_viewer.emplace_back(frame_dump.get(), cmd.data, cmd.base_addr, fname);
|
||||||
if (cmd.type == QueueType::dcb && cmd.submit_num == 0 && cmd.num2 == 0) {
|
if (cmd.type == QueueType::dcb && cmd.submit_num == 0 && cmd.num2 == 0) {
|
||||||
selected_cmd = static_cast<s32>(cmd_list_viewer.size() - 1);
|
selected_cmd = static_cast<s32>(cmd_list_viewer.size() - 1);
|
||||||
|
@ -64,9 +68,28 @@ void FrameDumpViewer::Draw() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto try_select = [&, this] {
|
||||||
|
const auto it = std::ranges::find_if(frame_dump->queues, [&](const auto& cmd) {
|
||||||
|
return cmd.type == selected_queue_type &&
|
||||||
|
(selected_submit_num == -1 || cmd.submit_num == selected_submit_num) &&
|
||||||
|
(selected_queue_num2 == -1 || cmd.num2 == selected_queue_num2);
|
||||||
|
});
|
||||||
|
if (it != frame_dump->queues.end()) {
|
||||||
|
selected_cmd = static_cast<s32>(std::distance(frame_dump->queues.begin(), it));
|
||||||
|
selected_submit_num = static_cast<s32>(frame_dump->queues[selected_cmd].submit_num);
|
||||||
|
selected_queue_num2 = static_cast<s32>(frame_dump->queues[selected_cmd].num2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_showing = Options.frame_dump_render_on_collapse;
|
||||||
|
bool is_collapsed = true;
|
||||||
|
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "Frame #%d dump", id);
|
snprintf(name, sizeof(name), "Frame #%d dump", frame_dump->frame_id);
|
||||||
if (Begin(name, &is_open, ImGuiWindowFlags_NoSavedSettings)) {
|
if (Begin(name, &is_open, ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
is_showing = true;
|
||||||
|
is_collapsed = false;
|
||||||
|
|
||||||
if (IsWindowAppearing()) {
|
if (IsWindowAppearing()) {
|
||||||
auto window = GetCurrentWindow();
|
auto window = GetCurrentWindow();
|
||||||
static ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
static ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
||||||
|
@ -79,12 +102,15 @@ void FrameDumpViewer::Draw() {
|
||||||
if (BeginCombo("##select_queue_type", magic_enum::enum_name(selected_queue_type).data(),
|
if (BeginCombo("##select_queue_type", magic_enum::enum_name(selected_queue_type).data(),
|
||||||
ImGuiComboFlags_WidthFitPreview)) {
|
ImGuiComboFlags_WidthFitPreview)) {
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
#define COMBO(x) C_V(magic_enum::enum_name(x).data(), x, selected_queue_type, selected)
|
#define COMBO(x) \
|
||||||
COMBO(QueueType::acb)
|
if (has_queue_type[static_cast<s32>(x)]) \
|
||||||
|
C_V(magic_enum::enum_name(x).data(), x, selected_queue_type, selected)
|
||||||
COMBO(QueueType::dcb);
|
COMBO(QueueType::dcb);
|
||||||
COMBO(QueueType::ccb);
|
COMBO(QueueType::ccb);
|
||||||
|
COMBO(QueueType::acb);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected_submit_num = selected_queue_num2 = -1;
|
selected_submit_num = selected_queue_num2 = -1;
|
||||||
|
try_select();
|
||||||
}
|
}
|
||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
|
@ -111,9 +137,9 @@ void FrameDumpViewer::Draw() {
|
||||||
SameLine();
|
SameLine();
|
||||||
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
||||||
ImGuiComboFlags_WidthFitPreview)) {
|
ImGuiComboFlags_WidthFitPreview)) {
|
||||||
std::array<bool, 32> available_submits{};
|
std::array<bool, 32> available_submits{false};
|
||||||
for (const auto& cmd : frame_dump->queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
if (cmd.type == selected_queue_type) {
|
if (cmd.type == selected_queue_type && !cmd.data.empty()) {
|
||||||
available_submits[cmd.submit_num] = true;
|
available_submits[cmd.submit_num] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +154,7 @@ void FrameDumpViewer::Draw() {
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected_queue_num2 = -1;
|
selected_queue_num2 = -1;
|
||||||
|
try_select();
|
||||||
}
|
}
|
||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
|
@ -136,9 +163,10 @@ void FrameDumpViewer::Draw() {
|
||||||
SameLine();
|
SameLine();
|
||||||
if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(),
|
if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(),
|
||||||
ImGuiComboFlags_WidthFitPreview)) {
|
ImGuiComboFlags_WidthFitPreview)) {
|
||||||
std::array<bool, 32> available_queues{};
|
std::array<bool, 32> available_queues{false};
|
||||||
for (const auto& cmd : frame_dump->queues) {
|
for (const auto& cmd : frame_dump->queues) {
|
||||||
if (cmd.type == selected_queue_type && cmd.submit_num == selected_submit_num) {
|
if (cmd.type == selected_queue_type && cmd.submit_num == selected_submit_num &&
|
||||||
|
!cmd.data.empty()) {
|
||||||
available_queues[cmd.num2] = true;
|
available_queues[cmd.num2] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,21 +180,14 @@ void FrameDumpViewer::Draw() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected) {
|
||||||
const auto it = std::ranges::find_if(frame_dump->queues, [&](const auto& cmd) {
|
try_select();
|
||||||
return cmd.type == selected_queue_type &&
|
|
||||||
cmd.submit_num == selected_submit_num && cmd.num2 == selected_queue_num2;
|
|
||||||
});
|
|
||||||
if (it != frame_dump->queues.end()) {
|
|
||||||
selected_cmd = static_cast<s32>(std::distance(frame_dump->queues.begin(), it));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
EndGroup();
|
EndGroup();
|
||||||
|
|
||||||
if (selected_cmd != -1) {
|
|
||||||
cmd_list_viewer[selected_cmd].Draw();
|
|
||||||
}
|
}
|
||||||
|
if (is_showing && selected_cmd != -1) {
|
||||||
|
cmd_list_viewer[selected_cmd].Draw(is_collapsed);
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ class FrameDumpViewer {
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
std::vector<CmdListViewer> cmd_list_viewer;
|
std::vector<CmdListViewer> cmd_list_viewer;
|
||||||
|
std::array<bool, 3> has_queue_type;
|
||||||
|
|
||||||
DebugStateType::QueueType selected_queue_type;
|
DebugStateType::QueueType selected_queue_type;
|
||||||
s32 selected_submit_num;
|
s32 selected_submit_num;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "cmd_list.h"
|
#include "cmd_list.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
using magic_enum::enum_name;
|
using magic_enum::enum_name;
|
||||||
|
@ -21,13 +22,13 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
DrawMultipleRow(
|
DrawValueRowList(
|
||||||
"BASE_ADDR", "%X", buffer.base_address,
|
"BASE_ADDR", buffer.base_address,
|
||||||
"PITCH.TILE_MAX", "%X", buffer.pitch.tile_max,
|
"PITCH.TILE_MAX", buffer.pitch.tile_max,
|
||||||
"PITCH.FMASK_TILE_MAX", "%X", buffer.pitch.fmask_tile_max,
|
"PITCH.FMASK_TILE_MAX", buffer.pitch.fmask_tile_max,
|
||||||
"SLICE.TILE_MAX", "%X", buffer.slice.tile_max,
|
"SLICE.TILE_MAX", buffer.slice.tile_max,
|
||||||
"VIEW.SLICE_START", "%X", buffer.view.slice_start,
|
"VIEW.SLICE_START", buffer.view.slice_start,
|
||||||
"VIEW.SLICE_MAX", "%X", buffer.view.slice_max
|
"VIEW.SLICE_MAX", buffer.view.slice_max
|
||||||
);
|
);
|
||||||
|
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
|
@ -49,31 +50,25 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
DrawMultipleRow(
|
DrawValueRowList(
|
||||||
"CMASK_BASE_EXT", "%X", buffer.cmask_base_address,
|
"CMASK_BASE_EXT", buffer.cmask_base_address,
|
||||||
"FMASK_BASE_EXT", "%X", buffer.fmask_base_address,
|
"FMASK_BASE_EXT", buffer.fmask_base_address,
|
||||||
"FMASK_SLICE.TILE_MAX", "%X", buffer.fmask_slice.tile_max,
|
"FMASK_SLICE.TILE_MAX", buffer.fmask_slice.tile_max,
|
||||||
"CLEAR_WORD0", "%X", buffer.clear_word0,
|
"CLEAR_WORD0", buffer.clear_word0,
|
||||||
"CLEAR_WORD1", "%X", buffer.clear_word1
|
"CLEAR_WORD1", buffer.clear_word1,
|
||||||
|
"Pitch()", buffer.Pitch(),
|
||||||
|
"Height()", buffer.Height(),
|
||||||
|
"Address()", buffer.Address(),
|
||||||
|
"CmaskAddress", buffer.CmaskAddress(),
|
||||||
|
"FmaskAddress", buffer.FmaskAddress(),
|
||||||
|
"NumSamples()", buffer.NumSamples(),
|
||||||
|
"NumSlices()", buffer.NumSlices(),
|
||||||
|
"GetColorSliceSize()", buffer.GetColorSliceSize(),
|
||||||
|
"GetTilingMode()", buffer.GetTilingMode(),
|
||||||
|
"IsTiled()", buffer.IsTiled(),
|
||||||
|
"NumFormat()", buffer.NumFormat()
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawMultipleRow(
|
|
||||||
"Pitch()", "%X", buffer.Pitch(),
|
|
||||||
"Height()", "%X", buffer.Height(),
|
|
||||||
"Address()", "%X", buffer.Address(),
|
|
||||||
"CmaskAddress", "%X", buffer.CmaskAddress(),
|
|
||||||
"FmaskAddress", "%X", buffer.FmaskAddress(),
|
|
||||||
"NumSamples()", "%X", buffer.NumSamples(),
|
|
||||||
"NumSlices()", "%X", buffer.NumSlices(),
|
|
||||||
"GetColorSliceSize()", "%X", buffer.GetColorSliceSize()
|
|
||||||
);
|
|
||||||
|
|
||||||
auto tiling_mode = buffer.GetTilingMode();
|
|
||||||
auto num_format = buffer.NumFormat();
|
|
||||||
DrawEnumRow("GetTilingMode()", tiling_mode);
|
|
||||||
DrawRow("IsTiled()", "%X", buffer.IsTiled());
|
|
||||||
DrawEnumRow("NumFormat()", num_format);
|
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
EndTable();
|
EndTable();
|
||||||
|
@ -89,37 +84,34 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
DrawEnumRow("Z_INFO.FORMAT", depth_buffer.z_info.format.Value());
|
DrawValueRowList(
|
||||||
DrawMultipleRow(
|
"Z_INFO.FORMAT", depth_buffer.z_info.format,
|
||||||
"Z_INFO.NUM_SAMPLES", "%X", depth_buffer.z_info.num_samples,
|
"Z_INFO.NUM_SAMPLES", depth_buffer.z_info.num_samples,
|
||||||
"Z_INFO.TILE_SPLIT", "%X", depth_buffer.z_info.tile_split,
|
"Z_INFO.TILE_SPLIT", depth_buffer.z_info.tile_split,
|
||||||
"Z_INFO.TILE_MODE_INDEX", "%X", depth_buffer.z_info.tile_mode_index,
|
"Z_INFO.TILE_MODE_INDEX", depth_buffer.z_info.tile_mode_index,
|
||||||
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", "%X", depth_buffer.z_info.decompress_on_n_zplanes,
|
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", depth_buffer.z_info.decompress_on_n_zplanes,
|
||||||
"Z_INFO.ALLOW_EXPCLEAR", "%X", depth_buffer.z_info.allow_expclear,
|
"Z_INFO.ALLOW_EXPCLEAR", depth_buffer.z_info.allow_expclear,
|
||||||
"Z_INFO.READ_SIZE", "%X", depth_buffer.z_info.read_size,
|
"Z_INFO.READ_SIZE", depth_buffer.z_info.read_size,
|
||||||
"Z_INFO.TILE_SURFACE_EN", "%X", depth_buffer.z_info.tile_surface_en,
|
"Z_INFO.TILE_SURFACE_EN", depth_buffer.z_info.tile_surface_en,
|
||||||
"Z_INFO.CLEAR_DISALLOWED", "%X", depth_buffer.z_info.clear_disallowed,
|
"Z_INFO.CLEAR_DISALLOWED", depth_buffer.z_info.clear_disallowed,
|
||||||
"Z_INFO.ZRANGE_PRECISION", "%X", depth_buffer.z_info.zrange_precision
|
"Z_INFO.ZRANGE_PRECISION", depth_buffer.z_info.zrange_precision,
|
||||||
);
|
"STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format,
|
||||||
|
"Z_READ_BASE", depth_buffer.z_read_base,
|
||||||
DrawEnumRow("STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format.Value());
|
"STENCIL_READ_BASE", depth_buffer.stencil_read_base,
|
||||||
|
"Z_WRITE_BASE", depth_buffer.z_write_base,
|
||||||
DrawMultipleRow(
|
"STENCIL_WRITE_BASE", depth_buffer.stencil_write_base,
|
||||||
"Z_READ_BASE", "%X", depth_buffer.z_read_base,
|
"DEPTH_SIZE.PITCH_TILE_MAX", depth_buffer.depth_size.pitch_tile_max,
|
||||||
"STENCIL_READ_BASE", "%X", depth_buffer.stencil_read_base,
|
"DEPTH_SIZE.HEIGHT_TILE_MAX", depth_buffer.depth_size.height_tile_max,
|
||||||
"Z_WRITE_BASE", "%X", depth_buffer.z_write_base,
|
"DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max,
|
||||||
"STENCIL_WRITE_BASE", "%X", depth_buffer.stencil_write_base,
|
"Pitch()", depth_buffer.Pitch(),
|
||||||
"DEPTH_SIZE.PITCH_TILE_MAX", "%X", depth_buffer.depth_size.pitch_tile_max,
|
"Height()", depth_buffer.Height(),
|
||||||
"DEPTH_SIZE.HEIGHT_TILE_MAX", "%X", depth_buffer.depth_size.height_tile_max,
|
"Address()", depth_buffer.Address(),
|
||||||
"DEPTH_SLICE.TILE_MAX", "%X", depth_buffer.depth_slice.tile_max,
|
"NumSamples()", depth_buffer.NumSamples(),
|
||||||
"Pitch()", "%X", depth_buffer.Pitch(),
|
"NumBits()", depth_buffer.NumBits(),
|
||||||
"Height()", "%X", depth_buffer.Height(),
|
"GetDepthSliceSize()", depth_buffer.GetDepthSliceSize()
|
||||||
"Address()", "%X", depth_buffer.Address(),
|
|
||||||
"NumSamples()", "%X", depth_buffer.NumSamples(),
|
|
||||||
"NumBits()", "%X", depth_buffer.NumBits(),
|
|
||||||
"GetDepthSliceSize()", "%X", depth_buffer.GetDepthSliceSize()
|
|
||||||
);
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
SeparatorText("Depth control");
|
SeparatorText("Depth control");
|
||||||
|
@ -127,19 +119,17 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
DrawMultipleRow(
|
DrawValueRowList(
|
||||||
"STENCIL_ENABLE", "%X", depth_control.stencil_enable,
|
"STENCIL_ENABLE", depth_control.stencil_enable,
|
||||||
"DEPTH_ENABLE", "%X", depth_control.depth_enable,
|
"DEPTH_ENABLE", depth_control.depth_enable,
|
||||||
"DEPTH_WRITE_ENABLE", "%X", depth_control.depth_write_enable,
|
"DEPTH_WRITE_ENABLE", depth_control.depth_write_enable,
|
||||||
"DEPTH_BOUNDS_ENABLE", "%X", depth_control.depth_bounds_enable
|
"DEPTH_BOUNDS_ENABLE", depth_control.depth_bounds_enable,
|
||||||
);
|
"DEPTH_FUNC", depth_control.depth_func,
|
||||||
DrawEnumRow("DEPTH_FUNC", depth_control.depth_func.Value());
|
"BACKFACE_ENABLE", depth_control.backface_enable,
|
||||||
DrawRow("BACKFACE_ENABLE", "%X", depth_control.backface_enable);
|
"STENCIL_FUNC", depth_control.stencil_ref_func,
|
||||||
DrawEnumRow("STENCIL_FUNC", depth_control.stencil_ref_func.Value());
|
"STENCIL_FUNC_BF", depth_control.stencil_bf_func,
|
||||||
DrawEnumRow("STENCIL_FUNC_BF", depth_control.stencil_bf_func.Value());
|
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", depth_control.enable_color_writes_on_depth_fail,
|
||||||
DrawMultipleRow(
|
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", depth_control.disable_color_writes_on_depth_pass
|
||||||
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", "%X", depth_control.enable_color_writes_on_depth_fail,
|
|
||||||
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", "%X", depth_control.disable_color_writes_on_depth_pass
|
|
||||||
);
|
);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
@ -152,24 +142,45 @@ RegPopup::RegPopup() {
|
||||||
id = unique_id++;
|
id = unique_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegPopup::SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id) {
|
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
|
||||||
|
u32 cb_id) {
|
||||||
this->data = color_buffer;
|
this->data = color_buffer;
|
||||||
this->title = fmt::format("Batch #{} CB #{}", batch_id, cb_id);
|
this->title = fmt::format("{}/CB #{}", base_title, cb_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegPopup::SetData(AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||||
AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id) {
|
AmdGpu::Liverpool::DepthControl depth_control) {
|
||||||
this->data = std::make_tuple(depth_buffer, depth_control);
|
this->data = std::make_tuple(depth_buffer, depth_control);
|
||||||
this->title = fmt::format("Batch #{} Depth", batch_id);
|
this->title = fmt::format("{}/Depth", base_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegPopup::SetPos(ImVec2 pos, bool auto_resize) {
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, sizeof(name), "%s###reg_popup_%d", title.c_str(), id);
|
||||||
|
Begin(name, &open, flags);
|
||||||
|
SetWindowPos(pos);
|
||||||
|
if (auto_resize) {
|
||||||
|
if (std::holds_alternative<AmdGpu::Liverpool::ColorBuffer>(data)) {
|
||||||
|
SetWindowSize({365.0f, 520.0f});
|
||||||
|
KeepWindowInside();
|
||||||
|
} else if (std::holds_alternative<DepthBuffer>(data)) {
|
||||||
|
SetWindowSize({404.0f, 543.0f});
|
||||||
|
KeepWindowInside();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_pos = GetWindowPos();
|
||||||
|
moved = false;
|
||||||
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegPopup::Draw() {
|
void RegPopup::Draw() {
|
||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, sizeof(name), "%s###reg_popup_%d", title.c_str(), id);
|
snprintf(name, sizeof(name), "%s###reg_popup_%d", title.c_str(), id);
|
||||||
|
if (Begin(name, &open, flags)) {
|
||||||
|
if (GetWindowPos() != last_pos) {
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
|
||||||
SetNextWindowSize({250.0f, 300.0f}, ImGuiCond_FirstUseEver);
|
|
||||||
if (Begin(name, &open, ImGuiWindowFlags_NoSavedSettings)) {
|
|
||||||
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
|
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
|
||||||
DrawColorBuffer(*buffer);
|
DrawColorBuffer(*buffer);
|
||||||
} else if (const auto* depth_data = std::get_if<DepthBuffer>(&data)) {
|
} else if (const auto* depth_data = std::get_if<DepthBuffer>(&data)) {
|
||||||
|
@ -178,5 +189,4 @@ void RegPopup::Draw() {
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||||
|
|
||||||
|
@ -12,25 +14,31 @@ namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
class RegPopup {
|
class RegPopup {
|
||||||
int id;
|
int id;
|
||||||
|
ImGuiWindowFlags flags{ImGuiWindowFlags_NoSavedSettings};
|
||||||
|
|
||||||
using DepthBuffer = std::tuple<AmdGpu::Liverpool::DepthBuffer, AmdGpu::Liverpool::DepthControl>;
|
using DepthBuffer = std::tuple<AmdGpu::Liverpool::DepthBuffer, AmdGpu::Liverpool::DepthControl>;
|
||||||
|
|
||||||
|
ImVec2 last_pos;
|
||||||
std::variant<AmdGpu::Liverpool::ColorBuffer, DepthBuffer> data;
|
std::variant<AmdGpu::Liverpool::ColorBuffer, DepthBuffer> data;
|
||||||
std::string title{};
|
std::string title{};
|
||||||
|
|
||||||
void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
static void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
||||||
|
|
||||||
void DrawDepthBuffer(const DepthBuffer& depth_data);
|
static void DrawDepthBuffer(const DepthBuffer& depth_data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
bool moved = false;
|
||||||
|
|
||||||
RegPopup();
|
RegPopup();
|
||||||
|
|
||||||
void SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id);
|
void SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
|
||||||
|
u32 cb_id);
|
||||||
|
|
||||||
void SetData(AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
void SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||||
AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id);
|
AmdGpu::Liverpool::DepthControl depth_control);
|
||||||
|
|
||||||
|
void SetPos(ImVec2 pos, bool auto_resize = false);
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "common/io_file.h"
|
#include "common/io_file.h"
|
||||||
#include "core/devtools/options.h"
|
#include "core/devtools/options.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "reg_view.h"
|
#include "reg_view.h"
|
||||||
|
|
||||||
|
@ -22,6 +23,8 @@
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
using magic_enum::enum_name;
|
using magic_enum::enum_name;
|
||||||
|
|
||||||
|
constexpr auto depth_id = 0xF3;
|
||||||
|
|
||||||
static std::optional<std::string> exec_cli(const char* cli) {
|
static std::optional<std::string> exec_cli(const char* cli) {
|
||||||
std::array<char, 64> buffer{};
|
std::array<char, 64> buffer{};
|
||||||
std::string output;
|
std::string output;
|
||||||
|
@ -40,7 +43,16 @@ static std::optional<std::string> exec_cli(const char* cli) {
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
void RegView::ProcessShader(int shader_id) {
|
void RegView::ProcessShader(int shader_id) {
|
||||||
auto shader = data.stages[shader_id];
|
std::vector<u32> shader_code;
|
||||||
|
Vulkan::Liverpool::UserData user_data;
|
||||||
|
if (data.is_compute) {
|
||||||
|
shader_code = data.cs_data.code;
|
||||||
|
user_data = data.cs_data.cs_program.user_data;
|
||||||
|
} else {
|
||||||
|
const auto& s = data.stages[shader_id];
|
||||||
|
shader_code = s.code;
|
||||||
|
user_data = s.user_data.user_data;
|
||||||
|
}
|
||||||
|
|
||||||
std::string shader_dis;
|
std::string shader_dis;
|
||||||
|
|
||||||
|
@ -57,7 +69,7 @@ void RegView::ProcessShader(int shader_id) {
|
||||||
} else {
|
} else {
|
||||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||||
file.Write(shader.code);
|
file.Write(shader_code);
|
||||||
file.Close();
|
file.Close();
|
||||||
|
|
||||||
auto result = exec_cli(cli.c_str());
|
auto result = exec_cli(cli.c_str());
|
||||||
|
@ -73,8 +85,9 @@ void RegView::ProcessShader(int shader_id) {
|
||||||
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 = 16;
|
hex_view.Cols = 8;
|
||||||
hex_view.OptShowAscii = false;
|
hex_view.OptShowAscii = false;
|
||||||
|
hex_view.OptShowOptions = false;
|
||||||
|
|
||||||
TextEditor dis_view;
|
TextEditor dis_view;
|
||||||
dis_view.SetPalette(TextEditor::GetDarkPalette());
|
dis_view.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
@ -84,7 +97,7 @@ void RegView::ProcessShader(int shader_id) {
|
||||||
ShaderCache cache{
|
ShaderCache cache{
|
||||||
.hex_view = hex_view,
|
.hex_view = hex_view,
|
||||||
.dis_view = dis_view,
|
.dis_view = dis_view,
|
||||||
.user_data = shader.user_data.user_data,
|
.user_data = user_data,
|
||||||
};
|
};
|
||||||
shader_decomp.emplace(shader_id, std::move(cache));
|
shader_decomp.emplace(shader_id, std::move(cache));
|
||||||
}
|
}
|
||||||
|
@ -95,34 +108,64 @@ void RegView::SelectShader(int id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegView::DrawRegs() {
|
void RegView::DrawComputeRegs() {
|
||||||
|
const auto& cs = data.cs_data.cs_program;
|
||||||
|
|
||||||
|
if (BeginTable("CREGS", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
DrawValueRowList(
|
||||||
|
"DISPATCH_INITIATOR", cs.dispatch_initiator,
|
||||||
|
"DIM_X", cs.dim_x,
|
||||||
|
"DIM_Y", cs.dim_y,
|
||||||
|
"DIM_Z", cs.dim_z,
|
||||||
|
"START_X", cs.start_x,
|
||||||
|
"START_Y", cs.start_y,
|
||||||
|
"START_Z", cs.start_z,
|
||||||
|
"NUM_THREAD_X.FULL", cs.num_thread_x.full,
|
||||||
|
"NUM_THREAD_X.PARTIAL", cs.num_thread_x.partial,
|
||||||
|
"NUM_THREAD_Y.FULL", cs.num_thread_y.full,
|
||||||
|
"NUM_THREAD_Y.PARTIAL", cs.num_thread_y.partial,
|
||||||
|
"NUM_THREAD_Z.FULL", cs.num_thread_z.full,
|
||||||
|
"NUM_THREAD_Z.PARTIAL", cs.num_thread_z.partial,
|
||||||
|
"MAX_WAVE_ID", cs.max_wave_id,
|
||||||
|
"SETTINGS.NUM_VGPRS", cs.settings.num_vgprs,
|
||||||
|
"SETTINGS.NUM_SGPRS", cs.settings.num_sgprs,
|
||||||
|
"SETTINGS.NUM_USER_REGS", cs.settings.num_user_regs,
|
||||||
|
"SETTINGS.TGID_ENABLE", cs.settings.tgid_enable,
|
||||||
|
"SETTINGS.LDS_DWORDS", cs.settings.lds_dwords,
|
||||||
|
"RESOURCE_LIMITS", cs.resource_limits
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::DrawGraphicsRegs() {
|
||||||
const auto& regs = data.regs;
|
const auto& regs = data.regs;
|
||||||
|
|
||||||
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
auto& s = regs.screen_scissor;
|
DrawValueRow("Primitive type", regs.primitive_type);
|
||||||
DrawRow("Scissor", "(%d, %d, %d, %d)", s.top_left_x, s.top_left_y, s.bottom_right_x,
|
|
||||||
s.bottom_right_y);
|
|
||||||
|
|
||||||
auto cc_mode = regs.color_control.mode.Value();
|
|
||||||
DrawRow("Color control", "%X (%s)", cc_mode, enum_name(cc_mode).data());
|
|
||||||
|
|
||||||
const auto open_new_popup = [&](int cb, auto... args) {
|
const auto open_new_popup = [&](int cb, auto... args) {
|
||||||
|
const auto pos = GetItemRectMax() + ImVec2(5.0f, 0.0f);
|
||||||
if (GetIO().KeyShift) {
|
if (GetIO().KeyShift) {
|
||||||
auto& pop = extra_reg_popup.emplace_back();
|
auto& pop = extra_reg_popup.emplace_back();
|
||||||
pop.SetData(args...);
|
pop.SetData(title, args...);
|
||||||
pop.open = true;
|
pop.open = true;
|
||||||
|
pop.SetPos(pos, true);
|
||||||
} else if (last_selected_cb == cb && default_reg_popup.open) {
|
} else if (last_selected_cb == cb && default_reg_popup.open) {
|
||||||
default_reg_popup.open = false;
|
default_reg_popup.open = false;
|
||||||
} else {
|
} else {
|
||||||
last_selected_cb = cb;
|
last_selected_cb = cb;
|
||||||
default_reg_popup.SetData(args...);
|
default_reg_popup.SetData(title, args...);
|
||||||
if (!default_reg_popup.open) {
|
if (!default_reg_popup.open || !default_reg_popup.moved) {
|
||||||
default_reg_popup.open = true;
|
default_reg_popup.open = true;
|
||||||
auto popup_pos =
|
default_reg_popup.SetPos(pos, true);
|
||||||
GetCurrentContext()->LastItemData.Rect.Max + ImVec2(5.0f, 0.0f);
|
|
||||||
SetNextWindowPos(popup_pos, ImGuiCond_Always);
|
|
||||||
default_reg_popup.Draw();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -142,7 +185,7 @@ void RegView::DrawRegs() {
|
||||||
} else {
|
} else {
|
||||||
const char* text = last_selected_cb == cb && default_reg_popup.open ? "x" : "->";
|
const char* text = last_selected_cb == cb && default_reg_popup.open ? "x" : "->";
|
||||||
if (SmallButton(text)) {
|
if (SmallButton(text)) {
|
||||||
open_new_popup(cb, buffer, batch_id, cb);
|
open_new_popup(cb, buffer, cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,13 +199,30 @@ void RegView::DrawRegs() {
|
||||||
if (regs.depth_buffer.Address() == 0 || !regs.depth_control.depth_enable) {
|
if (regs.depth_buffer.Address() == 0 || !regs.depth_control.depth_enable) {
|
||||||
TextUnformatted("N/A");
|
TextUnformatted("N/A");
|
||||||
} else {
|
} else {
|
||||||
constexpr auto depth_id = 0xF3;
|
|
||||||
const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->";
|
const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->";
|
||||||
if (SmallButton(text)) {
|
if (SmallButton(text)) {
|
||||||
open_new_popup(depth_id, regs.depth_buffer, regs.depth_control, batch_id);
|
open_new_popup(depth_id, regs.depth_buffer, regs.depth_control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& s = regs.screen_scissor;
|
||||||
|
DrawRow("Scissor", "(%d, %d, %d, %d)", s.top_left_x, s.top_left_y, s.bottom_right_x,
|
||||||
|
s.bottom_right_y);
|
||||||
|
|
||||||
|
DrawValueRow("Color control", regs.color_control.mode);
|
||||||
|
|
||||||
|
DrawRow("Primitive restart", "%X (IDX: %X)", regs.enable_primitive_restart & 1,
|
||||||
|
regs.primitive_restart_index);
|
||||||
|
// clang-format off
|
||||||
|
DrawValueRowList(
|
||||||
|
"Polygon mode", regs.polygon_control.PolyMode(),
|
||||||
|
"Cull mode", regs.polygon_control.CullingMode(),
|
||||||
|
"Clip Space", regs.clipper_control.clip_space,
|
||||||
|
"Front face", regs.polygon_control.front_face,
|
||||||
|
"Num Samples", regs.aa_config.NumSamples()
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,9 +232,9 @@ RegView::RegView() {
|
||||||
id = unique_id++;
|
id = unique_id++;
|
||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, sizeof(name), "BatchView###reg_dump_%d", id);
|
snprintf(name, sizeof(name), "###reg_dump_%d", id);
|
||||||
SetNextWindowPos({400.0f, 200.0f});
|
SetNextWindowPos({400.0f, 200.0f});
|
||||||
SetNextWindowSize({450.0f, 500.0f});
|
SetNextWindowSize({290.0f, 435.0f});
|
||||||
ImGuiID root_dock_id;
|
ImGuiID root_dock_id;
|
||||||
Begin(name);
|
Begin(name);
|
||||||
{
|
{
|
||||||
|
@ -188,7 +248,7 @@ RegView::RegView() {
|
||||||
ImGuiID up1, down1;
|
ImGuiID up1, down1;
|
||||||
|
|
||||||
DockBuilderRemoveNodeChildNodes(root_dock_id);
|
DockBuilderRemoveNodeChildNodes(root_dock_id);
|
||||||
DockBuilderSplitNode(root_dock_id, ImGuiDir_Up, 0.2f, &up1, &down1);
|
DockBuilderSplitNode(root_dock_id, ImGuiDir_Up, 0.19f, &up1, &down1);
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
DockBuilderDockWindow(name, up1);
|
DockBuilderDockWindow(name, up1);
|
||||||
|
@ -202,35 +262,68 @@ RegView::RegView() {
|
||||||
DockBuilderFinish(root_dock_id);
|
DockBuilderFinish(root_dock_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegView::SetData(DebugStateType::RegDump data, u32 batch_id) {
|
void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_title, u32 batch_id) {
|
||||||
this->data = std::move(data);
|
this->data = std::move(_data);
|
||||||
this->batch_id = batch_id;
|
this->batch_id = batch_id;
|
||||||
|
this->title = fmt::format("{}/Batch {}", base_title, batch_id);
|
||||||
// clear cache
|
// clear cache
|
||||||
selected_shader = -1;
|
|
||||||
shader_decomp.clear();
|
shader_decomp.clear();
|
||||||
|
if (data.is_compute) {
|
||||||
|
selected_shader = -2;
|
||||||
|
last_selected_cb = -1;
|
||||||
default_reg_popup.open = false;
|
default_reg_popup.open = false;
|
||||||
|
ProcessShader(-2);
|
||||||
|
} else {
|
||||||
|
const auto& regs = data.regs;
|
||||||
|
if (selected_shader >= 0 && !regs.stage_enable.IsStageEnabled(selected_shader)) {
|
||||||
|
selected_shader = -1;
|
||||||
|
}
|
||||||
|
if (default_reg_popup.open) {
|
||||||
|
default_reg_popup.open = false;
|
||||||
|
if (last_selected_cb == depth_id) {
|
||||||
|
const auto& has_depth =
|
||||||
|
regs.depth_buffer.Address() != 0 && regs.depth_control.depth_enable;
|
||||||
|
if (has_depth) {
|
||||||
|
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
|
||||||
|
default_reg_popup.open = true;
|
||||||
|
}
|
||||||
|
} else if (last_selected_cb >= 0 &&
|
||||||
|
last_selected_cb < AmdGpu::Liverpool::NumColorBuffers) {
|
||||||
|
const auto& buffer = regs.color_buffers[last_selected_cb];
|
||||||
|
const bool has_cb = buffer && regs.color_target_mask.GetMask(last_selected_cb);
|
||||||
|
if (has_cb) {
|
||||||
|
default_reg_popup.SetData(title, buffer, last_selected_cb);
|
||||||
|
default_reg_popup.open = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
extra_reg_popup.clear();
|
extra_reg_popup.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegView::Draw() {
|
void RegView::SetPos(ImVec2 pos) {
|
||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
snprintf(name, sizeof(name), "BatchView %u###reg_dump_%d", batch_id, id);
|
snprintf(name, sizeof(name), "%s###reg_dump_%d", title.c_str(), id);
|
||||||
|
Begin(name, &open, ImGuiWindowFlags_MenuBar);
|
||||||
|
SetWindowPos(pos);
|
||||||
|
KeepWindowInside();
|
||||||
|
last_pos = GetWindowPos();
|
||||||
|
moved = false;
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::Draw() {
|
||||||
|
char name[128];
|
||||||
|
snprintf(name, sizeof(name), "%s###reg_dump_%d", title.c_str(), id);
|
||||||
|
|
||||||
if (Begin(name, &open, ImGuiWindowFlags_MenuBar)) {
|
if (Begin(name, &open, ImGuiWindowFlags_MenuBar)) {
|
||||||
|
if (GetWindowPos() != last_pos) {
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
|
||||||
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
||||||
|
|
||||||
if (BeginMenuBar()) {
|
if (BeginMenuBar()) {
|
||||||
if (BeginMenu("Stage")) {
|
|
||||||
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
|
||||||
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
|
||||||
bool selected = selected_shader == i;
|
|
||||||
if (Selectable(names[i], &selected)) {
|
|
||||||
SelectShader(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
if (BeginMenu("Windows")) {
|
if (BeginMenu("Windows")) {
|
||||||
Checkbox("Registers", &show_registers);
|
Checkbox("Registers", &show_registers);
|
||||||
Checkbox("User data", &show_user_data);
|
Checkbox("User data", &show_user_data);
|
||||||
|
@ -240,11 +333,31 @@ void RegView::Draw() {
|
||||||
EndMenuBar();
|
EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data.is_compute &&
|
||||||
|
BeginChild("STAGES", {},
|
||||||
|
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {
|
||||||
|
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
||||||
|
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
const bool selected = selected_shader == i;
|
||||||
|
if (selected) {
|
||||||
|
PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
|
}
|
||||||
|
if (Button(names[i], {40.0f, 40.0f})) {
|
||||||
|
SelectShader(i);
|
||||||
|
}
|
||||||
|
if (selected) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SameLine();
|
||||||
|
}
|
||||||
|
EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
char dock_name[64];
|
char dock_name[64];
|
||||||
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
||||||
auto root_dock_id = ImHashStr(dock_name);
|
auto root_dock_id = ImHashStr(dock_name);
|
||||||
DockSpace(root_dock_id);
|
DockSpace(root_dock_id);
|
||||||
}
|
|
||||||
End();
|
End();
|
||||||
|
|
||||||
auto get_shader = [&]() -> ShaderCache* {
|
auto get_shader = [&]() -> ShaderCache* {
|
||||||
|
@ -257,10 +370,11 @@ void RegView::Draw() {
|
||||||
|
|
||||||
if (show_user_data) {
|
if (show_user_data) {
|
||||||
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
if (Begin(name, &show_user_data)) {
|
|
||||||
|
if (Begin(name, &show_user_data, ImGuiWindowFlags_NoScrollbar)) {
|
||||||
auto shader = get_shader();
|
auto shader = get_shader();
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
Text("Select a stage");
|
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());
|
||||||
}
|
}
|
||||||
|
@ -273,7 +387,7 @@ void RegView::Draw() {
|
||||||
if (Begin(name, &show_disassembly)) {
|
if (Begin(name, &show_disassembly)) {
|
||||||
auto shader = get_shader();
|
auto shader = get_shader();
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
Text("Select a stage");
|
Text("Stage not selected");
|
||||||
} else {
|
} else {
|
||||||
shader->dis_view.Render("Disassembly", GetContentRegionAvail());
|
shader->dis_view.Render("Disassembly", GetContentRegionAvail());
|
||||||
}
|
}
|
||||||
|
@ -284,7 +398,11 @@ void RegView::Draw() {
|
||||||
if (show_registers) {
|
if (show_registers) {
|
||||||
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
||||||
if (Begin(name, &show_registers)) {
|
if (Begin(name, &show_registers)) {
|
||||||
DrawRegs();
|
if (data.is_compute) {
|
||||||
|
DrawComputeRegs();
|
||||||
|
} else {
|
||||||
|
DrawGraphicsRegs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,10 @@ struct ShaderCache {
|
||||||
class RegView {
|
class RegView {
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
std::string title;
|
||||||
DebugStateType::RegDump data;
|
DebugStateType::RegDump data;
|
||||||
u32 batch_id{~0u};
|
u32 batch_id{~0u};
|
||||||
|
ImVec2 last_pos;
|
||||||
|
|
||||||
std::unordered_map<int, ShaderCache> shader_decomp;
|
std::unordered_map<int, ShaderCache> shader_decomp;
|
||||||
int selected_shader{-1};
|
int selected_shader{-1};
|
||||||
|
@ -35,14 +37,19 @@ class RegView {
|
||||||
|
|
||||||
void SelectShader(int shader_id);
|
void SelectShader(int shader_id);
|
||||||
|
|
||||||
void DrawRegs();
|
void DrawComputeRegs();
|
||||||
|
|
||||||
|
void DrawGraphicsRegs();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
bool moved = false;
|
||||||
|
|
||||||
RegView();
|
RegView();
|
||||||
|
|
||||||
void SetData(DebugStateType::RegDump data, u32 batch_id);
|
void SetData(DebugStateType::RegDump data, const std::string& base_title, u32 batch_id);
|
||||||
|
|
||||||
|
void SetPos(ImVec2 pos);
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
};
|
};
|
||||||
|
|
|
@ -245,7 +245,7 @@ void ImeDialogUi::Draw() {
|
||||||
window_size = {500.0f, 150.0f};
|
window_size = {500.0f, 150.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ inline void CentralizeNextWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CentralizeWindow() {
|
inline void CentralizeWindow() {
|
||||||
const auto display_size = GetIO().DisplaySize;
|
const auto display_size = GetIO().DisplaySize - GetCurrentWindowRead()->SizeFull;
|
||||||
SetWindowPos(display_size / 2.0f);
|
SetWindowPos(display_size / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
|
||||||
SetWindowPos(ImMax(cur_pos, ImVec2(0.0f, 0.0f)));
|
SetWindowPos(ImMax(cur_pos, ImVec2(0.0f, 0.0f)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto cur_size = GetWindowSize();
|
const auto cur_size = GetCurrentWindowRead()->SizeFull;
|
||||||
const auto bottom_right = cur_pos + cur_size;
|
const auto bottom_right = cur_pos + cur_size;
|
||||||
if (bottom_right.x > display_size.x || bottom_right.y > display_size.y) {
|
if (bottom_right.x > display_size.x || bottom_right.y > display_size.y) {
|
||||||
const auto max_pos = display_size - cur_size;
|
const auto max_pos = display_size - cur_size;
|
||||||
|
|
|
@ -446,7 +446,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
|
@ -463,7 +464,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
||||||
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
||||||
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
|
@ -645,7 +647,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs, true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
|
|
Loading…
Reference in a new issue