Cleaned up memory arena debugger + tag.
WIP
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
// 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>
|
||||
EntityType* MakeEntity(EntityManager& manager, float x, float y)
|
||||
{
|
||||
auto* arena = Juliet::GetGameArena();
|
||||
EntityType* result = Juliet::ArenaPushType<EntityType>(arena);
|
||||
Entity* base = result->Base = Juliet::ArenaPushType<Entity>(arena);
|
||||
auto* arena = Juliet::GetGameArena();
|
||||
EntityType* result = Juliet::ArenaPushType<EntityType>(arena, ConstString("EntityType"));
|
||||
Entity* base = result->Base = Juliet::ArenaPushType<Entity>(arena, ConstString("Entity"));
|
||||
base->X = x;
|
||||
base->Y = y;
|
||||
base->Derived = result;
|
||||
|
||||
@@ -40,7 +40,7 @@ extern "C" JULIET_API void GameInit(GameInitParams* /*params*/)
|
||||
int Score;
|
||||
};
|
||||
|
||||
auto* gameState = ArenaPushType<GameState>(GetGameArena());
|
||||
auto* gameState = ArenaPushType<GameState>(GetGameArena(), ConstString("GameState"));
|
||||
gameState->TotalTime = 0.0f;
|
||||
gameState->Score = 0;
|
||||
|
||||
|
||||
@@ -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<GraphicsDevice> device, NonNullPtr<Window> window);
|
||||
}
|
||||
}
|
||||
JULIET_API void RunTests();
|
||||
} // namespace ImGuiService
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
|
||||
namespace Juliet::UnitTest
|
||||
{
|
||||
void TestImGui(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
|
||||
void TestImGui();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Juliet.h>
|
||||
#include <Core/Common/CoreTypes.h>
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
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 <typename T>
|
||||
inline T* ArenaPushType(MemoryArena* arena, const char* tag = nullptr)
|
||||
inline T* ArenaPushType(MemoryArena* arena, String tag)
|
||||
{
|
||||
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T), tag));
|
||||
|
||||
@@ -67,7 +66,7 @@ namespace Juliet
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T), tag));
|
||||
|
||||
@@ -79,8 +78,9 @@ namespace Juliet
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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<T*>(Juliet::ArenaRealloc(arena, static_cast<void*>(oldPtr), sizeof(T) * oldCount, sizeof(T) * newCount, alignof(T)));
|
||||
return static_cast<T*>(Juliet::ArenaRealloc(arena, static_cast<void*>(oldPtr), sizeof(T) * oldCount,
|
||||
sizeof(T) * newCount, alignof(T), tag));
|
||||
}
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#pragma once
|
||||
#include <Juliet.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
|
||||
namespace Juliet
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <Core/HAL/Display/Display_Private.h>
|
||||
#include <Core/HAL/Display/DisplayDevice.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <format>
|
||||
|
||||
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<Window>(arena);
|
||||
MemoryArena* arena = GetEngineArena();
|
||||
auto window = ArenaPushType<Window>(arena, ConstString("Window"));
|
||||
if (!window)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -84,7 +84,7 @@ namespace Juliet
|
||||
window->Height = height;
|
||||
|
||||
auto titleLen = StringLength(title);
|
||||
auto buffer = ArenaPushArray<char>(arena, titleLen);
|
||||
auto buffer = ArenaPushArray<char>(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;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Juliet::Win32
|
||||
|
||||
DisplayDevice* CreateDevice()
|
||||
{
|
||||
auto device = ArenaPushType<DisplayDevice>(GetEngineArena());
|
||||
|
||||
auto device = ArenaPushType<DisplayDevice>(GetEngineArena(), ConstString("DisplayDevice"));
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return nullptr;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Juliet::Win32
|
||||
|
||||
bool SetupWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window, HWND handle)
|
||||
{
|
||||
auto state = ArenaPushType<Window32State>(GetEngineArena());
|
||||
auto state = ArenaPushType<Window32State>(GetEngineArena(), ConstString("Window32State"));
|
||||
|
||||
window->State = state;
|
||||
state->Handle = handle;
|
||||
|
||||
@@ -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<char>(GetEngineArena(), dllFullPathLength);
|
||||
const size_t dllFullPathLength =
|
||||
basePathLength + StringLength(dllName) + 1; // Need +1 because snprintf needs 0 terminated strings
|
||||
code.DLLFullPath.Data = ArenaPushArray<char>(GetEngineArena(), dllFullPathLength, ConstString("DLLFullPath"));
|
||||
int writtenSize = snprintf(CStr(code.DLLFullPath), dllFullPathLength, "%s%s", CStr(basePath), CStr(dllName));
|
||||
if (writtenSize < static_cast<int>(dllFullPathLength) - 1)
|
||||
{
|
||||
@@ -34,8 +35,9 @@ namespace Juliet
|
||||
code.DLLFullPath.Size = static_cast<size_t>(writtenSize);
|
||||
|
||||
// Lock filename path
|
||||
const size_t lockPathLength = basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings
|
||||
code.LockFullPath.Data = ArenaPushArray<char>(GetEngineArena(), lockPathLength);
|
||||
const size_t lockPathLength =
|
||||
basePathLength + StringLength(lockFilename) + 1; // Need +1 because snprintf needs 0 terminated strings
|
||||
code.LockFullPath.Data = ArenaPushArray<char>(GetEngineArena(), lockPathLength, ConstString("LockFullPath"));
|
||||
writtenSize = snprintf(CStr(code.LockFullPath), lockPathLength, "%s%s", CStr(basePath), CStr(lockFilename));
|
||||
if (writtenSize < static_cast<int>(lockPathLength) - 1)
|
||||
{
|
||||
|
||||
@@ -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<char>(GetScratchArena(), tempDllMaxBufferSize);
|
||||
|
||||
auto tempDllPath = ArenaPushArray<char>(GetScratchArena(), tempDllMaxBufferSize, ConstString("tempDllPath"));
|
||||
|
||||
for (uint32 attempt = 0; attempt < kMaxAttempts; ++attempt)
|
||||
{
|
||||
// int to char
|
||||
@@ -79,7 +79,8 @@ namespace Juliet
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(writtenSize) + 1 < basePathLength + static_cast<size_t>(idLength) + code.TransientDLLName.Size)
|
||||
if (static_cast<size_t>(writtenSize) + 1 <
|
||||
basePathLength + static_cast<size_t>(idLength) + code.TransientDLLName.Size)
|
||||
{
|
||||
// Scratch memory, no free needed
|
||||
Log(LogLevel::Error, LogCategory::Core, "Cannot create temp full path");
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#include <cstdio>
|
||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||
#include <Core/HAL/Display/Window.h>
|
||||
#include <Core/ImGui/ImGuiService.h>
|
||||
#include <Core/ImGui/ImGuiTests.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Graphics/D3D12/D3D12Includes.h>
|
||||
|
||||
#include <backends/imgui_impl_win32.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#include <backends/imgui_impl_dx12.h>
|
||||
#include <backends/imgui_impl_win32.h>
|
||||
#include <cstdio>
|
||||
|
||||
// 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> 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<Win32::Window32State*>(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<GraphicsDevice> device, NonNullPtr<Window> 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
|
||||
|
||||
@@ -1,29 +1,15 @@
|
||||
#include <Core/HAL/Display/Display.h>
|
||||
#include <Core/ImGui/ImGuiService.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <cstdio>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <imgui.h>
|
||||
#include <Juliet.h>
|
||||
#include <cstdio>
|
||||
|
||||
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<GraphicsDevice> device, NonNullPtr<Window> 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
|
||||
|
||||
@@ -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<size_t>(arena->Data), size, tag ? tag : "Unknown" };
|
||||
arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast<size_t>(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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <cstdio>
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <cstdio>
|
||||
|
||||
#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<size_t>(p3);
|
||||
void* p4 = ArenaPush(&arena, 1, 16);
|
||||
void* p4 = ArenaPush(&arena, 1, 16, ConstString("Test"));
|
||||
size_t addr2 = reinterpret_cast<size_t>(p4);
|
||||
Assert((addr2 % 16) == 0);
|
||||
|
||||
@@ -44,18 +44,18 @@ namespace Juliet::UnitTest
|
||||
int a;
|
||||
float b;
|
||||
};
|
||||
TestData* data = ArenaPushType<TestData>(&arena);
|
||||
TestData* data = ArenaPushType<TestData>(&arena, ConstString("Test"));
|
||||
Assert(data != nullptr);
|
||||
data->a = 10;
|
||||
data->b = 20.0f;
|
||||
|
||||
TestData* dataArray = ArenaPushArray<TestData>(&arena, 10);
|
||||
TestData* dataArray = ArenaPushArray<TestData>(&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);
|
||||
|
||||
@@ -1,68 +1,76 @@
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <cstdio>
|
||||
#include <Engine/Debug/MemoryDebugger.h>
|
||||
#include <imgui.h>
|
||||
#include <cstdio>
|
||||
|
||||
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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Engine/Engine.h>
|
||||
#include <Core/Common/CoreUtils.h>
|
||||
#include <Core/JulietInit.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <Engine/Engine.h>
|
||||
#include <Graphics/DebugDisplay.h>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Juliet::D3D12::Internal
|
||||
{
|
||||
ID3D12DescriptorHeap* handle;
|
||||
|
||||
auto heap = static_cast<D3D12DescriptorHeap*>(Calloc(1, sizeof(D3D12DescriptorHeap)));
|
||||
auto heap = ArenaPushType<D3D12DescriptorHeap>(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<uint32*>(Calloc(heap->FreeIndicesCapacity, sizeof(uint32)));
|
||||
heap->FreeIndices = ArenaPushArray<uint32>(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<D3D12DescriptorHeap*>(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity);
|
||||
pool->Heaps = ArenaRealloc<D3D12DescriptorHeap*>(GetEngineArena(), pool->Heaps, oldCapacity, pool->Capacity,
|
||||
ConstString("DescriptorHeapArray"));
|
||||
|
||||
// Initialize new slots to nullptr
|
||||
for (size_t i = oldCapacity; i < pool->Capacity; ++i)
|
||||
|
||||
@@ -1035,7 +1035,8 @@ namespace Juliet::D3D12
|
||||
{
|
||||
heapPool.Capacity = 4;
|
||||
heapPool.Count = 4;
|
||||
heapPool.Heaps = ArenaPushArray<Internal::D3D12DescriptorHeap*>(GetEngineArena(), heapPool.Capacity);
|
||||
heapPool.Heaps = ArenaPushArray<Internal::D3D12DescriptorHeap*>(GetEngineArena(), heapPool.Capacity,
|
||||
ConstString("DescriptorHeap"));
|
||||
|
||||
for (uint32 i = 0; i < heapPool.Capacity; ++i)
|
||||
{
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
|
||||
#include <Graphics/GraphicsPipeline.h>
|
||||
|
||||
#include <backends/imgui_impl_win32.h>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace Juliet
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user