Reduced Imgui memory usage by implementing a free node list.

This commit is contained in:
2026-08-01 19:16:02 -04:00
parent 7b21ca6b1d
commit 9f6064995f
2 changed files with 78 additions and 21 deletions
+29 -8
View File
@@ -75,32 +75,53 @@ namespace Juliet
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
[[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr<Arena> arena);
#if JULIET_DEBUG
template <typename FirstDebugArg, typename... DebugArgs>
#endif
[[nodiscard]] inline void* ArenaPushSize(NonNullPtr<Arena> arena, size_t size, size_t align,
bool shouldBeZeroed JULIET_DEBUG_PARAM(FirstDebugArg&& firstDebugArg,
DebugArgs&&... debugArgs))
{
return ArenaPush(arena, size, align,
shouldBeZeroed JULIET_DEBUG_PARAM(
[&]() -> const char*
{
return Format(GetDebugInfoArena(), std::forward<FirstDebugArg>(firstDebugArg),
std::forward<DebugArgs>(debugArgs)...)
.Data;
}()));
}
template <typename Type JULIET_DEBUG_ONLY(, typename... DebugArgs)>
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs))
{
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_PARAM(
[&]() -> const char* {
return static_cast<Type*>(
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type),
true JULIET_DEBUG_PARAM(
[&]() -> const char*
{
if constexpr (sizeof...(DebugArgs) > 0)
{
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
}
return GetTypeName<Type>();
}()
)));
}())));
}
template <typename Type JULIET_DEBUG_ONLY(, typename... DebugArgs)>
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs))
{
return static_cast<Type*>(ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)), true JULIET_DEBUG_PARAM(
[&]() -> const char* {
return static_cast<Type*>(
ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
true JULIET_DEBUG_PARAM(
[&]() -> const char*
{
if constexpr (sizeof...(DebugArgs) > 0)
{
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
}
return GetTypeName<Type>();
}()
)));
}())));
}
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);
+39 -3
View File
@@ -22,18 +22,54 @@ namespace Juliet::ImGuiService
ImGuiContext* g_ImGuiContext = nullptr;
bool g_Initialized = false;
struct FreeNode
{
size_t Size;
FreeNode* Next;
}* FirstFreeNode = nullptr;
// Dedicated Paged Arena for ImGui
// Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
Arena* g_ImGuiArena = {};
void* ImGuiAllocWrapper(size_t size, void* /*user_data*/)
{
return ArenaPush(g_ImGuiArena, size, 8, false JULIET_DEBUG_PARAM("ImGuiAlloc"));
Assert(size); // I trust Dear Imgui but just in case
// Let's make FreeNode a part of each alloc.
size_t sizeOfHeader = sizeof(FreeNode);
size_t totalSize = AlignPow2<size_t>(size + sizeOfHeader, 16);
FreeNode** previous = &FirstFreeNode;
FreeNode* current = FirstFreeNode;
// Find a free node if there is one big enough
while (current != nullptr)
{
if (current->Size >= totalSize)
{
*previous = current->Next;
return current + 1;
}
previous = &current->Next;
current = current->Next;
}
void ImGuiFreeWrapper(void* /*ptr*/, void* /*user_data*/)
auto* ptr = ArenaPushSize(g_ImGuiArena, totalSize, 8, false JULIET_DEBUG_PARAM("ImGuiAlloc {}", totalSize));
FreeNode* node = static_cast<FreeNode*>(ptr);
node->Size = totalSize;
node->Next = nullptr;
return node + 1;
}
void ImGuiFreeWrapper(void* ptr, void* /*user_data*/)
{
// TODO : Free list of imgui elements.
Assert(ptr); // I trust Dear Imgui but just in case
FreeNode* node = reinterpret_cast<FreeNode*>(static_cast<char*>(ptr) - sizeof(FreeNode));
node->Next = FirstFreeNode;
FirstFreeNode = node;
}
} // namespace