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