Skip to main content

SyncPoint

Enum SyncPoint 

Source
#[non_exhaustive]
pub enum SyncPoint {
Show 13 variants Vulkan { semaphore: u64, kind: VulkanSemaphoreKind, value: u64, device: *mut c_void, waiter: Arc<dyn SyncWaiter>, }, D3D12 { fence: *mut c_void, value: u64, waiter: Arc<dyn SyncWaiter>, }, D3D11 { keyed_mutex: *mut c_void, key: u64, waiter: Arc<dyn SyncWaiter>, }, Cuda { event: *mut c_void, value: Option<u64>, waiter: Arc<dyn SyncWaiter>, }, CudaEvent { event: *mut c_void, context: *mut c_void, device: i32, waiter: Arc<dyn SyncWaiter>, }, OpenCl { event: *mut c_void, value: Option<u64>, waiter: Arc<dyn SyncWaiter>, }, Metal { event: *mut c_void, value: u64, waiter: Arc<dyn SyncWaiter>, }, OpenGL { semaphore: u32, value: Option<u64>, context: *mut c_void, waiter: Arc<dyn SyncWaiter>, }, OpenGLSync { glsync: *mut c_void, backend: GlBackend, waiter: Arc<dyn SyncWaiter>, }, Wgpu { submission_index: SubmissionIndex, waiter: Arc<dyn SyncWaiter>, }, DeferredWgpu { slot: Arc<DeferredWgpuSlot>, device: Arc<Device>, waiter: Arc<dyn SyncWaiter>, }, Cpu, Noop,
}
Expand description

GPU sync primitive. Produced by every submit-side path; consumed by anything that needs to serialise on a prior GPU submission.

Cross-backend bridges are deliberately absent from this leaf crate — those belong in an interop layer (such as wgpu-interop), where the target-device context is available.

§Lifetime

The per-variant waiter: Arc<dyn SyncWaiter> field anchors the lifetime of any raw primitive the variant exposes (*mut c_void fence pointers, u64 semaphore handles, GLsync opaques, etc.). Cloning a SyncPoint is Arc::clone on the waiter — cheap, no driver round-trip. The raw fields are guaranteed to remain valid for as long as any clone is alive.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Vulkan

Vulkan semaphore. device is the VkDevice the semaphore was created on, exposed for bridges that need to re-import it. The waiter owns an Arc<TimelineSemaphore> (or equivalent) that anchors the VkSemaphore’s lifetime.

kind distinguishes timeline vs binary semaphores — see VulkanSemaphoreKind. value is the timeline payload coordinate when kind == Timeline; for kind == Binary the field is meaningless (set to 0 by convention) and consumers route through wgpu-hal’s binary-wait path (add_wait_semaphore(_, None, _)).

Fields

§semaphore: u64
§value: u64
§waiter: Arc<dyn SyncWaiter>
§

D3D12

D3D12 fence sync. fence is an ID3D12Fence* (COM pointer); value is the monotonic signal value the consumer waits on (fence->GetCompletedValue() >= value). The waiter owns the Arc<ExportFence> (or equivalent) that holds the COM ref.

value is monotonically signaled by the producer. Bridges that reuse a single shared fence across calls serialise the (mint + Signal) pair under a value-lock so concurrent bridges always sequence in monotonic order. A consumer waiting on value=N is guaranteed to pass once a later value=M >= N has been signaled, even if the producer’s counter has since advanced past M.

Fields

§value: u64
§waiter: Arc<dyn SyncWaiter>
§

D3D11

D3D11 keyed-mutex sync. keyed_mutex is an IDXGIKeyedMutex*; key is the integer key the producer released to. The waiter owns the Arc<...> that anchors the COM ref.

Fields

§keyed_mutex: *mut c_void
§key: u64
§waiter: Arc<dyn SyncWaiter>
§

Cuda

CUDA external semaphore. event is a CUexternalSemaphore; value is Some(v) for timeline waits — including the products of Vulkan→CUDA / D3D12→CUDA bridges, which carry the producer’s timeline value so the consumer can enqueue cuWaitExternalSemaphoresAsync on whichever CUDA stream their work runs on. None is reserved for setup-metadata SyncPoints where the consumer mints the actual signal value at emission time and doesn’t need a resolvable wait at construction.

Fields

§value: Option<u64>
§waiter: Arc<dyn SyncWaiter>
§

CudaEvent

Intra-CUDA event. event is a CUevent recorded on the producing stream via cuEventRecord. Consumers wait via cuStreamWaitEvent (chained CUDA streams — cross-context supported per NVIDIA Driver API) or cuEventSynchronize (blocking CPU wait).

