Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImDebugger: Framebuffer listing, keyboard shortcuts and more #19647

Merged
merged 4 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,8 @@ list(APPEND NativeAppSource
android/jni/TestRunner.cpp
UI/ImDebugger/ImDebugger.cpp
UI/ImDebugger/ImDebugger.h
UI/ImDebugger/ImGe.cpp
UI/ImDebugger/ImGe.h
UI/ImDebugger/ImDisasmView.cpp
UI/ImDebugger/ImDisasmView.h
UI/ImDebugger/ImStructViewer.cpp
Expand Down
3 changes: 3 additions & 0 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,9 @@ class VKFramebuffer : public Framebuffer {
void UpdateTag(const char *newTag) override {
buf_->UpdateTag(newTag);
}
const char *Tag() const override {
return buf_->Tag();
}
private:
VKRFramebuffer *buf_;
};
Expand Down
2 changes: 2 additions & 0 deletions Common/GPU/thin3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ class Framebuffer : public RefCountedObject {
int MultiSampleLevel() const { return multiSampleLevel_; }

virtual void UpdateTag(const char *tag) {}
virtual const char *Tag() const { return "(no name)"; }

protected:
int width_ = -1, height_ = -1, layers_ = 1, multiSampleLevel_ = 0;
};
Expand Down
1 change: 1 addition & 0 deletions Common/Log/ConsoleListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ void ConsoleListener::Close() {
if (thread_.joinable()) {
logPendingWritePos_.store((u32)-1, std::memory_order_release);
SetEvent(hTriggerEvent);
// If we seem hung here, it's just that you made a selection in the debug console, blocking output.
thread_.join();
}
if (hTriggerEvent) {
Expand Down
45 changes: 45 additions & 0 deletions GPU/Common/FramebufferManagerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <sstream>
#include <cmath>

#include "ext/imgui/imgui.h"

#include "Common/GPU/thin3d.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/Data/Collections/TinySet.h"
Expand Down Expand Up @@ -3661,3 +3663,46 @@ static void ApplyKillzoneFramebufferSplit(FramebufferHeuristicParams *params, in
*drawing_width = 480;
}
}

void FramebufferManagerCommon::DrawImGuiDebug(int &selected) const {
ImGui::BeginTable("framebuffers", 4);
ImGui::TableSetupColumn("Tag");
ImGui::TableSetupColumn("Color Addr");
ImGui::TableSetupColumn("Depth Addr");
ImGui::TableSetupColumn("Size");

ImGui::TableHeadersRow();
ImGui::TableSetColumnIndex(0);

for (int i = 0; i < (int)vfbs_.size(); i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();

auto &vfb = vfbs_[i];

const char *tag = vfb->fbo ? vfb->fbo->Tag() : "(no tag)";

ImGui::PushID(i);
if (ImGui::Selectable(tag, selected == i, ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_SpanAllColumns)) {
selected = i;
}
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
selected = i;
ImGui::OpenPopup("framebufferPopup");
}
ImGui::TableNextColumn();
ImGui::Text("%08x", vfb->fb_address);
ImGui::TableNextColumn();
ImGui::Text("%08x", vfb->z_address);
ImGui::TableNextColumn();
ImGui::Text("%dx%d", vfb->width, vfb->height);
if (ImGui::BeginPopup("framebufferPopup")) {
ImGui::Text("Framebuffer: %s", tag);
ImGui::EndPopup();
}
ImGui::PopID();
}
ImGui::EndTable();

// Now, draw the actual framebuffer image. This could be refined a lot.
}
2 changes: 2 additions & 0 deletions GPU/Common/FramebufferManagerCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ class FramebufferManagerCommon {

bool PresentedThisFrame() const;

void DrawImGuiDebug(int &selected) const;

protected:
virtual void ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode);
// Used for when a shader is required, such as GLES.
Expand Down
5 changes: 5 additions & 0 deletions GPU/Common/GPUDebugInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "GPU/GPU.h"
#include "GPU/GPUInterface.h"

class FramebufferManagerCommon;

struct GPUDebugOp {
u32 pc;
u8 cmd;
Expand Down Expand Up @@ -218,6 +220,9 @@ class GPUDebugInterface {

virtual uint32_t SetAddrTranslation(uint32_t value) = 0;
virtual uint32_t GetAddrTranslation() = 0;

// TODO: Make a proper debug interface instead of accessing directly?
virtual FramebufferManagerCommon *GetFramebufferManagerCommon() = 0;

virtual bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
return false;
Expand Down
4 changes: 4 additions & 0 deletions GPU/GPUCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ class GPUCommon : public GPUInterface, public GPUDebugInterface {
bool GetCurrentDisplayList(DisplayList &list) override;
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;

FramebufferManagerCommon *GetFramebufferManagerCommon() override {
return nullptr;
}

std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
return "N/A";
Expand Down
4 changes: 4 additions & 0 deletions GPU/GPUCommonHW.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ class GPUCommonHW : public GPUCommon {
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
bool GetCurrentClut(GPUDebugBuffer &buffer) override;

FramebufferManagerCommon *GetFramebufferManagerCommon() override {
return framebufferManager_;
}

// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
Expand Down
2 changes: 1 addition & 1 deletion UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1656,7 +1656,7 @@ void EmuScreen::renderImDebugger() {
ImGui_ImplThin3d_NewFrame(draw, ui_draw2d.GetDrawMatrix());

ImGui::NewFrame();
imDebugger_->Frame(currentDebugMIPS);
imDebugger_->Frame(currentDebugMIPS, gpuDebug);

ImGui::Render();
ImGui_ImplThin3d_RenderDrawData(ImGui::GetDrawData(), draw);
Expand Down
84 changes: 70 additions & 14 deletions UI/ImDebugger/ImDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@
// Callstack window
#include "Core/MIPS/MIPSStackWalk.h"

// GPU things
#include "GPU/Common/GPUDebugInterface.h"

#include "UI/ImDebugger/ImDebugger.h"
#include "UI/ImDebugger/ImGe.h"

void DrawRegisterView(MIPSDebugInterface *mipsDebug, bool *open) {
if (!ImGui::Begin("Registers", open)) {
Expand Down Expand Up @@ -332,7 +336,7 @@ void DrawHLEModules(ImConfig &config) {
ImGui::End();
}

void ImDebugger::Frame(MIPSDebugInterface *mipsDebug) {
void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug) {
// Snapshot the coreState to avoid inconsistency.
const CoreState coreState = ::coreState;

Expand Down Expand Up @@ -370,21 +374,32 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug) {
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window")) {
ImGui::Checkbox("Dear ImGUI Demo", &cfg_.demoOpen);
ImGui::Checkbox("CPU debugger", &cfg_.disasmOpen);
ImGui::Checkbox("Registers", &cfg_.regsOpen);
ImGui::Checkbox("Callstacks", &cfg_.callstackOpen);
ImGui::Checkbox("HLE Modules", &cfg_.modulesOpen);
ImGui::Checkbox("HLE Threads", &cfg_.threadsOpen);
ImGui::Checkbox("sceAtrac", &cfg_.atracOpen);
ImGui::Checkbox("Struct viewer", &cfg_.structViewerOpen);
if (ImGui::BeginMenu("CPU")) {
ImGui::MenuItem("CPU debugger", nullptr, &cfg_.disasmOpen);
ImGui::MenuItem("Registers", nullptr, &cfg_.regsOpen);
ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("OS HLE")) {
ImGui::MenuItem("HLE Threads", nullptr, &cfg_.threadsOpen);
ImGui::MenuItem("HLE Modules",nullptr, &cfg_.modulesOpen);
ImGui::MenuItem("sceAtrac", nullptr, &cfg_.atracOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Ge (GPU)")) {
ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen);
// More to come here...
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Struct viewer", nullptr, &cfg_.structViewerOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Misc")) {
if (ImGui::MenuItem("Close Debugger")) {
g_Config.bShowImDebugger = false;
}
ImGui::MenuItem("Dear ImGUI Demo", nullptr, &cfg_.demoOpen);
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
Expand Down Expand Up @@ -422,6 +437,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug) {
DrawHLEModules(cfg_);
}

if (cfg_.framebuffersOpen) {
DrawFramebuffersWindow(cfg_, gpuDebug->GetFramebufferManagerCommon());
}

if (cfg_.structViewerOpen) {
structViewer_.Draw(mipsDebug, &cfg_.structViewerOpen);
}
Expand Down Expand Up @@ -483,6 +502,26 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
disasmView_.gotoPC();
}

if (ImGui::BeginPopup("disSearch")) {
if (ImGui::InputText("Search", searchTerm_, sizeof(searchTerm_), ImGuiInputTextFlags_EnterReturnsTrue)) {
disasmView_.Search(searchTerm_);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}

ImGui::SameLine();
if (ImGui::SmallButton("Search")) {
// Open a small popup
ImGui::OpenPopup("disSearch");
ImGui::Shortcut(ImGuiKey_F | ImGuiMod_Ctrl);
}

ImGui::SameLine();
if (ImGui::SmallButton("Next")) {
disasmView_.SearchNext(true);
}

ImGui::SameLine();
ImGui::Checkbox("Follow PC", &disasmView_.followPC_);

Expand All @@ -497,18 +536,35 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
ImGui::TableSetupColumn("right", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);

if (symCache_.empty() || symsDirty_) {
symCache_ = g_symbolMap->GetAllSymbols(SymbolType::ST_FUNCTION);
symsDirty_ = false;
}

if (selectedSymbol_ >= 0 && selectedSymbol_ < symCache_.size()) {
auto &sym = symCache_[selectedSymbol_];
if (ImGui::TreeNode("Edit Symbol", "Edit %s", sym.name.c_str())) {
if (ImGui::InputText("Name", selectedSymbolName_, sizeof(selectedSymbolName_), ImGuiInputTextFlags_EnterReturnsTrue)) {
g_symbolMap->SetLabelName(selectedSymbolName_, sym.address);
symsDirty_ = true;
}
ImGui::Text("%08x (size: %0d)", sym.address, sym.size);
ImGui::TreePop();
}
}

ImVec2 sz = ImGui::GetContentRegionAvail();
if (ImGui::BeginListBox("##symbols", ImVec2(150.0, sz.y - ImGui::GetTextLineHeightWithSpacing() * 2))) {
if (symCache_.empty()) {
symCache_ = g_symbolMap->GetAllSymbols(SymbolType::ST_FUNCTION);
}
ImGuiListClipper clipper;
clipper.Begin((int)symCache_.size(), -1);
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
if (ImGui::Selectable(symCache_[i].name.c_str(), false)) {
if (ImGui::Selectable(symCache_[i].name.c_str(), selectedSymbol_ == i)) {
disasmView_.gotoAddr(symCache_[i].address);
disasmView_.scrollAddressIntoView();
truncate_cpy(selectedSymbolName_, symCache_[i].name.c_str());
selectedSymbol_ = i;
}
}
}
Expand Down
19 changes: 17 additions & 2 deletions UI/ImDebugger/ImDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@

#include "UI/ImDebugger/ImDisasmView.h"
#include "UI/ImDebugger/ImStructViewer.h"
#include "UI/ImDebugger/ImGe.h"

// This is the main state container of the whole Dear ImGUI-based in-game cross-platform debugger.
//
// Code conventions for ImGUI in PPSSPP
// * If windows/objects need state, prefix the class name with Im and just store straight in parent struct

class MIPSDebugInterface;

class GPUDebugInterface;

// Corresponds to the CDisasm dialog
class ImDisasmWindow {
Expand All @@ -40,8 +41,12 @@ class ImDisasmWindow {

// Symbol cache
std::vector<SymbolEntry> symCache_;
bool symsDirty_ = true;
int selectedSymbol_ = -1;
char selectedSymbolName_[128];

ImDisasmView disasmView_;
char searchTerm_[64]{};
};

class ImLuaConsole {
Expand All @@ -59,17 +64,27 @@ struct ImConfig {
bool hleModulesOpen = false;
bool atracOpen = true;
bool structViewerOpen = false;
bool framebuffersOpen = false;

// HLE explorer settings
// bool filterByUsed = true;

// Various selections
int selectedModule = 0;
int selectedThread = 0;
int selectedFramebuffer = -1;
};

enum ImUiCmd {
TRIGGER_FIND_POPUP = 0,
};

struct ImUiCommand {
ImUiCmd cmd;
};

struct ImDebugger {
void Frame(MIPSDebugInterface *mipsDebug);
void Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug);

ImDisasmWindow disasm_;
ImLuaConsole luaConsole_;
Expand Down
Loading
Loading