From 25de4d6b653187386e4f8da0532525fcaca28f57 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Wed, 16 Oct 2024 07:12:46 -0300 Subject: [PATCH] Devtools improvements I (#1392) * 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 --- src/common/bit_field.h | 5 +- src/core/debug_state.cpp | 33 ++- src/core/debug_state.h | 16 +- src/core/devtools/help.txt | 8 + src/core/devtools/layer.cpp | 35 +++ src/core/devtools/options.cpp | 6 + src/core/devtools/options.h | 3 +- src/core/devtools/widget/cmd_list.cpp | 47 ++-- src/core/devtools/widget/cmd_list.h | 4 +- src/core/devtools/widget/common.h | 23 +- src/core/devtools/widget/frame_dump.cpp | 63 ++++-- src/core/devtools/widget/frame_dump.h | 1 + src/core/devtools/widget/reg_popup.cpp | 172 ++++++++------- src/core/devtools/widget/reg_popup.h | 18 +- src/core/devtools/widget/reg_view.cpp | 218 ++++++++++++++----- src/core/devtools/widget/reg_view.h | 11 +- src/core/libraries/dialogs/ime_dialog_ui.cpp | 2 +- src/imgui/imgui_std.h | 4 +- src/video_core/amdgpu/liverpool.cpp | 8 +- 19 files changed, 474 insertions(+), 203 deletions(-) create mode 100644 src/core/devtools/help.txt diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 72af7b5c..bc8a2763 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h @@ -81,7 +81,9 @@ #pragma pack(1) template struct BitField { -private: + + using Type = T; + // 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 // 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 using StorageType = std::make_unsigned_t; -public: /// Constants to allow limited introspection of fields if needed static constexpr std::size_t position = Position; static constexpr std::size_t bits = Bits; diff --git a/src/core/debug_state.cpp b/src/core/debug_state.cpp index 93b00285..adcb0cad 100644 --- a/src/core/debug_state.cpp +++ b/src/core/debug_state.cpp @@ -102,6 +102,10 @@ void DebugStateImpl::RequestFrameDump(s32 count) { gnm_frame_dump_request_count = count; frame_dump_list.clear(); 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; } @@ -139,7 +143,7 @@ void DebugStateImpl::PushQueueDump(QueueDump dump) { } 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}; const auto it = waiting_reg_dumps.find(header_addr); if (it == waiting_reg_dumps.end()) { @@ -150,15 +154,24 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr, waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr)); auto& dump = frame.regs[header_addr - base_addr]; dump.regs = regs; - for (int i = 0; i < RegDump::MaxShaderStages; i++) { - if (regs.stage_enable.IsStageEnabled(i)) { - auto stage = regs.ProgramForStage(i); - if (stage->address_lo != 0) { - auto code = stage->Code(); - dump.stages[i] = ShaderDump{ - .user_data = *stage, - .code = std::vector{code.begin(), code.end()}, - }; + if (is_compute) { + dump.is_compute = true; + const auto& cs = dump.regs.cs_program; + dump.cs_data = ComputerShaderDump{ + .cs_program = cs, + .code = std::vector{cs.Code().begin(), cs.Code().end()}, + }; + } else { + for (int i = 0; i < RegDump::MaxShaderStages; i++) { + if (regs.stage_enable.IsStageEnabled(i)) { + auto stage = regs.ProgramForStage(i); + if (stage->address_lo != 0) { + auto code = stage->Code(); + dump.stages[i] = ShaderDump{ + .user_data = *stage, + .code = std::vector{code.begin(), code.end()}, + }; + } } } } diff --git a/src/core/debug_state.h b/src/core/debug_state.h index 26dfa202..cd1c6aa9 100644 --- a/src/core/debug_state.h +++ b/src/core/debug_state.h @@ -36,9 +36,9 @@ class FrameGraph; namespace DebugStateType { enum class QueueType { - acb, - dcb, - ccb, + dcb = 0, + ccb = 1, + acb = 2, }; struct QueueDump { @@ -54,13 +54,21 @@ struct ShaderDump { std::vector code{}; }; +struct ComputerShaderDump { + Vulkan::Liverpool::ComputeProgram cs_program{}; + std::vector code{}; +}; + struct RegDump { + bool is_compute{false}; static constexpr size_t MaxShaderStages = 5; Vulkan::Liverpool::Regs regs{}; std::array stages{}; + ComputerShaderDump cs_data{}; }; struct FrameDump { + u32 frame_id; std::vector queues; std::unordered_map regs; // address -> reg dump }; @@ -143,7 +151,7 @@ public: void PushQueueDump(QueueDump dump); 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 diff --git a/src/core/devtools/help.txt b/src/core/devtools/help.txt new file mode 100644 index 00000000..9670c5ce --- /dev/null +++ b/src/core/devtools/help.txt @@ -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}" +)" \ No newline at end of file diff --git a/src/core/devtools/layer.cpp b/src/core/devtools/layer.cpp index 17ef43bb..38b17c86 100644 --- a/src/core/devtools/layer.cpp +++ b/src/core/devtools/layer.cpp @@ -31,6 +31,12 @@ static float debug_popup_timing = 3.0f; static bool just_opened_options = false; +// clang-format off +static std::string help_text = +#include "help.txt" + ; +// clang-format on + void L::DrawMenuBar() { const auto& ctx = *GImGui; const auto& io = ctx.IO; @@ -38,6 +44,7 @@ void L::DrawMenuBar() { auto isSystemPaused = DebugState.IsGuestThreadsPaused(); bool open_popup_options = false; + bool open_popup_help = false; if (BeginMainMenuBar()) { if (BeginMenu("Options")) { @@ -60,6 +67,7 @@ void L::DrawMenuBar() { ImGui::EndMenu(); } open_popup_options = MenuItem("Options"); + open_popup_help = MenuItem("Help & Tips"); ImGui::EndMenu(); } EndMainMenuBar(); @@ -84,6 +92,9 @@ void L::DrawMenuBar() { OpenPopup("GPU Tools Options"); just_opened_options = true; } + if (open_popup_help) { + OpenPopup("HelpTips"); + } } void L::DrawAdvanced() { @@ -154,25 +165,49 @@ void L::DrawAdvanced() { if (BeginPopupModal("GPU Tools Options", &close_popup_options, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) { static char disassembly_cli[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'; + frame_dump_render_on_collapse = Options.frame_dump_render_on_collapse; } InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli)); if (IsItemHovered()) { 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")) { Options.disassembly_cli = disassembly_cli; + Options.frame_dump_render_on_collapse = frame_dump_render_on_collapse; SaveIniSettingsToDisk(io.IniFilename); CloseCurrentPopup(); } 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() { diff --git a/src/core/devtools/options.cpp b/src/core/devtools/options.cpp index 82fa6e87..1b49da76 100644 --- a/src/core/devtools/options.cpp +++ b/src/core/devtools/options.cpp @@ -11,14 +11,20 @@ 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; 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) { 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 diff --git a/src/core/devtools/options.h b/src/core/devtools/options.h index 9d291d76..c3a8aaf3 100644 --- a/src/core/devtools/options.h +++ b/src/core/devtools/options.h @@ -10,7 +10,8 @@ struct ImGuiTextBuffer; namespace Core::Devtools { struct TOptions { - std::string disassembly_cli; + std::string disassembly_cli{}; + bool frame_dump_render_on_collapse{false}; }; extern TOptions Options; diff --git a/src/core/devtools/widget/cmd_list.cpp b/src/core/devtools/widget/cmd_list.cpp index f5d31efe..9a42f823 100644 --- a/src/core/devtools/widget/cmd_list.cpp +++ b/src/core/devtools/widget/cmd_list.cpp @@ -1173,7 +1173,7 @@ CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump, } } -void CmdListViewer::Draw() { +void CmdListViewer::Draw(bool only_batches_view) { const auto& ctx = *GetCurrentContext(); if (batch_view.open) { @@ -1188,6 +1188,10 @@ void CmdListViewer::Draw() { ++it; } + if (only_batches_view) { + return; + } + if (cmdb_view.Open) { MemoryEditor::Sizes s; cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr); @@ -1228,7 +1232,7 @@ void CmdListViewer::Draw() { Text("size : %04llX", cmdb_size); Separator(); - if (TreeNode("Batches")) { + { int tree_depth = 0; int tree_depth_show = 0; @@ -1283,9 +1287,10 @@ void CmdListViewer::Draw() { auto const* pm4_hdr = reinterpret_cast(cmdb_addr + batch.start_addr); + bool ignore_header = false; char batch_hdr[128]; if (batch.type == static_cast(0xFF)) { - snprintf(batch_hdr, sizeof(batch_hdr), "State batch"); + ignore_header = true; } else if (!batch.marker.empty()) { snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d %s | %s", cmdb_addr + batch.start_addr, batch.id, @@ -1309,22 +1314,35 @@ void CmdListViewer::Draw() { auto data = frame_dump->regs.at(batch.command_addr); if (GetIO().KeyShift) { auto& pop = extra_batch_view.emplace_back(); - pop.SetData(data, batch_id); + pop.SetData(data, name, batch_id); pop.open = true; } else { - batch_view.SetData(data, batch_id); - batch_view.open = true; + if (batch_view.open && + this->last_selected_batch == static_cast(batch_id)) { + batch_view.open = false; + } else { + this->last_selected_batch = static_cast(batch_id); + batch_view.SetData(data, name, batch_id); + if (!batch_view.open || !batch_view.moved) { + batch_view.open = true; + const auto pos = GetItemRectMax() + ImVec2{5.0f, 0.0f}; + batch_view.SetPos(pos); + } + } } } }; bool show_batch_content = true; - if (group_batches) { + if (group_batches && !ignore_header) { show_batch_content = CollapsingHeader(batch_hdr, ImGuiTreeNodeFlags_AllowOverlap); SameLine(GetContentRegionAvail().x - 40.0f); - if (Button("->", {40.0f, 0.0f})) { + const char* text = + last_selected_batch == static_cast(batch_id) && batch_view.open ? "X" + : "->"; + if (Button(text, {40.0f, 0.0f})) { open_batch_view(); } } @@ -1332,7 +1350,7 @@ void CmdListViewer::Draw() { if (show_batch_content) { auto processed_size = 0ull; auto bb = ctx.LastItemData.Rect; - if (group_batches) { + if (group_batches && !ignore_header) { Indent(); } auto const batch_sz = batch.end_addr - batch.start_addr; @@ -1354,7 +1372,12 @@ void CmdListViewer::Draw() { if (!group_batches) { if (IsDrawCall(op)) { SameLine(GetContentRegionAvail().x - 40.0f); - if (Button("->", {40.0f, 0.0f})) { + const char* text = + last_selected_batch == static_cast(batch_id) && + batch_view.open + ? "X" + : "->"; + if (Button(text, {40.0f, 0.0f})) { open_batch_view(); } } @@ -1426,7 +1449,7 @@ void CmdListViewer::Draw() { processed_size += processed_len; } - if (group_batches) { + if (group_batches && !ignore_header) { Unindent(); }; bb = {{0.0f, bb.Max.y}, ctx.LastItemData.Rect.Max}; @@ -1450,8 +1473,6 @@ void CmdListViewer::Draw() { PopID(); highlight_batch = current_highlight_batch; - - TreePop(); } } EndChild(); diff --git a/src/core/devtools/widget/cmd_list.h b/src/core/devtools/widget/cmd_list.h index 971c8fff..ed71d0b7 100644 --- a/src/core/devtools/widget/cmd_list.h +++ b/src/core/devtools/widget/cmd_list.h @@ -53,6 +53,8 @@ class CmdListViewer { u32 highlight_batch{~0u}; RegView batch_view; + int last_selected_batch{-1}; + std::vector extra_batch_view; static void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body); @@ -68,7 +70,7 @@ public: explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector& cmd_list, uintptr_t base_addr = 0, std::string name = ""); - void Draw(); + void Draw(bool only_batches_view = false); }; } // namespace Core::Devtools::Widget diff --git a/src/core/devtools/widget/common.h b/src/core/devtools/widget/common.h index 701d1639..e650f5fc 100644 --- a/src/core/devtools/widget/common.h +++ b/src/core/devtools/widget/common.h @@ -4,15 +4,16 @@ #pragma once #include +#include #include #include +#include "common/bit_field.h" #include "common/types.h" #include "video_core/amdgpu/pm4_opcodes.h" namespace Core::Devtools::Widget { - /* * Generic PM4 header */ @@ -57,16 +58,24 @@ void DrawRow(const char* text, const char* fmt, Args... args) { ImGui::TextUnformatted(buf); } -template -void DrawEnumRow(const char* text, T value) { - DrawRow(text, "%X (%s)", V(value), magic_enum::enum_name(value).data()); +template +void DrawValueRow(const char* text, T value) { + if constexpr (std::is_enum_v) { + return DrawRow(text, "%X (%s)", value, magic_enum::enum_name(value).data()); + } else if constexpr (std::is_integral_v) { + return DrawRow(text, "%X", value); + } else if constexpr (std::is_base_of_v, T>) { + return DrawValueRow(text, value.Value()); + } else { + static_assert(false, "Unsupported type"); + } } template -void DrawMultipleRow(const char* text, const char* fmt, V arg, Extra&&... extra_args) { - DrawRow(text, fmt, arg); +void DrawValueRowList(const char* text, V arg, Extra&&... extra_args) { + DrawValueRow(text, arg); if constexpr (sizeof...(extra_args) > 0) { - DrawMultipleRow(std::forward(extra_args)...); + DrawValueRowList(std::forward(extra_args)...); } } diff --git a/src/core/devtools/widget/frame_dump.cpp b/src/core/devtools/widget/frame_dump.cpp index 29b5cb8e..86ba7b86 100644 --- a/src/core/devtools/widget/frame_dump.cpp +++ b/src/core/devtools/widget/frame_dump.cpp @@ -7,6 +7,7 @@ #include #include "common/io_file.h" +#include "core/devtools/options.h" #include "frame_dump.h" #include "imgui_internal.h" #include "imgui_memory_editor.h" @@ -45,11 +46,14 @@ FrameDumpViewer::FrameDumpViewer(const FrameDump& _frame_dump) selected_submit_num = 0; selected_queue_num2 = 0; + has_queue_type.fill(false); cmd_list_viewer.reserve(frame_dump->queues.size()); for (const auto& cmd : frame_dump->queues) { - const auto fname = - fmt::format("{}_{}_{:02}_{:02}", id, magic_enum::enum_name(selected_queue_type), - selected_submit_num, selected_queue_num2); + if (!cmd.data.empty()) { + has_queue_type[static_cast(cmd.type)] = true; + } + 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); if (cmd.type == QueueType::dcb && cmd.submit_num == 0 && cmd.num2 == 0) { selected_cmd = static_cast(cmd_list_viewer.size() - 1); @@ -64,9 +68,28 @@ void FrameDumpViewer::Draw() { 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(std::distance(frame_dump->queues.begin(), it)); + selected_submit_num = static_cast(frame_dump->queues[selected_cmd].submit_num); + selected_queue_num2 = static_cast(frame_dump->queues[selected_cmd].num2); + } + }; + + bool is_showing = Options.frame_dump_render_on_collapse; + bool is_collapsed = true; + 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)) { + is_showing = true; + is_collapsed = false; + if (IsWindowAppearing()) { auto window = GetCurrentWindow(); 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(), ImGuiComboFlags_WidthFitPreview)) { bool selected = false; -#define COMBO(x) C_V(magic_enum::enum_name(x).data(), x, selected_queue_type, selected) - COMBO(QueueType::acb) +#define COMBO(x) \ + if (has_queue_type[static_cast(x)]) \ + C_V(magic_enum::enum_name(x).data(), x, selected_queue_type, selected) COMBO(QueueType::dcb); COMBO(QueueType::ccb); + COMBO(QueueType::acb); if (selected) { selected_submit_num = selected_queue_num2 = -1; + try_select(); } EndCombo(); } @@ -111,9 +137,9 @@ void FrameDumpViewer::Draw() { SameLine(); if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(), ImGuiComboFlags_WidthFitPreview)) { - std::array available_submits{}; + std::array available_submits{false}; 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; } } @@ -128,6 +154,7 @@ void FrameDumpViewer::Draw() { } if (selected) { selected_queue_num2 = -1; + try_select(); } EndCombo(); } @@ -136,9 +163,10 @@ void FrameDumpViewer::Draw() { SameLine(); if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(), ImGuiComboFlags_WidthFitPreview)) { - std::array available_queues{}; + std::array available_queues{false}; 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; } } @@ -152,21 +180,14 @@ void FrameDumpViewer::Draw() { } } if (selected) { - const auto it = std::ranges::find_if(frame_dump->queues, [&](const auto& cmd) { - 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(std::distance(frame_dump->queues.begin(), it)); - } + try_select(); } EndCombo(); } 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(); } diff --git a/src/core/devtools/widget/frame_dump.h b/src/core/devtools/widget/frame_dump.h index 2b3ff241..cc4fe638 100644 --- a/src/core/devtools/widget/frame_dump.h +++ b/src/core/devtools/widget/frame_dump.h @@ -20,6 +20,7 @@ class FrameDumpViewer { int id; std::vector cmd_list_viewer; + std::array has_queue_type; DebugStateType::QueueType selected_queue_type; s32 selected_submit_num; diff --git a/src/core/devtools/widget/reg_popup.cpp b/src/core/devtools/widget/reg_popup.cpp index d012437c..0633e76e 100644 --- a/src/core/devtools/widget/reg_popup.cpp +++ b/src/core/devtools/widget/reg_popup.cpp @@ -9,6 +9,7 @@ #include "cmd_list.h" #include "common.h" +#include "imgui/imgui_std.h" using namespace ImGui; using magic_enum::enum_name; @@ -21,13 +22,13 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) { // clang-format off - DrawMultipleRow( - "BASE_ADDR", "%X", buffer.base_address, - "PITCH.TILE_MAX", "%X", buffer.pitch.tile_max, - "PITCH.FMASK_TILE_MAX", "%X", buffer.pitch.fmask_tile_max, - "SLICE.TILE_MAX", "%X", buffer.slice.tile_max, - "VIEW.SLICE_START", "%X", buffer.view.slice_start, - "VIEW.SLICE_MAX", "%X", buffer.view.slice_max + DrawValueRowList( + "BASE_ADDR", buffer.base_address, + "PITCH.TILE_MAX", buffer.pitch.tile_max, + "PITCH.FMASK_TILE_MAX", buffer.pitch.fmask_tile_max, + "SLICE.TILE_MAX", buffer.slice.tile_max, + "VIEW.SLICE_START", buffer.view.slice_start, + "VIEW.SLICE_MAX", buffer.view.slice_max ); TableNextRow(); @@ -49,31 +50,25 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) { } TableNextRow(); - DrawMultipleRow( - "CMASK_BASE_EXT", "%X", buffer.cmask_base_address, - "FMASK_BASE_EXT", "%X", buffer.fmask_base_address, - "FMASK_SLICE.TILE_MAX", "%X", buffer.fmask_slice.tile_max, - "CLEAR_WORD0", "%X", buffer.clear_word0, - "CLEAR_WORD1", "%X", buffer.clear_word1 + DrawValueRowList( + "CMASK_BASE_EXT", buffer.cmask_base_address, + "FMASK_BASE_EXT", buffer.fmask_base_address, + "FMASK_SLICE.TILE_MAX", buffer.fmask_slice.tile_max, + "CLEAR_WORD0", buffer.clear_word0, + "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 EndTable(); @@ -89,37 +84,34 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) { TableNextRow(); // clang-format off - DrawEnumRow("Z_INFO.FORMAT", depth_buffer.z_info.format.Value()); - DrawMultipleRow( - "Z_INFO.NUM_SAMPLES", "%X", depth_buffer.z_info.num_samples, - "Z_INFO.TILE_SPLIT", "%X", depth_buffer.z_info.tile_split, - "Z_INFO.TILE_MODE_INDEX", "%X", depth_buffer.z_info.tile_mode_index, - "Z_INFO.DECOMPRESS_ON_N_ZPLANES", "%X", depth_buffer.z_info.decompress_on_n_zplanes, - "Z_INFO.ALLOW_EXPCLEAR", "%X", depth_buffer.z_info.allow_expclear, - "Z_INFO.READ_SIZE", "%X", depth_buffer.z_info.read_size, - "Z_INFO.TILE_SURFACE_EN", "%X", depth_buffer.z_info.tile_surface_en, - "Z_INFO.CLEAR_DISALLOWED", "%X", depth_buffer.z_info.clear_disallowed, - "Z_INFO.ZRANGE_PRECISION", "%X", depth_buffer.z_info.zrange_precision - ); - - DrawEnumRow("STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format.Value()); - - DrawMultipleRow( - "Z_READ_BASE", "%X", depth_buffer.z_read_base, - "STENCIL_READ_BASE", "%X", depth_buffer.stencil_read_base, - "Z_WRITE_BASE", "%X", depth_buffer.z_write_base, - "STENCIL_WRITE_BASE", "%X", depth_buffer.stencil_write_base, - "DEPTH_SIZE.PITCH_TILE_MAX", "%X", depth_buffer.depth_size.pitch_tile_max, - "DEPTH_SIZE.HEIGHT_TILE_MAX", "%X", depth_buffer.depth_size.height_tile_max, - "DEPTH_SLICE.TILE_MAX", "%X", depth_buffer.depth_slice.tile_max, - "Pitch()", "%X", depth_buffer.Pitch(), - "Height()", "%X", depth_buffer.Height(), - "Address()", "%X", depth_buffer.Address(), - "NumSamples()", "%X", depth_buffer.NumSamples(), - "NumBits()", "%X", depth_buffer.NumBits(), - "GetDepthSliceSize()", "%X", depth_buffer.GetDepthSliceSize() + DrawValueRowList( + "Z_INFO.FORMAT", depth_buffer.z_info.format, + "Z_INFO.NUM_SAMPLES", depth_buffer.z_info.num_samples, + "Z_INFO.TILE_SPLIT", depth_buffer.z_info.tile_split, + "Z_INFO.TILE_MODE_INDEX", depth_buffer.z_info.tile_mode_index, + "Z_INFO.DECOMPRESS_ON_N_ZPLANES", depth_buffer.z_info.decompress_on_n_zplanes, + "Z_INFO.ALLOW_EXPCLEAR", depth_buffer.z_info.allow_expclear, + "Z_INFO.READ_SIZE", depth_buffer.z_info.read_size, + "Z_INFO.TILE_SURFACE_EN", depth_buffer.z_info.tile_surface_en, + "Z_INFO.CLEAR_DISALLOWED", depth_buffer.z_info.clear_disallowed, + "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, + "STENCIL_READ_BASE", depth_buffer.stencil_read_base, + "Z_WRITE_BASE", depth_buffer.z_write_base, + "STENCIL_WRITE_BASE", depth_buffer.stencil_write_base, + "DEPTH_SIZE.PITCH_TILE_MAX", depth_buffer.depth_size.pitch_tile_max, + "DEPTH_SIZE.HEIGHT_TILE_MAX", depth_buffer.depth_size.height_tile_max, + "DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max, + "Pitch()", depth_buffer.Pitch(), + "Height()", depth_buffer.Height(), + "Address()", depth_buffer.Address(), + "NumSamples()", depth_buffer.NumSamples(), + "NumBits()", depth_buffer.NumBits(), + "GetDepthSliceSize()", depth_buffer.GetDepthSliceSize() ); // clang-format on + EndTable(); } SeparatorText("Depth control"); @@ -127,19 +119,17 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) { TableNextRow(); // clang-format off - DrawMultipleRow( - "STENCIL_ENABLE", "%X", depth_control.stencil_enable, - "DEPTH_ENABLE", "%X", depth_control.depth_enable, - "DEPTH_WRITE_ENABLE", "%X", depth_control.depth_write_enable, - "DEPTH_BOUNDS_ENABLE", "%X", depth_control.depth_bounds_enable - ); - DrawEnumRow("DEPTH_FUNC", depth_control.depth_func.Value()); - DrawRow("BACKFACE_ENABLE", "%X", depth_control.backface_enable); - DrawEnumRow("STENCIL_FUNC", depth_control.stencil_ref_func.Value()); - DrawEnumRow("STENCIL_FUNC_BF", depth_control.stencil_bf_func.Value()); - DrawMultipleRow( - "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 + DrawValueRowList( + "STENCIL_ENABLE", depth_control.stencil_enable, + "DEPTH_ENABLE", depth_control.depth_enable, + "DEPTH_WRITE_ENABLE", depth_control.depth_write_enable, + "DEPTH_BOUNDS_ENABLE", depth_control.depth_bounds_enable, + "DEPTH_FUNC", depth_control.depth_func, + "BACKFACE_ENABLE", depth_control.backface_enable, + "STENCIL_FUNC", depth_control.stencil_ref_func, + "STENCIL_FUNC_BF", depth_control.stencil_bf_func, + "ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", depth_control.enable_color_writes_on_depth_fail, + "DISABLE_COLOR_WRITES_ON_DEPTH_PASS", depth_control.disable_color_writes_on_depth_pass ); // clang-format on @@ -152,24 +142,45 @@ RegPopup::RegPopup() { 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->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, - AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id) { +void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer, + AmdGpu::Liverpool::DepthControl 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(data)) { + SetWindowSize({365.0f, 520.0f}); + KeepWindowInside(); + } else if (std::holds_alternative(data)) { + SetWindowSize({404.0f, 543.0f}); + KeepWindowInside(); + } + } + last_pos = GetWindowPos(); + moved = false; + End(); } void RegPopup::Draw() { - char name[128]; 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(&data)) { DrawColorBuffer(*buffer); } else if (const auto* depth_data = std::get_if(&data)) { @@ -178,5 +189,4 @@ void RegPopup::Draw() { } End(); } - } // namespace Core::Devtools::Widget diff --git a/src/core/devtools/widget/reg_popup.h b/src/core/devtools/widget/reg_popup.h index ba4224d7..9ccd60ac 100644 --- a/src/core/devtools/widget/reg_popup.h +++ b/src/core/devtools/widget/reg_popup.h @@ -5,6 +5,8 @@ #include +#include + #include "common/types.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h" @@ -12,25 +14,31 @@ namespace Core::Devtools::Widget { class RegPopup { int id; + ImGuiWindowFlags flags{ImGuiWindowFlags_NoSavedSettings}; using DepthBuffer = std::tuple; + ImVec2 last_pos; std::variant data; 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: bool open = false; + bool moved = false; 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, - AmdGpu::Liverpool::DepthControl depth_control, u32 batch_id); + void SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer, + AmdGpu::Liverpool::DepthControl depth_control); + + void SetPos(ImVec2 pos, bool auto_resize = false); void Draw(); }; diff --git a/src/core/devtools/widget/reg_view.cpp b/src/core/devtools/widget/reg_view.cpp index 2e8bb8f5..10cc8808 100644 --- a/src/core/devtools/widget/reg_view.cpp +++ b/src/core/devtools/widget/reg_view.cpp @@ -11,6 +11,7 @@ #include "common.h" #include "common/io_file.h" #include "core/devtools/options.h" +#include "imgui/imgui_std.h" #include "imgui_internal.h" #include "reg_view.h" @@ -22,6 +23,8 @@ using namespace ImGui; using magic_enum::enum_name; +constexpr auto depth_id = 0xF3; + static std::optional exec_cli(const char* cli) { std::array buffer{}; std::string output; @@ -40,7 +43,16 @@ static std::optional exec_cli(const char* cli) { namespace Core::Devtools::Widget { void RegView::ProcessShader(int shader_id) { - auto shader = data.stages[shader_id]; + std::vector 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; @@ -57,7 +69,7 @@ void RegView::ProcessShader(int shader_id) { } 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.Write(shader_code); file.Close(); auto result = exec_cli(cli.c_str()); @@ -73,8 +85,9 @@ void RegView::ProcessShader(int shader_id) { MemoryEditor hex_view; hex_view.Open = true; hex_view.ReadOnly = true; - hex_view.Cols = 16; + hex_view.Cols = 8; hex_view.OptShowAscii = false; + hex_view.OptShowOptions = false; TextEditor dis_view; dis_view.SetPalette(TextEditor::GetDarkPalette()); @@ -84,7 +97,7 @@ void RegView::ProcessShader(int shader_id) { ShaderCache cache{ .hex_view = hex_view, .dis_view = dis_view, - .user_data = shader.user_data.user_data, + .user_data = user_data, }; 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; if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) { + TableNextRow(); - 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); - - auto cc_mode = regs.color_control.mode.Value(); - DrawRow("Color control", "%X (%s)", cc_mode, enum_name(cc_mode).data()); + DrawValueRow("Primitive type", regs.primitive_type); const auto open_new_popup = [&](int cb, auto... args) { + const auto pos = GetItemRectMax() + ImVec2(5.0f, 0.0f); if (GetIO().KeyShift) { auto& pop = extra_reg_popup.emplace_back(); - pop.SetData(args...); + pop.SetData(title, args...); pop.open = true; + pop.SetPos(pos, true); } else if (last_selected_cb == cb && default_reg_popup.open) { default_reg_popup.open = false; } else { last_selected_cb = cb; - default_reg_popup.SetData(args...); - if (!default_reg_popup.open) { + default_reg_popup.SetData(title, args...); + if (!default_reg_popup.open || !default_reg_popup.moved) { default_reg_popup.open = true; - auto popup_pos = - GetCurrentContext()->LastItemData.Rect.Max + ImVec2(5.0f, 0.0f); - SetNextWindowPos(popup_pos, ImGuiCond_Always); - default_reg_popup.Draw(); + default_reg_popup.SetPos(pos, true); } } }; @@ -142,7 +185,7 @@ void RegView::DrawRegs() { } else { const char* text = last_selected_cb == cb && default_reg_popup.open ? "x" : "->"; 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) { TextUnformatted("N/A"); } else { - constexpr auto depth_id = 0xF3; const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->"; 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(); } } @@ -172,9 +232,9 @@ RegView::RegView() { id = unique_id++; 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}); - SetNextWindowSize({450.0f, 500.0f}); + SetNextWindowSize({290.0f, 435.0f}); ImGuiID root_dock_id; Begin(name); { @@ -188,7 +248,7 @@ RegView::RegView() { ImGuiID up1, down1; 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); DockBuilderDockWindow(name, up1); @@ -202,35 +262,68 @@ RegView::RegView() { DockBuilderFinish(root_dock_id); } -void RegView::SetData(DebugStateType::RegDump data, u32 batch_id) { - this->data = std::move(data); +void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_title, u32 batch_id) { + this->data = std::move(_data); this->batch_id = batch_id; + this->title = fmt::format("{}/Batch {}", base_title, batch_id); // clear cache - selected_shader = -1; shader_decomp.clear(); - default_reg_popup.open = false; + if (data.is_compute) { + selected_shader = -2; + last_selected_cb = -1; + 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(); } -void RegView::Draw() { - +void RegView::SetPos(ImVec2 pos) { 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 (GetWindowPos() != last_pos) { + moved = true; + } + const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"}; 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")) { Checkbox("Registers", &show_registers); Checkbox("User data", &show_user_data); @@ -240,11 +333,31 @@ void RegView::Draw() { EndMenuBar(); } - char dock_name[64]; - snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id); - auto root_dock_id = ImHashStr(dock_name); - DockSpace(root_dock_id); + 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]; + snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id); + auto root_dock_id = ImHashStr(dock_name); + DockSpace(root_dock_id); End(); auto get_shader = [&]() -> ShaderCache* { @@ -257,10 +370,11 @@ void RegView::Draw() { if (show_user_data) { 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(); if (!shader) { - Text("Select a stage"); + Text("Stage not selected"); } else { shader->hex_view.DrawContents(shader->user_data.data(), shader->user_data.size()); } @@ -273,7 +387,7 @@ void RegView::Draw() { if (Begin(name, &show_disassembly)) { auto shader = get_shader(); if (!shader) { - Text("Select a stage"); + Text("Stage not selected"); } else { shader->dis_view.Render("Disassembly", GetContentRegionAvail()); } @@ -284,7 +398,11 @@ void RegView::Draw() { if (show_registers) { snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id); if (Begin(name, &show_registers)) { - DrawRegs(); + if (data.is_compute) { + DrawComputeRegs(); + } else { + DrawGraphicsRegs(); + } } End(); } diff --git a/src/core/devtools/widget/reg_view.h b/src/core/devtools/widget/reg_view.h index 67ab1e04..3ac8ec07 100644 --- a/src/core/devtools/widget/reg_view.h +++ b/src/core/devtools/widget/reg_view.h @@ -18,8 +18,10 @@ struct ShaderCache { class RegView { int id; + std::string title; DebugStateType::RegDump data; u32 batch_id{~0u}; + ImVec2 last_pos; std::unordered_map shader_decomp; int selected_shader{-1}; @@ -35,14 +37,19 @@ class RegView { void SelectShader(int shader_id); - void DrawRegs(); + void DrawComputeRegs(); + + void DrawGraphicsRegs(); public: bool open = false; + bool moved = false; 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(); }; diff --git a/src/core/libraries/dialogs/ime_dialog_ui.cpp b/src/core/libraries/dialogs/ime_dialog_ui.cpp index 48f5d75d..9d50d2fb 100644 --- a/src/core/libraries/dialogs/ime_dialog_ui.cpp +++ b/src/core/libraries/dialogs/ime_dialog_ui.cpp @@ -245,7 +245,7 @@ void ImeDialogUi::Draw() { window_size = {500.0f, 150.0f}; } - CentralizeWindow(); + CentralizeNextWindow(); SetNextWindowSize(window_size); SetNextWindowCollapsed(false); diff --git a/src/imgui/imgui_std.h b/src/imgui/imgui_std.h index ce79da70..cd720806 100644 --- a/src/imgui/imgui_std.h +++ b/src/imgui/imgui_std.h @@ -31,7 +31,7 @@ inline void CentralizeNextWindow() { } inline void CentralizeWindow() { - const auto display_size = GetIO().DisplaySize; + const auto display_size = GetIO().DisplaySize - GetCurrentWindowRead()->SizeFull; 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))); return; } - const auto cur_size = GetWindowSize(); + const auto cur_size = GetCurrentWindowRead()->SizeFull; const auto bottom_right = cur_pos + cur_size; if (bottom_right.x > display_size.x || bottom_right.y > display_size.y) { const auto max_pos = display_size - cur_size; diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index d4ebeb88..7b472708 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -446,7 +446,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::spandim_z; regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator; if (DebugState.DumpingCurrentReg()) { - DebugState.PushRegsDump(base_addr, reinterpret_cast(header), regs); + DebugState.PushRegsDump(base_addr, reinterpret_cast(header), regs, + true); } if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) { const auto cmd_address = reinterpret_cast(header); @@ -463,7 +464,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::span(header), regs); + DebugState.PushRegsDump(base_addr, reinterpret_cast(header), regs, + true); } if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) { const auto cmd_address = reinterpret_cast(header); @@ -645,7 +647,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span acb, int vqid) { regs.cs_program.dim_z = dispatch_direct->dim_z; regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator; if (DebugState.DumpingCurrentReg()) { - DebugState.PushRegsDump(base_addr, reinterpret_cast(header), regs); + DebugState.PushRegsDump(base_addr, reinterpret_cast(header), regs, true); } if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) { const auto cmd_address = reinterpret_cast(header);