fix(device): fence-keyed deferred resource-deletion queue (#101) #102
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Catcrafts/Crafter.Graphics!102
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "claude/issue-101"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Since #40 (per-frame fences, no per-frame
vkQueueWaitIdle) landed, frames are pipelined: a resource the CPU is "done" with may still be read by the GPU for up tonumFrames-1more frames. ButVulkanBuffer::Clear()/Resize()destroyed + freed immediately, makingResize's destroy-and-recreate path a live use-after-free (#63) whenever an in-flight frame still referenced the old buffer.Fix — fence-keyed deferred deletion queue
Devicegains a monotonic, frame-counter-keyed deletion queue:EnqueueDeletion(buffer, memory)tags the handles with the currentframeCounter.ReclaimDeletions()frees entries whereretireAfter + framesInFlight <= frameCounter— called once per frame after the per-image fence wait.DrainDeletions()frees everything unconditionally — called after a wait-idle.VulkanBuffer::DeferredClear()hands{buffer, memory}to the queue and nulls the handle;Resize()uses it instead of immediateClear(), closing #63.Window::RendersetsframesInFlightat init, reclaims after the fence wait, bumpsDevice::frameCounteronce per frame, and drains on the resize /OUT_OF_DATEwait-idle paths.Decisions (per the issue)
~VulkanBufferkeepsClear()) — callers destroying objects mid-flight remain responsible, unchanged from today.vkQueueWaitIdleare synchronous and keep immediateClear().Correctness
An entry tagged at frame F is freed only once
framesInFlightframes have elapsed (each gated by a per-image fence wait); single-queue submission order then guarantees all<=FGPU work is complete.Tests
New
DeferredDeletiontest drives the retire timing on a real headless Vulkan device (realVkBuffer/VkDeviceMemoryso the frees actually execute and the validation layer can object), steppingDevice::frameCounterto pin the exact reclaim frame, and verifyingResizedefers the old allocation,DrainDeletionsfrees regardless of retire frame, and validation stays silent. Full suite: 19 passed (incl.FrameLoopSync).Resolves #101.
🤖 Generated with Claude Code