1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Render pipelines the renderer builds from its own fixed sources: blurs,
//! blits, images and glyphs. A launch records, by label, the ones it draws
//! with, and later launches queue those on the warm-up lane before their
//! frames ask for them.
use std::cell::Cell;
use crate::{
lazy_resource::{LazyGpuResource, Pending},
pipeline_compiler::{CompileLane, CompilerSend, PipelineCompiler},
pipeline_recorder::PipelineRecorder,
};
/// One fixed render pipeline, named by a label no other fixed pipeline
/// shares.
pub(crate) struct FixedPipeline {
resource: LazyGpuResource<wgpu::RenderPipeline>,
/// Whether its build is queued, so it is queued once.
queued: Cell<bool>,
/// Whether the loaded driver cache holds it: a draw builds it in its
/// frame as a cache hit.
cached: Cell<bool>,
#[cfg(not(target_arch = "wasm32"))]
drawn: Cell<bool>,
}
impl FixedPipeline {
pub(crate) fn new(label: &'static str) -> Self {
Self {
resource: LazyGpuResource::new(label),
queued: Cell::new(false),
cached: Cell::new(false),
#[cfg(not(target_arch = "wasm32"))]
drawn: Cell::new(false),
}
}
/// The pipeline for a draw, built here if nothing has built it yet. The
/// first draw is noted with `recorder`.
pub(crate) fn for_draw(
&self,
recorder: &PipelineRecorder,
backend: wgpu::Backend,
create: impl FnOnce() -> wgpu::RenderPipeline,
) -> &wgpu::RenderPipeline {
#[cfg(not(target_arch = "wasm32"))]
if !self.drawn.replace(true) {
recorder.note_fixed(self.resource.label(), recorder.in_first_screen());
}
self.resource.for_draw(recorder, backend, create)
}
/// Queues the build on `lane` unless it is already built or queued.
pub(crate) fn queue(
&self,
compiler: &PipelineCompiler,
lane: CompileLane,
backend: wgpu::Backend,
create: impl FnOnce() -> wgpu::RenderPipeline + CompilerSend + 'static,
) {
if self.resource.get().is_none() && !self.queued.replace(true) {
self.resource.queue(compiler, lane, backend, create);
}
}
/// Builds the pipeline, which `job` makes, on `lane` ahead of its first
/// draw unless it is built, queued or in the loaded driver cache, or the
/// compiler builds nothing ahead (see [`PipelineCompiler::builds_ahead`]).
/// A pass asks for every pipeline it is about to draw with, so the
/// missing ones compile side by side. The pipeline while it is still to
/// land, for a caller that waits for it.
pub(crate) fn prefetch<J>(
&self,
lane: CompileLane,
compiler: &PipelineCompiler,
backend: wgpu::Backend,
job: impl FnOnce() -> J,
) -> Option<Pending<wgpu::RenderPipeline>>
where
J: FnOnce() -> wgpu::RenderPipeline + CompilerSend + 'static,
{
if !compiler.builds_ahead() || self.resource.get().is_some() || self.cached.get() {
return None;
}
if !self.queued.get() {
self.queue(compiler, lane, backend, job());
}
Some(self.resource.pending())
}
/// Whether the pipeline is built; when it is not, its build, which
/// `job` makes, is queued on the demand lane.
pub(crate) fn ready_or_queue<J>(
&self,
compiler: &PipelineCompiler,
backend: wgpu::Backend,
job: impl FnOnce() -> J,
) -> bool
where
J: FnOnce() -> wgpu::RenderPipeline + CompilerSend + 'static,
{
if self.resource.get().is_some() || self.cached.get() {
return true;
}
if compiler.is_active() {
self.queue(compiler, CompileLane::Demanded, backend, job());
return false;
}
true
}
/// Trusts the loaded driver cache with this pipeline.
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn trust_cached(&self) {
self.cached.set(true);
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn label(&self) -> &'static str {
self.resource.label()
}
}