wgpu/api/command_encoder.rs
1use std::{ops::Range, sync::Arc};
2
3use crate::{
4 api::{
5 blas::BlasBuildEntry,
6 tlas::{TlasBuildEntry, TlasPackage},
7 },
8 *,
9};
10
11/// Encodes a series of GPU operations.
12///
13/// A command encoder can record [`RenderPass`]es, [`ComputePass`]es,
14/// and transfer operations between driver-managed resources like [`Buffer`]s and [`Texture`]s.
15///
16/// When finished recording, call [`CommandEncoder::finish`] to obtain a [`CommandBuffer`] which may
17/// be submitted for execution.
18///
19/// Corresponds to [WebGPU `GPUCommandEncoder`](https://gpuweb.github.io/gpuweb/#command-encoder).
20#[derive(Debug)]
21pub struct CommandEncoder {
22 pub(crate) inner: dispatch::DispatchCommandEncoder,
23}
24#[cfg(send_sync)]
25static_assertions::assert_impl_all!(CommandEncoder: Send, Sync);
26
27crate::cmp::impl_eq_ord_hash_proxy!(CommandEncoder => .inner);
28
29/// Describes a [`CommandEncoder`].
30///
31/// For use with [`Device::create_command_encoder`].
32///
33/// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`](
34/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor).
35pub type CommandEncoderDescriptor<'a> = wgt::CommandEncoderDescriptor<Label<'a>>;
36static_assertions::assert_impl_all!(CommandEncoderDescriptor<'_>: Send, Sync);
37
38use parking_lot::Mutex;
39pub use wgt::TexelCopyBufferInfo as TexelCopyBufferInfoBase;
40/// View of a buffer which can be used to copy to/from a texture.
41///
42/// Corresponds to [WebGPU `GPUTexelCopyBufferInfo`](
43/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
44pub type TexelCopyBufferInfo<'a> = TexelCopyBufferInfoBase<&'a Buffer>;
45#[cfg(send_sync)]
46static_assertions::assert_impl_all!(TexelCopyBufferInfo<'_>: Send, Sync);
47
48pub use wgt::TexelCopyTextureInfo as TexelCopyTextureInfoBase;
49/// View of a texture which can be used to copy to/from a buffer/texture.
50///
51/// Corresponds to [WebGPU `GPUTexelCopyTextureInfo`](
52/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
53pub type TexelCopyTextureInfo<'a> = TexelCopyTextureInfoBase<&'a Texture>;
54#[cfg(send_sync)]
55static_assertions::assert_impl_all!(TexelCopyTextureInfo<'_>: Send, Sync);
56
57impl CommandEncoder {
58 /// Finishes recording and returns a [`CommandBuffer`] that can be submitted for execution.
59 pub fn finish(mut self) -> CommandBuffer {
60 let buffer = self.inner.finish();
61
62 CommandBuffer {
63 inner: Arc::new(Mutex::new(Some(buffer))),
64 }
65 }
66
67 /// Begins recording of a render pass.
68 ///
69 /// This function returns a [`RenderPass`] object which records a single render pass.
70 ///
71 /// As long as the returned [`RenderPass`] has not ended,
72 /// any mutating operation on this command encoder causes an error and invalidates it.
73 /// Note that the `'encoder` lifetime relationship protects against this,
74 /// but it is possible to opt out of it by calling [`RenderPass::forget_lifetime`].
75 /// This can be useful for runtime handling of the encoder->pass
76 /// dependency e.g. when pass and encoder are stored in the same data structure.
77 pub fn begin_render_pass<'encoder>(
78 &'encoder mut self,
79 desc: &RenderPassDescriptor<'_>,
80 ) -> RenderPass<'encoder> {
81 let rpass = self.inner.begin_render_pass(desc);
82 RenderPass {
83 inner: rpass,
84 _encoder_guard: api::PhantomDrop::default(),
85 }
86 }
87
88 /// Begins recording of a compute pass.
89 ///
90 /// This function returns a [`ComputePass`] object which records a single compute pass.
91 ///
92 /// As long as the returned [`ComputePass`] has not ended,
93 /// any mutating operation on this command encoder causes an error and invalidates it.
94 /// Note that the `'encoder` lifetime relationship protects against this,
95 /// but it is possible to opt out of it by calling [`ComputePass::forget_lifetime`].
96 /// This can be useful for runtime handling of the encoder->pass
97 /// dependency e.g. when pass and encoder are stored in the same data structure.
98 pub fn begin_compute_pass<'encoder>(
99 &'encoder mut self,
100 desc: &ComputePassDescriptor<'_>,
101 ) -> ComputePass<'encoder> {
102 let cpass = self.inner.begin_compute_pass(desc);
103 ComputePass {
104 inner: cpass,
105 _encoder_guard: api::PhantomDrop::default(),
106 }
107 }
108
109 /// Copy data from one buffer to another.
110 ///
111 /// # Panics
112 ///
113 /// - Buffer offsets or copy size not a multiple of [`COPY_BUFFER_ALIGNMENT`].
114 /// - Copy would overrun buffer.
115 /// - Copy within the same buffer.
116 pub fn copy_buffer_to_buffer(
117 &mut self,
118 source: &Buffer,
119 source_offset: BufferAddress,
120 destination: &Buffer,
121 destination_offset: BufferAddress,
122 copy_size: BufferAddress,
123 ) {
124 self.inner.copy_buffer_to_buffer(
125 &source.inner,
126 source_offset,
127 &destination.inner,
128 destination_offset,
129 copy_size,
130 );
131 }
132
133 /// Copy data from a buffer to a texture.
134 pub fn copy_buffer_to_texture(
135 &mut self,
136 source: TexelCopyBufferInfo<'_>,
137 destination: TexelCopyTextureInfo<'_>,
138 copy_size: Extent3d,
139 ) {
140 self.inner
141 .copy_buffer_to_texture(source, destination, copy_size);
142 }
143
144 /// Copy data from a texture to a buffer.
145 pub fn copy_texture_to_buffer(
146 &mut self,
147 source: TexelCopyTextureInfo<'_>,
148 destination: TexelCopyBufferInfo<'_>,
149 copy_size: Extent3d,
150 ) {
151 self.inner
152 .copy_texture_to_buffer(source, destination, copy_size);
153 }
154
155 /// Copy data from one texture to another.
156 ///
157 /// # Panics
158 ///
159 /// - Textures are not the same type
160 /// - If a depth texture, or a multisampled texture, the entire texture must be copied
161 /// - Copy would overrun either texture
162 pub fn copy_texture_to_texture(
163 &mut self,
164 source: TexelCopyTextureInfo<'_>,
165 destination: TexelCopyTextureInfo<'_>,
166 copy_size: Extent3d,
167 ) {
168 self.inner
169 .copy_texture_to_texture(source, destination, copy_size);
170 }
171
172 /// Clears texture to zero.
173 ///
174 /// Note that unlike with clear_buffer, `COPY_DST` usage is not required.
175 ///
176 /// # Implementation notes
177 ///
178 /// - implemented either via buffer copies and render/depth target clear, path depends on texture usages
179 /// - behaves like texture zero init, but is performed immediately (clearing is *not* delayed via marking it as uninitialized)
180 ///
181 /// # Panics
182 ///
183 /// - `CLEAR_TEXTURE` extension not enabled
184 /// - Range is out of bounds
185 pub fn clear_texture(&mut self, texture: &Texture, subresource_range: &ImageSubresourceRange) {
186 self.inner.clear_texture(&texture.inner, subresource_range);
187 }
188
189 /// Clears buffer to zero.
190 ///
191 /// # Panics
192 ///
193 /// - Buffer does not have `COPY_DST` usage.
194 /// - Range is out of bounds
195 pub fn clear_buffer(
196 &mut self,
197 buffer: &Buffer,
198 offset: BufferAddress,
199 size: Option<BufferAddress>,
200 ) {
201 self.inner.clear_buffer(&buffer.inner, offset, size);
202 }
203
204 /// Inserts debug marker.
205 pub fn insert_debug_marker(&mut self, label: &str) {
206 self.inner.insert_debug_marker(label);
207 }
208
209 /// Start record commands and group it into debug marker group.
210 pub fn push_debug_group(&mut self, label: &str) {
211 self.inner.push_debug_group(label);
212 }
213
214 /// Stops command recording and creates debug group.
215 pub fn pop_debug_group(&mut self) {
216 self.inner.pop_debug_group();
217 }
218
219 /// Resolves a query set, writing the results into the supplied destination buffer.
220 ///
221 /// Occlusion and timestamp queries are 8 bytes each (see [`crate::QUERY_SIZE`]). For pipeline statistics queries,
222 /// see [`PipelineStatisticsTypes`] for more information.
223 pub fn resolve_query_set(
224 &mut self,
225 query_set: &QuerySet,
226 query_range: Range<u32>,
227 destination: &Buffer,
228 destination_offset: BufferAddress,
229 ) {
230 self.inner.resolve_query_set(
231 &query_set.inner,
232 query_range.start,
233 query_range.end - query_range.start,
234 &destination.inner,
235 destination_offset,
236 );
237 }
238
239 /// Returns the inner hal CommandEncoder using a callback. The hal command encoder will be `None` if the
240 /// backend type argument does not match with this wgpu CommandEncoder
241 ///
242 /// This method will start the wgpu_core level command recording.
243 ///
244 /// # Safety
245 ///
246 /// - The raw handle obtained from the hal CommandEncoder must not be manually destroyed
247 #[cfg(wgpu_core)]
248 pub unsafe fn as_hal_mut<
249 A: wgc::hal_api::HalApi,
250 F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
251 R,
252 >(
253 &mut self,
254 hal_command_encoder_callback: F,
255 ) -> R {
256 if let Some(encoder) = self.inner.as_core_mut_opt() {
257 unsafe {
258 encoder
259 .context
260 .command_encoder_as_hal_mut::<A, F, R>(encoder, hal_command_encoder_callback)
261 }
262 } else {
263 hal_command_encoder_callback(None)
264 }
265 }
266}
267
268/// [`Features::TIMESTAMP_QUERY_INSIDE_ENCODERS`] must be enabled on the device in order to call these functions.
269impl CommandEncoder {
270 /// Issue a timestamp command at this point in the queue.
271 /// The timestamp will be written to the specified query set, at the specified index.
272 ///
273 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
274 /// the value in nanoseconds. Absolute values have no meaning,
275 /// but timestamps can be subtracted to get the time it takes
276 /// for a string of operations to complete.
277 ///
278 /// Attention: Since commands within a command recorder may be reordered,
279 /// there is no strict guarantee that timestamps are taken after all commands
280 /// recorded so far and all before all commands recorded after.
281 /// This may depend both on the backend and the driver.
282 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
283 self.inner.write_timestamp(&query_set.inner, query_index);
284 }
285}
286
287/// [`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE`] must be enabled on the device in order to call these functions.
288impl CommandEncoder {
289 /// Build bottom and top level acceleration structures.
290 ///
291 /// Builds the BLASes then the TLASes, but does ***not*** build the BLASes into the TLASes,
292 /// that must be done by setting a TLAS instance in the TLAS package to one that contains the BLAS (and with an appropriate transform)
293 ///
294 /// # Validation
295 ///
296 /// - blas: Iterator of bottom level acceleration structure entries to build.
297 /// For each entry, the provided size descriptor must be strictly smaller or equal to the descriptor given at BLAS creation, this means:
298 /// - Less or equal number of geometries
299 /// - Same kind of geometry (with index buffer or without) (same vertex/index format)
300 /// - Same flags
301 /// - Less or equal number of vertices
302 /// - Less or equal number of indices (if applicable)
303 /// - tlas: iterator of top level acceleration structure packages to build
304 /// For each entry:
305 /// - Each BLAS in each TLAS instance must have been being built in the current call or in a previous call to `build_acceleration_structures` or `build_acceleration_structures_unsafe_tlas`
306 /// - The number of TLAS instances must be less than or equal to the max number of tlas instances when creating (if creating a package with `TlasPackage::new()` this is already satisfied)
307 ///
308 /// If the device the command encoder is created from does not have [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE] enabled then a validation error is generated
309 ///
310 /// A bottom level acceleration structure may be build and used as a reference in a top level acceleration structure in the same invocation of this function.
311 ///
312 /// # Bind group usage
313 ///
314 /// When a top level acceleration structure is used in a bind group, some validation takes place:
315 /// - The top level acceleration structure is valid and has been built.
316 /// - All the bottom level acceleration structures referenced by the top level acceleration structure are valid and have been built prior,
317 /// or at same time as the containing top level acceleration structure.
318 ///
319 /// [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE]: wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
320 pub fn build_acceleration_structures<'a>(
321 &mut self,
322 blas: impl IntoIterator<Item = &'a BlasBuildEntry<'a>>,
323 tlas: impl IntoIterator<Item = &'a TlasPackage>,
324 ) {
325 self.inner
326 .build_acceleration_structures(&mut blas.into_iter(), &mut tlas.into_iter());
327 }
328
329 /// Build bottom and top level acceleration structures.
330 /// See [`CommandEncoder::build_acceleration_structures`] for the safe version and more details. All validation in [`CommandEncoder::build_acceleration_structures`] except that
331 /// listed under tlas applies here as well.
332 ///
333 /// # Safety
334 ///
335 /// - The contents of the raw instance buffer must be valid for the underling api.
336 /// - All bottom level acceleration structures, referenced in the raw instance buffer must be valid and built,
337 /// when the corresponding top level acceleration structure is built. (builds may happen in the same invocation of this function).
338 /// - At the time when the top level acceleration structure is used in a bind group, all associated bottom level acceleration structures must be valid,
339 /// and built (no later than the time when the top level acceleration structure was built).
340 pub unsafe fn build_acceleration_structures_unsafe_tlas<'a>(
341 &mut self,
342 blas: impl IntoIterator<Item = &'a BlasBuildEntry<'a>>,
343 tlas: impl IntoIterator<Item = &'a TlasBuildEntry<'a>>,
344 ) {
345 self.inner.build_acceleration_structures_unsafe_tlas(
346 &mut blas.into_iter(),
347 &mut tlas.into_iter(),
348 );
349 }
350}