Distinct from Self::Cuda — that variant carries a CUexternalSemaphore waited via cuWaitExternalSemaphoresAsync. CUevent and CUexternalSemaphore are different opaque types in the CUDA Driver API; passing a CUevent into the external- semaphore wait path returns CUDA_ERROR_INVALID_HANDLE.

Cross-API consumers cannot wait on a CUevent directly; they need a CUexternalSemaphore (the Self::Cuda shape); an interop layer performs that conversion when the chain spans a backend boundary.

context is the event’s owning CUcontext — bound at cuEventCreate time per the NVIDIA Driver API (“creates an event for the current context”). The owning context must still exist at destroy time or cuEventDestroy_v2 returns CUDA_ERROR_INVALID_CONTEXT. There is no cuEventGetCtx API — the metadata must travel with the event.

device is the CUDA ordinal the owning context was created on (derivable from context via cuCtxGetDevice but cheap to carry and matches the device-keyed bridge shape used by Self::Cuda).

waiter implements CudaEventWaiter — a supertrait of SyncWaiter that adds the CUDA-specific wait_on_foreign_stream extension method and the push-owning- context-before-destroy Drop discipline. The leaf crate stores the upcasted Arc<dyn SyncWaiter> so the generic Self::waiter dispatch path is uniform with every other variant; cross-API bridges that need the CUDA extension methods downcast through SyncWaiter::as_any.

Fields

§context: *mut c_void
§device: i32
§waiter: Arc<dyn SyncWaiter>
§

OpenCl

OpenCL sync. event is either a cl_event (binary, signaled-on-completion; value is None) or a cl_semaphore_khr aliasing a timeline (value is the caller-signaled timeline value). The waiter owns the Arc<...> that holds the producing context’s lifetime.

Fields

§value: Option<u64>
§waiter: Arc<dyn SyncWaiter>
§

Metal

Metal shared event. event is an MTLSharedEvent*; value is the signal value the consumer waits on. The waiter owns the Arc<MTLSharedEvent> keeping the event alive.

Fields

§value: u64
§waiter: Arc<dyn SyncWaiter>
§

OpenGL

OpenGL semaphore (GLuint produced by glGenSemaphoresEXT, imported from a cross-API OS handle via glImportSemaphoreFdEXT / glImportSemaphoreWin32HandleEXT).

value is Some(_) for timeline-equivalent semaphores (D3D12_FENCE_EXT handle types); None for plain binary (OPAQUE_FD / OPAQUE_WIN32) — the GL driver latches the D3D12 fence value at wait/signal time via glSemaphoreParameterui64vEXT(sem, GL_D3D12_FENCE_VALUE_EXT, &v).

context is the caller’s EGLContext / HGLRC / CGLContextObj this semaphore was created against. Waits must be dispatched on a thread where the same context is current.

Fields

§semaphore: u32
§value: Option<u64>
§context: *mut c_void
§waiter: Arc<dyn SyncWaiter>
§

OpenGLSync

GL fence sync. glsync is a GLsync opaque pointer produced by glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0).

Distinct from Self::OpenGL — that one carries an imported GL semaphore (GLuint); this one is the raw GL-native fence.

backend records the GlBackend flavour of the GL context that produced this GLsync. Cross-API consumers (an OpenGL→X bridge) route through it to pick the matching loader (wglGetProcAddress vs eglGetProcAddress) when resolving glClientWaitSync for the CPU-fallback path. Without it the consumer would hard-code Desktop, which silently resolves the wrong proc-address on EGL / ANGLE / Android hosts and stalls forever on a never-signalled handle.

Fields

§backend: GlBackend
§waiter: Arc<dyn SyncWaiter>
§

Wgpu

Available on crate feature wgpu only.

wgpu::Queue::submit return value. Wait dispatches through the waiter, which holds an Arc<wgpu::Device> and calls device.poll(PollType::Wait { submission_index: Some(..), .. }).

Fields

§submission_index: SubmissionIndex
§waiter: Arc<dyn SyncWaiter>
§

DeferredWgpu

Available on crate feature wgpu only.

wgpu::Queue::submit index not yet known at SyncPoint mint time. Used where the caller owns the encoder and submits after the producer has returned; slot.set(idx) is called once after queue.submit(...), and until then the waiter falls back to device.poll(PollType::Wait { submission_index: None, .. }) (full device drain). After commit, waits resolve precisely on the recorded SubmissionIndex.

Fields

§device: Arc<Device>
§waiter: Arc<dyn SyncWaiter>
§

