mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
devtools: pm4 - show color buffer info as popup
add ux improvements for open new windows with shift+click better window titles
This commit is contained in:
parent
ccd997c6a6
commit
dbce929d7b
@ -353,16 +353,18 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||
src/core/devtools/gcn/gcn_shader_regs.cpp
|
||||
src/core/devtools/widget/cmd_list.cpp
|
||||
src/core/devtools/widget/cmd_list.h
|
||||
src/core/devtools/widget/common.h
|
||||
src/core/devtools/widget/frame_dump.cpp
|
||||
src/core/devtools/widget/frame_dump.h
|
||||
src/core/devtools/widget/frame_graph.cpp
|
||||
src/core/devtools/widget/frame_graph.h
|
||||
src/core/devtools/widget/imgui_memory_editor.h
|
||||
src/core/devtools/widget/reg_popup.cpp
|
||||
src/core/devtools/widget/reg_popup.h
|
||||
src/core/devtools/widget/reg_view.cpp
|
||||
src/core/devtools/widget/reg_view.h
|
||||
src/core/devtools/widget/text_editor.cpp
|
||||
src/core/devtools/widget/text_editor.h
|
||||
src/core/devtools/widget/types.h
|
||||
)
|
||||
|
||||
set(COMMON src/common/logging/backend.cpp
|
||||
|
@ -1,11 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/native_clock.h"
|
||||
#include "common/singleton.h"
|
||||
#include "debug_state.h"
|
||||
#include "devtools/widget/types.h"
|
||||
#include "devtools/widget/common.h"
|
||||
#include "libraries/kernel/time_management.h"
|
||||
#include "libraries/system/msgdialog.h"
|
||||
#include "video_core/amdgpu/pm4_cmds.h"
|
||||
|
@ -105,9 +105,15 @@ void L::DrawAdvanced() {
|
||||
DebugState.should_show_frame_dump = false;
|
||||
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
||||
while (!DebugState.frame_dump_list.empty()) {
|
||||
auto frame_dump = std::move(DebugState.frame_dump_list.back());
|
||||
DebugState.frame_dump_list.pop_back();
|
||||
const auto& frame_dump = DebugState.frame_dump_list.back();
|
||||
frame_viewers.emplace_back(frame_dump);
|
||||
DebugState.frame_dump_list.pop_back();
|
||||
}
|
||||
static bool first_time = true;
|
||||
if (first_time) {
|
||||
first_time = false;
|
||||
DebugState.ShowDebugMessage("Tip: You can shift+click any\n"
|
||||
"popup to open a new window");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,21 @@ static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
||||
return curr_pm4;
|
||||
}
|
||||
|
||||
static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
|
||||
using AmdGpu::PM4ItOpcode;
|
||||
switch (opcode) {
|
||||
case PM4ItOpcode::DispatchDirect:
|
||||
case PM4ItOpcode::DispatchIndirect:
|
||||
case PM4ItOpcode::DrawIndex2:
|
||||
case PM4ItOpcode::DrawIndexAuto:
|
||||
case PM4ItOpcode::DrawIndexOffset2:
|
||||
case PM4ItOpcode::DrawIndexIndirect:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ParsePolygonControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<AmdGpu::Liverpool::PolygonControl const&>(value);
|
||||
|
||||
@ -888,7 +903,7 @@ void CmdListViewer::OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* b
|
||||
Separator();
|
||||
BeginGroup();
|
||||
|
||||
auto const* pkt = reinterpret_cast<AmdGpu::PM4CmdSetBase const*>(header);
|
||||
// auto const* pkt = reinterpret_cast<AmdGpu::PM4CmdSetBase const*>(header);
|
||||
Text("BASE_INDEX: %08X", body[0]);
|
||||
Text("ADDRESS0 : %08X", body[1]);
|
||||
Text("ADDRESS1 : %08X", body[2]);
|
||||
@ -1077,9 +1092,10 @@ void CmdListViewer::OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const*
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
CmdListViewer::CmdListViewer(const FrameDumpViewer* parent, const std::vector<u32>& cmd_list,
|
||||
uintptr_t base_addr, std::string name)
|
||||
: parent(parent), base_addr(base_addr), name(std::move(name)) {
|
||||
CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump,
|
||||
const std::vector<u32>& cmd_list, uintptr_t _base_addr,
|
||||
std::string _name)
|
||||
: frame_dump(_frame_dump), base_addr(_base_addr), name(std::move(_name)) {
|
||||
using namespace AmdGpu;
|
||||
|
||||
cmdb_addr = (uintptr_t)cmd_list.data();
|
||||
@ -1131,11 +1147,7 @@ CmdListViewer::CmdListViewer(const FrameDumpViewer* parent, const std::vector<u3
|
||||
}
|
||||
}
|
||||
|
||||
if (opcode == PM4ItOpcode::DispatchDirect || opcode == PM4ItOpcode::DispatchIndirect ||
|
||||
opcode == PM4ItOpcode::DrawIndex2 || opcode == PM4ItOpcode::DrawIndexAuto ||
|
||||
opcode == PM4ItOpcode::DrawIndexOffset2 || opcode == PM4ItOpcode::DrawIndexIndirect
|
||||
// ...
|
||||
) {
|
||||
if (IsDrawCall(opcode)) {
|
||||
// All these commands are terminated by NOP at the end, so
|
||||
// it is safe to skip it to be even with CP
|
||||
// next_pm4_hdr = get_next(next_pm4_hdr, 1);
|
||||
@ -1179,6 +1191,34 @@ CmdListViewer::CmdListViewer(const FrameDumpViewer* parent, const std::vector<u3
|
||||
void CmdListViewer::Draw() {
|
||||
const auto& ctx = *GetCurrentContext();
|
||||
|
||||
if (batch_view.open) {
|
||||
batch_view.Draw();
|
||||
}
|
||||
for (auto it = extra_batch_view.begin(); it != extra_batch_view.end();) {
|
||||
if (!it->open) {
|
||||
it = extra_batch_view.erase(it);
|
||||
continue;
|
||||
}
|
||||
it->Draw();
|
||||
++it;
|
||||
}
|
||||
|
||||
if (cmdb_view.Open) {
|
||||
MemoryEditor::Sizes s;
|
||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
||||
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
||||
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
|
||||
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
||||
if (cmdb_view.ContentsWidthChanged) {
|
||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||
SetWindowSize({s.WindowWidth, s.WindowWidth * 0.6f});
|
||||
}
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
PushID(name.c_str());
|
||||
if (BeginChild("cmd_queue", {})) {
|
||||
|
||||
@ -1213,10 +1253,17 @@ void CmdListViewer::Draw() {
|
||||
}
|
||||
|
||||
u32 batch_id = ~0u;
|
||||
s32 current_highlight_batch = -1;
|
||||
u32 current_highlight_batch = ~0u;
|
||||
|
||||
int id = 0;
|
||||
PushID(0);
|
||||
for (const auto& event : events) {
|
||||
auto processed_size = 0ull;
|
||||
PopID();
|
||||
PushID(id++);
|
||||
|
||||
if (std::holds_alternative<BatchBegin>(event)) {
|
||||
batch_id = std::get<BatchBegin>(event).id;
|
||||
}
|
||||
|
||||
if (show_markers) {
|
||||
if (std::holds_alternative<PushMarker>(event)) {
|
||||
@ -1243,11 +1290,6 @@ void CmdListViewer::Draw() {
|
||||
}
|
||||
}
|
||||
|
||||
if (std::holds_alternative<BatchBegin>(event)) {
|
||||
batch_id = std::get<BatchBegin>(event).id;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!std::holds_alternative<BatchInfo>(event)) {
|
||||
continue;
|
||||
}
|
||||
@ -1274,15 +1316,35 @@ void CmdListViewer::Draw() {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||
}
|
||||
|
||||
if (!group_batches || CollapsingHeader(batch_hdr)) {
|
||||
const auto open_batch_view = [&, this] {
|
||||
if (frame_dump->regs.contains(batch.command_addr)) {
|
||||
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.open = true;
|
||||
} else {
|
||||
batch_view.SetData(data, batch_id);
|
||||
batch_view.open = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool show_batch_content = true;
|
||||
|
||||
if (group_batches) {
|
||||
show_batch_content =
|
||||
CollapsingHeader(batch_hdr, ImGuiTreeNodeFlags_AllowOverlap);
|
||||
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||
if (Button("->", {40.0f, 0.0f})) {
|
||||
open_batch_view();
|
||||
}
|
||||
}
|
||||
|
||||
if (show_batch_content) {
|
||||
auto processed_size = 0ull;
|
||||
auto bb = ctx.LastItemData.Rect;
|
||||
if (group_batches) {
|
||||
if (IsItemToggledOpen()) {
|
||||
if (parent->frame_dump.regs.contains(batch.command_addr)) {
|
||||
batch_view.SetData(parent->frame_dump.regs.at(batch.command_addr));
|
||||
batch_view.open = true;
|
||||
}
|
||||
}
|
||||
Indent();
|
||||
}
|
||||
auto const batch_sz = batch.end_addr - batch.start_addr;
|
||||
@ -1300,9 +1362,23 @@ void CmdListViewer::Draw() {
|
||||
cmdb_addr + batch.start_addr + processed_size,
|
||||
Gcn::GetOpCodeName((u32)op));
|
||||
|
||||
if (TreeNode(header_name)) {
|
||||
const bool just_opened = IsItemToggledOpen();
|
||||
if (just_opened) {
|
||||
bool open_pm4 = TreeNode(header_name);
|
||||
if (!group_batches) {
|
||||
if (IsDrawCall(op)) {
|
||||
SameLine(GetContentRegionAvail().x - 40.0f);
|
||||
if (Button("->", {40.0f, 0.0f})) {
|
||||
open_batch_view();
|
||||
}
|
||||
}
|
||||
if (IsItemHovered() && ctx.IO.KeyShift) {
|
||||
if (BeginTooltip()) {
|
||||
Text("Batch %d", batch_id);
|
||||
EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (open_pm4) {
|
||||
if (IsItemToggledOpen()) {
|
||||
// Editor
|
||||
cmdb_view.GotoAddrAndHighlight(
|
||||
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr,
|
||||
@ -1383,6 +1459,7 @@ void CmdListViewer::Draw() {
|
||||
Separator();
|
||||
}
|
||||
}
|
||||
PopID();
|
||||
|
||||
highlight_batch = current_highlight_batch;
|
||||
|
||||
@ -1391,34 +1468,6 @@ void CmdListViewer::Draw() {
|
||||
}
|
||||
EndChild();
|
||||
PopID();
|
||||
|
||||
if (cmdb_view.Open) {
|
||||
MemoryEditor::Sizes s;
|
||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
||||
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
||||
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
|
||||
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
||||
if (cmdb_view.ContentsWidthChanged) {
|
||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||
SetWindowSize({s.WindowWidth, s.WindowWidth * 0.6f});
|
||||
}
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
if (batch_view.open) {
|
||||
batch_view.Draw();
|
||||
}
|
||||
for (auto it = extra_batch_view.begin(); it != extra_batch_view.end(); ++it) {
|
||||
if (!it->open) {
|
||||
it = extra_batch_view.erase(it);
|
||||
continue;
|
||||
}
|
||||
it->Draw();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -5,13 +5,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common/types.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include "reg_view.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace AmdGpu {
|
||||
union PM4Type3Header;
|
||||
@ -36,7 +37,7 @@ void ParseZInfo(u32 value, bool begin_table = true);
|
||||
|
||||
class CmdListViewer {
|
||||
|
||||
const FrameDumpViewer* parent;
|
||||
DebugStateType::FrameDump* frame_dump;
|
||||
|
||||
uintptr_t base_addr;
|
||||
std::string name;
|
||||
@ -49,22 +50,22 @@ class CmdListViewer {
|
||||
|
||||
int batch_bp{-1};
|
||||
int vqid{255};
|
||||
s32 highlight_batch{-1};
|
||||
u32 highlight_batch{~0u};
|
||||
|
||||
RegView batch_view;
|
||||
std::vector<RegView> extra_batch_view;
|
||||
|
||||
void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
void OnSetContextReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
void OnSetShReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
static void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
static void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
static void OnSetContextReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
static void OnSetShReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
static void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||
|
||||
public:
|
||||
static void LoadConfig(const char* line);
|
||||
static void SerializeConfig(ImGuiTextBuffer* buf);
|
||||
|
||||
explicit CmdListViewer(const FrameDumpViewer* parent, 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 = "");
|
||||
|
||||
void Draw();
|
||||
|
77
src/core/devtools/widget/common.h
Normal file
77
src/core/devtools/widget/common.h
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
/*
|
||||
* Generic PM4 header
|
||||
*/
|
||||
union PM4Header {
|
||||
struct {
|
||||
u32 reserved : 16;
|
||||
u32 count : 14;
|
||||
u32 type : 2; // PM4_TYPE
|
||||
};
|
||||
u32 u32All;
|
||||
};
|
||||
|
||||
struct PushMarker {
|
||||
std::string name{};
|
||||
};
|
||||
|
||||
struct PopMarker {};
|
||||
|
||||
struct BatchBegin {
|
||||
u32 id;
|
||||
};
|
||||
|
||||
struct BatchInfo {
|
||||
u32 id;
|
||||
std::string marker{};
|
||||
size_t start_addr;
|
||||
size_t end_addr;
|
||||
size_t command_addr;
|
||||
AmdGpu::PM4ItOpcode type;
|
||||
bool bypass{false};
|
||||
};
|
||||
|
||||
using GPUEvent = std::variant<PushMarker, PopMarker, BatchBegin, BatchInfo>;
|
||||
|
||||
template <typename... Args>
|
||||
void DrawRow(const char* text, const char* fmt, Args... args) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(text);
|
||||
ImGui::TableNextColumn();
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), fmt, args...);
|
||||
ImGui::TextUnformatted(buf);
|
||||
}
|
||||
|
||||
template <typename V, typename... Extra>
|
||||
void DrawMultipleRow(const char* text, const char* fmt, V arg, Extra&&... extra_args) {
|
||||
DrawRow(text, fmt, arg);
|
||||
if constexpr (sizeof...(extra_args) > 0) {
|
||||
DrawMultipleRow(std::forward<Extra>(extra_args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void DoTooltip(const char* str_id, Args&&... args) {
|
||||
if (ImGui::BeginTooltip()) {
|
||||
if (ImGui::BeginTable(str_id, 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
DrawMultipleRow(std::forward<Args>(args)...);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -36,7 +36,8 @@ static std::array<char, 3> small_int_to_str(const s32 i) {
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
FrameDumpViewer::FrameDumpViewer(FrameDump _frame_dump) : frame_dump(std::move(_frame_dump)) {
|
||||
FrameDumpViewer::FrameDumpViewer(const FrameDump& _frame_dump)
|
||||
: frame_dump(std::make_shared<FrameDump>(_frame_dump)) {
|
||||
static int unique_id = 0;
|
||||
id = unique_id++;
|
||||
|
||||
@ -44,15 +45,14 @@ FrameDumpViewer::FrameDumpViewer(FrameDump _frame_dump) : frame_dump(std::move(_
|
||||
selected_submit_num = 0;
|
||||
selected_queue_num2 = 0;
|
||||
|
||||
cmd_list_viewer.reserve(frame_dump.queues.size());
|
||||
for (const auto& cmd : frame_dump.queues) {
|
||||
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);
|
||||
cmd_list_viewer.emplace_back(this, cmd.data, cmd.base_addr, fname);
|
||||
if (cmd.type == QueueType::dcb && cmd.submit_num == selected_submit_num &&
|
||||
cmd.num2 == selected_queue_num2) {
|
||||
selected_cmd = cmd_list_viewer.size() - 1;
|
||||
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<s32>(cmd_list_viewer.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ void FrameDumpViewer::Draw() {
|
||||
magic_enum::enum_name(selected_queue_type),
|
||||
selected_submit_num, selected_queue_num2);
|
||||
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
||||
auto& data = frame_dump.queues[selected_cmd].data;
|
||||
const auto& data = frame_dump->queues[selected_cmd].data;
|
||||
if (file.IsOpen()) {
|
||||
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
||||
file.Write(data);
|
||||
@ -112,7 +112,7 @@ void FrameDumpViewer::Draw() {
|
||||
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
||||
ImGuiComboFlags_WidthFitPreview)) {
|
||||
std::array<bool, 32> available_submits{};
|
||||
for (const auto& cmd : frame_dump.queues) {
|
||||
for (const auto& cmd : frame_dump->queues) {
|
||||
if (cmd.type == selected_queue_type) {
|
||||
available_submits[cmd.submit_num] = true;
|
||||
}
|
||||
@ -137,7 +137,7 @@ void FrameDumpViewer::Draw() {
|
||||
if (BeginCombo("##select_queue_num2", small_int_to_str(selected_queue_num2).data(),
|
||||
ImGuiComboFlags_WidthFitPreview)) {
|
||||
std::array<bool, 32> available_queues{};
|
||||
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) {
|
||||
available_queues[cmd.num2] = true;
|
||||
}
|
||||
@ -152,12 +152,12 @@ void FrameDumpViewer::Draw() {
|
||||
}
|
||||
}
|
||||
if (selected) {
|
||||
const auto it = std::ranges::find_if(frame_dump.queues, [&](const auto& cmd) {
|
||||
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 = std::distance(frame_dump.queues.begin(), it);
|
||||
if (it != frame_dump->queues.end()) {
|
||||
selected_cmd = static_cast<s32>(std::distance(frame_dump->queues.begin(), it));
|
||||
}
|
||||
}
|
||||
EndCombo();
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "cmd_list.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
@ -17,7 +16,7 @@ class CmdListViewer;
|
||||
class FrameDumpViewer {
|
||||
friend class CmdListViewer;
|
||||
|
||||
DebugStateType::FrameDump frame_dump;
|
||||
std::shared_ptr<DebugStateType::FrameDump> frame_dump;
|
||||
int id;
|
||||
|
||||
std::vector<CmdListViewer> cmd_list_viewer;
|
||||
@ -30,7 +29,7 @@ class FrameDumpViewer {
|
||||
public:
|
||||
bool is_open = true;
|
||||
|
||||
explicit FrameDumpViewer(DebugStateType::FrameDump frame_dump);
|
||||
explicit FrameDumpViewer(const DebugStateType::FrameDump& frame_dump);
|
||||
|
||||
~FrameDumpViewer();
|
||||
|
||||
|
107
src/core/devtools/widget/reg_popup.cpp
Normal file
107
src/core/devtools/widget/reg_popup.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "reg_popup.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <imgui.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "cmd_list.h"
|
||||
#include "common.h"
|
||||
|
||||
using namespace ImGui;
|
||||
using magic_enum::enum_name;
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
if (BeginTable("COLOR_BUFFER", 2, ImGuiTableFlags_Borders)) {
|
||||
TableNextRow();
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
if (TreeNode("Color0Info")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Info(buffer.info.u32all, false);
|
||||
TreePop();
|
||||
}
|
||||
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
if (TreeNode("Color0Attrib")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Attrib(buffer.attrib.u32all, false);
|
||||
TreePop();
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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();
|
||||
DrawRow("GetTilingMode()", "%X (%s)", tiling_mode, enum_name(tiling_mode).data());
|
||||
DrawRow("IsTiled()", "%X", buffer.IsTiled());
|
||||
DrawRow("NumFormat()", "%X (%s)", num_format, enum_name(num_format).data());
|
||||
|
||||
// clang-format on
|
||||
|
||||
EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
RegPopup::RegPopup() {
|
||||
static int unique_id = 0;
|
||||
id = unique_id++;
|
||||
}
|
||||
|
||||
void RegPopup::SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id) {
|
||||
this->data = color_buffer;
|
||||
this->title = fmt::format("Batch #{} CB #{}", batch_id, cb_id);
|
||||
}
|
||||
|
||||
void RegPopup::Draw() {
|
||||
|
||||
char name[128];
|
||||
snprintf(name, sizeof(name), "%s###reg_popup_%d", title.c_str(), id);
|
||||
|
||||
SetNextWindowSize({250.0f, 300.0f}, ImGuiCond_FirstUseEver);
|
||||
if (Begin(name, &open, ImGuiWindowFlags_NoSavedSettings)) {
|
||||
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
|
||||
DrawColorBuffer(*buffer);
|
||||
}
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
31
src/core/devtools/widget/reg_popup.h
Normal file
31
src/core/devtools/widget/reg_popup.h
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
class RegPopup {
|
||||
int id;
|
||||
|
||||
std::variant<AmdGpu::Liverpool::ColorBuffer> data;
|
||||
std::string title{};
|
||||
|
||||
void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
||||
|
||||
public:
|
||||
bool open = false;
|
||||
|
||||
RegPopup();
|
||||
|
||||
void SetData(AmdGpu::Liverpool::ColorBuffer color_buffer, u32 batch_id, u32 cb_id);
|
||||
|
||||
void Draw();
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -8,7 +8,7 @@
|
||||
#include <magic_enum.hpp>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cmd_list.h"
|
||||
#include "common.h"
|
||||
#include "common/io_file.h"
|
||||
#include "core/devtools/options.h"
|
||||
#include "imgui_internal.h"
|
||||
@ -19,41 +19,9 @@
|
||||
#define pclose _pclose
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ImGui;
|
||||
using magic_enum::enum_name;
|
||||
|
||||
template <typename... Args>
|
||||
void DrawRow(const char* text, const char* fmt, Args... args) {
|
||||
TableNextColumn();
|
||||
TextUnformatted(text);
|
||||
TableNextColumn();
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), fmt, args...);
|
||||
TextUnformatted(buf);
|
||||
}
|
||||
|
||||
template <typename V, typename... Extra>
|
||||
void DrawMultipleRow(const char* text, const char* fmt, V arg, Extra&&... extra_args) {
|
||||
DrawRow(text, fmt, arg);
|
||||
if constexpr (sizeof...(extra_args) > 0) {
|
||||
DrawMultipleRow(std::forward<Extra>(extra_args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// Must end with EndTable
|
||||
template <typename... Args>
|
||||
static void DoTooltip(const char* str_id, Args&&... args) {
|
||||
if (BeginTooltip()) {
|
||||
if (BeginTable(str_id, 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
DrawMultipleRow(std::forward<Args>(args)...);
|
||||
EndTable();
|
||||
}
|
||||
EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<std::string> exec_cli(const char* cli) {
|
||||
std::array<char, 64> buffer{};
|
||||
std::string output;
|
||||
@ -132,9 +100,9 @@ void RegView::DrawRegs() {
|
||||
|
||||
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
||||
|
||||
auto& scissor = regs.screen_scissor;
|
||||
DrawRow("Scissor", "(%d, %d, %d, %d)", scissor.top_left_x, scissor.top_left_y,
|
||||
scissor.bottom_right_x, scissor.bottom_right_y);
|
||||
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());
|
||||
@ -147,77 +115,40 @@ void RegView::DrawRegs() {
|
||||
|
||||
const auto& buffer = regs.color_buffers[cb];
|
||||
|
||||
bool open = opened_cb[cb];
|
||||
const auto open_new_popup = [&] {
|
||||
auto& pop = extra_reg_popup.emplace_back();
|
||||
pop.SetData(buffer, batch_id, cb);
|
||||
pop.open = true;
|
||||
};
|
||||
|
||||
Text("Color buffer %d", cb);
|
||||
TableNextColumn();
|
||||
if (!buffer || !regs.color_target_mask.GetMask(cb)) {
|
||||
Text("Color buffer %d", cb);
|
||||
TableNextColumn();
|
||||
TextUnformatted("N/A");
|
||||
} else if (last_selected_cb == cb && default_reg_popup.open) {
|
||||
if (SmallButton("x")) {
|
||||
if (GetIO().KeyShift) {
|
||||
open_new_popup();
|
||||
} else {
|
||||
default_reg_popup.open = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SetNextItemOpen(open);
|
||||
bool keep_open = TreeNode("cb", "Color buffer %d", cb);
|
||||
open = opened_cb[cb] = keep_open;
|
||||
}
|
||||
|
||||
if (open) {
|
||||
TableNextRow();
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
if (TreeNode("Color0Info")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Info(buffer.info.u32all, false);
|
||||
TreePop();
|
||||
if (SmallButton("->")) {
|
||||
if (GetIO().KeyShift) {
|
||||
open_new_popup();
|
||||
} else {
|
||||
last_selected_cb = cb;
|
||||
default_reg_popup.SetData(buffer, batch_id, cb);
|
||||
if (!default_reg_popup.open) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
if (TreeNode("Color0Attrib")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Attrib(buffer.attrib.u32all, false);
|
||||
TreePop();
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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();
|
||||
DrawRow("GetTilingMode()", "%X (%s)", tiling_mode, enum_name(tiling_mode).data());
|
||||
DrawRow("IsTiled()", "%X", buffer.IsTiled());
|
||||
DrawRow("NumFormat()", "%X (%s)", num_format, enum_name(num_format).data());
|
||||
|
||||
// clang-format on
|
||||
|
||||
TreePop();
|
||||
}
|
||||
|
||||
PopID();
|
||||
@ -262,18 +193,20 @@ RegView::RegView() {
|
||||
DockBuilderFinish(root_dock_id);
|
||||
}
|
||||
|
||||
void RegView::SetData(DebugStateType::RegDump data) {
|
||||
void RegView::SetData(DebugStateType::RegDump data, u32 batch_id) {
|
||||
this->data = std::move(data);
|
||||
this->batch_id = batch_id;
|
||||
// clear cache
|
||||
selected_shader = -1;
|
||||
opened_cb.fill(false);
|
||||
shader_decomp.clear();
|
||||
default_reg_popup.open = false;
|
||||
extra_reg_popup.clear();
|
||||
}
|
||||
|
||||
void RegView::Draw() {
|
||||
|
||||
char name[128];
|
||||
snprintf(name, sizeof(name), "BatchView###reg_dump_%d", id);
|
||||
snprintf(name, sizeof(name), "BatchView %u###reg_dump_%d", batch_id, id);
|
||||
if (Begin(name, &open, ImGuiWindowFlags_MenuBar)) {
|
||||
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
||||
|
||||
@ -346,6 +279,18 @@ void RegView::Draw() {
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
if (default_reg_popup.open) {
|
||||
default_reg_popup.Draw();
|
||||
}
|
||||
for (auto it = extra_reg_popup.begin(); it != extra_reg_popup.end();) {
|
||||
if (!it->open) {
|
||||
it = extra_reg_popup.erase(it);
|
||||
continue;
|
||||
}
|
||||
it->Draw();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
#include "core/debug_state.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include "reg_popup.h"
|
||||
#include "text_editor.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
@ -16,13 +17,15 @@ struct ShaderCache {
|
||||
|
||||
class RegView {
|
||||
int id;
|
||||
bool first_render = true;
|
||||
|
||||
DebugStateType::RegDump data;
|
||||
u32 batch_id{~0u};
|
||||
|
||||
std::unordered_map<int, ShaderCache> shader_decomp;
|
||||
int selected_shader{-1};
|
||||
std::array<bool, AmdGpu::Liverpool::NumColorBuffers> opened_cb{};
|
||||
RegPopup default_reg_popup;
|
||||
int last_selected_cb{-1};
|
||||
std::vector<RegPopup> extra_reg_popup;
|
||||
|
||||
bool show_registers{true};
|
||||
bool show_user_data{true};
|
||||
@ -39,7 +42,7 @@ public:
|
||||
|
||||
RegView();
|
||||
|
||||
void SetData(DebugStateType::RegDump data);
|
||||
void SetData(DebugStateType::RegDump data, u32 batch_id);
|
||||
|
||||
void Draw();
|
||||
};
|
||||
|
@ -1,48 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
/*
|
||||
* Generic PM4 header
|
||||
*/
|
||||
union PM4Header {
|
||||
struct {
|
||||
u32 reserved : 16;
|
||||
u32 count : 14;
|
||||
u32 type : 2; // PM4_TYPE
|
||||
};
|
||||
u32 u32All;
|
||||
};
|
||||
|
||||
struct PushMarker {
|
||||
std::string name{};
|
||||
};
|
||||
|
||||
struct PopMarker {};
|
||||
|
||||
struct BatchBegin {
|
||||
u32 id;
|
||||
};
|
||||
|
||||
struct BatchInfo {
|
||||
u32 id;
|
||||
std::string marker{};
|
||||
size_t start_addr;
|
||||
size_t end_addr;
|
||||
size_t command_addr;
|
||||
AmdGpu::PM4ItOpcode type;
|
||||
bool bypass{false};
|
||||
};
|
||||
|
||||
using GPUEvent = std::variant<PushMarker, PopMarker, BatchBegin, BatchInfo>;
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
@ -80,8 +80,6 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
|
||||
imgui_font_proggyvector_regular_compressed_size,
|
||||
16.0f);
|
||||
|
||||
GetCurrentContext()->DebugLogFlags |= ImGuiDebugLogFlags_EventDocking;
|
||||
|
||||
StyleColorsDark();
|
||||
|
||||
::Core::Devtools::Layer::SetupSettings();
|
||||
|
Loading…
Reference in New Issue
Block a user