1use alloc::{borrow::Cow, sync::Arc, vec::Vec};
2use core::{convert::Infallible, fmt, num::NonZeroU32, ops::Range, str};
3use smallvec::SmallVec;
4
5use arrayvec::ArrayVec;
6use thiserror::Error;
7use wgt::{
8 error::{ErrorType, WebGpuError},
9 BufferAddress, BufferSize, BufferUsages, Color, DynamicOffset, IndexFormat, ShaderStages,
10 TextureSelector, TextureUsages, TextureViewDimension, VertexStepMode,
11};
12
13use crate::command::{
14 encoder::EncodingState,
15 pass::{self, flush_bindings_helper},
16 pass_base, pass_try, validate_and_begin_occlusion_query,
17 validate_and_begin_pipeline_statistics_query, ArcCommand, DebugGroupError, EncoderStateError,
18 InnerCommandEncoder, PassStateError, TimestampWritesError,
19};
20use crate::pipeline::{RenderPipeline, VertexStep};
21use crate::resource::RawResourceAccess;
22use crate::resource::{InvalidResourceError, ResourceErrorIdent};
23use crate::snatch::SnatchGuard;
24use crate::{
25 api_log,
26 command::{
27 bind::Binder,
28 end_occlusion_query, end_pipeline_statistics_query,
29 memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
30 ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandEncoderError, DrawError,
31 ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
32 RenderCommandError, StateChange,
33 },
34 device::{
35 AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures,
36 RenderPassCompatibilityError, RenderPassContext,
37 },
38 global::Global,
39 hal_label, id,
40 init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
41 pipeline::PipelineFlags,
42 resource::{
43 DestroyedResourceError, Labeled, MissingBufferUsageError, MissingTextureUsageError,
44 ParentDevice, QuerySet, Texture, TextureView, TextureViewNotRenderableReason,
45 },
46 track::{ResourceUsageCompatibilityError, Tracker, UsageScope},
47 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 stages,
2025 offset,
2026 size_bytes,
2027 values_offset,
2028 } => {
2029 let scope = PassErrorScope::SetImmediate;
2030 pass::set_immediates::<RenderPassErrorInner, _>(
2031 &mut state.pass,
2032 &base.immediates_data,
2033 stages,
2034 offset,
2035 size_bytes,
2036 values_offset,
2037 |_| {},
2038 )
2039 .map_pass_err(scope)?;
2040 }
2041 ArcRenderCommand::SetScissor(rect) => {
2042 let scope = PassErrorScope::SetScissorRect;
2043 set_scissor(&mut state, rect).map_pass_err(scope)?;
2044 }
2045 ArcRenderCommand::Draw {
2046 vertex_count,
2047 instance_count,
2048 first_vertex,
2049 first_instance,
2050 } => {
2051 let scope = PassErrorScope::Draw {
2052 kind: DrawKind::Draw,
2053 family: DrawCommandFamily::Draw,
2054 };
2055 draw(
2056 &mut state,
2057 vertex_count,
2058 instance_count,
2059 first_vertex,
2060 first_instance,
2061 )
2062 .map_pass_err(scope)?;
2063 }
2064 ArcRenderCommand::DrawIndexed {
2065 index_count,
2066 instance_count,
2067 first_index,
2068 base_vertex,
2069 first_instance,
2070 } => {
2071 let scope = PassErrorScope::Draw {
2072 kind: DrawKind::Draw,
2073 family: DrawCommandFamily::DrawIndexed,
2074 };
2075 draw_indexed(
2076 &mut state,
2077 index_count,
2078 instance_count,
2079 first_index,
2080 base_vertex,
2081 first_instance,
2082 )
2083 .map_pass_err(scope)?;
2084 }
2085 ArcRenderCommand::DrawMeshTasks {
2086 group_count_x,
2087 group_count_y,
2088 group_count_z,
2089 } => {
2090 let scope = PassErrorScope::Draw {
2091 kind: DrawKind::Draw,
2092 family: DrawCommandFamily::DrawMeshTasks,
2093 };
2094 draw_mesh_tasks(&mut state, group_count_x, group_count_y, group_count_z)
2095 .map_pass_err(scope)?;
2096 }
2097 ArcRenderCommand::DrawIndirect {
2098 buffer,
2099 offset,
2100 count,
2101 family,
2102
2103 vertex_or_index_limit: _,
2104 instance_limit: _,
2105 } => {
2106 let scope = PassErrorScope::Draw {
2107 kind: if count != 1 {
2108 DrawKind::MultiDrawIndirect
2109 } else {
2110 DrawKind::DrawIndirect
2111 },
2112 family,
2113 };
2114 multi_draw_indirect(
2115 &mut state,
2116 &mut indirect_draw_validation_batcher,
2117 device,
2118 buffer,
2119 offset,
2120 count,
2121 family,
2122 )
2123 .map_pass_err(scope)?;
2124 }
2125 ArcRenderCommand::MultiDrawIndirectCount {
2126 buffer,
2127 offset,
2128 count_buffer,
2129 count_buffer_offset,
2130 max_count,
2131 family,
2132 } => {
2133 let scope = PassErrorScope::Draw {
2134 kind: DrawKind::MultiDrawIndirectCount,
2135 family,
2136 };
2137 multi_draw_indirect_count(
2138 &mut state,
2139 device,
2140 buffer,
2141 offset,
2142 count_buffer,
2143 count_buffer_offset,
2144 max_count,
2145 family,
2146 )
2147 .map_pass_err(scope)?;
2148 }
2149 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2150 pass::push_debug_group(&mut state.pass, &base.string_data, len);
2151 }
2152 ArcRenderCommand::PopDebugGroup => {
2153 let scope = PassErrorScope::PopDebugGroup;
2154 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.pass)
2155 .map_pass_err(scope)?;
2156 }
2157 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2158 pass::insert_debug_marker(&mut state.pass, &base.string_data, len);
2159 }
2160 ArcRenderCommand::WriteTimestamp {
2161 query_set,
2162 query_index,
2163 } => {
2164 let scope = PassErrorScope::WriteTimestamp;
2165 pass::write_timestamp::<RenderPassErrorInner>(
2166 &mut state.pass,
2167 device,
2168 Some(&mut pending_query_resets),
2169 query_set,
2170 query_index,
2171 )
2172 .map_pass_err(scope)?;
2173 }
2174 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2175 api_log!("RenderPass::begin_occlusion_query {query_index}");
2176 let scope = PassErrorScope::BeginOcclusionQuery;
2177
2178 let query_set = occlusion_query_set
2179 .clone()
2180 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2181 .map_pass_err(scope)?;
2182
2183 validate_and_begin_occlusion_query(
2184 query_set,
2185 state.pass.base.raw_encoder,
2186 &mut state.pass.base.tracker.query_sets,
2187 query_index,
2188 Some(&mut pending_query_resets),
2189 &mut state.active_occlusion_query,
2190 )
2191 .map_pass_err(scope)?;
2192 }
2193 ArcRenderCommand::EndOcclusionQuery => {
2194 api_log!("RenderPass::end_occlusion_query");
2195 let scope = PassErrorScope::EndOcclusionQuery;
2196
2197 end_occlusion_query(
2198 state.pass.base.raw_encoder,
2199 &mut state.active_occlusion_query,
2200 )
2201 .map_pass_err(scope)?;
2202 }
2203 ArcRenderCommand::BeginPipelineStatisticsQuery {
2204 query_set,
2205 query_index,
2206 } => {
2207 api_log!(
2208 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2209 query_set.error_ident()
2210 );
2211 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2212
2213 validate_and_begin_pipeline_statistics_query(
2214 query_set,
2215 state.pass.base.raw_encoder,
2216 &mut state.pass.base.tracker.query_sets,
2217 device,
2218 query_index,
2219 Some(&mut pending_query_resets),
2220 &mut state.active_pipeline_statistics_query,
2221 )
2222 .map_pass_err(scope)?;
2223 }
2224 ArcRenderCommand::EndPipelineStatisticsQuery => {
2225 api_log!("RenderPass::end_pipeline_statistics_query");
2226 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2227
2228 end_pipeline_statistics_query(
2229 state.pass.base.raw_encoder,
2230 &mut state.active_pipeline_statistics_query,
2231 )
2232 .map_pass_err(scope)?;
2233 }
2234 ArcRenderCommand::ExecuteBundle(bundle) => {
2235 let scope = PassErrorScope::ExecuteBundle;
2236 execute_bundle(
2237 &mut state,
2238 &mut indirect_draw_validation_batcher,
2239 device,
2240 bundle,
2241 )
2242 .map_pass_err(scope)?;
2243 }
2244 }
2245 }
2246
2247 if *state.pass.base.debug_scope_depth > 0 {
2248 Err(
2249 RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2250 .map_pass_err(pass_scope),
2251 )?;
2252 }
2253 if state.active_occlusion_query.is_some() {
2254 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2255 query_type: super::SimplifiedQueryType::Occlusion,
2256 })
2257 .map_pass_err(pass_scope))?;
2258 }
2259 if state.active_pipeline_statistics_query.is_some() {
2260 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2261 query_type: super::SimplifiedQueryType::PipelineStatistics,
2262 })
2263 .map_pass_err(pass_scope))?;
2264 }
2265
2266 state
2267 .info
2268 .finish(
2269 device,
2270 state.pass.base.raw_encoder,
2271 state.pass.base.snatch_guard,
2272 &mut state.pass.scope,
2273 device.instance_flags,
2274 )
2275 .map_pass_err(pass_scope)?;
2276
2277 let trackers = state.pass.scope;
2278
2279 let pending_discard_init_fixups = state.pass.pending_discard_init_fixups;
2280
2281 parent_state.raw_encoder.close().map_pass_err(pass_scope)?;
2282 (trackers, pending_discard_init_fixups, pending_query_resets)
2283 };
2284
2285 let encoder = &mut parent_state.raw_encoder;
2286 let tracker = &mut parent_state.tracker;
2287
2288 {
2289 let transit = encoder
2290 .open_pass(hal_label(
2291 Some("(wgpu internal) Pre Pass"),
2292 device.instance_flags,
2293 ))
2294 .map_pass_err(pass_scope)?;
2295
2296 fixup_discarded_surfaces(
2297 pending_discard_init_fixups.into_iter(),
2298 transit,
2299 &mut tracker.textures,
2300 device,
2301 parent_state.snatch_guard,
2302 );
2303
2304 pending_query_resets.reset_queries(transit);
2305
2306 CommandEncoder::insert_barriers_from_scope(
2307 transit,
2308 tracker,
2309 &scope,
2310 parent_state.snatch_guard,
2311 );
2312
2313 if let Some(ref indirect_validation) = device.indirect_validation {
2314 indirect_validation
2315 .draw
2316 .inject_validation_pass(
2317 device,
2318 parent_state.snatch_guard,
2319 parent_state.indirect_draw_validation_resources,
2320 parent_state.temp_resources,
2321 transit,
2322 indirect_draw_validation_batcher,
2323 )
2324 .map_pass_err(pass_scope)?;
2325 }
2326 }
2327
2328 encoder.close_and_swap().map_pass_err(pass_scope)?;
2329
2330 Ok(())
2331}
2332
2333fn set_pipeline(
2334 state: &mut State,
2335 device: &Arc<Device>,
2336 pipeline: Arc<RenderPipeline>,
2337) -> Result<(), RenderPassErrorInner> {
2338 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2339
2340 state.pipeline = Some(pipeline.clone());
2341
2342 let pipeline = state
2343 .pass
2344 .base
2345 .tracker
2346 .render_pipelines
2347 .insert_single(pipeline)
2348 .clone();
2349
2350 pipeline.same_device(device)?;
2351
2352 state
2353 .info
2354 .context
2355 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2356 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2357
2358 state.pipeline_flags = pipeline.flags;
2359
2360 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2361 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2362 }
2363 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2364 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2365 }
2366
2367 state
2368 .blend_constant
2369 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2370
2371 unsafe {
2372 state
2373 .pass
2374 .base
2375 .raw_encoder
2376 .set_render_pipeline(pipeline.raw());
2377 }
2378
2379 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2380 unsafe {
2381 state
2382 .pass
2383 .base
2384 .raw_encoder
2385 .set_stencil_reference(state.stencil_reference);
2386 }
2387 }
2388
2389 pass::change_pipeline_layout::<RenderPassErrorInner, _>(
2391 &mut state.pass,
2392 &pipeline.layout,
2393 &pipeline.late_sized_buffer_groups,
2394 || {},
2395 )?;
2396
2397 state.vertex.update_limits(&pipeline.vertex_steps);
2399 Ok(())
2400}
2401
2402fn set_index_buffer(
2404 state: &mut State,
2405 device: &Arc<Device>,
2406 buffer: Arc<crate::resource::Buffer>,
2407 index_format: IndexFormat,
2408 offset: u64,
2409 size: Option<BufferSize>,
2410) -> Result<(), RenderPassErrorInner> {
2411 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2412
2413 state
2414 .pass
2415 .scope
2416 .buffers
2417 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2418
2419 buffer.same_device(device)?;
2420
2421 buffer.check_usage(BufferUsages::INDEX)?;
2422
2423 if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
2424 return Err(RenderCommandError::UnalignedIndexBuffer {
2425 offset,
2426 alignment: index_format.byte_size(),
2427 }
2428 .into());
2429 }
2430 let (binding, resolved_size) = buffer
2431 .binding(offset, size, state.pass.base.snatch_guard)
2432 .map_err(RenderCommandError::from)?;
2433 let end = offset + resolved_size;
2434 state.index.update_buffer(offset..end, index_format);
2435
2436 state.pass.base.buffer_memory_init_actions.extend(
2437 buffer.initialization_status.read().create_action(
2438 &buffer,
2439 offset..end,
2440 MemoryInitKind::NeedsInitializedMemory,
2441 ),
2442 );
2443
2444 unsafe {
2445 hal::DynCommandEncoder::set_index_buffer(
2446 state.pass.base.raw_encoder,
2447 binding,
2448 index_format,
2449 );
2450 }
2451 Ok(())
2452}
2453
2454fn set_vertex_buffer(
2456 state: &mut State,
2457 device: &Arc<Device>,
2458 slot: u32,
2459 buffer: Arc<crate::resource::Buffer>,
2460 offset: u64,
2461 size: Option<BufferSize>,
2462) -> Result<(), RenderPassErrorInner> {
2463 api_log!(
2464 "RenderPass::set_vertex_buffer {slot} {}",
2465 buffer.error_ident()
2466 );
2467
2468 state
2469 .pass
2470 .scope
2471 .buffers
2472 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2473
2474 buffer.same_device(device)?;
2475
2476 let max_vertex_buffers = state.pass.base.device.limits.max_vertex_buffers;
2477 if slot >= max_vertex_buffers {
2478 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2479 index: slot,
2480 max: max_vertex_buffers,
2481 }
2482 .into());
2483 }
2484
2485 buffer.check_usage(BufferUsages::VERTEX)?;
2486
2487 if offset % wgt::VERTEX_ALIGNMENT != 0 {
2488 return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2489 }
2490 let (binding, buffer_size) = buffer
2491 .binding(offset, size, state.pass.base.snatch_guard)
2492 .map_err(RenderCommandError::from)?;
2493 state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
2494
2495 state.pass.base.buffer_memory_init_actions.extend(
2496 buffer.initialization_status.read().create_action(
2497 &buffer,
2498 offset..(offset + buffer_size),
2499 MemoryInitKind::NeedsInitializedMemory,
2500 ),
2501 );
2502
2503 unsafe {
2504 hal::DynCommandEncoder::set_vertex_buffer(state.pass.base.raw_encoder, slot, binding);
2505 }
2506 if let Some(pipeline) = state.pipeline.as_ref() {
2507 state.vertex.update_limits(&pipeline.vertex_steps);
2508 }
2509 Ok(())
2510}
2511
2512fn set_blend_constant(state: &mut State, color: &Color) {
2513 api_log!("RenderPass::set_blend_constant");
2514
2515 state.blend_constant = OptionalState::Set;
2516 let array = [
2517 color.r as f32,
2518 color.g as f32,
2519 color.b as f32,
2520 color.a as f32,
2521 ];
2522 unsafe {
2523 state.pass.base.raw_encoder.set_blend_constants(&array);
2524 }
2525}
2526
2527fn set_stencil_reference(state: &mut State, value: u32) {
2528 api_log!("RenderPass::set_stencil_reference {value}");
2529
2530 state.stencil_reference = value;
2531 if state
2532 .pipeline_flags
2533 .contains(PipelineFlags::STENCIL_REFERENCE)
2534 {
2535 unsafe {
2536 state.pass.base.raw_encoder.set_stencil_reference(value);
2537 }
2538 }
2539}
2540
2541fn set_viewport(
2542 state: &mut State,
2543 rect: Rect<f32>,
2544 depth_min: f32,
2545 depth_max: f32,
2546) -> Result<(), RenderPassErrorInner> {
2547 api_log!("RenderPass::set_viewport {rect:?}");
2548
2549 if rect.w < 0.0
2550 || rect.h < 0.0
2551 || rect.w > state.pass.base.device.limits.max_texture_dimension_2d as f32
2552 || rect.h > state.pass.base.device.limits.max_texture_dimension_2d as f32
2553 {
2554 return Err(RenderCommandError::InvalidViewportRectSize {
2555 w: rect.w,
2556 h: rect.h,
2557 max: state.pass.base.device.limits.max_texture_dimension_2d,
2558 }
2559 .into());
2560 }
2561
2562 let max_viewport_range = state.pass.base.device.limits.max_texture_dimension_2d as f32 * 2.0;
2563
2564 if rect.x < -max_viewport_range
2565 || rect.y < -max_viewport_range
2566 || rect.x + rect.w > max_viewport_range - 1.0
2567 || rect.y + rect.h > max_viewport_range - 1.0
2568 {
2569 return Err(RenderCommandError::InvalidViewportRectPosition {
2570 rect,
2571 min: -max_viewport_range,
2572 max: max_viewport_range - 1.0,
2573 }
2574 .into());
2575 }
2576 if !(0.0..=1.0).contains(&depth_min)
2577 || !(0.0..=1.0).contains(&depth_max)
2578 || depth_min > depth_max
2579 {
2580 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
2581 }
2582 let r = hal::Rect {
2583 x: rect.x,
2584 y: rect.y,
2585 w: rect.w,
2586 h: rect.h,
2587 };
2588 unsafe {
2589 state
2590 .pass
2591 .base
2592 .raw_encoder
2593 .set_viewport(&r, depth_min..depth_max);
2594 }
2595 Ok(())
2596}
2597
2598fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
2599 api_log!("RenderPass::set_scissor_rect {rect:?}");
2600
2601 if rect.x.saturating_add(rect.w) > state.info.extent.width
2602 || rect.y.saturating_add(rect.h) > state.info.extent.height
2603 {
2604 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
2605 }
2606 let r = hal::Rect {
2607 x: rect.x,
2608 y: rect.y,
2609 w: rect.w,
2610 h: rect.h,
2611 };
2612 unsafe {
2613 state.pass.base.raw_encoder.set_scissor_rect(&r);
2614 }
2615 Ok(())
2616}
2617
2618fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
2619 if let Some(mv) = state.info.multiview_mask {
2620 let highest_bit = 31 - mv.leading_zeros();
2621
2622 let features = state.pass.base.device.features;
2623
2624 if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
2625 || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
2626 {
2627 return Err(RenderPassErrorInner::Draw(
2628 DrawError::MeshPipelineMultiviewLimitsViolated {
2629 highest_view_index: highest_bit,
2630 max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
2631 },
2632 ));
2633 }
2634 }
2635 Ok(())
2636}
2637
2638fn draw(
2639 state: &mut State,
2640 vertex_count: u32,
2641 instance_count: u32,
2642 first_vertex: u32,
2643 first_instance: u32,
2644) -> Result<(), RenderPassErrorInner> {
2645 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
2646
2647 state.is_ready(DrawCommandFamily::Draw)?;
2648 state.flush_bindings()?;
2649
2650 state
2651 .vertex
2652 .limits
2653 .validate_vertex_limit(first_vertex, vertex_count)?;
2654 state
2655 .vertex
2656 .limits
2657 .validate_instance_limit(first_instance, instance_count)?;
2658
2659 unsafe {
2660 if instance_count > 0 && vertex_count > 0 {
2661 state.pass.base.raw_encoder.draw(
2662 first_vertex,
2663 vertex_count,
2664 first_instance,
2665 instance_count,
2666 );
2667 }
2668 }
2669 Ok(())
2670}
2671
2672fn draw_indexed(
2673 state: &mut State,
2674 index_count: u32,
2675 instance_count: u32,
2676 first_index: u32,
2677 base_vertex: i32,
2678 first_instance: u32,
2679) -> Result<(), RenderPassErrorInner> {
2680 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
2681
2682 state.is_ready(DrawCommandFamily::DrawIndexed)?;
2683 state.flush_bindings()?;
2684
2685 let last_index = first_index as u64 + index_count as u64;
2686 let index_limit = state.index.limit;
2687 if last_index > index_limit {
2688 return Err(DrawError::IndexBeyondLimit {
2689 last_index,
2690 index_limit,
2691 }
2692 .into());
2693 }
2694 state
2695 .vertex
2696 .limits
2697 .validate_instance_limit(first_instance, instance_count)?;
2698
2699 unsafe {
2700 if instance_count > 0 && index_count > 0 {
2701 state.pass.base.raw_encoder.draw_indexed(
2702 first_index,
2703 index_count,
2704 base_vertex,
2705 first_instance,
2706 instance_count,
2707 );
2708 }
2709 }
2710 Ok(())
2711}
2712
2713fn draw_mesh_tasks(
2714 state: &mut State,
2715 group_count_x: u32,
2716 group_count_y: u32,
2717 group_count_z: u32,
2718) -> Result<(), RenderPassErrorInner> {
2719 api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
2720
2721 state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
2722
2723 state.flush_bindings()?;
2724 validate_mesh_draw_multiview(state)?;
2725
2726 let groups_size_limit = state
2727 .pass
2728 .base
2729 .device
2730 .limits
2731 .max_task_workgroups_per_dimension;
2732 let max_groups = state.pass.base.device.limits.max_task_workgroup_total_count;
2733 if group_count_x > groups_size_limit
2734 || group_count_y > groups_size_limit
2735 || group_count_z > groups_size_limit
2736 || group_count_x * group_count_y * group_count_z > max_groups
2737 {
2738 return Err(DrawError::InvalidGroupSize {
2739 current: [group_count_x, group_count_y, group_count_z],
2740 limit: groups_size_limit,
2741 max_total: max_groups,
2742 }
2743 .into());
2744 }
2745
2746 unsafe {
2747 if group_count_x > 0 && group_count_y > 0 && group_count_z > 0 {
2748 state.pass.base.raw_encoder.draw_mesh_tasks(
2749 group_count_x,
2750 group_count_y,
2751 group_count_z,
2752 );
2753 }
2754 }
2755 Ok(())
2756}
2757
2758fn multi_draw_indirect(
2759 state: &mut State,
2760 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2761 device: &Arc<Device>,
2762 indirect_buffer: Arc<crate::resource::Buffer>,
2763 offset: u64,
2764 count: u32,
2765 family: DrawCommandFamily,
2766) -> Result<(), RenderPassErrorInner> {
2767 api_log!(
2768 "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
2769 indirect_buffer.error_ident()
2770 );
2771
2772 state.is_ready(family)?;
2773 state.flush_bindings()?;
2774
2775 if family == DrawCommandFamily::DrawMeshTasks {
2776 validate_mesh_draw_multiview(state)?;
2777 }
2778
2779 state
2780 .pass
2781 .base
2782 .device
2783 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2784
2785 indirect_buffer.same_device(device)?;
2786 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2787 indirect_buffer.check_destroyed(state.pass.base.snatch_guard)?;
2788
2789 if offset % 4 != 0 {
2790 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2791 }
2792
2793 let stride = get_stride_of_indirect_args(family);
2794
2795 let end_offset = offset + stride * count as u64;
2796 if end_offset > indirect_buffer.size {
2797 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2798 count,
2799 offset,
2800 end_offset,
2801 buffer_size: indirect_buffer.size,
2802 });
2803 }
2804
2805 state.pass.base.buffer_memory_init_actions.extend(
2806 indirect_buffer.initialization_status.read().create_action(
2807 &indirect_buffer,
2808 offset..end_offset,
2809 MemoryInitKind::NeedsInitializedMemory,
2810 ),
2811 );
2812
2813 fn draw(
2814 raw_encoder: &mut dyn hal::DynCommandEncoder,
2815 family: DrawCommandFamily,
2816 indirect_buffer: &dyn hal::DynBuffer,
2817 offset: u64,
2818 count: u32,
2819 ) {
2820 match family {
2821 DrawCommandFamily::Draw => unsafe {
2822 raw_encoder.draw_indirect(indirect_buffer, offset, count);
2823 },
2824 DrawCommandFamily::DrawIndexed => unsafe {
2825 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2826 },
2827 DrawCommandFamily::DrawMeshTasks => unsafe {
2828 raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
2829 },
2830 }
2831 }
2832
2833 if state.pass.base.device.indirect_validation.is_some() {
2834 state
2835 .pass
2836 .scope
2837 .buffers
2838 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
2839
2840 struct DrawData {
2841 buffer_index: usize,
2842 offset: u64,
2843 count: u32,
2844 }
2845
2846 struct DrawContext<'a> {
2847 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2848 device: &'a Device,
2849
2850 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
2851 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
2852
2853 indirect_buffer: Arc<crate::resource::Buffer>,
2854 family: DrawCommandFamily,
2855 vertex_or_index_limit: u64,
2856 instance_limit: u64,
2857 }
2858
2859 impl<'a> DrawContext<'a> {
2860 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2861 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2862 self.indirect_draw_validation_resources,
2863 self.device,
2864 &self.indirect_buffer,
2865 offset,
2866 self.family,
2867 self.vertex_or_index_limit,
2868 self.instance_limit,
2869 )?;
2870 Ok(DrawData {
2871 buffer_index: dst_resource_index,
2872 offset: dst_offset,
2873 count: 1,
2874 })
2875 }
2876 fn draw(&mut self, draw_data: DrawData) {
2877 let dst_buffer = self
2878 .indirect_draw_validation_resources
2879 .get_dst_buffer(draw_data.buffer_index);
2880 draw(
2881 self.raw_encoder,
2882 self.family,
2883 dst_buffer,
2884 draw_data.offset,
2885 draw_data.count,
2886 );
2887 }
2888 }
2889
2890 let mut draw_ctx = DrawContext {
2891 raw_encoder: state.pass.base.raw_encoder,
2892 device: state.pass.base.device,
2893 indirect_draw_validation_resources: state.pass.base.indirect_draw_validation_resources,
2894 indirect_draw_validation_batcher,
2895 indirect_buffer,
2896 family,
2897 vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
2898 state.index.limit
2899 } else {
2900 state.vertex.limits.vertex_limit
2901 },
2902 instance_limit: state.vertex.limits.instance_limit,
2903 };
2904
2905 let mut current_draw_data = draw_ctx.add(offset)?;
2906
2907 for i in 1..count {
2908 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2909
2910 if draw_data.buffer_index == current_draw_data.buffer_index {
2911 debug_assert_eq!(
2912 draw_data.offset,
2913 current_draw_data.offset + stride * current_draw_data.count as u64
2914 );
2915 current_draw_data.count += 1;
2916 } else {
2917 draw_ctx.draw(current_draw_data);
2918 current_draw_data = draw_data;
2919 }
2920 }
2921
2922 draw_ctx.draw(current_draw_data);
2923 } else {
2924 state
2925 .pass
2926 .scope
2927 .buffers
2928 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2929
2930 draw(
2931 state.pass.base.raw_encoder,
2932 family,
2933 indirect_buffer.try_raw(state.pass.base.snatch_guard)?,
2934 offset,
2935 count,
2936 );
2937 };
2938
2939 Ok(())
2940}
2941
2942fn multi_draw_indirect_count(
2943 state: &mut State,
2944 device: &Arc<Device>,
2945 indirect_buffer: Arc<crate::resource::Buffer>,
2946 offset: u64,
2947 count_buffer: Arc<crate::resource::Buffer>,
2948 count_buffer_offset: u64,
2949 max_count: u32,
2950 family: DrawCommandFamily,
2951) -> Result<(), RenderPassErrorInner> {
2952 api_log!(
2953 "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
2954 indirect_buffer.error_ident(),
2955 count_buffer.error_ident()
2956 );
2957
2958 state.is_ready(family)?;
2959 state.flush_bindings()?;
2960
2961 if family == DrawCommandFamily::DrawMeshTasks {
2962 validate_mesh_draw_multiview(state)?;
2963 }
2964
2965 let stride = get_stride_of_indirect_args(family);
2966
2967 state
2968 .pass
2969 .base
2970 .device
2971 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
2972 state
2973 .pass
2974 .base
2975 .device
2976 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2977
2978 indirect_buffer.same_device(device)?;
2979 count_buffer.same_device(device)?;
2980
2981 state
2982 .pass
2983 .scope
2984 .buffers
2985 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2986
2987 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2988 let indirect_raw = indirect_buffer.try_raw(state.pass.base.snatch_guard)?;
2989
2990 state
2991 .pass
2992 .scope
2993 .buffers
2994 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
2995
2996 count_buffer.check_usage(BufferUsages::INDIRECT)?;
2997 let count_raw = count_buffer.try_raw(state.pass.base.snatch_guard)?;
2998
2999 if offset % 4 != 0 {
3000 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
3001 }
3002
3003 let end_offset = offset + stride * max_count as u64;
3004 if end_offset > indirect_buffer.size {
3005 return Err(RenderPassErrorInner::IndirectBufferOverrun {
3006 count: 1,
3007 offset,
3008 end_offset,
3009 buffer_size: indirect_buffer.size,
3010 });
3011 }
3012 state.pass.base.buffer_memory_init_actions.extend(
3013 indirect_buffer.initialization_status.read().create_action(
3014 &indirect_buffer,
3015 offset..end_offset,
3016 MemoryInitKind::NeedsInitializedMemory,
3017 ),
3018 );
3019
3020 let begin_count_offset = count_buffer_offset;
3021 let end_count_offset = count_buffer_offset + 4;
3022 if end_count_offset > count_buffer.size {
3023 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
3024 begin_count_offset,
3025 end_count_offset,
3026 count_buffer_size: count_buffer.size,
3027 });
3028 }
3029 state.pass.base.buffer_memory_init_actions.extend(
3030 count_buffer.initialization_status.read().create_action(
3031 &count_buffer,
3032 count_buffer_offset..end_count_offset,
3033 MemoryInitKind::NeedsInitializedMemory,
3034 ),
3035 );
3036
3037 match family {
3038 DrawCommandFamily::Draw => unsafe {
3039 state.pass.base.raw_encoder.draw_indirect_count(
3040 indirect_raw,
3041 offset,
3042 count_raw,
3043 count_buffer_offset,
3044 max_count,
3045 );
3046 },
3047 DrawCommandFamily::DrawIndexed => unsafe {
3048 state.pass.base.raw_encoder.draw_indexed_indirect_count(
3049 indirect_raw,
3050 offset,
3051 count_raw,
3052 count_buffer_offset,
3053 max_count,
3054 );
3055 },
3056 DrawCommandFamily::DrawMeshTasks => unsafe {
3057 state.pass.base.raw_encoder.draw_mesh_tasks_indirect_count(
3058 indirect_raw,
3059 offset,
3060 count_raw,
3061 count_buffer_offset,
3062 max_count,
3063 );
3064 },
3065 }
3066 Ok(())
3067}
3068
3069fn execute_bundle(
3070 state: &mut State,
3071 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3072 device: &Arc<Device>,
3073 bundle: Arc<super::RenderBundle>,
3074) -> Result<(), RenderPassErrorInner> {
3075 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
3076
3077 let bundle = state.pass.base.tracker.bundles.insert_single(bundle);
3078
3079 bundle.same_device(device)?;
3080
3081 state
3082 .info
3083 .context
3084 .check_compatible(&bundle.context, bundle.as_ref())
3085 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
3086
3087 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3088 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3089 {
3090 return Err(
3091 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3092 pass_depth: state.info.is_depth_read_only,
3093 pass_stencil: state.info.is_stencil_read_only,
3094 bundle_depth: bundle.is_depth_read_only,
3095 bundle_stencil: bundle.is_stencil_read_only,
3096 },
3097 );
3098 }
3099
3100 state.pass.base.buffer_memory_init_actions.extend(
3101 bundle
3102 .buffer_memory_init_actions
3103 .iter()
3104 .filter_map(|action| {
3105 action
3106 .buffer
3107 .initialization_status
3108 .read()
3109 .check_action(action)
3110 }),
3111 );
3112 for action in bundle.texture_memory_init_actions.iter() {
3113 state.pass.pending_discard_init_fixups.extend(
3114 state
3115 .pass
3116 .base
3117 .texture_memory_actions
3118 .register_init_action(action),
3119 );
3120 }
3121
3122 unsafe {
3123 bundle.execute(
3124 state.pass.base.raw_encoder,
3125 state.pass.base.indirect_draw_validation_resources,
3126 indirect_draw_validation_batcher,
3127 state.pass.base.snatch_guard,
3128 )
3129 }
3130 .map_err(|e| match e {
3131 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3132 ExecutionError::DestroyedResource(e) => {
3133 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3134 }
3135 ExecutionError::Unimplemented(what) => {
3136 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3137 }
3138 })?;
3139
3140 unsafe {
3141 state.pass.scope.merge_render_bundle(&bundle.used)?;
3142 };
3143 state.reset_bundle();
3144 Ok(())
3145}
3146
3147impl Global {
3160 pub fn render_pass_set_bind_group(
3161 &self,
3162 pass: &mut RenderPass,
3163 index: u32,
3164 bind_group_id: Option<id::BindGroupId>,
3165 offsets: &[DynamicOffset],
3166 ) -> Result<(), PassStateError> {
3167 let scope = PassErrorScope::SetBindGroup;
3168
3169 let base = pass_base!(pass, scope);
3173
3174 if pass.current_bind_groups.set_and_check_redundant(
3175 bind_group_id,
3176 index,
3177 &mut base.dynamic_offsets,
3178 offsets,
3179 ) {
3180 return Ok(());
3181 }
3182
3183 let mut bind_group = None;
3184 if let Some(bind_group_id) = bind_group_id {
3185 let hub = &self.hub;
3186 bind_group = Some(pass_try!(
3187 base,
3188 scope,
3189 hub.bind_groups.get(bind_group_id).get(),
3190 ));
3191 }
3192
3193 base.commands.push(ArcRenderCommand::SetBindGroup {
3194 index,
3195 num_dynamic_offsets: offsets.len(),
3196 bind_group,
3197 });
3198
3199 Ok(())
3200 }
3201
3202 pub fn render_pass_set_pipeline(
3203 &self,
3204 pass: &mut RenderPass,
3205 pipeline_id: id::RenderPipelineId,
3206 ) -> Result<(), PassStateError> {
3207 let scope = PassErrorScope::SetPipelineRender;
3208
3209 let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3210
3211 let base = pass_base!(pass, scope);
3214
3215 if redundant {
3216 return Ok(());
3217 }
3218
3219 let hub = &self.hub;
3220 let pipeline = pass_try!(base, scope, hub.render_pipelines.get(pipeline_id).get());
3221
3222 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3223
3224 Ok(())
3225 }
3226
3227 pub fn render_pass_set_index_buffer(
3228 &self,
3229 pass: &mut RenderPass,
3230 buffer_id: id::BufferId,
3231 index_format: IndexFormat,
3232 offset: BufferAddress,
3233 size: Option<BufferSize>,
3234 ) -> Result<(), PassStateError> {
3235 let scope = PassErrorScope::SetIndexBuffer;
3236 let base = pass_base!(pass, scope);
3237
3238 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3239 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3240 index_format,
3241 offset,
3242 size,
3243 });
3244
3245 Ok(())
3246 }
3247
3248 pub fn render_pass_set_vertex_buffer(
3249 &self,
3250 pass: &mut RenderPass,
3251 slot: u32,
3252 buffer_id: id::BufferId,
3253 offset: BufferAddress,
3254 size: Option<BufferSize>,
3255 ) -> Result<(), PassStateError> {
3256 let scope = PassErrorScope::SetVertexBuffer;
3257 let base = pass_base!(pass, scope);
3258
3259 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3260 slot,
3261 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3262 offset,
3263 size,
3264 });
3265
3266 Ok(())
3267 }
3268
3269 pub fn render_pass_set_blend_constant(
3270 &self,
3271 pass: &mut RenderPass,
3272 color: Color,
3273 ) -> Result<(), PassStateError> {
3274 let scope = PassErrorScope::SetBlendConstant;
3275 let base = pass_base!(pass, scope);
3276
3277 base.commands
3278 .push(ArcRenderCommand::SetBlendConstant(color));
3279
3280 Ok(())
3281 }
3282
3283 pub fn render_pass_set_stencil_reference(
3284 &self,
3285 pass: &mut RenderPass,
3286 value: u32,
3287 ) -> Result<(), PassStateError> {
3288 let scope = PassErrorScope::SetStencilReference;
3289 let base = pass_base!(pass, scope);
3290
3291 base.commands
3292 .push(ArcRenderCommand::SetStencilReference(value));
3293
3294 Ok(())
3295 }
3296
3297 pub fn render_pass_set_viewport(
3298 &self,
3299 pass: &mut RenderPass,
3300 x: f32,
3301 y: f32,
3302 w: f32,
3303 h: f32,
3304 depth_min: f32,
3305 depth_max: f32,
3306 ) -> Result<(), PassStateError> {
3307 let scope = PassErrorScope::SetViewport;
3308 let base = pass_base!(pass, scope);
3309
3310 base.commands.push(ArcRenderCommand::SetViewport {
3311 rect: Rect { x, y, w, h },
3312 depth_min,
3313 depth_max,
3314 });
3315
3316 Ok(())
3317 }
3318
3319 pub fn render_pass_set_scissor_rect(
3320 &self,
3321 pass: &mut RenderPass,
3322 x: u32,
3323 y: u32,
3324 w: u32,
3325 h: u32,
3326 ) -> Result<(), PassStateError> {
3327 let scope = PassErrorScope::SetScissorRect;
3328 let base = pass_base!(pass, scope);
3329
3330 base.commands
3331 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3332
3333 Ok(())
3334 }
3335
3336 pub fn render_pass_set_immediates(
3337 &self,
3338 pass: &mut RenderPass,
3339 stages: ShaderStages,
3340 offset: u32,
3341 data: &[u8],
3342 ) -> Result<(), PassStateError> {
3343 let scope = PassErrorScope::SetImmediate;
3344 let base = pass_base!(pass, scope);
3345
3346 if offset & (wgt::IMMEDIATES_ALIGNMENT - 1) != 0 {
3347 pass_try!(
3348 base,
3349 scope,
3350 Err(RenderPassErrorInner::ImmediateOffsetAlignment)
3351 );
3352 }
3353 if data.len() as u32 & (wgt::IMMEDIATES_ALIGNMENT - 1) != 0 {
3354 pass_try!(
3355 base,
3356 scope,
3357 Err(RenderPassErrorInner::ImmediateDataizeAlignment)
3358 );
3359 }
3360
3361 let value_offset = pass_try!(
3362 base,
3363 scope,
3364 base.immediates_data
3365 .len()
3366 .try_into()
3367 .map_err(|_| RenderPassErrorInner::ImmediateOutOfMemory),
3368 );
3369
3370 base.immediates_data.extend(
3371 data.chunks_exact(wgt::IMMEDIATES_ALIGNMENT as usize)
3372 .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3373 );
3374
3375 base.commands.push(ArcRenderCommand::SetImmediate {
3376 stages,
3377 offset,
3378 size_bytes: data.len() as u32,
3379 values_offset: Some(value_offset),
3380 });
3381
3382 Ok(())
3383 }
3384
3385 pub fn render_pass_draw(
3386 &self,
3387 pass: &mut RenderPass,
3388 vertex_count: u32,
3389 instance_count: u32,
3390 first_vertex: u32,
3391 first_instance: u32,
3392 ) -> Result<(), PassStateError> {
3393 let scope = PassErrorScope::Draw {
3394 kind: DrawKind::Draw,
3395 family: DrawCommandFamily::Draw,
3396 };
3397 let base = pass_base!(pass, scope);
3398
3399 base.commands.push(ArcRenderCommand::Draw {
3400 vertex_count,
3401 instance_count,
3402 first_vertex,
3403 first_instance,
3404 });
3405
3406 Ok(())
3407 }
3408
3409 pub fn render_pass_draw_indexed(
3410 &self,
3411 pass: &mut RenderPass,
3412 index_count: u32,
3413 instance_count: u32,
3414 first_index: u32,
3415 base_vertex: i32,
3416 first_instance: u32,
3417 ) -> Result<(), PassStateError> {
3418 let scope = PassErrorScope::Draw {
3419 kind: DrawKind::Draw,
3420 family: DrawCommandFamily::DrawIndexed,
3421 };
3422 let base = pass_base!(pass, scope);
3423
3424 base.commands.push(ArcRenderCommand::DrawIndexed {
3425 index_count,
3426 instance_count,
3427 first_index,
3428 base_vertex,
3429 first_instance,
3430 });
3431
3432 Ok(())
3433 }
3434
3435 pub fn render_pass_draw_mesh_tasks(
3436 &self,
3437 pass: &mut RenderPass,
3438 group_count_x: u32,
3439 group_count_y: u32,
3440 group_count_z: u32,
3441 ) -> Result<(), RenderPassError> {
3442 let scope = PassErrorScope::Draw {
3443 kind: DrawKind::Draw,
3444 family: DrawCommandFamily::DrawMeshTasks,
3445 };
3446 let base = pass_base!(pass, scope);
3447
3448 base.commands.push(ArcRenderCommand::DrawMeshTasks {
3449 group_count_x,
3450 group_count_y,
3451 group_count_z,
3452 });
3453 Ok(())
3454 }
3455
3456 pub fn render_pass_draw_indirect(
3457 &self,
3458 pass: &mut RenderPass,
3459 buffer_id: id::BufferId,
3460 offset: BufferAddress,
3461 ) -> Result<(), PassStateError> {
3462 let scope = PassErrorScope::Draw {
3463 kind: DrawKind::DrawIndirect,
3464 family: DrawCommandFamily::Draw,
3465 };
3466 let base = pass_base!(pass, scope);
3467
3468 base.commands.push(ArcRenderCommand::DrawIndirect {
3469 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3470 offset,
3471 count: 1,
3472 family: DrawCommandFamily::Draw,
3473
3474 vertex_or_index_limit: None,
3475 instance_limit: None,
3476 });
3477
3478 Ok(())
3479 }
3480
3481 pub fn render_pass_draw_indexed_indirect(
3482 &self,
3483 pass: &mut RenderPass,
3484 buffer_id: id::BufferId,
3485 offset: BufferAddress,
3486 ) -> Result<(), PassStateError> {
3487 let scope = PassErrorScope::Draw {
3488 kind: DrawKind::DrawIndirect,
3489 family: DrawCommandFamily::DrawIndexed,
3490 };
3491 let base = pass_base!(pass, scope);
3492
3493 base.commands.push(ArcRenderCommand::DrawIndirect {
3494 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3495 offset,
3496 count: 1,
3497 family: DrawCommandFamily::DrawIndexed,
3498
3499 vertex_or_index_limit: None,
3500 instance_limit: None,
3501 });
3502
3503 Ok(())
3504 }
3505
3506 pub fn render_pass_draw_mesh_tasks_indirect(
3507 &self,
3508 pass: &mut RenderPass,
3509 buffer_id: id::BufferId,
3510 offset: BufferAddress,
3511 ) -> Result<(), RenderPassError> {
3512 let scope = PassErrorScope::Draw {
3513 kind: DrawKind::DrawIndirect,
3514 family: DrawCommandFamily::DrawMeshTasks,
3515 };
3516 let base = pass_base!(pass, scope);
3517
3518 base.commands.push(ArcRenderCommand::DrawIndirect {
3519 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3520 offset,
3521 count: 1,
3522 family: DrawCommandFamily::DrawMeshTasks,
3523
3524 vertex_or_index_limit: None,
3525 instance_limit: None,
3526 });
3527
3528 Ok(())
3529 }
3530
3531 pub fn render_pass_multi_draw_indirect(
3532 &self,
3533 pass: &mut RenderPass,
3534 buffer_id: id::BufferId,
3535 offset: BufferAddress,
3536 count: u32,
3537 ) -> Result<(), PassStateError> {
3538 let scope = PassErrorScope::Draw {
3539 kind: DrawKind::MultiDrawIndirect,
3540 family: DrawCommandFamily::Draw,
3541 };
3542 let base = pass_base!(pass, scope);
3543
3544 base.commands.push(ArcRenderCommand::DrawIndirect {
3545 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3546 offset,
3547 count,
3548 family: DrawCommandFamily::Draw,
3549
3550 vertex_or_index_limit: None,
3551 instance_limit: None,
3552 });
3553
3554 Ok(())
3555 }
3556
3557 pub fn render_pass_multi_draw_indexed_indirect(
3558 &self,
3559 pass: &mut RenderPass,
3560 buffer_id: id::BufferId,
3561 offset: BufferAddress,
3562 count: u32,
3563 ) -> Result<(), PassStateError> {
3564 let scope = PassErrorScope::Draw {
3565 kind: DrawKind::MultiDrawIndirect,
3566 family: DrawCommandFamily::DrawIndexed,
3567 };
3568 let base = pass_base!(pass, scope);
3569
3570 base.commands.push(ArcRenderCommand::DrawIndirect {
3571 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3572 offset,
3573 count,
3574 family: DrawCommandFamily::DrawIndexed,
3575
3576 vertex_or_index_limit: None,
3577 instance_limit: None,
3578 });
3579
3580 Ok(())
3581 }
3582
3583 pub fn render_pass_multi_draw_mesh_tasks_indirect(
3584 &self,
3585 pass: &mut RenderPass,
3586 buffer_id: id::BufferId,
3587 offset: BufferAddress,
3588 count: u32,
3589 ) -> Result<(), RenderPassError> {
3590 let scope = PassErrorScope::Draw {
3591 kind: DrawKind::MultiDrawIndirect,
3592 family: DrawCommandFamily::DrawMeshTasks,
3593 };
3594 let base = pass_base!(pass, scope);
3595
3596 base.commands.push(ArcRenderCommand::DrawIndirect {
3597 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3598 offset,
3599 count,
3600 family: DrawCommandFamily::DrawMeshTasks,
3601
3602 vertex_or_index_limit: None,
3603 instance_limit: None,
3604 });
3605
3606 Ok(())
3607 }
3608
3609 pub fn render_pass_multi_draw_indirect_count(
3610 &self,
3611 pass: &mut RenderPass,
3612 buffer_id: id::BufferId,
3613 offset: BufferAddress,
3614 count_buffer_id: id::BufferId,
3615 count_buffer_offset: BufferAddress,
3616 max_count: u32,
3617 ) -> Result<(), PassStateError> {
3618 let scope = PassErrorScope::Draw {
3619 kind: DrawKind::MultiDrawIndirectCount,
3620 family: DrawCommandFamily::Draw,
3621 };
3622 let base = pass_base!(pass, scope);
3623
3624 base.commands
3625 .push(ArcRenderCommand::MultiDrawIndirectCount {
3626 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3627 offset,
3628 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3629 count_buffer_offset,
3630 max_count,
3631 family: DrawCommandFamily::Draw,
3632 });
3633
3634 Ok(())
3635 }
3636
3637 pub fn render_pass_multi_draw_indexed_indirect_count(
3638 &self,
3639 pass: &mut RenderPass,
3640 buffer_id: id::BufferId,
3641 offset: BufferAddress,
3642 count_buffer_id: id::BufferId,
3643 count_buffer_offset: BufferAddress,
3644 max_count: u32,
3645 ) -> Result<(), PassStateError> {
3646 let scope = PassErrorScope::Draw {
3647 kind: DrawKind::MultiDrawIndirectCount,
3648 family: DrawCommandFamily::DrawIndexed,
3649 };
3650 let base = pass_base!(pass, scope);
3651
3652 base.commands
3653 .push(ArcRenderCommand::MultiDrawIndirectCount {
3654 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3655 offset,
3656 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3657 count_buffer_offset,
3658 max_count,
3659 family: DrawCommandFamily::DrawIndexed,
3660 });
3661
3662 Ok(())
3663 }
3664
3665 pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
3666 &self,
3667 pass: &mut RenderPass,
3668 buffer_id: id::BufferId,
3669 offset: BufferAddress,
3670 count_buffer_id: id::BufferId,
3671 count_buffer_offset: BufferAddress,
3672 max_count: u32,
3673 ) -> Result<(), RenderPassError> {
3674 let scope = PassErrorScope::Draw {
3675 kind: DrawKind::MultiDrawIndirectCount,
3676 family: DrawCommandFamily::DrawMeshTasks,
3677 };
3678 let base = pass_base!(pass, scope);
3679
3680 base.commands
3681 .push(ArcRenderCommand::MultiDrawIndirectCount {
3682 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3683 offset,
3684 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
3685 count_buffer_offset,
3686 max_count,
3687 family: DrawCommandFamily::DrawMeshTasks,
3688 });
3689
3690 Ok(())
3691 }
3692
3693 pub fn render_pass_push_debug_group(
3694 &self,
3695 pass: &mut RenderPass,
3696 label: &str,
3697 color: u32,
3698 ) -> Result<(), PassStateError> {
3699 let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
3700
3701 let bytes = label.as_bytes();
3702 base.string_data.extend_from_slice(bytes);
3703
3704 base.commands.push(ArcRenderCommand::PushDebugGroup {
3705 color,
3706 len: bytes.len(),
3707 });
3708
3709 Ok(())
3710 }
3711
3712 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
3713 let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
3714
3715 base.commands.push(ArcRenderCommand::PopDebugGroup);
3716
3717 Ok(())
3718 }
3719
3720 pub fn render_pass_insert_debug_marker(
3721 &self,
3722 pass: &mut RenderPass,
3723 label: &str,
3724 color: u32,
3725 ) -> Result<(), PassStateError> {
3726 let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
3727
3728 let bytes = label.as_bytes();
3729 base.string_data.extend_from_slice(bytes);
3730
3731 base.commands.push(ArcRenderCommand::InsertDebugMarker {
3732 color,
3733 len: bytes.len(),
3734 });
3735
3736 Ok(())
3737 }
3738
3739 pub fn render_pass_write_timestamp(
3740 &self,
3741 pass: &mut RenderPass,
3742 query_set_id: id::QuerySetId,
3743 query_index: u32,
3744 ) -> Result<(), PassStateError> {
3745 let scope = PassErrorScope::WriteTimestamp;
3746 let base = pass_base!(pass, scope);
3747
3748 base.commands.push(ArcRenderCommand::WriteTimestamp {
3749 query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3750 query_index,
3751 });
3752
3753 Ok(())
3754 }
3755
3756 pub fn render_pass_begin_occlusion_query(
3757 &self,
3758 pass: &mut RenderPass,
3759 query_index: u32,
3760 ) -> Result<(), PassStateError> {
3761 let scope = PassErrorScope::BeginOcclusionQuery;
3762 let base = pass_base!(pass, scope);
3763
3764 base.commands
3765 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
3766
3767 Ok(())
3768 }
3769
3770 pub fn render_pass_end_occlusion_query(
3771 &self,
3772 pass: &mut RenderPass,
3773 ) -> Result<(), PassStateError> {
3774 let scope = PassErrorScope::EndOcclusionQuery;
3775 let base = pass_base!(pass, scope);
3776
3777 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
3778
3779 Ok(())
3780 }
3781
3782 pub fn render_pass_begin_pipeline_statistics_query(
3783 &self,
3784 pass: &mut RenderPass,
3785 query_set_id: id::QuerySetId,
3786 query_index: u32,
3787 ) -> Result<(), PassStateError> {
3788 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
3789 let base = pass_base!(pass, scope);
3790
3791 base.commands
3792 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
3793 query_set: pass_try!(base, scope, self.resolve_query_set(query_set_id)),
3794 query_index,
3795 });
3796
3797 Ok(())
3798 }
3799
3800 pub fn render_pass_end_pipeline_statistics_query(
3801 &self,
3802 pass: &mut RenderPass,
3803 ) -> Result<(), PassStateError> {
3804 let scope = PassErrorScope::EndPipelineStatisticsQuery;
3805 let base = pass_base!(pass, scope);
3806
3807 base.commands
3808 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
3809
3810 Ok(())
3811 }
3812
3813 pub fn render_pass_execute_bundles(
3814 &self,
3815 pass: &mut RenderPass,
3816 render_bundle_ids: &[id::RenderBundleId],
3817 ) -> Result<(), PassStateError> {
3818 let scope = PassErrorScope::ExecuteBundle;
3819 let base = pass_base!(pass, scope);
3820
3821 let hub = &self.hub;
3822 let bundles = hub.render_bundles.read();
3823
3824 for &bundle_id in render_bundle_ids {
3825 let bundle = pass_try!(base, scope, bundles.get(bundle_id).get());
3826
3827 base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
3828 }
3829 pass.current_pipeline.reset();
3830 pass.current_bind_groups.reset();
3831
3832 Ok(())
3833 }
3834}
3835
3836pub(crate) const fn get_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
3837 match family {
3838 DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
3839 DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
3840 DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
3841 }
3842}