Cpu

CPU-only work — no GPU sync needed. wait returns Ok(()) immediately.

§

Noop

No-op sync — used for pipelines where the consumer side handles ordering through a separate channel (e.g. SurfaceControl transactions). Behaves identically to Cpu for waits.

Implementations§

Source§

impl SyncPoint

Source

pub async fn wait(&self) -> Result<(), Error>

Async wait. Default 10-second timeout.

Async is the default. Use wait_blocking when the caller is on a synchronous code path (sync-loop renderers, test harnesses, JNI dispatcher Drop paths).

Source

pub async fn wait_with_timeout_async( &self, timeout: Duration, ) -> Result<(), Error>

Async wait with explicit timeout.

Source

pub fn wait_blocking(&self) -> Result<(), Error>

Synchronous wait with the default 10-second timeout.

Source

pub fn wait_with_timeout(&self, timeout: Duration) -> Result<(), Error>

Synchronous wait with an explicit timeout.

Timeout granularity is backend-dependent — see SyncWaiter::wait for the per-backend rounding contract. In particular, Metal and Win32 are millisecond-granular and round sub-ms positive timeouts up to 1 ms; Vulkan / D3D12 / CUDA / OpenCL are nanosecond-granular. For sub-ms polls use Self::is_signaled in a loop with your own Instant budget.

Source

pub fn chain(self, then: SyncPoint) -> SyncPoint

Sequence two sync points. Returns a SyncPoint whose wait completes only after both self and then have completed.

Implemented by a small adapter waiter that drives both inner waits in sequence; cheap (one heap alloc for the adapter Arc).

Source§

impl SyncPoint

Source

pub fn from_raw_d3d12_fence(fence: *mut c_void, value: u64) -> SyncPoint

Reconstruct a SyncPoint::D3D12 transport carrier from a raw ID3D12Fence* pointer + signal value that crossed an API / process boundary (e.g. a #[repr(C)] fence descriptor over a C ABI).

fence is an ID3D12Fence* COM pointer the caller guarantees is live for the carrier’s lifetime; value is the monotonic value the consumer waits for (fence->GetCompletedValue() >= value). The returned SyncPoint is a carrier (RawFenceCarrierWaiter) — its raw (fence, value) fields feed a device-side import (e.g. an interop layer’s acquire-sync path); a CPU wait() on it before import returns Error::NotSupported.

Source

pub fn from_raw_vulkan_semaphore( semaphore: u64, kind: VulkanSemaphoreKind, value: u64, device: *mut c_void, ) -> SyncPoint

Reconstruct a SyncPoint::Vulkan transport carrier from a raw VkSemaphore + VkDevice that crossed an API / process boundary.

semaphore is the raw VkSemaphore (a 64-bit non-dispatchable handle); kind distinguishes timeline vs binary (see VulkanSemaphoreKind); value is the timeline coordinate (ignored for Binary); device is the VkDevice* the semaphore lives on (needed by an importer that re-exports it for a cross-device wait). The returned SyncPoint is a carrier — its raw fields feed a device-side import; a CPU wait() before import returns Error::NotSupported.

Source

pub fn from_raw_metal_event(event: *mut c_void, value: u64) -> SyncPoint

Reconstruct a SyncPoint::Metal transport carrier from a raw MTLSharedEvent* + signal value that crossed an API / process boundary.

event is an MTLSharedEvent* the caller guarantees is live for the carrier’s lifetime; value is the value the consumer waits for. The returned SyncPoint is a carrier — its raw (event, value) fields feed a device-side import; a CPU wait() before import returns Error::NotSupported.

Source§

impl SyncPoint

Source

pub fn is_signaled(&self) -> Result<bool, Error>

Non-blocking probe.

  • Ok(true) — sync point reached (or trivial Cpu/Noop).
  • Ok(false) — work still in flight.
  • Err(_) — driver-level failure (device lost / TDR / wrong-submission-index). See SyncWaiter::is_signaled for the rationale on surfacing errors instead of folding them into false.
Source

pub fn backend(&self) -> BackendKind

Backend identity. For the trivial variants (Cpu, Noop) this returns BackendKind::Cpu; otherwise it dispatches to the per-variant waiter.

Source

pub fn waiter(&self) -> Option<&Arc<dyn SyncWaiter>>

Borrow the per-variant waiter, if any. Cpu and Noop return None.

Trait Implementations§

Source§

impl Clone for SyncPoint

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 SyncPoint

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Send for SyncPoint

Source§

impl Sync for SyncPoint

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,