-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrender_pass.rs
More file actions
356 lines (317 loc) · 9.91 KB
/
render_pass.rs
File metadata and controls
356 lines (317 loc) · 9.91 KB
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
//! Render pass wrapper and builder for starting a pass on a command encoder.
//!
//! This module provides a small builder to describe the pass setup (label and
//! clear color) and a thin `RenderPass` wrapper around `wgpu::RenderPass<'_>`.
//!
//! Building a render pass implicitly begins the pass on the provided
//! `CommandEncoder` and texture view. The returned `RenderPass` borrows the
//! encoder and remains valid until dropped.
use wgpu::{
self,
RenderPassColorAttachment,
};
use super::{
bind,
buffer,
command,
pipeline,
surface,
};
/// Color load operation for a render pass color attachment.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ColorLoadOp {
/// Load the existing contents of the attachment.
Load,
/// Clear the attachment to the provided RGBA color.
Clear([f64; 4]),
}
/// Store operation for a render pass attachment.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StoreOp {
/// Store the results to the attachment at the end of the pass.
Store,
/// Discard the results at the end of the pass when possible.
Discard,
}
/// Combined load and store operations for the color attachment.
#[derive(Clone, Copy, Debug)]
pub struct ColorOperations {
pub load: ColorLoadOp,
pub store: StoreOp,
}
impl Default for ColorOperations {
fn default() -> Self {
return Self {
load: ColorLoadOp::Clear([0.0, 0.0, 0.0, 1.0]),
store: StoreOp::Store,
};
}
}
/// Depth load operation for a depth attachment.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DepthLoadOp {
/// Load the existing contents of the depth attachment.
Load,
/// Clear the depth attachment to the provided value in [0,1].
Clear(f32),
}
/// Depth operations (load/store) for the depth attachment.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DepthOperations {
pub load: DepthLoadOp,
pub store: StoreOp,
}
impl Default for DepthOperations {
fn default() -> Self {
return Self {
load: DepthLoadOp::Clear(1.0),
store: StoreOp::Store,
};
}
}
/// Configuration for beginning a render pass.
#[derive(Clone, Debug, Default)]
pub struct RenderPassConfig {
pub label: Option<String>,
pub color_operations: ColorOperations,
}
/// Wrapper around `wgpu::RenderPass<'_>` exposing the operations needed by the
/// engine without leaking raw `wgpu` types at the call sites.
#[derive(Debug)]
pub struct RenderPass<'a> {
pub(super) raw: wgpu::RenderPass<'a>,
}
#[derive(Debug)]
struct RenderPassKeepAlive<'a> {
color_attachments: [Option<wgpu::RenderPassColorAttachment<'a>>; 1],
label: Option<String>,
}
impl<'a> RenderPass<'a> {
/// Set the active render pipeline.
pub fn set_pipeline(&mut self, pipeline: &pipeline::RenderPipeline) {
self.raw.set_pipeline(pipeline.raw());
}
/// Apply viewport state.
pub fn set_viewport(
&mut self,
x: f32,
y: f32,
width: f32,
height: f32,
min_depth: f32,
max_depth: f32,
) {
self
.raw
.set_viewport(x, y, width, height, min_depth, max_depth);
}
/// Apply scissor rectangle.
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
self.raw.set_scissor_rect(x, y, width, height);
}
/// Bind a group with optional dynamic offsets.
pub fn set_bind_group(
&mut self,
set: u32,
group: &bind::BindGroup,
dynamic_offsets: &[u32],
) {
self.raw.set_bind_group(set, group.raw(), dynamic_offsets);
}
/// Bind a vertex buffer slot.
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: &buffer::Buffer) {
self.raw.set_vertex_buffer(slot, buffer.raw().slice(..));
}
/// Bind an index buffer with the provided index format.
pub fn set_index_buffer(
&mut self,
buffer: &buffer::Buffer,
format: buffer::IndexFormat,
) {
self
.raw
.set_index_buffer(buffer.raw().slice(..), format.to_wgpu());
}
/// Upload push constants.
pub fn set_push_constants(
&mut self,
stages: pipeline::PipelineStage,
offset: u32,
data: &[u8],
) {
self.raw.set_push_constants(stages.to_wgpu(), offset, data);
}
/// Issue a non-indexed draw over a vertex range.
pub fn draw(&mut self, vertices: std::ops::Range<u32>) {
self.raw.draw(vertices, 0..1);
}
/// Issue an indexed draw with a base vertex applied.
pub fn draw_indexed(
&mut self,
indices: std::ops::Range<u32>,
base_vertex: i32,
) {
self.raw.draw_indexed(indices, base_vertex, 0..1);
}
}
/// Wrapper for a variably sized list of color attachments passed into a render
/// pass. The attachments borrow `TextureView` references for the duration of
/// the pass.
#[derive(Debug, Default)]
pub struct RenderColorAttachments<'a> {
attachments: Vec<Option<wgpu::RenderPassColorAttachment<'a>>>,
}
impl<'a> RenderColorAttachments<'a> {
/// Create an empty attachments list.
pub fn new() -> Self {
return Self {
attachments: Vec::new(),
};
}
/// Append a color attachment targeting the provided `TextureView`.
///
/// The load/store operations are initialized to load/store and will be
/// configured by the render pass builder before beginning the pass.
pub fn push_color(&mut self, view: surface::TextureViewRef<'a>) -> &mut Self {
let attachment = wgpu::RenderPassColorAttachment {
view: view.raw,
resolve_target: None,
depth_slice: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
};
self.attachments.push(Some(attachment));
return self;
}
/// Apply the same operations to all color attachments.
pub(crate) fn set_operations_for_all(
&mut self,
operations: wgpu::Operations<wgpu::Color>,
) {
for attachment in &mut self.attachments {
if let Some(ref mut a) = attachment {
a.ops = operations;
}
}
}
pub(crate) fn as_slice(
&self,
) -> &[Option<wgpu::RenderPassColorAttachment<'a>>] {
return &self.attachments;
}
}
#[derive(Debug, Default)]
/// Builder for beginning a render pass targeting a single color attachment.
///
/// Building a render pass implicitly begins one on the provided encoder and
/// returns a `RenderPass` wrapper that borrows the encoder.
pub struct RenderPassBuilder {
config: RenderPassConfig,
}
impl RenderPassBuilder {
/// Create a new builder. Defaults to clearing to opaque black.
pub fn new() -> Self {
Self {
config: RenderPassConfig {
label: None,
color_operations: ColorOperations::default(),
},
}
}
/// Attach a debug label to the render pass.
pub fn with_label(mut self, label: &str) -> Self {
self.config.label = Some(label.to_string());
return self;
}
/// Set the clear color for the color attachment.
pub fn with_clear_color(mut self, color: [f64; 4]) -> Self {
self.config.color_operations.load = ColorLoadOp::Clear(color);
self.config.color_operations.store = StoreOp::Store;
return self;
}
/// Set color load operation (load or clear with the previously set color).
pub fn with_color_load_op(mut self, load: ColorLoadOp) -> Self {
self.config.color_operations.load = load;
return self;
}
/// Set color store operation (store or discard).
pub fn with_store_op(mut self, store: StoreOp) -> Self {
self.config.color_operations.store = store;
return self;
}
/// Provide combined color operations.
pub fn with_color_operations(mut self, operations: ColorOperations) -> Self {
self.config.color_operations = operations;
return self;
}
// Depth attachment is supplied at build time by the caller.
/// Build (begin) the render pass on the provided encoder using the provided
/// color attachments list. The attachments list MUST outlive the returned
/// render pass value.
pub fn build<'view>(
&'view self,
encoder: &'view mut command::CommandEncoder,
attachments: &'view mut RenderColorAttachments<'view>,
depth_view: Option<crate::wgpu::surface::TextureViewRef<'view>>,
depth_ops: Option<DepthOperations>,
) -> RenderPass<'view> {
let operations = match self.config.color_operations.load {
ColorLoadOp::Load => wgpu::Operations {
load: wgpu::LoadOp::Load,
store: match self.config.color_operations.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
ColorLoadOp::Clear(color) => wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: color[0],
g: color[1],
b: color[2],
a: color[3],
}),
store: match self.config.color_operations.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
};
// Apply operations to all provided attachments.
attachments.set_operations_for_all(operations);
// Optional depth attachment
let depth_stencil_attachment = depth_view.map(|v| {
let dop = depth_ops.unwrap_or_default();
wgpu::RenderPassDepthStencilAttachment {
view: v.raw,
depth_ops: Some(match dop.load {
DepthLoadOp::Load => wgpu::Operations {
load: wgpu::LoadOp::Load,
store: match dop.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
DepthLoadOp::Clear(value) => wgpu::Operations {
load: wgpu::LoadOp::Clear(value),
store: match dop.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
}),
stencil_ops: None,
}
});
let desc: wgpu::RenderPassDescriptor<'view> = wgpu::RenderPassDescriptor {
label: self.config.label.as_deref(),
color_attachments: attachments.as_slice(),
depth_stencil_attachment,
timestamp_writes: None,
occlusion_query_set: None,
};
let pass = encoder.begin_render_pass_raw(&desc);
return RenderPass { raw: pass };
}
}