diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index e67a9d6..2f97176 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -75,32 +75,53 @@ namespace Juliet JULIET_API void ArenaClear(NonNullPtr arena); [[nodiscard]] JULIET_API size_t ArenaPos(NonNullPtr arena); +#if JULIET_DEBUG + template +#endif + [[nodiscard]] inline void* ArenaPushSize(NonNullPtr 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), + std::forward(debugArgs)...) + .Data; + }())); + } + template [[nodiscard]] Type* ArenaPushStruct(NonNullPtr arena JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) { - return static_cast(ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), true JULIET_DEBUG_PARAM( - [&]() -> const char* { - if constexpr (sizeof...(DebugArgs) > 0) - { - return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Data; - } - return GetTypeName(); - }() - ))); + return static_cast( + ArenaPush(arena, sizeof(Type) * 1, AlignOf(Type), + true JULIET_DEBUG_PARAM( + [&]() -> const char* + { + if constexpr (sizeof...(DebugArgs) > 0) + { + return Format(GetDebugInfoArena(), std::forward(debugArgs)...).Data; + } + return GetTypeName(); + }()))); } template [[nodiscard]] Type* ArenaPushArray(NonNullPtr arena, size_t count JULIET_DEBUG_PARAM(DebugArgs&&... debugArgs)) { - return static_cast(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)...).Data; - } - return GetTypeName(); - }() - ))); + return static_cast( + 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)...).Data; + } + return GetTypeName(); + }()))); } TempArena ArenaTempBegin(NonNullPtr arena); diff --git a/Juliet/src/Core/ImGui/ImGuiService.cpp b/Juliet/src/Core/ImGui/ImGuiService.cpp index bfd50e0..66b2995 100644 --- a/Juliet/src/Core/ImGui/ImGuiService.cpp +++ b/Juliet/src/Core/ImGui/ImGuiService.cpp @@ -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 + 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; + } + + auto* ptr = ArenaPushSize(g_ImGuiArena, totalSize, 8, false JULIET_DEBUG_PARAM("ImGuiAlloc {}", totalSize)); + + FreeNode* node = static_cast(ptr); + node->Size = totalSize; + node->Next = nullptr; + + return node + 1; } - void ImGuiFreeWrapper(void* /*ptr*/, void* /*user_data*/) + 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(static_cast(ptr) - sizeof(FreeNode)); + node->Next = FirstFreeNode; + FirstFreeNode = node; } } // namespace