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