wgpu/api/
render_bundle_encoder.rs

1use std::{marker::PhantomData, num::NonZeroU32, ops::Range, sync::Arc};
2
3use crate::context::DynContext;
4use crate::*;
5
6/// Encodes a series of GPU operations into a reusable "render bundle".
7///
8/// It only supports a handful of render commands, but it makes them reusable.
9/// It can be created with [`Device::create_render_bundle_encoder`].
10/// It can be executed onto a [`CommandEncoder`] using [`RenderPass::execute_bundles`].
11///
12/// Executing a [`RenderBundle`] is often more efficient than issuing the underlying commands
13/// manually.
14///
15/// Corresponds to [WebGPU `GPURenderBundleEncoder`](
16/// https://gpuweb.github.io/gpuweb/#gpurenderbundleencoder).
17#[derive(Debug)]
18pub struct RenderBundleEncoder<'a> {
19    pub(crate) context: Arc<C>,
20    pub(crate) data: Box<Data>,
21    pub(crate) parent: &'a Device,
22    /// This type should be !Send !Sync, because it represents an allocation on this thread's
23    /// command buffer.
24    pub(crate) _p: PhantomData<*const u8>,
25}
26static_assertions::assert_not_impl_any!(RenderBundleEncoder<'_>: Send, Sync);
27
28/// Describes a [`RenderBundleEncoder`].
29///
30/// For use with [`Device::create_render_bundle_encoder`].
31///
32/// Corresponds to [WebGPU `GPURenderBundleEncoderDescriptor`](
33/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor).
34#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
35pub struct RenderBundleEncoderDescriptor<'a> {
36    /// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
37    pub label: Label<'a>,
38    /// The formats of the color attachments that this render bundle is capable to rendering to. This
39    /// must match the formats of the color attachments in the render pass this render bundle is executed in.
40    pub color_formats: &'a [Option<TextureFormat>],
41    /// Information about the depth attachment that this render bundle is capable to rendering to. This
42    /// must match the format of the depth attachments in the render pass this render bundle is executed in.
43    pub depth_stencil: Option<RenderBundleDepthStencil>,
44    /// Sample count this render bundle is capable of rendering to. This must match the pipelines and
45    /// the render passes it is used in.
46    pub sample_count: u32,
47    /// If this render bundle will rendering to multiple array layers in the attachments at the same time.
48    pub multiview: Option<NonZeroU32>,
49}
50static_assertions::assert_impl_all!(RenderBundleEncoderDescriptor<'_>: Send, Sync);
51
52impl<'a> RenderBundleEncoder<'a> {
53    /// Finishes recording and returns a [`RenderBundle`] that can be executed in other render passes.
54    pub fn finish(self, desc: &RenderBundleDescriptor<'_>) -> RenderBundle {
55        let data = DynContext::render_bundle_encoder_finish(&*self.context, self.data, desc);
56        RenderBundle {
57            context: Arc::clone(&self.context),
58            data,
59        }
60    }
61
62    /// Sets the active bind group for a given bind group index. The bind group layout
63    /// in the active pipeline when any `draw()` function is called must match the layout of this bind group.
64    ///
65    /// If the bind group have dynamic offsets, provide them in the binding order.
66    pub fn set_bind_group<'b>(
67        &mut self,
68        index: u32,
69        bind_group: impl Into<Option<&'a BindGroup>>,
70        offsets: &[DynamicOffset],
71    ) {
72        let bg = bind_group.into().map(|x| x.data.as_ref());
73        DynContext::render_bundle_encoder_set_bind_group(
74            &*self.parent.context,
75            self.data.as_mut(),
76            index,
77            bg,
78            offsets,
79        )
80    }
81
82    /// Sets the active render pipeline.
83    ///
84    /// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
85    pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
86        DynContext::render_bundle_encoder_set_pipeline(
87            &*self.parent.context,
88            self.data.as_mut(),
89            pipeline.data.as_ref(),
90        )
91    }
92
93    /// Sets the active index buffer.
94    ///
95    /// Subsequent calls to [`draw_indexed`](RenderBundleEncoder::draw_indexed) on this [`RenderBundleEncoder`] will
96    /// use `buffer` as the source index buffer.
97    pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
98        DynContext::render_bundle_encoder_set_index_buffer(
99            &*self.parent.context,
100            self.data.as_mut(),
101            buffer_slice.buffer.data.as_ref(),
102            index_format,
103            buffer_slice.offset,
104            buffer_slice.size,
105        )
106    }
107
108    /// Assign a vertex buffer to a slot.
109    ///
110    /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
111    /// [`RenderBundleEncoder`] will use `buffer` as one of the source vertex buffers.
112    ///
113    /// The `slot` refers to the index of the matching descriptor in
114    /// [`VertexState::buffers`].
115    ///
116    /// [`draw`]: RenderBundleEncoder::draw
117    /// [`draw_indexed`]: RenderBundleEncoder::draw_indexed
118    pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
119        DynContext::render_bundle_encoder_set_vertex_buffer(
120            &*self.parent.context,
121            self.data.as_mut(),
122            slot,
123            buffer_slice.buffer.data.as_ref(),
124            buffer_slice.offset,
125            buffer_slice.size,
126        )
127    }
128
129    /// Draws primitives from the active vertex buffer(s).
130    ///
131    /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
132    /// Does not use an Index Buffer. If you need this see [`RenderBundleEncoder::draw_indexed`]
133    ///
134    /// Panics if vertices Range is outside of the range of the vertices range of any set vertex buffer.
135    ///
136    /// vertices: The range of vertices to draw.
137    /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
138    /// E.g.of how its used internally
139    /// ```rust ignore
140    /// for instance_id in instance_range {
141    ///     for vertex_id in vertex_range {
142    ///         let vertex = vertex[vertex_id];
143    ///         vertex_shader(vertex, vertex_id, instance_id);
144    ///     }
145    /// }
146    /// ```
147    pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
148        DynContext::render_bundle_encoder_draw(
149            &*self.parent.context,
150            self.data.as_mut(),
151            vertices,
152            instances,
153        )
154    }
155
156    /// Draws indexed primitives using the active index buffer and the active vertex buffer(s).
157    ///
158    /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`].
159    /// The active vertex buffer(s) can be set with [`RenderBundleEncoder::set_vertex_buffer`].
160    ///
161    /// Panics if indices Range is outside of the range of the indices range of any set index buffer.
162    ///
163    /// indices: The range of indices to draw.
164    /// base_vertex: value added to each index value before indexing into the vertex buffers.
165    /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
166    /// E.g.of how its used internally
167    /// ```rust ignore
168    /// for instance_id in instance_range {
169    ///     for index_index in index_range {
170    ///         let vertex_id = index_buffer[index_index];
171    ///         let adjusted_vertex_id = vertex_id + base_vertex;
172    ///         let vertex = vertex[adjusted_vertex_id];
173    ///         vertex_shader(vertex, adjusted_vertex_id, instance_id);
174    ///     }
175    /// }
176    /// ```
177    pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
178        DynContext::render_bundle_encoder_draw_indexed(
179            &*self.parent.context,
180            self.data.as_mut(),
181            indices,
182            base_vertex,
183            instances,
184        );
185    }
186
187    /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
188    ///
189    /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
190    ///
191    /// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
192    pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
193        DynContext::render_bundle_encoder_draw_indirect(
194            &*self.parent.context,
195            self.data.as_mut(),
196            indirect_buffer.data.as_ref(),
197            indirect_offset,
198        );
199    }
200
201    /// Draws indexed primitives using the active index buffer and the active vertex buffers,
202    /// based on the contents of the `indirect_buffer`.
203    ///
204    /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active
205    /// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
206    ///
207    /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
208    pub fn draw_indexed_indirect(
209        &mut self,
210        indirect_buffer: &'a Buffer,
211        indirect_offset: BufferAddress,
212    ) {
213        DynContext::render_bundle_encoder_draw_indexed_indirect(
214            &*self.parent.context,
215            self.data.as_mut(),
216            indirect_buffer.data.as_ref(),
217            indirect_offset,
218        );
219    }
220}
221
222/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
223impl<'a> RenderBundleEncoder<'a> {
224    /// Set push constant data.
225    ///
226    /// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`].
227    ///
228    /// Data size must be a multiple of 4 and must have an alignment of 4.
229    /// For example, with an offset of 4 and an array of `[u8; 8]`, that will write to the range
230    /// of 4..12.
231    ///
232    /// For each byte in the range of push constant data written, the union of the stages of all push constant
233    /// ranges that covers that byte must be exactly `stages`. There's no good way of explaining this simply,
234    /// so here are some examples:
235    ///
236    /// ```text
237    /// For the given ranges:
238    /// - 0..4 Vertex
239    /// - 4..8 Fragment
240    /// ```
241    ///
242    /// You would need to upload this in two set_push_constants calls. First for the `Vertex` range, second for the `Fragment` range.
243    ///
244    /// ```text
245    /// For the given ranges:
246    /// - 0..8  Vertex
247    /// - 4..12 Fragment
248    /// ```
249    ///
250    /// You would need to upload this in three set_push_constants calls. First for the `Vertex` only range 0..4, second
251    /// for the `Vertex | Fragment` range 4..8, third for the `Fragment` range 8..12.
252    pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
253        DynContext::render_bundle_encoder_set_push_constants(
254            &*self.parent.context,
255            self.data.as_mut(),
256            stages,
257            offset,
258            data,
259        );
260    }
261}