wgpu/api/render_pass.rs
1use std::{marker::PhantomData, ops::Range, sync::Arc, thread};
2
3use crate::context::DynContext;
4use crate::*;
5
6#[derive(Debug)]
7pub(crate) struct RenderPassInner {
8 pub(crate) data: Box<Data>,
9 pub(crate) context: Arc<C>,
10}
11
12impl Drop for RenderPassInner {
13 fn drop(&mut self) {
14 if !thread::panicking() {
15 self.context.render_pass_end(self.data.as_mut());
16 }
17 }
18}
19
20/// In-progress recording of a render pass: a list of render commands in a [`CommandEncoder`].
21///
22/// It can be created with [`CommandEncoder::begin_render_pass()`], whose [`RenderPassDescriptor`]
23/// specifies the attachments (textures) that will be rendered to.
24///
25/// Most of the methods on `RenderPass` serve one of two purposes, identifiable by their names:
26///
27/// * `draw_*()`: Drawing (that is, encoding a render command, which, when executed by the GPU, will
28/// rasterize something and execute shaders).
29/// * `set_*()`: Setting part of the [render state](https://gpuweb.github.io/gpuweb/#renderstate)
30/// for future drawing commands.
31///
32/// A render pass may contain any number of drawing commands, and before/between each command the
33/// render state may be updated however you wish; each drawing command will be executed using the
34/// render state that has been set when the `draw_*()` function is called.
35///
36/// Corresponds to [WebGPU `GPURenderPassEncoder`](
37/// https://gpuweb.github.io/gpuweb/#render-pass-encoder).
38#[derive(Debug)]
39pub struct RenderPass<'encoder> {
40 /// The inner data of the render pass, separated out so it's easy to replace the lifetime with 'static if desired.
41 pub(crate) inner: RenderPassInner,
42
43 /// This lifetime is used to protect the [`CommandEncoder`] from being used
44 /// while the pass is alive.
45 pub(crate) encoder_guard: PhantomData<&'encoder ()>,
46}
47
48impl<'encoder> RenderPass<'encoder> {
49 /// Drops the lifetime relationship to the parent command encoder, making usage of
50 /// the encoder while this pass is recorded a run-time error instead.
51 ///
52 /// Attention: As long as the render pass has not been ended, any mutating operation on the parent
53 /// command encoder will cause a run-time error and invalidate it!
54 /// By default, the lifetime constraint prevents this, but it can be useful
55 /// to handle this at run time, such as when storing the pass and encoder in the same
56 /// data structure.
57 ///
58 /// This operation has no effect on pass recording.
59 /// It's a safe operation, since [`CommandEncoder`] is in a locked state as long as the pass is active
60 /// regardless of the lifetime constraint or its absence.
61 pub fn forget_lifetime(self) -> RenderPass<'static> {
62 RenderPass {
63 inner: self.inner,
64 encoder_guard: PhantomData,
65 }
66 }
67
68 /// Sets the active bind group for a given bind group index. The bind group layout
69 /// in the active pipeline when any `draw_*()` method is called must match the layout of
70 /// this bind group.
71 ///
72 /// If the bind group have dynamic offsets, provide them in binding order.
73 /// These offsets have to be aligned to [`Limits::min_uniform_buffer_offset_alignment`]
74 /// or [`Limits::min_storage_buffer_offset_alignment`] appropriately.
75 ///
76 /// Subsequent draw calls’ shader executions will be able to access data in these bind groups.
77 pub fn set_bind_group<'a>(
78 &mut self,
79 index: u32,
80 bind_group: impl Into<Option<&'a BindGroup>>,
81 offsets: &[DynamicOffset],
82 ) {
83 let bg = bind_group.into().map(|x| x.data.as_ref());
84 DynContext::render_pass_set_bind_group(
85 &*self.inner.context,
86 self.inner.data.as_mut(),
87 index,
88 bg,
89 offsets,
90 )
91 }
92
93 /// Sets the active render pipeline.
94 ///
95 /// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
96 pub fn set_pipeline(&mut self, pipeline: &RenderPipeline) {
97 DynContext::render_pass_set_pipeline(
98 &*self.inner.context,
99 self.inner.data.as_mut(),
100 pipeline.data.as_ref(),
101 )
102 }
103
104 /// Sets the blend color as used by some of the blending modes.
105 ///
106 /// Subsequent blending tests will test against this value.
107 /// If this method has not been called, the blend constant defaults to [`Color::TRANSPARENT`]
108 /// (all components zero).
109 pub fn set_blend_constant(&mut self, color: Color) {
110 DynContext::render_pass_set_blend_constant(
111 &*self.inner.context,
112 self.inner.data.as_mut(),
113 color,
114 )
115 }
116
117 /// Sets the active index buffer.
118 ///
119 /// Subsequent calls to [`draw_indexed`](RenderPass::draw_indexed) on this [`RenderPass`] will
120 /// use `buffer` as the source index buffer.
121 pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'_>, index_format: IndexFormat) {
122 DynContext::render_pass_set_index_buffer(
123 &*self.inner.context,
124 self.inner.data.as_mut(),
125 buffer_slice.buffer.data.as_ref(),
126 index_format,
127 buffer_slice.offset,
128 buffer_slice.size,
129 )
130 }
131
132 /// Assign a vertex buffer to a slot.
133 ///
134 /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
135 /// [`RenderPass`] will use `buffer` as one of the source vertex buffers.
136 ///
137 /// The `slot` refers to the index of the matching descriptor in
138 /// [`VertexState::buffers`].
139 ///
140 /// [`draw`]: RenderPass::draw
141 /// [`draw_indexed`]: RenderPass::draw_indexed
142 pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'_>) {
143 DynContext::render_pass_set_vertex_buffer(
144 &*self.inner.context,
145 self.inner.data.as_mut(),
146 slot,
147 buffer_slice.buffer.data.as_ref(),
148 buffer_slice.offset,
149 buffer_slice.size,
150 )
151 }
152
153 /// Sets the scissor rectangle used during the rasterization stage.
154 /// After transformation into [viewport coordinates](https://www.w3.org/TR/webgpu/#viewport-coordinates).
155 ///
156 /// Subsequent draw calls will discard any fragments which fall outside the scissor rectangle.
157 /// If this method has not been called, the scissor rectangle defaults to the entire bounds of
158 /// the render targets.
159 ///
160 /// The function of the scissor rectangle resembles [`set_viewport()`](Self::set_viewport),
161 /// but it does not affect the coordinate system, only which fragments are discarded.
162 pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
163 DynContext::render_pass_set_scissor_rect(
164 &*self.inner.context,
165 self.inner.data.as_mut(),
166 x,
167 y,
168 width,
169 height,
170 );
171 }
172
173 /// Sets the viewport used during the rasterization stage to linearly map
174 /// from [normalized device coordinates](https://www.w3.org/TR/webgpu/#ndc) to [viewport coordinates](https://www.w3.org/TR/webgpu/#viewport-coordinates).
175 ///
176 /// Subsequent draw calls will only draw within this region.
177 /// If this method has not been called, the viewport defaults to the entire bounds of the render
178 /// targets.
179 pub fn set_viewport(&mut self, x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32) {
180 DynContext::render_pass_set_viewport(
181 &*self.inner.context,
182 self.inner.data.as_mut(),
183 x,
184 y,
185 w,
186 h,
187 min_depth,
188 max_depth,
189 );
190 }
191
192 /// Sets the stencil reference.
193 ///
194 /// Subsequent stencil tests will test against this value.
195 /// If this method has not been called, the stencil reference value defaults to `0`.
196 pub fn set_stencil_reference(&mut self, reference: u32) {
197 DynContext::render_pass_set_stencil_reference(
198 &*self.inner.context,
199 self.inner.data.as_mut(),
200 reference,
201 );
202 }
203
204 /// Inserts debug marker.
205 pub fn insert_debug_marker(&mut self, label: &str) {
206 DynContext::render_pass_insert_debug_marker(
207 &*self.inner.context,
208 self.inner.data.as_mut(),
209 label,
210 );
211 }
212
213 /// Start record commands and group it into debug marker group.
214 pub fn push_debug_group(&mut self, label: &str) {
215 DynContext::render_pass_push_debug_group(
216 &*self.inner.context,
217 self.inner.data.as_mut(),
218 label,
219 );
220 }
221
222 /// Stops command recording and creates debug group.
223 pub fn pop_debug_group(&mut self) {
224 DynContext::render_pass_pop_debug_group(&*self.inner.context, self.inner.data.as_mut());
225 }
226
227 /// Draws primitives from the active vertex buffer(s).
228 ///
229 /// The active vertex buffer(s) can be set with [`RenderPass::set_vertex_buffer`].
230 /// Does not use an Index Buffer. If you need this see [`RenderPass::draw_indexed`]
231 ///
232 /// Panics if vertices Range is outside of the range of the vertices range of any set vertex buffer.
233 ///
234 /// vertices: The range of vertices to draw.
235 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
236 /// E.g.of how its used internally
237 /// ```rust ignore
238 /// for instance_id in instance_range {
239 /// for vertex_id in vertex_range {
240 /// let vertex = vertex[vertex_id];
241 /// vertex_shader(vertex, vertex_id, instance_id);
242 /// }
243 /// }
244 /// ```
245 ///
246 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
247 /// It is not affected by changes to the state that are performed after it is called.
248 pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
249 DynContext::render_pass_draw(
250 &*self.inner.context,
251 self.inner.data.as_mut(),
252 vertices,
253 instances,
254 )
255 }
256
257 /// Draws indexed primitives using the active index buffer and the active vertex buffers.
258 ///
259 /// The active index buffer can be set with [`RenderPass::set_index_buffer`]
260 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
261 ///
262 /// Panics if indices Range is outside of the range of the indices range of any set index buffer.
263 ///
264 /// indices: The range of indices to draw.
265 /// base_vertex: value added to each index value before indexing into the vertex buffers.
266 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
267 /// E.g.of how its used internally
268 /// ```rust ignore
269 /// for instance_id in instance_range {
270 /// for index_index in index_range {
271 /// let vertex_id = index_buffer[index_index];
272 /// let adjusted_vertex_id = vertex_id + base_vertex;
273 /// let vertex = vertex[adjusted_vertex_id];
274 /// vertex_shader(vertex, adjusted_vertex_id, instance_id);
275 /// }
276 /// }
277 /// ```
278 ///
279 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
280 /// It is not affected by changes to the state that are performed after it is called.
281 pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
282 DynContext::render_pass_draw_indexed(
283 &*self.inner.context,
284 self.inner.data.as_mut(),
285 indices,
286 base_vertex,
287 instances,
288 );
289 }
290
291 /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
292 ///
293 /// This is like calling [`RenderPass::draw`] but the contents of the call are specified in the `indirect_buffer`.
294 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
295 ///
296 /// Indirect drawing has some caveats depending on the features available. We are not currently able to validate
297 /// these and issue an error.
298 /// - If [`Features::INDIRECT_FIRST_INSTANCE`] is not present on the adapter,
299 /// [`DrawIndirect::first_instance`](crate::util::DrawIndirectArgs::first_instance) will be ignored.
300 /// - If [`DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW`] is not present on the adapter,
301 /// any use of `@builtin(vertex_index)` or `@builtin(instance_index)` in the vertex shader will have different values.
302 ///
303 /// See details on the individual flags for more information.
304 pub fn draw_indirect(&mut self, indirect_buffer: &Buffer, indirect_offset: BufferAddress) {
305 DynContext::render_pass_draw_indirect(
306 &*self.inner.context,
307 self.inner.data.as_mut(),
308 indirect_buffer.data.as_ref(),
309 indirect_offset,
310 );
311 }
312
313 /// Draws indexed primitives using the active index buffer and the active vertex buffers,
314 /// based on the contents of the `indirect_buffer`.
315 ///
316 /// This is like calling [`RenderPass::draw_indexed`] but the contents of the call are specified in the `indirect_buffer`.
317 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
318 ///
319 /// Indirect drawing has some caveats depending on the features available. We are not currently able to validate
320 /// these and issue an error.
321 /// - If [`Features::INDIRECT_FIRST_INSTANCE`] is not present on the adapter,
322 /// [`DrawIndexedIndirect::first_instance`](crate::util::DrawIndexedIndirectArgs::first_instance) will be ignored.
323 /// - If [`DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW`] is not present on the adapter,
324 /// any use of `@builtin(vertex_index)` or `@builtin(instance_index)` in the vertex shader will have different values.
325 ///
326 /// See details on the individual flags for more information.
327 pub fn draw_indexed_indirect(
328 &mut self,
329 indirect_buffer: &Buffer,
330 indirect_offset: BufferAddress,
331 ) {
332 DynContext::render_pass_draw_indexed_indirect(
333 &*self.inner.context,
334 self.inner.data.as_mut(),
335 indirect_buffer.data.as_ref(),
336 indirect_offset,
337 );
338 }
339
340 /// Execute a [render bundle][RenderBundle], which is a set of pre-recorded commands
341 /// that can be run together.
342 ///
343 /// Commands in the bundle do not inherit this render pass's current render state, and after the
344 /// bundle has executed, the state is **cleared** (reset to defaults, not the previous state).
345 pub fn execute_bundles<'a, I: IntoIterator<Item = &'a RenderBundle>>(
346 &mut self,
347 render_bundles: I,
348 ) {
349 let mut render_bundles = render_bundles.into_iter().map(|rb| rb.data.as_ref());
350
351 DynContext::render_pass_execute_bundles(
352 &*self.inner.context,
353 self.inner.data.as_mut(),
354 &mut render_bundles,
355 )
356 }
357}
358
359/// [`Features::MULTI_DRAW_INDIRECT`] must be enabled on the device in order to call these functions.
360impl<'encoder> RenderPass<'encoder> {
361 /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
362 /// `count` draw calls are issued.
363 ///
364 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
365 ///
366 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
367 /// These draw structures are expected to be tightly packed.
368 ///
369 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
370 /// It is not affected by changes to the state that are performed after it is called.
371 pub fn multi_draw_indirect(
372 &mut self,
373 indirect_buffer: &Buffer,
374 indirect_offset: BufferAddress,
375 count: u32,
376 ) {
377 DynContext::render_pass_multi_draw_indirect(
378 &*self.inner.context,
379 self.inner.data.as_mut(),
380 indirect_buffer.data.as_ref(),
381 indirect_offset,
382 count,
383 );
384 }
385
386 /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
387 /// based on the contents of the `indirect_buffer`. `count` draw calls are issued.
388 ///
389 /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
390 /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
391 ///
392 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
393 /// These draw structures are expected to be tightly packed.
394 ///
395 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
396 /// It is not affected by changes to the state that are performed after it is called.
397 pub fn multi_draw_indexed_indirect(
398 &mut self,
399 indirect_buffer: &Buffer,
400 indirect_offset: BufferAddress,
401 count: u32,
402 ) {
403 DynContext::render_pass_multi_draw_indexed_indirect(
404 &*self.inner.context,
405 self.inner.data.as_mut(),
406 indirect_buffer.data.as_ref(),
407 indirect_offset,
408 count,
409 );
410 }
411}
412
413/// [`Features::MULTI_DRAW_INDIRECT_COUNT`] must be enabled on the device in order to call these functions.
414impl<'encoder> RenderPass<'encoder> {
415 /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
416 /// The count buffer is read to determine how many draws to issue.
417 ///
418 /// The indirect buffer must be long enough to account for `max_count` draws, however only `count`
419 /// draws will be read. If `count` is greater than `max_count`, `max_count` will be used.
420 ///
421 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
422 ///
423 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
424 /// These draw structures are expected to be tightly packed.
425 ///
426 /// The structure expected in `count_buffer` is the following:
427 ///
428 /// ```rust
429 /// #[repr(C)]
430 /// struct DrawIndirectCount {
431 /// count: u32, // Number of draw calls to issue.
432 /// }
433 /// ```
434 ///
435 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
436 /// It is not affected by changes to the state that are performed after it is called.
437 pub fn multi_draw_indirect_count(
438 &mut self,
439 indirect_buffer: &Buffer,
440 indirect_offset: BufferAddress,
441 count_buffer: &Buffer,
442 count_offset: BufferAddress,
443 max_count: u32,
444 ) {
445 DynContext::render_pass_multi_draw_indirect_count(
446 &*self.inner.context,
447 self.inner.data.as_mut(),
448 indirect_buffer.data.as_ref(),
449 indirect_offset,
450 count_buffer.data.as_ref(),
451 count_offset,
452 max_count,
453 );
454 }
455
456 /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
457 /// based on the contents of the `indirect_buffer`. The count buffer is read to determine how many draws to issue.
458 ///
459 /// The indirect buffer must be long enough to account for `max_count` draws, however only `count`
460 /// draws will be read. If `count` is greater than `max_count`, `max_count` will be used.
461 ///
462 /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
463 /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
464 ///
465 ///
466 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
467 ///
468 /// These draw structures are expected to be tightly packed.
469 ///
470 /// The structure expected in `count_buffer` is the following:
471 ///
472 /// ```rust
473 /// #[repr(C)]
474 /// struct DrawIndexedIndirectCount {
475 /// count: u32, // Number of draw calls to issue.
476 /// }
477 /// ```
478 ///
479 /// This drawing command uses the current render state, as set by preceding `set_*()` methods.
480 /// It is not affected by changes to the state that are performed after it is called.
481 pub fn multi_draw_indexed_indirect_count(
482 &mut self,
483 indirect_buffer: &Buffer,
484 indirect_offset: BufferAddress,
485 count_buffer: &Buffer,
486 count_offset: BufferAddress,
487 max_count: u32,
488 ) {
489 DynContext::render_pass_multi_draw_indexed_indirect_count(
490 &*self.inner.context,
491 self.inner.data.as_mut(),
492 indirect_buffer.data.as_ref(),
493 indirect_offset,
494 count_buffer.data.as_ref(),
495 count_offset,
496 max_count,
497 );
498 }
499}
500
501/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
502impl<'encoder> RenderPass<'encoder> {
503 /// Set push constant data for subsequent draw calls.
504 ///
505 /// Write the bytes in `data` at offset `offset` within push constant
506 /// storage, all of which are accessible by all the pipeline stages in
507 /// `stages`, and no others. Both `offset` and the length of `data` must be
508 /// multiples of [`PUSH_CONSTANT_ALIGNMENT`], which is always 4.
509 ///
510 /// For example, if `offset` is `4` and `data` is eight bytes long, this
511 /// call will write `data` to bytes `4..12` of push constant storage.
512 ///
513 /// # Stage matching
514 ///
515 /// Every byte in the affected range of push constant storage must be
516 /// accessible to exactly the same set of pipeline stages, which must match
517 /// `stages`. If there are two bytes of storage that are accessible by
518 /// different sets of pipeline stages - say, one is accessible by fragment
519 /// shaders, and the other is accessible by both fragment shaders and vertex
520 /// shaders - then no single `set_push_constants` call may affect both of
521 /// them; to write both, you must make multiple calls, each with the
522 /// appropriate `stages` value.
523 ///
524 /// Which pipeline stages may access a given byte is determined by the
525 /// pipeline's [`PushConstant`] global variable and (if it is a struct) its
526 /// members' offsets.
527 ///
528 /// For example, suppose you have twelve bytes of push constant storage,
529 /// where bytes `0..8` are accessed by the vertex shader, and bytes `4..12`
530 /// are accessed by the fragment shader. This means there are three byte
531 /// ranges each accessed by a different set of stages:
532 ///
533 /// - Bytes `0..4` are accessed only by the fragment shader.
534 ///
535 /// - Bytes `4..8` are accessed by both the fragment shader and the vertex shader.
536 ///
537 /// - Bytes `8..12` are accessed only by the vertex shader.
538 ///
539 /// To write all twelve bytes requires three `set_push_constants` calls, one
540 /// for each range, each passing the matching `stages` mask.
541 ///
542 /// [`PushConstant`]: https://docs.rs/naga/latest/naga/enum.StorageClass.html#variant.PushConstant
543 pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
544 DynContext::render_pass_set_push_constants(
545 &*self.inner.context,
546 self.inner.data.as_mut(),
547 stages,
548 offset,
549 data,
550 );
551 }
552}
553
554/// [`Features::TIMESTAMP_QUERY_INSIDE_PASSES`] must be enabled on the device in order to call these functions.
555impl<'encoder> RenderPass<'encoder> {
556 /// Issue a timestamp command at this point in the queue. The
557 /// timestamp will be written to the specified query set, at the specified index.
558 ///
559 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
560 /// the value in nanoseconds. Absolute values have no meaning,
561 /// but timestamps can be subtracted to get the time it takes
562 /// for a string of operations to complete.
563 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
564 DynContext::render_pass_write_timestamp(
565 &*self.inner.context,
566 self.inner.data.as_mut(),
567 query_set.data.as_ref(),
568 query_index,
569 )
570 }
571}
572
573impl<'encoder> RenderPass<'encoder> {
574 /// Start a occlusion query on this render pass. It can be ended with
575 /// `end_occlusion_query`. Occlusion queries may not be nested.
576 pub fn begin_occlusion_query(&mut self, query_index: u32) {
577 DynContext::render_pass_begin_occlusion_query(
578 &*self.inner.context,
579 self.inner.data.as_mut(),
580 query_index,
581 );
582 }
583
584 /// End the occlusion query on this render pass. It can be started with
585 /// `begin_occlusion_query`. Occlusion queries may not be nested.
586 pub fn end_occlusion_query(&mut self) {
587 DynContext::render_pass_end_occlusion_query(&*self.inner.context, self.inner.data.as_mut());
588 }
589}
590
591/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
592impl<'encoder> RenderPass<'encoder> {
593 /// Start a pipeline statistics query on this render pass. It can be ended with
594 /// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
595 pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
596 DynContext::render_pass_begin_pipeline_statistics_query(
597 &*self.inner.context,
598 self.inner.data.as_mut(),
599 query_set.data.as_ref(),
600 query_index,
601 );
602 }
603
604 /// End the pipeline statistics query on this render pass. It can be started with
605 /// `begin_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
606 pub fn end_pipeline_statistics_query(&mut self) {
607 DynContext::render_pass_end_pipeline_statistics_query(
608 &*self.inner.context,
609 self.inner.data.as_mut(),
610 );
611 }
612}
613
614/// Operation to perform to the output attachment at the start of a render pass.
615///
616/// Corresponds to [WebGPU `GPULoadOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpuloadop),
617/// plus the corresponding clearValue.
618#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
619#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
620pub enum LoadOp<V> {
621 /// Loads the specified value for this attachment into the render pass.
622 ///
623 /// On some GPU hardware (primarily mobile), "clear" is significantly cheaper
624 /// because it avoids loading data from main memory into tile-local memory.
625 ///
626 /// On other GPU hardware, there isn’t a significant difference.
627 ///
628 /// As a result, it is recommended to use "clear" rather than "load" in cases
629 /// where the initial value doesn’t matter
630 /// (e.g. the render target will be cleared using a skybox).
631 Clear(V),
632 /// Loads the existing value for this attachment into the render pass.
633 Load,
634}
635
636impl<V: Default> Default for LoadOp<V> {
637 fn default() -> Self {
638 Self::Clear(Default::default())
639 }
640}
641
642/// Operation to perform to the output attachment at the end of a render pass.
643///
644/// Corresponds to [WebGPU `GPUStoreOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpustoreop).
645#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
646#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
647pub enum StoreOp {
648 /// Stores the resulting value of the render pass for this attachment.
649 #[default]
650 Store,
651 /// Discards the resulting value of the render pass for this attachment.
652 ///
653 /// The attachment will be treated as uninitialized afterwards.
654 /// (If only either Depth or Stencil texture-aspects is set to `Discard`,
655 /// the respective other texture-aspect will be preserved.)
656 ///
657 /// This can be significantly faster on tile-based render hardware.
658 ///
659 /// Prefer this if the attachment is not read by subsequent passes.
660 Discard,
661}
662
663/// Pair of load and store operations for an attachment aspect.
664///
665/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
666/// separate `loadOp` and `storeOp` fields are used instead.
667#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
668#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
669pub struct Operations<V> {
670 /// How data should be read through this attachment.
671 pub load: LoadOp<V>,
672 /// Whether data will be written to through this attachment.
673 ///
674 /// Note that resolve textures (if specified) are always written to,
675 /// regardless of this setting.
676 pub store: StoreOp,
677}
678
679impl<V: Default> Default for Operations<V> {
680 #[inline]
681 fn default() -> Self {
682 Self {
683 load: LoadOp::<V>::default(),
684 store: StoreOp::default(),
685 }
686 }
687}
688
689/// Describes the timestamp writes of a render pass.
690///
691/// For use with [`RenderPassDescriptor`].
692/// At least one of `beginning_of_pass_write_index` and `end_of_pass_write_index` must be `Some`.
693///
694/// Corresponds to [WebGPU `GPURenderPassTimestampWrite`](
695/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderpasstimestampwrites).
696#[derive(Clone, Debug)]
697pub struct RenderPassTimestampWrites<'a> {
698 /// The query set to write to.
699 pub query_set: &'a QuerySet,
700 /// The index of the query set at which a start timestamp of this pass is written, if any.
701 pub beginning_of_pass_write_index: Option<u32>,
702 /// The index of the query set at which an end timestamp of this pass is written, if any.
703 pub end_of_pass_write_index: Option<u32>,
704}
705#[cfg(send_sync)]
706static_assertions::assert_impl_all!(RenderPassTimestampWrites<'_>: Send, Sync);
707
708/// Describes a color attachment to a [`RenderPass`].
709///
710/// For use with [`RenderPassDescriptor`].
711///
712/// Corresponds to [WebGPU `GPURenderPassColorAttachment`](
713/// https://gpuweb.github.io/gpuweb/#color-attachments).
714#[derive(Clone, Debug)]
715pub struct RenderPassColorAttachment<'tex> {
716 /// The view to use as an attachment.
717 pub view: &'tex TextureView,
718 /// The view that will receive the resolved output if multisampling is used.
719 ///
720 /// If set, it is always written to, regardless of how [`Self::ops`] is configured.
721 pub resolve_target: Option<&'tex TextureView>,
722 /// What operations will be performed on this color attachment.
723 pub ops: Operations<Color>,
724}
725#[cfg(send_sync)]
726static_assertions::assert_impl_all!(RenderPassColorAttachment<'_>: Send, Sync);
727
728/// Describes a depth/stencil attachment to a [`RenderPass`].
729///
730/// For use with [`RenderPassDescriptor`].
731///
732/// Corresponds to [WebGPU `GPURenderPassDepthStencilAttachment`](
733/// https://gpuweb.github.io/gpuweb/#depth-stencil-attachments).
734#[derive(Clone, Debug)]
735pub struct RenderPassDepthStencilAttachment<'tex> {
736 /// The view to use as an attachment.
737 pub view: &'tex TextureView,
738 /// What operations will be performed on the depth part of the attachment.
739 pub depth_ops: Option<Operations<f32>>,
740 /// What operations will be performed on the stencil part of the attachment.
741 pub stencil_ops: Option<Operations<u32>>,
742}
743#[cfg(send_sync)]
744static_assertions::assert_impl_all!(RenderPassDepthStencilAttachment<'_>: Send, Sync);
745
746/// Describes the attachments of a render pass.
747///
748/// For use with [`CommandEncoder::begin_render_pass`].
749///
750/// Corresponds to [WebGPU `GPURenderPassDescriptor`](
751/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderpassdescriptor).
752#[derive(Clone, Debug, Default)]
753pub struct RenderPassDescriptor<'a> {
754 /// Debug label of the render pass. This will show up in graphics debuggers for easy identification.
755 pub label: Label<'a>,
756 /// The color attachments of the render pass.
757 pub color_attachments: &'a [Option<RenderPassColorAttachment<'a>>],
758 /// The depth and stencil attachment of the render pass, if any.
759 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'a>>,
760 /// Defines which timestamp values will be written for this pass, and where to write them to.
761 ///
762 /// Requires [`Features::TIMESTAMP_QUERY`] to be enabled.
763 pub timestamp_writes: Option<RenderPassTimestampWrites<'a>>,
764 /// Defines where the occlusion query results will be stored for this pass.
765 pub occlusion_query_set: Option<&'a QuerySet>,
766}
767#[cfg(send_sync)]
768static_assertions::assert_impl_all!(RenderPassDescriptor<'_>: Send, Sync);