Skip to main content

PipelineCache

Struct PipelineCache 

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

The engine’s render-pipeline cache.

Owns nothing but policy plus the compiled pipelines: the wgpu::Device is passed per call, and the shader modules come from the shared ShaderLibrary handed to PipelineCache::new.

See the module docs for the variant key, the warm-up queue and the eager-steal rule.

Implementations§

Source§

impl PipelineCache

Source

pub fn new( shaders: Arc<ShaderLibrary>, driver_cache: Option<PipelineCache>, ) -> Self

A cache over shaders, optionally seeding every pipeline it builds from a persisted driver_cache.

driver_cache is None on every backend but Vulkan; see crate::pipeline_cache for how a persisted blob is validated before it becomes one.

Source

pub fn shaders(&self) -> &ShaderLibrary

The library this cache resolves ShaderIds against.

Source

pub fn get_or_create( &mut self, device: &Device, desc: &RenderPipelineDesc, ) -> &RenderPipeline

The pipeline for desc, compiling it if this is the first request.

A variant queued for the warm-up worker but not yet started is stolen and built inline; one the worker is already building is waited for. Either way the variant is compiled exactly once.

§Panics

If desc.shader was not minted by this cache’s ShaderLibrary. An id is opaque and library-scoped, so that is a wiring bug, not a runtime condition.

Source

pub fn warm_up(&mut self, device: &Device, descs: &[RenderPipelineDesc])

Queues descs and builds them on a worker thread.

Call it once the surface (and therefore the device) exists, with every variant the app is known to draw. Returns immediately, and the render thread never blocks on the worker — a variant it asks for early is stolen out of the queue instead.

Safe to call repeatedly: a surface reinstall enqueues its variants against the live worker rather than starting a second one, and a call whose variants are all built already starts nothing at all.

If the thread cannot be spawned the queue is drained inline instead, so warm-up degrades to a synchronous build rather than silently not happening.

The worker creates each program’s shader module as its first variant over that program reaches it, unless Self::warm_up_shaders or an earlier request already has.

Source

pub fn warm_up_shaders(&mut self, device: &Device, ids: &[ShaderId])

Starts creating the shader modules ids name on a small pool of short-lived threads and returns at once.

Call it at install, before Self::warm_up, with the modules the first frame draws with: the pool creates them side by side while the render thread finishes its install, and the worker’s or the render thread’s first build over one of them then finds the module built, or waits for the pool thread creating it — never creating it twice. A module already created, an id listed twice, and an id this cache’s library did not mint are skipped; everything else stays created on first use.

One thread per module, at most one fewer than the machine’s available parallelism (and at least one), so the calling thread keeps a core. The threads exit when the list is done; Self::shutdown (and drop) joins them. If a thread cannot be spawned the modules it would have created are left to their first use rather than created inline — the call must not put module creation back in front of the caller. After Self::shutdown it starts nothing.

Source

pub fn shutdown(&mut self)

Stops warm-up and joins the worker and any Self::warm_up_shaders thread, so no thread holding a clone of the device outlives this cache.

Drop calls this; call it explicitly to order the wait before other teardown of your own. It is idempotent, and terminal — afterwards Self::warm_up records its variants without starting a worker, and they are compiled on first request.

Source

pub fn compiled_variants(&self) -> u64

How many pipelines this cache has actually compiled.

Source

pub fn queued_variants(&self) -> usize

How many warm-up variants are still waiting to be built.

Source

pub fn warm_up_finished(&self) -> u64

How many pipelines the warm-up worker has finished building (variants the render thread stole or built itself are not counted).

Source

pub fn warm_up_done(&self) -> bool

Whether every variant Self::warm_up has listed so far is settled — built, or failed and left to be rebuilt on its next request.

true for a cache that was never asked to warm anything up.

Source

pub fn wait_warm_up(&mut self, timeout: Duration) -> bool

Blocks the calling thread until the warm-up is done (Self::warm_up_done) or timeout has passed, returning whether it finished.

Compiles nothing on the calling thread and steals nothing from the queue — the worker builds every remaining variant — so it is the counterpart of requesting each listed variant through Self::get_or_create, which would build the queued ones inline. A zero timeout is a non-blocking Self::warm_up_done. After Self::shutdown with variants still queued nothing will ever build them, so it returns false at once instead of waiting out timeout.

Under perf-trace the time spent here counts toward [Self::take_resolve_wait], beside the waits get_or_create makes.

Trait Implementations§

Source§

impl Debug for PipelineCache

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> 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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,