Establish the ownership graph#
VulkanDevice owns VkDevice, selected queues, memory metadata, descriptor infrastructure, and command pools. VulkanSwapchain owns the surface-facing images and their views. Each FrameContext owns command buffers, host-visible per-frame allocations, an acquire semaphore, and a submission completion fence or timeline value. A command pool belongs to a queue family and must not be concurrently accessed without the required external synchronization. Worker recording uses separate pools or a carefully synchronized ownership policy. Reusing a command buffer or pool requires completion of its submitted uses.
Swap-chain configuration and recreation#
Query surface capabilities, formats, and present modes. Choose an allowed extent and image count, respecting min/max limits and usage support. The surface can have a fixed extent or permit an application-chosen extent. Select an sRGB-compatible display format according to the engine’s color pipeline. If graphics and presentation use different families, choose a supported sharing strategy. Concurrent sharing is simpler; exclusive sharing needs ownership transfers. Out-of-date or suboptimal results lead to a controlled recreation policy. Wait for relevant work before destroying old views and resources; handle minimized zero dimensions without repeatedly recreating.
Bind descriptors and create a pipeline#
A descriptor set layout specifies bindings, types, counts, and shader visibility. A pipeline layout combines set layouts and push-constant ranges. Descriptor pools allocate the sets. Updating a set already referenced by in-flight work is unsafe unless the exact supported update policy permits it. The baseline Vulkan variant binds sampled image, sampler, and frame buffer separately at explicit set/binding locations. Dynamic rendering removes the need for a traditional render-pass object in this profile, but the graphics pipeline still declares compatible attachment formats and all relevant shader and fixed-function state. Vertex layout, viewport/scissor, triangle topology, rasterization, blending, and depth state serve the same purposes as the DX12 path. Their objects and validation rules are different. Matching shader intent is not the same as using identical native pipeline descriptors.
One frame, carefully ordered#
- Wait for the selected frame slot’s last submission to complete.
- Acquire a swap-chain image. If acquisition is out of date, recreate before resetting a fence that will not be signaled.
- Reset safe command storage and begin recording.
- Transition the acquired image to the chosen color-attachment usage, begin rendering, bind pipeline and descriptors, and draw.
- End rendering, transition to PRESENT_SRC_KHR, and submit with the acquire semaphore wait and a render-finished signal.
- Present the acquired image waiting on its render-finished binary semaphore.
CPU and GPU, in parallel This illustration uses canvas. The explanation below describes the same process.
Semaphore reuse is an image-lifetime problem too#
Acquire semaphores can be owned by frame slots whose submissions consume them before reuse. Render-finished semaphores need proof that presentation has consumed their waits. A straightforward policy assigns one render-finished semaphore to each swap-chain image and reuses it after reacquiring that image under the required synchronization. A graphics submission fence alone does not prove the presentation engine has finished waiting on a binary semaphore. Swap-chain recreation has its own safe teardown requirements. This subtle distinction matters even when a two-frame CPU/GPU schedule looks correct.
Camera and shader conventions#
Vulkan depth after projection uses the zero-to-one range like the chosen DX12 convention. Y orientation and framebuffer conventions still need an explicit policy, such as a supported negative-height viewport or an adjusted projection. Set winding/front-face consistently with that policy. Avoid fixing a flipped image by changing unrelated matrix multiplication order.
Investigate failures#
A validation message about command-buffer reuse points to pool/submission completion. A semaphore validation error points to a wait/signal lifecycle, often presentation reuse. A blank frame can have valid submission but wrong image layout, descriptor bindings, attachment format, or viewport. Native Vulkan execution is not verified here. Use the platform’s validation layers and official swap-chain semaphore reuse guidance when implementing the secondary backend, then read resources and synchronization.