From 3676f4792e44bf777ff18a9f806ea8761059718f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 8 Apr 2025 11:30:37 +0200 Subject: [PATCH] GE debugger: Split out the vertices window, show matrices in state window --- Core/HLE/sceReg.cpp | 2 + UI/ImDebugger/ImDebugger.cpp | 6 ++ UI/ImDebugger/ImDebugger.h | 1 + UI/ImDebugger/ImGe.cpp | 198 +++++++++++++++++++++-------------- UI/ImDebugger/ImGe.h | 2 + 5 files changed, 132 insertions(+), 77 deletions(-) diff --git a/Core/HLE/sceReg.cpp b/Core/HLE/sceReg.cpp index a88f0e4ce3..cb2249f8dc 100644 --- a/Core/HLE/sceReg.cpp +++ b/Core/HLE/sceReg.cpp @@ -61,6 +61,8 @@ struct KeyValue { // Dump of the PSP registry using tests/misc/reg.prx in pspautotests +// TODO: /DATA/FONT/PROPERTY could just be generated from our fontRegistry in sceFont.cpp. + // Dump of /DATA/FONT/PROPERTY/INFO0 static const KeyValue tree_DATA_FONT_PROPERTY_INFO0[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index c64708ba08..bb445690e3 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1916,6 +1916,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu if (ImGui::BeginMenu("Graphics")) { ImGui::MenuItem("GE Debugger", nullptr, &cfg_.geDebuggerOpen); ImGui::MenuItem("GE State", nullptr, &cfg_.geStateOpen); + ImGui::MenuItem("GE Vertices", nullptr, &cfg_.geVertsOpen); ImGui::MenuItem("Display Output", nullptr, &cfg_.displayOpen); ImGui::MenuItem("Textures", nullptr, &cfg_.texturesOpen); ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen); @@ -2067,6 +2068,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu geStateWindow_.Draw(cfg_, control, gpuDebug); } + if (cfg_.geVertsOpen) { + DrawImGeVertsWindow(cfg_, control, gpuDebug); + } + if (cfg_.schedulerOpen) { DrawSchedulerView(cfg_); } @@ -2505,6 +2510,7 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) { sync.Sync("debugStatsOpen", &debugStatsOpen, false); sync.Sync("geDebuggerOpen", &geDebuggerOpen, false); sync.Sync("geStateOpen", &geStateOpen, false); + sync.Sync("geVertsOpen", &geVertsOpen, false); sync.Sync("schedulerOpen", &schedulerOpen, false); sync.Sync("socketsOpen", &socketsOpen, false); sync.Sync("npOpen", &npOpen, false); diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index d93e66e181..9d7c29f7c0 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -139,6 +139,7 @@ struct ImConfig { bool debugStatsOpen; bool geDebuggerOpen; bool geStateOpen; + bool geVertsOpen; bool schedulerOpen; bool watchOpen; bool pixelViewerOpen; diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index a7756b3782..467a8c4626 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -1414,92 +1414,136 @@ void ImGeStateWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterface buildStateTab("Lighting", g_lightingState, ARRAY_SIZE(g_lightingState)); buildStateTab("Transform/Tess", g_vertexState, ARRAY_SIZE(g_vertexState)); - // Do a vertex tab (maybe later a separate window) - if (ImGui::BeginTabItem("Vertices")) { - const ImGuiTableFlags tableFlags = - ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; - if (ImGui::BeginTabBar("vertexmode", ImGuiTabBarFlags_None)) { - auto state = gpuDebug->GetGState(); - char fmtTemp[256]; - FormatStateRow(gpuDebug, fmtTemp, sizeof(fmtTemp), CMD_FMT_VERTEXTYPE, state.vertType, true, false, false); - ImGui::TextUnformatted(fmtTemp); - // Let's see if it's fast enough to just do all this each frame. - int rowCount_ = gpuDebug->GetCurrentPrimCount(); - std::vector vertices; - std::vector indices; - if (!gpuDebug->GetCurrentDrawAsDebugVertices(rowCount_, vertices, indices)) { - rowCount_ = 0; - } - auto buildVertexTable = [&](bool raw) { - // Ignore indices for now. - if (ImGui::BeginTable("rawverts", VERTEXLIST_COL_COUNT + 1, tableFlags)) { - static VertexDecoder decoder; - u32 vertTypeID = GetVertTypeID(state.vertType, state.getUVGenMode(), true); - VertexDecoderOptions options{}; - decoder.SetVertexType(vertTypeID, options); - - static const char * const colNames[] = { - "Index", - "X", - "Y", - "Z", - "U", - "V", - "Color", - "NX", - "NY", - "NZ", - }; - for (int i = 0; i < ARRAY_SIZE(colNames); i++) { - ImGui::TableSetupColumn(colNames[i], ImGuiTableColumnFlags_WidthFixed, 0.0f, i); + if (ImGui::BeginTabItem("Matrices")) { + auto visMatrix = [](const char *name, const float *data, bool is4x4) { + ImGui::TextUnformatted(name); + int stride = (is4x4 ? 4 : 3); + if (ImGui::BeginTable(name, stride, ImGuiTableFlags_Borders, ImVec2(90.0f * stride, 0.0f))) { + for (int row = 0; row < 4; ++row) { + ImGui::TableNextRow(); + for (int col = 0; col < stride; ++col) { + ImGui::TableSetColumnIndex(col); + ImGui::Text("%.4f", data[row * stride + col]); } - ImGui::TableSetupScrollFreeze(0, 1); // Make header row always visible - ImGui::TableHeadersRow(); - - ImGuiListClipper clipper; - _dbg_assert_(rowCount_ >= 0); - clipper.Begin(rowCount_); - while (clipper.Step()) { - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - int index = indices.empty() ? i : indices[i]; - ImGui::PushID(i); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%d", index); - for (int column = 0; column < VERTEXLIST_COL_COUNT; column++) { - ImGui::TableNextColumn(); - char temp[36]; - if (raw) { - FormatVertColRaw(&decoder, temp, sizeof(temp), index, column); - } else { - FormatVertCol(temp, sizeof(temp), vertices[index], column); - } - ImGui::TextUnformatted(temp); - } - ImGui::PopID(); - } - } - clipper.End(); - - ImGui::EndTable(); } - }; + ImGui::EndTable(); + } + }; - if (ImGui::BeginTabItem("Raw")) { - buildVertexTable(true); - ImGui::EndTabItem(); + if (ImGui::CollapsingHeader("Common", ImGuiTreeNodeFlags_DefaultOpen)) { + if (gstate.isModeThrough()) { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 160)); + ImGui::TextUnformatted("Through mode: No matrices are used"); } - if (ImGui::BeginTabItem("Transformed")) { - buildVertexTable(false); - ImGui::EndTabItem(); + visMatrix("World", gstate.worldMatrix, false); + visMatrix("View", gstate.viewMatrix, false); + visMatrix("Proj", gstate.projMatrix, true); + visMatrix("Tex", gstate.tgenMatrix, false); + if (gstate.isModeThrough()) { + ImGui::PopStyleColor(); } - // TODO: Let's not include columns for which we have no data. - ImGui::EndTabBar(); } + + if (ImGui::CollapsingHeader("Bone matrices")) { + for (int i = 0; i < 8; i++) { + char n[16]; + snprintf(n, sizeof(n), "Bone %d", i); + visMatrix(n, gstate.boneMatrix + 12 * i, false); + } + } + ImGui::EndTabItem(); } + ImGui::EndTabBar(); + } + ImGui::End(); +} +void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUDebugInterface *gpuDebug) { + ImGui::SetNextWindowSize(ImVec2(300, 500), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("GE Vertices", &cfg.geVertsOpen)) { + ImGui::End(); + return; + } + const ImGuiTableFlags tableFlags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; + if (ImGui::BeginTabBar("vertexmode", ImGuiTabBarFlags_None)) { + auto state = gpuDebug->GetGState(); + char fmtTemp[256]; + FormatStateRow(gpuDebug, fmtTemp, sizeof(fmtTemp), CMD_FMT_VERTEXTYPE, state.vertType, true, false, false); + ImGui::TextUnformatted(fmtTemp); + // Let's see if it's fast enough to just do all this each frame. + int rowCount_ = gpuDebug->GetCurrentPrimCount(); + std::vector vertices; + std::vector indices; + if (!gpuDebug->GetCurrentDrawAsDebugVertices(rowCount_, vertices, indices)) { + rowCount_ = 0; + } + auto buildVertexTable = [&](bool raw) { + // Ignore indices for now. + if (ImGui::BeginTable("rawverts", VERTEXLIST_COL_COUNT + 1, tableFlags)) { + static VertexDecoder decoder; + u32 vertTypeID = GetVertTypeID(state.vertType, state.getUVGenMode(), true); + VertexDecoderOptions options{}; + decoder.SetVertexType(vertTypeID, options); + + static const char * const colNames[] = { + "Index", + "X", + "Y", + "Z", + "U", + "V", + "Color", + "NX", + "NY", + "NZ", + }; + for (int i = 0; i < ARRAY_SIZE(colNames); i++) { + ImGui::TableSetupColumn(colNames[i], ImGuiTableColumnFlags_WidthFixed, 0.0f, i); + } + ImGui::TableSetupScrollFreeze(0, 1); // Make header row always visible + ImGui::TableHeadersRow(); + + ImGuiListClipper clipper; + _dbg_assert_(rowCount_ >= 0); + clipper.Begin(rowCount_); + while (clipper.Step()) { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + int index = indices.empty() ? i : indices[i]; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::PushID(i); + ImGui::Text("%d", index); + for (int column = 0; column < VERTEXLIST_COL_COUNT; column++) { + ImGui::TableNextColumn(); + char temp[36]; + if (raw) { + FormatVertColRaw(&decoder, temp, sizeof(temp), index, column); + } else { + FormatVertCol(temp, sizeof(temp), vertices[index], column); + } + ImGui::TextUnformatted(temp); + } + ImGui::PopID(); + } + } + clipper.End(); + + ImGui::EndTable(); + } + }; + + if (ImGui::BeginTabItem("Raw")) { + buildVertexTable(true); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Transformed")) { + buildVertexTable(false); + ImGui::EndTabItem(); + } + // TODO: Let's not include columns for which we have no data. ImGui::EndTabBar(); } ImGui::End(); diff --git a/UI/ImDebugger/ImGe.h b/UI/ImDebugger/ImGe.h index e2066a4fd5..53b5cbbab8 100644 --- a/UI/ImDebugger/ImGe.h +++ b/UI/ImDebugger/ImGe.h @@ -50,6 +50,8 @@ public: void Snapshot(); }; +void DrawImGeVertsWindow(ImConfig &cfg, ImControl &control, GPUDebugInterface *gpuDebug); + namespace Draw { class Texture; enum class Aspect;