Skip to main content

wgpu/api/
render_bundle_encoder.rs

1use core::{marker::PhantomData, num::NonZeroU32, ops::Range};
2
3use crate::dispatch::RenderBundleEncoderInterface;
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) inner: dispatch::DispatchRenderBundleEncoder,
20    /// This type should be !Send !Sync, because it represents an allocation on this thread's
21    /// command buffer.
22    pub(crate) _p: PhantomData<(*const u8, &'a ())>,
23}
24static_assertions::assert_not_impl_any!(RenderBundleEncoder<'_>: Send, Sync);
25
26crate::cmp::impl_eq_ord_hash_proxy!(RenderBundleEncoder<'_> => .inner);
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 bundle = match self.inner {
56            #[cfg(wgpu_core)]
57            dispatch::DispatchRenderBundleEncoder::Core(b) => b.finish(desc),
58            #[cfg(webgpu)]
59            dispatch::DispatchRenderBundleEncoder::WebGPU(b) => b.finish(desc),
60            #[cfg(custom)]
61            dispatch::DispatchRenderBundleEncoder::Custom(b) => b.finish_boxed(desc),
62        };
63
64        RenderBundle { inner: bundle }
65    }
66
67    /// Sets the active bind group for a given bind group index. The bind group layout
68    /// in the active pipeline when any `draw()` function is called must match the layout of this bind group.
69    ///
70    /// If the bind group have dynamic offsets, provide them in the binding order.
71    pub fn set_bind_group<'b, BG>(&mut self, index: u32, bind_group: BG, offsets: &[DynamicOffset])
72    where
73        Option<&'b BindGroup>: From<BG>,
74    {
75        let bg: Option<&'b BindGroup> = bind_group.into();
76        let bg = bg.map(|x| &x.inner);
77        self.inner.set_bind_group(index, bg, offsets);
78    }
79
80    /// Sets the active render pipeline.
81    ///
82    /// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
83    pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
84        self.inner.set_pipeline(&pipeline.inner);
85    }
86
87    /// Sets the active index buffer.
88    ///
89    /// Subsequent calls to [`draw_indexed`](RenderBundleEncoder::draw_indexed) on this [`RenderBundleEncoder`] will
90    /// use `buffer` as the source index buffer.
91    ///
92    /// # Panics
93    ///
94    /// - If the buffer slice length is 0.
95    pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
96        self.inner.set_index_buffer(
97            &buffer_slice.buffer.inner,
98            index_format,
99            buffer_slice.offset,
100            Some(buffer_slice.size),
101        );
102    }
103
104    /// Assign a vertex buffer to a slot.
105    ///
106    /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
107    /// [`RenderBundleEncoder`] will use `buffer` as one of the source vertex buffers.
108    ///
109    /// The `slot` refers to the index of the matching descriptor in
110    /// [`VertexState::buffers`].
111    ///
112    /// [`draw`]: RenderBundleEncoder::draw
113    /// [`draw_indexed`]: RenderBundleEncoder::draw_indexed
114    ///
115    /// # Panics
116    ///
117    /// - If the buffer slice length is 0.
118    pub fn set_vertex_buffer<'b, B>(&mut self, slot: u32, buffer_slice: B)
119    where
120        Option<BufferSlice<'b>>: From<B>,
121    {
122        let buffer_slice: Option<BufferSlice<'b>> = buffer_slice.into();
123        if let Some(buffer_slice) = buffer_slice {
124            self.inner.set_vertex_buffer(
125                slot,
126                Some(&buffer_slice.buffer.inner),
127                buffer_slice.offset,
128                Some(buffer_slice.size),
129            );
130        } else {
131            self.inner.set_vertex_buffer(slot, None, 0, None);
132        }
133    }
134
135    /// Inserts a debug marker into the recorded commands.
136    pub fn insert_debug_marker(&mut self, label: &str) {
137        self.inner.insert_debug_marker(label);
138    }
139
140    /// Begins a debug group for the recorded commands.
141    ///
142    /// All debug groups must be popped before calling [`Self::finish`].
143    pub fn push_debug_group(&mut self, label: &str) {
144        self.inner.push_debug_group(label);
145    }
146
147    /// Ends the most recently pushed debug group.
148    pub fn pop_debug_group(&mut self) {
149        self.inner.pop_debug_group();
150    }
151
152    /// Draws primitives from the active vertex buffer(s).
153    ///
154    /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
155    /// Does not use an Index Buffer. If you need this see [`RenderBundleEncoder::draw_indexed`]
156    ///
157    /// Panics if vertices Range is outside of the range of the vertices range of any set vertex buffer.
158    ///
159    /// vertices: The range of vertices to draw.
160    /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
161    /// E.g.of how its used internally
162    /// ```rust ignore
163    /// for instance_id in instance_range {
164    ///     for vertex_id in vertex_range {
165    ///         let vertex = vertex[vertex_id];
166    ///         vertex_shader(vertex, vertex_id, instance_id);
167    ///     }
168    /// }
169    /// ```
170    pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
171        self.inner.draw(vertices, instances);
172    }
173
174    /// Draws indexed primitives using the active index buffer and the active vertex buffer(s).
175    ///
176    /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`].
177    /// The active vertex buffer(s) can be set with [`RenderBundleEncoder::set_vertex_buffer`].
178    ///
179    /// Panics if indices Range is outside of the range of the indices range of any set index buffer.
180    ///
181    /// indices: The range of indices to draw.
182    /// base_vertex: value added to each index value before indexing into the vertex buffers.
183    /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
184    /// E.g.of how its used internally
185    /// ```rust ignore
186    /// for instance_id in instance_range {
187    ///     for index_index in index_range {
188    ///         let vertex_id = index_buffer[index_index];
189    ///         let adjusted_vertex_id = vertex_id + base_vertex;
190    ///         let vertex = vertex[adjusted_vertex_id];
191    ///         vertex_shader(vertex, adjusted_vertex_id, instance_id);
192    ///     }
193    /// }
194    /// ```
195    pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
196        self.inner.draw_indexed(indices, base_vertex, instances);
197    }
198
199    /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
200    ///
201    /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
202    ///
203    /// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
204    pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
205        self.inner
206            .draw_indirect(&indirect_buffer.inner, indirect_offset);
207    }
208
209    /// Draws indexed primitives using the active index buffer and the active vertex buffers,
210    /// based on the contents of the `indirect_buffer`.
211    ///
212    /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active
213    /// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
214    ///
215    /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
216    pub fn draw_indexed_indirect(
217        &mut self,
218        indirect_buffer: &'a Buffer,
219        indirect_offset: BufferAddress,
220    ) {
221        self.inner
222            .draw_indexed_indirect(&indirect_buffer.inner, indirect_offset);
223    }
224
225    #[cfg(custom)]
226    /// Returns custom implementation of RenderBundleEncoder (if custom backend and is internally T)
227    pub fn as_custom<T: custom::RenderBundleEncoderInterface>(&self) -> Option<&T> {
228        self.inner.as_custom()
229    }
230}
231
232/// [`Features::IMMEDIATES`] must be enabled on the device in order to call these functions.
233impl RenderBundleEncoder<'_> {
234    /// Set immediate data for subsequent draw calls within the render bundle.
235    ///
236    /// Write the bytes in `data` at offset `offset` within immediate data
237    /// storage. Both `offset` and the length of `data` must be
238    /// multiples of [`crate::IMMEDIATE_DATA_ALIGNMENT`], which is always 4.
239    ///
240    /// For example, if `offset` is `4` and `data` is eight bytes long, this
241    /// call will write `data` to bytes `4..12` of immediate data storage.
242    pub fn set_immediates(&mut self, offset: u32, data: &[u8]) {
243        self.inner.set_immediates(offset, data);
244    }
245}