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