Reduced Imgui memory usage by implementing a free node list.
This commit is contained in:
@@ -75,32 +75,53 @@ namespace Juliet
|
|||||||
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
||||||
[[nodiscard]] JULIET_API size_t ArenaPos(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)>
|
template <typename Type JULIET_DEBUG_ONLY(, typename... DebugArgs)>
|
||||||
[[nodiscard]] Type* ArenaPushStruct(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(DebugArgs&&... 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(
|
return static_cast<Type*>(
|
||||||
[&]() -> const char* {
|
ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type),
|
||||||
|
true JULIET_DEBUG_PARAM(
|
||||||
|
[&]() -> const char*
|
||||||
|
{
|
||||||
if constexpr (sizeof...(DebugArgs) > 0)
|
if constexpr (sizeof...(DebugArgs) > 0)
|
||||||
{
|
{
|
||||||
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
|
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
|
||||||
}
|
}
|
||||||
return GetTypeName<Type>();
|
return GetTypeName<Type>();
|
||||||
}()
|
}())));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type JULIET_DEBUG_ONLY(, typename... DebugArgs)>
|
template <typename Type JULIET_DEBUG_ONLY(, typename... DebugArgs)>
|
||||||
[[nodiscard]] Type* ArenaPushArray(NonNullPtr<Arena> arena, size_t count JULIET_DEBUG_PARAM(DebugArgs&&... 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(
|
return static_cast<Type*>(
|
||||||
[&]() -> const char* {
|
ArenaPush(arena, sizeof(Type) * count, Max(8ull, AlignOf(Type)),
|
||||||
|
true JULIET_DEBUG_PARAM(
|
||||||
|
[&]() -> const char*
|
||||||
|
{
|
||||||
if constexpr (sizeof...(DebugArgs) > 0)
|
if constexpr (sizeof...(DebugArgs) > 0)
|
||||||
{
|
{
|
||||||
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
|
return Format(GetDebugInfoArena(), std::forward<DebugArgs>(debugArgs)...).Data;
|
||||||
}
|
}
|
||||||
return GetTypeName<Type>();
|
return GetTypeName<Type>();
|
||||||
}()
|
}())));
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);
|
TempArena ArenaTempBegin(NonNullPtr<Arena> arena);
|
||||||
|
|||||||
@@ -22,18 +22,54 @@ namespace Juliet::ImGuiService
|
|||||||
ImGuiContext* g_ImGuiContext = nullptr;
|
ImGuiContext* g_ImGuiContext = nullptr;
|
||||||
bool g_Initialized = false;
|
bool g_Initialized = false;
|
||||||
|
|
||||||
|
struct FreeNode
|
||||||
|
{
|
||||||
|
size_t Size;
|
||||||
|
FreeNode* Next;
|
||||||
|
}* FirstFreeNode = nullptr;
|
||||||
|
|
||||||
// Dedicated Paged Arena for ImGui
|
// Dedicated Paged Arena for ImGui
|
||||||
// Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
|
// Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
|
||||||
Arena* g_ImGuiArena = {};
|
Arena* g_ImGuiArena = {};
|
||||||
|
|
||||||
void* ImGuiAllocWrapper(size_t size, void* /*user_data*/)
|
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 = ¤t->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
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user