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