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