Skip to content

Commit c61f469

Browse files
Merge branch 'user/kernel/fix-command-buffer-manager' of https://github.com/JeanPhilippeKernel/RendererEngine into user/kernel/fix-command-buffer-manager
2 parents 61910cb + a045774 commit c61f469

3 files changed

Lines changed: 72 additions & 72 deletions

File tree

ZEngine/ZEngine/Hardwares/DeviceSwapchain.cpp

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ namespace ZEngine::Hardwares
1818

1919
Device = device;
2020

21+
BufferredFrameCount = buffered_frame_size;
22+
FrameContextPoolSize = BufferredFrameCount * FrameContextPoolSizeFactor;
23+
2124
Specifications::AttachmentSpecification attachment_specification = {.BindPoint = Specifications::PipelineBindPoint::GRAPHIC};
2225
attachment_specification.ColorsMap.init(&Arena, 2);
2326
attachment_specification.ColorsMap[0] = {};
@@ -28,15 +31,15 @@ namespace ZEngine::Hardwares
2831
attachment_specification.ColorsMap[0].Final = ImageLayout::PRESENT_SRC;
2932
attachment_specification.ColorsMap[0].ReferenceLayout = ImageLayout::COLOR_ATTACHMENT_OPTIMAL;
3033
SwapchainAttachment = ZPushStructCtorArgs(&Arena, RenderPasses::Attachment, Device, attachment_specification);
31-
BufferredFrameCount = buffered_frame_size;
32-
IdleFrameThreshold.store(BufferredFrameCount * 3 * 3, std::memory_order_release);
33-
FrameContexts.init(&Arena, BufferredFrameCount, BufferredFrameCount);
3434

35-
for (uint32_t i = 0; i < BufferredFrameCount; ++i)
35+
IdleFrameThreshold.store(BufferredFrameCount * 3 * 3 * 3, std::memory_order_release);
36+
FrameContexts.init(&Arena, FrameContextPoolSize, FrameContextPoolSize);
37+
38+
for (uint32_t i = 0; i < FrameContextPoolSize; ++i)
3639
{
3740
auto& frame = FrameContexts[i];
3841

39-
frame.Index = i;
42+
frame.Index = (i % BufferredFrameCount);
4043
frame.Acquired = ZPushStructCtorArgs(&Arena, Primitives::Semaphore, Device);
4144
frame.Fence = ZPushStructCtorArgs(&Arena, Primitives::Fence, Device, true);
4245
}
@@ -107,24 +110,33 @@ namespace ZEngine::Hardwares
107110
{
108111
SwapchainFramebuffers.init(&Arena, SwapchainImageCount, SwapchainImageCount);
109112
}
110-
}
111113

