From c10d371836809021423cb0cd1610db385440d062 Mon Sep 17 00:00:00 2001 From: Patedam Date: Wed, 21 Jan 2026 20:36:38 -0500 Subject: [PATCH] Cleaned up memory arena debugger + tag. WIP --- Game/Entity/Entity.h | 10 +- Game/game.cpp | 2 +- Juliet/include/Core/ImGui/ImGuiService.h | 8 +- Juliet/include/Core/ImGui/ImGuiTests.h | 2 +- Juliet/include/Core/Memory/MemoryArena.h | 34 +++---- Juliet/include/Engine/Debug/MemoryDebugger.h | 16 ++-- Juliet/src/Core/HAL/Display/Display.cpp | 12 +-- .../HAL/Display/Win32/Win32DisplayDevice.cpp | 4 +- .../Core/HAL/Display/Win32/Win32Window.cpp | 2 +- Juliet/src/Core/HotReload/HotReload.cpp | 10 +- .../Core/HotReload/Win32/Win32HotReload.cpp | 9 +- Juliet/src/Core/ImGui/ImGuiService.cpp | 45 ++------- Juliet/src/Core/ImGui/ImGuiTests.cpp | 49 ++++------ Juliet/src/Core/Memory/MemoryArena.cpp | 12 +-- Juliet/src/Core/Memory/MemoryArenaTests.cpp | 16 ++-- Juliet/src/Engine/Debug/MemoryDebugger.cpp | 96 ++++++++++--------- Juliet/src/Engine/Engine.cpp | 12 +-- .../Graphics/D3D12/D3D12DescriptorHeap.cpp | 22 ++--- .../Graphics/D3D12/D3D12GraphicsDevice.cpp | 3 +- Juliet/src/Graphics/ImGuiRenderer.cpp | 4 +- JulietApp/main.cpp | 16 +--- 21 files changed, 169 insertions(+), 215 deletions(-) diff --git a/Game/Entity/Entity.h b/Game/Entity/Entity.h index f1ba924..eb6cffc 100644 --- a/Game/Entity/Entity.h +++ b/Game/Entity/Entity.h @@ -9,7 +9,7 @@ #include // Add any new fields into the concept below -#define DECLARE_ENTITY() \ +#define DECLARE_ENTITY() \ Entity* Base; \ static const Juliet::Class* Kind; @@ -18,8 +18,6 @@ constexpr Juliet::Class entityKind##entity(#entity, sizeof(#entity) / sizeof(char)); \ const Juliet::Class* entity::Kind = &entityKind##entity; - - namespace Game { using DerivedType = void*; @@ -49,9 +47,9 @@ namespace Game requires EntityConcept EntityType* MakeEntity(EntityManager& manager, float x, float y) { - auto* arena = Juliet::GetGameArena(); - EntityType* result = Juliet::ArenaPushType(arena); - Entity* base = result->Base = Juliet::ArenaPushType(arena); + auto* arena = Juliet::GetGameArena(); + EntityType* result = Juliet::ArenaPushType(arena, ConstString("EntityType")); + Entity* base = result->Base = Juliet::ArenaPushType(arena, ConstString("Entity")); base->X = x; base->Y = y; base->Derived = result; diff --git a/Game/game.cpp b/Game/game.cpp index 63e0349..f741572 100644 --- a/Game/game.cpp +++ b/Game/game.cpp @@ -40,7 +40,7 @@ extern "C" JULIET_API void GameInit(GameInitParams* /*params*/) int Score; }; - auto* gameState = ArenaPushType(GetGameArena()); + auto* gameState = ArenaPushType(GetGameArena(), ConstString("GameState")); gameState->TotalTime = 0.0f; gameState->Score = 0; diff --git a/Juliet/include/Core/ImGui/ImGuiService.h b/Juliet/include/Core/ImGui/ImGuiService.h index 08f793f..a700a65 100644 --- a/Juliet/include/Core/ImGui/ImGuiService.h +++ b/Juliet/include/Core/ImGui/ImGuiService.h @@ -18,10 +18,10 @@ namespace Juliet JULIET_API void NewFrame(); JULIET_API void Render(); - JULIET_API bool IsInitialized(); + JULIET_API bool IsInitialized(); JULIET_API ImGuiContext* GetContext(); // Run internal unit tests - JULIET_API void RunTests(NonNullPtr device, NonNullPtr window); - } -} + JULIET_API void RunTests(); + } // namespace ImGuiService +} // namespace Juliet diff --git a/Juliet/include/Core/ImGui/ImGuiTests.h b/Juliet/include/Core/ImGui/ImGuiTests.h index 723219a..59befec 100644 --- a/Juliet/include/Core/ImGui/ImGuiTests.h +++ b/Juliet/include/Core/ImGui/ImGuiTests.h @@ -8,5 +8,5 @@ namespace Juliet::UnitTest { - void TestImGui(NonNullPtr device, NonNullPtr window); + void TestImGui(); } diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index 9f3cf56..b356433 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -1,9 +1,10 @@ #pragma once -#include #include #include +#include #include +#include namespace Juliet { @@ -12,12 +13,13 @@ namespace Juliet uint8* Data; size_t Size; size_t Offset; + #if JULIET_DEBUG struct AllocationInfo { - size_t Offset; - size_t Size; - const char* Tag; + size_t Offset; + size_t Size; + String Tag; }; // Use a simple array for now to avoid std::vector dependency in the header or complex management // Ideally this should be a linked list or similar @@ -25,17 +27,14 @@ namespace Juliet AllocationInfo Allocations[kMaxAllocations]; size_t AllocationCount = 0; #endif - }; - JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size); - JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16, const char* tag = nullptr); - - JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16, const char* tag = nullptr); - - JULIET_API void ArenaReset(MemoryArena* arena); + JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size); + JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, String tag); + JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag); + JULIET_API void ArenaReset(MemoryArena* arena); JULIET_API size_t ArenaGetMarker(MemoryArena* arena); - JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker); + JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker); // --- Global Arenas & Management --- @@ -50,12 +49,12 @@ namespace Juliet // Internal engine function to initialize memory arenas. void MemoryArenasInit(); - + // Internal engine function to shutdown memory arenas. void MemoryArenasShutdown(); template - inline T* ArenaPushType(MemoryArena* arena, const char* tag = nullptr) + inline T* ArenaPushType(MemoryArena* arena, String tag) { T* result = static_cast(ArenaPush(arena, sizeof(T), alignof(T), tag)); @@ -67,7 +66,7 @@ namespace Juliet } template - inline T* ArenaPushArray(MemoryArena* arena, size_t count, const char* tag = nullptr) + inline T* ArenaPushArray(MemoryArena* arena, size_t count, String tag) { T* result = static_cast(ArenaPush(arena, sizeof(T) * count, alignof(T), tag)); @@ -79,8 +78,9 @@ namespace Juliet } template - inline T* ArenaRealloc(MemoryArena* arena, T* oldPtr, size_t oldCount, size_t newCount) + inline T* ArenaRealloc(MemoryArena* arena, T* oldPtr, size_t oldCount, size_t newCount, String tag) { - return static_cast(Juliet::ArenaRealloc(arena, static_cast(oldPtr), sizeof(T) * oldCount, sizeof(T) * newCount, alignof(T))); + return static_cast(Juliet::ArenaRealloc(arena, static_cast(oldPtr), sizeof(T) * oldCount, + sizeof(T) * newCount, alignof(T), tag)); } } // namespace Juliet diff --git a/Juliet/include/Engine/Debug/MemoryDebugger.h b/Juliet/include/Engine/Debug/MemoryDebugger.h index 806dee7..90c74d1 100644 --- a/Juliet/include/Engine/Debug/MemoryDebugger.h +++ b/Juliet/include/Engine/Debug/MemoryDebugger.h @@ -1,13 +1,9 @@ #pragma once -#include -#include -namespace Juliet +#include +#include + +namespace Juliet::Debug { - class JULIET_API MemoryDebugger - { - public: - static void DrawMemoryArena(const char* name, const MemoryArena& arena); - static void DrawGlobalArenas(); - }; -} + JULIET_API void DebugDrawMemoryArena(); +} // namespace Juliet::Debug diff --git a/Juliet/src/Core/HAL/Display/Display.cpp b/Juliet/src/Core/HAL/Display/Display.cpp index 2359d72..406e0fd 100644 --- a/Juliet/src/Core/HAL/Display/Display.cpp +++ b/Juliet/src/Core/HAL/Display/Display.cpp @@ -2,8 +2,8 @@ #include #include #include -#include #include +#include #include namespace Juliet @@ -17,7 +17,7 @@ namespace Juliet { // TODO : IfDef new factories that are not compatible constexpr DisplayDeviceFactory* Factories[] = { &Win32DisplayDeviceFactory, nullptr }; - } // namespace + } // namespace Internal::Display void InitializeDisplaySystem() { @@ -74,8 +74,8 @@ namespace Juliet { Assert(g_CurrentDisplayDevice->CreatePlatformWindow); - MemoryArena* arena = GetEngineArena(); - auto window = ArenaPushType(arena); + MemoryArena* arena = GetEngineArena(); + auto window = ArenaPushType(arena, ConstString("Window")); if (!window) { return nullptr; @@ -84,7 +84,7 @@ namespace Juliet window->Height = height; auto titleLen = StringLength(title); - auto buffer = ArenaPushArray(arena, titleLen); + auto buffer = ArenaPushArray(arena, titleLen, ConstString("Window Title Array")); MemCopy(buffer, title, titleLen); window->Title.Data = buffer; @@ -93,7 +93,7 @@ namespace Juliet g_CurrentDisplayDevice->MainWindow = window; if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, window)) { - // Note: We don't "free" from arena easily, but since this is catastrophic + // Note: We don't "free" from arena easily, but since this is catastrophic // and persistent, we just leak the small amount of arena space or handle it if we had a marker. return nullptr; } diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp index be3dc76..e418494 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayDevice.cpp @@ -18,8 +18,8 @@ namespace Juliet::Win32 DisplayDevice* CreateDevice() { - auto device = ArenaPushType(GetEngineArena()); - + auto device = ArenaPushType(GetEngineArena(), ConstString("DisplayDevice")); + if (!device) { return nullptr; diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp index c81719f..45a2912 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp @@ -14,7 +14,7 @@ namespace Juliet::Win32 bool SetupWindowState(NonNullPtr /*self*/, NonNullPtr window, HWND handle) { - auto state = ArenaPushType(GetEngineArena()); + auto state = ArenaPushType(GetEngineArena(), ConstString("Window32State")); window->State = state; state->Handle = handle; diff --git a/Juliet/src/Core/HotReload/HotReload.cpp b/Juliet/src/Core/HotReload/HotReload.cpp index 88f3d93..da31704 100644 --- a/Juliet/src/Core/HotReload/HotReload.cpp +++ b/Juliet/src/Core/HotReload/HotReload.cpp @@ -22,8 +22,9 @@ namespace Juliet // First allocate all the full path. // TODO: Add path composition into filesystem + string format + string builder - const size_t dllFullPathLength = basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings - code.DLLFullPath.Data = ArenaPushArray(GetEngineArena(), dllFullPathLength); + const size_t dllFullPathLength = + basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings + code.DLLFullPath.Data = ArenaPushArray(GetEngineArena(), dllFullPathLength, ConstString("DLLFullPath")); int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName)); if (writtenSize < static_cast(dllFullPathLength) - 1) { @@ -34,8 +35,9 @@ namespace Juliet code.DLLFullPath.Size = static_cast(writtenSize); // Lock filename path - const size_t lockPathLength = basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings - code.LockFullPath.Data = ArenaPushArray(GetEngineArena(), lockPathLength); + const size_t lockPathLength = + basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings + code.LockFullPath.Data = ArenaPushArray(GetEngineArena(), lockPathLength, ConstString("LockFullPath")); writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename)); if (writtenSize < static_cast(lockPathLength) - 1) { diff --git a/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp b/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp index 8adce57..849c0c6 100644 --- a/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp +++ b/Juliet/src/Core/HotReload/Win32/Win32HotReload.cpp @@ -54,10 +54,10 @@ namespace Juliet const size_t tempDllMaxBufferSize = basePathLength + StringLength(code.TransientDLLName) + /* _ */ 1 + kTempDLLBufferSizeForID + 1 /* \0 */; - + // Allocate from Scratch Arena (transient) - auto tempDllPath = ArenaPushArray(GetScratchArena(), tempDllMaxBufferSize); - + auto tempDllPath = ArenaPushArray(GetScratchArena(), tempDllMaxBufferSize, ConstString("tempDllPath")); + for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt) { // int to char @@ -79,7 +79,8 @@ namespace Juliet return; } - if (static_cast(writtenSize) + 1 < basePathLength + static_cast(idLength) + code.TransientDLLName.Size) + if (static_cast(writtenSize) + 1 < + basePathLength + static_cast(idLength) + code.TransientDLLName.Size) { // Scratch memory, no free needed Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path"); diff --git a/Juliet/src/Core/ImGui/ImGuiService.cpp b/Juliet/src/Core/ImGui/ImGuiService.cpp index 6814a96..37cc7a1 100644 --- a/Juliet/src/Core/ImGui/ImGuiService.cpp +++ b/Juliet/src/Core/ImGui/ImGuiService.cpp @@ -1,16 +1,15 @@ -#include #include #include #include #include #include +#include #include -#include +#include #include -#include -#include +#include // Forward declare implementation functions from backends extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -24,7 +23,7 @@ namespace Juliet::ImGuiService void* ImGuiAllocWrapper(size_t size, void* /*user_data*/) { - return ArenaPush(GetGameArena(), size, 16, "ImGui"); + return ArenaPush(GetEngineArena(), size, 16, ConstString("ImGui")); } void ImGuiFreeWrapper(void* /*ptr*/, void* /*user_data*/) @@ -35,10 +34,7 @@ namespace Juliet::ImGuiService void Initialize(NonNullPtr window) { - if (g_Initialized) - { - return; - } + Assert(!g_Initialized); // Setup Allocator ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr); @@ -46,7 +42,6 @@ namespace Juliet::ImGuiService IMGUI_CHECKVERSION(); g_ImGuiContext = ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls @@ -56,17 +51,12 @@ namespace Juliet::ImGuiService auto* win32State = static_cast(window->State); ImGui_ImplWin32_Init(win32State->Handle); - // Renderer Init is done later or here? - // We need the ID3D12Device, which is in GraphicsDevice. - // We should probably split Init. - // For now, let's assume we do Renderer Init in GraphicsDevice. - g_Initialized = true; } void Shutdown() { - if (!g_Initialized) return; + Assert(g_Initialized); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(g_ImGuiContext); @@ -76,7 +66,7 @@ namespace Juliet::ImGuiService void NewFrame() { - if (!g_Initialized) return; + Assert(g_Initialized); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); @@ -84,7 +74,7 @@ namespace Juliet::ImGuiService void Render() { - if (!g_Initialized) return; + Assert(g_Initialized); ImGui::Render(); } @@ -99,24 +89,9 @@ namespace Juliet::ImGuiService return g_ImGuiContext; } - void RunTests(NonNullPtr device, NonNullPtr window) + void RunTests() { printf("ImGuiService: Running Unit Tests...\n"); - Juliet::UnitTest::TestImGui(device, window); - - // Also run internal Dear ImGui validation - if (g_ImGuiContext) - { - // Verify version and data layout (Basic internal check) - bool result = ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)); - if (result) - { - printf("ImGuiService: DebugCheckVersionAndDataLayout Passed.\n"); - } - else - { - printf("ImGuiService: DebugCheckVersionAndDataLayout FAILED!\n"); - } - } + Juliet::UnitTest::TestImGui(); } } // namespace Juliet::ImGuiService diff --git a/Juliet/src/Core/ImGui/ImGuiTests.cpp b/Juliet/src/Core/ImGui/ImGuiTests.cpp index 9bf17ab..faff455 100644 --- a/Juliet/src/Core/ImGui/ImGuiTests.cpp +++ b/Juliet/src/Core/ImGui/ImGuiTests.cpp @@ -1,29 +1,15 @@ #include #include #include +#include #include #include #include -#include namespace Juliet::UnitTest { - // Mocking window creation is hard because it needs real OS calls. - // We will assume the test runner has created a window or we create a headless one? - // Win32Window requires RegisterClass etc. - // Let's rely on the fact that if we run this test in "App" mode it works, - // but in CI headless it might fail if we don't handle it. - // For now, let's skip the Platform Init part if we can't create a window, - // or try to create a dummy window. - - void TestImGui(NonNullPtr device, NonNullPtr window) + void TestImGui() { - (void)device; - // 1. Verify Allocator Hook - - // Initialize (Idempotent safe) - ImGuiService::Initialize(window); - ImGuiContext* ctx = ImGuiService::GetContext(); if (ImGui::GetCurrentContext() != ctx) @@ -35,31 +21,28 @@ namespace Juliet::UnitTest (void)ctx; printf("TestImGui: Context Verified.\n"); - // 3. Verify IO ImGuiIO& io = ImGui::GetIO(); Assert(io.BackendPlatformName != nullptr); printf("TestImGui: IO Verified. Backend: %s\n", io.BackendPlatformName); - - // 4. Verify Version + Assert(ImGui::GetVersion() != nullptr); printf("TestImGui: Version Verified: %s\n", ImGui::GetVersion()); - - // 5. Verify Fonts + Assert(io.Fonts != nullptr); printf("TestImGui: Fonts Verified.\n"); - + bool built = io.Fonts->IsBuilt(); + Assert(built); printf("TestImGui: Fonts Built Status: %d\n", built); - - // Assert(io.Fonts->IsBuilt() == false); // Disabled as Renderer might have built it - + unsigned char* pixels; - int width, height; + int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); Assert(pixels != nullptr); Assert(width > 0 && height > 0); - Assert(io.Fonts->IsBuilt() == true); - (void)pixels; (void)width; (void)height; + (void)pixels; + (void)width; + (void)height; printf("TestImGui: Font Atlas Verified.\n"); // 6. Verify Style @@ -70,14 +53,15 @@ namespace Juliet::UnitTest // 7. Test New Frame Assert(ImGuiService::IsInitialized()); - + // Simulate a frame - if (io.DisplaySize.x <= 0.0f || io.DisplaySize.y <= 0.0f) { - io.DisplaySize = ImVec2(1920, 1080); + if (io.DisplaySize.x <= 0.0f || io.DisplaySize.y <= 0.0f) + { + io.DisplaySize = ImVec2(1920, 1080); } io.DeltaTime = 1.0f / 60.0f; printf("TestImGui: About to DrawList check.\n"); - + // 8. Check Draw List Access ImDrawList* drawList = ImGui::GetForegroundDrawList(); Assert(drawList != nullptr); @@ -85,5 +69,4 @@ namespace Juliet::UnitTest printf("ImGui tests passed (Exhaustive).\n"); } - } // namespace Juliet::UnitTest diff --git a/Juliet/src/Core/Memory/MemoryArena.cpp b/Juliet/src/Core/Memory/MemoryArena.cpp index d3410f1..2af1392 100644 --- a/Juliet/src/Core/Memory/MemoryArena.cpp +++ b/Juliet/src/Core/Memory/MemoryArena.cpp @@ -23,9 +23,8 @@ namespace Juliet #endif } - void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, const char* tag) + void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, [[maybe_unused]] String tag) { - (void)tag; // TODO: Use tag for allocation tracking in Debug builds Assert(arena); // Alignment must be power of 2 @@ -47,7 +46,8 @@ namespace Juliet #if JULIET_DEBUG if (arena->AllocationCount < MemoryArena::kMaxAllocations) { - arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast(arena->Data), size, tag ? tag : "Unknown" }; + arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast(arena->Data), size, + IsValid(tag) ? tag : WrapString("Unknown") }; arena->AllocationCount++; } #endif @@ -55,8 +55,7 @@ namespace Juliet return result; } - void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, const char* tag) - + void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, String tag) { Assert(arena); // Alignment must be power of 2 @@ -119,7 +118,7 @@ namespace Juliet if (newPtr) { size_t copySize = oldSize < newSize ? oldSize : newSize; - std::memcpy(newPtr, oldPtr, copySize); + MemCopy(newPtr, oldPtr, copySize); } return newPtr; } @@ -161,7 +160,6 @@ namespace Juliet } // --- Global Arenas & Management --- - namespace { MemoryArena g_ScratchArena; diff --git a/Juliet/src/Core/Memory/MemoryArenaTests.cpp b/Juliet/src/Core/Memory/MemoryArenaTests.cpp index 4ab8642..9318a61 100644 --- a/Juliet/src/Core/Memory/MemoryArenaTests.cpp +++ b/Juliet/src/Core/Memory/MemoryArenaTests.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #if JULIET_DEBUG @@ -16,12 +16,12 @@ namespace Juliet::UnitTest Assert(arena.Offset == 0); Assert(arena.Size == 1024); - void* p1 = ArenaPush(&arena, 100); + void* p1 = ArenaPush(&arena, 100, 16, ConstString("Test")); Assert(p1 != nullptr); Assert(arena.Offset >= 100); size_t marker = ArenaGetMarker(&arena); - void* p2 = ArenaPush(&arena, 200); + void* p2 = ArenaPush(&arena, 200, 16, ConstString("Test")); Assert(p2 != nullptr); Assert(arena.Offset >= marker + 200); @@ -32,9 +32,9 @@ namespace Juliet::UnitTest Assert(arena.Offset == 0); // 2. Alignment Test - void* p3 = ArenaPush(&arena, 1, 1); + void* p3 = ArenaPush(&arena, 1, 1, ConstString("Test")); [[maybe_unused]] size_t addr = reinterpret_cast(p3); - void* p4 = ArenaPush(&arena, 1, 16); + void* p4 = ArenaPush(&arena, 1, 16, ConstString("Test")); size_t addr2 = reinterpret_cast(p4); Assert((addr2 % 16) == 0); @@ -44,18 +44,18 @@ namespace Juliet::UnitTest int a; float b; }; - TestData* data = ArenaPushType(&arena); + TestData* data = ArenaPushType(&arena, ConstString("Test")); Assert(data != nullptr); data->a = 10; data->b = 20.0f; - TestData* dataArray = ArenaPushArray(&arena, 10); + TestData* dataArray = ArenaPushArray(&arena, 10, ConstString("Test")); Assert(dataArray != nullptr); // 4. Scratch Arena MemoryArena* scratch = GetScratchArena(); Assert(scratch != nullptr); - void* sp = ArenaPush(scratch, 100); + void* sp = ArenaPush(scratch, 100, 16, ConstString("Test")); Assert(sp != nullptr); ScratchArenaReset(); Assert(scratch->Offset == 0); diff --git a/Juliet/src/Engine/Debug/MemoryDebugger.cpp b/Juliet/src/Engine/Debug/MemoryDebugger.cpp index 5bb63f2..171f450 100644 --- a/Juliet/src/Engine/Debug/MemoryDebugger.cpp +++ b/Juliet/src/Engine/Debug/MemoryDebugger.cpp @@ -1,68 +1,76 @@ +#include +#include +#include #include #include -#include -namespace Juliet +namespace Juliet::Debug { - void MemoryDebugger::DrawMemoryArena(const char* name, const MemoryArena& arena) + namespace { - if (ImGui::CollapsingHeader(name, ImGuiTreeNodeFlags_DefaultOpen)) + void DrawMemoryArena(String name, const MemoryArena& arena) { - float progress = 0.0f; - if (arena.Size > 0) + if (ImGui::CollapsingHeader(CStr(name), ImGuiTreeNodeFlags_DefaultOpen)) { - progress = (float)arena.Offset / (float)arena.Size; - } + float progress = 0.0f; + if (arena.Size > 0) + { + progress = (float)arena.Offset / (float)arena.Size; + } - char overlay[64]; - sprintf_s(overlay, "%zu / %zu bytes", arena.Offset, arena.Size); - ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), overlay); + char overlay[64]; + sprintf_s(overlay, "%zu / %zu bytes", arena.Offset, arena.Size); + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), overlay); #if JULIET_DEBUG - if (ImGui::TreeNode("Allocations")) - { - size_t displayedSize = 0; - // Draw allocations as a list for now - if (ImGui::BeginTable("AllocationsTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable)) + ImGui::PushID(CStr(name)); + if (ImGui::TreeNode("Allocations")) { - ImGui::TableSetupColumn("Tag"); - ImGui::TableSetupColumn("Size"); - ImGui::TableSetupColumn("Offset"); - ImGui::TableHeadersRow(); - - for (size_t i = 0; i < arena.AllocationCount; ++i) + size_t displayedSize = 0; + // Draw allocations as a list for now + if (ImGui::BeginTable("AllocationsTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable)) { - const auto& alloc = arena.Allocations[i]; - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("%s", alloc.Tag); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%zu", alloc.Size); - ImGui::TableSetColumnIndex(2); - ImGui::Text("%zu", alloc.Offset); - - displayedSize += alloc.Size; + ImGui::TableSetupColumn("Tag"); + ImGui::TableSetupColumn("Size"); + ImGui::TableSetupColumn("Offset"); + ImGui::TableHeadersRow(); + + for (size_t i = 0; i < arena.AllocationCount; ++i) + { + const auto& alloc = arena.Allocations[i]; + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::Text("%s", CStr(alloc.Tag)); + ImGui::TableSetColumnIndex(1); + ImGui::Text("%zu", alloc.Size); + ImGui::TableSetColumnIndex(2); + ImGui::Text("%zu", alloc.Offset); + + displayedSize += alloc.Size; + } + ImGui::EndTable(); } - ImGui::EndTable(); + ImGui::Text("Total Tracked Size: %zu", displayedSize); + ImGui::Text("Untracked/Padding: %zu", arena.Offset - displayedSize); + + ImGui::TreePop(); } - ImGui::Text("Total Tracked Size: %zu", displayedSize); - ImGui::Text("Untracked/Padding: %zu", arena.Offset - displayedSize); - - ImGui::TreePop(); - } + ImGui::PopID(); #else - ImGui::Text("Detailed allocation tracking disabled in Release build."); + ImGui::Text("Detailed allocation tracking disabled in Release build."); #endif + } } - } + } // namespace - void MemoryDebugger::DrawGlobalArenas() + void DebugDrawMemoryArena() { if (ImGui::Begin("Memory Debugger")) { - DrawMemoryArena("Scratch Arena", *GetScratchArena()); - DrawMemoryArena("Game Arena", *GetGameArena()); + DrawMemoryArena(ConstString("Game Arena"), *GetGameArena()); + DrawMemoryArena(ConstString("Engine Arena"), *GetEngineArena()); + DrawMemoryArena(ConstString("Scratch Arena"), *GetScratchArena()); } ImGui::End(); } -} +} // namespace Juliet::Debug diff --git a/Juliet/src/Engine/Engine.cpp b/Juliet/src/Engine/Engine.cpp index a4bab03..1934ae7 100644 --- a/Juliet/src/Engine/Engine.cpp +++ b/Juliet/src/Engine/Engine.cpp @@ -1,8 +1,8 @@ -#include -#include #include #include +#include #include +#include #include #include #include @@ -24,7 +24,7 @@ namespace Juliet void InitializeDependentSystems() { GraphicsDevice* device = EngineInstance.Application->GetGraphicsDevice(); - + // DebugDisplay system if (device) { @@ -32,9 +32,7 @@ namespace Juliet } #ifdef JULIET_ENABLE_IMGUI - Window* window = EngineInstance.Application->GetPlatformWindow(); - - if (window) + if (NonNullPtr window = EngineInstance.Application->GetPlatformWindow()) { ImGuiService::Initialize(window); ImGui::SetCurrentContext(ImGuiService::GetContext()); @@ -44,7 +42,7 @@ namespace Juliet ImGuiRenderer_Initialize(device); // Run Unit Tests automatically - ImGuiService::RunTests(device, window); + ImGuiService::RunTests(); } } #endif diff --git a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp b/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp index a751449..4979f5d 100644 --- a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp @@ -10,7 +10,7 @@ namespace Juliet::D3D12::Internal { ID3D12DescriptorHeap* handle; - auto heap = static_cast(Calloc(1, sizeof(D3D12DescriptorHeap))); + auto heap = ArenaPushType(GetEngineArena(), ConstString("D3D12DescriptorHeap")); if (!heap) { return nullptr; @@ -19,7 +19,8 @@ namespace Juliet::D3D12::Internal heap->CurrentDescriptorIndex = 0; heap->FreeIndicesCapacity = 16; heap->FreeIndicesCount = 0; - heap->FreeIndices = static_cast(Calloc(heap->FreeIndicesCapacity, sizeof(uint32))); + heap->FreeIndices = ArenaPushArray(GetEngineArena(), heap->FreeIndicesCapacity, + ConstString("D3D12DescriptorHeap/FreeIndices")); D3D12_DESCRIPTOR_HEAP_DESC heapDesc; heapDesc.NumDescriptors = count; @@ -27,8 +28,7 @@ namespace Juliet::D3D12::Internal heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; heapDesc.NodeMask = 0; - HRESULT result = - driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle); + HRESULT result = driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle); if (FAILED(result)) { LogError(driver->D3D12Device, "Failed to create descriptor heap!", result); @@ -36,11 +36,11 @@ namespace Juliet::D3D12::Internal return nullptr; } - heap->Handle = handle; - heap->HeapType = type; - heap->MaxDescriptors = count; - heap->Staging = isStaging; - heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); + heap->Handle = handle; + heap->HeapType = type; + heap->MaxDescriptors = count; + heap->Staging = isStaging; + heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart(); if (!isStaging) { @@ -143,8 +143,8 @@ namespace Juliet::D3D12::Internal size_t oldCapacity = pool->Capacity; pool->Capacity = pool->Capacity == 0 ? 1 : pool->Capacity * 2; - // Using ArenaRealloc (Template): - pool->Heaps = ArenaRealloc(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity); + pool->Heaps = ArenaRealloc(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity, + ConstString("DescriptorHeapArray")); // Initialize new slots to nullptr for (size_t i = oldCapacity; i < pool->Capacity; ++i) diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp index 176b822..3ecfd5e 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp @@ -1035,7 +1035,8 @@ namespace Juliet::D3D12 { heapPool.Capacity = 4; heapPool.Count = 4; - heapPool.Heaps = ArenaPushArray(GetEngineArena(), heapPool.Capacity); + heapPool.Heaps = ArenaPushArray(GetEngineArena(), heapPool.Capacity, + ConstString("DescriptorHeap")); for (uint32 i = 0; i < heapPool.Capacity; ++i) { diff --git a/Juliet/src/Graphics/ImGuiRenderer.cpp b/Juliet/src/Graphics/ImGuiRenderer.cpp index 64eaf17..99fa22b 100644 --- a/Juliet/src/Graphics/ImGuiRenderer.cpp +++ b/Juliet/src/Graphics/ImGuiRenderer.cpp @@ -5,10 +5,10 @@ #include #include -#include #include - #include + +#include #include namespace Juliet diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 04ae92f..cb946ab 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -267,10 +267,6 @@ void JulietApplication::Update() } } - if (evt.Type == EventType::Key_Down) - { - } - // Shader hot reload using keyboard. if (!reloadShadersDebounce && ((GetKeyModState() & KeyMod::Alt) != KeyMod::None) && IsKeyDown(ScanCode::R)) { @@ -355,6 +351,11 @@ void JulietApplication::Update() Running = false; } } + + if (ShowMemoryDebugger) + { + Debug::DebugDrawMemoryArena(); + } } void JulietApplication::OnPreRender(CommandList* cmd) @@ -383,8 +384,6 @@ void JulietApplication::OnPreRender(CommandList* cmd) CopyBuffer(cmd, ConstantBuffer, TransferBuffer, 256); TransitionBufferToReadable(cmd, ConstantBuffer); } - - } void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd) @@ -403,11 +402,6 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd) SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData); DrawPrimitives(pass, 6, 1, 0, 0); - - if (ShowMemoryDebugger) - { - MemoryDebugger::DrawGlobalArenas(); - } } ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)