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