Skip to main content

VkSlotRelease

Struct VkSlotRelease 

Source
pub struct VkSlotRelease { /* private fields */ }
Expand description

Consumer→producer slot-release back-pressure carrier.

Pairs a per-slot Arc<AtomicU64> “gate” with a value the consumer is expected to publish into it once the consumer has finished reading from the producer’s slot. Used by ring-pool producers (e.g. an FFmpeg-Vulkan intermediate ring, SDK exporters) to prevent overwriting a slot the consumer’s GPU is still sampling — without this gate, a fast producer (a hardware decoder feeding a high-frame-rate wgpu render loop, say) cycles back to a slot while the consumer’s compute / blit shader is still reading the same VkDeviceMemory through its imported VkImage, triggering a write-after-read hazard that surfaces as a GPU fault (VK_ERROR_DEVICE_LOST on the producer’s next vkQueueSubmit2).

§Protocol

  1. Producer publishes carrier for frame N with slot K. Carrier holds VkSlotRelease { gate: G_prev, value: V_prev } — the PREVIOUS frame’s gate + value, NOT this frame’s.
  2. Consumer’s import path registers a wgpu wgpu::Queue::on_submitted_work_done callback that stores value into gate (release ordering). The callback’s snapshot captures every queued submit up to the registration point — which by usage contract includes the user’s frame N-1 render submission (because the user is expected to submit each frame’s work between consecutive decode→import calls). The callback therefore fires only after the user’s frame N-1 render has retired on the GPU, at which point the slot is no longer being sampled and is safe to reuse.
  3. Producer’s pool, before reusing slot K_prev in frame N+1 (cycle 2 of its ring), CPU-waits for G_prev.load(Acquire) >= V_prev. Steady-state this is a zero-cost atomic load (the callback has already fired); under tail-latency or stalled-consumer conditions the producer yields until the consumer catches up — proper back-pressure rather than blind overwrite.

§Why ARC, not a sender / channel?

Arc<AtomicU64> is the minimal primitive that satisfies the requirement: lock-free store from the wgpu polling thread’s callback + lock-free load from the producer thread’s pre-write check, with release/acquire ordering establishing the necessary happens-before edge. No allocation per frame, no channel-send overhead, no per-frame mutex contention. Clone is one refcount bump.

§Usage contract

This carrier is only meaningful when the user follows the “submit each frame’s render between consecutive decodes” pattern (which is the standard video-playback loop). Batched / out-of-order rendering would register the callback before the relevant render submit, firing the gate too early and re-enabling the race. Producers that publish this carrier therefore assume the standard loop; mis-use would corrupt rendered output but not crash — the QFOT acquire still gates per-Vulkan-spec memory visibility.

§Lifetime

The producer owns the long-lived per-slot Arc<AtomicU64> (one per pool slot, allocated once at pool init). Each per-frame carrier clones that Arc cheaply. The consumer’s on_submitted_work_done closure captures its own Arc clone; once the closure runs (or the queue is torn down with the closure unrun), the closure’s Arc drops and the count returns to producer-only. No cyclic ownership.

Implementations§

Source§

impl VkSlotRelease

Source

pub fn new(gate: Arc<AtomicU64>, value: u64) -> Self

Construct from a producer-owned gate Arc and the value the consumer should publish once its prior-frame render retires.

Source

pub fn gate(&self) -> &Arc<AtomicU64> ⓘ

Borrow the gate Arc (for cloning into a callback closure).

Source

pub fn value(&self) -> u64

The value the consumer must store into Self::gate when its prior-frame render has retired. Producer-side reuse logic CPU-waits for gate.load(Acquire) >= value before overwriting the associated slot.

Source

pub fn release_now(&self)

Convenience helper for consumers that don’t need a delayed on_submitted_work_done registration — stores value into gate with release ordering immediately.

Trait Implementations§

Source§

impl Clone for VkSlotRelease

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for VkSlotRelease

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> MaybeSendSync for T
where T: Send + Sync + ?Sized,

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,