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