112-
void DeviceSwapchain::Clear()
113-
{
114-
for (VkImageView image_view : SwapchainImageViews)
114+
scratch = ZGetScratch(&Arena);
115+
116+
Array<VkImage> swapchain_images = {};
117+
swapchain_images.init(scratch.Arena, SwapchainImageCount, SwapchainImageCount);
118+
ZENGINE_VALIDATE_ASSERT(vkGetSwapchainImagesKHR(Device->LogicalDevice, SwapchainHandle, &SwapchainImageCount, swapchain_images.data()) == VK_SUCCESS, "Failed to get VkImages from Swapchain")
119+
for (int i = 0; i < SwapchainImageCount; ++i)
115120
{
116-
if (image_view)
117-
{
118-
Device->EnqueueForDeletion(DeviceResourceType::IMAGEVIEW, image_view);
119-
}
121+
SwapchainImageViews[i] = Device->CreateImageView(swapchain_images[i], Device->SurfaceFormat.format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
122+
123+
Array<VkImageView> fb_images_views;
124+
fb_images_views.init(scratch.Arena, 1);
125+
fb_images_views.push(SwapchainImageViews[i]);
126+
SwapchainFramebuffers[i] = Device->CreateFramebuffer(ArrayView{fb_images_views}, SwapchainAttachment->GetHandle(), SwapchainImageWidth, SwapchainImageHeight);
120127
}
121128

122-
for (VkFramebuffer framebuffer : SwapchainFramebuffers)
129+
ZReleaseScratch(scratch);
130+
}
131+
132+
void DeviceSwapchain::Clear()
133+
{
134+
for (uint32_t i = 0; i < SwapchainImageCount; ++i)
123135
{
124-
if (framebuffer)
125-
{
126-
Device->EnqueueForDeletion(DeviceResourceType::FRAMEBUFFER, framebuffer);
127-
}
136+
Device->EnqueueForDeletion(DeviceResourceType::IMAGEVIEW, SwapchainImageViews[i]);
137+
Device->EnqueueForDeletion(DeviceResourceType::FRAMEBUFFER, SwapchainFramebuffers[i]);
138+
SwapchainImageViews[i] = VK_NULL_HANDLE;
139+
SwapchainFramebuffers[i] = VK_NULL_HANDLE;
128140
}
129141

130142
for (uint32_t i = 0; i < SwapchainImageCount; ++i)
@@ -147,6 +159,17 @@ namespace ZEngine::Hardwares
147159
{
148160
if (HasRecreationPending)
149161
{
162+
/*
163+
* On macOS:
164+
* Because of ASYNCHRONOUS communication between MoltenVK and Metal:
165+
* 1. vkDeviceWaitIdle() only guarantees Vulkan sees GPU idle
166+
* 2. Metal's CAMetalLayer may still have pending present operations
167+
* 3. Semaphores can appear "stuck" in Submitted state due to Metal async completion
168+
*
169+
* Pool of BufferredFrameCount * 4 = 12 contexts rotates every resize.
170+
* Skipping 3 ensures we land on fully Idle semaphores/fences even under Metal async.
171+
*
172+
*/
150173
#ifdef __APPLE__
151174
vkDeviceWaitIdle(Device->LogicalDevice);
152175
#endif
@@ -157,26 +180,23 @@ namespace ZEngine::Hardwares
157180
ImageInFlights[i]->Wait(UINT64_MAX);
158181
}
159182
}
160-
Clear();
161-
Create();
162-
AsPresentSource();
163183

164-
for (auto& frame : FrameContexts)
184+
for (int i = 0; i < FrameContextPoolSizeFactor; ++i)
165185
{
166-
*(frame.Fence) = Rendering::Primitives::Fence(Device, true);
186+
FrameContext& frame = FrameContexts[i + FrameContextOffset];
167187
frame.Acquired->SetState(Primitives::SemaphoreState::Idle);
168188
}
169189

190+
FrameContextOffset = (FrameContextOffset + FrameContextPoolSizeFactor) % FrameContextPoolSize;
191+
Clear();
192+
Create();
193+
170194
HasRecreationPending = false;
171195
ZENGINE_CORE_WARN("Swapchain has been re-created")
172196
}
173197

174-
FrameContext& frame = FrameContexts[frame_context_idx];
198+
FrameContext& frame = FrameContexts[frame_context_idx + FrameContextOffset];
175199

176-
if (!(frame.Fence)->IsSignaled())
177-
{
178-
frame.Fence->Wait(UINT64_MAX);
179-
}
180200
frame.Fence->Reset();
181201

182202
ZENGINE_VALIDATE_ASSERT(frame.Acquired->GetState() != Primitives::SemaphoreState::Submitted, "")
@@ -207,43 +227,25 @@ namespace ZEngine::Hardwares
207227

208228
void DeviceSwapchain::AsPresentSource()
209229
{
210-
auto command_buffer_info = Device->CommandBufferMgr->GetInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE, (CurrentFrame == nullptr) ? 0u : CurrentFrame->Index, 0, 2, true);
211-
212-
auto scratch = ZGetScratch(&Arena);
213-
214-
Array<VkImage> SwapchainImages = {};
215-
SwapchainImages.init(scratch.Arena, SwapchainImageCount, SwapchainImageCount);
216-
ZENGINE_VALIDATE_ASSERT(vkGetSwapchainImagesKHR(Device->LogicalDevice, SwapchainHandle, &SwapchainImageCount, SwapchainImages.data()) == VK_SUCCESS, "Failed to get VkImages from Swapchain")
217-
218-
for (int i = 0; i < SwapchainImages.size(); ++i)
219-
{
220-
Rendering::Specifications::ImageMemoryBarrierSpecification barrier_spec = {};
221-
barrier_spec.ImageHandle = SwapchainImages[i];
222-
barrier_spec.OldLayout = Specifications::ImageLayout::UNDEFINED;
223-
barrier_spec.NewLayout = Specifications::ImageLayout::PRESENT_SRC;
224-
barrier_spec.ImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
225-
barrier_spec.SourceAccessMask = 0;
226-
barrier_spec.DestinationAccessMask = VK_ACCESS_MEMORY_READ_BIT;
227-
barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
228-
barrier_spec.DestinationStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
229-
barrier_spec.LayerCount = 1;
230-
231-
Rendering::Primitives::ImageMemoryBarrier barrier{barrier_spec};
232-
command_buffer_info.Buffer->TransitionImageLayout(barrier);
233-
}
234-
Device->CommandBufferMgr->EndInstantCommandBuffer(command_buffer_info);
235-
236-
for (int i = 0; i < SwapchainImageCount; ++i)
237-
{
238-
SwapchainImageViews[i] = Device->CreateImageView(SwapchainImages[i], Device->SurfaceFormat.format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
239-
240-
Array<VkImageView> fb_images_views;
241-
fb_images_views.init(scratch.Arena, 1);
242-
fb_images_views.push(SwapchainImageViews[i]);
243-
SwapchainFramebuffers[i] = Device->CreateFramebuffer(ArrayView{fb_images_views}, SwapchainAttachment->GetHandle(), SwapchainImageWidth, SwapchainImageHeight);
244-
}
245-
246-
ZReleaseScratch(scratch);
230+
// auto command_buffer_info = Device->CommandBufferMgr->GetInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE, (CurrentFrame == nullptr) ? 0u : CurrentFrame->Index, 0, 2, true);
231+
232+
// for (int i = 0; i < SwapchainImages.size(); ++i)
233+
// {
234+
// Rendering::Specifications::ImageMemoryBarrierSpecification barrier_spec = {};
235+
// barrier_spec.ImageHandle = SwapchainImages[i];
236+
// barrier_spec.OldLayout = Specifications::ImageLayout::UNDEFINED;
237+
// barrier_spec.NewLayout = Specifications::ImageLayout::PRESENT_SRC;
238+
// barrier_spec.ImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
239+
// barrier_spec.SourceAccessMask = 0;
240+
// barrier_spec.DestinationAccessMask = VK_ACCESS_MEMORY_READ_BIT;
241+
// barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
242+
// barrier_spec.DestinationStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
243+
// barrier_spec.LayerCount = 1;
244+
245+
// Rendering::Primitives::ImageMemoryBarrier barrier{barrier_spec};
246+
// command_buffer_info.Buffer->TransitionImageLayout(barrier);
247+
// }
248+
// Device->CommandBufferMgr->EndInstantCommandBuffer(command_buffer_info);
247249
}
248250

249251
void DeviceSwapchain::Present()
@@ -336,6 +338,8 @@ namespace ZEngine::Hardwares
336338

337339
CurrentFrame->Acquired->SetState(Rendering::Primitives::SemaphoreState::Idle);
338340

341+
IdleFrameCount.fetch_add(1);
342+
339343
if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR)
340344
{
341345
HasRecreationPending = true;
@@ -346,7 +350,5 @@ namespace ZEngine::Hardwares
346350
}
347351

