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
impl PipelineCache
Sourcepub fn new(
shaders: Arc<ShaderLibrary>,
driver_cache: Option<PipelineCache>,
) -> Self
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.
Sourcepub fn shaders(&self) -> &ShaderLibrary
pub fn shaders(&self) -> &ShaderLibrary
The library this cache resolves ShaderIds against.
Sourcepub fn get_or_create(
&mut self,
device: &Device,
desc: &RenderPipelineDesc,
) -> &RenderPipeline
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.
Sourcepub fn warm_up(&mut self, device: &Device, descs: &[RenderPipelineDesc])
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.
Sourcepub fn warm_up_shaders(&mut self, device: &Device, ids: &[ShaderId])
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.
Sourcepub fn shutdown(&mut self)
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.
Sourcepub fn compiled_variants(&self) -> u64
pub fn compiled_variants(&self) -> u64
How many pipelines this cache has actually compiled.
Sourcepub fn queued_variants(&self) -> usize
pub fn queued_variants(&self) -> usize
How many warm-up variants are still waiting to be built.
Sourcepub fn warm_up_finished(&self) -> u64
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).
Sourcepub fn warm_up_done(&self) -> bool
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.
Sourcepub fn wait_warm_up(&mut self, timeout: Duration) -> bool
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.