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