wgpu_core/command/
render.rs

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