From d83267098e55bf4b842a3e5e9e45e8b208ebd6ed Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 1 Mar 2026 22:23:30 +0100 Subject: [PATCH] Add heap imgui --- files.cmake | 1 + include/JSystem/JKernel/JKRHeap.h | 13 ++++ include/d/d_procname.h | 14 +++- src/JSystem/JAudio2/JASHeapCtrl.cpp | 2 + src/JSystem/JFramework/JFWSystem.cpp | 2 + src/JSystem/JKernel/JKRHeap.cpp | 17 ++++ src/d/d_attention.cpp | 1 + src/d/d_kankyo.cpp | 2 + src/d/d_particle.cpp | 2 + src/d/d_resorce.cpp | 6 ++ src/dusk/imgui.cpp | 1 + src/dusk/imgui/debug_overlay.cpp | 10 +-- src/dusk/imgui/heaps.cpp | 112 +++++++++++++++++++++++++++ src/dusk/imgui/imgui.hpp | 4 + src/dusk/imgui/processes.cpp | 12 +-- src/f_op/f_op_actor_mng.cpp | 17 ++++ src/m_Do/m_Do_ext.cpp | 7 ++ src/m_Do/m_Do_main.cpp | 1 + 18 files changed, 206 insertions(+), 18 deletions(-) create mode 100644 src/dusk/imgui/heaps.cpp diff --git a/files.cmake b/files.cmake index 7808531231..c9c7b5fa4a 100644 --- a/files.cmake +++ b/files.cmake @@ -1331,6 +1331,7 @@ set(DUSK_FILES src/dusk/imgui/imgui.hpp src/dusk/imgui/processes.cpp src/dusk/imgui/debug_overlay.cpp + src/dusk/imgui/heaps.cpp src/dusk/offset_ptr.cpp src/dolphin/os/OSContext.cpp src/dolphin/os/OSThread.cpp diff --git a/include/JSystem/JKernel/JKRHeap.h b/include/JSystem/JKernel/JKRHeap.h index 3f3f44083e..05862bd85d 100644 --- a/include/JSystem/JKernel/JKRHeap.h +++ b/include/JSystem/JKernel/JKRHeap.h @@ -141,6 +141,10 @@ protected: /* 0x68 */ bool mErrorFlag; /* 0x69 */ bool mInitFlag; +#if TARGET_PC + char mName[32]; +#endif + public: static bool initArena(char** memory, u32* size, int maxHeaps); static bool initArena2(char** memory, u32* size, int maxHeaps); @@ -209,6 +213,15 @@ public: #endif static JKRErrorHandler mErrorHandler; + +#if TARGET_PC + void setName(const char* name); + const char* getName() const; + +#define JKRHEAP_NAME(heap, name) (heap)->setName(name) +#else +#define JKRHEAP_NAME(heap, name) +#endif }; #ifndef TARGET_PC diff --git a/include/d/d_procname.h b/include/d/d_procname.h index 4ec2faa84a..6c15c741f0 100644 --- a/include/d/d_procname.h +++ b/include/d/d_procname.h @@ -819,10 +819,20 @@ struct ProcName { }; #define X(name) { name, #name }, -inline ProcName procNames[] = { +inline const ProcName procNames[] = { ALL_PROCS }; -#undef name +#undef X + +inline const char* GetProcName(unsigned int id) { + for (auto procName : procNames) { + if (procName.id == id) { + return procName.name; + } + } + + return nullptr; +} #endif diff --git a/src/JSystem/JAudio2/JASHeapCtrl.cpp b/src/JSystem/JAudio2/JASHeapCtrl.cpp index f53676185e..70f3c0d5e4 100644 --- a/src/JSystem/JAudio2/JASHeapCtrl.cpp +++ b/src/JSystem/JAudio2/JASHeapCtrl.cpp @@ -294,8 +294,10 @@ JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>* JASKernel::sComma void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) { JUT_ASSERT(784, heap); sSystemHeap = JKRExpHeap::create(size, heap, false); + JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap"); JUT_ASSERT(787, sSystemHeap); sCommandHeap = new (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>(); + JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap"); JUT_ASSERT(790, sCommandHeap); JASDram = heap; } diff --git a/src/JSystem/JFramework/JFWSystem.cpp b/src/JSystem/JFramework/JFWSystem.cpp index c41f7ffc8f..e240b8d19c 100644 --- a/src/JSystem/JFramework/JFWSystem.cpp +++ b/src/JSystem/JFramework/JFWSystem.cpp @@ -45,7 +45,9 @@ void JFWSystem::firstInit() { OSInit(); DVDInit(); rootHeap = JKRExpHeap::createRoot(CSetUpParam::maxStdHeaps, false); + JKRHEAP_NAME(rootHeap, "Root"); systemHeap = JKRExpHeap::create(CSetUpParam::sysHeapSize, rootHeap, false); + JKRHEAP_NAME(systemHeap, "System"); } JKRThread* JFWSystem::mainThread; diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp index 3364bfc492..14a719f3f7 100644 --- a/src/JSystem/JKernel/JKRHeap.cpp +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -6,6 +6,11 @@ #include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JKernel/JKRHeap.h" + +#if TARGET_PC +#include +#endif + #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTException.h" #ifdef __MWERKS__ @@ -83,6 +88,10 @@ JKRHeap::JKRHeap(void* data, u32 size, JKRHeap* parent, bool errorFlag) mDebugFill = sDefaultFillFlag; mCheckMemoryFilled = data_80451380; mInitFlag = false; + +#if TARGET_PC + memset(mName, 0, sizeof(mName)); +#endif } JKRHeap::~JKRHeap() { @@ -668,4 +677,12 @@ void JKRHeap::setCurrentHeap(JKRHeap* heap) { JKRHeap* JKRHeap::getCurrentHeap() { return sCurrentHeap; } + +void JKRHeap::setName(const char* name) { + size_t len = strlen(name); + memcpy(mName, name, std::max(len, sizeof(mName)-1)); +} +const char* JKRHeap::getName() const { + return mName; +} #endif diff --git a/src/d/d_attention.cpp b/src/d/d_attention.cpp index f3318b63c2..1a2385821f 100644 --- a/src/d/d_attention.cpp +++ b/src/d/d_attention.cpp @@ -173,6 +173,7 @@ dAttention_c::dAttention_c(fopAc_ac_c* i_player, u32 i_padNo) { mAttnBlockTimer = 0; heap = mDoExt_createSolidHeapFromGameToCurrent(0x9000, 0); + JKRHEAP_NAME(heap, "dAttention_c::heap"); JUT_ASSERT(0x198, heap != NULL); J3DModelData* modelDataR = (J3DModelData*)dComIfG_getObjectRes("Always", 0x25); diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 7b9f3516c2..ef92c23dd3 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -24,6 +24,7 @@ #include "f_op/f_op_kankyo.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_lib.h" +#include "JSystem/JKernel/JKRSolidHeap.h" #include #include @@ -1168,6 +1169,7 @@ static void undwater_init() { JUT_ASSERT(1867, modelData2 != NULL); g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20); + JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap"); if (g_env_light.undwater_ef_heap != NULL) { g_env_light.undwater_ef_model = mDoExt_J3DModel__create(modelData2, 0x80000, 0x11020202); diff --git a/src/d/d_particle.cpp b/src/d/d_particle.cpp index 0a169d2546..edeeda7494 100644 --- a/src/d/d_particle.cpp +++ b/src/d/d_particle.cpp @@ -1201,6 +1201,7 @@ void dPa_control_c::createCommon(void const* param_0) { OS_REPORT("常駐パーティクルリソースサイズ<%d>\n", heapSize); #endif mHeap = mDoExt_createSolidHeapFromSystem(0, 0); + JKRHEAP_NAME(mHeap, "dPa_control_c::mHeap"); JUT_ASSERT(2518, mHeap != NULL); mCommonResMng = new (mHeap, 0) JPAResourceManager(param_0, mHeap); JUT_ASSERT(2521, mCommonResMng != NULL); @@ -1226,6 +1227,7 @@ void dPa_control_c::createCommon(void const* param_0) { void dPa_control_c::createRoomScene() { mSceneHeap = mDoExt_createSolidHeapFromGame(0, 0); + JKRHEAP_NAME(mSceneHeap, "dPa_control_c::mSceneHeap"); JUT_ASSERT(2573, mSceneHeap != NULL); mSceneResMng = new (mSceneHeap, 0) JPAResourceManager(m_sceneRes, mSceneHeap); JUT_ASSERT(2576, mSceneResMng != NULL); diff --git a/src/d/d_resorce.cpp b/src/d/d_resorce.cpp index 40c94e7e51..2ffc64253f 100644 --- a/src/d/d_resorce.cpp +++ b/src/d/d_resorce.cpp @@ -640,6 +640,12 @@ int dRes_info_c::setRes() { u32 heapSize = mDataHeap->getHeapSize(); DCStoreRangeNoSync(mDataHeap->getStartAddr(), heapSize); + +#if TARGET_PC + char buf[32]; + snprintf(buf, sizeof(buf), "Arc %s", mArchiveName); + JKRHEAP_NAME(mDataHeap, buf); +#endif } return 0; diff --git a/src/dusk/imgui.cpp b/src/dusk/imgui.cpp index 61d339e3fe..245941a3e9 100644 --- a/src/dusk/imgui.cpp +++ b/src/dusk/imgui.cpp @@ -31,6 +31,7 @@ void imgui_main(const AuroraInfo *info) DuskImguiDebugOverlay(info); DuskImguiProcesses(); + DuskImguiHeaps(); ImGui::EndMainMenuBar(); } diff --git a/src/dusk/imgui/debug_overlay.cpp b/src/dusk/imgui/debug_overlay.cpp index 5d8332fb41..ae97dbd0a8 100644 --- a/src/dusk/imgui/debug_overlay.cpp +++ b/src/dusk/imgui/debug_overlay.cpp @@ -49,7 +49,7 @@ static void ImGuiStringViewText(std::string_view text) ImGui::TextUnformatted(text.data(), text.data() + text.size()); } -static std::string BytesToString(size_t bytes) +std::string BytesToString(size_t bytes) { constexpr std::array suffixes{"B"sv, "KB"sv, "MB"sv, "GB"sv, "TB"sv, "PB"sv, "EB"sv}; uint32_t s = 0; @@ -66,20 +66,20 @@ static std::string BytesToString(size_t bytes) return fmt::format(FMT_STRING("{:.1f}{}"), count, suffixes[s]); } -static bool DebugOverlayActive = false; +static bool Active = false; void DuskImguiDebugOverlay(const AuroraInfo *info) { if (ImGui::BeginMenu(MenuView)) { - ImGui::MenuItem("Debug overlay", "F3", &DebugOverlayActive); + ImGui::MenuItem("Debug overlay", "F3", &Active); ImGui::EndMenu(); } if (ImGui::IsKeyPressed(ImGuiKey_F3)) { - DebugOverlayActive = !DebugOverlayActive; + Active = !Active; } - if (!DebugOverlayActive) { + if (!Active) { return; } diff --git a/src/dusk/imgui/heaps.cpp b/src/dusk/imgui/heaps.cpp new file mode 100644 index 0000000000..aa4de04ba3 --- /dev/null +++ b/src/dusk/imgui/heaps.cpp @@ -0,0 +1,112 @@ +#include + +#include "JSystem/JFramework/JFWSystem.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "imgui.h" +#include "imgui.hpp" + +static bool Active = false; + +static void DrawTableCore(); + +void DuskImguiHeaps() { + if (ImGui::BeginMenu(MenuView)) { + ImGui::MenuItem("Heaps", "F4", &Active); + + ImGui::EndMenu(); + } + + if (ImGui::IsKeyPressed(ImGuiKey_F4)) { + Active = !Active; + } + + if (!Active) { + return; + } + + if (ImGui::Begin("Heaps", &Active)) { + if (ImGui::BeginTable( + "heaps", + 5, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable)) { + + DrawTableCore(); + + ImGui::EndTable(); + } + } + + ImGui::End(); +} + +static void DrawHeap(JKRHeap* heap, int depth = 0); + +static void DrawTableCore() { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Heap name"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Use%"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Available"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Total"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Type"); + + DrawHeap(reinterpret_cast(JFWSystem::rootHeap)); +} + +static std::array GetHeapType(JKRHeap* heap) { + auto type = heap->getHeapType(); + + return { + (char)(type >> 24 & 0xFF), + (char)(type >> 16 & 0xFF), + (char)(type >> 8 & 0xFF), + (char)(type >> 0 & 0xFF), + }; +} + +static const char* GetHeapName(const JKRHeap* heap) { + const auto name = heap->getName(); + if (strlen(name) == 0) { + return "Unknown"; + } + + return name; +} + +static void DrawHeap(JKRHeap* heap, const int depth) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + auto indentSize = depth * 16; + if (indentSize != 0) + ImGui::Indent(indentSize); + ImGui::TextUnformatted(GetHeapName(heap)); + if (indentSize != 0) + ImGui::Unindent(indentSize); + + ImGui::TableNextColumn(); + ImGui::ProgressBar( + 1 - (f32)heap->getFreeSize() / (f32)heap->getSize(), + ImVec2(ImGui::GetContentRegionAvail().x, 0)); + + ImGui::TableNextColumn(); + auto freeSizeString = BytesToString(heap->getFreeSize()); + ImGui::TextUnformatted(freeSizeString.c_str()); + + ImGui::TableNextColumn(); + auto totalSizeString = BytesToString(heap->getSize()); + ImGui::TextUnformatted(totalSizeString.c_str()); + + ImGui::TableNextColumn(); + auto typeString = GetHeapType(heap); + ImGui::TextUnformatted(typeString.data(), typeString.data() + 4); + + const JSUTree& tree = heap->getHeapTree(); + for (JSUTreeIterator iter(tree.getFirstChild()); iter != tree.getEndChild(); ++iter) { + DrawHeap(*iter, depth + 1); + } +} \ No newline at end of file diff --git a/src/dusk/imgui/imgui.hpp b/src/dusk/imgui/imgui.hpp index bd93989d99..d6006f8353 100644 --- a/src/dusk/imgui/imgui.hpp +++ b/src/dusk/imgui/imgui.hpp @@ -2,10 +2,14 @@ #define DUSK_IMGUI_HPP #include +#include inline const char* MenuView = "View"; void DuskImguiDebugOverlay(const AuroraInfo *info); void DuskImguiProcesses(); +void DuskImguiHeaps(); + +std::string BytesToString(size_t bytes); #endif // DUSK_IMGUI_HPP diff --git a/src/dusk/imgui/processes.cpp b/src/dusk/imgui/processes.cpp index 016a6141a6..7bbaeaf26e 100644 --- a/src/dusk/imgui/processes.cpp +++ b/src/dusk/imgui/processes.cpp @@ -13,16 +13,6 @@ #include "imgui.hpp" #include "imgui_internal.h" -static const char* getProcName(s16 id) { - for (auto procName : procNames) { - if (procName.id == id) { - return procName.name; - } - } - - return nullptr; -} - bool showTreeRecursive; static int ShowProcess(void* p, void*) { @@ -35,7 +25,7 @@ static int ShowProcess(void* p, void*) { ImVec2 vec = {avail.x, 0}; if (ImGui::BeginChild(buf, vec, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { - ImGui::Text("[%d] %s", proc->id, getProcName(proc->profname)); + ImGui::Text("[%d] %s", proc->id, GetProcName(proc->profname)); ImGui::Text("init_state: %d, create_phase: %d", proc->state.init_state, proc->state.create_phase); const char* ofTypeName = "unknown"; diff --git a/src/f_op/f_op_actor_mng.cpp b/src/f_op/f_op_actor_mng.cpp index 2bc28c2014..eddc63aaa0 100644 --- a/src/f_op/f_op_actor_mng.cpp +++ b/src/f_op/f_op_actor_mng.cpp @@ -3,6 +3,11 @@ * Actor Manager */ +#if TARGET_PC +#define PROCS_DUMP_NAMES 1 +#include "d/d_procname.h" +#endif + #include "d/dolzel.h" // IWYU pragma: keep #include "JSystem/J3DGraphBase/J3DMaterial.h" @@ -727,6 +732,18 @@ u8 var_r30 = fopAcM::HeapAdjustEntry; #endif fopAcM::HeapAdjustUnk = var_r31; fopAcM::HeapAdjustEntry = var_r30; + +#if TARGET_PC + char buf[32]; + snprintf( + buf, + sizeof(buf), + "Actor %d (%s)", + i_actor->id, + GetProcName(i_actor->profname)); + JKRHEAP_NAME(i_actor->heap, buf); +#endif + return result; } diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index d7743b2d6c..ff1ed5de36 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -670,6 +670,7 @@ static JKRExpHeap* DbPrintHeap; JKRExpHeap* mDoExt_createDbPrintHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(1693, DbPrintHeap == NULL || heapSize == 0); DbPrintHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(DbPrintHeap, "DbPrintHeap"); return DbPrintHeap; } @@ -683,6 +684,7 @@ static intptr_t safeGameHeapSize = -1; JKRExpHeap* mDoExt_createGameHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(1739, gameHeap == NULL || heapSize == 0); gameHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(gameHeap, "gameHeap"); gameHeap->setAllocationMode(JKRExpHeap::ALLOC_MODE_1); return gameHeap; } @@ -715,6 +717,7 @@ intptr_t safeZeldaHeapSize = -1; JKRExpHeap* mDoExt_createZeldaHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(1815, zeldaHeap == NULL || heapSize == 0); zeldaHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(zeldaHeap, "zeldaHeap"); return zeldaHeap; } @@ -748,6 +751,7 @@ intptr_t safeCommandHeapSize = -1; JKRExpHeap* mDoExt_createCommandHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(1894, commandHeap == 0 || heapSize == 0); commandHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(commandHeap, "commandHeap"); return commandHeap; } @@ -774,6 +778,7 @@ intptr_t safeArchiveHeapSize = -1; JKRExpHeap* mDoExt_createArchiveHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(1966, archiveHeap == 0 || heapSize == 0); archiveHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(archiveHeap, "archiveHeap"); archiveHeap->setAllocationMode(JKRExpHeap::ALLOC_MODE_1); return archiveHeap; } @@ -811,6 +816,7 @@ intptr_t safeJ2dHeapSize = -1; JKRExpHeap* mDoExt_createJ2dHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(2059, j2dHeap == 0 || heapSize == 0); j2dHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(j2dHeap, "j2dHeap"); j2dHeap->setAllocationMode(JKRExpHeap::ALLOC_MODE_1); return j2dHeap; } @@ -843,6 +849,7 @@ static JKRExpHeap* HostIOHeap; JKRHeap* mDoExt_createHostIOHeap(u32 heapSize, JKRHeap* parentHeap) { JUT_ASSERT(2142, HostIOHeap == 0 || heapSize == 0); HostIOHeap = JKRExpHeap::create(heapSize, parentHeap, true); + JKRHEAP_NAME(HostIOHeap, "HostIOHeap"); return HostIOHeap; } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index fdd69bdb9c..424e99c507 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -164,6 +164,7 @@ void main01(void) { cDyl_InitAsync(); g_mDoAud_audioHeap = JKRCreateSolidHeap(audioHeapSize, JKRGetCurrentHeap(), false); + JKRHEAP_NAME(g_mDoAud_audioHeap, "g_mDoAud_audioHeap"); if (DUSK_AUDIO_DISABLED) { // Pretend the audio engine initialized already. This is a lie, but needed to boot.