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);