From e2e03f39bc3d77f875d5dcdd511ebcdd89f9af11 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Fri, 10 Apr 2026 17:42:30 +0900 Subject: [PATCH] fix: improved HandleManager threading mgmt support --- .../Components/SceneViewportUIComponent.cpp | 10 +- .../Components/SceneViewportUIComponent.h | 3 +- ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp | 6 +- ZEngine/ZEngine/Hardwares/DeviceSwapchain.h | 5 +- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 220 +++++++++--------- ZEngine/ZEngine/Helpers/HandleManager.h | 172 +++++++++----- .../Rendering/Renderers/RenderGraph.cpp | 9 +- ZEngine/tests/Memory/handleManager_test.cpp | 4 +- 8 files changed, 246 insertions(+), 183 deletions(-) diff --git a/Tetragrama/Components/SceneViewportUIComponent.cpp b/Tetragrama/Components/SceneViewportUIComponent.cpp index f7ca4dd4..b56365ee 100644 --- a/Tetragrama/Components/SceneViewportUIComponent.cpp +++ b/Tetragrama/Components/SceneViewportUIComponent.cpp @@ -32,6 +32,8 @@ namespace Tetragrama::Components void SceneViewportUIComponent::Update(ZEngine::Core::TimeStep dt) { + auto app = reinterpret_cast(ParentLayer->CurrentApp); + if ((m_viewport_size.x != m_content_region_available_size.x) || (m_viewport_size.y != m_content_region_available_size.y)) { if (!m_is_resizing) @@ -45,14 +47,13 @@ namespace Tetragrama::Components else if (m_is_resizing) { m_idle_frame_count++; - if (m_idle_frame_count >= m_idle_frame_threshold) + if (m_idle_frame_count >= app->RenderPipeline->Device->SwapchainPtr->IdleFrameThreshold) { m_is_resizing = false; m_request_renderer_resize = true; } } - auto app = reinterpret_cast(ParentLayer->CurrentApp); auto camera_controller = reinterpret_cast(app->CameraController); if (m_request_renderer_resize) @@ -101,7 +102,10 @@ namespace Tetragrama::Components m_refresh_texture_handle = false; } - ImGui::Image((ImTextureID) m_scene_texture.Index, m_viewport_size, ImVec2(0, 1), ImVec2(1, 0)); + if (m_scene_texture.Valid()) + { + ImGui::Image((ImTextureID) m_scene_texture.Index, m_viewport_size, ImVec2(0, 1), ImVec2(1, 0)); + } // ViewPort bound computation ImVec2 viewport_windows_size = ImGui::GetWindowSize(); ImVec2 minimum_bound = ImGui::GetWindowPos(); diff --git a/Tetragrama/Components/SceneViewportUIComponent.h b/Tetragrama/Components/SceneViewportUIComponent.h index 62a52367..e8ed44e0 100644 --- a/Tetragrama/Components/SceneViewportUIComponent.h +++ b/Tetragrama/Components/SceneViewportUIComponent.h @@ -32,8 +32,7 @@ namespace Tetragrama::Components bool m_refresh_texture_handle{false}; bool m_request_renderer_resize{false}; bool m_is_resizing{false}; - int m_idle_frame_count = 0; - int m_idle_frame_threshold = 9; // SwapchainImageCount * 3 + int m_idle_frame_count = 0; ImVec2 m_viewport_size{0.f, 0.f}; ImVec2 m_content_region_available_size{0.f, 0.f}; std::array m_viewport_bounds; diff --git a/ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp b/ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp index 17cc4596..0da715ae 100644 --- a/ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp +++ b/ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp @@ -34,7 +34,7 @@ namespace ZEngine::Hardwares attachment_specification.ColorsMap[0].ReferenceLayout = ImageLayout::COLOR_ATTACHMENT_OPTIMAL; SwapchainAttachment = ZPushStructCtorArgs(&Arena, RenderPasses::Attachment, Device, attachment_specification); - IdleFrameThreshold.store(BufferredFrameCount * 3 * 3 * 3, std::memory_order_release); + IdleFrameThreshold = (BufferredFrameCount * 3 * 3 * 3); FrameContexts.init(&Arena, FrameContextPoolSize, FrameContextPoolSize); for (uint32_t i = 0; i < FrameContextPoolSize; ++i) @@ -268,7 +268,7 @@ namespace ZEngine::Hardwares { if (HasRecreationPending) { - IdleFrameCount.fetch_add(1); + IdleFrameCount.value.fetch_add(1, std::memory_order_acq_rel); Device->CommandBufferMgr->ResetEnqueuedBufferIndex(); return; } @@ -493,7 +493,7 @@ namespace ZEngine::Hardwares }; VkResult present_result = vkQueuePresentKHR(queue.Handle, &present_info); - IdleFrameCount.fetch_add(1); + IdleFrameCount.value.fetch_add(1, std::memory_order_acq_rel); if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) { diff --git a/ZEngine/ZEngine/Hardwares/DeviceSwapchain.h b/ZEngine/ZEngine/Hardwares/DeviceSwapchain.h index 65e4dcca..beeb3b0f 100644 --- a/ZEngine/ZEngine/Hardwares/DeviceSwapchain.h +++ b/ZEngine/ZEngine/Hardwares/DeviceSwapchain.h @@ -36,9 +36,8 @@ namespace ZEngine::Hardwares uint32_t FrameContextOffset = 0; uint32_t FrameContextPoolSize = 0; const uint32_t FrameContextPoolSizeFactor = 4; - // Todo Convert atomic_uint as PaddedAtomic.. - std::atomic_uint IdleFrameCount = 0; - std::atomic_uint IdleFrameThreshold = std::numeric_limits::max(); + uint64_t IdleFrameThreshold = 0; + PaddedAtomic IdleFrameCount = {.value = 0}; uint64_t RenderTimelineNextValue = 0; VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; FrameContextPtr CurrentFrame = nullptr; diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index a0deb584..047107e8 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -848,6 +848,7 @@ namespace ZEngine::Hardwares { auto ds = reinterpret_cast(res_handle.Handle); vkFreeDescriptorSets(LogicalDevice, reinterpret_cast(res_handle.Data1), 1, &ds); + break; } case DeviceResourceType::RESOURCE_COUNT: break; @@ -1204,144 +1205,137 @@ namespace ZEngine::Hardwares } void VulkanDevice::DirtyCollector() - { +{ RunningDirtyCollector.store(true, std::memory_order_release); - + ZENGINE_CORE_INFO("[*] Dirty Resource Collector started...") - + while (RunningDirtyCollector.load(std::memory_order_acquire)) { - uint32_t idle_count = SwapchainPtr->IdleFrameCount.load(std::memory_order_acquire); - uint32_t threshold = SwapchainPtr->IdleFrameThreshold.load(std::memory_order_acquire); - - if (idle_count < threshold) + uint32_t idle_count = SwapchainPtr->IdleFrameCount.value.load(std::memory_order_acquire); + + if (idle_count < SwapchainPtr->IdleFrameThreshold) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; } - - if (DirtyResources.CanRemove()) + + + uint32_t dirty_resource_count = DirtyResources.Size(); + for (uint32_t i = 0; i < dirty_resource_count; ++i) { - uint32_t dirty_resource_count = DirtyResources.Head(); - for (uint32_t i = 0; i < dirty_resource_count; ++i) + auto handle = DirtyResources.ToHandle(i); + + if (!handle) { - auto handle = DirtyResources.ToHandle(i); - - if (!handle) - { - continue; - } - - DirtyResource& res_handle = DirtyResources[handle]; - if (res_handle.FrameIndex == SwapchainPtr->CurrentFrame->Index) + continue; + } + + DirtyResource& res_handle = DirtyResources[handle]; + if (res_handle.FrameIndex == SwapchainPtr->CurrentFrame->Index) + { + switch (res_handle.Type) { - switch (res_handle.Type) + case Rendering::DeviceResourceType::SAMPLER: + // vkDestroySampler(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::FRAMEBUFFER: + vkDestroyFramebuffer(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGEVIEW: + vkDestroyImageView(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGE: + vkDestroyImage(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::RENDERPASS: + vkDestroyRenderPass(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFERMEMORY: + vkFreeMemory(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFER: + vkDestroyBuffer(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE_LAYOUT: + vkDestroyPipelineLayout(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE: + vkDestroyPipeline(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT: + vkDestroyDescriptorSetLayout(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORPOOL: + vkDestroyDescriptorPool(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::SEMAPHORE: + vkDestroySemaphore(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::FENCE: + vkDestroyFence(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSET: { - case Rendering::DeviceResourceType::SAMPLER: - // vkDestroySampler(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::FRAMEBUFFER: - vkDestroyFramebuffer(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::IMAGEVIEW: - vkDestroyImageView(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::IMAGE: - vkDestroyImage(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::RENDERPASS: - vkDestroyRenderPass(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::BUFFERMEMORY: - vkFreeMemory(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::BUFFER: - vkDestroyBuffer(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::PIPELINE_LAYOUT: - vkDestroyPipelineLayout(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::PIPELINE: - vkDestroyPipeline(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT: - vkDestroyDescriptorSetLayout(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORPOOL: - vkDestroyDescriptorPool(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::SEMAPHORE: - vkDestroySemaphore(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::FENCE: - vkDestroyFence(LogicalDevice, reinterpret_cast(res_handle.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORSET: - { - auto ds = reinterpret_cast(res_handle.Handle); - vkFreeDescriptorSets(LogicalDevice, reinterpret_cast(res_handle.Data1), 1, &ds); - break; - } - case DeviceResourceType::RESOURCE_COUNT: - break; + auto ds = reinterpret_cast(res_handle.Handle); + vkFreeDescriptorSets(LogicalDevice, reinterpret_cast(res_handle.Data1), 1, &ds); + break; } - - DirtyResources.Remove(handle); + case DeviceResourceType::RESOURCE_COUNT: + break; } + + DirtyResources.Remove(handle); } } - - if (DirtyBuffers.CanRemove()) + + uint32_t dirty_buffer_count = DirtyBuffers.Size(); + for (uint32_t i = 0; i < dirty_buffer_count; ++i) { - uint32_t dirty_buffer_count = DirtyBuffers.Head(); - for (uint32_t i = 0; i < dirty_buffer_count; ++i) + auto handle = DirtyBuffers.ToHandle(i); + + if (!handle) { - auto handle = DirtyBuffers.ToHandle(i); - - if (!handle) - { - continue; - } - - BufferView& buffer = DirtyBuffers[handle]; - if (buffer && buffer.FrameIndex == SwapchainPtr->CurrentFrame->Index) - { - vmaDestroyBuffer(VmaAllocatorValue, buffer.Handle, buffer.Allocation); - buffer.Handle = VK_NULL_HANDLE; - buffer.Allocation = VK_NULL_HANDLE; - DirtyBuffers.Remove(handle); - } + continue; + } + + BufferView& buffer = DirtyBuffers[handle]; + if (buffer && buffer.FrameIndex == SwapchainPtr->CurrentFrame->Index) + { + vmaDestroyBuffer(VmaAllocatorValue, buffer.Handle, buffer.Allocation); + buffer.Handle = VK_NULL_HANDLE; + buffer.Allocation = VK_NULL_HANDLE; + DirtyBuffers.Remove(handle); } } - - if (DirtyBufferImages.CanRemove()) + + + uint32_t dirty_buffer_image_count = DirtyBufferImages.Size(); + for (uint32_t i = 0; i < dirty_buffer_image_count; ++i) { - uint32_t dirty_buffer_image_count = DirtyBufferImages.Head(); - for (uint32_t i = 0; i < dirty_buffer_image_count; ++i) + auto handle = DirtyBufferImages.ToHandle(i); + + if (!handle) { - auto handle = DirtyBufferImages.ToHandle(i); - - if (!handle) - { - continue; - } - - BufferImage& buffer = DirtyBufferImages[handle]; - - if (buffer && buffer.FrameIndex == SwapchainPtr->CurrentFrame->Index) - { - vkDestroyImageView(LogicalDevice, buffer.ViewHandle, nullptr); - // vkDestroySampler(LogicalDevice, buffer.Sampler, nullptr); - vmaDestroyImage(VmaAllocatorValue, buffer.Handle, buffer.Allocation); - buffer.Handle = VK_NULL_HANDLE; - buffer.Allocation = VK_NULL_HANDLE; - DirtyBufferImages.Remove(handle); - } + continue; + } + + BufferImage& buffer = DirtyBufferImages[handle]; + + if (buffer && buffer.FrameIndex == SwapchainPtr->CurrentFrame->Index) + { + vkDestroyImageView(LogicalDevice, buffer.ViewHandle, nullptr); + // vkDestroySampler(LogicalDevice, buffer.Sampler, nullptr); + vmaDestroyImage(VmaAllocatorValue, buffer.Handle, buffer.Allocation); + buffer.Handle = VK_NULL_HANDLE; + buffer.Allocation = VK_NULL_HANDLE; + DirtyBufferImages.Remove(handle); } } - SwapchainPtr->IdleFrameCount.store(0, std::memory_order_release); + + SwapchainPtr->IdleFrameCount.value.store(0, std::memory_order_release); } - + ZENGINE_CORE_INFO("[*] Dirty Resource Collector stopped...") } diff --git a/ZEngine/ZEngine/Helpers/HandleManager.h b/ZEngine/ZEngine/Helpers/HandleManager.h index d0da0c75..55afb508 100644 --- a/ZEngine/ZEngine/Helpers/HandleManager.h +++ b/ZEngine/ZEngine/Helpers/HandleManager.h @@ -3,7 +3,6 @@ #include #include #include -#include #define INVALID_HANDLE_INDEX -1 @@ -18,7 +17,8 @@ namespace ZEngine::Helpers template struct Handle { - uint64_t Index = UINT64_MAX; + uint64_t Index = UINT64_MAX; + uint64_t Generation = 0u; bool Valid() const { @@ -27,64 +27,90 @@ namespace ZEngine::Helpers operator bool() const { - return this->Valid(); + return Valid(); } }; template class HandleManager { - uint32_t m_count = 0; - uint32_t m_head = 0; - uint32_t m_free_slot_index = 0; - Core::Containers::Array m_memory = {}; - Core::Containers::Array m_free_slot = {}; - - mutable std::shared_mutex m_mutex; + union FreeHead + { + struct + { + uint32_t index; + uint32_t tag; + }; + uint64_t raw; + }; + static_assert(sizeof(FreeHead) == 8, "FreeHead must be 8 bytes"); + + uint32_t m_count = 0; + PaddedAtomic m_head = {.value = 0}; + PaddedAtomic m_live_count = {.value = 0}; + PaddedAtomic m_free_head = {}; // FreeHead packed + + Core::Containers::Array m_memory = {}; + Core::Containers::Array m_next = {}; // free-list next pointers + Core::Containers::Array> m_generations = {}; public: void Initialize(Core::Memory::ArenaAllocator* arena, uint32_t count = 0) { + m_count = count; m_memory.init(arena, count, count); - m_free_slot.init(arena, count, count); - m_count = count; - m_head = 0; - m_free_slot_index = 0; + m_next.init(arena, count, count); + m_generations.init(arena, count, count); + + for (uint32_t i = 0; i < count; ++i) + { + m_generations[i].value.store(0, std::memory_order_relaxed); + } + + FreeHead empty{UINT32_MAX, 0}; + m_free_head.value.store(empty.raw, std::memory_order_relaxed); + m_head.value.store(0, std::memory_order_relaxed); + m_live_count.value.store(0, std::memory_order_relaxed); } T& operator[](const Handle& handle) { - return *Access(handle); + ZENGINE_VALIDATE_ASSERT(IsLive(handle), "Trying to access an invalid handle") + return *(&m_memory[handle.Index]); } Handle Create() { - std::unique_lock lock(m_mutex); - Handle handle = {}; - - if (m_free_slot_index > 0 && m_free_slot_index >= m_head) - { - m_head = 0; - m_free_slot_index = 0; - } + Handle handle = {}; + uint64_t index = TryPopFree(); - if (m_free_slot_index > 0) + if (index == UINT64_MAX) { - handle.Index = m_free_slot[--m_free_slot_index]; + index = m_head.value.fetch_add(1, std::memory_order_acq_rel); + if (index >= m_count) + { + m_head.value.fetch_sub(1, std::memory_order_acq_rel); + return {}; + } } - else if (m_head < m_count) + else { - handle.Index = m_head++; + uint64_t gen = m_generations[index].value.load(std::memory_order_acquire); + ZENGINE_VALIDATE_ASSERT((gen & 1) == 1, "Popped a slot that wasn't freed") + + m_generations[index].value.store(gen + 1, std::memory_order_release); } + + handle.Index = index; + handle.Generation = m_generations[index].value.load(std::memory_order_acquire); + m_live_count.value.fetch_add(1, std::memory_order_acq_rel); return handle; } T* Access(const Handle& handle) { - std::shared_lock lock(m_mutex); - T* ptr = nullptr; - - if (handle && (handle.Index < m_count)) + T* ptr = nullptr; + if (IsLive(handle)) { ptr = &m_memory[handle.Index]; } @@ -117,15 +143,16 @@ namespace ZEngine::Helpers return handle; } - Handle ToHandle(uint32_t index) + Handle ToHandle(uint64_t index) { - std::shared_lock lock(m_mutex); - Handle handle{}; - ZENGINE_VALIDATE_ASSERT(index != UINT32_MAX && index < m_count, "Handle Index is invalid") + Handle handle{}; + ZENGINE_VALIDATE_ASSERT(index != UINT64_MAX && index < m_count, "Handle Index is invalid") - if (!(index >= m_head)) + uint64_t gen = m_generations[index].value.load(std::memory_order_acquire); + if ((gen & 1) == 0 && index < m_head.value.load(std::memory_order_acquire)) { - handle.Index = index; + handle.Index = index; + handle.Generation = gen; } return handle; @@ -133,8 +160,7 @@ namespace ZEngine::Helpers void Update(Handle& handle, T& data) { - std::unique_lock lock(m_mutex); - ZENGINE_VALIDATE_ASSERT((handle) && handle.Index < m_count, "Handle Index is invalid") + ZENGINE_VALIDATE_ASSERT(IsLive(handle), "Handle Index is invalid") T* ptr = &m_memory[handle.Index]; *ptr = data; @@ -142,45 +168,81 @@ namespace ZEngine::Helpers void Update(Handle& handle, T&& data) { - std::unique_lock lock(m_mutex); - ZENGINE_VALIDATE_ASSERT((handle) && handle.Index < m_count, "Handle Index is invalid") + ZENGINE_VALIDATE_ASSERT(IsLive(handle), "Handle Index is invalid") T* ptr = &m_memory[handle.Index]; *ptr = std::move(data); } - bool CanRemove() + bool IsLive(const Handle& handle) const { - return !(m_free_slot_index >= m_head); + if (!handle || handle.Index >= m_count) + { + return false; + } + + uint64_t gen = m_generations[handle.Index].value.load(std::memory_order_acquire); + return (gen & 1) == 0 && gen == handle.Generation; } void Remove(Handle& handle) { - std::unique_lock lock(m_mutex); - if (!handle || !(handle.Index < m_count)) + if (!IsLive(handle)) { return; } - if (!CanRemove()) - { - return; - } + uint64_t gen = m_generations[handle.Index].value.load(std::memory_order_acquire); + ZENGINE_VALIDATE_ASSERT((gen & 1) == 0, "Trying to remove a handle that is already freed") + m_generations[handle.Index].value.store(gen + 1, std::memory_order_release); - m_free_slot[m_free_slot_index++] = handle.Index; - handle = Handle{}; + PushFree(handle.Index); + m_live_count.value.fetch_sub(1, std::memory_order_acq_rel); + handle = Handle{}; } size_t Size() const { - std::shared_lock lock(m_mutex); - return m_count; + return m_live_count.value.load(std::memory_order_acquire); } uint32_t Head() const { - std::shared_lock lock(m_mutex); - return m_head; + return m_head.value.load(std::memory_order_acquire); + } + + uint32_t Capacity() const + { + return m_count; + } + + void PushFree(uint64_t index) + { + FreeHead expected, desired; + expected.raw = m_free_head.value.load(std::memory_order_acquire); + do + { + m_next[index] = expected.index; + desired.index = static_cast(index); + desired.tag = expected.tag + 1; + } while (!m_free_head.value.compare_exchange_weak(expected.raw, desired.raw, std::memory_order_release, std::memory_order_relaxed)); + } + + uint64_t TryPopFree() + { + FreeHead expected, desired; + expected.raw = m_free_head.value.load(std::memory_order_acquire); + do + { + if (expected.index == UINT32_MAX) + { + return UINT64_MAX; // No free slots + } + desired.index = m_next[expected.index]; + desired.tag = expected.tag + 1; + } while (!m_free_head.value.compare_exchange_weak(expected.raw, desired.raw, std::memory_order_acquire, std::memory_order_relaxed)); + + return expected.index; } void Dispose() {} diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp index 8b10ed64..de18bfdb 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp @@ -335,8 +335,13 @@ namespace ZEngine::Rendering::Renderers node.Handle->UpdateRenderTargets(); node.Handle->UpdateInputBinding(); - Specifications::FrameBufferSpecificationVNext framebuffer_spec = {.Width = node.Handle->RenderAreaWidth, .Height = node.Handle->RenderAreaHeight, .RenderTargets = node.Handle->RenderTargets, .Attachment = node.Handle->Attachment}; - node.Framebuffer = ZPushStructCtorArgs(Device->Arena, Buffers::FramebufferVNext, Device, framebuffer_spec); + Specifications::FrameBufferSpecificationVNext framebuffer_spec = { + .Width = node.Handle->RenderAreaWidth, + .Height = node.Handle->RenderAreaHeight, + .RenderTargets = node.Handle->RenderTargets, + .Attachment = node.Handle->Attachment, + }; + node.Framebuffer = ZPushStructCtorArgs(Device->Arena, Buffers::FramebufferVNext, Device, framebuffer_spec); } } diff --git a/ZEngine/tests/Memory/handleManager_test.cpp b/ZEngine/tests/Memory/handleManager_test.cpp index 6508127f..91666d4d 100644 --- a/ZEngine/tests/Memory/handleManager_test.cpp +++ b/ZEngine/tests/Memory/handleManager_test.cpp @@ -81,9 +81,9 @@ TEST_F(HandleManagerTest, RemoveHandle) TEST_F(HandleManagerTest, FullCapacity) { std::vector> handles; - std::vector values(handle_manager.Size()); + std::vector values(handle_manager.Capacity()); - for (size_t i = 0; i < handle_manager.Size(); ++i) + for (size_t i = 0; i < handle_manager.Capacity(); ++i) { values[i] = static_cast(i); auto handle = handle_manager.Add(&values[i]);