From dce6d35a278954ad633b85dcdb829f13ca25ec13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 10:10:29 -0600 Subject: [PATCH 1/5] ImDebugger: Fix titles of MIPS register views --- UI/ImDebugger/ImDebugger.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 8155acbe7f..69dd68488a 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -141,7 +141,7 @@ void DrawSchedulerView(ImConfig &cfg) { static void DrawGPRs(ImConfig &config, ImControl &control, const MIPSDebugInterface *mipsDebug, const ImSnapshotState &prev) { ImGui::SetNextWindowSize(ImVec2(320, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("MIPS GPRs", &config.gprOpen)) { + if (!ImGui::Begin("GPRs", &config.gprOpen)) { ImGui::End(); return; } @@ -201,7 +201,7 @@ static void DrawGPRs(ImConfig &config, ImControl &control, const MIPSDebugInterf static void DrawFPRs(ImConfig &config, ImControl &control, const MIPSDebugInterface *mipsDebug, const ImSnapshotState &prev) { ImGui::SetNextWindowSize(ImVec2(320, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("MIPS FPRs", &config.fprOpen)) { + if (!ImGui::Begin("FPRs", &config.fprOpen)) { ImGui::End(); return; } @@ -253,7 +253,7 @@ static void DrawFPRs(ImConfig &config, ImControl &control, const MIPSDebugInterf static void DrawVFPU(ImConfig &config, ImControl &control, const MIPSDebugInterface *mipsDebug, const ImSnapshotState &prev) { ImGui::SetNextWindowSize(ImVec2(320, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("MIPS VFPU regs", &config.vfpuOpen)) { + if (!ImGui::Begin("VFPU", &config.vfpuOpen)) { ImGui::End(); return; } From 3d34c734842e93d2770b36a7536520a1328da46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 10:39:17 -0600 Subject: [PATCH 2/5] ImDebugger: Add a visual focus indicator --- UI/EmuScreen.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index ca90bd13c1..094ffc93ed 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -95,6 +95,7 @@ using namespace std::placeholders; #include "UI/DebugOverlay.h" #include "ext/imgui/imgui.h" +#include "ext/imgui/imgui_internal.h" #include "ext/imgui/imgui_impl_thin3d.h" #include "ext/imgui/imgui_impl_platform.h" @@ -1750,7 +1751,22 @@ void EmuScreen::runImDebugger() { io.AddKeyEvent(ImGuiMod_Alt, keyAltLeft_ || keyAltRight_); // io.AddKeyEvent(ImGuiMod_Super, e.key.super); - ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); + ImGuiID dockID = ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); + + ImGuiDockNode* node = ImGui::DockBuilderGetCentralNode(dockID); + + if (!io.WantCaptureKeyboard) { + // Draw a focus rectangle to indicate inputs will be passed through. + ImGui::GetBackgroundDrawList()->AddRect + ( + node->Pos, + { node->Pos.x + node->Size.x, node->Pos.y + node->Size.y }, + IM_COL32(255, 255, 255, 90), + 0.f, + ImDrawFlags_None, + 1.f + ); + } imDebugger_->Frame(currentDebugMIPS, gpuDebug, draw); From 34308a326c0d0192f9dd071e41852b11a34754ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 10:50:32 -0600 Subject: [PATCH 3/5] Add basic sceSas state viewer to debugger --- Core/HLE/sceSas.cpp | 8 ++- Core/HLE/sceSas.h | 4 ++ Core/HW/SasAudio.cpp | 6 +- Core/HW/SasAudio.h | 1 + UI/ImDebugger/ImDebugger.cpp | 109 +++++++++++++++++++++++++++++++++++ UI/ImDebugger/ImDebugger.h | 3 + 6 files changed, 126 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 5252ec2580..05091303fd 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -77,7 +77,11 @@ enum { // TODO - allow more than one, associating each with one Core pointer (passed in to all the functions) // No known games use more than one instance of Sas though. -static SasInstance *sas = NULL; +static SasInstance *sas; + +SasInstance *GetSasInstance() { + return sas; +} enum SasThreadState { DISABLED, @@ -247,7 +251,7 @@ static u32 sceSasInit(u32 core, u32 grainSize, u32 maxVoices, u32 outputMode, u3 INFO_LOG(Log::sceSas, "sceSasInit(%08x, %i, %i, %i, %i)", core, grainSize, maxVoices, outputMode, sampleRate); sas->SetGrainSize(grainSize); - // Seems like maxVoices is actually ignored for all intents and purposes. + // Seems like the maxVoices param is actually ignored for all intents and purposes. sas->maxVoices = PSP_SAS_VOICES_MAX; sas->outputMode = outputMode; for (int i = 0; i < sas->maxVoices; i++) { diff --git a/Core/HLE/sceSas.h b/Core/HLE/sceSas.h index a957f3d475..66dc65db6d 100644 --- a/Core/HLE/sceSas.h +++ b/Core/HLE/sceSas.h @@ -24,3 +24,7 @@ void __SasShutdown(); void __SasGetDebugStats(char *stats, size_t bufsize); void Register_sceSasCore(); + +class SasInstance; + +SasInstance *GetSasInstance(); diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 081469c1ef..7532297397 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -188,9 +188,9 @@ void VagDecoder::DoState(PointerWrap &p) { Do(p, end_); } -int SasAtrac3::setContext(u32 context) { - contextAddr_ = context; - atracID_ = AtracSasGetIDByContext(context); +int SasAtrac3::setContext(u32 contextAddr) { + contextAddr_ = contextAddr; + atracID_ = AtracSasGetIDByContext(contextAddr); if (!sampleQueue_) sampleQueue_ = new BufferQueue(); sampleQueue_->clear(); diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index 7cd5e094f1..1cd2bc255c 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -140,6 +140,7 @@ public: SasAtrac3() : contextAddr_(0), atracID_(-1), sampleQueue_(0), end_(false) {} ~SasAtrac3() { delete sampleQueue_; } int setContext(u32 context); + int id() const { return atracID_; } void getNextSamples(s16 *outbuf, int wantedSamples); int addStreamData(u32 bufPtr, u32 addbytes); void DoState(PointerWrap &p); diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 69dd68488a..77a3bdf9a5 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -36,6 +36,9 @@ #include "Core/HLE/sceAudiocodec.h" #include "Core/HLE/sceMp3.h" #include "Core/HLE/AtracCtx.h" +#include "Core/HLE/sceSas.h" +#include "Core/HW/SasAudio.h" + #include "Core/CoreTiming.h" // Threads window #include "Core/HLE/sceKernelThread.h" @@ -1053,6 +1056,106 @@ void DrawAudioChannels(ImConfig &cfg) { ImGui::End(); } +static const char *VoiceTypeToString(VoiceType type) { + switch (type) { + case VOICETYPE_OFF: return "OFF"; + case VOICETYPE_VAG: return "VAG"; // default + case VOICETYPE_NOISE: return "NOISE"; + case VOICETYPE_TRIWAVE: return "TRIWAVE"; // are these used? there are functions for them (sceSetTriangularWave) + case VOICETYPE_PULSEWAVE: return "PULSEWAVE"; + case VOICETYPE_PCM: return "PCM"; + case VOICETYPE_ATRAC3: return "ATRAC3"; + default: return "(unknown!)"; + } +} + +void DrawSasAudio(ImConfig &cfg) { + if (!ImGui::Begin("sasAudio", &cfg.sasAudioOpen)) { + ImGui::End(); + return; + } + + const SasInstance *sas = GetSasInstance(); + if (!sas) { + ImGui::Text("Sas instance not available"); + ImGui::End(); + return; + } + + ImGui::Checkbox("Show all voices", &cfg.sasShowAllVoices); + + if (ImGui::BeginTable("saschannels", 9, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) { + ImGui::TableSetupColumn("Index", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Loop", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Pause", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Cur", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Addr", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("Volume", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableHeadersRow(); + + for (int i = 0; i < PSP_SAS_VOICES_MAX; i++) { + const SasVoice &voice = sas->voices[i]; + if (!voice.on && !cfg.sasShowAllVoices) { + continue; + } + if (!voice.on) { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 128)); + } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%d", i); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(VoiceTypeToString(voice.type)); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(BoolStr(voice.on)); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(BoolStr(voice.loop)); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(BoolStr(voice.paused)); + ImGui::TableNextColumn(); + switch (voice.type) { + case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; + case VOICETYPE_VAG: ImGui::Text("%08x", voice.vag.GetReadPtr()); break; + case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmAddr + voice.pcmIndex * 2); break; + default: + ImGui::TextUnformatted("N/A"); + break; + } + ImGui::TableNextColumn(); + switch (voice.type) { + case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; + case VOICETYPE_VAG: ImGui::Text("%08x", voice.vagAddr); break; + case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmAddr); break; + case VOICETYPE_ATRAC3: ImGui::Text("atrac: %d", voice.atrac3.id()); break; + default: + ImGui::TextUnformatted("N/A"); + break; + } + ImGui::TableNextColumn(); + switch (voice.type) { + case VOICETYPE_OFF: ImGui::TextUnformatted("(off)"); break; + case VOICETYPE_VAG: ImGui::Text("%08x", voice.vagSize); break; + case VOICETYPE_PCM: ImGui::Text("%08x", voice.pcmSize); break; + case VOICETYPE_ATRAC3: ImGui::Text("atrac: n/a"); break; + default: + ImGui::TextUnformatted("N/A"); + break; + } + ImGui::TableNextColumn(); + ImGui::Text("%d | %d", voice.volumeLeft, voice.volumeRight); + if (!voice.on) { + ImGui::PopStyleColor(); + } + } + + ImGui::EndTable(); + } + ImGui::End(); +} + static void DrawCallStacks(const MIPSDebugInterface *debug, bool *open) { if (!ImGui::Begin("Callstacks", open)) { ImGui::End(); @@ -1327,6 +1430,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu ImGui::EndMenu(); } if (ImGui::BeginMenu("Audio")) { + ImGui::MenuItem("SasAudio mixer", nullptr, &cfg_.sasAudioOpen); ImGui::MenuItem("Raw audio channels", nullptr, &cfg_.audioChannelsOpen); ImGui::MenuItem("Decoder contexts", nullptr, &cfg_.audioDecodersOpen); ImGui::EndMenu(); @@ -1391,6 +1495,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu DrawAudioChannels(cfg_); } + if (cfg_.sasAudioOpen) { + DrawSasAudio(cfg_); + } + if (cfg_.kernelObjectsOpen) { DrawKernelObjects(cfg_); } @@ -1851,6 +1959,7 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) { sync.Sync("apctlOpen", &apctlOpen, false); sync.Sync("pixelViewerOpen", &pixelViewerOpen, false); sync.Sync("internalsOpen", &internalsOpen, false); + sync.Sync("sasAudioOpen", &sasAudioOpen, false); for (int i = 0; i < 4; i++) { char name[64]; snprintf(name, sizeof(name), "memory%dOpen", i + 1); diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index 80f7d204fb..685c99373e 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -147,6 +147,7 @@ struct ImConfig { bool adhocOpen; bool memDumpOpen; bool internalsOpen; + bool sasAudioOpen; bool memViewOpen[4]; // HLE explorer settings @@ -166,6 +167,8 @@ struct ImConfig { bool displayLatched = false; int requesterToken; + bool sasShowAllVoices = false; + // We use a separate ini file from the main PPSSPP config. void LoadConfig(const Path &iniFile); void SaveConfig(const Path &iniFile); From 1f7461bb7092209bcf798d42751f19cfc48ad538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 11:00:20 -0600 Subject: [PATCH 4/5] When ImDebugger is active, shrink the display area to match the central node. --- GPU/Common/PresentationCommon.cpp | 12 ++++++++++++ GPU/Common/PresentationCommon.h | 1 - UI/EmuScreen.cpp | 5 +++-- ext/imgui/imgui_impl_platform.cpp | 1 + ext/imgui/imgui_impl_platform.h | 3 +++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 3b862c88c4..2670f65ea4 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -26,6 +26,7 @@ #include "Common/System/OSD.h" #include "Common/File/VFS/VFS.h" #include "Common/VR/PPSSPPVR.h" +#include "Common/Math/geom2d.h" #include "Common/Log.h" #include "Common/TimeUtil.h" #include "Core/Config.h" @@ -43,6 +44,8 @@ struct Vertex { uint32_t rgba; }; +extern Bounds g_imguiCentralNodeBounds; + FRect GetScreenFrame(float pixelWidth, float pixelHeight) { FRect rc = FRect{ 0.0f, @@ -66,6 +69,15 @@ FRect GetScreenFrame(float pixelWidth, float pixelHeight) { rc.y += top; rc.h -= (top + bottom); } + + if (g_Config.bShowImDebugger) { + // Set rectangle to match central node. Here we ignore bIgnoreScreenInsets. + rc.x = g_imguiCentralNodeBounds.x; + rc.y = g_imguiCentralNodeBounds.y; + rc.w = g_imguiCentralNodeBounds.w; + rc.h = g_imguiCentralNodeBounds.h; + } + return rc; } diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 2da590dfc5..cfda5b8bc0 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -39,7 +39,6 @@ struct PostShaderUniforms { float gl_HalfPixel[4]; }; -// Could use UI::Bounds but don't want to depend on that here. struct FRect { float x; float y; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 094ffc93ed..1ffa352677 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1752,9 +1752,11 @@ void EmuScreen::runImDebugger() { // io.AddKeyEvent(ImGuiMod_Super, e.key.super); ImGuiID dockID = ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); - ImGuiDockNode* node = ImGui::DockBuilderGetCentralNode(dockID); + // Not elegant! But don't know how else to pass through the bounds, without making a mess. + g_imguiCentralNodeBounds = Bounds(node->Pos.x, node->Pos.y, node->Size.x, node->Size.y); + if (!io.WantCaptureKeyboard) { // Draw a focus rectangle to indicate inputs will be passed through. ImGui::GetBackgroundDrawList()->AddRect @@ -1767,7 +1769,6 @@ void EmuScreen::runImDebugger() { 1.f ); } - imDebugger_->Frame(currentDebugMIPS, gpuDebug, draw); // Convert to drawlists. diff --git a/ext/imgui/imgui_impl_platform.cpp b/ext/imgui/imgui_impl_platform.cpp index aaa606d470..720126ab0f 100644 --- a/ext/imgui/imgui_impl_platform.cpp +++ b/ext/imgui/imgui_impl_platform.cpp @@ -10,6 +10,7 @@ #include "imgui_impl_platform.h" static ImGuiMouseCursor g_cursor = ImGuiMouseCursor_Arrow; +Bounds g_imguiCentralNodeBounds; void ImGui_ImplPlatform_KeyEvent(const KeyInput &key) { ImGuiIO &io = ImGui::GetIO(); diff --git a/ext/imgui/imgui_impl_platform.h b/ext/imgui/imgui_impl_platform.h index 4f25c19239..67b0d0f18f 100644 --- a/ext/imgui/imgui_impl_platform.h +++ b/ext/imgui/imgui_impl_platform.h @@ -3,6 +3,7 @@ #include "ext/imgui/imgui.h" #include "Common/Input/KeyCodes.h" #include "Common/Input/InputState.h" +#include "Common/Math/geom2d.h" class Path; @@ -15,4 +16,6 @@ void ImGui_ImplPlatform_KeyEvent(const KeyInput &key); void ImGui_ImplPlatform_TouchEvent(const TouchInput &touch); void ImGui_ImplPlatform_AxisEvent(const AxisInput &axis); +extern Bounds g_imguiCentralNodeBounds; + ImGuiMouseCursor ImGui_ImplPlatform_GetCursor(); From e8bfcb433e8478bc624183dd5f800283ef6f7cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 11:09:49 -0600 Subject: [PATCH 5/5] Logspam fix (when fast-forwarding) --- Core/HLE/sceDisplay.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 17d56c667d..0b7bae03cc 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -649,15 +649,17 @@ void __DisplayFlip(int cyclesLate) { if (fbReallyDirty || noRecentFlip || postEffectRequiresFlip) { // Check first though, might've just quit / been paused. - if (!forceNoFlip) + if (!forceNoFlip) { nextFrame = Core_NextFrame(); + if (!nextFrame) { + WARN_LOG(Log::sceDisplay, "Core_NextFrame returned false"); + } + } if (nextFrame) { gpu->CopyDisplayToOutput(fbReallyDirty); if (fbReallyDirty) { DisplayFireActualFlip(); } - } else { - WARN_LOG(Log::sceDisplay, "Core_NextFrame returned false"); } }