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 let e: &dyn WebGpuError = match inner {
874 RenderPassErrorInner::Device(e) => e,
875 RenderPassErrorInner::ColorAttachment(e) => e,
876 RenderPassErrorInner::EncoderState(e) => e,
877 RenderPassErrorInner::DebugGroupError(e) => e,
878 RenderPassErrorInner::MissingFeatures(e) => e,
879 RenderPassErrorInner::MissingDownlevelFlags(e) => e,
880 RenderPassErrorInner::RenderCommand(e) => e,
881 RenderPassErrorInner::Draw(e) => e,
882 RenderPassErrorInner::Bind(e) => e,
883 RenderPassErrorInner::QueryUse(e) => e,
884 RenderPassErrorInner::DestroyedResource(e) => e,
885 RenderPassErrorInner::InvalidResource(e) => e,
886 RenderPassErrorInner::IncompatibleBundleTargets(e) => e,
887 RenderPassErrorInner::InvalidAttachment(e) => e,
888 RenderPassErrorInner::TimestampWrites(e) => e,
889 RenderPassErrorInner::InvalidValuesOffset(e) => e,
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 => return ErrorType::Validation,
914 };
915 e.webgpu_error_type()
916 }
917}
918
919struct RenderAttachment {
920 texture: Arc<Texture>,
921 selector: TextureSelector,
922 usage: wgt::TextureUses,
923}
924
925impl TextureView {
926 fn to_render_attachment(&self, usage: wgt::TextureUses) -> RenderAttachment {
927 RenderAttachment {
928 texture: self.parent.clone(),
929 selector: self.selector.clone(),
930 usage,
931 }
932 }
933}
934
935const MAX_TOTAL_ATTACHMENTS: usize = hal::MAX_COLOR_ATTACHMENTS + hal::MAX_COLOR_ATTACHMENTS + 1;
936type AttachmentDataVec<T> = ArrayVec<T, MAX_TOTAL_ATTACHMENTS>;
937
938struct RenderPassInfo {
939 context: RenderPassContext,
940 render_attachments: AttachmentDataVec<RenderAttachment>,
942 is_depth_read_only: bool,
943 is_stencil_read_only: bool,
944 extent: wgt::Extent3d,
945
946 divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>,
947 multiview_mask: Option<NonZeroU32>,
948}
949
950impl RenderPassInfo {
951 fn add_pass_texture_init_actions<V>(
952 load_op: LoadOp<V>,
953 store_op: StoreOp,
954 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
955 view: &TextureView,
956 pending_discard_init_fixups: &mut SurfacesInDiscardState,
957 ) {
958 if matches!(load_op, LoadOp::Load) {
959 pending_discard_init_fixups.extend(texture_memory_actions.register_init_action(
960 &TextureInitTrackerAction {
961 texture: view.parent.clone(),
962 range: TextureInitRange::from(view.selector.clone()),
963 kind: MemoryInitKind::NeedsInitializedMemory,
965 },
966 ));
967 } else if store_op == StoreOp::Store {
968 texture_memory_actions.register_implicit_init(
970 &view.parent,
971 TextureInitRange::from(view.selector.clone()),
972 );
973 }
974 if store_op == StoreOp::Discard {
975 texture_memory_actions.discard(TextureSurfaceDiscard {
979 texture: view.parent.clone(),
980 mip_level: view.selector.mips.start,
981 layer: view.selector.layers.start,
982 });
983 }
984 }
985
986 fn start(
987 device: &Arc<Device>,
988 hal_label: Option<&str>,
989 color_attachments: &[Option<ArcRenderPassColorAttachment>],
990 mut depth_stencil_attachment: Option<
991 ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
992 >,
993 mut timestamp_writes: Option<ArcPassTimestampWrites>,
994 mut occlusion_query_set: Option<Arc<QuerySet>>,
995 encoder: &mut dyn hal::DynCommandEncoder,
996 trackers: &mut Tracker,
997 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
998 pending_query_resets: &mut QueryResetMap,
999 pending_discard_init_fixups: &mut SurfacesInDiscardState,
1000 snatch_guard: &SnatchGuard<'_>,
1001 multiview_mask: Option<NonZeroU32>,
1002 ) -> Result<Self, RenderPassErrorInner> {
1003 profiling::scope!("RenderPassInfo::start");
1004
1005 let mut is_depth_read_only = false;
1009 let mut is_stencil_read_only = false;
1010
1011 let mut render_attachments = AttachmentDataVec::<RenderAttachment>::new();
1012 let mut discarded_surfaces = AttachmentDataVec::new();
1013 let mut divergent_discarded_depth_stencil_aspect = None;
1014
1015 let mut attachment_location = AttachmentErrorLocation::Color {
1016 index: usize::MAX,
1017 resolve: false,
1018 };
1019 let mut extent = None;
1020 let mut sample_count = 0;
1021
1022 let mut detected_multiview: Option<Option<NonZeroU32>> = None;
1023
1024 let mut check_multiview = |view: &TextureView| {
1025 let layers = view.selector.layers.end - view.selector.layers.start;
1027 let this_multiview = if layers >= 2 {
1028 Some(unsafe { NonZeroU32::new_unchecked(layers) })
1030 } else {
1031 None
1032 };
1033
1034 if this_multiview.is_some() && view.desc.dimension != TextureViewDimension::D2Array {
1036 return Err(RenderPassErrorInner::MultiViewDimensionMismatch);
1037 }
1038
1039 if let Some(multiview) = detected_multiview {
1041 if multiview != this_multiview {
1042 return Err(RenderPassErrorInner::MultiViewMismatch);
1043 }
1044 } else {
1045 if let Some(this_multiview) = this_multiview {
1047 device.require_features(wgt::Features::MULTIVIEW)?;
1048 if this_multiview.get() > device.limits.max_multiview_view_count {
1049 return Err(RenderPassErrorInner::TooManyMultiviewViews);
1050 }
1051 }
1052
1053 detected_multiview = Some(this_multiview);
1054 }
1055
1056 Ok(())
1057 };
1058 let mut add_view = |view: &TextureView, location| {
1059 let render_extent = view.render_extent.map_err(|reason| {
1060 RenderPassErrorInner::TextureViewIsNotRenderable { location, reason }
1061 })?;
1062 if let Some(ex) = extent {
1063 if ex != render_extent {
1064 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1065 expected_location: attachment_location,
1066 expected_extent: ex,
1067 actual_location: location,
1068 actual_extent: render_extent,
1069 });
1070 }
1071 } else {
1072 extent = Some(render_extent);
1073 }
1074 if sample_count == 0 {
1075 sample_count = view.samples;
1076 } else if sample_count != view.samples {
1077 return Err(RenderPassErrorInner::AttachmentSampleCountMismatch {
1078 expected_location: attachment_location,
1079 expected_samples: sample_count,
1080 actual_location: location,
1081 actual_samples: view.samples,
1082 });
1083 }
1084 attachment_location = location;
1085 Ok(())
1086 };
1087
1088 let mut depth_stencil = None;
1089
1090 if let Some(at) = depth_stencil_attachment.as_ref() {
1091 let view = &at.view;
1092 check_multiview(view)?;
1093 add_view(view, AttachmentErrorLocation::Depth)?;
1094
1095 let ds_aspects = view.desc.aspects();
1096
1097 if !ds_aspects.contains(hal::FormatAspects::STENCIL)
1098 || (at.stencil.load_op().eq_variant(at.depth.load_op())
1099 && at.stencil.store_op() == at.depth.store_op())
1100 {
1101 Self::add_pass_texture_init_actions(
1102 at.depth.load_op(),
1103 at.depth.store_op(),
1104 texture_memory_actions,
1105 view,
1106 pending_discard_init_fixups,
1107 );
1108 } else if !ds_aspects.contains(hal::FormatAspects::DEPTH) {
1109 Self::add_pass_texture_init_actions(
1110 at.stencil.load_op(),
1111 at.stencil.store_op(),
1112 texture_memory_actions,
1113 view,
1114 pending_discard_init_fixups,
1115 );
1116 } else {
1117 let need_init_beforehand =
1139 at.depth.load_op() == LoadOp::Load || at.stencil.load_op() == LoadOp::Load;
1140 if need_init_beforehand {
1141 pending_discard_init_fixups.extend(
1142 texture_memory_actions.register_init_action(&TextureInitTrackerAction {
1143 texture: view.parent.clone(),
1144 range: TextureInitRange::from(view.selector.clone()),
1145 kind: MemoryInitKind::NeedsInitializedMemory,
1146 }),
1147 );
1148 }
1149
1150 if at.depth.store_op() != at.stencil.store_op() {
1159 if !need_init_beforehand {
1160 texture_memory_actions.register_implicit_init(
1161 &view.parent,
1162 TextureInitRange::from(view.selector.clone()),
1163 );
1164 }
1165 divergent_discarded_depth_stencil_aspect = Some((
1166 if at.depth.store_op() == StoreOp::Discard {
1167 wgt::TextureAspect::DepthOnly
1168 } else {
1169 wgt::TextureAspect::StencilOnly
1170 },
1171 view.clone(),
1172 ));
1173 } else if at.depth.store_op() == StoreOp::Discard {
1174 discarded_surfaces.push(TextureSurfaceDiscard {
1176 texture: view.parent.clone(),
1177 mip_level: view.selector.mips.start,
1178 layer: view.selector.layers.start,
1179 });
1180 }
1181 }
1182
1183 is_depth_read_only = at.depth.is_readonly();
1184 is_stencil_read_only = at.stencil.is_readonly();
1185
1186 let usage = if is_depth_read_only
1187 && is_stencil_read_only
1188 && device
1189 .downlevel
1190 .flags
1191 .contains(wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
1192 {
1193 wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::RESOURCE
1194 } else {
1195 wgt::TextureUses::DEPTH_STENCIL_WRITE
1196 };
1197 render_attachments.push(view.to_render_attachment(usage));
1198
1199 depth_stencil = Some(hal::DepthStencilAttachment {
1200 target: hal::Attachment {
1201 view: view.try_raw(snatch_guard)?,
1202 usage,
1203 },
1204 depth_ops: at.depth.hal_ops(),
1205 stencil_ops: at.stencil.hal_ops(),
1206 clear_value: (at.depth.clear_value(), at.stencil.clear_value()),
1207 });
1208 }
1209
1210 let mut attachment_set = crate::FastHashSet::default();
1211
1212 let mut color_attachments_hal =
1213 ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
1214 for (index, attachment) in color_attachments.iter().enumerate() {
1215 let at = if let Some(attachment) = attachment.as_ref() {
1216 attachment
1217 } else {
1218 color_attachments_hal.push(None);
1219 continue;
1220 };
1221 let color_view: &TextureView = &at.view;
1222 color_view.same_device(device)?;
1223 check_multiview(color_view)?;
1224 add_view(
1225 color_view,
1226 AttachmentErrorLocation::Color {
1227 index,
1228 resolve: false,
1229 },
1230 )?;
1231
1232 if !color_view.desc.aspects().intersects(
1233 hal::FormatAspects::COLOR
1234 | hal::FormatAspects::PLANE_0
1235 | hal::FormatAspects::PLANE_1
1236 | hal::FormatAspects::PLANE_2,
1237 ) {
1238 return Err(RenderPassErrorInner::ColorAttachment(
1239 ColorAttachmentError::InvalidFormat(color_view.desc.format),
1240 ));
1241 }
1242
1243 if color_view.desc.dimension == TextureViewDimension::D3 {
1244 if let Some(depth_slice) = at.depth_slice {
1245 let mip = color_view.desc.range.base_mip_level;
1246 let mip_size = color_view
1247 .parent
1248 .desc
1249 .size
1250 .mip_level_size(mip, color_view.parent.desc.dimension);
1251 let limit = mip_size.depth_or_array_layers;
1252 if depth_slice >= limit {
1253 return Err(RenderPassErrorInner::ColorAttachment(
1254 ColorAttachmentError::DepthSliceLimit {
1255 given: depth_slice,
1256 limit,
1257 },
1258 ));
1259 }
1260 } else {
1261 return Err(RenderPassErrorInner::ColorAttachment(
1262 ColorAttachmentError::MissingDepthSlice,
1263 ));
1264 }
1265 } else if at.depth_slice.is_some() {
1266 return Err(RenderPassErrorInner::ColorAttachment(
1267 ColorAttachmentError::UnneededDepthSlice,
1268 ));
1269 }
1270
1271 validation::validate_color_attachment_bytes_per_sample(
1272 color_attachments
1273 .iter()
1274 .flatten()
1275 .map(|at| at.view.desc.format),
1276 device.limits.max_color_attachment_bytes_per_sample,
1277 )
1278 .map_err(RenderPassErrorInner::ColorAttachment)?;
1279
1280 fn check_attachment_overlap(
1281 attachment_set: &mut crate::FastHashSet<(crate::track::TrackerIndex, u32, u32)>,
1282 view: &TextureView,
1283 depth_slice: Option<u32>,
1284 ) -> Result<(), ColorAttachmentError> {
1285 let mut insert = |slice| {
1286 let mip_level = view.desc.range.base_mip_level;
1287 if attachment_set.insert((
1288 view.parent.tracking_data.tracker_index(),
1289 mip_level,
1290 slice,
1291 )) {
1292 Ok(())
1293 } else {
1294 Err(ColorAttachmentError::SubresourceOverlap {
1295 view: view.error_ident(),
1296 mip_level,
1297 depth_or_array_layer: slice,
1298 })
1299 }
1300 };
1301 match view.desc.dimension {
1302 TextureViewDimension::D2 => {
1303 insert(view.desc.range.base_array_layer)?;
1304 }
1305 TextureViewDimension::D2Array => {
1306 for layer in view.selector.layers.clone() {
1307 insert(layer)?;
1308 }
1309 }
1310 TextureViewDimension::D3 => {
1311 insert(depth_slice.unwrap())?;
1312 }
1313 _ => unreachable!(),
1314 };
1315 Ok(())
1316 }
1317
1318 check_attachment_overlap(&mut attachment_set, color_view, at.depth_slice)?;
1319
1320 Self::add_pass_texture_init_actions(
1321 at.load_op,
1322 at.store_op,
1323 texture_memory_actions,
1324 color_view,
1325 pending_discard_init_fixups,
1326 );
1327 render_attachments
1328 .push(color_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1329
1330 let mut hal_resolve_target = None;
1331 if let Some(resolve_view) = &at.resolve_target {
1332 resolve_view.same_device(device)?;
1333 check_multiview(resolve_view)?;
1334
1335 check_attachment_overlap(&mut attachment_set, resolve_view, None)?;
1336
1337 let resolve_location = AttachmentErrorLocation::Color {
1338 index,
1339 resolve: true,
1340 };
1341
1342 let render_extent = resolve_view.render_extent.map_err(|reason| {
1343 RenderPassErrorInner::TextureViewIsNotRenderable {
1344 location: resolve_location,
1345 reason,
1346 }
1347 })?;
1348 if color_view.render_extent.unwrap() != render_extent {
1349 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1350 expected_location: attachment_location,
1351 expected_extent: extent.unwrap_or_default(),
1352 actual_location: resolve_location,
1353 actual_extent: render_extent,
1354 });
1355 }
1356 if color_view.samples == 1 || resolve_view.samples != 1 {
1357 return Err(RenderPassErrorInner::InvalidResolveSampleCounts {
1358 location: resolve_location,
1359 src: color_view.samples,
1360 dst: resolve_view.samples,
1361 });
1362 }
1363 if color_view.desc.format != resolve_view.desc.format {
1364 return Err(RenderPassErrorInner::MismatchedResolveTextureFormat {
1365 location: resolve_location,
1366 src: color_view.desc.format,
1367 dst: resolve_view.desc.format,
1368 });
1369 }
1370 if !resolve_view
1371 .format_features
1372 .flags
1373 .contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE)
1374 {
1375 return Err(RenderPassErrorInner::UnsupportedResolveTargetFormat {
1376 location: resolve_location,
1377 format: resolve_view.desc.format,
1378 });
1379 }
1380
1381 texture_memory_actions.register_implicit_init(
1382 &resolve_view.parent,
1383 TextureInitRange::from(resolve_view.selector.clone()),
1384 );
1385 render_attachments
1386 .push(resolve_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1387
1388 hal_resolve_target = Some(hal::Attachment {
1389 view: resolve_view.try_raw(snatch_guard)?,
1390 usage: wgt::TextureUses::COLOR_TARGET,
1391 });
1392 }
1393
1394 color_attachments_hal.push(Some(hal::ColorAttachment {
1395 target: hal::Attachment {
1396 view: color_view.try_raw(snatch_guard)?,
1397 usage: wgt::TextureUses::COLOR_TARGET,
1398 },
1399 depth_slice: at.depth_slice,
1400 resolve_target: hal_resolve_target,
1401 ops: at.hal_ops(),
1402 clear_value: at.clear_value(),
1403 }));
1404 }
1405
1406 let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
1407
1408 let detected_multiview =
1409 detected_multiview.expect("Multiview was not detected, no attachments");
1410 if let Some(mask) = multiview_mask {
1411 let mask_msb = 31 - mask.leading_zeros();
1413 let detected_mv = detected_multiview.map(NonZeroU32::get).unwrap_or(1);
1414 if mask_msb >= detected_mv {
1415 return Err(RenderPassErrorInner::MultiViewMismatch);
1416 }
1417 if mask.get() != (1 << detected_mv) - 1 {
1418 device.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
1419 }
1420 }
1421
1422 let attachment_formats = AttachmentData {
1423 colors: color_attachments
1424 .iter()
1425 .map(|at| at.as_ref().map(|at| at.view.desc.format))
1426 .collect(),
1427 resolves: color_attachments
1428 .iter()
1429 .filter_map(|at| {
1430 at.as_ref().and_then(|at| {
1431 at.resolve_target
1432 .as_ref()
1433 .map(|resolve| resolve.desc.format)
1434 })
1435 })
1436 .collect(),
1437 depth_stencil: depth_stencil_attachment
1438 .as_ref()
1439 .map(|at| at.view.desc.format),
1440 };
1441
1442 let context = RenderPassContext {
1443 attachments: attachment_formats,
1444 sample_count,
1445 multiview_mask,
1446 };
1447
1448 let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() {
1449 let query_set = &tw.query_set;
1450 query_set.same_device(device)?;
1451
1452 if let Some(index) = tw.beginning_of_pass_write_index {
1453 pending_query_resets.use_query_set(query_set, index);
1454 }
1455 if let Some(index) = tw.end_of_pass_write_index {
1456 pending_query_resets.use_query_set(query_set, index);
1457 }
1458
1459 Some(hal::PassTimestampWrites {
1460 query_set: query_set.raw(),
1461 beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
1462 end_of_pass_write_index: tw.end_of_pass_write_index,
1463 })
1464 } else {
1465 None
1466 };
1467
1468 let occlusion_query_set_hal = if let Some(query_set) = occlusion_query_set.as_ref() {
1469 query_set.same_device(device)?;
1470 Some(query_set.raw())
1471 } else {
1472 None
1473 };
1474
1475 let hal_desc = hal::RenderPassDescriptor {
1476 label: hal_label,
1477 extent,
1478 sample_count,
1479 color_attachments: &color_attachments_hal,
1480 depth_stencil_attachment: depth_stencil,
1481 multiview_mask,
1482 timestamp_writes: timestamp_writes_hal,
1483 occlusion_query_set: occlusion_query_set_hal,
1484 };
1485 unsafe {
1486 encoder
1487 .begin_render_pass(&hal_desc)
1488 .map_err(|e| device.handle_hal_error(e))?;
1489 };
1490 drop(color_attachments_hal); if let Some(tw) = timestamp_writes.take() {
1494 trackers.query_sets.insert_single(tw.query_set);
1495 };
1496 if let Some(occlusion_query_set) = occlusion_query_set.take() {
1497 trackers.query_sets.insert_single(occlusion_query_set);
1498 };
1499 if let Some(at) = depth_stencil_attachment.take() {
1500 trackers.views.insert_single(at.view.clone());
1501 }
1502 for at in color_attachments.iter().flatten() {
1503 trackers.views.insert_single(at.view.clone());
1504 if let Some(resolve_target) = at.resolve_target.clone() {
1505 trackers.views.insert_single(resolve_target);
1506 }
1507 }
1508
1509 Ok(Self {
1510 context,
1511 render_attachments,
1512 is_depth_read_only,
1513 is_stencil_read_only,
1514 extent,
1515 divergent_discarded_depth_stencil_aspect,
1516 multiview_mask,
1517 })
1518 }
1519
1520 fn finish(
1521 self,
1522 device: &Device,
1523 raw: &mut dyn hal::DynCommandEncoder,
1524 snatch_guard: &SnatchGuard,
1525 scope: &mut UsageScope<'_>,
1526 instance_flags: wgt::InstanceFlags,
1527 ) -> Result<(), RenderPassErrorInner> {
1528 profiling::scope!("RenderPassInfo::finish");
1529 unsafe {
1530 raw.end_render_pass();
1531 }
1532
1533 for ra in self.render_attachments {
1534 let texture = &ra.texture;
1535 texture.check_usage(TextureUsages::RENDER_ATTACHMENT)?;
1536
1537 unsafe {
1539 scope
1540 .textures
1541 .merge_single(texture, Some(ra.selector.clone()), ra.usage)?
1542 };
1543 }
1544
1545 if let Some((aspect, view)) = self.divergent_discarded_depth_stencil_aspect {
1555 let (depth_ops, stencil_ops) = if aspect == wgt::TextureAspect::DepthOnly {
1556 (
1557 hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, )
1560 } else {
1561 (
1562 hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, )
1565 };
1566 let desc = hal::RenderPassDescriptor::<'_, _, dyn hal::DynTextureView> {
1567 label: hal_label(
1568 Some("(wgpu internal) Zero init discarded depth/stencil aspect"),
1569 instance_flags,
1570 ),
1571 extent: view.render_extent.unwrap(),
1572 sample_count: view.samples,
1573 color_attachments: &[],
1574 depth_stencil_attachment: Some(hal::DepthStencilAttachment {
1575 target: hal::Attachment {
1576 view: view.try_raw(snatch_guard)?,
1577 usage: wgt::TextureUses::DEPTH_STENCIL_WRITE,
1578 },
1579 depth_ops,
1580 stencil_ops,
1581 clear_value: (0.0, 0),
1582 }),
1583 multiview_mask: self.multiview_mask,
1584 timestamp_writes: None,
1585 occlusion_query_set: None,
1586 };
1587 unsafe {
1588 raw.begin_render_pass(&desc)
1589 .map_err(|e| device.handle_hal_error(e))?;
1590 raw.end_render_pass();
1591 }
1592 }
1593
1594 Ok(())
1595 }
1596}
1597
1598impl Global {
1599 pub fn command_encoder_begin_render_pass(
1610 &self,
1611 encoder_id: id::CommandEncoderId,
1612 desc: &RenderPassDescriptor<'_>,
1613 ) -> (RenderPass, Option<CommandEncoderError>) {
1614 use EncoderStateError as SErr;
1615
1616 fn fill_arc_desc(
1617 hub: &crate::hub::Hub,
1618 desc: &RenderPassDescriptor<'_>,
1619 arc_desc: &mut ArcRenderPassDescriptor,
1620 device: &Device,
1621 ) -> Result<(), RenderPassErrorInner> {
1622 device.check_is_valid()?;
1623
1624 let query_sets = hub.query_sets.read();
1625 let texture_views = hub.texture_views.read();
1626
1627 let max_color_attachments = device.limits.max_color_attachments as usize;
1628 if desc.color_attachments.len() > max_color_attachments {
1629 return Err(RenderPassErrorInner::ColorAttachment(
1630 ColorAttachmentError::TooMany {
1631 given: desc.color_attachments.len(),
1632 limit: max_color_attachments,
1633 },
1634 ));
1635 }
1636
1637 for color_attachment in desc.color_attachments.iter() {
1638 if let Some(RenderPassColorAttachment {
1639 view: view_id,
1640 depth_slice,
1641 resolve_target,
1642 load_op,
1643 store_op,
1644 }) = color_attachment
1645 {
1646 let view = texture_views.get(*view_id).get()?;
1647 view.same_device(device)?;
1648
1649 if view.desc.usage.contains(TextureUsages::TRANSIENT)
1650 && *store_op != StoreOp::Discard
1651 {
1652 return Err(RenderPassErrorInner::ColorAttachment(
1653 ColorAttachmentError::InvalidUsageForStoreOp(
1654 TextureUsages::TRANSIENT,
1655 StoreOp::Discard,
1656 *store_op,
1657 ),
1658 ));
1659 }
1660
1661 let resolve_target = if let Some(resolve_target_id) = resolve_target {
1662 let rt_arc = texture_views.get(*resolve_target_id).get()?;
1663 rt_arc.same_device(device)?;
1664
1665 Some(rt_arc)
1666 } else {
1667 None
1668 };
1669
1670 arc_desc
1671 .color_attachments
1672 .push(Some(ArcRenderPassColorAttachment {
1673 view,
1674 depth_slice: *depth_slice,
1675 resolve_target,
1676 load_op: *load_op,
1677 store_op: *store_op,
1678 }));
1679 } else {
1680 arc_desc.color_attachments.push(None);
1681 }
1682 }
1683
1684 arc_desc.depth_stencil_attachment =
1685 if let Some(depth_stencil_attachment) = desc.depth_stencil_attachment {
1687 let view = texture_views.get(depth_stencil_attachment.view).get()?;
1688 view.same_device(device)?;
1689
1690 let format = view.desc.format;
1691 if !format.is_depth_stencil_format() {
1692 return Err(RenderPassErrorInner::InvalidAttachment(AttachmentError::InvalidDepthStencilAttachmentFormat(
1693 view.desc.format,
1694 )));
1695 }
1696
1697 Some(ResolvedRenderPassDepthStencilAttachment {
1698 view,
1699 depth: if format.has_depth_aspect() {
1700 depth_stencil_attachment.depth.resolve(|clear| if let Some(clear) = clear {
1701 if !(0.0..=1.0).contains(&clear) {
1703 Err(AttachmentError::ClearValueOutOfRange(clear))
1704 } else {
1705 Ok(clear)
1706 }
1707 } else {
1708 Err(AttachmentError::NoClearValue)
1709 })?
1710 } else {
1711 ResolvedPassChannel::ReadOnly
1712 },
1713 stencil: if format.has_stencil_aspect() {
1714 depth_stencil_attachment.stencil.resolve(|clear| Ok(clear.unwrap_or_default()))?
1715 } else {
1716 ResolvedPassChannel::ReadOnly
1717 },
1718 })
1719 } else {
1720 None
1721 };
1722
1723 arc_desc.timestamp_writes = desc
1724 .timestamp_writes
1725 .map(|tw| {
1726 Global::validate_pass_timestamp_writes::<RenderPassErrorInner>(
1727 device,
1728 &query_sets,
1729 tw,
1730 )
1731 })
1732 .transpose()?;
1733
1734 arc_desc.occlusion_query_set =
1735 if let Some(occlusion_query_set) = desc.occlusion_query_set {
1736 let query_set = query_sets.get(occlusion_query_set).get()?;
1737 query_set.same_device(device)?;
1738
1739 if !matches!(query_set.desc.ty, wgt::QueryType::Occlusion) {
1740 return Err(QueryUseError::IncompatibleType {
1741 set_type: query_set.desc.ty.into(),
1742 query_type: super::SimplifiedQueryType::Occlusion,
1743 }
1744 .into());
1745 }
1746
1747 Some(query_set)
1748 } else {
1749 None
1750 };
1751
1752 arc_desc.multiview_mask = desc.multiview_mask;
1753
1754 Ok(())
1755 }
1756
1757 let scope = PassErrorScope::Pass;
1758 let hub = &self.hub;
1759
1760 let cmd_enc = hub.command_encoders.get(encoder_id);
1761 let mut cmd_buf_data = cmd_enc.data.lock();
1762
1763 match cmd_buf_data.lock_encoder() {
1764 Ok(()) => {
1765 drop(cmd_buf_data);
1766 let mut arc_desc = ArcRenderPassDescriptor {
1767 label: &desc.label,
1768 timestamp_writes: None,
1769 color_attachments: ArrayVec::new(),
1770 depth_stencil_attachment: None,
1771 occlusion_query_set: None,
1772 multiview_mask: None,
1773 };
1774 match fill_arc_desc(hub, desc, &mut arc_desc, &cmd_enc.device) {
1775 Ok(()) => (RenderPass::new(cmd_enc, arc_desc), None),
1776 Err(err) => (
1777 RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1778 None,
1779 ),
1780 }
1781 }
1782 Err(err @ SErr::Locked) => {
1783 cmd_buf_data.invalidate(err.clone());
1787 drop(cmd_buf_data);
1788 (
1789 RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1790 None,
1791 )
1792 }
1793 Err(err @ (SErr::Ended | SErr::Submitted)) => {
1794 drop(cmd_buf_data);
1797 (
1798 RenderPass::new_invalid(cmd_enc, &desc.label, err.clone().map_pass_err(scope)),
1799 Some(err.into()),
1800 )
1801 }
1802 Err(err @ SErr::Invalid) => {
1803 drop(cmd_buf_data);
1809 (
1810 RenderPass::new_invalid(cmd_enc, &desc.label, err.map_pass_err(scope)),
1811 None,
1812 )
1813 }
1814 Err(SErr::Unlocked) => {
1815 unreachable!("lock_encoder cannot fail due to the encoder being unlocked")
1816 }
1817 }
1818 }
1819
1820 pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
1821 profiling::scope!(
1822 "CommandEncoder::run_render_pass {}",
1823 pass.base.label.as_deref().unwrap_or("")
1824 );
1825
1826 let cmd_enc = pass.parent.take().ok_or(EncoderStateError::Ended)?;
1827 let mut cmd_buf_data = cmd_enc.data.lock();
1828
1829 cmd_buf_data.unlock_encoder()?;
1830
1831 let base = pass.base.take();
1832
1833 if let Err(RenderPassError {
1834 inner:
1835 RenderPassErrorInner::EncoderState(
1836 err @ (EncoderStateError::Locked | EncoderStateError::Ended),
1837 ),
1838 scope: _,
1839 }) = base
1840 {
1841 return Err(err.clone());
1848 }
1849
1850 cmd_buf_data.push_with(|| -> Result<_, RenderPassError> {
1851 Ok(ArcCommand::RunRenderPass {
1852 pass: base?,
1853 color_attachments: SmallVec::from(pass.color_attachments.as_slice()),
1854 depth_stencil_attachment: pass.depth_stencil_attachment.take(),
1855 timestamp_writes: pass.timestamp_writes.take(),
1856 occlusion_query_set: pass.occlusion_query_set.take(),
1857 multiview_mask: pass.multiview_mask,
1858 })
1859 })
1860 }
1861}
1862
1863pub(super) fn encode_render_pass(
1864 parent_state: &mut EncodingState<InnerCommandEncoder>,
1865 mut base: BasePass<ArcRenderCommand, Infallible>,
1866 color_attachments: ColorAttachments<Arc<TextureView>>,
1867 mut depth_stencil_attachment: Option<
1868 ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
1869 >,
1870 mut timestamp_writes: Option<ArcPassTimestampWrites>,
1871 occlusion_query_set: Option<Arc<QuerySet>>,
1872 multiview_mask: Option<NonZeroU32>,
1873) -> Result<(), RenderPassError> {
1874 let pass_scope = PassErrorScope::Pass;
1875
1876 let device = parent_state.device;
1877
1878 let mut indirect_draw_validation_batcher = crate::indirect_validation::DrawBatcher::new();
1879
1880 parent_state
1884 .raw_encoder
1885 .close_if_open()
1886 .map_pass_err(pass_scope)?;
1887 let raw_encoder = parent_state
1888 .raw_encoder
1889 .open_pass(base.label.as_deref())
1890 .map_pass_err(pass_scope)?;
1891
1892 let (scope, pending_discard_init_fixups, mut pending_query_resets) = {
1893 let mut pending_query_resets = QueryResetMap::new();
1894 let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
1895
1896 let info = RenderPassInfo::start(
1897 device,
1898 hal_label(base.label.as_deref(), device.instance_flags),
1899 &color_attachments,
1900 depth_stencil_attachment.take(),
1901 timestamp_writes.take(),
1902 occlusion_query_set.clone(),
1905 raw_encoder,
1906 parent_state.tracker,
1907 parent_state.texture_memory_actions,
1908 &mut pending_query_resets,
1909 &mut pending_discard_init_fixups,
1910 parent_state.snatch_guard,
1911 multiview_mask,
1912 )
1913 .map_pass_err(pass_scope)?;
1914
1915 let indices = &device.tracker_indices;
1916 parent_state
1917 .tracker
1918 .buffers
1919 .set_size(indices.buffers.size());
1920 parent_state
1921 .tracker
1922 .textures
1923 .set_size(indices.textures.size());
1924
1925 let mut debug_scope_depth = 0;
1926
1927 let mut state = State {
1928 pipeline_flags: PipelineFlags::empty(),
1929 blend_constant: OptionalState::Unused,
1930 stencil_reference: 0,
1931 pipeline: None,
1932 index: IndexState::default(),
1933 vertex: VertexState::default(),
1934
1935 info,
1936
1937 pass: pass::PassState {
1938 base: EncodingState {
1939 device,
1940 raw_encoder,
1941 tracker: parent_state.tracker,
1942 buffer_memory_init_actions: parent_state.buffer_memory_init_actions,
1943 texture_memory_actions: parent_state.texture_memory_actions,
1944 as_actions: parent_state.as_actions,
1945 temp_resources: parent_state.temp_resources,
1946 indirect_draw_validation_resources: parent_state
1947 .indirect_draw_validation_resources,
1948 snatch_guard: parent_state.snatch_guard,
1949 debug_scope_depth: &mut debug_scope_depth,
1950 },
1951 pending_discard_init_fixups,
1952 scope: device.new_usage_scope(),
1953 binder: Binder::new(),
1954
1955 temp_offsets: Vec::new(),
1956 dynamic_offset_count: 0,
1957
1958 string_offset: 0,
1959 },
1960
1961 active_occlusion_query: None,
1962 active_pipeline_statistics_query: None,
1963 };
1964
1965 for command in base.commands.drain(..) {
1966 match command {
1967 ArcRenderCommand::SetBindGroup {
1968 index,
1969 num_dynamic_offsets,
1970 bind_group,
1971 } => {
1972 let scope = PassErrorScope::SetBindGroup;
1973 pass::set_bind_group::<RenderPassErrorInner>(
1974 &mut state.pass,
1975 device,
1976 &base.dynamic_offsets,
1977 index,
1978 num_dynamic_offsets,
1979 bind_group,
1980 true,
1981 )
1982 .map_pass_err(scope)?;
1983 }
1984 ArcRenderCommand::SetPipeline(pipeline) => {
1985 let scope = PassErrorScope::SetPipelineRender;
1986 set_pipeline(&mut state, device, pipeline).map_pass_err(scope)?;
1987 }
1988 ArcRenderCommand::SetIndexBuffer {
1989 buffer,
1990 index_format,
1991 offset,
1992 size,
1993 } => {
1994 let scope = PassErrorScope::SetIndexBuffer;
1995 set_index_buffer(&mut state, device, buffer, index_format, offset, size)
1996 .map_pass_err(scope)?;
1997 }
1998 ArcRenderCommand::SetVertexBuffer {
1999 slot,
2000 buffer,
2001 offset,
2002 size,
2003 } => {
2004 let scope = PassErrorScope::SetVertexBuffer;
2005 set_vertex_buffer(&mut state, device, slot, buffer, offset, size)
2006 .map_pass_err(scope)?;
2007 }
2008 ArcRenderCommand::SetBlendConstant(ref color) => {
2009 set_blend_constant(&mut state, color);
2010 }
2011 ArcRenderCommand::SetStencilReference(value) => {
2012 set_stencil_reference(&mut state, value);
2013 }
2014 ArcRenderCommand::SetViewport {
2015 rect,
2016 depth_min,
2017 depth_max,
2018 } => {
2019 let scope = PassErrorScope::SetViewport;
2020 set_viewport(&mut state, rect, depth_min, depth_max).map_pass_err(scope)?;
2021 }
2022 ArcRenderCommand::SetImmediate {
2023 offset,
2024 size_bytes,
2025 values_offset,
2026 } => {
2027 let scope = PassErrorScope::SetImmediate;
2028 pass::set_immediates::<RenderPassErrorInner, _>(
2029 &mut state.pass,
2030 &base.immediates_data,
2031 offset,
2032 size_bytes,
2033 values_offset,
2034 |_| {},
2035 )
2036 .map_pass_err(scope)?;
2037 }
2038 ArcRenderCommand::SetScissor(rect) => {
2039 let scope = PassErrorScope::SetScissorRect;
2040 set_scissor(&mut state, rect).map_pass_err(scope)?;
2041 }
2042 ArcRenderCommand::Draw {
2043 vertex_count,
2044 instance_count,
2045 first_vertex,
2046 first_instance,
2047 } => {
2048 let scope = PassErrorScope::Draw {
2049 kind: DrawKind::Draw,
2050 family: DrawCommandFamily::Draw,
2051 };
2052 draw(
2053 &mut state,
2054 vertex_count,
2055 instance_count,
2056 first_vertex,
2057 first_instance,
2058 )
2059 .map_pass_err(scope)?;
2060 }
2061 ArcRenderCommand::DrawIndexed {
2062 index_count,
2063 instance_count,
2064 first_index,
2065 base_vertex,
2066 first_instance,
2067 } => {
2068 let scope = PassErrorScope::Draw {
2069 kind: DrawKind::Draw,
2070 family: DrawCommandFamily::DrawIndexed,
2071 };
2072 draw_indexed(
2073 &mut state,
2074 index_count,
2075 instance_count,
2076 first_index,
2077 base_vertex,
2078 first_instance,
2079 )
2080 .map_pass_err(scope)?;
2081 }
2082 ArcRenderCommand::DrawMeshTasks {
2083 group_count_x,
2084 group_count_y,
2085 group_count_z,
2086 } => {
2087 let scope = PassErrorScope::Draw {
2088 kind: DrawKind::Draw,
2089 family: DrawCommandFamily::DrawMeshTasks,
2090 };
2091 draw_mesh_tasks(&mut state, group_count_x, group_count_y, group_count_z)
2092 .map_pass_err(scope)?;
2093 }
2094 ArcRenderCommand::DrawIndirect {
2095 buffer,
2096 offset,
2097 count,
2098 family,
2099
2100 vertex_or_index_limit: _,
2101 instance_limit: _,
2102 } => {
2103 let scope = PassErrorScope::Draw {
2104 kind: if count != 1 {
2105 DrawKind::MultiDrawIndirect
2106 } else {
2107 DrawKind::DrawIndirect
2108 },
2109 family,
2110 };
2111 multi_draw_indirect(
2112 &mut state,
2113 &mut indirect_draw_validation_batcher,
2114 device,
2115 buffer,
2116 offset,
2117 count,
2118 family,
2119 )
2120 .map_pass_err(scope)?;
2121 }
2122 ArcRenderCommand::MultiDrawIndirectCount {
2123 buffer,
2124 offset,
2125 count_buffer,
2126 count_buffer_offset,
2127 max_count,
2128 family,
2129 } => {
2130 let scope = PassErrorScope::Draw {
2131 kind: DrawKind::MultiDrawIndirectCount,
2132 family,
2133 };
2134 multi_draw_indirect_count(
2135 &mut state,
2136 device,
2137 buffer,
2138 offset,
2139 count_buffer,
2140 count_buffer_offset,
2141 max_count,
2142 family,
2143 )
2144 .map_pass_err(scope)?;
2145 }
2146 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2147 pass::push_debug_group(&mut state.pass, &base.string_data, len);
2148 }
2149 ArcRenderCommand::PopDebugGroup => {
2150 let scope = PassErrorScope::PopDebugGroup;
2151 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.pass)
2152 .map_pass_err(scope)?;
2153 }
2154 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2155 pass::insert_debug_marker(&mut state.pass, &base.string_data, len);
2156 }
2157 ArcRenderCommand::WriteTimestamp {
2158 query_set,
2159 query_index,
2160 } => {
2161 let scope = PassErrorScope::WriteTimestamp;
2162 pass::write_timestamp::<RenderPassErrorInner>(
2163 &mut state.pass,
2164 device,
2165 Some(&mut pending_query_resets),
2166 query_set,
2167 query_index,
2168 )
2169 .map_pass_err(scope)?;
2170 }
2171 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2172 api_log!("RenderPass::begin_occlusion_query {query_index}");
2173 let scope = PassErrorScope::BeginOcclusionQuery;
2174
2175 let query_set = occlusion_query_set
2176 .clone()
2177 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2178 .map_pass_err(scope)?;
2179
2180 validate_and_begin_occlusion_query(
2181 query_set,
2182 state.pass.base.raw_encoder,
2183 &mut state.pass.base.tracker.query_sets,
2184 query_index,
2185 Some(&mut pending_query_resets),
2186 &mut state.active_occlusion_query,
2187 )
2188 .map_pass_err(scope)?;
2189 }
2190 ArcRenderCommand::EndOcclusionQuery => {
2191 api_log!("RenderPass::end_occlusion_query");
2192 let scope = PassErrorScope::EndOcclusionQuery;
2193
2194 end_occlusion_query(
2195 state.pass.base.raw_encoder,
2196 &mut state.active_occlusion_query,
2197 )
2198 .map_pass_err(scope)?;
2199 }
2200 ArcRenderCommand::BeginPipelineStatisticsQuery {
2201 query_set,
2202 query_index,
2203 } => {
2204 api_log!(
2205 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2206 query_set.error_ident()
2207 );
2208 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2209
2210 validate_and_begin_pipeline_statistics_query(
2211 query_set,
2212 state.pass.base.raw_encoder,
2213 &mut state.pass.base.tracker.query_sets,
2214 device,
2215 query_index,
2216 Some(&mut pending_query_resets),
2217 &mut state.active_pipeline_statistics_query,
2218 )
2219 .map_pass_err(scope)?;
2220 }
2221 ArcRenderCommand::EndPipelineStatisticsQuery => {
2222 api_log!("RenderPass::end_pipeline_statistics_query");
2223 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2224
2225 end_pipeline_statistics_query(
2226 state.pass.base.raw_encoder,
2227 &mut state.active_pipeline_statistics_query,
2228 )
2229 .map_pass_err(scope)?;
2230 }
2231 ArcRenderCommand::ExecuteBundle(bundle) => {
2232 let scope = PassErrorScope::ExecuteBundle;
2233 execute_bundle(
2234 &mut state,
2235 &mut indirect_draw_validation_batcher,
2236 device,
2237 bundle,
2238 )
2239 .map_pass_err(scope)?;
2240 }
2241 }
2242 }
2243
2244 if *state.pass.base.debug_scope_depth > 0 {
2245 Err(
2246 RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2247 .map_pass_err(pass_scope),
2248 )?;
2249 }
2250 if state.active_occlusion_query.is_some() {
2251 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2252 query_type: super::SimplifiedQueryType::Occlusion,
2253 })
2254 .map_pass_err(pass_scope))?;
2255 }
2256 if state.active_pipeline_statistics_query.is_some() {
2257 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2258 query_type: super::SimplifiedQueryType::PipelineStatistics,
2259 })
2260 .map_pass_err(pass_scope))?;
2261 }
2262
2263 state
2264 .info
2265 .finish(
2266 device,
2267 state.pass.base.raw_encoder,
2268 state.pass.base.snatch_guard,
2269 &mut state.pass.scope,
2270 device.instance_flags,
2271 )
2272 .map_pass_err(pass_scope)?;
2273
2274 let trackers = state.pass.scope;
2275
2276 let pending_discard_init_fixups = state.pass.pending_discard_init_fixups;
2277
2278 parent_state.raw_encoder.close().map_pass_err(pass_scope)?;
2279 (trackers, pending_discard_init_fixups, pending_query_resets)
2280 };
2281
2282 let encoder = &mut parent_state.raw_encoder;
2283 let tracker = &mut parent_state.tracker;
2284
2285 {
2286 let transit = encoder
2287 .open_pass(hal_label(
2288 Some("(wgpu internal) Pre Pass"),
2289 device.instance_flags,
2290 ))
2291 .map_pass_err(pass_scope)?;
2292
2293 fixup_discarded_surfaces(
2294 pending_discard_init_fixups.into_iter(),
2295 transit,
2296 &mut tracker.textures,
2297 device,
2298 parent_state.snatch_guard,
2299 );
2300
2301 pending_query_resets.reset_queries(transit);
2302
2303 CommandEncoder::insert_barriers_from_scope(
2304 transit,
2305 tracker,
2306 &scope,
2307 parent_state.snatch_guard,
2308 );
2309
2310 if let Some(ref indirect_validation) = device.indirect_validation {
2311 indirect_validation
2312 .draw
2313 .inject_validation_pass(
2314 device,
2315 parent_state.snatch_guard,
2316 parent_state.indirect_draw_validation_resources,
2317 parent_state.temp_resources,
2318 transit,
2319 indirect_draw_validation_batcher,
2320 )
2321 .map_pass_err(pass_scope)?;
2322 }
2323 }
2324
2325 encoder.close_and_swap().map_pass_err(pass_scope)?;
2326
2327 Ok(())
2328}
2329
2330fn set_pipeline(
2331 state: &mut State,
2332 device: &Arc<Device>,
2333 pipeline: Arc<RenderPipeline>,
2334) -> Result<(), RenderPassErrorInner> {
2335 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2336
2337 state.pipeline = Some(pipeline.clone());
2338
2339 let pipeline = state
2340 .pass
2341 .base
2342 .tracker
2343 .render_pipelines
2344 .insert_single(pipeline)
2345 .clone();
2346
2347 pipeline.same_device(device)?;
2348
2349 state
2350 .info
2351 .context
2352 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2353 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2354
2355 state.pipeline_flags = pipeline.flags;
2356
2357 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2358 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2359 }
2360 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2361 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2362 }
2363
2364 state
2365 .blend_constant
2366 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2367
2368 unsafe {
2369 state
2370 .pass
2371 .base
2372 .raw_encoder
2373 .set_render_pipeline(pipeline.raw());
2374 }
2375
2376 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2377 unsafe {
2378 state
2379 .pass
2380 .base
2381 .raw_encoder
2382 .set_stencil_reference(state.stencil_reference);
2383 }
2384 }
2385
2386 pass::change_pipeline_layout::<RenderPassErrorInner, _>(
2388 &mut state.pass,
2389 &pipeline.layout,
2390 &pipeline.late_sized_buffer_groups,
2391 || {},
2392 )?;
2393
2394 state.vertex.update_limits(&pipeline.vertex_steps);
2396 Ok(())
2397}
2398
2399fn set_index_buffer(
2401 state: &mut State,
2402 device: &Arc<Device>,
2403 buffer: Arc<crate::resource::Buffer>,
2404 index_format: IndexFormat,
2405 offset: u64,
2406 size: Option<BufferSize>,
2407) -> Result<(), RenderPassErrorInner> {
2408 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2409
2410 state
2411 .pass
2412 .scope
2413 .buffers
2414 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2415
2416 buffer.same_device(device)?;
2417
2418 buffer.check_usage(BufferUsages::INDEX)?;
2419
2420 if !offset.is_multiple_of(u64::try_from(index_format.byte_size()).unwrap()) {
2421 return Err(RenderCommandError::UnalignedIndexBuffer {
2422 offset,
2423 alignment: index_format.byte_size(),
2424 }
2425 .into());
2426 }
2427 let (binding, resolved_size) = buffer
2428 .binding(offset, size, state.pass.base.snatch_guard)
2429 .map_err(RenderCommandError::from)?;
2430 let end = offset + resolved_size;
2431 state.index.update_buffer(offset..end, index_format);
2432
2433 state.pass.base.buffer_memory_init_actions.extend(
2434 buffer.initialization_status.read().create_action(
2435 &buffer,
2436 offset..end,
2437 MemoryInitKind::NeedsInitializedMemory,
2438 ),
2439 );
2440
2441 unsafe {
2442 hal::DynCommandEncoder::set_index_buffer(
2443 state.pass.base.raw_encoder,
2444 binding,
2445 index_format,
2446 );
2447 }
2448 Ok(())
2449}
2450
2451fn set_vertex_buffer(
2453 state: &mut State,
2454 device: &Arc<Device>,
2455 slot: u32,
2456 buffer: Arc<crate::resource::Buffer>,
2457 offset: u64,
2458 size: Option<BufferSize>,
2459) -> Result<(), RenderPassErrorInner> {
2460 api_log!(
2461 "RenderPass::set_vertex_buffer {slot} {}",
2462 buffer.error_ident()
2463 );
2464
2465 state
2466 .pass
2467 .scope
2468 .buffers
2469 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2470
2471 buffer.same_device(device)?;
2472
2473 let max_vertex_buffers = state.pass.base.device.limits.max_vertex_buffers;
2474 if slot >= max_vertex_buffers {
2475 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2476 index: slot,
2477 max: max_vertex_buffers,
2478 }
2479 .into());
2480 }
2481
2482 buffer.check_usage(BufferUsages::VERTEX)?;
2483
2484 if !offset.is_multiple_of(wgt::VERTEX_ALIGNMENT) {
2485 return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2486 }
2487 let (binding, buffer_size) = buffer
2488 .binding(offset, size, state.pass.base.snatch_guard)
2489 .map_err(RenderCommandError::from)?;
2490 state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
2491
2492 state.pass.base.buffer_memory_init_actions.extend(
2493 buffer.initialization_status.read().create_action(
2494 &buffer,
2495 offset..(offset + buffer_size),
2496 MemoryInitKind::NeedsInitializedMemory,
2497 ),
2498 );
2499
2500 unsafe {
2501 hal::DynCommandEncoder::set_vertex_buffer(state.pass.base.raw_encoder, slot, binding);
2502 }
2503 if let Some(pipeline) = state.pipeline.as_ref() {
2504 state.vertex.update_limits(&pipeline.vertex_steps);
2505 }
2506 Ok(())
2507}
2508
2509fn set_blend_constant(state: &mut State, color: &Color) {
2510 api_log!("RenderPass::set_blend_constant");
2511
2512 state.blend_constant = OptionalState::Set;
2513 let array = [
2514 color.r as f32,
2515 color.g as f32,
2516 color.b as f32,
2517 color.a as f32,
2518 ];
2519 unsafe {
2520 state.pass.base.raw_encoder.set_blend_constants(&array);
2521 }
2522}
2523
2524fn set_stencil_reference(state: &mut State, value: u32) {
2525 api_log!("RenderPass::set_stencil_reference {value}");
2526
2527 state.stencil_reference = value;
2528 if state
2529 .pipeline_flags
2530 .contains(PipelineFlags::STENCIL_REFERENCE)
2531 {
2532 unsafe {
2533 state.pass.base.raw_encoder.set_stencil_reference(value);
2534 }
2535 }
2536}
2537
2538fn set_viewport(
2539 state: &mut State,
2540 rect: Rect<f32>,
2541 depth_min: f32,
2542 depth_max: f32,
2543) -> Result<(), RenderPassErrorInner> {
2544 api_log!("RenderPass::set_viewport {rect:?}");
2545
2546 if rect.w < 0.0
2547 || rect.h < 0.0
2548 || rect.w > state.pass.base.device.limits.max_texture_dimension_2d as f32
2549 || rect.h > state.pass.base.device.limits.max_texture_dimension_2d as f32
2550 {
2551 return Err(RenderCommandError::InvalidViewportRectSize {
2552 w: rect.w,
2553 h: rect.h,
2554 max: state.pass.base.device.limits.max_texture_dimension_2d,
2555 }
2556 .into());
2557 }
2558
2559 let max_viewport_range = state.pass.base.device.limits.max_texture_dimension_2d as f32 * 2.0;
2560
2561 if rect.x < -max_viewport_range
2562 || rect.y < -max_viewport_range
2563 || rect.x + rect.w > max_viewport_range - 1.0
2564 || rect.y + rect.h > max_viewport_range - 1.0
2565 {
2566 return Err(RenderCommandError::InvalidViewportRectPosition {
2567 rect,
2568 min: -max_viewport_range,
2569 max: max_viewport_range - 1.0,
2570 }
2571 .into());
2572 }
2573 if !(0.0..=1.0).contains(&depth_min)
2574 || !(0.0..=1.0).contains(&depth_max)
2575 || depth_min > depth_max
2576 {
2577 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
2578 }
2579 let r = hal::Rect {
2580 x: rect.x,
2581 y: rect.y,
2582 w: rect.w,
2583 h: rect.h,
2584 };
2585 unsafe {
2586 state
2587 .pass
2588 .base
2589 .raw_encoder
2590 .set_viewport(&r, depth_min..depth_max);
2591 }
2592 Ok(())
2593}
2594
2595fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
2596 api_log!("RenderPass::set_scissor_rect {rect:?}");
2597
2598 if rect.x.saturating_add(rect.w) > state.info.extent.width
2599 || rect.y.saturating_add(rect.h) > state.info.extent.height
2600 {
2601 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
2602 }
2603 let r = hal::Rect {
2604 x: rect.x,
2605 y: rect.y,
2606 w: rect.w,
2607 h: rect.h,
2608 };
2609 unsafe {
2610 state.pass.base.raw_encoder.set_scissor_rect(&r);
2611 }
2612 Ok(())
2613}
2614
2615fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
2616 if let Some(mv) = state.info.multiview_mask {
2617 let highest_bit = 31 - mv.leading_zeros();
2618
2619 let features = state.pass.base.device.features;
2620
2621 if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
2622 || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
2623 {
2624 return Err(RenderPassErrorInner::Draw(
2625 DrawError::MeshPipelineMultiviewLimitsViolated {
2626 highest_view_index: highest_bit,
2627 max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
2628 },
2629 ));
2630 }
2631 }
2632 Ok(())
2633}
2634
2635fn draw(
2636 state: &mut State,
2637 vertex_count: u32,
2638 instance_count: u32,
2639 first_vertex: u32,
2640 first_instance: u32,
2641) -> Result<(), RenderPassErrorInner> {
2642 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
2643
2644 state.is_ready(DrawCommandFamily::Draw)?;
2645 state.flush_bindings()?;
2646
2647 state
2648 .vertex
2649 .limits
2650 .validate_vertex_limit(first_vertex, vertex_count)?;
2651 state
2652 .vertex
2653 .limits
2654 .validate_instance_limit(first_instance, instance_count)?;
2655
2656 unsafe {
2657 if instance_count > 0 && vertex_count > 0 {
2658 state.pass.base.raw_encoder.draw(
2659 first_vertex,
2660 vertex_count,
2661 first_instance,
2662 instance_count,
2663 );
2664 }
2665 }
2666 Ok(())
2667}
2668
2669fn draw_indexed(
2670 state: &mut State,
2671 index_count: u32,
2672 instance_count: u32,
2673 first_index: u32,
2674 base_vertex: i32,
2675 first_instance: u32,
2676) -> Result<(), RenderPassErrorInner> {
2677 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
2678
2679 state.is_ready(DrawCommandFamily::DrawIndexed)?;
2680 state.flush_bindings()?;
2681
2682 let last_index = first_index as u64 + index_count as u64;
2683 let index_limit = state.index.limit;
2684 if last_index > index_limit {
2685 return Err(DrawError::IndexBeyondLimit {
2686 last_index,
2687 index_limit,
2688 }
2689 .into());
2690 }
2691 state
2692 .vertex
2693 .limits
2694 .validate_instance_limit(first_instance, instance_count)?;
2695
2696 unsafe {
2697 if instance_count > 0 && index_count > 0 {
2698 state.pass.base.raw_encoder.draw_indexed(
2699 first_index,
2700 index_count,
2701 base_vertex,
2702 first_instance,
2703 instance_count,
2704 );
2705 }
2706 }
2707 Ok(())
2708}
2709
2710fn draw_mesh_tasks(
2711 state: &mut State,
2712 group_count_x: u32,
2713 group_count_y: u32,
2714 group_count_z: u32,
2715) -> Result<(), RenderPassErrorInner> {
2716 api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
2717
2718 state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
2719
2720 state.flush_bindings()?;
2721 validate_mesh_draw_multiview(state)?;
2722
2723 let groups_size_limit = state
2724 .pass
2725 .base
2726 .device
2727 .limits
2728 .max_task_mesh_workgroups_per_dimension;
2729 let max_groups = state
2730 .pass
2731 .base
2732 .device
2733 .limits
2734 .max_task_mesh_workgroup_total_count;
2735 if group_count_x > groups_size_limit
2736 || group_count_y > groups_size_limit
2737 || group_count_z > groups_size_limit
2738 || group_count_x * group_count_y * group_count_z > max_groups
2739 {
2740 return Err(DrawError::InvalidGroupSize {
2741 current: [group_count_x, group_count_y, group_count_z],
2742 limit: groups_size_limit,
2743 max_total: max_groups,
2744 }
2745 .into());
2746 }
2747
2748 unsafe {
2749 if group_count_x > 0 && group_count_y > 0 && group_count_z > 0 {
2750 state.pass.base.raw_encoder.draw_mesh_tasks(
2751 group_count_x,
2752 group_count_y,
2753 group_count_z,
2754 );
2755 }
2756 }
2757 Ok(())
2758}
2759
2760fn multi_draw_indirect(
2761 state: &mut State,
2762 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2763 device: &Arc<Device>,
2764 indirect_buffer: Arc<crate::resource::Buffer>,
2765 offset: u64,
2766 count: u32,
2767 family: DrawCommandFamily,
2768) -> Result<(), RenderPassErrorInner> {
2769 api_log!(
2770 "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
2771 indirect_buffer.error_ident()
2772 );
2773
2774 state.is_ready(family)?;
2775 state.flush_bindings()?;
2776
2777 if family == DrawCommandFamily::DrawMeshTasks {
2778 validate_mesh_draw_multiview(state)?;
2779 }
2780
2781 state
2782 .pass
2783 .base
2784 .device
2785 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2786
2787 indirect_buffer.same_device(device)?;
2788 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2789 indirect_buffer.check_destroyed(state.pass.base.snatch_guard)?;
2790
2791 if !offset.is_multiple_of(4) {
2792 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2793 }
2794
2795 let stride = get_stride_of_indirect_args(family);
2796
2797 let end_offset = offset + stride * count as u64;
2798 if end_offset > indirect_buffer.size {
2799 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2800 count,
2801 offset,
2802 end_offset,
2803 buffer_size: indirect_buffer.size,
2804 });
2805 }
2806
2807 state.pass.base.buffer_memory_init_actions.extend(
2808 indirect_buffer.initialization_status.read().create_action(
2809 &indirect_buffer,
2810 offset..end_offset,
2811 MemoryInitKind::NeedsInitializedMemory,
2812 ),
2813 );
2814
2815 fn draw(
2816 raw_encoder: &mut dyn hal::DynCommandEncoder,
2817 family: DrawCommandFamily,
2818 indirect_buffer: &dyn hal::DynBuffer,
2819 offset: u64,
2820 count: u32,
2821 ) {
2822 match family {
2823 DrawCommandFamily::Draw => unsafe {
2824 raw_encoder.draw_indirect(indirect_buffer, offset, count);
2825 },
2826 DrawCommandFamily::DrawIndexed => unsafe {
2827 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2828 },
2829 DrawCommandFamily::DrawMeshTasks => unsafe {
2830 raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
2831 },
2832 }
2833 }
2834
2835 if state.pass.base.device.indirect_validation.is_some() {
2836 state
2837 .pass
2838 .scope
2839 .buffers
2840 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
2841
2842 struct DrawData {
2843 buffer_index: usize,
2844 offset: u64,
2845 count: u32,
2846 }
2847
2848 struct DrawContext<'a> {
2849 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2850 device: &'a Device,
2851
2852 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
2853 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
2854
2855 indirect_buffer: Arc<crate::resource::Buffer>,
2856 family: DrawCommandFamily,
2857 vertex_or_index_limit: u64,
2858 instance_limit: u64,
2859 }
2860
2861 impl<'a> DrawContext<'a> {
2862 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2863 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2864 self.indirect_draw_validation_resources,
2865 self.device,
2866 &self.indirect_buffer,
2867 offset,
2868 self.family,
2869 self.vertex_or_index_limit,
2870 self.instance_limit,
2871 )?;
2872 Ok(DrawData {
2873 buffer_index: dst_resource_index,
2874 offset: dst_offset,
2875 count: 1,
2876 })
2877 }
2878 fn draw(&mut self, draw_data: DrawData) {
2879 let dst_buffer = self
2880 .indirect_draw_validation_resources
2881 .get_dst_buffer(draw_data.buffer_index);
2882 draw(
2883 self.raw_encoder,
2884 self.family,
2885 dst_buffer,
2886 draw_data.offset,
2887 draw_data.count,
2888 );
2889 }
2890 }
2891
2892 let mut draw_ctx = DrawContext {
2893 raw_encoder: state.pass.base.raw_encoder,
2894 device: state.pass.base.device,
2895 indirect_draw_validation_resources: state.pass.base.indirect_draw_validation_resources,
2896 indirect_draw_validation_batcher,
2897 indirect_buffer,
2898 family,
2899 vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
2900 state.index.limit
2901 } else {
2902 state.vertex.limits.vertex_limit
2903 },
2904 instance_limit: state.vertex.limits.instance_limit,
2905 };
2906
2907 let mut current_draw_data = draw_ctx.add(offset)?;
2908
2909 for i in 1..count {
2910 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2911
2912 if draw_data.buffer_index == current_draw_data.buffer_index {
2913 debug_assert_eq!(
2914 draw_data.offset,
2915 current_draw_data.offset + stride * current_draw_data.count as u64
2916 );
2917 current_draw_data.count += 1;
2918 } else {
2919 draw_ctx.draw(current_draw_data);
2920 current_draw_data = draw_data;
2921 }
2922 }
2923
2924 draw_ctx.draw(current_draw_data);
2925 } else {
2926 state
2927 .pass
2928 .scope
2929 .buffers
2930 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2931
2932 draw(
2933 state.pass.base.raw_encoder,
2934 family,
2935 indirect_buffer.try_raw(state.pass.base.snatch_guard)?,
2936 offset,
2937 count,
2938 );
2939 };
2940
2941 Ok(())
2942}
2943
2944fn multi_draw_indirect_count(
2945 state: &mut State,
2946 device: &Arc<Device>,
2947 indirect_buffer: Arc<crate::resource::Buffer>,
2948 offset: u64,
2949 count_buffer: Arc<crate::resource::Buffer>,
2950 count_buffer_offset: u64,
2951 max_count: u32,
2952 family: DrawCommandFamily,
2953) -> Result<(), RenderPassErrorInner> {
2954 api_log!(
2955 "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
2956 indirect_buffer.error_ident(),
2957 count_buffer.error_ident()
2958 );
2959
2960 state.is_ready(family)?;
2961 state.flush_bindings()?;
2962
2963 if family == DrawCommandFamily::DrawMeshTasks {
2964 validate_mesh_draw_multiview(state)?;
2965 }
2966
2967 let stride = get_stride_of_indirect_args(family);
2968
2969 state
2970 .pass
2971 .base
2972 .device
2973 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
2974 state
2975 .pass
2976 .base
2977 .device
2978 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2979
2980 indirect_buffer.same_device(device)?;
2981 count_buffer.same_device(device)?;
2982
2983 state
2984 .pass
2985 .scope
2986 .buffers
2987 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2988
2989 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2990 let indirect_raw = indirect_buffer.try_raw(state.pass.base.snatch_guard)?;
2991
2992 state
2993 .pass
2994 .scope
2995 .buffers
2996 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
2997
2998 count_buffer.check_usage(BufferUsages::INDIRECT)?;
2999 let count_raw = count_buffer.try_raw(state.pass.base.snatch_guard)?;
3000
3001 if !offset.is_multiple_of(4) {
3002 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
3003 }
3004
3005 let end_offset = offset + stride * max_count as u64;
3006 if end_offset > indirect_buffer.size {
3007 return Err(RenderPassErrorInner::IndirectBufferOverrun {
3008 count: 1,
3009 offset,
3010 end_offset,
3011 buffer_size: indirect_buffer.size,
3012 });
3013 }
3014 state.pass.base.buffer_memory_init_actions.extend(
3015 indirect_buffer.initialization_status.read().create_action(
3016 &indirect_buffer,
3017 offset..end_offset,
3018 MemoryInitKind::NeedsInitializedMemory,
3019 ),
3020 );
3021
3022 let begin_count_offset = count_buffer_offset;
3023 let end_count_offset = count_buffer_offset + 4;
3024 if end_count_offset > count_buffer.size {
3025 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
3026 begin_count_offset,
3027 end_count_offset,
3028 count_buffer_size: count_buffer.size,
3029 });
3030 }
3031 state.pass.base.buffer_memory_init_actions.extend(
3032 count_buffer.initialization_status.read().create_action(
3033 &count_buffer,
3034 count_buffer_offset..end_count_offset,
3035 MemoryInitKind::NeedsInitializedMemory,
3036 ),
3037 );
3038
3039 match family {
3040 DrawCommandFamily::Draw => unsafe {
3041 state.pass.base.raw_encoder.draw_indirect_count(
3042 indirect_raw,
3043 offset,
3044 count_raw,
3045 count_buffer_offset,
3046 max_count,
3047 );
3048 },
3049 DrawCommandFamily::DrawIndexed => unsafe {
3050 state.pass.base.raw_encoder.draw_indexed_indirect_count(
3051 indirect_raw,
3052 offset,
3053 count_raw,
3054 count_buffer_offset,
3055 max_count,
3056 );
3057 },
3058 DrawCommandFamily::DrawMeshTasks => unsafe {
3059 state.pass.base.raw_encoder.draw_mesh_tasks_indirect_count(
3060 indirect_raw,
3061 offset,
3062 count_raw,
3063 count_buffer_offset,
3064 max_count,
3065 );
3066 },
3067 }
3068 Ok(())
3069}
3070
3071fn execute_bundle(
3072 state: &mut State,
3073 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3074 device: &Arc<Device>,
3075 bundle: Arc<super::RenderBundle>,
3076) -> Result<(), RenderPassErrorInner> {
3077 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
3078
3079 let bundle = state.pass.base.tracker.bundles.insert_single(bundle);
3080
3081 bundle.same_device(device)?;
3082
3083 state
3084 .info
3085 .context
3086 .check_compatible(&bundle.context, bundle.as_ref())
3087 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
3088
3089 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3090 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3091 {
3092 return Err(
3093 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3094 pass_depth: state.info.is_depth_read_only,
3095 pass_stencil: state.info.is_stencil_read_only,
3096 bundle_depth: bundle.is_depth_read_only,
3097 bundle_stencil: bundle.is_stencil_read_only,
3098 },
3099 );
3100 }
3101
3102 state.pass.base.buffer_memory_init_actions.extend(
3103 bundle
3104 .buffer_memory_init_actions
3105 .iter()
3106 .filter_map(|action| {
3107 action
3108 .buffer
3109 .initialization_status
3110 .read()
3111 .check_action(action)
3112 }),
3113 );
3114 for action in bundle.texture_memory_init_actions.iter() {
3115 state.pass.pending_discard_init_fixups.extend(
3116 state
3117 .pass
3118 .base
3119 .texture_memory_actions
3120 .register_init_action(action),
3121 );
3122 }
3123
3124 unsafe {
3125 bundle.execute(
3126 state.pass.base.raw_encoder,
3127 state.pass.base.indirect_draw_validation_resources,
3128 indirect_draw_validation_batcher,
3129 state.pass.base.snatch_guard,
3130 )
3131 }
3132 .map_err(|e| match e {
3133 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3134 ExecutionError::DestroyedResource(e) => {
3135 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3136 }
3137 ExecutionError::Unimplemented(what) => {
3138 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3139 }
3140 })?;
3141
3142 unsafe {
3143 state.pass.scope.merge_render_bundle(&bundle.used)?;
3144 };
3145 state.reset_bundle();
3146 Ok(())
3147}
3148
3149impl Global {
3162 pub fn render_pass_set_bind_group(
3163 &self,
3164 pass: &mut RenderPass,
3165 index: u32,
3166 bind_group_id: Option<id::BindGroupId>,
3167 offsets: &[DynamicOffset],
3168 ) -> Result<(), PassStateError> {
3169 let scope = PassErrorScope::SetBindGroup;
3170
3171 let base = pass_base!(pass, scope);
3175
3176 if pass.current_bind_groups.set_and_check_redundant(
3177 bind_group_id,
3178 index,
3179 &mut base.dynamic_offsets,
3180 offsets,
3181 ) {
3182 return Ok(());
3183 }
3184
3185 let mut bind_group = None;
3186 if let Some(bind_group_id) = bind_group_id {
3187 let hub = &self.hub;
3188 bind_group = Some(pass_try!(
3189 base,
3190 scope,
3191 hub.bind_groups.get(bind_group_id).get(),
3192 ));
3193 }
3194
3195 base.commands.push(ArcRenderCommand::SetBindGroup {
3196 index,
3197 num_dynamic_offsets: offsets.len(),
3198 bind_group,
3199 });
3200
3201 Ok(())
3202 }
3203
3204 pub fn render_pass_set_pipeline(
3205 &self,
3206 pass: &mut RenderPass,
3207 pipeline_id: id::RenderPipelineId,
3208 ) -> Result<(), PassStateError> {
3209 let scope = PassErrorScope::SetPipelineRender;
3210
3211 let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3212
3213 let base = pass_base!(pass, scope);
3216
3217 if redundant {
3218 return Ok(());
3219 }
3220
3221 let hub = &self.hub;
3222 let pipeline = pass_try!(base, scope, hub.render_pipelines.get(pipeline_id).get());
3223
3224 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3225
3226 Ok(())
3227 }
3228
3229 pub fn render_pass_set_index_buffer(
3230 &self,
3231 pass: &mut RenderPass,
3232 buffer_id: id::BufferId,
3233 index_format: IndexFormat,
3234 offset: BufferAddress,
3235 size: Option<BufferSize>,
3236 ) -> Result<(), PassStateError> {
3237 let scope = PassErrorScope::SetIndexBuffer;
3238 let base = pass_base!(pass, scope);
3239
3240 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3241 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3242 index_format,
3243 offset,
3244 size,
3245 });
3246
3247 Ok(())
3248 }
3249
3250 pub fn render_pass_set_vertex_buffer(
3251 &self,
3252 pass: &mut RenderPass,
3253 slot: u32,
3254 buffer_id: id::BufferId,
3255 offset: BufferAddress,
3256 size: Option<BufferSize>,
3257 ) -> Result<(), PassStateError> {
3258 let scope = PassErrorScope::SetVertexBuffer;
3259 let base = pass_base!(pass, scope);
3260
3261 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3262 slot,
3263 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3264 offset,
3265 size,
3266 });
3267
3268 Ok(())
3269 }
3270
3271 pub fn render_pass_set_blend_constant(
3272 &self,
3273 pass: &mut RenderPass,
3274 color: Color,
3275 ) -> Result<(), PassStateError> {
3276 let scope = PassErrorScope::SetBlendConstant;
3277 let base = pass_base!(pass, scope);
3278
3279 base.commands
3280 .push(ArcRenderCommand::SetBlendConstant(color));
3281
3282 Ok(())
3283 }
3284
3285 pub fn render_pass_set_stencil_reference(
3286 &self,
3287 pass: &mut RenderPass,
3288 value: u32,
3289 ) -> Result<(), PassStateError> {
3290 let scope = PassErrorScope::SetStencilReference;
3291 let base = pass_base!(pass, scope);
3292
3293 base.commands
3294 .push(ArcRenderCommand::SetStencilReference(value));
3295
3296 Ok(())
3297 }
3298
3299 pub fn render_pass_set_viewport(
3300 &self,
3301 pass: &mut RenderPass,
3302 x: f32,
3303 y: f32,
3304 w: f32,
3305 h: f32,
3306 depth_min: f32,
3307 depth_max: f32,
3308 ) -> Result<(), PassStateError> {
3309 let scope = PassErrorScope::SetViewport;
3310 let base = pass_base!(pass, scope);
3311
3312 base.commands.push(ArcRenderCommand::SetViewport {
3313 rect: Rect { x, y, w, h },
3314 depth_min,
3315 depth_max,
3316 });
3317
3318 Ok(())
3319 }
3320
3321 pub fn render_pass_set_scissor_rect(
3322 &self,
3323 pass: &mut RenderPass,
3324 x: u32,
3325 y: u32,
3326 w: u32,
3327 h: u32,
3328 ) -> Result<(), PassStateError> {
3329 let scope = PassErrorScope::SetScissorRect;
3330 let base = pass_base!(pass, scope);
3331
3332 base.commands
3333 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3334
3335 Ok(())
3336 }
3337
3338 pub fn render_pass_set_immediates(
3339 &self,
3340 pass: &mut RenderPass,
3341 offset: u32,
3342 data: &[u8],
3343 ) -> Result<(), PassStateError> {
3344 let scope = PassErrorScope::SetImmediate;
3345 let base = pass_base!(pass, scope);
3346
3347 if offset & (wgt::IMMEDIATE_DATA_ALIGNMENT - 1) != 0 {
3348 pass_try!(
3349 base,
3350 scope,
3351 Err(RenderPassErrorInner::ImmediateOffsetAlignment)
3352 );
3353 }
3354 if data.len() as u32 & (wgt::IMMEDIATE_DATA_ALIGNMENT - 1) != 0 {
3355 pass_try!(
3356 base,
3357 scope,
3358 Err(RenderPassErrorInner::ImmediateDataizeAlignment)
3359 );
3360 }
3361
3362 let value_offset = pass_try!(
3363 base,
3364 scope,
3365 base.immediates_data
3366 .len()
3367 .try_into()
3368 .map_err(|_| RenderPassErrorInner::ImmediateOutOfMemory),
3369 );
3370
3371 base.immediates_data.extend(
3372 data.chunks_exact(wgt::IMMEDIATE_DATA_ALIGNMENT as usize)
3373 .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3374 );
3375
3376 base.commands.push(ArcRenderCommand::SetImmediate {
3377 offset,
3378 size_bytes: data.len() as u32,
3379 values_offset: Some(value_offset),
3380 });
3381
3382 Ok(())
3383 }
3384
3385 pub fn render_pass_draw(
3386 &self,
3387 pass: &mut RenderPass,
3388 vertex_count: u32,
3389 instance_count: u32,
3390 first_vertex: u32,
3391 first_instance: u32,
3392 ) -> Result<(), PassStateError> {
3393 let scope = PassErrorScope::Draw {
3394 kind: DrawKind::Draw,
3395 family: DrawCommandFamily::Draw,
3396 };
3397 let base = pass_base!(pass, scope);
3398
3399 base.commands.push(ArcRenderCommand::Draw {
3400 vertex_count,
3401 instance_count,
3402 first_vertex,
3403 first_instance,
3404 });
3405
3406 Ok(())
3407 }
3408
3409 pub fn render_pass_draw_indexed(
3410 &self,
3411 pass: &mut RenderPass,
3412 index_count: u32,
3413 instance_count: u32,
3414 first_index: u32,
3415 base_vertex: i32,
3416 first_instance: u32,
3417 ) -> Result<(), PassStateError> {
3418 let scope = PassErrorScope::Draw {
3419 kind: DrawKind::Draw,
3420 family: DrawCommandFamily::DrawIndexed,
3421 };
3422 let base = pass_base!(pass, scope);
3423
3424 base.commands.push(ArcRenderCommand::DrawIndexed {
3425 index_count,
3426 instance_count,
3427 first_index,
3428 base_vertex,
3429 first_instance,
3430 });
3431
3432 Ok(())
3433 }
3434
3435 pub fn render_pass_draw_mesh_tasks(
3436 &self,
3437 pass: &mut RenderPass,
3438 group_count_x: u32,
3439 group_count_y: u32,
3440 group_count_z: u32,
3441 ) -> Result<(), RenderPassError> {
3442 let scope = PassErrorScope::Draw {
3443 kind: DrawKind::Draw,
3444 family: DrawCommandFamily::DrawMeshTasks,
3445 };
3446 let base = pass_base!(pass, scope);
3447
3448 base.commands.push(ArcRenderCommand::DrawMeshTasks {
3449 group_count_x,
3450 group_count_y,
3451 group_count_z,
3452 });
3453 Ok(())
3454 }
3455
3456 pub fn render_pass_draw_indirect(
3457 &self,
3458 pass: &mut RenderPass,
3459 buffer_id: id::BufferId,
3460 offset: BufferAddress,
3461 ) -> Result<(), PassStateError> {
3462 let scope = PassErrorScope::Draw {
3463 kind: DrawKind::DrawIndirect,
3464 family: DrawCommandFamily::Draw,
3465 };
3466 let base = pass_base!(pass, scope);
3467
3468 base.commands.push(ArcRenderCommand::DrawIndirect {
3469 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3470 offset,
3471 count: 1,
3472 family: DrawCommandFamily::Draw,
3473
3474 vertex_or_index_limit: None,
3475 instance_limit: None,
3476 });
3477
3478 Ok(())
3479 }
3480
3481 pub fn render_pass_draw_indexed_indirect(
3482 &self,
3483 pass: &mut RenderPass,
3484 buffer_id: id::BufferId,
3485 offset: BufferAddress,
3486 ) -> Result<(), PassStateError> {
3487 let scope = PassErrorScope::Draw {
3488 kind: DrawKind::DrawIndirect,
3489 family: DrawCommandFamily::DrawIndexed,
3490 };
3491 let base = pass_base!(pass, scope);
3492
3493 base.commands.push(ArcRenderCommand::DrawIndirect {
3494 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3495 offset,
3496 count: 1,
3497 family: DrawCommandFamily::DrawIndexed,
3498
3499 vertex_or_index_limit: None,
3500 instance_limit: None,
3501 });
3502
3503 Ok(())
3504 }
3505
3506 pub fn render_pass_draw_mesh_tasks_indirect(
3507 &self,
3508 pass: &mut RenderPass,
3509 buffer_id: id::BufferId,
3510 offset: BufferAddress,
3511 ) -> Result<(), RenderPassError> {
3512 let scope = PassErrorScope::Draw {
3513 kind: DrawKind::DrawIndirect,
3514 family: DrawCommandFamily::DrawMeshTasks,
3515 };
3516 let base = pass_base!(pass, scope);
3517
3518 base.commands.push(ArcRenderCommand::DrawIndirect {
3519 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3520 offset,
3521 count: 1,
3522 family: DrawCommandFamily::DrawMeshTasks,
3523
3524 vertex_or_index_limit: None,
3525 instance_limit: None,
3526 });
3527
3528 Ok(())
3529 }
3530
3531 pub fn render_pass_multi_draw_indirect(
3532 &self,
3533 pass: &mut RenderPass,
3534 buffer_id: id::BufferId,
3535 offset: BufferAddress,
3536 count: u32,
3537 ) -> Result<(), PassStateError> {
3538 let scope = PassErrorScope::Draw {
3539 kind: DrawKind::MultiDrawIndirect,
3540 family: DrawCommandFamily::Draw,
3541 };
3542 let base = pass_base!(pass, scope);
3543
3544 base.commands.push(ArcRenderCommand::DrawIndirect {
3545 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3546 offset,
3547 count,
3548 family: DrawCommandFamily::Draw,
3549
3550 vertex_or_index_limit: None,
3551 instance_limit: None,
3552 });
3553
3554 Ok(())
3555 }
3556
3557 pub fn render_pass_multi_draw_indexed_indirect(
3558 &self,
3559 pass: &mut RenderPass,
3560 buffer_id: id::BufferId,
3561 offset: BufferAddress,
3562 count: u32,
3563 ) -> Result<(), PassStateError> {
3564 let scope = PassErrorScope::Draw {
3565 kind: DrawKind::MultiDrawIndirect,
3566 family: DrawCommandFamily::DrawIndexed,
3567 };
3568 let base = pass_base!(pass, scope);
3569
3570 base.commands.push(ArcRenderCommand::DrawIndirect {
3571 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3572 offset,
3573 count,
3574 family: DrawCommandFamily::DrawIndexed,
3575
3576 vertex_or_index_limit: None,
3577 instance_limit: None,
3578 });
3579
3580 Ok(())
3581 }
3582
3583 pub fn render_pass_multi_draw_mesh_tasks_indirect(
3584 &self,
3585 pass: &mut RenderPass,
3586 buffer_id: id::BufferId,
3587 offset: BufferAddress,
3588 count: u32,
3589 ) -> Result<(), RenderPassError> {
3590 let scope = PassErrorScope::Draw {
3591 kind: DrawKind::MultiDrawIndirect,
3592 family: DrawCommandFamily::DrawMeshTasks,
3593 };
3594 let base = pass_base!(pass, scope);
3595
3596 base.commands.push(ArcRenderCommand::DrawIndirect {
3597 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3598 offset,
3599 count,
3600 family: DrawCommandFamily::DrawMeshTasks,
3601
3602 vertex_or_index_limit: None,
3603 instance_limit: None,
3604 });
3605
3606 Ok(())
3607 }
3608
3609 pub fn render_pass_multi_draw_indirect_count(
3610 &self,
3611 pass: &mut RenderPass,
3612 buffer_id: id::BufferId,
3613 offset: BufferAddress,
3614 count_buffer_id: id::BufferId,
3615 count_buffer_offset: BufferAddress,
3616 max_count: u32,
3617 ) -> Result<(), PassStateError> {
3618 let scope = PassErrorScope::Draw {
3619 kind: DrawKind::MultiDrawIndirectCount,
3620 family: DrawCommandFamily::Draw,
3621 };
3622 let base = pass_base!(pass, scope);
3623
3624 base.commands
3625 .push(ArcRenderCommand::MultiDrawIndirectCount {
3626 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3627 offset,
3628 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3629 count_buffer_offset,
3630 max_count,
3631 family: DrawCommandFamily::Draw,
3632 });
3633
3634 Ok(())
3635 }
3636
3637 pub fn render_pass_multi_draw_indexed_indirect_count(
3638 &self,
3639 pass: &mut RenderPass,
3640 buffer_id: id::BufferId,
3641 offset: BufferAddress,
3642 count_buffer_id: id::BufferId,
3643 count_buffer_offset: BufferAddress,
3644 max_count: u32,
3645 ) -> Result<(), PassStateError> {
3646 let scope = PassErrorScope::Draw {
3647 kind: DrawKind::MultiDrawIndirectCount,
3648 family: DrawCommandFamily::DrawIndexed,
3649 };
3650 let base = pass_base!(pass, scope);
3651
3652 base.commands
3653 .push(ArcRenderCommand::MultiDrawIndirectCount {
3654 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3655 offset,
3656 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3657 count_buffer_offset,
3658 max_count,
3659 family: DrawCommandFamily::DrawIndexed,
3660 });
3661
3662 Ok(())
3663 }
3664
3665 pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
3666 &self,
3667 pass: &mut RenderPass,
3668 buffer_id: id::BufferId,
3669 offset: BufferAddress,
3670 count_buffer_id: id::BufferId,
3671 count_buffer_offset: BufferAddress,
3672 max_count: u32,
3673 ) -> Result<(), RenderPassError> {
3674 let scope = PassErrorScope::Draw {
3675 kind: DrawKind::MultiDrawIndirectCount,
3676 family: DrawCommandFamily::DrawMeshTasks,
3677 };
3678 let base = pass_base!(pass, scope);
3679
3680 base.commands
3681 .push(ArcRenderCommand::MultiDrawIndirectCount {
3682 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3683 offset,
3684 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3685 count_buffer_offset,
3686 max_count,
3687 family: DrawCommandFamily::DrawMeshTasks,
3688 });
3689
3690 Ok(())
3691 }
3692
3693 pub fn render_pass_push_debug_group(
3694 &self,
3695 pass: &mut RenderPass,
3696 label: &str,
3697 color: u32,
3698 ) -> Result<(), PassStateError> {
3699 let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
3700
3701 let bytes = label.as_bytes();
3702 base.string_data.extend_from_slice(bytes);
3703
3704 base.commands.push(ArcRenderCommand::PushDebugGroup {
3705 color,
3706 len: bytes.len(),
3707 });
3708
3709 Ok(())
3710 }
3711
3712 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
3713 let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
3714
3715 base.commands.push(ArcRenderCommand::PopDebugGroup);
3716
3717 Ok(())
3718 }
3719
3720 pub fn render_pass_insert_debug_marker(
3721 &self,
3722 pass: &mut RenderPass,
3723 label: &str,
3724 color: u32,
3725 ) -> Result<(), PassStateError> {
3726 let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
3727
3728 let bytes = label.as_bytes();
3729 base.string_data.extend_from_slice(bytes);
3730
3731 base.commands.push(ArcRenderCommand::InsertDebugMarker {
3732 color,
3733 len: bytes.len(),
3734 });
3735
3736 Ok(())
3737 }
3738
3739 pub fn render_pass_write_timestamp(
3740 &self,
3741 pass: &mut RenderPass,
3742 query_set_id: id::QuerySetId,
3743 query_index: u32,
3744 ) -> Result<(), PassStateError> {
3745 let scope = PassErrorScope::WriteTimestamp;
3746 let base = pass_base!(pass, scope);
3747
3748 base.commands.push(ArcRenderCommand::WriteTimestamp {
3749 query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3750 query_index,
3751 });
3752
3753 Ok(())
3754 }
3755
3756 pub fn render_pass_begin_occlusion_query(
3757 &self,
3758 pass: &mut RenderPass,
3759 query_index: u32,
3760 ) -> Result<(), PassStateError> {
3761 let scope = PassErrorScope::BeginOcclusionQuery;
3762 let base = pass_base!(pass, scope);
3763
3764 base.commands
3765 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
3766
3767 Ok(())
3768 }
3769
3770 pub fn render_pass_end_occlusion_query(
3771 &self,
3772 pass: &mut RenderPass,
3773 ) -> Result<(), PassStateError> {
3774 let scope = PassErrorScope::EndOcclusionQuery;
3775 let base = pass_base!(pass, scope);
3776
3777 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
3778
3779 Ok(())
3780 }
3781
3782 pub fn render_pass_begin_pipeline_statistics_query(
3783 &self,
3784 pass: &mut RenderPass,
3785 query_set_id: id::QuerySetId,
3786 query_index: u32,
3787 ) -> Result<(), PassStateError> {
3788 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
3789 let base = pass_base!(pass, scope);
3790
3791 base.commands
3792 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
3793 query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3794 query_index,
3795 });
3796
3797 Ok(())
3798 }
3799
3800 pub fn render_pass_end_pipeline_statistics_query(
3801 &self,
3802 pass: &mut RenderPass,
3803 ) -> Result<(), PassStateError> {
3804 let scope = PassErrorScope::EndPipelineStatisticsQuery;
3805 let base = pass_base!(pass, scope);
3806
3807 base.commands
3808 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
3809
3810 Ok(())
3811 }
3812
3813 pub fn render_pass_execute_bundles(
3814 &self,
3815 pass: &mut RenderPass,
3816 render_bundle_ids: &[id::RenderBundleId],
3817 ) -> Result<(), PassStateError> {
3818 let scope = PassErrorScope::ExecuteBundle;
3819 let base = pass_base!(pass, scope);
3820
3821 let hub = &self.hub;
3822 let bundles = hub.render_bundles.read();
3823
3824 for &bundle_id in render_bundle_ids {
3825 let bundle = pass_try!(base, scope, bundles.get(bundle_id).get());
3826
3827 base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
3828 }
3829 pass.current_pipeline.reset();
3830 pass.current_bind_groups.reset();
3831
3832 Ok(())
3833 }
3834}
3835
3836pub(crate) const fn get_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
3837 match family {
3838 DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
3839 DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
3840 DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
3841 }
3842}