vulkan-utils-0.5.11.0: Utils for the vulkan package
Safe HaskellNone
LanguageHaskell2010

Vulkan.Utils.Frame

Description

Per-frame state and the recycling-Frame loop. Each frame owns a binary image-available semaphore and a command pool — those are RecycledResources that get handed back to a channel in VulkanContext once the frame's GPU work has completed. (The present-wait/render-finished semaphore is per swapchain image, on the Swapchain, because it is only safe to reuse once its image is re-acquired — not when the frame's render finishes.)

The host-side timeline semaphore (fHostTimeline) lives across frames: each frame increments it to its own fIndex on the GPU, and the host waits on it inside the spawned wait-and-recycle thread.

This module requires Vulkan 1.2-level timeline-semaphore support. See frameInstanceRequirements / frameDeviceRequirements for the extension/feature requirements to merge into your boot sequence.

Synopsis

Documentation

data Frame Source #

Constructors

Frame 

Fields

  • fIndex :: Word64

    Monotonic, used as the timeline-semaphore signal value for this frame.

  • fSwapchain :: Swapchain

    The swapchain this frame targets. Held by reference so a frame in flight keeps its swapchain alive across recreation.

  • fRecycled :: RecycledResources

    This frame's image-available semaphore + command pool — borrowed from the recycle channel; returned at retire time.

  • fHostTimeline :: Semaphore

    Long-lived timeline semaphore. Each frame increments it to fIndex on the GPU; the host wait thread blocks on this.

  • fGPUWork :: IORef [(Semaphore, Word64)]

    (Timeline semaphore, value) pairs the host wait thread will block on. Appended to by queueSubmitFrame.

  • fResources :: (ReleaseKey, InternalState)

    ResourceT scope for frame-local allocations; closed when the frame retires. The ReleaseKey lives in the outer ResourceT so the scope is freed cleanly even on early shutdown.

initialFrame :: MonadResource m => VulkanContext -> Swapchain -> m Frame Source #

Build the initial frame with one spare RecycledResources seeded into the recycle channel. That, plus the set attached to this frame, caps max-in-flight at 2 (CPU recording + GPU executing the previous).

advanceFrame Source #

Arguments

:: MonadResource m 
=> VulkanContext 
-> Swapchain

Same as old, or freshly recreated

-> Frame

The just-finished frame

-> m Frame 

Build the next frame, taking one set of recycled resources from the bin. Caller passes the (possibly-recreated) Swapchain.

runFrame :: VulkanContext -> Frame -> ResourceT IO a -> IO a Source #

Run a per-frame action against this frame's per-frame ResourceT scope, then asynchronously wait for the GPU work and recycle. The wait/recycle runs in a forked thread so the next frame can begin recording immediately.

Anything allocated inside action is freed when the frame retires.

recordCommands :: (MonadResource m, MonadFail m) => VulkanContext -> Frame -> (CommandBuffer -> m ()) -> m CommandBuffer Source #

Allocate a primary command buffer from this frame's recycled command pool, begin it with COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, run the caller's recording action, end recording, and return the buffer ready to hand to queueSubmitFrame.

For a non-standard begin shape (secondary level, different usage flags, inheritance info) call withCommandBuffers and useCommandBuffer directly.

queueSubmitFrame Source #

Arguments

:: MonadIO m 
=> VulkanContext 
-> Frame 
-> Word32

Acquired image index (from acquireFrameImage); selects the per-image present-wait semaphore to signal.

-> Vector CommandBuffer 
-> m () 

Submit a per-frame command buffer batch and record the timeline-wait bookkeeping the host wait thread will block on.

Builds the standard frame submit from context/frame: waits on the frame's image-available semaphore at COLOR_ATTACHMENT_OUTPUT, signals the swapchain's per-image render-finished semaphore (at imageIndex) plus its timeline value, and submits on the graphics queue.

For a non-standard submit shape (multiple submit infos, different wait stage, extra signals), call queueSubmit directly and append (fHostTimeline f, fIndex f) to fGPUWork f.

acquireFrameImage :: MonadIO m => VulkanContext -> Frame -> m (Result, Word32) Source #

Acquire the next swapchain image for this frame, signalling the frame's image-available semaphore on completion.

The acquire result is returned alongside the image index so the caller can thread it into presentFrameImage, which honours SUBOPTIMAL_KHR from either side by raising ERROR_OUT_OF_DATE_KHR to drive a swapchain recreation. Timeouts and unexpected results are also translated to ERROR_OUT_OF_DATE_KHR — the main loop's swapchain-recreation path is the right place to recover.

presentFrameImage :: MonadIO m => VulkanContext -> Frame -> Result -> Word32 -> m () Source #

Present this frame's acquired image, waiting on the swapchain's per-image render-finished semaphore (at imageIndex). Presents on the graphics queue (qGraphics . vcQueues).

If either the prior acquire (passed in) or this present reports SUBOPTIMAL_KHR, raises ERROR_OUT_OF_DATE_KHR so the main loop recreates the swapchain.

drainFrames :: VulkanContext -> Frame -> IO () Source #

Shutdown drain: spawn the unrendered current frame's wait/recycle thread, then block on the recycle channel until both this frame's and the previous in-flight frame's deposits have arrived. After this returns, every forked wait thread has run its per-frame cleanup, so the outer ResourceT is safe to tear down GPU resources.

Assumes max-in-flight is 2 (see initialFrame).

allocateTimelineSemaphore :: MonadResource m => Device -> Word64 -> m (ReleaseKey, Semaphore) Source #

Allocate a timeline semaphore initialised to the given value.

frameInstanceRequirements :: [InstanceRequirement] Source #

Instance-level requirements for the recycling Frame machinery. Merge with your application's other InstanceRequirements at instance creation.

Required because checking PhysicalDeviceTimelineSemaphoreFeatures at physical-device pick time goes through VkPhysicalDeviceFeatures2, which needs either Vulkan 1.1+ or this extension.

frameDeviceRequirements :: [DeviceRequirement] Source #

The device-level requirements needed by runFrame queueSubmitFrame allocateTimelineSemaphore. Merge into your other DeviceRequirements when calling allocateDeviceFromRequirements.