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