-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrender_pass.rs
More file actions
439 lines (394 loc) · 12.8 KB
/
render_pass.rs
File metadata and controls
439 lines (394 loc) · 12.8 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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
//! 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;
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,
};
}
}
/// Stencil load operation for a stencil attachment.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StencilLoadOp {
/// Load the existing contents of the stencil attachment.
Load,
/// Clear the stencil attachment to the provided value.
Clear(u32),
}
/// Stencil operations (load/store) for the stencil attachment.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct StencilOperations {
pub load: StencilLoadOp,
pub store: StoreOp,
}
impl Default for StencilOperations {
fn default() -> Self {
return Self {
load: StencilLoadOp::Clear(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>,
}
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());
}
/// Issue a non-indexed draw over a vertex range.
pub fn draw(
&mut self,
vertices: std::ops::Range<u32>,
instances: std::ops::Range<u32>,
) {
self.raw.draw(vertices, instances);
}
/// Issue an indexed draw with a base vertex applied.
pub fn draw_indexed(
&mut self,
indices: std::ops::Range<u32>,
base_vertex: i32,
instances: std::ops::Range<u32>,
) {
self.raw.draw_indexed(indices, base_vertex, instances);
}
}
/// 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;
}
/// Append a multi-sampled color attachment with a resolve target view.
///
/// The `msaa_view` MUST have a sample count > 1 and the `resolve_view` MUST
/// be a single-sample view of the same format and size.
pub fn push_msaa_color(
&mut self,
msaa_view: surface::TextureViewRef<'a>,
resolve_view: surface::TextureViewRef<'a>,
) -> &mut Self {
let attachment = wgpu::RenderPassColorAttachment {
view: msaa_view.raw,
resolve_target: Some(resolve_view.raw),
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 a in self.attachments.iter_mut().flatten() {
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 (used only for debugging during
/// builder setup, the actual label must be passed to `build`).
#[deprecated(
note = "The label must be passed directly to build() for proper lifetime management"
)]
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.
///
/// # Arguments
/// * `encoder` - The command encoder to begin the pass on.
/// * `attachments` - Color attachments for the pass.
/// * `depth_view` - Optional depth view.
/// * `depth_ops` - Optional depth operations.
/// * `stencil_ops` - Optional stencil operations.
/// * `label` - Optional debug label (must outlive the pass).
pub fn build<'view>(
self,
encoder: &'view mut command::CommandEncoder,
attachments: &'view mut RenderColorAttachments<'view>,
depth_view: Option<crate::wgpu::surface::TextureViewRef<'view>>,
depth_ops: Option<DepthOperations>,
stencil_ops: Option<StencilOperations>,
label: Option<&'view str>,
) -> 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/stencil attachment. Include depth or stencil ops only
// when provided to avoid touching aspects that were not requested.
let depth_stencil_attachment = depth_view.map(|v| {
// Map depth ops only when explicitly provided; when `None`, preserve the
// depth aspect, which is important for stencil-only passes.
let mapped_depth_ops = depth_ops.map(|dop| 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,
},
},
});
// Map stencil ops only if explicitly provided.
let mapped_stencil_ops = stencil_ops.map(|sop| match sop.load {
StencilLoadOp::Load => wgpu::Operations {
load: wgpu::LoadOp::Load,
store: match sop.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
StencilLoadOp::Clear(value) => wgpu::Operations {
load: wgpu::LoadOp::Clear(value),
store: match sop.store {
StoreOp::Store => wgpu::StoreOp::Store,
StoreOp::Discard => wgpu::StoreOp::Discard,
},
},
});
wgpu::RenderPassDepthStencilAttachment {
view: v.raw,
depth_ops: mapped_depth_ops,
stencil_ops: mapped_stencil_ops,
}
});
let desc = wgpu::RenderPassDescriptor {
label,
color_attachments: attachments.as_slice(),
depth_stencil_attachment,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
};
let pass = encoder.begin_render_pass_raw(&desc);
return RenderPass { raw: pass };
}
}
impl<'a> RenderPass<'a> {
/// Set the stencil reference value used by the active pipeline's stencil test.
pub fn set_stencil_reference(&mut self, reference: u32) {
self.raw.set_stencil_reference(reference);
}
/// Set immediate data for subsequent draw calls.
///
/// This is the wgpu v28 replacement for push constants. The `offset` and
/// `data` length MUST be multiples of 4 bytes (IMMEDIATE_DATA_ALIGNMENT).
pub fn set_immediates(&mut self, offset: u32, data: &[u8]) {
self.raw.set_immediates(offset, data);
}
}