wgpu_core/command/
render_command.rs

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