wgpu/api/
command_encoder.rs

1use std::{marker::PhantomData, ops::Range, sync::Arc, thread};
2
3use crate::context::DynContext;
4use crate::*;
5
6/// Encodes a series of GPU operations.
7///
8/// A command encoder can record [`RenderPass`]es, [`ComputePass`]es,
9/// and transfer operations between driver-managed resources like [`Buffer`]s and [`Texture`]s.
10///
11/// When finished recording, call [`CommandEncoder::finish`] to obtain a [`CommandBuffer`] which may
12/// be submitted for execution.
13///
14/// Corresponds to [WebGPU `GPUCommandEncoder`](https://gpuweb.github.io/gpuweb/#command-encoder).
15#[derive(Debug)]
16pub struct CommandEncoder {
17    pub(crate) context: Arc<C>,
18    pub(crate) data: Box<Data>,
19}
20#[cfg(send_sync)]
21static_assertions::assert_impl_all!(CommandEncoder: Send, Sync);
22
23impl Drop for CommandEncoder {
24    fn drop(&mut self) {
25        if !thread::panicking() {
26            self.context.command_encoder_drop(self.data.as_ref());
27        }
28    }
29}
30
31/// Describes a [`CommandEncoder`].
32///
33/// For use with [`Device::create_command_encoder`].
34///
35/// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`](
36/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor).
37pub type CommandEncoderDescriptor<'a> = wgt::CommandEncoderDescriptor<Label<'a>>;
38static_assertions::assert_impl_all!(CommandEncoderDescriptor<'_>: Send, Sync);
39
40pub use wgt::ImageCopyBuffer as ImageCopyBufferBase;
41/// View of a buffer which can be used to copy to/from a texture.
42///
43/// Corresponds to [WebGPU `GPUImageCopyBuffer`](
44/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
45pub type ImageCopyBuffer<'a> = ImageCopyBufferBase<&'a Buffer>;
46#[cfg(send_sync)]
47static_assertions::assert_impl_all!(ImageCopyBuffer<'_>: Send, Sync);
48
49pub use wgt::ImageCopyTexture as ImageCopyTextureBase;
50/// View of a texture which can be used to copy to/from a buffer/texture.
51///
52/// Corresponds to [WebGPU `GPUImageCopyTexture`](
53/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
54pub type ImageCopyTexture<'a> = ImageCopyTextureBase<&'a Texture>;
55#[cfg(send_sync)]
56static_assertions::assert_impl_all!(ImageCopyTexture<'_>: Send, Sync);
57
58pub use wgt::ImageCopyTextureTagged as ImageCopyTextureTaggedBase;
59/// View of a texture which can be used to copy to a texture, including
60/// color space and alpha premultiplication information.
61///
62/// Corresponds to [WebGPU `GPUImageCopyTextureTagged`](
63/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged).
64pub type ImageCopyTextureTagged<'a> = ImageCopyTextureTaggedBase<&'a Texture>;
65#[cfg(send_sync)]
66static_assertions::assert_impl_all!(ImageCopyTexture<'_>: Send, Sync);
67
68impl CommandEncoder {
69    /// Finishes recording and returns a [`CommandBuffer`] that can be submitted for execution.
70    pub fn finish(mut self) -> CommandBuffer {
71        let data = DynContext::command_encoder_finish(&*self.context, self.data.as_mut());
72        CommandBuffer {
73            context: Arc::clone(&self.context),
74            data: Some(data),
75        }
76    }
77
78    /// Begins recording of a render pass.
79    ///
80    /// This function returns a [`RenderPass`] object which records a single render pass.
81    ///
82    /// As long as the returned  [`RenderPass`] has not ended,
83    /// any mutating operation on this command encoder causes an error and invalidates it.
84    /// Note that the `'encoder` lifetime relationship protects against this,
85    /// but it is possible to opt out of it by calling [`RenderPass::forget_lifetime`].
86    /// This can be useful for runtime handling of the encoder->pass
87    /// dependency e.g. when pass and encoder are stored in the same data structure.
88    pub fn begin_render_pass<'encoder>(
89        &'encoder mut self,
90        desc: &RenderPassDescriptor<'_>,
91    ) -> RenderPass<'encoder> {
92        let data =
93            DynContext::command_encoder_begin_render_pass(&*self.context, self.data.as_ref(), desc);
94        RenderPass {
95            inner: RenderPassInner {
96                data,
97                context: self.context.clone(),
98            },
99            encoder_guard: PhantomData,
100        }
101    }
102
103    /// Begins recording of a compute pass.
104    ///
105    /// This function returns a [`ComputePass`] object which records a single compute pass.
106    ///
107    /// As long as the returned  [`ComputePass`] has not ended,
108    /// any mutating operation on this command encoder causes an error and invalidates it.
109    /// Note that the `'encoder` lifetime relationship protects against this,
110    /// but it is possible to opt out of it by calling [`ComputePass::forget_lifetime`].
111    /// This can be useful for runtime handling of the encoder->pass
112    /// dependency e.g. when pass and encoder are stored in the same data structure.
113    pub fn begin_compute_pass<'encoder>(
114        &'encoder mut self,
115        desc: &ComputePassDescriptor<'_>,
116    ) -> ComputePass<'encoder> {
117        let data = DynContext::command_encoder_begin_compute_pass(
118            &*self.context,
119            self.data.as_ref(),
120            desc,
121        );
122        ComputePass {
123            inner: ComputePassInner {
124                data,
125                context: self.context.clone(),
126            },
127            encoder_guard: PhantomData,
128        }
129    }
130
131    /// Copy data from one buffer to another.
132    ///
133    /// # Panics
134    ///
135    /// - Buffer offsets or copy size not a multiple of [`COPY_BUFFER_ALIGNMENT`].
136    /// - Copy would overrun buffer.
137    /// - Copy within the same buffer.
138    pub fn copy_buffer_to_buffer(
139        &mut self,
140        source: &Buffer,
141        source_offset: BufferAddress,
142        destination: &Buffer,
143        destination_offset: BufferAddress,
144        copy_size: BufferAddress,
145    ) {
146        DynContext::command_encoder_copy_buffer_to_buffer(
147            &*self.context,
148            self.data.as_ref(),
149            source.data.as_ref(),
150            source_offset,
151            destination.data.as_ref(),
152            destination_offset,
153            copy_size,
154        );
155    }
156
157    /// Copy data from a buffer to a texture.
158    pub fn copy_buffer_to_texture(
159        &mut self,
160        source: ImageCopyBuffer<'_>,
161        destination: ImageCopyTexture<'_>,
162        copy_size: Extent3d,
163    ) {
164        DynContext::command_encoder_copy_buffer_to_texture(
165            &*self.context,
166            self.data.as_ref(),
167            source,
168            destination,
169            copy_size,
170        );
171    }
172
173    /// Copy data from a texture to a buffer.
174    pub fn copy_texture_to_buffer(
175        &mut self,
176        source: ImageCopyTexture<'_>,
177        destination: ImageCopyBuffer<'_>,
178        copy_size: Extent3d,
179    ) {
180        DynContext::command_encoder_copy_texture_to_buffer(
181            &*self.context,
182            self.data.as_ref(),
183            source,
184            destination,
185            copy_size,
186        );
187    }
188
189    /// Copy data from one texture to another.
190    ///
191    /// # Panics
192    ///
193    /// - Textures are not the same type
194    /// - If a depth texture, or a multisampled texture, the entire texture must be copied
195    /// - Copy would overrun either texture
196    pub fn copy_texture_to_texture(
197        &mut self,
198        source: ImageCopyTexture<'_>,
199        destination: ImageCopyTexture<'_>,
200        copy_size: Extent3d,
201    ) {
202        DynContext::command_encoder_copy_texture_to_texture(
203            &*self.context,
204            self.data.as_ref(),
205            source,
206            destination,
207            copy_size,
208        );
209    }
210
211    /// Clears texture to zero.
212    ///
213    /// Note that unlike with clear_buffer, `COPY_DST` usage is not required.
214    ///
215    /// # Implementation notes
216    ///
217    /// - implemented either via buffer copies and render/depth target clear, path depends on texture usages
218    /// - behaves like texture zero init, but is performed immediately (clearing is *not* delayed via marking it as uninitialized)
219    ///
220    /// # Panics
221    ///
222    /// - `CLEAR_TEXTURE` extension not enabled
223    /// - Range is out of bounds
224    pub fn clear_texture(&mut self, texture: &Texture, subresource_range: &ImageSubresourceRange) {
225        DynContext::command_encoder_clear_texture(
226            &*self.context,
227            self.data.as_ref(),
228            texture.data.as_ref(),
229            subresource_range,
230        );
231    }
232
233    /// Clears buffer to zero.
234    ///
235    /// # Panics
236    ///
237    /// - Buffer does not have `COPY_DST` usage.
238    /// - Range is out of bounds
239    pub fn clear_buffer(
240        &mut self,
241        buffer: &Buffer,
242        offset: BufferAddress,
243        size: Option<BufferAddress>,
244    ) {
245        DynContext::command_encoder_clear_buffer(
246            &*self.context,
247            self.data.as_ref(),
248            buffer.data.as_ref(),
249            offset,
250            size,
251        );
252    }
253
254    /// Inserts debug marker.
255    pub fn insert_debug_marker(&mut self, label: &str) {
256        DynContext::command_encoder_insert_debug_marker(&*self.context, self.data.as_ref(), label);
257    }
258
259    /// Start record commands and group it into debug marker group.
260    pub fn push_debug_group(&mut self, label: &str) {
261        DynContext::command_encoder_push_debug_group(&*self.context, self.data.as_ref(), label);
262    }
263
264    /// Stops command recording and creates debug group.
265    pub fn pop_debug_group(&mut self) {
266        DynContext::command_encoder_pop_debug_group(&*self.context, self.data.as_ref());
267    }
268
269    /// Resolves a query set, writing the results into the supplied destination buffer.
270    ///
271    /// Occlusion and timestamp queries are 8 bytes each (see [`crate::QUERY_SIZE`]). For pipeline statistics queries,
272    /// see [`PipelineStatisticsTypes`] for more information.
273    pub fn resolve_query_set(
274        &mut self,
275        query_set: &QuerySet,
276        query_range: Range<u32>,
277        destination: &Buffer,
278        destination_offset: BufferAddress,
279    ) {
280        DynContext::command_encoder_resolve_query_set(
281            &*self.context,
282            self.data.as_ref(),
283            query_set.data.as_ref(),
284            query_range.start,
285            query_range.end - query_range.start,
286            destination.data.as_ref(),
287            destination_offset,
288        )
289    }
290
291    /// Returns the inner hal CommandEncoder using a callback. The hal command encoder will be `None` if the
292    /// backend type argument does not match with this wgpu CommandEncoder
293    ///
294    /// This method will start the wgpu_core level command recording.
295    ///
296    /// # Safety
297    ///
298    /// - The raw handle obtained from the hal CommandEncoder must not be manually destroyed
299    #[cfg(wgpu_core)]
300    pub unsafe fn as_hal_mut<
301        A: wgc::hal_api::HalApi,
302        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
303        R,
304    >(
305        &mut self,
306        hal_command_encoder_callback: F,
307    ) -> Option<R> {
308        self.context
309            .as_any()
310            .downcast_ref::<crate::backend::ContextWgpuCore>()
311            .map(|ctx| unsafe {
312                ctx.command_encoder_as_hal_mut::<A, F, R>(
313                    crate::context::downcast_ref(self.data.as_ref()),
314                    hal_command_encoder_callback,
315                )
316            })
317    }
318}
319
320/// [`Features::TIMESTAMP_QUERY_INSIDE_ENCODERS`] must be enabled on the device in order to call these functions.
321impl CommandEncoder {
322    /// Issue a timestamp command at this point in the queue.
323    /// The timestamp will be written to the specified query set, at the specified index.
324    ///
325    /// Must be multiplied by [`Queue::get_timestamp_period`] to get
326    /// the value in nanoseconds. Absolute values have no meaning,
327    /// but timestamps can be subtracted to get the time it takes
328    /// for a string of operations to complete.
329    ///
330    /// Attention: Since commands within a command recorder may be reordered,
331    /// there is no strict guarantee that timestamps are taken after all commands
332    /// recorded so far and all before all commands recorded after.
333    /// This may depend both on the backend and the driver.
334    pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
335        DynContext::command_encoder_write_timestamp(
336            &*self.context,
337            self.data.as_mut(),
338            query_set.data.as_ref(),
339            query_index,
340        )
341    }
342}