wgpu_core/command/
render_command.rs

1use alloc::sync::Arc;
2
3use wgt::{BufferAddress, BufferSize, Color};
4
5use super::{DrawCommandFamily, Rect, RenderBundle};
6use crate::{
7    binding_model::BindGroup,
8    id,
9    pipeline::RenderPipeline,
10    resource::{Buffer, QuerySet},
11};
12
13#[doc(hidden)]
14#[derive(Clone, Copy, Debug)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub enum RenderCommand {
17    SetBindGroup {
18        index: u32,
19        num_dynamic_offsets: usize,
20        bind_group_id: Option<id::BindGroupId>,
21    },
22    SetPipeline(id::RenderPipelineId),
23    SetIndexBuffer {
24        buffer_id: id::BufferId,
25        index_format: wgt::IndexFormat,
26        offset: BufferAddress,
27        size: Option<BufferSize>,
28    },
29    SetVertexBuffer {
30        slot: u32,
31        buffer_id: id::BufferId,
32        offset: BufferAddress,
33        size: Option<BufferSize>,
34    },
35    SetBlendConstant(Color),
36    SetStencilReference(u32),
37    SetViewport {
38        rect: Rect<f32>,
39        //TODO: use half-float to reduce the size?
40        depth_min: f32,
41        depth_max: f32,
42    },
43    SetScissor(Rect<u32>),
44
45    /// Set a range of push constants to values stored in [`BasePass::push_constant_data`].
46    ///
47    /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation
48    /// of the restrictions these commands must satisfy.
49    SetPushConstant {
50        /// Which stages we are setting push constant values for.
51        stages: wgt::ShaderStages,
52
53        /// The byte offset within the push constant storage to write to.  This
54        /// must be a multiple of four.
55        offset: u32,
56
57        /// The number of bytes to write. This must be a multiple of four.
58        size_bytes: u32,
59
60        /// Index in [`BasePass::push_constant_data`] of the start of the data
61        /// to be written.
62        ///
63        /// Note: this is not a byte offset like `offset`. Rather, it is the
64        /// index of the first `u32` element in `push_constant_data` to read.
65        ///
66        /// `None` means zeros should be written to the destination range, and
67        /// there is no corresponding data in `push_constant_data`. This is used
68        /// by render bundles, which explicitly clear out any state that
69        /// post-bundle code might see.
70        values_offset: Option<u32>,
71    },
72    Draw {
73        vertex_count: u32,
74        instance_count: u32,
75        first_vertex: u32,
76        first_instance: u32,
77    },
78    DrawIndexed {
79        index_count: u32,
80        instance_count: u32,
81        first_index: u32,
82        base_vertex: i32,
83        first_instance: u32,
84    },
85    DrawMeshTasks {
86        group_count_x: u32,
87        group_count_y: u32,
88        group_count_z: u32,
89    },
90    DrawIndirect {
91        buffer_id: id::BufferId,
92        offset: BufferAddress,
93        count: u32,
94        family: DrawCommandFamily,
95    },
96    MultiDrawIndirectCount {
97        buffer_id: id::BufferId,
98        offset: BufferAddress,
99        count_buffer_id: id::BufferId,
100        count_buffer_offset: BufferAddress,
101        max_count: u32,
102        family: DrawCommandFamily,
103    },
104    PushDebugGroup {
105        color: u32,
106        len: usize,
107    },
108    PopDebugGroup,
109    InsertDebugMarker {
110        color: u32,
111        len: usize,
112    },
113    WriteTimestamp {
114        query_set_id: id::QuerySetId,
115        query_index: u32,
116    },
117    BeginOcclusionQuery {
118        query_index: u32,
119    },
120    EndOcclusionQuery,
121    BeginPipelineStatisticsQuery {
122        query_set_id: id::QuerySetId,
123        query_index: u32,
124    },
125    EndPipelineStatisticsQuery,
126    ExecuteBundle(id::RenderBundleId),
127}
128
129impl RenderCommand {
130    /// Resolves all ids in a list of commands into the corresponding resource Arc.
131    #[cfg(any(feature = "serde", feature = "replay"))]
132    pub fn resolve_render_command_ids(
133        hub: &crate::hub::Hub,
134        commands: &[RenderCommand],
135    ) -> Result<alloc::vec::Vec<ArcRenderCommand>, super::RenderPassError> {
136        use super::{DrawKind, PassErrorScope, RenderPassError};
137        use alloc::vec::Vec;
138
139        let buffers_guard = hub.buffers.read();
140        let bind_group_guard = hub.bind_groups.read();
141        let query_set_guard = hub.query_sets.read();
142        let pipelines_guard = hub.render_pipelines.read();
143        let render_bundles_guard = hub.render_bundles.read();
144
145        let resolved_commands: Vec<ArcRenderCommand> =
146            commands
147                .iter()
148                .map(|c| -> Result<ArcRenderCommand, RenderPassError> {
149                    Ok(match *c {
150                        RenderCommand::SetBindGroup {
151                            index,
152                            num_dynamic_offsets,
153                            bind_group_id,
154                        } => {
155                            if bind_group_id.is_none() {
156                                return Ok(ArcRenderCommand::SetBindGroup {
157                                    index,
158                                    num_dynamic_offsets,
159                                    bind_group: None,
160                                });
161                            }
162
163                            let bind_group_id = bind_group_id.unwrap();
164                            let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| {
165                                RenderPassError {
166                                    scope: PassErrorScope::SetBindGroup,
167                                    inner: e.into(),
168                                }
169                            })?;
170
171                            ArcRenderCommand::SetBindGroup {
172                                index,
173                                num_dynamic_offsets,
174                                bind_group: Some(bg),
175                            }
176                        }
177
178                        RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline(
179                            pipelines_guard.get(pipeline_id).get().map_err(|e| {
180                                RenderPassError {
181                                    scope: PassErrorScope::SetPipelineRender,
182                                    inner: e.into(),
183                                }
184                            })?,
185                        ),
186
187                        RenderCommand::SetPushConstant {
188                            offset,
189                            size_bytes,
190                            values_offset,
191                            stages,
192                        } => ArcRenderCommand::SetPushConstant {
193                            offset,
194                            size_bytes,
195                            values_offset,
196                            stages,
197                        },
198
199                        RenderCommand::PushDebugGroup { color, len } => {
200                            ArcRenderCommand::PushDebugGroup { color, len }
201                        }
202
203                        RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup,
204
205                        RenderCommand::InsertDebugMarker { color, len } => {
206                            ArcRenderCommand::InsertDebugMarker { color, len }
207                        }
208
209                        RenderCommand::WriteTimestamp {
210                            query_set_id,
211                            query_index,
212                        } => ArcRenderCommand::WriteTimestamp {
213                            query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
214                                RenderPassError {
215                                    scope: PassErrorScope::WriteTimestamp,
216                                    inner: e.into(),
217                                }
218                            })?,
219                            query_index,
220                        },
221
222                        RenderCommand::BeginPipelineStatisticsQuery {
223                            query_set_id,
224                            query_index,
225                        } => ArcRenderCommand::BeginPipelineStatisticsQuery {
226                            query_set: query_set_guard.get(query_set_id).get().map_err(|e| {
227                                RenderPassError {
228                                    scope: PassErrorScope::BeginPipelineStatisticsQuery,
229                                    inner: e.into(),
230                                }
231                            })?,
232                            query_index,
233                        },
234
235                        RenderCommand::EndPipelineStatisticsQuery => {
236                            ArcRenderCommand::EndPipelineStatisticsQuery
237                        }
238
239                        RenderCommand::SetIndexBuffer {
240                            buffer_id,
241                            index_format,
242                            offset,
243                            size,
244                        } => ArcRenderCommand::SetIndexBuffer {
245                            buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
246                                RenderPassError {
247                                    scope: PassErrorScope::SetIndexBuffer,
248                                    inner: e.into(),
249                                }
250                            })?,
251                            index_format,
252                            offset,
253                            size,
254                        },
255
256                        RenderCommand::SetVertexBuffer {
257                            slot,
258                            buffer_id,
259                            offset,
260                            size,
261                        } => ArcRenderCommand::SetVertexBuffer {
262                            slot,
263                            buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
264                                RenderPassError {
265                                    scope: PassErrorScope::SetVertexBuffer,
266                                    inner: e.into(),
267                                }
268                            })?,
269                            offset,
270                            size,
271                        },
272
273                        RenderCommand::SetBlendConstant(color) => {
274                            ArcRenderCommand::SetBlendConstant(color)
275                        }
276
277                        RenderCommand::SetStencilReference(reference) => {
278                            ArcRenderCommand::SetStencilReference(reference)
279                        }
280
281                        RenderCommand::SetViewport {
282                            rect,
283                            depth_min,
284                            depth_max,
285                        } => ArcRenderCommand::SetViewport {
286                            rect,
287                            depth_min,
288                            depth_max,
289                        },
290
291                        RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor),
292
293                        RenderCommand::Draw {
294                            vertex_count,
295                            instance_count,
296                            first_vertex,
297                            first_instance,
298                        } => ArcRenderCommand::Draw {
299                            vertex_count,
300                            instance_count,
301                            first_vertex,
302                            first_instance,
303                        },
304
305                        RenderCommand::DrawIndexed {
306                            index_count,
307                            instance_count,
308                            first_index,
309                            base_vertex,
310                            first_instance,
311                        } => ArcRenderCommand::DrawIndexed {
312                            index_count,
313                            instance_count,
314                            first_index,
315                            base_vertex,
316                            first_instance,
317                        },
318                        RenderCommand::DrawMeshTasks {
319                            group_count_x,
320                            group_count_y,
321                            group_count_z,
322                        } => ArcRenderCommand::DrawMeshTasks {
323                            group_count_x,
324                            group_count_y,
325                            group_count_z,
326                        },
327
328                        RenderCommand::DrawIndirect {
329                            buffer_id,
330                            offset,
331                            count,
332                            family,
333                        } => ArcRenderCommand::DrawIndirect {
334                            buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
335                                RenderPassError {
336                                    scope: PassErrorScope::Draw {
337                                        kind: if count != 1 {
338                                            DrawKind::MultiDrawIndirect
339                                        } else {
340                                            DrawKind::DrawIndirect
341                                        },
342                                        family,
343                                    },
344                                    inner: e.into(),
345                                }
346                            })?,
347                            offset,
348                            count,
349                            family,
350
351                            vertex_or_index_limit: 0,
352                            instance_limit: 0,
353                        },
354
355                        RenderCommand::MultiDrawIndirectCount {
356                            buffer_id,
357                            offset,
358                            count_buffer_id,
359                            count_buffer_offset,
360                            max_count,
361                            family,
362                        } => {
363                            let scope = PassErrorScope::Draw {
364                                kind: DrawKind::MultiDrawIndirectCount,
365                                family,
366                            };
367                            ArcRenderCommand::MultiDrawIndirectCount {
368                                buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
369                                    RenderPassError {
370                                        scope,
371                                        inner: e.into(),
372                                    }
373                                })?,
374                                offset,
375                                count_buffer: buffers_guard.get(count_buffer_id).get().map_err(
376                                    |e| RenderPassError {
377                                        scope,
378                                        inner: e.into(),
379                                    },
380                                )?,
381                                count_buffer_offset,
382                                max_count,
383                                family,
384                            }
385                        }
386
387                        RenderCommand::BeginOcclusionQuery { query_index } => {
388                            ArcRenderCommand::BeginOcclusionQuery { query_index }
389                        }
390
391                        RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery,
392
393                        RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle(
394                            render_bundles_guard.get(bundle).get().map_err(|e| {
395                                RenderPassError {
396                                    scope: PassErrorScope::ExecuteBundle,
397                                    inner: e.into(),
398                                }
399                            })?,
400                        ),
401                    })
402                })
403                .collect::<Result<Vec<_>, RenderPassError>>()?;
404        Ok(resolved_commands)
405    }
406}
407
408/// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs.
409///
410/// In a render pass, commands are stored in this format between when they are
411/// added to the pass, and when the pass is `end()`ed and the commands are
412/// replayed to the HAL encoder. Validation occurs when the pass is ended, which
413/// means that parameters stored in an `ArcRenderCommand` for a pass operation
414/// have generally not been validated.
415///
416/// In a render bundle, commands are stored in this format between when the bundle
417/// is `finish()`ed and when the bundle is executed. Validation occurs when the
418/// bundle is finished, which means that parameters stored in an `ArcRenderCommand`
419/// for a render bundle operation must have been validated.
420#[doc(hidden)]
421#[derive(Clone, Debug)]
422pub enum ArcRenderCommand {
423    SetBindGroup {
424        index: u32,
425        num_dynamic_offsets: usize,
426        bind_group: Option<Arc<BindGroup>>,
427    },
428    SetPipeline(Arc<RenderPipeline>),
429    SetIndexBuffer {
430        buffer: Arc<Buffer>,
431        index_format: wgt::IndexFormat,
432        offset: BufferAddress,
433        size: Option<BufferSize>,
434    },
435    SetVertexBuffer {
436        slot: u32,
437        buffer: Arc<Buffer>,
438        offset: BufferAddress,
439        size: Option<BufferSize>,
440    },
441    SetBlendConstant(Color),
442    SetStencilReference(u32),
443    SetViewport {
444        rect: Rect<f32>,
445        depth_min: f32,
446        depth_max: f32,
447    },
448    SetScissor(Rect<u32>),
449
450    /// Set a range of push constants to values stored in [`BasePass::push_constant_data`].
451    ///
452    /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation
453    /// of the restrictions these commands must satisfy.
454    SetPushConstant {
455        /// Which stages we are setting push constant values for.
456        stages: wgt::ShaderStages,
457
458        /// The byte offset within the push constant storage to write to.  This
459        /// must be a multiple of four.
460        offset: u32,
461
462        /// The number of bytes to write. This must be a multiple of four.
463        size_bytes: u32,
464
465        /// Index in [`BasePass::push_constant_data`] of the start of the data
466        /// to be written.
467        ///
468        /// Note: this is not a byte offset like `offset`. Rather, it is the
469        /// index of the first `u32` element in `push_constant_data` to read.
470        ///
471        /// `None` means zeros should be written to the destination range, and
472        /// there is no corresponding data in `push_constant_data`. This is used
473        /// by render bundles, which explicitly clear out any state that
474        /// post-bundle code might see.
475        values_offset: Option<u32>,
476    },
477    Draw {
478        vertex_count: u32,
479        instance_count: u32,
480        first_vertex: u32,
481        first_instance: u32,
482    },
483    DrawIndexed {
484        index_count: u32,
485        instance_count: u32,
486        first_index: u32,
487        base_vertex: i32,
488        first_instance: u32,
489    },
490    DrawMeshTasks {
491        group_count_x: u32,
492        group_count_y: u32,
493        group_count_z: u32,
494    },
495    DrawIndirect {
496        buffer: Arc<Buffer>,
497        offset: BufferAddress,
498        count: u32,
499        family: DrawCommandFamily,
500
501        /// This limit is only populated for commands in a [`RenderBundle`].
502        vertex_or_index_limit: u64,
503        /// This limit is only populated for commands in a [`RenderBundle`].
504        instance_limit: u64,
505    },
506    MultiDrawIndirectCount {
507        buffer: Arc<Buffer>,
508        offset: BufferAddress,
509        count_buffer: Arc<Buffer>,
510        count_buffer_offset: BufferAddress,
511        max_count: u32,
512        family: DrawCommandFamily,
513    },
514    PushDebugGroup {
515        #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
516        color: u32,
517        len: usize,
518    },
519    PopDebugGroup,
520    InsertDebugMarker {
521        #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))]
522        color: u32,
523        len: usize,
524    },
525    WriteTimestamp {
526        query_set: Arc<QuerySet>,
527        query_index: u32,
528    },
529    BeginOcclusionQuery {
530        query_index: u32,
531    },
532    EndOcclusionQuery,
533    BeginPipelineStatisticsQuery {
534        query_set: Arc<QuerySet>,
535        query_index: u32,
536    },
537    EndPipelineStatisticsQuery,
538    ExecuteBundle(Arc<RenderBundle>),
539}