wgpu_core/command/
render.rs

1use alloc::{borrow::Cow, sync::Arc, vec::Vec};
2use core::{convert::Infallible, fmt, num::NonZeroU32, ops::Range, str};
3use smallvec::SmallVec;
4
5use arrayvec::ArrayVec;
6use thiserror::Error;
7use wgt::{
8    error::{ErrorType, WebGpuError},
9    BufferAddress, BufferSize, BufferUsages, Color, DynamicOffset, IndexFormat, TextureSelector,
10    TextureUsages, TextureViewDimension, VertexStepMode,
11};
12
13use crate::command::{
14    encoder::EncodingState,
15    pass::{self, flush_bindings_helper},
16    pass_base, pass_try, validate_and_begin_occlusion_query,
17    validate_and_begin_pipeline_statistics_query, ArcCommand, DebugGroupError, EncoderStateError,
18    InnerCommandEncoder, PassStateError, TimestampWritesError,
19};
20use crate::pipeline::{RenderPipeline, VertexStep};
21use crate::resource::RawResourceAccess;
22use crate::resource::{InvalidResourceError, ResourceErrorIdent};
23use crate::snatch::SnatchGuard;
24use crate::{
25    api_log,
26    command::{
27        bind::Binder,
28        end_occlusion_query, end_pipeline_statistics_query,
29        memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
30        ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandEncoderError, DrawError,
31        ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
32        RenderCommandError, StateChange,
33    },
34    device::{
35        AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures,
36        RenderPassCompatibilityError, RenderPassContext,
37    },
38    global::Global,
39    hal_label, id,
40    init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
41    pipeline::PipelineFlags,
42    resource::{
43        DestroyedResourceError, Labeled, MissingBufferUsageError, MissingTextureUsageError,
44        ParentDevice, QuerySet, Texture, TextureView, TextureViewNotRenderableReason,
45    },
46    track::{ResourceUsageCompatibilityError, Tracker, UsageScope},
47    validation, Label,
48};
49
50#[cfg(feature = "serde")]
51use serde::Deserialize;
52#[cfg(feature = "serde")]
53use serde::Serialize;
54
55use super::render_command::ArcRenderCommand;
56use super::{
57    memory_init::TextureSurfaceDiscard, CommandBufferTextureMemoryActions, CommandEncoder,
58    QueryResetMap,
59};
60use super::{DrawCommandFamily, DrawKind, Rect};
61
62use crate::binding_model::{BindError, ImmediateUploadError};
63pub use wgt::{LoadOp, StoreOp};
64
65fn load_hal_ops<V>(load: LoadOp<V>) -> hal::AttachmentOps {
66    match load {
67        LoadOp::Load => hal::AttachmentOps::LOAD,
68        LoadOp::Clear(_) => hal::AttachmentOps::LOAD_CLEAR,
69        LoadOp::DontCare(_) => hal::AttachmentOps::LOAD_DONT_CARE,
70    }
71}
72
73fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps {
74    match store {
75        StoreOp::Store => hal::AttachmentOps::STORE,
76        StoreOp::Discard => hal::AttachmentOps::STORE_DISCARD,
77    }
78}
79
80/// Describes an individual channel within a render pass, such as color, depth, or stencil.
81///
82/// A channel must either be read-only, or it must specify both load and store
83/// operations. See [`ResolvedPassChannel`] for a validated version.
84#[repr(C)]
85#[derive(Clone, Debug, Eq, PartialEq)]
86#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87pub struct PassChannel<V> {
88    /// Operation to perform to the output attachment at the start of a
89    /// renderpass.
90    ///
91    /// This must be clear if it is the first renderpass rendering to a swap
92    /// chain image.
93    pub load_op: Option<LoadOp<V>>,
94    /// Operation to perform to the output attachment at the end of a renderpass.
95    pub store_op: Option<StoreOp>,
96    /// If true, the relevant channel is not changed by a renderpass, and the
97    /// corresponding attachment can be used inside the pass by other read-only
98    /// usages.
99    pub read_only: bool,
100}
101
102impl<V: Copy + Default> PassChannel<Option<V>> {
103    fn resolve(
104        &self,
105        handle_clear: impl Fn(Option<V>) -> Result<V, AttachmentError>,
106    ) -> Result<ResolvedPassChannel<V>, AttachmentError> {
107        if self.read_only {
108            if self.load_op.is_some() {
109                return Err(AttachmentError::ReadOnlyWithLoad);
110            }
111            if self.store_op.is_some() {
112                return Err(AttachmentError::ReadOnlyWithStore);
113            }
114            Ok(ResolvedPassChannel::ReadOnly)
115        } else {
116            Ok(ResolvedPassChannel::Operational(wgt::Operations {
117                load: match self.load_op.ok_or(AttachmentError::NoLoad)? {
118                    LoadOp::Clear(clear_value) => LoadOp::Clear(handle_clear(clear_value)?),
119                    LoadOp::DontCare(token) => LoadOp::DontCare(token),
120                    LoadOp::Load => LoadOp::Load,
121                },
122                store: self.store_op.ok_or(AttachmentError::NoStore)?,
123            }))
124        }
125    }
126}
127
128/// Describes an individual channel within a render pass, such as color, depth, or stencil.
129///
130/// Unlike [`PassChannel`], this version uses the Rust type system to guarantee
131/// a valid specification.
132#[derive(Clone, Debug)]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134pub enum ResolvedPassChannel<V> {
135    ReadOnly,
136    Operational(wgt::Operations<V>),
137}
138
139impl<V: Copy + Default> ResolvedPassChannel<V> {
140    fn load_op(&self) -> LoadOp<V> {
141        match self {
142            ResolvedPassChannel::ReadOnly => LoadOp::Load,
143            ResolvedPassChannel::Operational(wgt::Operations { load, .. }) => *load,
144        }
145    }
146
147    fn store_op(&self) -> StoreOp {
148        match self {
149            ResolvedPassChannel::ReadOnly => StoreOp::Store,
150            ResolvedPassChannel::Operational(wgt::Operations { store, .. }) => *store,
151        }
152    }
153
154    fn clear_value(&self) -> V {
155        match self {
156            Self::Operational(wgt::Operations {
157                load: LoadOp::Clear(clear_value),
158                ..
159            }) => *clear_value,
160            _ => Default::default(),
161        }
162    }
163
164    fn is_readonly(&self) -> bool {
165        matches!(self, Self::ReadOnly)
166    }
167
168    fn hal_ops(&self) -> hal::AttachmentOps {
169        load_hal_ops(self.load_op()) | store_hal_ops(self.store_op())
170    }
171}
172
173/// Describes a color attachment to a render pass.
174#[repr(C)]
175#[derive(Clone, Debug, PartialEq)]
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
177pub struct RenderPassColorAttachment<TV = id::TextureViewId> {
178    /// The view to use as an attachment.
179    pub view: TV,
180    /// The depth slice index of a 3D view. It must not be provided if the view is not 3D.
181    pub depth_slice: Option<u32>,
182    /// The view that will receive the resolved output if multisampling is used.
183    pub resolve_target: Option<TV>,
184    /// Operation to perform to the output attachment at the start of a
185    /// renderpass.
186    ///
187    /// This must be clear if it is the first renderpass rendering to a swap
188    /// chain image.
189    pub load_op: LoadOp<Color>,
190    /// Operation to perform to the output attachment at the end of a renderpass.
191    pub store_op: StoreOp,
192}
193
194pub type ArcRenderPassColorAttachment = RenderPassColorAttachment<Arc<TextureView>>;
195
196// Avoid allocation in the common case that there is only one color attachment,
197// but don't bloat `ArcCommand::RunRenderPass` excessively.
198pub type ColorAttachments<TV = Arc<TextureView>> =
199    SmallVec<[Option<RenderPassColorAttachment<TV>>; 1]>;
200
201impl ArcRenderPassColorAttachment {
202    fn hal_ops(&self) -> hal::AttachmentOps {
203        load_hal_ops(self.load_op) | store_hal_ops(self.store_op)
204    }
205
206    fn clear_value(&self) -> Color {
207        match self.load_op {
208            LoadOp::Clear(clear_value) => clear_value,
209            LoadOp::DontCare(_) | LoadOp::Load => Color::default(),
210        }
211    }
212}
213
214/// Describes a depth/stencil attachment to a render pass.
215///
216/// This version uses the unvalidated [`PassChannel`].
217#[repr(C)]
218#[derive(Clone, Debug, PartialEq)]
219#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
220pub struct RenderPassDepthStencilAttachment<TV> {
221    /// The view to use as an attachment.
222    pub view: TV,
223    /// What operations will be performed on the depth part of the attachment.
224    pub depth: PassChannel<Option<f32>>,
225    /// What operations will be performed on the stencil part of the attachment.
226    pub stencil: PassChannel<Option<u32>>,
227}
228
229/// Describes a depth/stencil attachment to a render pass.
230///
231/// This version uses the validated [`ResolvedPassChannel`].
232#[derive(Clone, Debug)]
233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
234pub struct ResolvedRenderPassDepthStencilAttachment<TV> {
235    /// The view to use as an attachment.
236    pub view: TV,
237    /// What operations will be performed on the depth part of the attachment.
238    pub depth: ResolvedPassChannel<f32>,
239    /// What operations will be performed on the stencil part of the attachment.
240    pub stencil: ResolvedPassChannel<u32>,
241}
242
243/// Describes the attachments of a render pass.
244#[derive(Clone, Debug, Default, PartialEq)]
245pub struct RenderPassDescriptor<'a> {
246    pub label: Label<'a>,
247    /// The color attachments of the render pass.
248    pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
249    /// The depth and stencil attachment of the render pass, if any.
250    pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment<id::TextureViewId>>,
251    /// Defines where and when timestamp values will be written for this pass.
252    pub timestamp_writes: Option<&'a PassTimestampWrites>,
253    /// Defines where the occlusion query results will be stored for this pass.
254    pub occlusion_query_set: Option<id::QuerySetId>,
255    /// The multiview array layers that will be used
256    pub multiview_mask: Option<NonZeroU32>,
257}
258
259/// Describes the attachments of a render pass.
260struct ArcRenderPassDescriptor<'a> {
261    pub label: &'a Label<'a>,
262    /// The color attachments of the render pass.
263    pub color_attachments:
264        ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
265    /// The depth and stencil attachment of the render pass, if any.
266    pub depth_stencil_attachment:
267        Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
268    /// Defines where and when timestamp values will be written for this pass.
269    pub timestamp_writes: Option<ArcPassTimestampWrites>,
270    /// Defines where the occlusion query results will be stored for this pass.
271    pub occlusion_query_set: Option<Arc<QuerySet>>,
272    /// The multiview array layers that will be used
273    pub multiview_mask: Option<NonZeroU32>,
274}
275
276pub type RenderBasePass = BasePass<ArcRenderCommand, RenderPassError>;
277
278/// A pass's [encoder state](https://www.w3.org/TR/webgpu/#encoder-state) and
279/// its validity are two distinct conditions, i.e., the full matrix of
280/// (open, ended) x (valid, invalid) is possible.
281///
282/// The presence or absence of the `parent` `Option` indicates the pass's state.
283/// The presence or absence of an error in `base.error` indicates the pass's
284/// validity.
285pub struct RenderPass {
286    /// All pass data & records is stored here.
287    base: BasePass<ArcRenderCommand, RenderPassError>,
288
289    /// Parent command encoder that this pass records commands into.
290    ///
291    /// If this is `Some`, then the pass is in WebGPU's "open" state. If it is
292    /// `None`, then the pass is in the "ended" state.
293    /// See <https://www.w3.org/TR/webgpu/#encoder-state>
294    parent: Option<Arc<CommandEncoder>>,
295
296    color_attachments:
297        ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
298    depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
299    timestamp_writes: Option<ArcPassTimestampWrites>,
300    occlusion_query_set: Option<Arc<QuerySet>>,
301    multiview_mask: Option<NonZeroU32>,
302
303    // Resource binding dedupe state.
304    current_bind_groups: BindGroupStateChange,
305    current_pipeline: StateChange<id::RenderPipelineId>,
306}
307
308impl RenderPass {
309    /// If the parent command encoder is invalid, the returned pass will be invalid.
310    fn new(parent: Arc<CommandEncoder>, desc: ArcRenderPassDescriptor) -> Self {
311        let ArcRenderPassDescriptor {
312            label,
313            timestamp_writes,
314            color_attachments,
315            depth_stencil_attachment,
316            occlusion_query_set,
317            multiview_mask,
318        } = desc;
319
320        Self {
321            base: BasePass::new(label),
322            parent: Some(parent),
323            color_attachments,
324            depth_stencil_attachment,
325            timestamp_writes,
326            occlusion_query_set,
327            multiview_mask,
328
329            current_bind_groups: BindGroupStateChange::new(),
330            current_pipeline: StateChange::new(),
331        }
332    }
333
334    fn new_invalid(parent: Arc<CommandEncoder>, label: &Label, err: RenderPassError) -> Self {
335        Self {
336            base: BasePass::new_invalid(label, err),
337            parent: Some(parent),
338            color_attachments: ArrayVec::new(),
339            depth_stencil_attachment: None,
340            timestamp_writes: None,
341            occlusion_query_set: None,
342            multiview_mask: None,
343            current_bind_groups: BindGroupStateChange::new(),
344            current_pipeline: StateChange::new(),
345        }
346    }
347
348    #[inline]
349    pub fn label(&self) -> Option<&str> {
350        self.base.label.as_deref()
351    }
352}
353
354impl fmt::Debug for RenderPass {
355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356        f.debug_struct("RenderPass")
357            .field("label", &self.label())
358            .field("color_attachments", &self.color_attachments)
359            .field("depth_stencil_target", &self.depth_stencil_attachment)
360            .field("command count", &self.base.commands.len())
361            .field("dynamic offset count", &self.base.dynamic_offsets.len())
362            .field("immediate data u32 count", &self.base.immediates_data.len())
363            .field("multiview mask", &self.multiview_mask)
364            .finish()
365    }
366}
367
368#[derive(Debug, PartialEq)]
369enum OptionalState {
370    Unused,
371    Required,
372    Set,
373}
374
375impl OptionalState {
376    fn require(&mut self, require: bool) {
377        if require && *self == Self::Unused {
378            *self = Self::Required;
379        }
380    }
381}
382
383#[derive(Debug, Default)]
384struct IndexState {
385    buffer_format: Option<IndexFormat>,
386    limit: u64,
387}
388
389impl IndexState {
390    fn update_buffer(&mut self, range: Range<BufferAddress>, format: IndexFormat) {
391        self.buffer_format = Some(format);
392        let shift = match format {
393            IndexFormat::Uint16 => 1,
394            IndexFormat::Uint32 => 2,
395        };
396        self.limit = (range.end - range.start) >> shift;
397    }
398
399    fn reset(&mut self) {
400        self.buffer_format = None;
401        self.limit = 0;
402    }
403}
404
405#[derive(Debug, Default)]
406pub(crate) struct VertexLimits {
407    /// Length of the shortest vertex rate vertex buffer
408    pub(crate) vertex_limit: u64,
409    /// Buffer slot which the shortest vertex rate vertex buffer is bound to
410    vertex_limit_slot: u32,
411    /// Length of the shortest instance rate vertex buffer
412    pub(crate) instance_limit: u64,
413    /// Buffer slot which the shortest instance rate vertex buffer is bound to
414    instance_limit_slot: u32,
415}
416
417impl VertexLimits {
418    pub(crate) fn new(
419        buffer_sizes: impl Iterator<Item = Option<BufferAddress>>,
420        pipeline_steps: &[VertexStep],
421    ) -> Self {
422        // Implements the validation from https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw
423        // Except that the formula is shuffled to extract the number of vertices in order
424        // to carry the bulk of the computation when changing states instead of when producing
425        // draws. Draw calls tend to happen at a higher frequency. Here we determine vertex
426        // limits that can be cheaply checked for each draw call.
427
428        let mut vertex_limit = u64::MAX;
429        let mut vertex_limit_slot = 0;
430        let mut instance_limit = u64::MAX;
431        let mut instance_limit_slot = 0;
432
433        for (idx, (buffer_size, step)) in buffer_sizes.zip(pipeline_steps).enumerate() {
434            let Some(buffer_size) = buffer_size else {
435                // Missing required vertex buffer
436                return Self::default();
437            };
438
439            let limit = if buffer_size < step.last_stride {
440                // The buffer cannot fit the last vertex.
441                0
442            } else {
443                if step.stride == 0 {
444                    // We already checked that the last stride fits, the same
445                    // vertex will be repeated so this slot can accommodate any number of
446                    // vertices.
447                    continue;
448                }
449
450                // The general case.
451                (buffer_size - step.last_stride) / step.stride + 1
452            };
453
454            match step.mode {
455                VertexStepMode::Vertex => {
456                    if limit < vertex_limit {
457                        vertex_limit = limit;
458                        vertex_limit_slot = idx as _;
459                    }
460                }
461                VertexStepMode::Instance => {
462                    if limit < instance_limit {
463                        instance_limit = limit;
464                        instance_limit_slot = idx as _;
465                    }
466                }
467            }
468        }
469
470        Self {
471            vertex_limit,
472            vertex_limit_slot,
473            instance_limit,
474            instance_limit_slot,
475        }
476    }
477
478    pub(crate) fn validate_vertex_limit(
479        &self,
480        first_vertex: u32,
481        vertex_count: u32,
482    ) -> Result<(), DrawError> {
483        let last_vertex = first_vertex as u64 + vertex_count as u64;
484        let vertex_limit = self.vertex_limit;
485        if last_vertex > vertex_limit {
486            return Err(DrawError::VertexBeyondLimit {
487                last_vertex,
488                vertex_limit,
489                slot: self.vertex_limit_slot,
490            });
491        }
492
493        Ok(())
494    }
495
496    pub(crate) fn validate_instance_limit(
497        &self,
498        first_instance: u32,
499        instance_count: u32,
500    ) -> Result<(), DrawError> {
501        let last_instance = first_instance as u64 + instance_count as u64;
502        let instance_limit = self.instance_limit;
503        if last_instance > instance_limit {
504            return Err(DrawError::InstanceBeyondLimit {
505                last_instance,
506                instance_limit,
507                slot: self.instance_limit_slot,
508            });
509        }
510
511        Ok(())
512    }
513}
514
515#[derive(Debug, Default)]
516struct VertexState {
517    buffer_sizes: [Option<BufferAddress>; hal::MAX_VERTEX_BUFFERS],
518    limits: VertexLimits,
519}
520
521impl VertexState {
522    fn update_limits(&mut self, pipeline_steps: &[VertexStep]) {
523        self.limits = VertexLimits::new(self.buffer_sizes.iter().copied(), pipeline_steps);
524    }
525}
526
527struct State<'scope, 'snatch_guard, 'cmd_enc> {
528    pipeline_flags: PipelineFlags,
529    blend_constant: OptionalState,
530    stencil_reference: u32,
531    pipeline: Option<Arc<RenderPipeline>>,
532    index: IndexState,
533    vertex: VertexState,
534
535    info: RenderPassInfo,
536
537    pass: pass::PassState<'scope, 'snatch_guard, 'cmd_enc>,
538
539    active_occlusion_query: Option<(Arc<QuerySet>, u32)>,
540    active_pipeline_statistics_query: Option<(Arc<QuerySet>, u32)>,
541}
542
543impl<'scope, 'snatch_guard, 'cmd_enc> State<'scope, 'snatch_guard, 'cmd_enc> {
544    fn is_ready(&self, family: DrawCommandFamily) -> Result<(), DrawError> {
545        if let Some(pipeline) = self.pipeline.as_ref() {
546            self.pass.binder.check_compatibility(pipeline.as_ref())?;
547            self.pass.binder.check_late_buffer_bindings()?;
548
549            if self.blend_constant == OptionalState::Required {
550                return Err(DrawError::MissingBlendConstant);
551            }
552
553            // Determine how many vertex buffers have already been bound
554            let vertex_buffer_count = self
555                .vertex
556                .buffer_sizes
557                .iter()
558                .take_while(|v| v.is_some())
559                .count() as u32;
560            // Compare with the needed quantity
561            if vertex_buffer_count < pipeline.vertex_steps.len() as u32 {
562                return Err(DrawError::MissingVertexBuffer {
563                    pipeline: pipeline.error_ident(),
564                    index: vertex_buffer_count,
565                });
566            }
567
568            if family == DrawCommandFamily::DrawIndexed {
569                // Pipeline expects an index buffer
570                if let Some(pipeline_index_format) = pipeline.strip_index_format {
571                    // We have a buffer bound
572                    let buffer_index_format = self
573                        .index
574                        .buffer_format
575                        .ok_or(DrawError::MissingIndexBuffer)?;
576
577                    // The buffers are different formats
578                    if pipeline_index_format != buffer_index_format {
579                        return Err(DrawError::UnmatchedIndexFormats {
580                            pipeline: pipeline.error_ident(),
581                            pipeline_format: pipeline_index_format,
582                            buffer_format: buffer_index_format,
583                        });
584                    }
585                }
586            }
587            if (family == DrawCommandFamily::DrawMeshTasks) != pipeline.is_mesh {
588                return Err(DrawError::WrongPipelineType {
589                    wanted_mesh_pipeline: !pipeline.is_mesh,
590                });
591            }
592            Ok(())
593        } else {
594            Err(DrawError::MissingPipeline(pass::MissingPipeline))
595        }
596    }
597
598    /// Flush binding state in preparation for a draw call.
599    ///
600    /// See the compute pass version for an explanation of some ways that
601    /// `flush_bindings` differs between the two types of passes.
602    fn flush_bindings(&mut self) -> Result<(), RenderPassErrorInner> {
603        flush_bindings_helper(&mut self.pass)?;
604        Ok(())
605    }
606
607    /// Reset the `RenderBundle`-related states.
608    fn reset_bundle(&mut self) {
609        self.pass.binder.reset();
610        self.pipeline = None;
611        self.index.reset();
612        self.vertex = Default::default();
613    }
614}
615
616/// Describes an attachment location in words.
617///
618/// Can be used as "the {loc} has..." or "{loc} has..."
619#[derive(Debug, Copy, Clone)]
620pub enum AttachmentErrorLocation {
621    Color { index: usize, resolve: bool },
622    Depth,
623}
624
625impl fmt::Display for AttachmentErrorLocation {
626    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627        match *self {
628            AttachmentErrorLocation::Color {
629                index,
630                resolve: false,
631            } => write!(f, "color attachment at index {index}'s texture view"),
632            AttachmentErrorLocation::Color {
633                index,
634                resolve: true,
635            } => write!(
636                f,
637                "color attachment at index {index}'s resolve texture view"
638            ),
639            AttachmentErrorLocation::Depth => write!(f, "depth attachment's texture view"),
640        }
641    }
642}
643
644#[derive(Clone, Debug, Error)]
645#[non_exhaustive]
646pub enum ColorAttachmentError {
647    #[error("Attachment format {0:?} is not a color format")]
648    InvalidFormat(wgt::TextureFormat),
649    #[error("The number of color attachments {given} exceeds the limit {limit}")]
650    TooMany { given: usize, limit: usize },
651    #[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
652    TooManyBytesPerSample { total: u32, limit: u32 },
653    #[error("Depth slice must be less than {limit} but is {given}")]
654    DepthSliceLimit { given: u32, limit: u32 },
655    #[error("Color attachment's view is 3D and requires depth slice to be provided")]
656    MissingDepthSlice,
657    #[error("Depth slice was provided but the color attachment's view is not 3D")]
658    UnneededDepthSlice,
659    #[error("{view}'s subresource at mip {mip_level} and depth/array layer {depth_or_array_layer} is already attached to this render pass")]
660    SubresourceOverlap {
661        view: ResourceErrorIdent,
662        mip_level: u32,
663        depth_or_array_layer: u32,
664    },
665    #[error("Color attachment's usage contains {0:?}. This can only be used with StoreOp::{1:?}, but StoreOp::{2:?} was provided")]
666    InvalidUsageForStoreOp(TextureUsages, StoreOp, StoreOp),
667}
668
669impl WebGpuError for ColorAttachmentError {
670    fn webgpu_error_type(&self) -> ErrorType {
671        ErrorType::Validation
672    }
673}
674
675#[derive(Clone, Debug, Error)]
676#[non_exhaustive]
677pub enum AttachmentError {
678    #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-or-stencil format")]
679    InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
680    #[error("LoadOp must be None for read-only attachments")]
681    ReadOnlyWithLoad,
682    #[error("StoreOp must be None for read-only attachments")]
683    ReadOnlyWithStore,
684    #[error("Attachment without load")]
685    NoLoad,
686    #[error("Attachment without store")]
687    NoStore,
688    #[error("LoadOp is `Clear` but no clear value was provided")]
689    NoClearValue,
690    #[error("Clear value ({0}) must be between 0.0 and 1.0, inclusive")]
691    ClearValueOutOfRange(f32),
692}
693
694impl WebGpuError for AttachmentError {
695    fn webgpu_error_type(&self) -> ErrorType {
696        ErrorType::Validation
697    }
698}
699
700/// Error encountered when performing a render pass.
701#[derive(Clone, Debug, Error)]
702pub enum RenderPassErrorInner {
703    #[error(transparent)]
704    Device(#[from] DeviceError),
705    #[error(transparent)]
706    ColorAttachment(#[from] ColorAttachmentError),
707    #[error(transparent)]
708    InvalidAttachment(#[from] AttachmentError),
709    #[error(transparent)]
710    EncoderState(#[from] EncoderStateError),
711    #[error("Parent encoder is invalid")]
712    InvalidParentEncoder,
713    #[error(transparent)]
714    DebugGroupError(#[from] DebugGroupError),
715    #[error("The format of the {location} ({format:?}) is not resolvable")]
716    UnsupportedResolveTargetFormat {
717        location: AttachmentErrorLocation,
718        format: wgt::TextureFormat,
719    },
720    #[error("No color attachments or depth attachments were provided, at least one attachment of any kind must be provided")]
721    MissingAttachments,
722    #[error("The {location} is not renderable:")]
723    TextureViewIsNotRenderable {
724        location: AttachmentErrorLocation,
725        #[source]
726        reason: TextureViewNotRenderableReason,
727    },
728    #[error("Attachments have differing sizes: the {expected_location} has extent {expected_extent:?} but is followed by the {actual_location} which has {actual_extent:?}")]
729    AttachmentsDimensionMismatch {
730        expected_location: AttachmentErrorLocation,
731        expected_extent: wgt::Extent3d,
732        actual_location: AttachmentErrorLocation,
733        actual_extent: wgt::Extent3d,
734    },
735    #[error("Attachments have differing sample counts: the {expected_location} has count {expected_samples:?} but is followed by the {actual_location} which has count {actual_samples:?}")]
736    AttachmentSampleCountMismatch {
737        expected_location: AttachmentErrorLocation,
738        expected_samples: u32,
739        actual_location: AttachmentErrorLocation,
740        actual_samples: u32,
741    },
742    #[error("The resolve source, {location}, must be multi-sampled (has {src} samples) while the resolve destination must not be multisampled (has {dst} samples)")]
743    InvalidResolveSampleCounts {
744        location: AttachmentErrorLocation,
745        src: u32,
746        dst: u32,
747    },
748    #[error(
749        "Resource source, {location}, format ({src:?}) must match the resolve destination format ({dst:?})"
750    )]
751    MismatchedResolveTextureFormat {
752        location: AttachmentErrorLocation,
753        src: wgt::TextureFormat,
754        dst: wgt::TextureFormat,
755    },
756    #[error("Unable to clear non-present/read-only depth")]
757    InvalidDepthOps,
758    #[error("Unable to clear non-present/read-only stencil")]
759    InvalidStencilOps,
760    #[error(transparent)]
761    InvalidValuesOffset(#[from] pass::InvalidValuesOffset),
762    #[error(transparent)]
763    MissingFeatures(#[from] MissingFeatures),
764    #[error(transparent)]
765    MissingDownlevelFlags(#[from] MissingDownlevelFlags),
766    #[error("Indirect buffer offset {0:?} is not a multiple of 4")]
767    UnalignedIndirectBufferOffset(BufferAddress),
768    #[error("Indirect draw uses bytes {offset}..{end_offset} using count {count} which overruns indirect buffer of size {buffer_size}")]
769    IndirectBufferOverrun {
770        count: u32,
771        offset: u64,
772        end_offset: u64,
773        buffer_size: u64,
774    },
775    #[error("Indirect draw uses bytes {begin_count_offset}..{end_count_offset} which overruns indirect buffer of size {count_buffer_size}")]
776    IndirectCountBufferOverrun {
777        begin_count_offset: u64,
778        end_count_offset: u64,
779        count_buffer_size: u64,
780    },
781    #[error(transparent)]
782    ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
783    #[error("Render bundle has incompatible targets, {0}")]
784    IncompatibleBundleTargets(#[from] RenderPassCompatibilityError),
785    #[error(
786        "Render bundle has incompatible read-only flags: \
787             bundle has flags depth = {bundle_depth} and stencil = {bundle_stencil}, \
788             while the pass has flags depth = {pass_depth} and stencil = {pass_stencil}. \
789             Read-only renderpasses are only compatible with read-only bundles for that aspect."
790    )]
791    IncompatibleBundleReadOnlyDepthStencil {
792        pass_depth: bool,
793        pass_stencil: bool,
794        bundle_depth: bool,
795        bundle_stencil: bool,
796    },
797    #[error(transparent)]
798    RenderCommand(#[from] RenderCommandError),
799    #[error(transparent)]
800    Draw(#[from] DrawError),
801    #[error(transparent)]
802    Bind(#[from] BindError),
803    #[error("Immediate data offset must be aligned to 4 bytes")]
804    ImmediateOffsetAlignment,
805    #[error("Immediate data size must be aligned to 4 bytes")]
806    ImmediateDataizeAlignment,
807    #[error("Ran out of immediate data space. Don't set 4gb of immediates per ComputePass.")]
808    ImmediateOutOfMemory,
809    #[error(transparent)]
810    QueryUse(#[from] QueryUseError),
811    #[error("Multiview layer count must match")]
812    MultiViewMismatch,
813    #[error(
814        "Multiview pass texture views with more than one array layer must have D2Array dimension"
815    )]
816    MultiViewDimensionMismatch,
817    #[error("Multiview view count limit violated")]
818    TooManyMultiviewViews,
819    #[error("missing occlusion query set")]
820    MissingOcclusionQuerySet,
821    #[error(transparent)]
822    DestroyedResource(#[from] DestroyedResourceError),
823    #[error("The compute pass has already been ended and no further commands can be recorded")]
824    PassEnded,
825    #[error(transparent)]
826    InvalidResource(#[from] InvalidResourceError),
827    #[error(transparent)]
828    TimestampWrites(#[from] TimestampWritesError),
829}
830
831impl From<MissingBufferUsageError> for RenderPassErrorInner {
832    fn from(error: MissingBufferUsageError) -> Self {
833        Self::RenderCommand(error.into())
834    }
835}
836
837impl From<MissingTextureUsageError> for RenderPassErrorInner {
838    fn from(error: MissingTextureUsageError) -> Self {
839        Self::RenderCommand(error.into())
840    }
841}
842
843impl From<pass::BindGroupIndexOutOfRange> for RenderPassErrorInner {
844    fn from(error: pass::BindGroupIndexOutOfRange) -> Self {
845        Self::RenderCommand(RenderCommandError::BindGroupIndexOutOfRange(error))
846    }
847}
848
849impl From<pass::MissingPipeline> for RenderPassErrorInner {
850    fn from(error: pass::MissingPipeline) -> Self {
851        Self::Draw(DrawError::MissingPipeline(error))
852    }
853}
854
855impl From<ImmediateUploadError> for RenderPassErrorInner {
856    fn from(error: ImmediateUploadError) -> Self {
857        Self::RenderCommand(error.into())
858    }
859}
860
861/// Error encountered when performing a render pass.
862#[derive(Clone, Debug, Error)]
863#[error("{scope}")]
864pub struct RenderPassError {
865    pub scope: PassErrorScope,
866    #[source]
867    pub(super) inner: RenderPassErrorInner,
868}
869
870impl<E: Into<RenderPassErrorInner>> MapPassErr<RenderPassError> for E {
871    fn map_pass_err(self, scope: PassErrorScope) -> RenderPassError {
872        RenderPassError {
873            scope,
874            inner: self.into(),
875        }
876    }
877}
878
879impl WebGpuError for RenderPassError {
880    fn webgpu_error_type(&self) -> ErrorType {
881        let Self { scope: _, inner } = self;
882        let e: &dyn WebGpuError = match inner {
883            RenderPassErrorInner::Device(e) => e,
884            RenderPassErrorInner::ColorAttachment(e) => e,
885            RenderPassErrorInner::EncoderState(e) => e,
886            RenderPassErrorInner::DebugGroupError(e) => e,
887            RenderPassErrorInner::MissingFeatures(e) => e,
888            RenderPassErrorInner::MissingDownlevelFlags(e) => e,
889            RenderPassErrorInner::RenderCommand(e) => e,
890            RenderPassErrorInner::Draw(e) => e,
891            RenderPassErrorInner::Bind(e) => e,
892            RenderPassErrorInner::QueryUse(e) => e,
893            RenderPassErrorInner::DestroyedResource(e) => e,
894            RenderPassErrorInner::InvalidResource(e) => e,
895            RenderPassErrorInner::IncompatibleBundleTargets(e) => e,
896            RenderPassErrorInner::InvalidAttachment(e) => e,
897            RenderPassErrorInner::TimestampWrites(e) => e,
898            RenderPassErrorInner::InvalidValuesOffset(e) => e,
899
900            RenderPassErrorInner::InvalidParentEncoder
901            | RenderPassErrorInner::UnsupportedResolveTargetFormat { .. }
902            | RenderPassErrorInner::MissingAttachments
903            | RenderPassErrorInner::TextureViewIsNotRenderable { .. }
904            | RenderPassErrorInner::AttachmentsDimensionMismatch { .. }
905            | RenderPassErrorInner::AttachmentSampleCountMismatch { .. }
906            | RenderPassErrorInner::InvalidResolveSampleCounts { .. }
907            | RenderPassErrorInner::MismatchedResolveTextureFormat { .. }
908            | RenderPassErrorInner::InvalidDepthOps
909            | RenderPassErrorInner::InvalidStencilOps
910            | RenderPassErrorInner::UnalignedIndirectBufferOffset(..)
911            | RenderPassErrorInner::IndirectBufferOverrun { .. }
912            | RenderPassErrorInner::IndirectCountBufferOverrun { .. }
913            | RenderPassErrorInner::ResourceUsageCompatibility(..)
914            | RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil { .. }
915            | RenderPassErrorInner::ImmediateOffsetAlignment
916            | RenderPassErrorInner::ImmediateDataizeAlignment
917            | RenderPassErrorInner::ImmediateOutOfMemory
918            | RenderPassErrorInner::MultiViewMismatch
919            | RenderPassErrorInner::MultiViewDimensionMismatch
920            | RenderPassErrorInner::TooManyMultiviewViews
921            | RenderPassErrorInner::MissingOcclusionQuerySet
922            | RenderPassErrorInner::PassEnded => return ErrorType::Validation,
923        };
924        e.webgpu_error_type()
925    }
926}
927
928struct RenderAttachment {
929    texture: Arc<Texture>,
930    selector: TextureSelector,
931    usage: wgt::TextureUses,
932}
933
934impl TextureView {
935    fn to_render_attachment(&self, usage: wgt::TextureUses) -> RenderAttachment {
936        RenderAttachment {
937            texture: self.parent.clone(),
938            selector: self.selector.clone(),
939            usage,
940        }
941    }
942}
943
944const MAX_TOTAL_ATTACHMENTS: usize = hal::MAX_COLOR_ATTACHMENTS + hal::MAX_COLOR_ATTACHMENTS + 1;
945type AttachmentDataVec<T> = ArrayVec<T, MAX_TOTAL_ATTACHMENTS>;
946
947struct RenderPassInfo {
948    context: RenderPassContext,
949    /// All render attachments, including depth/stencil
950    render_attachments: AttachmentDataVec<RenderAttachment>,
951    is_depth_read_only: bool,
952    is_stencil_read_only: bool,
953    extent: wgt::Extent3d,
954
955    divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>,
956    multiview_mask: Option<NonZeroU32>,
957}
958
959impl RenderPassInfo {
960    fn add_pass_texture_init_actions<V>(
961        load_op: LoadOp<V>,
962        store_op: StoreOp,
963        texture_memory_actions: &mut CommandBufferTextureMemoryActions,
964        view: &TextureView,
965        pending_discard_init_fixups: &mut SurfacesInDiscardState,
966    ) {
967        if matches!(load_op, LoadOp::Load) {
968            pending_discard_init_fixups.extend(texture_memory_actions.register_init_action(
969                &TextureInitTrackerAction {
970                    texture: view.parent.clone(),
971                    range: TextureInitRange::from(view.selector.clone()),
972                    // Note that this is needed even if the target is discarded,
973                    kind: MemoryInitKind::NeedsInitializedMemory,
974                },
975            ));
976        } else if store_op == StoreOp::Store {
977            // Clear + Store
978            texture_memory_actions.register_implicit_init(
979                &view.parent,
980                TextureInitRange::from(view.selector.clone()),
981            );
982        }
983        if store_op == StoreOp::Discard {
984            // the discard happens at the *end* of a pass, but recording the
985            // discard right away be alright since the texture can't be used
986            // during the pass anyways
987            texture_memory_actions.discard(TextureSurfaceDiscard {
988                texture: view.parent.clone(),
989                mip_level: view.selector.mips.start,
990                layer: view.selector.layers.start,
991            });
992        }
993    }
994
995    fn start(
996        device: &Arc<Device>,
997        hal_label: Option<&str>,
998        color_attachments: &[Option<ArcRenderPassColorAttachment>],
999        mut depth_stencil_attachment: Option<
1000            ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
1001        >,
1002        mut timestamp_writes: Option<ArcPassTimestampWrites>,
1003        mut occlusion_query_set: Option<Arc<QuerySet>>,
1004        encoder: &mut dyn hal::DynCommandEncoder,
1005        trackers: &mut Tracker,
1006        texture_memory_actions: &mut CommandBufferTextureMemoryActions,
1007        pending_query_resets: &mut QueryResetMap,
1008        pending_discard_init_fixups: &mut SurfacesInDiscardState,
1009        snatch_guard: &SnatchGuard<'_>,
1010        multiview_mask: Option<NonZeroU32>,
1011    ) -> Result<Self, RenderPassErrorInner> {
1012        profiling::scope!("RenderPassInfo::start");
1013
1014        // We default to false intentionally, even if depth-stencil isn't used at all.
1015        // This allows us to use the primary raw pipeline in `RenderPipeline`,
1016        // instead of the special read-only one, which would be `None`.
1017        let mut is_depth_read_only = false;
1018        let mut is_stencil_read_only = false;
1019
1020        let mut render_attachments = AttachmentDataVec::<RenderAttachment>::new();
1021        let mut discarded_surfaces = AttachmentDataVec::new();
1022        let mut divergent_discarded_depth_stencil_aspect = None;
1023
1024        let mut attachment_location = AttachmentErrorLocation::Color {
1025            index: usize::MAX,
1026            resolve: false,
1027        };
1028        let mut extent = None;
1029        let mut sample_count = 0;
1030
1031        let mut detected_multiview: Option<Option<NonZeroU32>> = None;
1032
1033        let mut check_multiview = |view: &TextureView| {
1034            // Get the multiview configuration for this texture view
1035            let layers = view.selector.layers.end - view.selector.layers.start;
1036            let this_multiview = if layers >= 2 {
1037                // Trivially proven by the if above
1038                Some(unsafe { NonZeroU32::new_unchecked(layers) })
1039            } else {
1040                None
1041            };
1042
1043            // Make sure that if this view is a multiview, it is set to be an array
1044            if this_multiview.is_some() && view.desc.dimension != TextureViewDimension::D2Array {
1045                return Err(RenderPassErrorInner::MultiViewDimensionMismatch);
1046            }
1047
1048            // Validate matching first, or store the first one
1049            if let Some(multiview) = detected_multiview {
1050                if multiview != this_multiview {
1051                    return Err(RenderPassErrorInner::MultiViewMismatch);
1052                }
1053            } else {
1054                // Multiview is only supported if the feature is enabled
1055                if let Some(this_multiview) = this_multiview {
1056                    device.require_features(wgt::Features::MULTIVIEW)?;
1057                    if this_multiview.get() > device.limits.max_multiview_view_count {
1058                        return Err(RenderPassErrorInner::TooManyMultiviewViews);
1059                    }
1060                }
1061
1062                detected_multiview = Some(this_multiview);
1063            }
1064
1065            Ok(())
1066        };
1067        let mut add_view = |view: &TextureView, location| {
1068            let render_extent = view.render_extent.map_err(|reason| {
1069                RenderPassErrorInner::TextureViewIsNotRenderable { location, reason }
1070            })?;
1071            if let Some(ex) = extent {
1072                if ex != render_extent {
1073                    return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1074                        expected_location: attachment_location,
1075                        expected_extent: ex,
1076                        actual_location: location,
1077                        actual_extent: render_extent,
1078                    });
1079                }
1080            } else {
1081                extent = Some(render_extent);
1082            }
1083            if sample_count == 0 {
1084                sample_count = view.samples;
1085            } else if sample_count != view.samples {
1086                return Err(RenderPassErrorInner::AttachmentSampleCountMismatch {
1087                    expected_location: attachment_location,
1088                    expected_samples: sample_count,
1089                    actual_location: location,
1090                    actual_samples: view.samples,
1091                });
1092            }
1093            attachment_location = location;
1094            Ok(())
1095        };
1096
1097        let mut depth_stencil = None;
1098
1099        if let Some(at) = depth_stencil_attachment.as_ref() {
1100            let view = &at.view;
1101            check_multiview(view)?;
1102            add_view(view, AttachmentErrorLocation::Depth)?;
1103
1104            let ds_aspects = view.desc.aspects();
1105
1106            if !ds_aspects.contains(hal::FormatAspects::STENCIL)
1107                || (at.stencil.load_op().eq_variant(at.depth.load_op())
1108                    && at.stencil.store_op() == at.depth.store_op())
1109            {
1110                Self::add_pass_texture_init_actions(
1111                    at.depth.load_op(),
1112                    at.depth.store_op(),
1113                    texture_memory_actions,
1114                    view,
1115                    pending_discard_init_fixups,
1116                );
1117            } else if !ds_aspects.contains(hal::FormatAspects::DEPTH) {
1118                Self::add_pass_texture_init_actions(
1119                    at.stencil.load_op(),
1120                    at.stencil.store_op(),
1121                    texture_memory_actions,
1122                    view,
1123                    pending_discard_init_fixups,
1124                );
1125            } else {
1126                // This is the only place (anywhere in wgpu) where Stencil &
1127                // Depth init state can diverge.
1128                //
1129                // To safe us the overhead of tracking init state of texture
1130                // aspects everywhere, we're going to cheat a little bit in
1131                // order to keep the init state of both Stencil and Depth
1132                // aspects in sync. The expectation is that we hit this path
1133                // extremely rarely!
1134                //
1135                // Diverging LoadOp, i.e. Load + Clear:
1136                //
1137                // Record MemoryInitKind::NeedsInitializedMemory for the entire
1138                // surface, a bit wasteful on unit but no negative effect!
1139                //
1140                // Rationale: If the loaded channel is uninitialized it needs
1141                // clearing, the cleared channel doesn't care. (If everything is
1142                // already initialized nothing special happens)
1143                //
1144                // (possible minor optimization: Clear caused by
1145                // NeedsInitializedMemory should know that it doesn't need to
1146                // clear the aspect that was set to C)
1147                let need_init_beforehand =
1148                    at.depth.load_op() == LoadOp::Load || at.stencil.load_op() == LoadOp::Load;
1149                if need_init_beforehand {
1150                    pending_discard_init_fixups.extend(
1151                        texture_memory_actions.register_init_action(&TextureInitTrackerAction {
1152                            texture: view.parent.clone(),
1153                            range: TextureInitRange::from(view.selector.clone()),
1154                            kind: MemoryInitKind::NeedsInitializedMemory,
1155                        }),
1156                    );
1157                }
1158
1159                // Diverging Store, i.e. Discard + Store:
1160                //
1161                // Immediately zero out channel that is set to discard after
1162                // we're done with the render pass. This allows us to set the
1163                // entire surface to MemoryInitKind::ImplicitlyInitialized (if
1164                // it isn't already set to NeedsInitializedMemory).
1165                //
1166                // (possible optimization: Delay and potentially drop this zeroing)
1167                if at.depth.store_op() != at.stencil.store_op() {
1168                    if !need_init_beforehand {
1169                        texture_memory_actions.register_implicit_init(
1170                            &view.parent,
1171                            TextureInitRange::from(view.selector.clone()),
1172                        );
1173                    }
1174                    divergent_discarded_depth_stencil_aspect = Some((
1175                        if at.depth.store_op() == StoreOp::Discard {
1176                            wgt::TextureAspect::DepthOnly
1177                        } else {
1178                            wgt::TextureAspect::StencilOnly
1179                        },
1180                        view.clone(),
1181                    ));
1182                } else if at.depth.store_op() == StoreOp::Discard {
1183                    // Both are discarded using the regular path.
1184                    discarded_surfaces.push(TextureSurfaceDiscard {
1185                        texture: view.parent.clone(),
1186                        mip_level: view.selector.mips.start,
1187                        layer: view.selector.layers.start,
1188                    });
1189                }
1190            }
1191
1192            is_depth_read_only = at.depth.is_readonly();
1193            is_stencil_read_only = at.stencil.is_readonly();
1194
1195            let usage = if is_depth_read_only
1196                && is_stencil_read_only
1197                && device
1198                    .downlevel
1199                    .flags
1200                    .contains(wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
1201            {
1202                wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::RESOURCE
1203            } else {
1204                wgt::TextureUses::DEPTH_STENCIL_WRITE
1205            };
1206            render_attachments.push(view.to_render_attachment(usage));
1207
1208            depth_stencil = Some(hal::DepthStencilAttachment {
1209                target: hal::Attachment {
1210                    view: view.try_raw(snatch_guard)?,
1211                    usage,
1212                },
1213                depth_ops: at.depth.hal_ops(),
1214                stencil_ops: at.stencil.hal_ops(),
1215                clear_value: (at.depth.clear_value(), at.stencil.clear_value()),
1216            });
1217        }
1218
1219        let mut attachment_set = crate::FastHashSet::default();
1220
1221        let mut color_attachments_hal =
1222            ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
1223        for (index, attachment) in color_attachments.iter().enumerate() {
1224            let at = if let Some(attachment) = attachment.as_ref() {
1225                attachment
1226            } else {
1227                color_attachments_hal.push(None);
1228                continue;
1229            };
1230            let color_view: &TextureView = &at.view;
1231            color_view.same_device(device)?;
1232            check_multiview(color_view)?;
1233            add_view(
1234                color_view,
1235                AttachmentErrorLocation::Color {
1236                    index,
1237                    resolve: false,
1238                },
1239            )?;
1240
1241            if !color_view.desc.aspects().intersects(
1242                hal::FormatAspects::COLOR
1243                    | hal::FormatAspects::PLANE_0
1244                    | hal::FormatAspects::PLANE_1
1245                    | hal::FormatAspects::PLANE_2,
1246            ) {
1247                return Err(RenderPassErrorInner::ColorAttachment(
1248                    ColorAttachmentError::InvalidFormat(color_view.desc.format),
1249                ));
1250            }
1251
1252            if color_view.desc.dimension == TextureViewDimension::D3 {
1253                if let Some(depth_slice) = at.depth_slice {
1254                    let mip = color_view.desc.range.base_mip_level;
1255                    let mip_size = color_view
1256                        .parent
1257                        .desc
1258                        .size
1259                        .mip_level_size(mip, color_view.parent.desc.dimension);
1260                    let limit = mip_size.depth_or_array_layers;
1261                    if depth_slice >= limit {
1262                        return Err(RenderPassErrorInner::ColorAttachment(
1263                            ColorAttachmentError::DepthSliceLimit {
1264                                given: depth_slice,
1265                                limit,
1266                            },
1267                        ));
1268                    }
1269                } else {
1270                    return Err(RenderPassErrorInner::ColorAttachment(
1271                        ColorAttachmentError::MissingDepthSlice,
1272                    ));
1273                }
1274            } else if at.depth_slice.is_some() {
1275                return Err(RenderPassErrorInner::ColorAttachment(
1276                    ColorAttachmentError::UnneededDepthSlice,
1277                ));
1278            }
1279
1280            validation::validate_color_attachment_bytes_per_sample(
1281                color_attachments
1282                    .iter()
1283                    .flatten()
1284                    .map(|at| at.view.desc.format),
1285                device.limits.max_color_attachment_bytes_per_sample,
1286            )
1287            .map_err(RenderPassErrorInner::ColorAttachment)?;
1288
1289            fn check_attachment_overlap(
1290                attachment_set: &mut crate::FastHashSet<(crate::track::TrackerIndex, u32, u32)>,
1291                view: &TextureView,
1292                depth_slice: Option<u32>,
1293            ) -> Result<(), ColorAttachmentError> {
1294                let mut insert = |slice| {
1295                    let mip_level = view.desc.range.base_mip_level;
1296                    if attachment_set.insert((
1297                        view.parent.tracking_data.tracker_index(),
1298                        mip_level,
1299                        slice,
1300                    )) {
1301                        Ok(())
1302                    } else {
1303                        Err(ColorAttachmentError::SubresourceOverlap {
1304                            view: view.error_ident(),
1305                            mip_level,
1306                            depth_or_array_layer: slice,
1307                        })
1308                    }
1309                };
1310                match view.desc.dimension {
1311                    TextureViewDimension::D2 => {
1312                        insert(view.desc.range.base_array_layer)?;
1313                    }
1314                    TextureViewDimension::D2Array => {
1315                        for layer in view.selector.layers.clone() {
1316                            insert(layer)?;
1317                        }
1318                    }
1319                    TextureViewDimension::D3 => {
1320                        insert(depth_slice.unwrap())?;
1321                    }
1322                    _ => unreachable!(),
1323                };
1324                Ok(())
1325            }
1326
1327            check_attachment_overlap(&mut attachment_set, color_view, at.depth_slice)?;
1328
1329            Self::add_pass_texture_init_actions(
1330                at.load_op,
1331                at.store_op,
1332                texture_memory_actions,
1333                color_view,
1334                pending_discard_init_fixups,
1335            );
1336            render_attachments
1337                .push(color_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1338
1339            let mut hal_resolve_target = None;
1340            if let Some(resolve_view) = &at.resolve_target {
1341                resolve_view.same_device(device)?;
1342                check_multiview(resolve_view)?;
1343
1344                check_attachment_overlap(&mut attachment_set, resolve_view, None)?;
1345
1346                let resolve_location = AttachmentErrorLocation::Color {
1347                    index,
1348                    resolve: true,
1349                };
1350
1351                let render_extent = resolve_view.render_extent.map_err(|reason| {
1352                    RenderPassErrorInner::TextureViewIsNotRenderable {
1353                        location: resolve_location,
1354                        reason,
1355                    }
1356                })?;
1357                if color_view.render_extent.unwrap() != render_extent {
1358                    return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1359                        expected_location: attachment_location,
1360                        expected_extent: extent.unwrap_or_default(),
1361                        actual_location: resolve_location,
1362                        actual_extent: render_extent,
1363                    });
1364                }
1365                if color_view.samples == 1 || resolve_view.samples != 1 {
1366                    return Err(RenderPassErrorInner::InvalidResolveSampleCounts {
1367                        location: resolve_location,
1368                        src: color_view.samples,
1369                        dst: resolve_view.samples,
1370                    });
1371                }
1372                if color_view.desc.format != resolve_view.desc.format {
1373                    return Err(RenderPassErrorInner::MismatchedResolveTextureFormat {
1374                        location: resolve_location,
1375                        src: color_view.desc.format,
1376                        dst: resolve_view.desc.format,
1377                    });
1378                }
1379                if !resolve_view
1380                    .format_features
1381                    .flags
1382                    .contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE)
1383                {
1384                    return Err(RenderPassErrorInner::UnsupportedResolveTargetFormat {
1385                        location: resolve_location,
1386                        format: resolve_view.desc.format,
1387                    });
1388                }
1389
1390                texture_memory_actions.register_implicit_init(
1391                    &resolve_view.parent,
1392                    TextureInitRange::from(resolve_view.selector.clone()),
1393                );
1394                render_attachments
1395                    .push(resolve_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1396
1397                hal_resolve_target = Some(hal::Attachment {
1398                    view: resolve_view.try_raw(snatch_guard)?,
1399                    usage: wgt::TextureUses::COLOR_TARGET,
1400                });
1401            }
1402
1403            color_attachments_hal.push(Some(hal::ColorAttachment {
1404                target: hal::Attachment {
1405                    view: color_view.try_raw(snatch_guard)?,
1406                    usage: wgt::TextureUses::COLOR_TARGET,
1407                },
1408                depth_slice: at.depth_slice,
1409                resolve_target: hal_resolve_target,
1410                ops: at.hal_ops(),
1411                clear_value: at.clear_value(),
1412            }));
1413        }
1414
1415        let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
1416
1417        let detected_multiview =
1418            detected_multiview.expect("Multiview was not detected, no attachments");
1419        if let Some(mask) = multiview_mask {
1420            // 0x01 will have msb 0
1421            let mask_msb = 31 - mask.leading_zeros();
1422            let detected_mv = detected_multiview.map(NonZeroU32::get).unwrap_or(1);
1423            if mask_msb >= detected_mv {
1424                return Err(RenderPassErrorInner::MultiViewMismatch);
1425            }
1426            if mask.get() != (1 << detected_mv) - 1 {
1427                device.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
1428            }
1429        }
1430
1431        let attachment_formats = AttachmentData {
1432            colors: color_attachments
1433                .iter()
1434                .map(|at| at.as_ref().map(|at| at.view.desc.format))
1435                .collect(),
1436            resolves: color_attachments
1437                .iter()
1438                .filter_map(|at| {
1439                    at.as_ref().and_then(|at| {
1440                        at.resolve_target
1441                            .as_ref()
1442                            .map(|resolve| resolve.desc.format)
1443                    })
1444                })
1445                .collect(),
1446            depth_stencil: depth_stencil_attachment
1447                .as_ref()
1448                .map(|at| at.view.desc.format),
1449        };
1450
1451        let context = RenderPassContext {
1452            attachments: attachment_formats,
1453            sample_count,
1454            multiview_mask,
1455        };
1456
1457        let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() {
1458            let query_set = &tw.query_set;
1459            query_set.same_device(device)?;
1460
1461            if let Some(index) = tw.beginning_of_pass_write_index {
1462                pending_query_resets.use_query_set(query_set, index);
1463            }
1464            if let Some(index) = tw.end_of_pass_write_index {
1465                pending_query_resets.use_query_set(query_set, index);
1466            }
1467
1468            Some(hal::PassTimestampWrites {
1469                query_set: query_set.raw(),
1470                beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
1471                end_of_pass_write_index: tw.end_of_pass_write_index,
1472            })
1473        } else {
1474            None
1475        };
1476
1477        let occlusion_query_set_hal = if let Some(query_set) = occlusion_query_set.as_ref() {
1478            query_set.same_device(device)?;
1479            Some(query_set.raw())
1480        } else {
1481            None
1482        };
1483
1484        let hal_desc = hal::RenderPassDescriptor {
1485            label: hal_label,
1486            extent,
1487            sample_count,
1488            color_attachments: &color_attachments_hal,
1489            depth_stencil_attachment: depth_stencil,
1490            multiview_mask,
1491            timestamp_writes: timestamp_writes_hal,
1492            occlusion_query_set: occlusion_query_set_hal,
1493        };
1494        unsafe {
1495            encoder
1496                .begin_render_pass(&hal_desc)
1497                .map_err(|e| device.handle_hal_error(e))?;
1498        };
1499        drop(color_attachments_hal); // Drop, so we can consume `color_attachments` for the tracker.
1500
1501        // Can't borrow the tracker more than once, so have to add to the tracker after the `begin_render_pass` hal call.
1502        if let Some(tw) = timestamp_writes.take() {
1503            trackers.query_sets.insert_single(tw.query_set);
1504        };
1505        if let Some(occlusion_query_set) = occlusion_query_set.take() {
1506            trackers.query_sets.insert_single(occlusion_query_set);
1507        };
1508        if let Some(at) = depth_stencil_attachment.take() {
1509            trackers.views.insert_single(at.view.clone());
1510        }
1511        for at in color_attachments.iter().flatten() {
1512            trackers.views.insert_single(at.view.clone());
1513            if let Some(resolve_target) = at.resolve_target.clone() {
1514                trackers.views.insert_single(resolve_target);
1515            }
1516        }
1517
1518        Ok(Self {
1519            context,
1520            render_attachments,
1521            is_depth_read_only,
1522            is_stencil_read_only,
1523            extent,
1524            divergent_discarded_depth_stencil_aspect,
1525            multiview_mask,
1526        })
1527    }
1528
1529    fn finish(
1530        self,
1531        device: &Device,
1532        raw: &mut dyn hal::DynCommandEncoder,
1533        snatch_guard: &SnatchGuard,
1534        scope: &mut UsageScope<'_>,
1535        instance_flags: wgt::InstanceFlags,
1536    ) -> Result<(), RenderPassErrorInner> {
1537        profiling::scope!("RenderPassInfo::finish");
1538        unsafe {
1539            raw.end_render_pass();
1540        }
1541
1542        for ra in self.render_attachments {
1543            let texture = &ra.texture;
1544            texture.check_usage(TextureUsages::RENDER_ATTACHMENT)?;
1545
1546            // the tracker set of the pass is always in "extend" mode
1547            unsafe {
1548                scope
1549                    .textures
1550                    .merge_single(texture, Some(ra.selector.clone()), ra.usage)?
1551            };
1552        }
1553
1554        // If either only stencil or depth was discarded, we put in a special
1555        // clear pass to keep the init status of the aspects in sync. We do this
1556        // so we don't need to track init state for depth/stencil aspects
1557        // individually.
1558        //
1559        // Note that we don't go the usual route of "brute force" initializing
1560        // the texture when need arises here, since this path is actually
1561        // something a user may genuinely want (where as the other cases are
1562        // more seen along the lines as gracefully handling a user error).
1563        if let Some((aspect, view)) = self.divergent_discarded_depth_stencil_aspect {
1564            let (depth_ops, stencil_ops) = if aspect == wgt::TextureAspect::DepthOnly {
1565                (
1566                    hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, // clear depth
1567                    hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE,       // unchanged stencil
1568                )
1569            } else {
1570                (
1571                    hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, // unchanged stencil
1572                    hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, // clear depth
1573                )
1574            };
1575            let desc = hal::RenderPassDescriptor::<'_, _, dyn hal::DynTextureView> {
1576                label: hal_label(
1577                    Some("(wgpu internal) Zero init discarded depth/stencil aspect"),
1578                    instance_flags,
1579                ),
1580                extent: view.render_extent.unwrap(),
1581                sample_count: view.samples,
1582                color_attachments: &[],
1583                depth_stencil_attachment: Some(hal::DepthStencilAttachment {
1584                    target: hal::Attachment {
1585                        view: view.try_raw(snatch_guard)?,
1586                        usage: wgt::TextureUses::DEPTH_STENCIL_WRITE,
1587                    },
1588                    depth_ops,
1589                    stencil_ops,
1590                    clear_value: (0.0, 0),
1591                }),
1592                multiview_mask: self.multiview_mask,
1593                timestamp_writes: None,
1594                occlusion_query_set: None,
1595            };
1596            unsafe {
1597                raw.begin_render_pass(&desc)
1598                    .map_err(|e| device.handle_hal_error(e))?;
1599                raw.end_render_pass();
1600            }
1601        }
1602
1603        Ok(())
1604    }
1605}
1606
1607impl Global {
1608    /// Creates a render pass.
1609    ///
1610    /// If creation fails, an invalid pass is returned. Attempting to record
1611    /// commands into an invalid pass is permitted, but a validation error will
1612    /// ultimately be generated when the parent encoder is finished, and it is
1613    /// not possible to run any commands from the invalid pass.
1614    ///
1615    /// If successful, puts the encoder into the [`Locked`] state.
1616    ///
1617    /// [`Locked`]: crate::command::CommandEncoderStatus::Locked
1618    pub fn command_encoder_begin_render_pass(
1619        &self,
1620        encoder_id: id::CommandEncoderId,
1621        desc: &RenderPassDescriptor<'_>,
1622    ) -> (RenderPass, Option<CommandEncoderError>) {
1623        use EncoderStateError as SErr;
1624
1625        fn fill_arc_desc(
1626            hub: &crate::hub::Hub,
1627            desc: &RenderPassDescriptor<'_>,
1628            arc_desc: &mut ArcRenderPassDescriptor,
1629            device: &Device,
1630        ) -> Result<(), RenderPassErrorInner> {
1631            device.check_is_valid()?;
1632
1633            let query_sets = hub.query_sets.read();
1634            let texture_views = hub.texture_views.read();
1635
1636            let max_color_attachments = device.limits.max_color_attachments as usize;
1637            if desc.color_attachments.len() > max_color_attachments {
1638                return Err(RenderPassErrorInner::ColorAttachment(
1639                    ColorAttachmentError::TooMany {
1640                        given: desc.color_attachments.len(),
1641                        limit: max_color_attachments,
1642                    },
1643                ));
1644            }
1645
1646            for color_attachment in desc.color_attachments.iter() {
1647                if let Some(RenderPassColorAttachment {
1648                    view: view_id,
1649                    depth_slice,
1650                    resolve_target,
1651                    load_op,
1652                    store_op,
1653                }) = color_attachment
1654                {
1655                    let view = texture_views.get(*view_id).get()?;
1656                    view.same_device(device)?;
1657
1658                    if view.desc.usage.contains(TextureUsages::TRANSIENT)
1659                        && *store_op != StoreOp::Discard
1660                    {
1661                        return Err(RenderPassErrorInner::ColorAttachment(
1662                            ColorAttachmentError::InvalidUsageForStoreOp(
1663                                TextureUsages::TRANSIENT,
1664                                StoreOp::Discard,
1665                                *store_op,
1666                            ),
1667                        ));
1668                    }
1669
1670                    let resolve_target = if let Some(resolve_target_id) = resolve_target {
1671                        let rt_arc = texture_views.get(*resolve_target_id).get()?;
1672                        rt_arc.same_device(device)?;
1673
1674                        Some(rt_arc)
1675                    } else {
1676                        None
1677                    };
1678
1679                    arc_desc
1680                        .color_attachments
1681                        .push(Some(ArcRenderPassColorAttachment {
1682                            view,
1683                            depth_slice: *depth_slice,
1684                            resolve_target,
1685                            load_op: *load_op,
1686                            store_op: *store_op,
1687                        }));
1688                } else {
1689                    arc_desc.color_attachments.push(None);
1690                }
1691            }
1692
1693            arc_desc.depth_stencil_attachment =
1694            // https://gpuweb.github.io/gpuweb/#abstract-opdef-gpurenderpassdepthstencilattachment-gpurenderpassdepthstencilattachment-valid-usage
1695                if let Some(depth_stencil_attachment) = desc.depth_stencil_attachment {
1696                    let view = texture_views.get(depth_stencil_attachment.view).get()?;
1697                    view.same_device(device)?;
1698
1699                    let format = view.desc.format;
1700                    if !format.is_depth_stencil_format() {
1701                        return Err(RenderPassErrorInner::InvalidAttachment(AttachmentError::InvalidDepthStencilAttachmentFormat(
1702                            view.desc.format,
1703                        )));
1704                    }
1705
1706                    Some(ResolvedRenderPassDepthStencilAttachment {
1707                        view,
1708                        depth: if format.has_depth_aspect() {
1709                            depth_stencil_attachment.depth.resolve(|clear| if let Some(clear) = clear {
1710                                // If this.depthLoadOp is "clear", this.depthClearValue must be provided and must be between 0.0 and 1.0, inclusive.
1711                                if !(0.0..=1.0).contains(&clear) {
1712                                    Err(AttachmentError::ClearValueOutOfRange(clear))
1713                                } else {
1714                                    Ok(clear)
1715                                }
1716                            } else {
1717                                Err(AttachmentError::NoClearValue)
1718                            })?
1719                        } else {
1720                            ResolvedPassChannel::ReadOnly
1721                        },
1722                        stencil: if format.has_stencil_aspect() {
1723                            depth_stencil_attachment.stencil.resolve(|clear| Ok(clear.unwrap_or_default()))?
1724                        } else {
1725                            ResolvedPassChannel::ReadOnly
1726                        },
1727                    })
1728                } else {
1729                    None
1730                };
1731
1732            arc_desc.timestamp_writes = desc
1733                .timestamp_writes
1734                .map(|tw| {
1735                    Global::validate_pass_timestamp_writes::<RenderPassErrorInner>(
1736                        device,
1737                        &query_sets,
1738                        tw,
1739                    )
1740                })
1741                .transpose()?;
1742
1743            arc_desc.occlusion_query_set =
1744                if let Some(occlusion_query_set) = desc.occlusion_query_set {
1745                    let query_set = query_sets.get(occlusion_query_set).get()?;
1746                    query_set.same_device(device)?;
1747
1748                    Some(query_set)
1749                } else {
1750                    None
1751                };
1752
1753            arc_desc.multiview_mask = desc.multiview_mask;
1754
1755            Ok(())
1756        }
1757
1758        let scope = PassErrorScope::Pass;
1759        let hub = &self.hub;
1760
1761        let cmd_enc = hub.command_encoders.get(encoder_id);
1762        let mut cmd_buf_data = cmd_enc.data.lock();
1763
1764        match cmd_buf_data.lock_encoder() {
1765            Ok(()) => {
1766                drop(cmd_buf_data);
1767                let mut arc_desc = ArcRenderPassDescriptor {
1768                    label: &desc.label,
1769                    timestamp_writes: None,
1770                    color_attachments: ArrayVec::new(),
1771                    depth_stencil_attachment: None,
1772                    occlusion_query_set: None,
1773                    multiview_mask: None,
1774                };
1775                match fill_arc_desc(hub, desc, &mut arc_desc, &cmd_enc.device) {
1776                    Ok(()) => (RenderPass::new(cmd_enc, arc_desc), None),
1777                    Err(err) => (
1778                        RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1779                        None,
1780                    ),
1781                }
1782            }
1783            Err(err @ SErr::Locked) => {
1784                // Attempting to open a new pass while the encoder is locked
1785                // invalidates the encoder, but does not generate a validation
1786                // error.
1787                cmd_buf_data.invalidate(err.clone());
1788                drop(cmd_buf_data);
1789                (
1790                    RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1791                    None,
1792                )
1793            }
1794            Err(err @ (SErr::Ended | SErr::Submitted)) => {
1795                // Attempting to open a new pass after the encode has ended
1796                // generates an immediate validation error.
1797                drop(cmd_buf_data);
1798                (
1799                    RenderPass::new_invalid(cmd_enc, &desc.label, err.clone().map_pass_err(scope)),
1800                    Some(err.into()),
1801                )
1802            }
1803            Err(err @ SErr::Invalid) => {
1804                // Passes can be opened even on an invalid encoder. Such passes
1805                // are even valid, but since there's no visible side-effect of
1806                // the pass being valid and there's no point in storing recorded
1807                // commands that will ultimately be discarded, we open an
1808                // invalid pass to save that work.
1809                drop(cmd_buf_data);
1810                (
1811                    RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1812                    None,
1813                )
1814            }
1815            Err(SErr::Unlocked) => {
1816                unreachable!("lock_encoder cannot fail due to the encoder being unlocked")
1817            }
1818        }
1819    }
1820
1821    pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
1822        profiling::scope!(
1823            "CommandEncoder::run_render_pass {}",
1824            pass.base.label.as_deref().unwrap_or("")
1825        );
1826
1827        let cmd_enc = pass.parent.take().ok_or(EncoderStateError::Ended)?;
1828        let mut cmd_buf_data = cmd_enc.data.lock();
1829
1830        cmd_buf_data.unlock_encoder()?;
1831
1832        let base = pass.base.take();
1833
1834        if let Err(RenderPassError {
1835            inner:
1836                RenderPassErrorInner::EncoderState(
1837                    err @ (EncoderStateError::Locked | EncoderStateError::Ended),
1838                ),
1839            scope: _,
1840        }) = base
1841        {
1842            // Most encoding errors are detected and raised within `finish()`.
1843            //
1844            // However, we raise a validation error here if the pass was opened
1845            // within another pass, or on a finished encoder. The latter is
1846            // particularly important, because in that case reporting errors via
1847            // `CommandEncoder::finish` is not possible.
1848            return Err(err.clone());
1849        }
1850
1851        cmd_buf_data.push_with(|| -> Result<_, RenderPassError> {
1852            Ok(ArcCommand::RunRenderPass {
1853                pass: base?,
1854                color_attachments: SmallVec::from(pass.color_attachments.as_slice()),
1855                depth_stencil_attachment: pass.depth_stencil_attachment.take(),
1856                timestamp_writes: pass.timestamp_writes.take(),
1857                occlusion_query_set: pass.occlusion_query_set.take(),
1858                multiview_mask: pass.multiview_mask,
1859            })
1860        })
1861    }
1862}
1863
1864pub(super) fn encode_render_pass(
1865    parent_state: &mut EncodingState<InnerCommandEncoder>,
1866    mut base: BasePass<ArcRenderCommand, Infallible>,
1867    color_attachments: ColorAttachments<Arc<TextureView>>,
1868    mut depth_stencil_attachment: Option<
1869        ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
1870    >,
1871    mut timestamp_writes: Option<ArcPassTimestampWrites>,
1872    occlusion_query_set: Option<Arc<QuerySet>>,
1873    multiview_mask: Option<NonZeroU32>,
1874) -> Result<(), RenderPassError> {
1875    let pass_scope = PassErrorScope::Pass;
1876
1877    let device = parent_state.device;
1878
1879    let mut indirect_draw_validation_batcher = crate::indirect_validation::DrawBatcher::new();
1880
1881    // We automatically keep extending command buffers over time, and because
1882    // we want to insert a command buffer _before_ what we're about to record,
1883    // we need to make sure to close the previous one.
1884    parent_state
1885        .raw_encoder
1886        .close_if_open()
1887        .map_pass_err(pass_scope)?;
1888    let raw_encoder = parent_state
1889        .raw_encoder
1890        .open_pass(base.label.as_deref())
1891        .map_pass_err(pass_scope)?;
1892
1893    let (scope, pending_discard_init_fixups, mut pending_query_resets) = {
1894        let mut pending_query_resets = QueryResetMap::new();
1895        let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
1896
1897        let info = RenderPassInfo::start(
1898            device,
1899            hal_label(base.label.as_deref(), device.instance_flags),
1900            &color_attachments,
1901            depth_stencil_attachment.take(),
1902            timestamp_writes.take(),
1903            // Still needed down the line.
1904            // TODO(wumpf): by restructuring the code, we could get rid of some of this Arc clone.
1905            occlusion_query_set.clone(),
1906            raw_encoder,
1907            parent_state.tracker,
1908            parent_state.texture_memory_actions,
1909            &mut pending_query_resets,
1910            &mut pending_discard_init_fixups,
1911            parent_state.snatch_guard,
1912            multiview_mask,
1913        )
1914        .map_pass_err(pass_scope)?;
1915
1916        let indices = &device.tracker_indices;
1917        parent_state
1918            .tracker
1919            .buffers
1920            .set_size(indices.buffers.size());
1921        parent_state
1922            .tracker
1923            .textures
1924            .set_size(indices.textures.size());
1925
1926        let mut debug_scope_depth = 0;
1927
1928        let mut state = State {
1929            pipeline_flags: PipelineFlags::empty(),
1930            blend_constant: OptionalState::Unused,
1931            stencil_reference: 0,
1932            pipeline: None,
1933            index: IndexState::default(),
1934            vertex: VertexState::default(),
1935
1936            info,
1937
1938            pass: pass::PassState {
1939                base: EncodingState {
1940                    device,
1941                    raw_encoder,
1942                    tracker: parent_state.tracker,
1943                    buffer_memory_init_actions: parent_state.buffer_memory_init_actions,
1944                    texture_memory_actions: parent_state.texture_memory_actions,
1945                    as_actions: parent_state.as_actions,
1946                    temp_resources: parent_state.temp_resources,
1947                    indirect_draw_validation_resources: parent_state
1948                        .indirect_draw_validation_resources,
1949                    snatch_guard: parent_state.snatch_guard,
1950                    debug_scope_depth: &mut debug_scope_depth,
1951                },
1952                pending_discard_init_fixups,
1953                scope: device.new_usage_scope(),
1954                binder: Binder::new(),
1955
1956                temp_offsets: Vec::new(),
1957                dynamic_offset_count: 0,
1958
1959                string_offset: 0,
1960            },
1961
1962            active_occlusion_query: None,
1963            active_pipeline_statistics_query: None,
1964        };
1965
1966        for command in base.commands.drain(..) {
1967            match command {
1968                ArcRenderCommand::SetBindGroup {
1969                    index,
1970                    num_dynamic_offsets,
1971                    bind_group,
1972                } => {
1973                    let scope = PassErrorScope::SetBindGroup;
1974                    pass::set_bind_group::<RenderPassErrorInner>(
1975                        &mut state.pass,
1976                        device,
1977                        &base.dynamic_offsets,
1978                        index,
1979                        num_dynamic_offsets,
1980                        bind_group,
1981                        true,
1982                    )
1983                    .map_pass_err(scope)?;
1984                }
1985                ArcRenderCommand::SetPipeline(pipeline) => {
1986                    let scope = PassErrorScope::SetPipelineRender;
1987                    set_pipeline(&mut state, device, pipeline).map_pass_err(scope)?;
1988                }
1989                ArcRenderCommand::SetIndexBuffer {
1990                    buffer,
1991                    index_format,
1992                    offset,
1993                    size,
1994                } => {
1995                    let scope = PassErrorScope::SetIndexBuffer;
1996                    set_index_buffer(&mut state, device, buffer, index_format, offset, size)
1997                        .map_pass_err(scope)?;
1998                }
1999                ArcRenderCommand::SetVertexBuffer {
2000                    slot,
2001                    buffer,
2002                    offset,
2003                    size,
2004                } => {
2005                    let scope = PassErrorScope::SetVertexBuffer;
2006                    set_vertex_buffer(&mut state, device, slot, buffer, offset, size)
2007                        .map_pass_err(scope)?;
2008                }
2009                ArcRenderCommand::SetBlendConstant(ref color) => {
2010                    set_blend_constant(&mut state, color);
2011                }
2012                ArcRenderCommand::SetStencilReference(value) => {
2013                    set_stencil_reference(&mut state, value);
2014                }
2015                ArcRenderCommand::SetViewport {
2016                    rect,
2017                    depth_min,
2018                    depth_max,
2019                } => {
2020                    let scope = PassErrorScope::SetViewport;
2021                    set_viewport(&mut state, rect, depth_min, depth_max).map_pass_err(scope)?;
2022                }
2023                ArcRenderCommand::SetImmediate {
2024                    offset,
2025                    size_bytes,
2026                    values_offset,
2027                } => {
2028                    let scope = PassErrorScope::SetImmediate;
2029                    pass::set_immediates::<RenderPassErrorInner, _>(
2030                        &mut state.pass,
2031                        &base.immediates_data,
2032                        offset,
2033                        size_bytes,
2034                        values_offset,
2035                        |_| {},
2036                    )
2037                    .map_pass_err(scope)?;
2038                }
2039                ArcRenderCommand::SetScissor(rect) => {
2040                    let scope = PassErrorScope::SetScissorRect;
2041                    set_scissor(&mut state, rect).map_pass_err(scope)?;
2042                }
2043                ArcRenderCommand::Draw {
2044                    vertex_count,
2045                    instance_count,
2046                    first_vertex,
2047                    first_instance,
2048                } => {
2049                    let scope = PassErrorScope::Draw {
2050                        kind: DrawKind::Draw,
2051                        family: DrawCommandFamily::Draw,
2052                    };
2053                    draw(
2054                        &mut state,
2055                        vertex_count,
2056                        instance_count,
2057                        first_vertex,
2058                        first_instance,
2059                    )
2060                    .map_pass_err(scope)?;
2061                }
2062                ArcRenderCommand::DrawIndexed {
2063                    index_count,
2064                    instance_count,
2065                    first_index,
2066                    base_vertex,
2067                    first_instance,
2068                } => {
2069                    let scope = PassErrorScope::Draw {
2070                        kind: DrawKind::Draw,
2071                        family: DrawCommandFamily::DrawIndexed,
2072                    };
2073                    draw_indexed(
2074                        &mut state,
2075                        index_count,
2076                        instance_count,
2077                        first_index,
2078                        base_vertex,
2079                        first_instance,
2080                    )
2081                    .map_pass_err(scope)?;
2082                }
2083                ArcRenderCommand::DrawMeshTasks {
2084                    group_count_x,
2085                    group_count_y,
2086                    group_count_z,
2087                } => {
2088                    let scope = PassErrorScope::Draw {
2089                        kind: DrawKind::Draw,
2090                        family: DrawCommandFamily::DrawMeshTasks,
2091                    };
2092                    draw_mesh_tasks(&mut state, group_count_x, group_count_y, group_count_z)
2093                        .map_pass_err(scope)?;
2094                }
2095                ArcRenderCommand::DrawIndirect {
2096                    buffer,
2097                    offset,
2098                    count,
2099                    family,
2100
2101                    vertex_or_index_limit: _,
2102                    instance_limit: _,
2103                } => {
2104                    let scope = PassErrorScope::Draw {
2105                        kind: if count != 1 {
2106                            DrawKind::MultiDrawIndirect
2107                        } else {
2108                            DrawKind::DrawIndirect
2109                        },
2110                        family,
2111                    };
2112                    multi_draw_indirect(
2113                        &mut state,
2114                        &mut indirect_draw_validation_batcher,
2115                        device,
2116                        buffer,
2117                        offset,
2118                        count,
2119                        family,
2120                    )
2121                    .map_pass_err(scope)?;
2122                }
2123                ArcRenderCommand::MultiDrawIndirectCount {
2124                    buffer,
2125                    offset,
2126                    count_buffer,
2127                    count_buffer_offset,
2128                    max_count,
2129                    family,
2130                } => {
2131                    let scope = PassErrorScope::Draw {
2132                        kind: DrawKind::MultiDrawIndirectCount,
2133                        family,
2134                    };
2135                    multi_draw_indirect_count(
2136                        &mut state,
2137                        device,
2138                        buffer,
2139                        offset,
2140                        count_buffer,
2141                        count_buffer_offset,
2142                        max_count,
2143                        family,
2144                    )
2145                    .map_pass_err(scope)?;
2146                }
2147                ArcRenderCommand::PushDebugGroup { color: _, len } => {
2148                    pass::push_debug_group(&mut state.pass, &base.string_data, len);
2149                }
2150                ArcRenderCommand::PopDebugGroup => {
2151                    let scope = PassErrorScope::PopDebugGroup;
2152                    pass::pop_debug_group::<RenderPassErrorInner>(&mut state.pass)
2153                        .map_pass_err(scope)?;
2154                }
2155                ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2156                    pass::insert_debug_marker(&mut state.pass, &base.string_data, len);
2157                }
2158                ArcRenderCommand::WriteTimestamp {
2159                    query_set,
2160                    query_index,
2161                } => {
2162                    let scope = PassErrorScope::WriteTimestamp;
2163                    pass::write_timestamp::<RenderPassErrorInner>(
2164                        &mut state.pass,
2165                        device,
2166                        Some(&mut pending_query_resets),
2167                        query_set,
2168                        query_index,
2169                    )
2170                    .map_pass_err(scope)?;
2171                }
2172                ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2173                    api_log!("RenderPass::begin_occlusion_query {query_index}");
2174                    let scope = PassErrorScope::BeginOcclusionQuery;
2175
2176                    let query_set = occlusion_query_set
2177                        .clone()
2178                        .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2179                        .map_pass_err(scope)?;
2180
2181                    validate_and_begin_occlusion_query(
2182                        query_set,
2183                        state.pass.base.raw_encoder,
2184                        &mut state.pass.base.tracker.query_sets,
2185                        query_index,
2186                        Some(&mut pending_query_resets),
2187                        &mut state.active_occlusion_query,
2188                    )
2189                    .map_pass_err(scope)?;
2190                }
2191                ArcRenderCommand::EndOcclusionQuery => {
2192                    api_log!("RenderPass::end_occlusion_query");
2193                    let scope = PassErrorScope::EndOcclusionQuery;
2194
2195                    end_occlusion_query(
2196                        state.pass.base.raw_encoder,
2197                        &mut state.active_occlusion_query,
2198                    )
2199                    .map_pass_err(scope)?;
2200                }
2201                ArcRenderCommand::BeginPipelineStatisticsQuery {
2202                    query_set,
2203                    query_index,
2204                } => {
2205                    api_log!(
2206                        "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2207                        query_set.error_ident()
2208                    );
2209                    let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2210
2211                    validate_and_begin_pipeline_statistics_query(
2212                        query_set,
2213                        state.pass.base.raw_encoder,
2214                        &mut state.pass.base.tracker.query_sets,
2215                        device,
2216                        query_index,
2217                        Some(&mut pending_query_resets),
2218                        &mut state.active_pipeline_statistics_query,
2219                    )
2220                    .map_pass_err(scope)?;
2221                }
2222                ArcRenderCommand::EndPipelineStatisticsQuery => {
2223                    api_log!("RenderPass::end_pipeline_statistics_query");
2224                    let scope = PassErrorScope::EndPipelineStatisticsQuery;
2225
2226                    end_pipeline_statistics_query(
2227                        state.pass.base.raw_encoder,
2228                        &mut state.active_pipeline_statistics_query,
2229                    )
2230                    .map_pass_err(scope)?;
2231                }
2232                ArcRenderCommand::ExecuteBundle(bundle) => {
2233                    let scope = PassErrorScope::ExecuteBundle;
2234                    execute_bundle(
2235                        &mut state,
2236                        &mut indirect_draw_validation_batcher,
2237                        device,
2238                        bundle,
2239                    )
2240                    .map_pass_err(scope)?;
2241                }
2242            }
2243        }
2244
2245        if *state.pass.base.debug_scope_depth > 0 {
2246            Err(
2247                RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2248                    .map_pass_err(pass_scope),
2249            )?;
2250        }
2251        if state.active_occlusion_query.is_some() {
2252            Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2253                query_type: super::SimplifiedQueryType::Occlusion,
2254            })
2255            .map_pass_err(pass_scope))?;
2256        }
2257        if state.active_pipeline_statistics_query.is_some() {
2258            Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2259                query_type: super::SimplifiedQueryType::PipelineStatistics,
2260            })
2261            .map_pass_err(pass_scope))?;
2262        }
2263
2264        state
2265            .info
2266            .finish(
2267                device,
2268                state.pass.base.raw_encoder,
2269                state.pass.base.snatch_guard,
2270                &mut state.pass.scope,
2271                device.instance_flags,
2272            )
2273            .map_pass_err(pass_scope)?;
2274
2275        let trackers = state.pass.scope;
2276
2277        let pending_discard_init_fixups = state.pass.pending_discard_init_fixups;
2278
2279        parent_state.raw_encoder.close().map_pass_err(pass_scope)?;
2280        (trackers, pending_discard_init_fixups, pending_query_resets)
2281    };
2282
2283    let encoder = &mut parent_state.raw_encoder;
2284    let tracker = &mut parent_state.tracker;
2285
2286    {
2287        let transit = encoder
2288            .open_pass(hal_label(
2289                Some("(wgpu internal) Pre Pass"),
2290                device.instance_flags,
2291            ))
2292            .map_pass_err(pass_scope)?;
2293
2294        fixup_discarded_surfaces(
2295            pending_discard_init_fixups.into_iter(),
2296            transit,
2297            &mut tracker.textures,
2298            device,
2299            parent_state.snatch_guard,
2300        );
2301
2302        pending_query_resets.reset_queries(transit);
2303
2304        CommandEncoder::insert_barriers_from_scope(
2305            transit,
2306            tracker,
2307            &scope,
2308            parent_state.snatch_guard,
2309        );
2310
2311        if let Some(ref indirect_validation) = device.indirect_validation {
2312            indirect_validation
2313                .draw
2314                .inject_validation_pass(
2315                    device,
2316                    parent_state.snatch_guard,
2317                    parent_state.indirect_draw_validation_resources,
2318                    parent_state.temp_resources,
2319                    transit,
2320                    indirect_draw_validation_batcher,
2321                )
2322                .map_pass_err(pass_scope)?;
2323        }
2324    }
2325
2326    encoder.close_and_swap().map_pass_err(pass_scope)?;
2327
2328    Ok(())
2329}
2330
2331fn set_pipeline(
2332    state: &mut State,
2333    device: &Arc<Device>,
2334    pipeline: Arc<RenderPipeline>,
2335) -> Result<(), RenderPassErrorInner> {
2336    api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2337
2338    state.pipeline = Some(pipeline.clone());
2339
2340    let pipeline = state
2341        .pass
2342        .base
2343        .tracker
2344        .render_pipelines
2345        .insert_single(pipeline)
2346        .clone();
2347
2348    pipeline.same_device(device)?;
2349
2350    state
2351        .info
2352        .context
2353        .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2354        .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2355
2356    state.pipeline_flags = pipeline.flags;
2357
2358    if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2359        return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2360    }
2361    if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2362        return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2363    }
2364
2365    state
2366        .blend_constant
2367        .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2368
2369    unsafe {
2370        state
2371            .pass
2372            .base
2373            .raw_encoder
2374            .set_render_pipeline(pipeline.raw());
2375    }
2376
2377    if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2378        unsafe {
2379            state
2380                .pass
2381                .base
2382                .raw_encoder
2383                .set_stencil_reference(state.stencil_reference);
2384        }
2385    }
2386
2387    // Rebind resource
2388    pass::change_pipeline_layout::<RenderPassErrorInner, _>(
2389        &mut state.pass,
2390        &pipeline.layout,
2391        &pipeline.late_sized_buffer_groups,
2392        || {},
2393    )?;
2394
2395    // Update vertex buffer limits.
2396    state.vertex.update_limits(&pipeline.vertex_steps);
2397    Ok(())
2398}
2399
2400// This function is duplicative of `bundle::set_index_buffer`.
2401fn set_index_buffer(
2402    state: &mut State,
2403    device: &Arc<Device>,
2404    buffer: Arc<crate::resource::Buffer>,
2405    index_format: IndexFormat,
2406    offset: u64,
2407    size: Option<BufferSize>,
2408) -> Result<(), RenderPassErrorInner> {
2409    api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2410
2411    state
2412        .pass
2413        .scope
2414        .buffers
2415        .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2416
2417    buffer.same_device(device)?;
2418
2419    buffer.check_usage(BufferUsages::INDEX)?;
2420
2421    if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
2422        return Err(RenderCommandError::UnalignedIndexBuffer {
2423            offset,
2424            alignment: index_format.byte_size(),
2425        }
2426        .into());
2427    }
2428    let (binding, resolved_size) = buffer
2429        .binding(offset, size, state.pass.base.snatch_guard)
2430        .map_err(RenderCommandError::from)?;
2431    let end = offset + resolved_size;
2432    state.index.update_buffer(offset..end, index_format);
2433
2434    state.pass.base.buffer_memory_init_actions.extend(
2435        buffer.initialization_status.read().create_action(
2436            &buffer,
2437            offset..end,
2438            MemoryInitKind::NeedsInitializedMemory,
2439        ),
2440    );
2441
2442    unsafe {
2443        hal::DynCommandEncoder::set_index_buffer(
2444            state.pass.base.raw_encoder,
2445            binding,
2446            index_format,
2447        );
2448    }
2449    Ok(())
2450}
2451
2452// This function is duplicative of `render::set_vertex_buffer`.
2453fn set_vertex_buffer(
2454    state: &mut State,
2455    device: &Arc<Device>,
2456    slot: u32,
2457    buffer: Arc<crate::resource::Buffer>,
2458    offset: u64,
2459    size: Option<BufferSize>,
2460) -> Result<(), RenderPassErrorInner> {
2461    api_log!(
2462        "RenderPass::set_vertex_buffer {slot} {}",
2463        buffer.error_ident()
2464    );
2465
2466    state
2467        .pass
2468        .scope
2469        .buffers
2470        .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2471
2472    buffer.same_device(device)?;
2473
2474    let max_vertex_buffers = state.pass.base.device.limits.max_vertex_buffers;
2475    if slot >= max_vertex_buffers {
2476        return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2477            index: slot,
2478            max: max_vertex_buffers,
2479        }
2480        .into());
2481    }
2482
2483    buffer.check_usage(BufferUsages::VERTEX)?;
2484
2485    if offset % wgt::VERTEX_ALIGNMENT != 0 {
2486        return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2487    }
2488    let (binding, buffer_size) = buffer
2489        .binding(offset, size, state.pass.base.snatch_guard)
2490        .map_err(RenderCommandError::from)?;
2491    state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
2492
2493    state.pass.base.buffer_memory_init_actions.extend(
2494        buffer.initialization_status.read().create_action(
2495            &buffer,
2496            offset..(offset + buffer_size),
2497            MemoryInitKind::NeedsInitializedMemory,
2498        ),
2499    );
2500
2501    unsafe {
2502        hal::DynCommandEncoder::set_vertex_buffer(state.pass.base.raw_encoder, slot, binding);
2503    }
2504    if let Some(pipeline) = state.pipeline.as_ref() {
2505        state.vertex.update_limits(&pipeline.vertex_steps);
2506    }
2507    Ok(())
2508}
2509
2510fn set_blend_constant(state: &mut State, color: &Color) {
2511    api_log!("RenderPass::set_blend_constant");
2512
2513    state.blend_constant = OptionalState::Set;
2514    let array = [
2515        color.r as f32,
2516        color.g as f32,
2517        color.b as f32,
2518        color.a as f32,
2519    ];
2520    unsafe {
2521        state.pass.base.raw_encoder.set_blend_constants(&array);
2522    }
2523}
2524
2525fn set_stencil_reference(state: &mut State, value: u32) {
2526    api_log!("RenderPass::set_stencil_reference {value}");
2527
2528    state.stencil_reference = value;
2529    if state
2530        .pipeline_flags
2531        .contains(PipelineFlags::STENCIL_REFERENCE)
2532    {
2533        unsafe {
2534            state.pass.base.raw_encoder.set_stencil_reference(value);
2535        }
2536    }
2537}
2538
2539fn set_viewport(
2540    state: &mut State,
2541    rect: Rect<f32>,
2542    depth_min: f32,
2543    depth_max: f32,
2544) -> Result<(), RenderPassErrorInner> {
2545    api_log!("RenderPass::set_viewport {rect:?}");
2546
2547    if rect.w < 0.0
2548        || rect.h < 0.0
2549        || rect.w > state.pass.base.device.limits.max_texture_dimension_2d as f32
2550        || rect.h > state.pass.base.device.limits.max_texture_dimension_2d as f32
2551    {
2552        return Err(RenderCommandError::InvalidViewportRectSize {
2553            w: rect.w,
2554            h: rect.h,
2555            max: state.pass.base.device.limits.max_texture_dimension_2d,
2556        }
2557        .into());
2558    }
2559
2560    let max_viewport_range = state.pass.base.device.limits.max_texture_dimension_2d as f32 * 2.0;
2561
2562    if rect.x < -max_viewport_range
2563        || rect.y < -max_viewport_range
2564        || rect.x + rect.w > max_viewport_range - 1.0
2565        || rect.y + rect.h > max_viewport_range - 1.0
2566    {
2567        return Err(RenderCommandError::InvalidViewportRectPosition {
2568            rect,
2569            min: -max_viewport_range,
2570            max: max_viewport_range - 1.0,
2571        }
2572        .into());
2573    }
2574    if !(0.0..=1.0).contains(&depth_min)
2575        || !(0.0..=1.0).contains(&depth_max)
2576        || depth_min > depth_max
2577    {
2578        return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
2579    }
2580    let r = hal::Rect {
2581        x: rect.x,
2582        y: rect.y,
2583        w: rect.w,
2584        h: rect.h,
2585    };
2586    unsafe {
2587        state
2588            .pass
2589            .base
2590            .raw_encoder
2591            .set_viewport(&r, depth_min..depth_max);
2592    }
2593    Ok(())
2594}
2595
2596fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
2597    api_log!("RenderPass::set_scissor_rect {rect:?}");
2598
2599    if rect.x.saturating_add(rect.w) > state.info.extent.width
2600        || rect.y.saturating_add(rect.h) > state.info.extent.height
2601    {
2602        return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
2603    }
2604    let r = hal::Rect {
2605        x: rect.x,
2606        y: rect.y,
2607        w: rect.w,
2608        h: rect.h,
2609    };
2610    unsafe {
2611        state.pass.base.raw_encoder.set_scissor_rect(&r);
2612    }
2613    Ok(())
2614}
2615
2616fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
2617    if let Some(mv) = state.info.multiview_mask {
2618        let highest_bit = 31 - mv.leading_zeros();
2619
2620        let features = state.pass.base.device.features;
2621
2622        if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
2623            || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
2624        {
2625            return Err(RenderPassErrorInner::Draw(
2626                DrawError::MeshPipelineMultiviewLimitsViolated {
2627                    highest_view_index: highest_bit,
2628                    max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
2629                },
2630            ));
2631        }
2632    }
2633    Ok(())
2634}
2635
2636fn draw(
2637    state: &mut State,
2638    vertex_count: u32,
2639    instance_count: u32,
2640    first_vertex: u32,
2641    first_instance: u32,
2642) -> Result<(), RenderPassErrorInner> {
2643    api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
2644
2645    state.is_ready(DrawCommandFamily::Draw)?;
2646    state.flush_bindings()?;
2647
2648    state
2649        .vertex
2650        .limits
2651        .validate_vertex_limit(first_vertex, vertex_count)?;
2652    state
2653        .vertex
2654        .limits
2655        .validate_instance_limit(first_instance, instance_count)?;
2656
2657    unsafe {
2658        if instance_count > 0 && vertex_count > 0 {
2659            state.pass.base.raw_encoder.draw(
2660                first_vertex,
2661                vertex_count,
2662                first_instance,
2663                instance_count,
2664            );
2665        }
2666    }
2667    Ok(())
2668}
2669
2670fn draw_indexed(
2671    state: &mut State,
2672    index_count: u32,
2673    instance_count: u32,
2674    first_index: u32,
2675    base_vertex: i32,
2676    first_instance: u32,
2677) -> Result<(), RenderPassErrorInner> {
2678    api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
2679
2680    state.is_ready(DrawCommandFamily::DrawIndexed)?;
2681    state.flush_bindings()?;
2682
2683    let last_index = first_index as u64 + index_count as u64;
2684    let index_limit = state.index.limit;
2685    if last_index > index_limit {
2686        return Err(DrawError::IndexBeyondLimit {
2687            last_index,
2688            index_limit,
2689        }
2690        .into());
2691    }
2692    state
2693        .vertex
2694        .limits
2695        .validate_instance_limit(first_instance, instance_count)?;
2696
2697    unsafe {
2698        if instance_count > 0 && index_count > 0 {
2699            state.pass.base.raw_encoder.draw_indexed(
2700                first_index,
2701                index_count,
2702                base_vertex,
2703                first_instance,
2704                instance_count,
2705            );
2706        }
2707    }
2708    Ok(())
2709}
2710
2711fn draw_mesh_tasks(
2712    state: &mut State,
2713    group_count_x: u32,
2714    group_count_y: u32,
2715    group_count_z: u32,
2716) -> Result<(), RenderPassErrorInner> {
2717    api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
2718
2719    state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
2720
2721    state.flush_bindings()?;
2722    validate_mesh_draw_multiview(state)?;
2723
2724    let groups_size_limit = state
2725        .pass
2726        .base
2727        .device
2728        .limits
2729        .max_task_mesh_workgroups_per_dimension;
2730    let max_groups = state
2731        .pass
2732        .base
2733        .device
2734        .limits
2735        .max_task_mesh_workgroup_total_count;
2736    if group_count_x > groups_size_limit
2737        || group_count_y > groups_size_limit
2738        || group_count_z > groups_size_limit
2739        || group_count_x * group_count_y * group_count_z > max_groups
2740    {
2741        return Err(DrawError::InvalidGroupSize {
2742            current: [group_count_x, group_count_y, group_count_z],
2743            limit: groups_size_limit,
2744            max_total: max_groups,
2745        }
2746        .into());
2747    }
2748
2749    unsafe {
2750        if group_count_x > 0 && group_count_y > 0 && group_count_z > 0 {
2751            state.pass.base.raw_encoder.draw_mesh_tasks(
2752                group_count_x,
2753                group_count_y,
2754                group_count_z,
2755            );
2756        }
2757    }
2758    Ok(())
2759}
2760
2761fn multi_draw_indirect(
2762    state: &mut State,
2763    indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2764    device: &Arc<Device>,
2765    indirect_buffer: Arc<crate::resource::Buffer>,
2766    offset: u64,
2767    count: u32,
2768    family: DrawCommandFamily,
2769) -> Result<(), RenderPassErrorInner> {
2770    api_log!(
2771        "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
2772        indirect_buffer.error_ident()
2773    );
2774
2775    state.is_ready(family)?;
2776    state.flush_bindings()?;
2777
2778    if family == DrawCommandFamily::DrawMeshTasks {
2779        validate_mesh_draw_multiview(state)?;
2780    }
2781
2782    state
2783        .pass
2784        .base
2785        .device
2786        .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2787
2788    indirect_buffer.same_device(device)?;
2789    indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2790    indirect_buffer.check_destroyed(state.pass.base.snatch_guard)?;
2791
2792    if offset % 4 != 0 {
2793        return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2794    }
2795
2796    let stride = get_stride_of_indirect_args(family);
2797
2798    let end_offset = offset + stride * count as u64;
2799    if end_offset > indirect_buffer.size {
2800        return Err(RenderPassErrorInner::IndirectBufferOverrun {
2801            count,
2802            offset,
2803            end_offset,
2804            buffer_size: indirect_buffer.size,
2805        });
2806    }
2807
2808    state.pass.base.buffer_memory_init_actions.extend(
2809        indirect_buffer.initialization_status.read().create_action(
2810            &indirect_buffer,
2811            offset..end_offset,
2812            MemoryInitKind::NeedsInitializedMemory,
2813        ),
2814    );
2815
2816    fn draw(
2817        raw_encoder: &mut dyn hal::DynCommandEncoder,
2818        family: DrawCommandFamily,
2819        indirect_buffer: &dyn hal::DynBuffer,
2820        offset: u64,
2821        count: u32,
2822    ) {
2823        match family {
2824            DrawCommandFamily::Draw => unsafe {
2825                raw_encoder.draw_indirect(indirect_buffer, offset, count);
2826            },
2827            DrawCommandFamily::DrawIndexed => unsafe {
2828                raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2829            },
2830            DrawCommandFamily::DrawMeshTasks => unsafe {
2831                raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
2832            },
2833        }
2834    }
2835
2836    if state.pass.base.device.indirect_validation.is_some() {
2837        state
2838            .pass
2839            .scope
2840            .buffers
2841            .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
2842
2843        struct DrawData {
2844            buffer_index: usize,
2845            offset: u64,
2846            count: u32,
2847        }
2848
2849        struct DrawContext<'a> {
2850            raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2851            device: &'a Device,
2852
2853            indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
2854            indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
2855
2856            indirect_buffer: Arc<crate::resource::Buffer>,
2857            family: DrawCommandFamily,
2858            vertex_or_index_limit: u64,
2859            instance_limit: u64,
2860        }
2861
2862        impl<'a> DrawContext<'a> {
2863            fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2864                let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2865                    self.indirect_draw_validation_resources,
2866                    self.device,
2867                    &self.indirect_buffer,
2868                    offset,
2869                    self.family,
2870                    self.vertex_or_index_limit,
2871                    self.instance_limit,
2872                )?;
2873                Ok(DrawData {
2874                    buffer_index: dst_resource_index,
2875                    offset: dst_offset,
2876                    count: 1,
2877                })
2878            }
2879            fn draw(&mut self, draw_data: DrawData) {
2880                let dst_buffer = self
2881                    .indirect_draw_validation_resources
2882                    .get_dst_buffer(draw_data.buffer_index);
2883                draw(
2884                    self.raw_encoder,
2885                    self.family,
2886                    dst_buffer,
2887                    draw_data.offset,
2888                    draw_data.count,
2889                );
2890            }
2891        }
2892
2893        let mut draw_ctx = DrawContext {
2894            raw_encoder: state.pass.base.raw_encoder,
2895            device: state.pass.base.device,
2896            indirect_draw_validation_resources: state.pass.base.indirect_draw_validation_resources,
2897            indirect_draw_validation_batcher,
2898            indirect_buffer,
2899            family,
2900            vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
2901                state.index.limit
2902            } else {
2903                state.vertex.limits.vertex_limit
2904            },
2905            instance_limit: state.vertex.limits.instance_limit,
2906        };
2907
2908        let mut current_draw_data = draw_ctx.add(offset)?;
2909
2910        for i in 1..count {
2911            let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2912
2913            if draw_data.buffer_index == current_draw_data.buffer_index {
2914                debug_assert_eq!(
2915                    draw_data.offset,
2916                    current_draw_data.offset + stride * current_draw_data.count as u64
2917                );
2918                current_draw_data.count += 1;
2919            } else {
2920                draw_ctx.draw(current_draw_data);
2921                current_draw_data = draw_data;
2922            }
2923        }
2924
2925        draw_ctx.draw(current_draw_data);
2926    } else {
2927        state
2928            .pass
2929            .scope
2930            .buffers
2931            .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2932
2933        draw(
2934            state.pass.base.raw_encoder,
2935            family,
2936            indirect_buffer.try_raw(state.pass.base.snatch_guard)?,
2937            offset,
2938            count,
2939        );
2940    };
2941
2942    Ok(())
2943}
2944
2945fn multi_draw_indirect_count(
2946    state: &mut State,
2947    device: &Arc<Device>,
2948    indirect_buffer: Arc<crate::resource::Buffer>,
2949    offset: u64,
2950    count_buffer: Arc<crate::resource::Buffer>,
2951    count_buffer_offset: u64,
2952    max_count: u32,
2953    family: DrawCommandFamily,
2954) -> Result<(), RenderPassErrorInner> {
2955    api_log!(
2956        "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
2957        indirect_buffer.error_ident(),
2958        count_buffer.error_ident()
2959    );
2960
2961    state.is_ready(family)?;
2962    state.flush_bindings()?;
2963
2964    if family == DrawCommandFamily::DrawMeshTasks {
2965        validate_mesh_draw_multiview(state)?;
2966    }
2967
2968    let stride = get_stride_of_indirect_args(family);
2969
2970    state
2971        .pass
2972        .base
2973        .device
2974        .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
2975    state
2976        .pass
2977        .base
2978        .device
2979        .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2980
2981    indirect_buffer.same_device(device)?;
2982    count_buffer.same_device(device)?;
2983
2984    state
2985        .pass
2986        .scope
2987        .buffers
2988        .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2989
2990    indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2991    let indirect_raw = indirect_buffer.try_raw(state.pass.base.snatch_guard)?;
2992
2993    state
2994        .pass
2995        .scope
2996        .buffers
2997        .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
2998
2999    count_buffer.check_usage(BufferUsages::INDIRECT)?;
3000    let count_raw = count_buffer.try_raw(state.pass.base.snatch_guard)?;
3001
3002    if offset % 4 != 0 {
3003        return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
3004    }
3005
3006    let end_offset = offset + stride * max_count as u64;
3007    if end_offset > indirect_buffer.size {
3008        return Err(RenderPassErrorInner::IndirectBufferOverrun {
3009            count: 1,
3010            offset,
3011            end_offset,
3012            buffer_size: indirect_buffer.size,
3013        });
3014    }
3015    state.pass.base.buffer_memory_init_actions.extend(
3016        indirect_buffer.initialization_status.read().create_action(
3017            &indirect_buffer,
3018            offset..end_offset,
3019            MemoryInitKind::NeedsInitializedMemory,
3020        ),
3021    );
3022
3023    let begin_count_offset = count_buffer_offset;
3024    let end_count_offset = count_buffer_offset + 4;
3025    if end_count_offset > count_buffer.size {
3026        return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
3027            begin_count_offset,
3028            end_count_offset,
3029            count_buffer_size: count_buffer.size,
3030        });
3031    }
3032    state.pass.base.buffer_memory_init_actions.extend(
3033        count_buffer.initialization_status.read().create_action(
3034            &count_buffer,
3035            count_buffer_offset..end_count_offset,
3036            MemoryInitKind::NeedsInitializedMemory,
3037        ),
3038    );
3039
3040    match family {
3041        DrawCommandFamily::Draw => unsafe {
3042            state.pass.base.raw_encoder.draw_indirect_count(
3043                indirect_raw,
3044                offset,
3045                count_raw,
3046                count_buffer_offset,
3047                max_count,
3048            );
3049        },
3050        DrawCommandFamily::DrawIndexed => unsafe {
3051            state.pass.base.raw_encoder.draw_indexed_indirect_count(
3052                indirect_raw,
3053                offset,
3054                count_raw,
3055                count_buffer_offset,
3056                max_count,
3057            );
3058        },
3059        DrawCommandFamily::DrawMeshTasks => unsafe {
3060            state.pass.base.raw_encoder.draw_mesh_tasks_indirect_count(
3061                indirect_raw,
3062                offset,
3063                count_raw,
3064                count_buffer_offset,
3065                max_count,
3066            );
3067        },
3068    }
3069    Ok(())
3070}
3071
3072fn execute_bundle(
3073    state: &mut State,
3074    indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3075    device: &Arc<Device>,
3076    bundle: Arc<super::RenderBundle>,
3077) -> Result<(), RenderPassErrorInner> {
3078    api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
3079
3080    let bundle = state.pass.base.tracker.bundles.insert_single(bundle);
3081
3082    bundle.same_device(device)?;
3083
3084    state
3085        .info
3086        .context
3087        .check_compatible(&bundle.context, bundle.as_ref())
3088        .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
3089
3090    if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3091        || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3092    {
3093        return Err(
3094            RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3095                pass_depth: state.info.is_depth_read_only,
3096                pass_stencil: state.info.is_stencil_read_only,
3097                bundle_depth: bundle.is_depth_read_only,
3098                bundle_stencil: bundle.is_stencil_read_only,
3099            },
3100        );
3101    }
3102
3103    state.pass.base.buffer_memory_init_actions.extend(
3104        bundle
3105            .buffer_memory_init_actions
3106            .iter()
3107            .filter_map(|action| {
3108                action
3109                    .buffer
3110                    .initialization_status
3111                    .read()
3112                    .check_action(action)
3113            }),
3114    );
3115    for action in bundle.texture_memory_init_actions.iter() {
3116        state.pass.pending_discard_init_fixups.extend(
3117            state
3118                .pass
3119                .base
3120                .texture_memory_actions
3121                .register_init_action(action),
3122        );
3123    }
3124
3125    unsafe {
3126        bundle.execute(
3127            state.pass.base.raw_encoder,
3128            state.pass.base.indirect_draw_validation_resources,
3129            indirect_draw_validation_batcher,
3130            state.pass.base.snatch_guard,
3131        )
3132    }
3133    .map_err(|e| match e {
3134        ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3135        ExecutionError::DestroyedResource(e) => {
3136            RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3137        }
3138        ExecutionError::Unimplemented(what) => {
3139            RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3140        }
3141    })?;
3142
3143    unsafe {
3144        state.pass.scope.merge_render_bundle(&bundle.used)?;
3145    };
3146    state.reset_bundle();
3147    Ok(())
3148}
3149
3150// Recording a render pass.
3151//
3152// The only error that should be returned from these methods is
3153// `EncoderStateError::Ended`, when the pass has already ended and an immediate
3154// validation error is raised.
3155//
3156// All other errors should be stored in the pass for later reporting when
3157// `CommandEncoder.finish()` is called.
3158//
3159// The `pass_try!` macro should be used to handle errors appropriately. Note
3160// that the `pass_try!` and `pass_base!` macros may return early from the
3161// function that invokes them, like the `?` operator.
3162impl Global {
3163    pub fn render_pass_set_bind_group(
3164        &self,
3165        pass: &mut RenderPass,
3166        index: u32,
3167        bind_group_id: Option<id::BindGroupId>,
3168        offsets: &[DynamicOffset],
3169    ) -> Result<(), PassStateError> {
3170        let scope = PassErrorScope::SetBindGroup;
3171
3172        // This statement will return an error if the pass is ended. It's
3173        // important the error check comes before the early-out for
3174        // `set_and_check_redundant`.
3175        let base = pass_base!(pass, scope);
3176
3177        if pass.current_bind_groups.set_and_check_redundant(
3178            bind_group_id,
3179            index,
3180            &mut base.dynamic_offsets,
3181            offsets,
3182        ) {
3183            return Ok(());
3184        }
3185
3186        let mut bind_group = None;
3187        if let Some(bind_group_id) = bind_group_id {
3188            let hub = &self.hub;
3189            bind_group = Some(pass_try!(
3190                base,
3191                scope,
3192                hub.bind_groups.get(bind_group_id).get(),
3193            ));
3194        }
3195
3196        base.commands.push(ArcRenderCommand::SetBindGroup {
3197            index,
3198            num_dynamic_offsets: offsets.len(),
3199            bind_group,
3200        });
3201
3202        Ok(())
3203    }
3204
3205    pub fn render_pass_set_pipeline(
3206        &self,
3207        pass: &mut RenderPass,
3208        pipeline_id: id::RenderPipelineId,
3209    ) -> Result<(), PassStateError> {
3210        let scope = PassErrorScope::SetPipelineRender;
3211
3212        let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3213
3214        // This statement will return an error if the pass is ended.
3215        // Its important the error check comes before the early-out for `redundant`.
3216        let base = pass_base!(pass, scope);
3217
3218        if redundant {
3219            return Ok(());
3220        }
3221
3222        let hub = &self.hub;
3223        let pipeline = pass_try!(base, scope, hub.render_pipelines.get(pipeline_id).get());
3224
3225        base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3226
3227        Ok(())
3228    }
3229
3230    pub fn render_pass_set_index_buffer(
3231        &self,
3232        pass: &mut RenderPass,
3233        buffer_id: id::BufferId,
3234        index_format: IndexFormat,
3235        offset: BufferAddress,
3236        size: Option<BufferSize>,
3237    ) -> Result<(), PassStateError> {
3238        let scope = PassErrorScope::SetIndexBuffer;
3239        let base = pass_base!(pass, scope);
3240
3241        base.commands.push(ArcRenderCommand::SetIndexBuffer {
3242            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3243            index_format,
3244            offset,
3245            size,
3246        });
3247
3248        Ok(())
3249    }
3250
3251    pub fn render_pass_set_vertex_buffer(
3252        &self,
3253        pass: &mut RenderPass,
3254        slot: u32,
3255        buffer_id: id::BufferId,
3256        offset: BufferAddress,
3257        size: Option<BufferSize>,
3258    ) -> Result<(), PassStateError> {
3259        let scope = PassErrorScope::SetVertexBuffer;
3260        let base = pass_base!(pass, scope);
3261
3262        base.commands.push(ArcRenderCommand::SetVertexBuffer {
3263            slot,
3264            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3265            offset,
3266            size,
3267        });
3268
3269        Ok(())
3270    }
3271
3272    pub fn render_pass_set_blend_constant(
3273        &self,
3274        pass: &mut RenderPass,
3275        color: Color,
3276    ) -> Result<(), PassStateError> {
3277        let scope = PassErrorScope::SetBlendConstant;
3278        let base = pass_base!(pass, scope);
3279
3280        base.commands
3281            .push(ArcRenderCommand::SetBlendConstant(color));
3282
3283        Ok(())
3284    }
3285
3286    pub fn render_pass_set_stencil_reference(
3287        &self,
3288        pass: &mut RenderPass,
3289        value: u32,
3290    ) -> Result<(), PassStateError> {
3291        let scope = PassErrorScope::SetStencilReference;
3292        let base = pass_base!(pass, scope);
3293
3294        base.commands
3295            .push(ArcRenderCommand::SetStencilReference(value));
3296
3297        Ok(())
3298    }
3299
3300    pub fn render_pass_set_viewport(
3301        &self,
3302        pass: &mut RenderPass,
3303        x: f32,
3304        y: f32,
3305        w: f32,
3306        h: f32,
3307        depth_min: f32,
3308        depth_max: f32,
3309    ) -> Result<(), PassStateError> {
3310        let scope = PassErrorScope::SetViewport;
3311        let base = pass_base!(pass, scope);
3312
3313        base.commands.push(ArcRenderCommand::SetViewport {
3314            rect: Rect { x, y, w, h },
3315            depth_min,
3316            depth_max,
3317        });
3318
3319        Ok(())
3320    }
3321
3322    pub fn render_pass_set_scissor_rect(
3323        &self,
3324        pass: &mut RenderPass,
3325        x: u32,
3326        y: u32,
3327        w: u32,
3328        h: u32,
3329    ) -> Result<(), PassStateError> {
3330        let scope = PassErrorScope::SetScissorRect;
3331        let base = pass_base!(pass, scope);
3332
3333        base.commands
3334            .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3335
3336        Ok(())
3337    }
3338
3339    pub fn render_pass_set_immediates(
3340        &self,
3341        pass: &mut RenderPass,
3342        offset: u32,
3343        data: &[u8],
3344    ) -> Result<(), PassStateError> {
3345        let scope = PassErrorScope::SetImmediate;
3346        let base = pass_base!(pass, scope);
3347
3348        if offset & (wgt::IMMEDIATE_DATA_ALIGNMENT - 1) != 0 {
3349            pass_try!(
3350                base,
3351                scope,
3352                Err(RenderPassErrorInner::ImmediateOffsetAlignment)
3353            );
3354        }
3355        if data.len() as u32 & (wgt::IMMEDIATE_DATA_ALIGNMENT - 1) != 0 {
3356            pass_try!(
3357                base,
3358                scope,
3359                Err(RenderPassErrorInner::ImmediateDataizeAlignment)
3360            );
3361        }
3362
3363        let value_offset = pass_try!(
3364            base,
3365            scope,
3366            base.immediates_data
3367                .len()
3368                .try_into()
3369                .map_err(|_| RenderPassErrorInner::ImmediateOutOfMemory),
3370        );
3371
3372        base.immediates_data.extend(
3373            data.chunks_exact(wgt::IMMEDIATE_DATA_ALIGNMENT as usize)
3374                .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3375        );
3376
3377        base.commands.push(ArcRenderCommand::SetImmediate {
3378            offset,
3379            size_bytes: data.len() as u32,
3380            values_offset: Some(value_offset),
3381        });
3382
3383        Ok(())
3384    }
3385
3386    pub fn render_pass_draw(
3387        &self,
3388        pass: &mut RenderPass,
3389        vertex_count: u32,
3390        instance_count: u32,
3391        first_vertex: u32,
3392        first_instance: u32,
3393    ) -> Result<(), PassStateError> {
3394        let scope = PassErrorScope::Draw {
3395            kind: DrawKind::Draw,
3396            family: DrawCommandFamily::Draw,
3397        };
3398        let base = pass_base!(pass, scope);
3399
3400        base.commands.push(ArcRenderCommand::Draw {
3401            vertex_count,
3402            instance_count,
3403            first_vertex,
3404            first_instance,
3405        });
3406
3407        Ok(())
3408    }
3409
3410    pub fn render_pass_draw_indexed(
3411        &self,
3412        pass: &mut RenderPass,
3413        index_count: u32,
3414        instance_count: u32,
3415        first_index: u32,
3416        base_vertex: i32,
3417        first_instance: u32,
3418    ) -> Result<(), PassStateError> {
3419        let scope = PassErrorScope::Draw {
3420            kind: DrawKind::Draw,
3421            family: DrawCommandFamily::DrawIndexed,
3422        };
3423        let base = pass_base!(pass, scope);
3424
3425        base.commands.push(ArcRenderCommand::DrawIndexed {
3426            index_count,
3427            instance_count,
3428            first_index,
3429            base_vertex,
3430            first_instance,
3431        });
3432
3433        Ok(())
3434    }
3435
3436    pub fn render_pass_draw_mesh_tasks(
3437        &self,
3438        pass: &mut RenderPass,
3439        group_count_x: u32,
3440        group_count_y: u32,
3441        group_count_z: u32,
3442    ) -> Result<(), RenderPassError> {
3443        let scope = PassErrorScope::Draw {
3444            kind: DrawKind::Draw,
3445            family: DrawCommandFamily::DrawMeshTasks,
3446        };
3447        let base = pass_base!(pass, scope);
3448
3449        base.commands.push(ArcRenderCommand::DrawMeshTasks {
3450            group_count_x,
3451            group_count_y,
3452            group_count_z,
3453        });
3454        Ok(())
3455    }
3456
3457    pub fn render_pass_draw_indirect(
3458        &self,
3459        pass: &mut RenderPass,
3460        buffer_id: id::BufferId,
3461        offset: BufferAddress,
3462    ) -> Result<(), PassStateError> {
3463        let scope = PassErrorScope::Draw {
3464            kind: DrawKind::DrawIndirect,
3465            family: DrawCommandFamily::Draw,
3466        };
3467        let base = pass_base!(pass, scope);
3468
3469        base.commands.push(ArcRenderCommand::DrawIndirect {
3470            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3471            offset,
3472            count: 1,
3473            family: DrawCommandFamily::Draw,
3474
3475            vertex_or_index_limit: None,
3476            instance_limit: None,
3477        });
3478
3479        Ok(())
3480    }
3481
3482    pub fn render_pass_draw_indexed_indirect(
3483        &self,
3484        pass: &mut RenderPass,
3485        buffer_id: id::BufferId,
3486        offset: BufferAddress,
3487    ) -> Result<(), PassStateError> {
3488        let scope = PassErrorScope::Draw {
3489            kind: DrawKind::DrawIndirect,
3490            family: DrawCommandFamily::DrawIndexed,
3491        };
3492        let base = pass_base!(pass, scope);
3493
3494        base.commands.push(ArcRenderCommand::DrawIndirect {
3495            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3496            offset,
3497            count: 1,
3498            family: DrawCommandFamily::DrawIndexed,
3499
3500            vertex_or_index_limit: None,
3501            instance_limit: None,
3502        });
3503
3504        Ok(())
3505    }
3506
3507    pub fn render_pass_draw_mesh_tasks_indirect(
3508        &self,
3509        pass: &mut RenderPass,
3510        buffer_id: id::BufferId,
3511        offset: BufferAddress,
3512    ) -> Result<(), RenderPassError> {
3513        let scope = PassErrorScope::Draw {
3514            kind: DrawKind::DrawIndirect,
3515            family: DrawCommandFamily::DrawMeshTasks,
3516        };
3517        let base = pass_base!(pass, scope);
3518
3519        base.commands.push(ArcRenderCommand::DrawIndirect {
3520            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3521            offset,
3522            count: 1,
3523            family: DrawCommandFamily::DrawMeshTasks,
3524
3525            vertex_or_index_limit: None,
3526            instance_limit: None,
3527        });
3528
3529        Ok(())
3530    }
3531
3532    pub fn render_pass_multi_draw_indirect(
3533        &self,
3534        pass: &mut RenderPass,
3535        buffer_id: id::BufferId,
3536        offset: BufferAddress,
3537        count: u32,
3538    ) -> Result<(), PassStateError> {
3539        let scope = PassErrorScope::Draw {
3540            kind: DrawKind::MultiDrawIndirect,
3541            family: DrawCommandFamily::Draw,
3542        };
3543        let base = pass_base!(pass, scope);
3544
3545        base.commands.push(ArcRenderCommand::DrawIndirect {
3546            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3547            offset,
3548            count,
3549            family: DrawCommandFamily::Draw,
3550
3551            vertex_or_index_limit: None,
3552            instance_limit: None,
3553        });
3554
3555        Ok(())
3556    }
3557
3558    pub fn render_pass_multi_draw_indexed_indirect(
3559        &self,
3560        pass: &mut RenderPass,
3561        buffer_id: id::BufferId,
3562        offset: BufferAddress,
3563        count: u32,
3564    ) -> Result<(), PassStateError> {
3565        let scope = PassErrorScope::Draw {
3566            kind: DrawKind::MultiDrawIndirect,
3567            family: DrawCommandFamily::DrawIndexed,
3568        };
3569        let base = pass_base!(pass, scope);
3570
3571        base.commands.push(ArcRenderCommand::DrawIndirect {
3572            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3573            offset,
3574            count,
3575            family: DrawCommandFamily::DrawIndexed,
3576
3577            vertex_or_index_limit: None,
3578            instance_limit: None,
3579        });
3580
3581        Ok(())
3582    }
3583
3584    pub fn render_pass_multi_draw_mesh_tasks_indirect(
3585        &self,
3586        pass: &mut RenderPass,
3587        buffer_id: id::BufferId,
3588        offset: BufferAddress,
3589        count: u32,
3590    ) -> Result<(), RenderPassError> {
3591        let scope = PassErrorScope::Draw {
3592            kind: DrawKind::MultiDrawIndirect,
3593            family: DrawCommandFamily::DrawMeshTasks,
3594        };
3595        let base = pass_base!(pass, scope);
3596
3597        base.commands.push(ArcRenderCommand::DrawIndirect {
3598            buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3599            offset,
3600            count,
3601            family: DrawCommandFamily::DrawMeshTasks,
3602
3603            vertex_or_index_limit: None,
3604            instance_limit: None,
3605        });
3606
3607        Ok(())
3608    }
3609
3610    pub fn render_pass_multi_draw_indirect_count(
3611        &self,
3612        pass: &mut RenderPass,
3613        buffer_id: id::BufferId,
3614        offset: BufferAddress,
3615        count_buffer_id: id::BufferId,
3616        count_buffer_offset: BufferAddress,
3617        max_count: u32,
3618    ) -> Result<(), PassStateError> {
3619        let scope = PassErrorScope::Draw {
3620            kind: DrawKind::MultiDrawIndirectCount,
3621            family: DrawCommandFamily::Draw,
3622        };
3623        let base = pass_base!(pass, scope);
3624
3625        base.commands
3626            .push(ArcRenderCommand::MultiDrawIndirectCount {
3627                buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3628                offset,
3629                count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3630                count_buffer_offset,
3631                max_count,
3632                family: DrawCommandFamily::Draw,
3633            });
3634
3635        Ok(())
3636    }
3637
3638    pub fn render_pass_multi_draw_indexed_indirect_count(
3639        &self,
3640        pass: &mut RenderPass,
3641        buffer_id: id::BufferId,
3642        offset: BufferAddress,
3643        count_buffer_id: id::BufferId,
3644        count_buffer_offset: BufferAddress,
3645        max_count: u32,
3646    ) -> Result<(), PassStateError> {
3647        let scope = PassErrorScope::Draw {
3648            kind: DrawKind::MultiDrawIndirectCount,
3649            family: DrawCommandFamily::DrawIndexed,
3650        };
3651        let base = pass_base!(pass, scope);
3652
3653        base.commands
3654            .push(ArcRenderCommand::MultiDrawIndirectCount {
3655                buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3656                offset,
3657                count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3658                count_buffer_offset,
3659                max_count,
3660                family: DrawCommandFamily::DrawIndexed,
3661            });
3662
3663        Ok(())
3664    }
3665
3666    pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
3667        &self,
3668        pass: &mut RenderPass,
3669        buffer_id: id::BufferId,
3670        offset: BufferAddress,
3671        count_buffer_id: id::BufferId,
3672        count_buffer_offset: BufferAddress,
3673        max_count: u32,
3674    ) -> Result<(), RenderPassError> {
3675        let scope = PassErrorScope::Draw {
3676            kind: DrawKind::MultiDrawIndirectCount,
3677            family: DrawCommandFamily::DrawMeshTasks,
3678        };
3679        let base = pass_base!(pass, scope);
3680
3681        base.commands
3682            .push(ArcRenderCommand::MultiDrawIndirectCount {
3683                buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3684                offset,
3685                count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3686                count_buffer_offset,
3687                max_count,
3688                family: DrawCommandFamily::DrawMeshTasks,
3689            });
3690
3691        Ok(())
3692    }
3693
3694    pub fn render_pass_push_debug_group(
3695        &self,
3696        pass: &mut RenderPass,
3697        label: &str,
3698        color: u32,
3699    ) -> Result<(), PassStateError> {
3700        let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
3701
3702        let bytes = label.as_bytes();
3703        base.string_data.extend_from_slice(bytes);
3704
3705        base.commands.push(ArcRenderCommand::PushDebugGroup {
3706            color,
3707            len: bytes.len(),
3708        });
3709
3710        Ok(())
3711    }
3712
3713    pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
3714        let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
3715
3716        base.commands.push(ArcRenderCommand::PopDebugGroup);
3717
3718        Ok(())
3719    }
3720
3721    pub fn render_pass_insert_debug_marker(
3722        &self,
3723        pass: &mut RenderPass,
3724        label: &str,
3725        color: u32,
3726    ) -> Result<(), PassStateError> {
3727        let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
3728
3729        let bytes = label.as_bytes();
3730        base.string_data.extend_from_slice(bytes);
3731
3732        base.commands.push(ArcRenderCommand::InsertDebugMarker {
3733            color,
3734            len: bytes.len(),
3735        });
3736
3737        Ok(())
3738    }
3739
3740    pub fn render_pass_write_timestamp(
3741        &self,
3742        pass: &mut RenderPass,
3743        query_set_id: id::QuerySetId,
3744        query_index: u32,
3745    ) -> Result<(), PassStateError> {
3746        let scope = PassErrorScope::WriteTimestamp;
3747        let base = pass_base!(pass, scope);
3748
3749        base.commands.push(ArcRenderCommand::WriteTimestamp {
3750            query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3751            query_index,
3752        });
3753
3754        Ok(())
3755    }
3756
3757    pub fn render_pass_begin_occlusion_query(
3758        &self,
3759        pass: &mut RenderPass,
3760        query_index: u32,
3761    ) -> Result<(), PassStateError> {
3762        let scope = PassErrorScope::BeginOcclusionQuery;
3763        let base = pass_base!(pass, scope);
3764
3765        base.commands
3766            .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
3767
3768        Ok(())
3769    }
3770
3771    pub fn render_pass_end_occlusion_query(
3772        &self,
3773        pass: &mut RenderPass,
3774    ) -> Result<(), PassStateError> {
3775        let scope = PassErrorScope::EndOcclusionQuery;
3776        let base = pass_base!(pass, scope);
3777
3778        base.commands.push(ArcRenderCommand::EndOcclusionQuery);
3779
3780        Ok(())
3781    }
3782
3783    pub fn render_pass_begin_pipeline_statistics_query(
3784        &self,
3785        pass: &mut RenderPass,
3786        query_set_id: id::QuerySetId,
3787        query_index: u32,
3788    ) -> Result<(), PassStateError> {
3789        let scope = PassErrorScope::BeginPipelineStatisticsQuery;
3790        let base = pass_base!(pass, scope);
3791
3792        base.commands
3793            .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
3794                query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3795                query_index,
3796            });
3797
3798        Ok(())
3799    }
3800
3801    pub fn render_pass_end_pipeline_statistics_query(
3802        &self,
3803        pass: &mut RenderPass,
3804    ) -> Result<(), PassStateError> {
3805        let scope = PassErrorScope::EndPipelineStatisticsQuery;
3806        let base = pass_base!(pass, scope);
3807
3808        base.commands
3809            .push(ArcRenderCommand::EndPipelineStatisticsQuery);
3810
3811        Ok(())
3812    }
3813
3814    pub fn render_pass_execute_bundles(
3815        &self,
3816        pass: &mut RenderPass,
3817        render_bundle_ids: &[id::RenderBundleId],
3818    ) -> Result<(), PassStateError> {
3819        let scope = PassErrorScope::ExecuteBundle;
3820        let base = pass_base!(pass, scope);
3821
3822        let hub = &self.hub;
3823        let bundles = hub.render_bundles.read();
3824
3825        for &bundle_id in render_bundle_ids {
3826            let bundle = pass_try!(base, scope, bundles.get(bundle_id).get());
3827
3828            base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
3829        }
3830        pass.current_pipeline.reset();
3831        pass.current_bind_groups.reset();
3832
3833        Ok(())
3834    }
3835}
3836
3837pub(crate) const fn get_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
3838    match family {
3839        DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
3840        DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
3841        DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
3842    }
3843}