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