wgpu/api/compute_pass.rs
1use std::{marker::PhantomData, sync::Arc, thread};
2
3use crate::context::DynContext;
4use crate::*;
5
6/// In-progress recording of a compute pass.
7///
8/// It can be created with [`CommandEncoder::begin_compute_pass`].
9///
10/// Corresponds to [WebGPU `GPUComputePassEncoder`](
11/// https://gpuweb.github.io/gpuweb/#compute-pass-encoder).
12#[derive(Debug)]
13pub struct ComputePass<'encoder> {
14 /// The inner data of the compute pass, separated out so it's easy to replace the lifetime with 'static if desired.
15 pub(crate) inner: ComputePassInner,
16
17 /// This lifetime is used to protect the [`CommandEncoder`] from being used
18 /// while the pass is alive.
19 pub(crate) encoder_guard: PhantomData<&'encoder ()>,
20}
21
22impl<'encoder> ComputePass<'encoder> {
23 /// Drops the lifetime relationship to the parent command encoder, making usage of
24 /// the encoder while this pass is recorded a run-time error instead.
25 ///
26 /// Attention: As long as the compute pass has not been ended, any mutating operation on the parent
27 /// command encoder will cause a run-time error and invalidate it!
28 /// By default, the lifetime constraint prevents this, but it can be useful
29 /// to handle this at run time, such as when storing the pass and encoder in the same
30 /// data structure.
31 ///
32 /// This operation has no effect on pass recording.
33 /// It's a safe operation, since [`CommandEncoder`] is in a locked state as long as the pass is active
34 /// regardless of the lifetime constraint or its absence.
35 pub fn forget_lifetime(self) -> ComputePass<'static> {
36 ComputePass {
37 inner: self.inner,
38 encoder_guard: PhantomData,
39 }
40 }
41
42 /// Sets the active bind group for a given bind group index. The bind group layout
43 /// in the active pipeline when the `dispatch()` function is called must match the layout of this bind group.
44 ///
45 /// If the bind group have dynamic offsets, provide them in the binding order.
46 /// These offsets have to be aligned to [`Limits::min_uniform_buffer_offset_alignment`]
47 /// or [`Limits::min_storage_buffer_offset_alignment`] appropriately.
48 pub fn set_bind_group<'a>(
49 &mut self,
50 index: u32,
51 bind_group: impl Into<Option<&'a BindGroup>>,
52 offsets: &[DynamicOffset],
53 ) {
54 let bg = bind_group.into().map(|x| x.data.as_ref());
55 DynContext::compute_pass_set_bind_group(
56 &*self.inner.context,
57 self.inner.data.as_mut(),
58 index,
59 bg,
60 offsets,
61 );
62 }
63
64 /// Sets the active compute pipeline.
65 pub fn set_pipeline(&mut self, pipeline: &ComputePipeline) {
66 DynContext::compute_pass_set_pipeline(
67 &*self.inner.context,
68 self.inner.data.as_mut(),
69 pipeline.data.as_ref(),
70 );
71 }
72
73 /// Inserts debug marker.
74 pub fn insert_debug_marker(&mut self, label: &str) {
75 DynContext::compute_pass_insert_debug_marker(
76 &*self.inner.context,
77 self.inner.data.as_mut(),
78 label,
79 );
80 }
81
82 /// Start record commands and group it into debug marker group.
83 pub fn push_debug_group(&mut self, label: &str) {
84 DynContext::compute_pass_push_debug_group(
85 &*self.inner.context,
86 self.inner.data.as_mut(),
87 label,
88 );
89 }
90
91 /// Stops command recording and creates debug group.
92 pub fn pop_debug_group(&mut self) {
93 DynContext::compute_pass_pop_debug_group(&*self.inner.context, self.inner.data.as_mut());
94 }
95
96 /// Dispatches compute work operations.
97 ///
98 /// `x`, `y` and `z` denote the number of work groups to dispatch in each dimension.
99 pub fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32) {
100 DynContext::compute_pass_dispatch_workgroups(
101 &*self.inner.context,
102 self.inner.data.as_mut(),
103 x,
104 y,
105 z,
106 );
107 }
108
109 /// Dispatches compute work operations, based on the contents of the `indirect_buffer`.
110 ///
111 /// The structure expected in `indirect_buffer` must conform to [`DispatchIndirectArgs`](crate::util::DispatchIndirectArgs).
112 pub fn dispatch_workgroups_indirect(
113 &mut self,
114 indirect_buffer: &Buffer,
115 indirect_offset: BufferAddress,
116 ) {
117 DynContext::compute_pass_dispatch_workgroups_indirect(
118 &*self.inner.context,
119 self.inner.data.as_mut(),
120 indirect_buffer.data.as_ref(),
121 indirect_offset,
122 );
123 }
124}
125
126/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
127impl<'encoder> ComputePass<'encoder> {
128 /// Set push constant data for subsequent dispatch calls.
129 ///
130 /// Write the bytes in `data` at offset `offset` within push constant
131 /// storage. Both `offset` and the length of `data` must be
132 /// multiples of [`PUSH_CONSTANT_ALIGNMENT`], which is always 4.
133 ///
134 /// For example, if `offset` is `4` and `data` is eight bytes long, this
135 /// call will write `data` to bytes `4..12` of push constant storage.
136 pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
137 DynContext::compute_pass_set_push_constants(
138 &*self.inner.context,
139 self.inner.data.as_mut(),
140 offset,
141 data,
142 );
143 }
144}
145
146/// [`Features::TIMESTAMP_QUERY_INSIDE_PASSES`] must be enabled on the device in order to call these functions.
147impl<'encoder> ComputePass<'encoder> {
148 /// Issue a timestamp command at this point in the queue. The timestamp will be written to the specified query set, at the specified index.
149 ///
150 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
151 /// the value in nanoseconds. Absolute values have no meaning,
152 /// but timestamps can be subtracted to get the time it takes
153 /// for a string of operations to complete.
154 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
155 DynContext::compute_pass_write_timestamp(
156 &*self.inner.context,
157 self.inner.data.as_mut(),
158 query_set.data.as_ref(),
159 query_index,
160 )
161 }
162}
163
164/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
165impl<'encoder> ComputePass<'encoder> {
166 /// Start a pipeline statistics query on this compute pass. It can be ended with
167 /// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
168 pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
169 DynContext::compute_pass_begin_pipeline_statistics_query(
170 &*self.inner.context,
171 self.inner.data.as_mut(),
172 query_set.data.as_ref(),
173 query_index,
174 );
175 }
176
177 /// End the pipeline statistics query on this compute pass. It can be started with
178 /// `begin_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
179 pub fn end_pipeline_statistics_query(&mut self) {
180 DynContext::compute_pass_end_pipeline_statistics_query(
181 &*self.inner.context,
182 self.inner.data.as_mut(),
183 );
184 }
185}
186
187#[derive(Debug)]
188pub(crate) struct ComputePassInner {
189 pub(crate) data: Box<Data>,
190 pub(crate) context: Arc<C>,
191}
192
193impl Drop for ComputePassInner {
194 fn drop(&mut self) {
195 if !thread::panicking() {
196 self.context.compute_pass_end(self.data.as_mut());
197 }
198 }
199}
200
201/// Describes the timestamp writes of a compute pass.
202///
203/// For use with [`ComputePassDescriptor`].
204/// At least one of `beginning_of_pass_write_index` and `end_of_pass_write_index` must be `Some`.
205///
206/// Corresponds to [WebGPU `GPUComputePassTimestampWrites`](
207/// https://gpuweb.github.io/gpuweb/#dictdef-gpucomputepasstimestampwrites).
208#[derive(Clone, Debug)]
209pub struct ComputePassTimestampWrites<'a> {
210 /// The query set to write to.
211 pub query_set: &'a QuerySet,
212 /// The index of the query set at which a start timestamp of this pass is written, if any.
213 pub beginning_of_pass_write_index: Option<u32>,
214 /// The index of the query set at which an end timestamp of this pass is written, if any.
215 pub end_of_pass_write_index: Option<u32>,
216}
217#[cfg(send_sync)]
218static_assertions::assert_impl_all!(ComputePassTimestampWrites<'_>: Send, Sync);
219
220/// Describes the attachments of a compute pass.
221///
222/// For use with [`CommandEncoder::begin_compute_pass`].
223///
224/// Corresponds to [WebGPU `GPUComputePassDescriptor`](
225/// https://gpuweb.github.io/gpuweb/#dictdef-gpucomputepassdescriptor).
226#[derive(Clone, Default, Debug)]
227pub struct ComputePassDescriptor<'a> {
228 /// Debug label of the compute pass. This will show up in graphics debuggers for easy identification.
229 pub label: Label<'a>,
230 /// Defines which timestamp values will be written for this pass, and where to write them to.
231 ///
232 /// Requires [`Features::TIMESTAMP_QUERY`] to be enabled.
233 pub timestamp_writes: Option<ComputePassTimestampWrites<'a>>,
234}
235#[cfg(send_sync)]
236static_assertions::assert_impl_all!(ComputePassDescriptor<'_>: Send, Sync);