348352
ZENGINE_VALIDATE_ASSERT(present_result == VK_SUCCESS || present_result == VK_SUBOPTIMAL_KHR, "Failed to present current frame on Window")
349-
350-
IdleFrameCount.fetch_add(1);
351353
}
352354
} // namespace ZEngine::Hardwares

ZEngine/ZEngine/Hardwares/DeviceSwapchain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ namespace ZEngine::Hardwares
3434

3535
uint32_t SwapchainImageWidth = std::numeric_limits<uint32_t>::max();
3636
uint32_t SwapchainImageHeight = std::numeric_limits<uint32_t>::max();
37+
uint32_t FrameContextOffset = 0;
38+
uint32_t FrameContextPoolSize = 0;
39+
const uint32_t FrameContextPoolSizeFactor = 4;
3740
// Todo Convert atomic_uint as PaddedAtomic..
3841
std::atomic_uint IdleFrameCount = 0;
3942
std::atomic_uint IdleFrameThreshold = std::numeric_limits<uint32_t>::max();

ZEngine/ZEngine/Hardwares/VulkanDevice.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,6 @@ namespace ZEngine::Hardwares
416416
*/
417417
CommandBufferMgr->Initialize(this, SwapchainPtr->BufferredFrameCount);
418418

419-
/*
420-
* Transition image layout as Present src
421-
*/
422-
SwapchainPtr->AsPresentSource();
423-
424419
/*
425420
* Creating Global Descriptor Pool for : Textures
426421
*/

0 commit comments

Comments
 (0)