Merge pull request #19663 from hrydgard/more-imdebugger

ImDebugger: Add config saving, add new audio channels window
This commit is contained in:
Henrik Rydgård 2024-11-27 13:35:36 +01:00 committed by GitHub
commit 5273d993bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 296 additions and 69 deletions

View file

@ -1677,11 +1677,10 @@ const Path Config::FindConfigFile(const std::string &baseFilename) {
}
// Make sure at least the directory it's supposed to be in exists.
Path path = filename.NavigateUp();
// This check is just to avoid logging.
if (!File::Exists(path)) {
File::CreateFullPath(path);
}
Path parent = filename.NavigateUp();
// We try to create the path and ignore if it fails (already exists).
File::CreateFullPath(parent);
return filename;
}

View file

@ -36,15 +36,15 @@ struct AudioCodecContext {
u32_le inDataSizeAgain; // 10 ??
};
// audioList is to store current playing audios.
static std::map<u32, AudioDecoder *> audioList;
// g_audioDecoderContexts is to store current playing audios.
std::map<u32, AudioDecoder *> g_audioDecoderContexts;
static bool oldStateLoaded = false;
// find the audio decoder for corresponding ctxPtr in audioList
static AudioDecoder *findDecoder(u32 ctxPtr) {
auto it = audioList.find(ctxPtr);
if (it != audioList.end()) {
auto it = g_audioDecoderContexts.find(ctxPtr);
if (it != g_audioDecoderContexts.end()) {
return it->second;
}
return NULL;
@ -52,20 +52,20 @@ static AudioDecoder *findDecoder(u32 ctxPtr) {
// remove decoder from audioList
static bool removeDecoder(u32 ctxPtr) {
auto it = audioList.find(ctxPtr);
if (it != audioList.end()) {
auto it = g_audioDecoderContexts.find(ctxPtr);
if (it != g_audioDecoderContexts.end()) {
delete it->second;
audioList.erase(it);
g_audioDecoderContexts.erase(it);
return true;
}
return false;
}
static void clearDecoders() {
for (const auto &[_, decoder] : audioList) {
for (const auto &[_, decoder] : g_audioDecoderContexts) {
delete decoder;
}
audioList.clear();
g_audioDecoderContexts.clear();
}
void __AudioCodecInit() {
@ -86,9 +86,9 @@ static int sceAudiocodecInit(u32 ctxPtr, int codec) {
}
AudioDecoder *decoder = CreateAudioDecoder(audioType);
decoder->SetCtxPtr(ctxPtr);
audioList[ctxPtr] = decoder;
g_audioDecoderContexts[ctxPtr] = decoder;
INFO_LOG(Log::ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(audioType));
DEBUG_LOG(Log::ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size());
DEBUG_LOG(Log::ME, "Number of playing sceAudioCodec audios : %d", (int)g_audioDecoderContexts.size());
return 0;
}
ERROR_LOG_REPORT(Log::ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(audioType), codec);
@ -111,7 +111,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
// Fake it by creating the desired context.
decoder = CreateAudioDecoder(audioType);
decoder->SetCtxPtr(ctxPtr);
audioList[ctxPtr] = decoder;
g_audioDecoderContexts[ctxPtr] = decoder;
}
if (decoder != NULL) {
@ -175,7 +175,7 @@ void __sceAudiocodecDoState(PointerWrap &p){
return;
}
int count = (int)audioList.size();
int count = (int)g_audioDecoderContexts.size();
Do(p, count);
if (count > 0) {
@ -200,7 +200,7 @@ void __sceAudiocodecDoState(PointerWrap &p){
for (int i = 0; i < count; i++) {
auto decoder = CreateAudioDecoder((PSPAudioType)codec_[i]);
decoder->SetCtxPtr(ctxPtr_[i]);
audioList[ctxPtr_[i]] = decoder;
g_audioDecoderContexts[ctxPtr_[i]] = decoder;
}
#ifdef __clang__
#pragma clang diagnostic pop
@ -217,7 +217,7 @@ void __sceAudiocodecDoState(PointerWrap &p){
auto codec_ = new int[count];
auto ctxPtr_ = new u32[count];
int i = 0;
for (auto iter : audioList) {
for (auto iter : g_audioDecoderContexts) {
const AudioDecoder *decoder = iter.second;
codec_[i] = decoder->GetAudioType();
ctxPtr_[i] = decoder->GetCtxPtr();

View file

@ -17,6 +17,8 @@
#pragma once
#include <map>
class PointerWrap;
typedef struct {
@ -61,3 +63,6 @@ void __AudioCodecInit();
void __AudioCodecShutdown();
void Register_sceAudiocodec();
void __sceAudiocodecDoState(PointerWrap &p);
class AudioDecoder;
extern std::map<u32, AudioDecoder *> g_audioDecoderContexts;

View file

@ -15,7 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Games known to support custom music and almost certainly use sceMp3:
// Games known to support custom music and almost certainly use sceMp3, unless they use sceAudiocodec:
//
// * ATV Offroad Fury: Blazin' Trails
// * Beats (/PSP/MUSIC)
@ -147,7 +147,7 @@ public:
};
};
static std::map<u32, AuCtx *> mp3Map;
std::map<u32, AuCtx *> mp3Map;
static const int mp3DecodeDelay = 2400;
static bool resourceInited = false;

View file

@ -17,6 +17,10 @@
#pragma once
#include <map>
class AuCtx;
class PointerWrap;
void Register_sceMp3();
@ -24,3 +28,5 @@ void Register_sceMp3();
void __Mp3Init();
void __Mp3Shutdown();
void __Mp3DoState(PointerWrap &p);
extern std::map<u32, AuCtx *> mp3Map;

View file

@ -1532,7 +1532,8 @@ void PostPutAction::run(MipsCall &call) {
}
if (invalid) {
// Bail out early - don't accept any of the packets, even the good ones.
ERROR_LOG_REPORT(Log::ME, "sceMpegRingbufferPut(): invalid mpeg data");
// This happens during legit playback at the Burnout Legends menu!
ERROR_LOG(Log::ME, "sceMpegRingbufferPut(): invalid mpeg data");
call.setReturnValue(ERROR_MPEG_INVALID_VALUE);
if (mpegLibVersion <= 0x0103) {

View file

@ -1670,6 +1670,7 @@ void EmuScreen::renderImDebugger() {
Draw::DrawContext *draw = screenManager()->getDrawContext();
if (!imguiInited_) {
imguiInited_ = true;
ImGui_ImplPlatform_Init(GetSysDirectory(DIRECTORY_SYSTEM) / "imgui.ini");
imDebugger_ = std::make_unique<ImDebugger>();
// Read the TTF font

View file

@ -14,6 +14,7 @@
#include "Core/Debugger/Breakpoints.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/HW/SimpleAudioDec.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MemMap.h"
@ -21,6 +22,9 @@
#include "Common/System/Request.h"
#include "Core/HLE/sceAtrac.h"
#include "Core/HLE/sceAudio.h"
#include "Core/HLE/sceAudiocodec.h"
#include "Core/HLE/sceMp3.h"
#include "Core/HLE/AtracCtx.h"
// Threads window
@ -439,38 +443,158 @@ static void DrawBreakpointsView(MIPSDebugInterface *mipsDebug, ImConfig &cfg) {
ImGui::End();
}
void DrawAtracView(ImConfig &cfg) {
if (!ImGui::Begin("sceAtrac contexts", &cfg.atracOpen)) {
void DrawAudioDecodersView(ImConfig &cfg) {
if (!ImGui::Begin("Audio decoding contexts", &cfg.audioDecodersOpen)) {
ImGui::End();
return;
}
if (ImGui::BeginTable("atracs", 5, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("OutChans", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("CurrentSample", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("RemainingFrames", ImGuiTableColumnFlags_WidthFixed);
if (ImGui::CollapsingHeader("sceAtrac", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::BeginTable("atracs", 5, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Index", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("OutChans", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("CurrentSample", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("RemainingFrames", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
for (int i = 0; i < PSP_NUM_ATRAC_IDS; i++) {
u32 type = 0;
const AtracBase *atracBase = __AtracGetCtx(i, &type);
if (!atracBase) {
continue;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", i);
ImGui::TableNextColumn();
switch (type) {
case PSP_MODE_AT_3_PLUS:
ImGui::TextUnformatted("Atrac3+");
break;
case PSP_MODE_AT_3:
ImGui::TextUnformatted("Atrac3");
break;
default:
ImGui::Text("%04x", type);
break;
}
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->GetOutputChannels());
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->CurrentSample());
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->RemainingFrames());
// TODO: Add more.
}
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("sceAudiocodec", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::BeginTable("codecs", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("CtxAddr", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
for (auto &iter : g_audioDecoderContexts) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%08x", iter.first);
ImGui::TableNextColumn();
switch (iter.second->GetAudioType()) {
case PSP_CODEC_AAC: ImGui::TextUnformatted("AAC"); break;
case PSP_CODEC_MP3: ImGui::TextUnformatted("MP3"); break;
case PSP_CODEC_AT3PLUS: ImGui::TextUnformatted("Atrac3+"); break;
case PSP_CODEC_AT3: ImGui::TextUnformatted("Atrac3"); break;
default: ImGui::Text("%08x", iter.second->GetAudioType()); break;
}
}
ImGui::EndTable();
}
}
if (ImGui::CollapsingHeader("sceMp3", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::BeginTable("mp3", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Handle", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Channels", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("StartPos", ImGuiTableColumnFlags_WidthFixed);
// TODO: more..
for (auto &iter : mp3Map) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", iter.first);
if (!iter.second) {
continue;
}
ImGui::TableNextColumn();
ImGui::Text("%d", iter.second->Channels);
ImGui::TableNextColumn();
ImGui::Text("%d", iter.second->startPos);
}
ImGui::EndTable();
}
}
ImGui::End();
}
void DrawAudioChannels(ImConfig &cfg) {
if (!ImGui::Begin("Raw audio channels", &cfg.audioChannelsOpen)) {
ImGui::End();
return;
}
if (ImGui::BeginTable("audios", 6, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
ImGui::TableSetupColumn("Index", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("SampleAddr", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("SampleCount", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Volume", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Format", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Waiting Thread", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
for (int i = 0; i < PSP_NUM_ATRAC_IDS; i++) {
u32 type = 0;
const AtracBase *atracBase = __AtracGetCtx(i, &type);
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (!atracBase) {
ImGui::Text("-", type);
// vaudio / output2 uses channel 8.
for (int i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) {
if (!chans[i].reserved) {
continue;
}
ImGui::Text("%d", type);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->GetOutputChannels());
if (i == 8) {
ImGui::TextUnformatted("audio2");
} else {
ImGui::Text("%d", i);
}
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->CurrentSample());
ImGui::Text("%08x", chans[i].sampleAddress);
ImGui::TableNextColumn();
ImGui::Text("%d", atracBase->RemainingFrames());
ImGui::Text("%08x", chans[i].sampleCount);
ImGui::TableNextColumn();
ImGui::Text("%d | %d", chans[i].leftVolume, chans[i].rightVolume);
ImGui::TableNextColumn();
switch (chans[i].format) {
case PSP_AUDIO_FORMAT_STEREO:
ImGui::TextUnformatted("Stereo");
break;
case PSP_AUDIO_FORMAT_MONO:
ImGui::TextUnformatted("Mono");
break;
default:
ImGui::TextUnformatted("UNK: %04x");
break;
}
ImGui::TableNextColumn();
for (auto t : chans[i].waitingThreads) {
KernelObject *thread = kernelObjects.GetFast<KernelObject>(t.threadID);
if (thread) {
ImGui::Text("%s: %d", thread->GetName(), t.numSamples);
}
}
}
ImGui::EndTable();
@ -607,8 +731,14 @@ void DrawHLEModules(ImConfig &config) {
ImDebugger::ImDebugger() {
reqToken_ = g_requestManager.GenerateRequesterToken();
cfg_.LoadConfig(ConfigPath());
}
ImDebugger::~ImDebugger() {
cfg_.SaveConfig(ConfigPath());
}
void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug) {
// Snapshot the coreState to avoid inconsistency.
const CoreState coreState = ::coreState;
@ -683,20 +813,24 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("OS HLE")) {
if (ImGui::BeginMenu("HLE")) {
ImGui::MenuItem("File System Browser", nullptr, &cfg_.filesystemBrowserOpen);
ImGui::MenuItem("Kernel Objects", nullptr, &cfg_.kernelObjectsOpen);
ImGui::MenuItem("Threads", nullptr, &cfg_.threadsOpen);
ImGui::MenuItem("Modules",nullptr, &cfg_.modulesOpen);
ImGui::MenuItem("sceAtrac", nullptr, &cfg_.atracOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Ge (GPU)")) {
if (ImGui::BeginMenu("Graphics")) {
ImGui::MenuItem("Display Output", nullptr, &cfg_.displayOpen);
ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen);
// More to come here...
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Audio")) {
ImGui::MenuItem("Raw audio channels", nullptr, &cfg_.audioChannelsOpen);
ImGui::MenuItem("Decoder contexts", nullptr, &cfg_.audioDecodersOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Struct viewer", nullptr, &cfg_.structViewerOpen);
ImGui::EndMenu();
@ -736,6 +870,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawFilesystemBrowser(cfg_);
}
if (cfg_.audioChannelsOpen) {
DrawAudioChannels(cfg_);
}
if (cfg_.kernelObjectsOpen) {
DrawKernelObjects(cfg_);
}
@ -752,8 +890,8 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawModules(mipsDebug, cfg_);
}
if (cfg_.atracOpen) {
DrawAtracView(cfg_);
if (cfg_.audioDecodersOpen) {
DrawAudioDecodersView(cfg_);
}
if (cfg_.hleModulesOpen) {
@ -921,6 +1059,63 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, bool *open, CoreState c
ImGui::End();
}
void ImDebugger::LoadConfig() {
IniFile ini;
Path ImDebugger::ConfigPath() {
return GetSysDirectory(DIRECTORY_SYSTEM) / "imdebugger.ini";
}
// TODO: Move this into the main config at some point.
// But, I don't really want Core to know about the ImDebugger..
void ImConfig::LoadConfig(const Path &iniFile) {
IniFile ini;
ini.Load(iniFile); // Ignore return value, might not exist yet. In that case we'll end up loading defaults.
SyncConfig(&ini, false);
}
void ImConfig::SaveConfig(const Path &iniFile) {
IniFile ini;
ini.Load(iniFile); // ignore return value, might not exist yet
SyncConfig(&ini, true);
ini.Save(iniFile);
}
class Syncer {
public:
explicit Syncer(bool save) : save_(save) {}
void SetSection(Section *section) { section_ = section; }
template<class T>
void Sync(std::string_view key, T *value, T defaultValue) {
if (save_) {
section_->Set(key, *value);
} else {
section_->Get(key, value, defaultValue);
}
}
private:
Section *section_ = nullptr;
bool save_;
};
void ImConfig::SyncConfig(IniFile *ini, bool save) {
Syncer sync(save);
sync.SetSection(ini->GetOrCreateSection("Windows"));
sync.Sync("disasmOpen", &disasmOpen, true);
sync.Sync("demoOpen ", &demoOpen, false);
sync.Sync("regsOpen", &regsOpen, true);
sync.Sync("threadsOpen", &threadsOpen, false);
sync.Sync("callstackOpen", &callstackOpen, false);
sync.Sync("breakpointsOpen", &breakpointsOpen, false);
sync.Sync("modulesOpen", &modulesOpen, false);
sync.Sync("hleModulesOpen", &hleModulesOpen, false);
sync.Sync("audioDecodersOpen", &audioDecodersOpen, false);
sync.Sync("structViewerOpen", &structViewerOpen, false);
sync.Sync("framebuffersOpen", &framebuffersOpen, false);
sync.Sync("displayOpen", &displayOpen, true);
sync.Sync("styleEditorOpen", &styleEditorOpen, false);
sync.Sync("filesystemBrowserOpen", &filesystemBrowserOpen, false);
sync.Sync("kernelObjectsOpen", &kernelObjectsOpen, false);
sync.Sync("audioChannelsOpen", &audioChannelsOpen, false);
sync.SetSection(ini->GetOrCreateSection("Settings"));
sync.Sync("displayLatched", &displayLatched, false);
}

View file

@ -58,21 +58,24 @@ private:
};
struct ImConfig {
bool disasmOpen = true;
bool demoOpen = false;
bool regsOpen = true;
bool threadsOpen = true;
bool callstackOpen = true;
bool breakpointsOpen = false;
bool modulesOpen = true;
bool hleModulesOpen = false;
bool atracOpen = true;
bool structViewerOpen = false;
bool framebuffersOpen = false;
bool displayOpen = false;
bool styleEditorOpen = false;
bool filesystemBrowserOpen = false;
bool kernelObjectsOpen = false;
// Defaults for saved settings are set in SyncConfig.
bool disasmOpen;
bool demoOpen;
bool regsOpen;
bool threadsOpen;
bool callstackOpen;
bool breakpointsOpen;
bool modulesOpen;
bool hleModulesOpen;
bool audioDecodersOpen;
bool structViewerOpen;
bool framebuffersOpen;
bool displayOpen;
bool styleEditorOpen;
bool filesystemBrowserOpen;
bool kernelObjectsOpen;
bool audioChannelsOpen;
// HLE explorer settings
// bool filterByUsed = true;
@ -85,6 +88,12 @@ struct ImConfig {
int selectedMemCheck = -1;
bool displayLatched = false;
// We use a separate ini file from the main PPSSPP config.
void LoadConfig(const Path &iniFile);
void SaveConfig(const Path &iniFile);
void SyncConfig(IniFile *ini, bool save);
};
enum ImUiCmd {
@ -98,13 +107,12 @@ struct ImUiCommand {
class ImDebugger {
public:
ImDebugger();
~ImDebugger();
void Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebug);
private:
// We use a separate ini file from the main PPSSPP config.
void LoadConfig();
void SaveConfig();
Path ConfigPath();
RequesterToken reqToken_;
@ -112,5 +120,5 @@ private:
ImStructViewer structViewer_;
// Open variables.
ImConfig cfg_;
ImConfig cfg_{};
};

View file

@ -1,8 +1,10 @@
#include "ext/imgui/imgui.h"
#include "Common/File/Path.h"
#include "Common/Input/KeyCodes.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/System/Display.h"
#include "Common/TimeUtil.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "imgui_impl_platform.h"
@ -73,6 +75,12 @@ void ImGui_ImplPlatform_TouchEvent(const TouchInput &touch) {
}
}
void ImGui_ImplPlatform_Init(const Path &configPath) {
static char path[1024];
truncate_cpy(path, configPath.ToString());
ImGui::GetIO().IniFilename = path;
}
void ImGui_ImplPlatform_AxisEvent(const AxisInput &axis) {
// Ignore for now.
}

View file

@ -4,8 +4,11 @@
#include "Common/Input/KeyCodes.h"
#include "Common/Input/InputState.h"
class Path;
ImGuiKey KeyCodeToImGui(InputKeyCode keyCode);
void ImGui_ImplPlatform_Init(const Path &configPath);
void ImGui_ImplPlatform_NewFrame();
void ImGui_ImplPlatform_KeyEvent(const KeyInput &key);

View file

@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.nonTransitiveRClass=true
android.nonFinalResIds=true
android.ndk.suppressMinSdkVersionError=21