1use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
2use core::{convert::Infallible, fmt, num::NonZeroU32, ops::Range, str};
3use parking_lot::Mutex;
4use smallvec::SmallVec;
5
6use arrayvec::ArrayVec;
7use thiserror::Error;
8use wgt::{
9 error::{ErrorType, WebGpuError},
10 BufferAddress, BufferSize, BufferUsages, Color, DynamicOffset, IndexFormat, InstanceFlags,
11 TextureSelector, TextureUsages, TextureViewDimension, VertexStepMode,
12};
13
14use crate::{
15 api_log,
16 binding_model::{BindError, BindGroup, ImmediateUploadError},
17 command::{
18 bind::Binder,
19 memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState, TextureSurfaceDiscard},
20 pass::{self, flush_bindings_helper, ImmediateState},
21 pass_base, pass_try,
22 query::{
23 end_occlusion_query, end_pipeline_statistics_query, record_pass_timestamp_writes,
24 validate_and_begin_occlusion_query, validate_and_begin_pipeline_statistics_query,
25 QueryResetMap, QuerySetWrites,
26 },
27 render_command::ArcRenderCommand,
28 ArcCommand, BasePass, BindGroupStateChange, CommandBufferTextureMemoryActions,
29 CommandEncoder, CommandEncoderError, DebugGroupError, DrawCommandFamily, DrawError,
30 DrawKind, EncoderStateError, EncodingState, ExecutionError, InnerCommandEncoder,
31 MapPassErr, PassErrorScope, PassStateError, PassTimestampWrites, QueryUseError, Rect,
32 RenderBundle, RenderCommandError, StateChange, TimestampWritesError,
33 },
34 device::{
35 AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures,
36 RenderPassCompatibilityError, RenderPassContext,
37 },
38 global::Global,
39 hal_label, id, impl_resource_type,
40 init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
41 pipeline::{PipelineFlags, RenderPipeline, VertexStep},
42 resource::{
43 Buffer, DestroyedResourceError, InvalidOrDestroyedResourceError, InvalidResourceError,
44 Labeled, MissingBufferUsageError, MissingTextureUsageError, ParentDevice, QuerySet,
45 RawResourceAccess, ResourceErrorIdent, Texture, TextureView,
46 TextureViewNotRenderableReason,
47 },
48 snatch::SnatchGuard,
49 track::{ResourceUsageCompatibilityError, Tracker, UsageScope},
50 validation::{self, WorkgroupSizeCheck},
51 Label,
52};
53
54#[cfg(feature = "serde")]
55use serde::Deserialize;
56#[cfg(feature = "serde")]
57use serde::Serialize;
58
59pub use wgt::{LoadOp, StoreOp};
60
61fn load_hal_ops<V>(load: LoadOp<V>) -> hal::AttachmentOps {
62 match load {
63 LoadOp::Load => hal::AttachmentOps::LOAD,
64 LoadOp::Clear(_) => hal::AttachmentOps::LOAD_CLEAR,
65 LoadOp::DontCare(_) => hal::AttachmentOps::LOAD_DONT_CARE,
66 }
67}
68
69fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps {
70 match store {
71 StoreOp::Store => hal::AttachmentOps::STORE,
72 StoreOp::Discard => hal::AttachmentOps::STORE_DISCARD,
73 }
74}
75
76fn convert_stencil_value(value: u32, format: Option<wgt::TextureFormat>) -> u32 {
78 let Some(format) = format else {
79 return value;
80 };
81 let Some(stencil_format) = format.aspect_specific_format(wgt::TextureAspect::StencilOnly)
82 else {
83 return value;
84 };
85 assert_eq!(stencil_format, wgt::TextureFormat::Stencil8);
87 value & 255
88}
89
90#[repr(C)]
95#[derive(Clone, Debug, Eq, PartialEq)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97pub struct PassChannel<V> {
98 pub load_op: Option<LoadOp<V>>,
104 pub store_op: Option<StoreOp>,
106 pub read_only: bool,
110}
111
112impl<V: Copy + Default> PassChannel<Option<V>> {
113 fn resolve(
114 &self,
115 instance_flags: InstanceFlags,
116 handle_clear: impl Fn(Option<V>) -> Result<V, AttachmentError>,
117 ) -> Result<ResolvedPassChannel<V>, AttachmentError> {
118 if self.read_only {
119 if self.load_op.is_some() {
120 return Err(AttachmentError::ReadOnlyWithLoad);
121 }
122 if self.store_op.is_some() {
123 return Err(AttachmentError::ReadOnlyWithStore);
124 }
125 Ok(ResolvedPassChannel::ReadOnly)
126 } else {
127 Ok(ResolvedPassChannel::Operational(wgt::Operations {
128 load: match self.load_op.ok_or(AttachmentError::NoLoad)? {
129 LoadOp::Clear(clear_value) => LoadOp::Clear(handle_clear(clear_value)?),
130 LoadOp::DontCare(token) => {
131 if instance_flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
132 return Err(AttachmentError::LoadOpDontCareUnderStrictWebgpuCompliance);
133 }
134 LoadOp::DontCare(token)
135 }
136 LoadOp::Load => LoadOp::Load,
137 },
138 store: self.store_op.ok_or(AttachmentError::NoStore)?,
139 }))
140 }
141 }
142}
143
144#[derive(Clone, Debug)]
149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
150pub enum ResolvedPassChannel<V> {
151 ReadOnly,
152 Operational(wgt::Operations<V>),
153}
154
155impl<V: Copy + Default> ResolvedPassChannel<V> {
156 fn load_op(&self) -> LoadOp<V> {
157 match self {
158 ResolvedPassChannel::ReadOnly => LoadOp::Load,
159 ResolvedPassChannel::Operational(wgt::Operations { load, .. }) => *load,
160 }
161 }
162
163 fn store_op(&self) -> StoreOp {
164 match self {
165 ResolvedPassChannel::ReadOnly => StoreOp::Store,
166 ResolvedPassChannel::Operational(wgt::Operations { store, .. }) => *store,
167 }
168 }
169
170 fn clear_value(&self) -> V {
171 match self {
172 Self::Operational(wgt::Operations {
173 load: LoadOp::Clear(clear_value),
174 ..
175 }) => *clear_value,
176 _ => Default::default(),
177 }
178 }
179
180 fn is_readonly(&self) -> bool {
181 matches!(self, Self::ReadOnly)
182 }
183
184 fn hal_ops(&self) -> hal::AttachmentOps {
185 load_hal_ops(self.load_op()) | store_hal_ops(self.store_op())
186 }
187}
188
189#[repr(C)]
191#[derive(Clone, Debug, PartialEq)]
192#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
193pub struct RenderPassColorAttachment<TV = Arc<TextureView>> {
194 pub view: TV,
196 pub depth_slice: Option<u32>,
198 pub resolve_target: Option<TV>,
200 pub load_op: LoadOp<Color>,
206 pub store_op: StoreOp,
208}
209
210pub type ColorAttachments<TV = Arc<TextureView>> =
213 SmallVec<[Option<RenderPassColorAttachment<TV>>; 1]>;
214
215impl RenderPassColorAttachment {
216 fn hal_ops(&self) -> hal::AttachmentOps {
217 load_hal_ops(self.load_op) | store_hal_ops(self.store_op)
218 }
219
220 fn clear_value(&self) -> Color {
221 match self.load_op {
222 LoadOp::Clear(clear_value) => clear_value,
223 LoadOp::DontCare(_) | LoadOp::Load => Color::default(),
224 }
225 }
226}
227
228#[repr(C)]
232#[derive(Clone, Debug, PartialEq)]
233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
234pub struct RenderPassDepthStencilAttachment<TV> {
235 pub view: TV,
237 pub depth: PassChannel<Option<f32>>,
239 pub stencil: PassChannel<Option<u32>>,
241}
242
243#[derive(Clone, Debug)]
247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
248pub struct ResolvedRenderPassDepthStencilAttachment<TV> {
249 pub view: TV,
251 pub depth: ResolvedPassChannel<f32>,
253 pub stencil: ResolvedPassChannel<u32>,
255}
256
257#[derive(Clone, Debug, Default, PartialEq)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260pub struct RenderPassDescriptor<'a> {
261 pub label: Label<'a>,
262 pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment<id::TextureViewId>>]>,
264 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<id::TextureViewId>>,
266 pub timestamp_writes: Option<PassTimestampWrites<id::QuerySetId>>,
268 pub occlusion_query_set: Option<id::QuerySetId>,
270 pub multiview_mask: Option<NonZeroU32>,
272}
273
274#[derive(Clone, Default)]
276pub struct ResolvedRenderPassDescriptor<'a> {
277 pub label: Label<'a>,
278 pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment<Arc<TextureView>>>]>,
280 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<Arc<TextureView>>>,
282 pub timestamp_writes: Option<PassTimestampWrites<Arc<QuerySet>>>,
284 pub occlusion_query_set: Option<Arc<QuerySet>>,
286 pub multiview_mask: Option<NonZeroU32>,
288}
289
290struct ArcRenderPassDescriptor<'a> {
292 pub label: &'a Label<'a>,
293 pub color_attachments:
295 ArrayVec<Option<RenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
296 pub depth_stencil_attachment:
298 Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
299 pub timestamp_writes: Option<PassTimestampWrites>,
301 pub occlusion_query_set: Option<Arc<QuerySet>>,
303 pub multiview_mask: Option<NonZeroU32>,
305}
306
307pub type RenderBasePass = BasePass<ArcRenderCommand, RenderPassError>;
308
309pub struct RenderPass {
317 base: BasePass<ArcRenderCommand, RenderPassError>,
319
320 parent: Option<Arc<CommandEncoder>>,
326
327 color_attachments: ArrayVec<Option<RenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
328 depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
329 timestamp_writes: Option<PassTimestampWrites>,
330 occlusion_query_set: Option<Arc<QuerySet>>,
331 multiview_mask: Option<NonZeroU32>,
332
333 current_bind_groups: BindGroupStateChange,
335 current_pipeline: StateChange<Arc<RenderPipeline>>,
336}
337
338impl_resource_type!(RenderPass);
339
340impl crate::storage::StorageItem for RenderPass {
341 type Marker = id::markers::RenderPassEncoder;
342}
343
344impl RenderPass {
345 fn new(parent: Arc<CommandEncoder>, desc: ArcRenderPassDescriptor) -> Self {
347 let ArcRenderPassDescriptor {
348 label,
349 timestamp_writes,
350 color_attachments,
351 depth_stencil_attachment,
352 occlusion_query_set,
353 multiview_mask,
354 } = desc;
355
356 Self {
357 base: BasePass::new(label),
358 parent: Some(parent),
359 color_attachments,
360 depth_stencil_attachment,
361 timestamp_writes,
362 occlusion_query_set,
363 multiview_mask,
364
365 current_bind_groups: BindGroupStateChange::new(),
366 current_pipeline: StateChange::new(),
367 }
368 }
369
370 fn new_invalid(parent: Arc<CommandEncoder>, label: &Label, err: RenderPassError) -> Self {
371 Self {
372 base: BasePass::new_invalid(label, err),
373 parent: Some(parent),
374 color_attachments: ArrayVec::new(),
375 depth_stencil_attachment: None,
376 timestamp_writes: None,
377 occlusion_query_set: None,
378 multiview_mask: None,
379 current_bind_groups: BindGroupStateChange::new(),
380 current_pipeline: StateChange::new(),
381 }
382 }
383
384 #[inline]
385 pub fn label(&self) -> Option<&str> {
386 self.base.label.as_deref()
387 }
388}
389
390impl fmt::Debug for RenderPass {
391 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392 f.debug_struct("RenderPass")
393 .field("label", &self.label())
394 .field("color_attachments", &self.color_attachments)
395 .field("depth_stencil_target", &self.depth_stencil_attachment)
396 .field("command count", &self.base.commands.len())
397 .field("dynamic offset count", &self.base.dynamic_offsets.len())
398 .field("multiview mask", &self.multiview_mask)
399 .finish()
400 }
401}
402
403#[derive(Debug, PartialEq)]
404enum OptionalState {
405 Unused,
406 Required,
407 Set,
408}
409
410impl OptionalState {
411 fn require(&mut self, require: bool) {
412 if require && *self == Self::Unused {
413 *self = Self::Required;
414 }
415 }
416}
417
418#[derive(Debug, Default)]
419struct IndexState {
420 buffer_format: Option<IndexFormat>,
421 limit: u64,
422}
423
424impl IndexState {
425 fn update_buffer(&mut self, range: Range<BufferAddress>, format: IndexFormat) {
426 self.buffer_format = Some(format);
427 let shift = match format {
428 IndexFormat::Uint16 => 1,
429 IndexFormat::Uint32 => 2,
430 };
431 self.limit = (range.end - range.start) >> shift;
432 }
433
434 fn reset(&mut self) {
435 self.buffer_format = None;
436 self.limit = 0;
437 }
438}
439
440#[derive(Debug, Default)]
441pub(crate) struct VertexLimits {
442 pub(crate) vertex_limit: u64,
444 vertex_limit_slot: u32,
446 pub(crate) instance_limit: u64,
448 instance_limit_slot: u32,
450}
451
452impl VertexLimits {
453 pub(crate) fn new(
454 buffer_sizes: impl ExactSizeIterator<Item = Option<BufferAddress>>,
455 pipeline_steps: &[Option<VertexStep>],
456 ) -> Self {
457 let mut vertex_limit = u64::MAX;
464 let mut vertex_limit_slot = 0;
465 let mut instance_limit = u64::MAX;
466 let mut instance_limit_slot = 0;
467
468 for (idx, (buffer_size, step)) in buffer_sizes.zip(pipeline_steps).enumerate() {
469 let Some(step) = step else {
470 continue;
471 };
472
473 let Some(buffer_size) = buffer_size else {
474 return Self::default();
476 };
477
478 let limit = if buffer_size < step.last_stride {
479 0
481 } else {
482 if step.stride == 0 {
483 continue;
487 }
488
489 (buffer_size - step.last_stride) / step.stride + 1
491 };
492
493 match step.mode {
494 VertexStepMode::Vertex => {
495 if limit < vertex_limit {
496 vertex_limit = limit;
497 vertex_limit_slot = idx as _;
498 }
499 }
500 VertexStepMode::Instance => {
501 if limit < instance_limit {
502 instance_limit = limit;
503 instance_limit_slot = idx as _;
504 }
505 }
506 }
507 }
508
509 Self {
510 vertex_limit,
511 vertex_limit_slot,
512 instance_limit,
513 instance_limit_slot,
514 }
515 }
516
517 pub(crate) fn validate_vertex_limit(
518 &self,
519 first_vertex: u32,
520 vertex_count: u32,
521 ) -> Result<(), DrawError> {
522 let last_vertex = first_vertex as u64 + vertex_count as u64;
523 let vertex_limit = self.vertex_limit;
524 if last_vertex > vertex_limit {
525 return Err(DrawError::VertexBeyondLimit {
526 last_vertex,
527 vertex_limit,
528 slot: self.vertex_limit_slot,
529 });
530 }
531
532 Ok(())
533 }
534
535 pub(crate) fn validate_instance_limit(
536 &self,
537 first_instance: u32,
538 instance_count: u32,
539 ) -> Result<(), DrawError> {
540 let last_instance = first_instance as u64 + instance_count as u64;
541 let instance_limit = self.instance_limit;
542 if last_instance > instance_limit {
543 return Err(DrawError::InstanceBeyondLimit {
544 last_instance,
545 instance_limit,
546 slot: self.instance_limit_slot,
547 });
548 }
549
550 Ok(())
551 }
552}
553
554#[derive(Debug)]
556pub(crate) struct VertexSlot {
557 pub(crate) buffer: Arc<Buffer>,
558 pub(crate) range: Range<BufferAddress>,
559 pub(crate) is_dirty: bool,
560}
561
562#[derive(Debug, Default)]
567pub(crate) struct VertexState {
568 slots: [Option<VertexSlot>; hal::MAX_VERTEX_BUFFERS],
569 pub(crate) limits: VertexLimits,
570}
571
572impl VertexState {
573 pub(crate) fn set_buffer(
575 &mut self,
576 slot: usize,
577 buffer: Arc<Buffer>,
578 range: Range<BufferAddress>,
579 ) {
580 self.slots[slot] = Some(VertexSlot {
581 buffer,
582 range,
583 is_dirty: true,
584 });
585 }
586
587 pub(crate) fn clear_buffer(&mut self, slot: usize) {
589 self.slots[slot] = None;
590 }
591
592 pub(crate) fn update_limits(&mut self, pipeline_steps: &[Option<VertexStep>]) {
594 self.limits = VertexLimits::new(
595 self.slots
596 .iter()
597 .map(|s| s.as_ref().map(|s| s.range.end - s.range.start)),
598 pipeline_steps,
599 );
600 }
601
602 fn last_assigned_index(&self) -> Option<usize> {
603 self.slots
604 .iter()
605 .enumerate()
606 .filter_map(|(i, s)| s.as_ref().map(|_| i))
607 .next_back()
608 }
609
610 pub(super) fn validate(
611 &self,
612 pipeline: &RenderPipeline,
613 binder: &Binder,
614 ) -> Result<(), DrawError> {
615 for index in pipeline
617 .vertex_steps
618 .iter()
619 .enumerate()
620 .filter_map(|(index, step)| step.map(|_| index))
621 {
622 if self.slots[index].is_none() {
623 return Err(DrawError::MissingVertexBuffer {
624 pipeline: pipeline.error_ident(),
625 index,
626 });
627 }
628 }
629
630 let bind_group_space_used = binder.last_assigned_index().map_or(0, |i| i + 1);
631 let vertex_buffer_space_used = self.last_assigned_index().map_or(0, |i| i + 1);
632
633 let bind_groups_plus_vertex_buffers =
634 u32::try_from(bind_group_space_used + vertex_buffer_space_used).unwrap();
635 if bind_groups_plus_vertex_buffers
636 > pipeline.device.limits.max_bind_groups_plus_vertex_buffers
637 {
638 return Err(DrawError::TooManyBindGroupsPlusVertexBuffers {
639 given: bind_groups_plus_vertex_buffers,
640 limit: pipeline.device.limits.max_bind_groups_plus_vertex_buffers,
641 });
642 }
643
644 Ok(())
645 }
646
647 pub(crate) fn flush<F>(&mut self, mut f: F)
649 where
650 F: FnMut(u32, &Arc<Buffer>, BufferAddress, Option<BufferSize>),
651 {
652 for (i, slot) in self.slots.iter_mut().enumerate() {
653 let Some(slot) = slot.as_mut() else { continue };
654 if !slot.is_dirty {
655 continue;
656 }
657 slot.is_dirty = false;
658 let size = slot.range.end - slot.range.start;
659 f(
660 i as u32,
661 &slot.buffer,
662 slot.range.start,
663 BufferSize::new(size),
664 );
665 }
666 }
667}
668
669struct State<'scope, 'snatch_guard, 'cmd_enc> {
670 pipeline_flags: PipelineFlags,
671 blend_constant: OptionalState,
672 stencil_reference: u32,
673 pipeline: Option<Arc<RenderPipeline>>,
674 index: IndexState,
675 vertex: VertexState,
676
677 info: RenderPassInfo,
678
679 pass: pass::PassState<'scope, 'snatch_guard, 'cmd_enc>,
680
681 active_occlusion_query: Option<(Arc<QuerySet>, u32)>,
682 active_pipeline_statistics_query: Option<(Arc<QuerySet>, u32)>,
683}
684
685impl<'scope, 'snatch_guard, 'cmd_enc> State<'scope, 'snatch_guard, 'cmd_enc> {
686 fn is_ready(&self, family: DrawCommandFamily) -> Result<(), DrawError> {
687 if let Some(pipeline) = self.pipeline.as_ref() {
688 self.pass.binder.check_compatibility(pipeline.as_ref())?;
689 self.pass.binder.check_late_buffer_bindings()?;
690
691 if self.blend_constant == OptionalState::Required {
692 return Err(DrawError::MissingBlendConstant);
693 }
694
695 self.vertex.validate(pipeline.as_ref(), &self.pass.binder)?;
696
697 if family == DrawCommandFamily::DrawIndexed {
698 let buffer_index_format = self
701 .index
702 .buffer_format
703 .ok_or(DrawError::MissingIndexBuffer)?;
704
705 if pipeline.topology.is_strip()
706 && pipeline.strip_index_format != Some(buffer_index_format)
707 {
708 return Err(DrawError::UnmatchedStripIndexFormat {
709 pipeline: pipeline.error_ident(),
710 strip_index_format: pipeline.strip_index_format,
711 buffer_format: buffer_index_format,
712 });
713 }
714 }
715 if (family == DrawCommandFamily::DrawMeshTasks) != pipeline.is_mesh {
716 return Err(DrawError::WrongPipelineType {
717 wanted_mesh_pipeline: !pipeline.is_mesh,
718 });
719 }
720 if !self
721 .pass
722 .immediate_state
723 .immediate_slots_set
724 .contains(pipeline.immediate_slots_required)
725 {
726 return Err(DrawError::MissingImmediateData {
727 missing: pipeline
728 .immediate_slots_required
729 .difference(self.pass.immediate_state.immediate_slots_set),
730 });
731 }
732 Ok(())
733 } else {
734 Err(DrawError::MissingPipeline(pass::MissingPipeline))
735 }
736 }
737
738 fn flush_immediates(&mut self) {
739 let pipeline = self.pipeline.as_ref().unwrap();
740 let layout = pipeline.layout().unwrap();
741 self.pass
742 .immediate_state
743 .flush_immediates(layout, self.pass.base.raw_encoder);
744 }
745
746 fn flush_bindings(&mut self) -> Result<(), RenderPassErrorInner> {
751 flush_bindings_helper(&mut self.pass)?;
752 Ok(())
753 }
754
755 fn reset_bundle(&mut self) {
757 self.pass.binder.reset();
758 self.pipeline = None;
759 self.index.reset();
760 self.vertex = Default::default();
761 self.pass.immediate_state.immediate_slots_set = Default::default();
762 }
763
764 fn flush_vertex_buffers(&mut self) -> Result<(), RenderPassErrorInner> {
766 let vertex = &mut self.vertex;
767 let raw_encoder: &mut dyn hal::DynCommandEncoder = self.pass.base.raw_encoder;
768 let snatch_guard = self.pass.base.snatch_guard;
769 let mut result = Ok(());
770 vertex.flush(|slot, buffer, offset, size| {
771 if result.is_err() {
772 return;
773 }
774 match buffer.try_raw(snatch_guard) {
775 Ok(raw) => unsafe {
776 raw_encoder.set_vertex_buffer(
778 slot,
779 hal::BufferBinding::new_unchecked(raw, offset, size),
780 );
781 },
782 Err(e) => result = Err(e.into()),
783 }
784 });
785 result
786 }
787}
788
789#[derive(Debug, Copy, Clone)]
793pub enum AttachmentErrorLocation {
794 Color { index: usize, resolve: bool },
795 Depth,
796}
797
798impl fmt::Display for AttachmentErrorLocation {
799 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
800 match *self {
801 AttachmentErrorLocation::Color {
802 index,
803 resolve: false,
804 } => write!(f, "color attachment at index {index}'s texture view"),
805 AttachmentErrorLocation::Color {
806 index,
807 resolve: true,
808 } => write!(
809 f,
810 "color attachment at index {index}'s resolve texture view"
811 ),
812 AttachmentErrorLocation::Depth => write!(f, "depth attachment's texture view"),
813 }
814 }
815}
816
817#[derive(Clone, Debug, Error)]
818#[non_exhaustive]
819pub enum ColorAttachmentError {
820 #[error("Attachment format {0:?} is not a color format")]
821 InvalidFormat(wgt::TextureFormat),
822 #[error("The number of color attachments {given} exceeds the limit {limit}")]
823 TooMany { given: usize, limit: usize },
824 #[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
825 TooManyBytesPerSample { total: u32, limit: u32 },
826 #[error("Depth slice must be less than {limit} but is {given}")]
827 DepthSliceLimit { given: u32, limit: u32 },
828 #[error("Color attachment's view is 3D and requires depth slice to be provided")]
829 MissingDepthSlice,
830 #[error("Depth slice was provided but the color attachment's view is not 3D")]
831 UnneededDepthSlice,
832 #[error("{view}'s subresource at mip {mip_level} and depth/array layer {depth_or_array_layer} is already attached to this render pass")]
833 SubresourceOverlap {
834 view: ResourceErrorIdent,
835 mip_level: u32,
836 depth_or_array_layer: u32,
837 },
838 #[error(
839 "Color attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
840 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
841 )]
842 InvalidTransientAttachmentOp((LoadOp<Color>, StoreOp)),
843 #[error("Color attachment's load op is `LoadOp::DontCare` but `InstanceFlags::STRICT_WEBGPU_COMPLIANCE` is set")]
844 LoadOpDontCareUnderStrictWebgpuCompliance,
845}
846
847impl WebGpuError for ColorAttachmentError {
848 fn webgpu_error_type(&self) -> ErrorType {
849 ErrorType::Validation
850 }
851}
852
853#[derive(Clone, Debug, Error)]
854#[non_exhaustive]
855pub enum AttachmentError {
856 #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-or-stencil format")]
857 InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
858 #[error(
859 "Depth attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
860 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
861 )]
862 InvalidTransientDepthAttachmentOps((LoadOp<Option<f32>>, StoreOp)),
863 #[error("Depth attachment with `TRANSIENT_ATTACHMENT` usage cannot be read-only")]
864 ReadOnlyTransientDepthAttachment,
865 #[error(
866 "Stencil attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
867 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
868 )]
869 InvalidTransientStencilAttachmentOps((LoadOp<Option<u32>>, StoreOp)),
870 #[error("Stencil attachment with `TRANSIENT_ATTACHMENT` usage cannot be read-only")]
871 ReadOnlyTransientStencilAttachment,
872 #[error("LoadOp must be None for read-only attachments")]
873 ReadOnlyWithLoad,
874 #[error("StoreOp must be None for read-only attachments")]
875 ReadOnlyWithStore,
876 #[error("Depth `LoadOp` and `StoreOp` (`{ops:?}`) must be `None` for attachments (`{format:?}`) without depth aspect")]
877 DepthOpsWithoutAspect {
878 format: wgt::TextureFormat,
879 ops: (Option<LoadOp<Option<f32>>>, Option<StoreOp>),
880 },
881 #[error("Stencil `LoadOp` and `StoreOp` (`{ops:?}`) must be `None` for attachments (`{format:?}`) without stencil aspect")]
882 StencilOpsWithoutAspect {
883 format: wgt::TextureFormat,
884 ops: (Option<LoadOp<Option<u32>>>, Option<StoreOp>),
885 },
886 #[error("Attachment without load")]
887 NoLoad,
888 #[error("Attachment without store")]
889 NoStore,
890 #[error("LoadOp is `Clear` but no clear value was provided")]
891 NoClearValue,
892 #[error("Clear value ({0}) must be between 0.0 and 1.0, inclusive")]
893 ClearValueOutOfRange(f32),
894 #[error("Load op is `DontCare` but `InstanceFlags::STRICT_WEBGPU_COMPLIANCE` is set")]
895 LoadOpDontCareUnderStrictWebgpuCompliance,
896}
897
898impl WebGpuError for AttachmentError {
899 fn webgpu_error_type(&self) -> ErrorType {
900 ErrorType::Validation
901 }
902}
903
904#[derive(Clone, Debug, Error)]
906pub enum RenderPassErrorInner {
907 #[error(transparent)]
908 Device(#[from] DeviceError),
909 #[error(transparent)]
910 ColorAttachment(#[from] ColorAttachmentError),
911 #[error(transparent)]
912 InvalidAttachment(#[from] AttachmentError),
913 #[error(transparent)]
914 EncoderState(#[from] EncoderStateError),
915 #[error("Parent encoder is invalid")]
916 InvalidParentEncoder,
917 #[error(transparent)]
918 DebugGroupError(#[from] DebugGroupError),
919 #[error("The format of the {location} ({format:?}) is not resolvable")]
920 UnsupportedResolveTargetFormat {
921 location: AttachmentErrorLocation,
922 format: wgt::TextureFormat,
923 },
924 #[error("The {location} is not valid, because the texture has `TRANSIENT_ATTACHMENT` usage")]
925 InvalidTransientResolveTarget { location: AttachmentErrorLocation },
926 #[error("No color attachments or depth attachments were provided, at least one attachment of any kind must be provided")]
927 MissingAttachments,
928 #[error("The {location} is not renderable:")]
929 TextureViewIsNotRenderable {
930 location: AttachmentErrorLocation,
931 #[source]
932 reason: TextureViewNotRenderableReason,
933 },
934 #[error("Attachments have differing sizes: the {expected_location} has extent {expected_extent:?} but is followed by the {actual_location} which has {actual_extent:?}")]
935 AttachmentsDimensionMismatch {
936 expected_location: AttachmentErrorLocation,
937 expected_extent: wgt::Extent3d,
938 actual_location: AttachmentErrorLocation,
939 actual_extent: wgt::Extent3d,
940 },
941 #[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:?}")]
942 AttachmentSampleCountMismatch {
943 expected_location: AttachmentErrorLocation,
944 expected_samples: u32,
945 actual_location: AttachmentErrorLocation,
946 actual_samples: u32,
947 },
948 #[error("The resolve source, {location}, must be multi-sampled (has {src} samples) while the resolve destination must not be multisampled (has {dst} samples)")]
949 InvalidResolveSampleCounts {
950 location: AttachmentErrorLocation,
951 src: u32,
952 dst: u32,
953 },
954 #[error(
955 "Resource source, {location}, format ({src:?}) must match the resolve destination format ({dst:?})"
956 )]
957 MismatchedResolveTextureFormat {
958 location: AttachmentErrorLocation,
959 src: wgt::TextureFormat,
960 dst: wgt::TextureFormat,
961 },
962 #[error("Unable to clear non-present/read-only depth")]
963 InvalidDepthOps,
964 #[error("Unable to clear non-present/read-only stencil")]
965 InvalidStencilOps,
966 #[error(transparent)]
967 MissingFeatures(#[from] MissingFeatures),
968 #[error(transparent)]
969 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
970 #[error("Indirect draw count of {count_bytes} bytes starting at {begin_count_offset} would overrun buffer of size {count_buffer_size}")]
971 IndirectCountBufferOverrun {
972 count_bytes: u64,
973 begin_count_offset: u64,
974 count_buffer_size: u64,
975 },
976 #[error(transparent)]
977 ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
978 #[error("Render bundle has incompatible targets, {0}")]
979 IncompatibleBundleTargets(#[from] RenderPassCompatibilityError),
980 #[error(
981 "Render bundle has incompatible read-only flags: \
982 bundle has flags depth = {bundle_depth} and stencil = {bundle_stencil}, \
983 while the pass has flags depth = {pass_depth} and stencil = {pass_stencil}. \
984 Read-only renderpasses are only compatible with read-only bundles for that aspect."
985 )]
986 IncompatibleBundleReadOnlyDepthStencil {
987 pass_depth: bool,
988 pass_stencil: bool,
989 bundle_depth: bool,
990 bundle_stencil: bool,
991 },
992 #[error(transparent)]
993 RenderCommand(#[from] RenderCommandError),
994 #[error(transparent)]
995 Draw(#[from] DrawError),
996 #[error(transparent)]
997 Bind(#[from] BindError),
998 #[error(transparent)]
999 QueryUse(#[from] QueryUseError),
1000 #[error("Multiview layer count must match")]
1001 MultiViewMismatch,
1002 #[error(
1003 "Multiview pass texture views with more than one array layer must have D2Array dimension"
1004 )]
1005 MultiViewDimensionMismatch,
1006 #[error("Multiview view count limit violated")]
1007 TooManyMultiviewViews,
1008 #[error("missing occlusion query set")]
1009 MissingOcclusionQuerySet,
1010 #[error(transparent)]
1011 DestroyedResource(#[from] DestroyedResourceError),
1012 #[error("The compute pass has already been ended and no further commands can be recorded")]
1013 PassEnded,
1014 #[error(transparent)]
1015 InvalidResource(#[from] InvalidResourceError),
1016 #[error(transparent)]
1017 TimestampWrites(#[from] TimestampWritesError),
1018}
1019
1020impl From<InvalidOrDestroyedResourceError> for RenderPassErrorInner {
1021 fn from(error: InvalidOrDestroyedResourceError) -> Self {
1022 match error {
1023 InvalidOrDestroyedResourceError::InvalidResource(e) => Self::InvalidResource(e),
1024 InvalidOrDestroyedResourceError::DestroyedResource(e) => Self::DestroyedResource(e),
1025 }
1026 }
1027}
1028
1029impl From<MissingBufferUsageError> for RenderPassErrorInner {
1030 fn from(error: MissingBufferUsageError) -> Self {
1031 Self::RenderCommand(error.into())
1032 }
1033}
1034
1035impl From<MissingTextureUsageError> for RenderPassErrorInner {
1036 fn from(error: MissingTextureUsageError) -> Self {
1037 Self::RenderCommand(error.into())
1038 }
1039}
1040
1041impl From<pass::BindGroupIndexOutOfRange> for RenderPassErrorInner {
1042 fn from(error: pass::BindGroupIndexOutOfRange) -> Self {
1043 Self::RenderCommand(RenderCommandError::BindGroupIndexOutOfRange(error))
1044 }
1045}
1046
1047impl From<pass::MissingPipeline> for RenderPassErrorInner {
1048 fn from(error: pass::MissingPipeline) -> Self {
1049 Self::Draw(DrawError::MissingPipeline(error))
1050 }
1051}
1052
1053impl From<ImmediateUploadError> for RenderPassErrorInner {
1054 fn from(error: ImmediateUploadError) -> Self {
1055 Self::RenderCommand(error.into())
1056 }
1057}
1058
1059#[derive(Clone, Debug, Error)]
1061#[error("{scope}")]
1062pub struct RenderPassError {
1063 pub scope: PassErrorScope,
1064 #[source]
1065 pub(super) inner: Box<RenderPassErrorInner>,
1066}
1067
1068impl<E: Into<RenderPassErrorInner>> MapPassErr<RenderPassError> for E {
1069 fn map_pass_err(self, scope: PassErrorScope) -> RenderPassError {
1070 RenderPassError {
1071 scope,
1072 inner: Box::new(self.into()),
1073 }
1074 }
1075}
1076
1077impl WebGpuError for RenderPassError {
1078 fn webgpu_error_type(&self) -> ErrorType {
1079 match self.inner.as_ref() {
1080 RenderPassErrorInner::Device(e) => e.webgpu_error_type(),
1081 RenderPassErrorInner::ColorAttachment(e) => e.webgpu_error_type(),
1082 RenderPassErrorInner::EncoderState(e) => e.webgpu_error_type(),
1083 RenderPassErrorInner::DebugGroupError(e) => e.webgpu_error_type(),
1084 RenderPassErrorInner::MissingFeatures(e) => e.webgpu_error_type(),
1085 RenderPassErrorInner::MissingDownlevelFlags(e) => e.webgpu_error_type(),
1086 RenderPassErrorInner::RenderCommand(e) => e.webgpu_error_type(),
1087 RenderPassErrorInner::Draw(e) => e.webgpu_error_type(),
1088 RenderPassErrorInner::Bind(e) => e.webgpu_error_type(),
1089 RenderPassErrorInner::QueryUse(e) => e.webgpu_error_type(),
1090 RenderPassErrorInner::DestroyedResource(e) => e.webgpu_error_type(),
1091 RenderPassErrorInner::InvalidResource(e) => e.webgpu_error_type(),
1092 RenderPassErrorInner::IncompatibleBundleTargets(e) => e.webgpu_error_type(),
1093 RenderPassErrorInner::InvalidAttachment(e) => e.webgpu_error_type(),
1094 RenderPassErrorInner::TimestampWrites(e) => e.webgpu_error_type(),
1095
1096 RenderPassErrorInner::InvalidParentEncoder
1097 | RenderPassErrorInner::UnsupportedResolveTargetFormat { .. }
1098 | RenderPassErrorInner::InvalidTransientResolveTarget { .. }
1099 | RenderPassErrorInner::MissingAttachments
1100 | RenderPassErrorInner::TextureViewIsNotRenderable { .. }
1101 | RenderPassErrorInner::AttachmentsDimensionMismatch { .. }
1102 | RenderPassErrorInner::AttachmentSampleCountMismatch { .. }
1103 | RenderPassErrorInner::InvalidResolveSampleCounts { .. }
1104 | RenderPassErrorInner::MismatchedResolveTextureFormat { .. }
1105 | RenderPassErrorInner::InvalidDepthOps
1106 | RenderPassErrorInner::InvalidStencilOps
1107 | RenderPassErrorInner::IndirectCountBufferOverrun { .. }
1108 | RenderPassErrorInner::ResourceUsageCompatibility(..)
1109 | RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil { .. }
1110 | RenderPassErrorInner::MultiViewMismatch
1111 | RenderPassErrorInner::MultiViewDimensionMismatch
1112 | RenderPassErrorInner::TooManyMultiviewViews
1113 | RenderPassErrorInner::MissingOcclusionQuerySet
1114 | RenderPassErrorInner::PassEnded => ErrorType::Validation,
1115 }
1116 }
1117}
1118
1119struct RenderAttachment {
1120 texture: Arc<Texture>,
1121 selector: TextureSelector,
1122 usage: wgt::TextureUses,
1123}
1124
1125impl TextureView {
1126 fn to_render_attachment(&self, usage: wgt::TextureUses) -> RenderAttachment {
1127 RenderAttachment {
1128 texture: self.parent.clone(),
1129 selector: self.selector.clone(),
1130 usage,
1131 }
1132 }
1133}
1134
1135const MAX_TOTAL_ATTACHMENTS: usize = hal::MAX_COLOR_ATTACHMENTS + hal::MAX_COLOR_ATTACHMENTS + 1;
1136type AttachmentDataVec<T> = ArrayVec<T, MAX_TOTAL_ATTACHMENTS>;
1137
1138struct RenderPassInfo {
1139 context: RenderPassContext,
1140 render_attachments: AttachmentDataVec<RenderAttachment>,
1142 is_depth_read_only: bool,
1143 is_stencil_read_only: bool,
1144 extent: wgt::Extent3d,
1145
1146 divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>,
1147 multiview_mask: Option<NonZeroU32>,
1148}
1149
1150impl RenderPassInfo {
1151 fn add_pass_texture_init_actions<V>(
1152 load_op: LoadOp<V>,
1153 store_op: StoreOp,
1154 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
1155 view: &TextureView,
1156 pending_discard_init_fixups: &mut SurfacesInDiscardState,
1157 ) {
1158 if matches!(load_op, LoadOp::Load) {
1159 pending_discard_init_fixups.extend(texture_memory_actions.register_init_action(
1160 &TextureInitTrackerAction {
1161 texture: view.parent.clone(),
1162 range: TextureInitRange::from(view.selector.clone()),
1163 kind: MemoryInitKind::NeedsInitializedMemory,
1165 },
1166 ));
1167 } else if store_op == StoreOp::Store {
1168 texture_memory_actions.register_implicit_init(
1170 &view.parent,
1171 TextureInitRange::from(view.selector.clone()),
1172 );
1173 }
1174 if store_op == StoreOp::Discard {
1175 texture_memory_actions.discard(TextureSurfaceDiscard {
1179 texture: view.parent.clone(),
1180 mip_level: view.selector.mips.start,
1181 layer: view.selector.layers.start,
1182 });
1183 }
1184 }
1185
1186 fn start(
1187 device: &Arc<Device>,
1188 hal_label: Option<&str>,
1189 color_attachments: &[Option<RenderPassColorAttachment>],
1190 mut depth_stencil_attachment: Option<
1191 ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
1192 >,
1193 mut timestamp_writes: Option<PassTimestampWrites>,
1194 mut occlusion_query_set: Option<Arc<QuerySet>>,
1195 encoder: &mut dyn hal::DynCommandEncoder,
1196 trackers: &mut Tracker,
1197 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
1198 pending_query_resets: &mut QueryResetMap,
1199 pending_discard_init_fixups: &mut SurfacesInDiscardState,
1200 snatch_guard: &SnatchGuard<'_>,
1201 query_set_writes: &mut QuerySetWrites,
1202 multiview_mask: Option<NonZeroU32>,
1203 ) -> Result<Self, RenderPassErrorInner> {
1204 profiling::scope!("RenderPassInfo::start");
1205
1206 let mut is_depth_read_only = false;
1210 let mut is_stencil_read_only = false;
1211
1212 let mut render_attachments = AttachmentDataVec::<RenderAttachment>::new();
1213 let mut discarded_surfaces = AttachmentDataVec::new();
1214 let mut divergent_discarded_depth_stencil_aspect = None;
1215
1216 let mut attachment_location = AttachmentErrorLocation::Color {
1217 index: usize::MAX,
1218 resolve: false,
1219 };
1220 let mut extent = None;
1221 let mut sample_count = 0;
1222
1223 let mut detected_multiview: Option<Option<NonZeroU32>> = None;
1224
1225 let mut check_multiview = |view: &TextureView| {
1226 let layers = view.selector.layers.end - view.selector.layers.start;
1228 let this_multiview = if layers >= 2 {
1229 Some(unsafe { NonZeroU32::new_unchecked(layers) })
1231 } else {
1232 None
1233 };
1234
1235 if this_multiview.is_some() && view.desc.dimension != TextureViewDimension::D2Array {
1237 return Err(RenderPassErrorInner::MultiViewDimensionMismatch);
1238 }
1239
1240 if let Some(multiview) = detected_multiview {
1242 if multiview != this_multiview {
1243 return Err(RenderPassErrorInner::MultiViewMismatch);
1244 }
1245 } else {
1246 if let Some(this_multiview) = this_multiview {
1248 device.require_features(wgt::Features::MULTIVIEW)?;
1249 if this_multiview.get() > device.limits.max_multiview_view_count {
1250 return Err(RenderPassErrorInner::TooManyMultiviewViews);
1251 }
1252 }
1253
1254 detected_multiview = Some(this_multiview);
1255 }
1256
1257 Ok(())
1258 };
1259 let mut add_view = |view: &TextureView, location| {
1260 let render_extent = view.state()?.render_extent.map_err(|reason| {
1261 RenderPassErrorInner::TextureViewIsNotRenderable { location, reason }
1262 })?;
1263 if let Some(ex) = extent {
1264 if ex != render_extent {
1265 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1266 expected_location: attachment_location,
1267 expected_extent: ex,
1268 actual_location: location,
1269 actual_extent: render_extent,
1270 });
1271 }
1272 } else {
1273 extent = Some(render_extent);
1274 }
1275 if sample_count == 0 {
1276 sample_count = view.samples;
1277 } else if sample_count != view.samples {
1278 return Err(RenderPassErrorInner::AttachmentSampleCountMismatch {
1279 expected_location: attachment_location,
1280 expected_samples: sample_count,
1281 actual_location: location,
1282 actual_samples: view.samples,
1283 });
1284 }
1285 attachment_location = location;
1286 Ok(())
1287 };
1288
1289 let mut depth_stencil = None;
1290
1291 if let Some(at) = depth_stencil_attachment.as_ref() {
1292 let view = &at.view;
1293 check_multiview(view)?;
1294 add_view(view, AttachmentErrorLocation::Depth)?;
1295
1296 let ds_aspects = view.desc.aspects();
1297
1298 if !ds_aspects.contains(hal::FormatAspects::STENCIL)
1299 || (at.stencil.load_op().eq_variant(at.depth.load_op())
1300 && at.stencil.store_op() == at.depth.store_op())
1301 {
1302 Self::add_pass_texture_init_actions(
1303 at.depth.load_op(),
1304 at.depth.store_op(),
1305 texture_memory_actions,
1306 view,
1307 pending_discard_init_fixups,
1308 );
1309 } else if !ds_aspects.contains(hal::FormatAspects::DEPTH) {
1310 Self::add_pass_texture_init_actions(
1311 at.stencil.load_op(),
1312 at.stencil.store_op(),
1313 texture_memory_actions,
1314 view,
1315 pending_discard_init_fixups,
1316 );
1317 } else {
1318 let need_init_beforehand =
1340 at.depth.load_op() == LoadOp::Load || at.stencil.load_op() == LoadOp::Load;
1341 if need_init_beforehand {
1342 pending_discard_init_fixups.extend(
1343 texture_memory_actions.register_init_action(&TextureInitTrackerAction {
1344 texture: view.parent.clone(),
1345 range: TextureInitRange::from(view.selector.clone()),
1346 kind: MemoryInitKind::NeedsInitializedMemory,
1347 }),
1348 );
1349 }
1350
1351 if at.depth.store_op() != at.stencil.store_op() {
1360 if !need_init_beforehand {
1361 texture_memory_actions.register_implicit_init(
1362 &view.parent,
1363 TextureInitRange::from(view.selector.clone()),
1364 );
1365 }
1366 divergent_discarded_depth_stencil_aspect = Some((
1367 if at.depth.store_op() == StoreOp::Discard {
1368 wgt::TextureAspect::DepthOnly
1369 } else {
1370 wgt::TextureAspect::StencilOnly
1371 },
1372 view.clone(),
1373 ));
1374 } else if at.depth.store_op() == StoreOp::Discard {
1375 discarded_surfaces.push(TextureSurfaceDiscard {
1377 texture: view.parent.clone(),
1378 mip_level: view.selector.mips.start,
1379 layer: view.selector.layers.start,
1380 });
1381 }
1382 }
1383
1384 is_depth_read_only = at.depth.is_readonly();
1385 is_stencil_read_only = at.stencil.is_readonly();
1386
1387 let usage = if is_depth_read_only
1388 && is_stencil_read_only
1389 && device
1390 .downlevel
1391 .flags
1392 .contains(wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
1393 {
1394 if view.desc.usage.contains(TextureUsages::TEXTURE_BINDING) {
1399 wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::RESOURCE
1400 } else {
1401 wgt::TextureUses::DEPTH_STENCIL_READ
1402 }
1403 } else {
1404 wgt::TextureUses::DEPTH_STENCIL_WRITE
1405 };
1406 render_attachments.push(view.to_render_attachment(usage));
1407
1408 depth_stencil = Some(hal::DepthStencilAttachment {
1409 target: hal::Attachment {
1410 view: view.try_raw(snatch_guard)?,
1411 usage,
1412 },
1413 depth_ops: at.depth.hal_ops(),
1414 stencil_ops: at.stencil.hal_ops(),
1415 clear_value: (at.depth.clear_value(), at.stencil.clear_value()),
1416 });
1417 }
1418
1419 let mut attachment_set = crate::FastHashSet::default();
1420
1421 let mut color_attachments_hal =
1422 ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
1423 for (index, attachment) in color_attachments.iter().enumerate() {
1424 let at = if let Some(attachment) = attachment.as_ref() {
1425 attachment
1426 } else {
1427 color_attachments_hal.push(None);
1428 continue;
1429 };
1430 let color_view: &TextureView = &at.view;
1431 color_view.same_device(device)?;
1432 check_multiview(color_view)?;
1433 add_view(
1434 color_view,
1435 AttachmentErrorLocation::Color {
1436 index,
1437 resolve: false,
1438 },
1439 )?;
1440
1441 if !color_view.desc.aspects().intersects(
1442 hal::FormatAspects::COLOR
1443 | hal::FormatAspects::PLANE_0
1444 | hal::FormatAspects::PLANE_1
1445 | hal::FormatAspects::PLANE_2,
1446 ) {
1447 return Err(RenderPassErrorInner::ColorAttachment(
1448 ColorAttachmentError::InvalidFormat(color_view.desc.format),
1449 ));
1450 }
1451
1452 if color_view.desc.dimension == TextureViewDimension::D3 {
1453 if let Some(depth_slice) = at.depth_slice {
1454 let mip = color_view.desc.range.base_mip_level;
1455 let mip_size = color_view
1456 .parent
1457 .desc
1458 .size
1459 .mip_level_size(mip, color_view.parent.desc.dimension);
1460 let limit = mip_size.depth_or_array_layers;
1461 if depth_slice >= limit {
1462 return Err(RenderPassErrorInner::ColorAttachment(
1463 ColorAttachmentError::DepthSliceLimit {
1464 given: depth_slice,
1465 limit,
1466 },
1467 ));
1468 }
1469 } else {
1470 return Err(RenderPassErrorInner::ColorAttachment(
1471 ColorAttachmentError::MissingDepthSlice,
1472 ));
1473 }
1474 } else if at.depth_slice.is_some() {
1475 return Err(RenderPassErrorInner::ColorAttachment(
1476 ColorAttachmentError::UnneededDepthSlice,
1477 ));
1478 }
1479
1480 validation::validate_color_attachment_bytes_per_sample(
1481 color_attachments
1482 .iter()
1483 .flatten()
1484 .map(|at| at.view.desc.format),
1485 device.limits.max_color_attachment_bytes_per_sample,
1486 )
1487 .map_err(RenderPassErrorInner::ColorAttachment)?;
1488
1489 fn check_attachment_overlap(
1490 attachment_set: &mut crate::FastHashSet<(crate::track::TrackerIndex, u32, u32)>,
1491 view: &TextureView,
1492 depth_slice: Option<u32>,
1493 ) -> Result<(), ColorAttachmentError> {
1494 let mut insert = |slice| {
1495 let mip_level = view.desc.range.base_mip_level;
1496 if attachment_set.insert((
1497 view.parent.tracking_data.tracker_index(),
1498 mip_level,
1499 slice,
1500 )) {
1501 Ok(())
1502 } else {
1503 Err(ColorAttachmentError::SubresourceOverlap {
1504 view: view.error_ident(),
1505 mip_level,
1506 depth_or_array_layer: slice,
1507 })
1508 }
1509 };
1510 match view.desc.dimension {
1511 TextureViewDimension::D2 => {
1512 insert(view.desc.range.base_array_layer)?;
1513 }
1514 TextureViewDimension::D2Array => {
1515 for layer in view.selector.layers.clone() {
1516 insert(layer)?;
1517 }
1518 }
1519 TextureViewDimension::D3 => {
1520 insert(depth_slice.unwrap())?;
1521 }
1522 _ => unreachable!(),
1523 };
1524 Ok(())
1525 }
1526
1527 check_attachment_overlap(&mut attachment_set, color_view, at.depth_slice)?;
1528
1529 Self::add_pass_texture_init_actions(
1530 at.load_op,
1531 at.store_op,
1532 texture_memory_actions,
1533 color_view,
1534 pending_discard_init_fixups,
1535 );
1536 render_attachments
1537 .push(color_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1538
1539 let mut hal_resolve_target = None;
1540 if let Some(resolve_view) = &at.resolve_target {
1541 resolve_view.same_device(device)?;
1542 check_multiview(resolve_view)?;
1543
1544 check_attachment_overlap(&mut attachment_set, resolve_view, None)?;
1545
1546 let resolve_location = AttachmentErrorLocation::Color {
1547 index,
1548 resolve: true,
1549 };
1550
1551 let render_extent = resolve_view.state()?.render_extent.map_err(|reason| {
1552 RenderPassErrorInner::TextureViewIsNotRenderable {
1553 location: resolve_location,
1554 reason,
1555 }
1556 })?;
1557 if color_view.state()?.render_extent.unwrap() != render_extent {
1558 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1559 expected_location: attachment_location,
1560 expected_extent: extent.unwrap_or_default(),
1561 actual_location: resolve_location,
1562 actual_extent: render_extent,
1563 });
1564 }
1565 if color_view.samples == 1 || resolve_view.samples != 1 {
1566 return Err(RenderPassErrorInner::InvalidResolveSampleCounts {
1567 location: resolve_location,
1568 src: color_view.samples,
1569 dst: resolve_view.samples,
1570 });
1571 }
1572 if color_view.desc.format != resolve_view.desc.format {
1573 return Err(RenderPassErrorInner::MismatchedResolveTextureFormat {
1574 location: resolve_location,
1575 src: color_view.desc.format,
1576 dst: resolve_view.desc.format,
1577 });
1578 }
1579 if !resolve_view
1580 .format_features
1581 .flags
1582 .contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE)
1583 {
1584 return Err(RenderPassErrorInner::UnsupportedResolveTargetFormat {
1585 location: resolve_location,
1586 format: resolve_view.desc.format,
1587 });
1588 }
1589 if resolve_view
1590 .desc
1591 .usage
1592 .contains(TextureUsages::TRANSIENT_ATTACHMENT)
1593 {
1594 return Err(RenderPassErrorInner::InvalidTransientResolveTarget {
1595 location: resolve_location,
1596 });
1597 }
1598
1599 texture_memory_actions.register_implicit_init(
1600 &resolve_view.parent,
1601 TextureInitRange::from(resolve_view.selector.clone()),
1602 );
1603 render_attachments
1604 .push(resolve_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1605
1606 hal_resolve_target = Some(hal::Attachment {
1607 view: resolve_view.try_raw(snatch_guard)?,
1608 usage: wgt::TextureUses::COLOR_TARGET,
1609 });
1610 }
1611
1612 color_attachments_hal.push(Some(hal::ColorAttachment {
1613 target: hal::Attachment {
1614 view: color_view.try_raw(snatch_guard)?,
1615 usage: wgt::TextureUses::COLOR_TARGET,
1616 },
1617 depth_slice: at.depth_slice,
1618 resolve_target: hal_resolve_target,
1619 ops: at.hal_ops(),
1620 clear_value: at.clear_value(),
1621 }));
1622 }
1623
1624 let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
1625
1626 let detected_multiview =
1627 detected_multiview.expect("Multiview was not detected, no attachments");
1628 if let Some(mask) = multiview_mask {
1629 let mask_msb = 31 - mask.leading_zeros();
1631 let detected_mv = detected_multiview.map(NonZeroU32::get).unwrap_or(1);
1632 if mask_msb >= detected_mv {
1633 return Err(RenderPassErrorInner::MultiViewMismatch);
1634 }
1635 if mask.get() != (1 << detected_mv) - 1 {
1636 device.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
1637 }
1638 }
1639
1640 let attachment_formats = AttachmentData {
1641 colors: color_attachments
1642 .iter()
1643 .map(|at| at.as_ref().map(|at| at.view.desc.format))
1644 .collect(),
1645 resolves: color_attachments
1646 .iter()
1647 .filter_map(|at| {
1648 at.as_ref().and_then(|at| {
1649 at.resolve_target
1650 .as_ref()
1651 .map(|resolve| resolve.desc.format)
1652 })
1653 })
1654 .collect(),
1655 depth_stencil: depth_stencil_attachment
1656 .as_ref()
1657 .map(|at| at.view.desc.format),
1658 };
1659
1660 let context = RenderPassContext {
1661 attachments: attachment_formats,
1662 sample_count,
1663 multiview_mask,
1664 };
1665
1666 let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() {
1667 let query_set = &tw.query_set;
1668 query_set.same_device(device)?;
1669
1670 if let Some(index) = tw.beginning_of_pass_write_index {
1671 pending_query_resets.use_query_set(query_set, index);
1672 }
1673 if let Some(index) = tw.end_of_pass_write_index {
1674 pending_query_resets.use_query_set(query_set, index);
1675 }
1676
1677 record_pass_timestamp_writes(tw, query_set_writes);
1678
1679 Some(hal::PassTimestampWrites {
1680 query_set: query_set.try_raw(snatch_guard)?,
1681 beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
1682 end_of_pass_write_index: tw.end_of_pass_write_index,
1683 })
1684 } else {
1685 None
1686 };
1687
1688 let occlusion_query_set_hal = if let Some(query_set) = occlusion_query_set.as_ref() {
1689 query_set.same_device(device)?;
1690 Some(query_set.try_raw(snatch_guard)?)
1691 } else {
1692 None
1693 };
1694
1695 let hal_desc = hal::RenderPassDescriptor {
1696 label: hal_label,
1697 extent,
1698 sample_count,
1699 color_attachments: &color_attachments_hal,
1700 depth_stencil_attachment: depth_stencil,
1701 multiview_mask,
1702 timestamp_writes: timestamp_writes_hal,
1703 occlusion_query_set: occlusion_query_set_hal,
1704 };
1705 unsafe {
1706 encoder
1707 .begin_render_pass(&hal_desc)
1708 .map_err(|e| device.handle_hal_error(e))?;
1709 };
1710 drop(color_attachments_hal); if let Some(tw) = timestamp_writes.take() {
1714 trackers.query_sets.insert_single(tw.query_set);
1715 };
1716 if let Some(occlusion_query_set) = occlusion_query_set.take() {
1717 trackers.query_sets.insert_single(occlusion_query_set);
1718 };
1719 if let Some(at) = depth_stencil_attachment.take() {
1720 trackers.views.insert_single(at.view.clone());
1721 }
1722 for at in color_attachments.iter().flatten() {
1723 trackers.views.insert_single(at.view.clone());
1724 if let Some(resolve_target) = at.resolve_target.clone() {
1725 trackers.views.insert_single(resolve_target);
1726 }
1727 }
1728
1729 Ok(Self {
1730 context,
1731 render_attachments,
1732 is_depth_read_only,
1733 is_stencil_read_only,
1734 extent,
1735 divergent_discarded_depth_stencil_aspect,
1736 multiview_mask,
1737 })
1738 }
1739
1740 fn finish(
1741 self,
1742 device: &Device,
1743 raw: &mut dyn hal::DynCommandEncoder,
1744 snatch_guard: &SnatchGuard,
1745 scope: &mut UsageScope<'_>,
1746 instance_flags: InstanceFlags,
1747 ) -> Result<(), RenderPassErrorInner> {
1748 profiling::scope!("RenderPassInfo::finish");
1749 unsafe {
1750 raw.end_render_pass();
1751 }
1752
1753 for ra in self.render_attachments {
1754 let texture = &ra.texture;
1755 texture.check_usage(TextureUsages::RENDER_ATTACHMENT)?;
1756
1757 unsafe {
1759 scope
1760 .textures
1761 .merge_single(texture, Some(ra.selector.clone()), ra.usage)?
1762 };
1763 }
1764
1765 if let Some((aspect, view)) = self.divergent_discarded_depth_stencil_aspect {
1775 let (depth_ops, stencil_ops) = if aspect == wgt::TextureAspect::DepthOnly {
1776 (
1777 hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, )
1780 } else {
1781 (
1782 hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, )
1785 };
1786 let desc = hal::RenderPassDescriptor::<'_, _, dyn hal::DynTextureView> {
1787 label: hal_label(
1788 Some("(wgpu internal) Zero init discarded depth/stencil aspect"),
1789 instance_flags,
1790 ),
1791 extent: view.state()?.render_extent.unwrap(),
1792 sample_count: view.samples,
1793 color_attachments: &[],
1794 depth_stencil_attachment: Some(hal::DepthStencilAttachment {
1795 target: hal::Attachment {
1796 view: view.try_raw(snatch_guard)?,
1797 usage: wgt::TextureUses::DEPTH_STENCIL_WRITE,
1798 },
1799 depth_ops,
1800 stencil_ops,
1801 clear_value: (0.0, 0),
1802 }),
1803 multiview_mask: self.multiview_mask,
1804 timestamp_writes: None,
1805 occlusion_query_set: None,
1806 };
1807 unsafe {
1808 raw.begin_render_pass(&desc)
1809 .map_err(|e| device.handle_hal_error(e))?;
1810 raw.end_render_pass();
1811 }
1812 }
1813
1814 Ok(())
1815 }
1816}
1817
1818fn check_transient_attachment_ops<V>(load_op: LoadOp<V>, store_op: StoreOp) -> bool {
1819 matches!(
1820 (load_op, store_op),
1821 (LoadOp::Clear(_) | LoadOp::DontCare(_), StoreOp::Discard)
1822 )
1823}
1824
1825impl CommandEncoder {
1826 pub fn begin_render_pass(
1827 self: &Arc<Self>,
1828 desc: ResolvedRenderPassDescriptor<'_>,
1829 ) -> (RenderPass, Option<CommandEncoderError>) {
1830 use EncoderStateError as SErr;
1831
1832 fn fill_arc_desc(
1833 desc: ResolvedRenderPassDescriptor<'_>,
1834 arc_desc: &mut ArcRenderPassDescriptor,
1835 device: &Device,
1836 ) -> Result<(), RenderPassErrorInner> {
1837 device.check_is_valid()?;
1838
1839 let max_color_attachments = device.limits.max_color_attachments as usize;
1840 if desc.color_attachments.len() > max_color_attachments {
1841 return Err(RenderPassErrorInner::ColorAttachment(
1842 ColorAttachmentError::TooMany {
1843 given: desc.color_attachments.len(),
1844 limit: max_color_attachments,
1845 },
1846 ));
1847 }
1848
1849 for color_attachment in desc.color_attachments.iter() {
1850 if let Some(RenderPassColorAttachment {
1851 view,
1852 depth_slice,
1853 resolve_target,
1854 load_op,
1855 store_op,
1856 }) = color_attachment
1857 {
1858 view.check_valid()?;
1859 view.same_device(device)?;
1860 if matches!(*load_op, LoadOp::DontCare(..))
1861 && device
1862 .instance_flags
1863 .contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE)
1864 {
1865 return Err(RenderPassErrorInner::ColorAttachment(
1866 ColorAttachmentError::LoadOpDontCareUnderStrictWebgpuCompliance,
1867 ));
1868 }
1869
1870 if view
1871 .desc
1872 .usage
1873 .contains(TextureUsages::TRANSIENT_ATTACHMENT)
1874 && !check_transient_attachment_ops(*load_op, *store_op)
1875 {
1876 return Err(RenderPassErrorInner::ColorAttachment(
1877 ColorAttachmentError::InvalidTransientAttachmentOp((
1878 *load_op, *store_op,
1879 )),
1880 ));
1881 }
1882
1883 let resolve_target = if let Some(resolve_target) = resolve_target {
1884 resolve_target.check_valid()?;
1885 resolve_target.same_device(device)?;
1886
1887 Some(resolve_target)
1888 } else {
1889 None
1890 };
1891
1892 arc_desc
1893 .color_attachments
1894 .push(Some(RenderPassColorAttachment {
1895 view: Arc::clone(view),
1896 depth_slice: *depth_slice,
1897 resolve_target: resolve_target.map(Arc::clone),
1898 load_op: *load_op,
1899 store_op: *store_op,
1900 }));
1901 } else {
1902 arc_desc.color_attachments.push(None);
1903 }
1904 }
1905
1906 arc_desc.depth_stencil_attachment = if let Some(depth_stencil_attachment) =
1908 desc.depth_stencil_attachment
1909 {
1910 let view = depth_stencil_attachment.view;
1911 view.check_valid()?;
1912 view.same_device(device)?;
1913
1914 let format = view.desc.format;
1915 if !format.is_depth_stencil_format() {
1916 return Err(RenderPassErrorInner::InvalidAttachment(
1917 AttachmentError::InvalidDepthStencilAttachmentFormat(view.desc.format),
1918 ));
1919 }
1920
1921 if view
1922 .desc
1923 .usage
1924 .contains(TextureUsages::TRANSIENT_ATTACHMENT)
1925 {
1926 if format.has_depth_aspect() {
1931 match depth_stencil_attachment.depth {
1932 PassChannel {
1933 load_op: Some(load_op),
1934 store_op: Some(store_op),
1935 read_only: _,
1936 } => {
1937 if !check_transient_attachment_ops(load_op, store_op) {
1938 return Err(RenderPassErrorInner::InvalidAttachment(
1939 AttachmentError::InvalidTransientDepthAttachmentOps((
1940 load_op, store_op,
1941 )),
1942 ));
1943 }
1944 }
1945 PassChannel {
1946 read_only: true, ..
1947 } => {
1948 return Err(RenderPassErrorInner::InvalidAttachment(
1949 AttachmentError::ReadOnlyTransientDepthAttachment,
1950 ))
1951 }
1952 _ => {}
1953 }
1954 }
1955
1956 if format.has_stencil_aspect() {
1957 match depth_stencil_attachment.stencil {
1958 PassChannel {
1959 load_op: Some(load_op),
1960 store_op: Some(store_op),
1961 read_only: _,
1962 } => {
1963 if !check_transient_attachment_ops(load_op, store_op) {
1964 return Err(RenderPassErrorInner::InvalidAttachment(
1965 AttachmentError::InvalidTransientStencilAttachmentOps((
1966 load_op, store_op,
1967 )),
1968 ));
1969 }
1970 }
1971 PassChannel {
1972 read_only: true, ..
1973 } => {
1974 return Err(RenderPassErrorInner::InvalidAttachment(
1975 AttachmentError::ReadOnlyTransientStencilAttachment,
1976 ))
1977 }
1978 _ => {}
1979 }
1980 }
1981 }
1982
1983 Some(ResolvedRenderPassDepthStencilAttachment {
1984 view,
1985 depth: if format.has_depth_aspect() {
1986 depth_stencil_attachment
1987 .depth
1988 .resolve(device.instance_flags, |clear| {
1989 if let Some(clear) = clear {
1990 if !(0.0..=1.0).contains(&clear) {
1992 Err(AttachmentError::ClearValueOutOfRange(clear))
1993 } else {
1994 Ok(clear)
1995 }
1996 } else {
1997 Err(AttachmentError::NoClearValue)
1998 }
1999 })?
2000 } else {
2001 if depth_stencil_attachment.depth.load_op.is_some()
2002 || depth_stencil_attachment.depth.store_op.is_some()
2003 {
2004 return Err(RenderPassErrorInner::InvalidAttachment(
2005 AttachmentError::DepthOpsWithoutAspect {
2006 format,
2007 ops: (
2008 depth_stencil_attachment.depth.load_op,
2009 depth_stencil_attachment.depth.store_op,
2010 ),
2011 },
2012 ));
2013 }
2014 ResolvedPassChannel::ReadOnly
2015 },
2016 stencil: if format.has_stencil_aspect() {
2017 depth_stencil_attachment.stencil.resolve(
2018 device.instance_flags,
2019 |clear| {
2020 Ok(convert_stencil_value(
2021 clear.unwrap_or_default(),
2022 Some(format),
2023 ))
2024 },
2025 )?
2026 } else {
2027 if depth_stencil_attachment.stencil.load_op.is_some()
2028 || depth_stencil_attachment.stencil.store_op.is_some()
2029 {
2030 return Err(RenderPassErrorInner::InvalidAttachment(
2031 AttachmentError::StencilOpsWithoutAspect {
2032 format,
2033 ops: (
2034 depth_stencil_attachment.stencil.load_op,
2035 depth_stencil_attachment.stencil.store_op,
2036 ),
2037 },
2038 ));
2039 }
2040 ResolvedPassChannel::ReadOnly
2041 },
2042 })
2043 } else {
2044 None
2045 };
2046
2047 arc_desc.timestamp_writes = desc
2048 .timestamp_writes
2049 .map(|tw| {
2050 CommandEncoder::validate_pass_timestamp_writes::<RenderPassErrorInner>(
2051 device, &tw,
2052 )
2053 })
2054 .transpose()?;
2055
2056 arc_desc.occlusion_query_set =
2057 if let Some(occlusion_query_set) = desc.occlusion_query_set {
2058 occlusion_query_set.check_is_valid()?;
2059 occlusion_query_set.same_device(device)?;
2060
2061 if !matches!(occlusion_query_set.desc.ty, wgt::QueryType::Occlusion) {
2062 return Err(QueryUseError::IncompatibleType {
2063 set_type: occlusion_query_set.desc.ty.into(),
2064 query_type: super::SimplifiedQueryType::Occlusion,
2065 }
2066 .into());
2067 }
2068
2069 Some(occlusion_query_set)
2070 } else {
2071 None
2072 };
2073
2074 arc_desc.multiview_mask = desc.multiview_mask;
2075
2076 Ok(())
2077 }
2078
2079 let scope = PassErrorScope::Pass;
2080 let mut cmd_buf_data = self.data.lock();
2081
2082 match cmd_buf_data.lock_encoder() {
2083 Ok(()) => {
2084 drop(cmd_buf_data);
2085 let label = desc.label.clone();
2086 let mut arc_desc = ArcRenderPassDescriptor {
2087 label: &label,
2088 timestamp_writes: None,
2089 color_attachments: ArrayVec::new(),
2090 depth_stencil_attachment: None,
2091 occlusion_query_set: None,
2092 multiview_mask: None,
2093 };
2094 match fill_arc_desc(desc, &mut arc_desc, &self.device) {
2095 Ok(()) => (RenderPass::new(self.clone(), arc_desc), None),
2096 Err(err) => (
2097 RenderPass::new_invalid(self.clone(), &label, err.map_pass_err(scope)),
2098 None,
2099 ),
2100 }
2101 }
2102 Err(err @ SErr::Locked) => {
2103 cmd_buf_data.invalidate(err.clone());
2107 drop(cmd_buf_data);
2108 (
2109 RenderPass::new_invalid(self.clone(), &desc.label, err.map_pass_err(scope)),
2110 None,
2111 )
2112 }
2113 Err(err @ (SErr::Ended | SErr::Submitted)) => {
2114 drop(cmd_buf_data);
2117 (
2118 RenderPass::new_invalid(
2119 self.clone(),
2120 &desc.label,
2121 err.clone().map_pass_err(scope),
2122 ),
2123 Some(err.into()),
2124 )
2125 }
2126 Err(err @ SErr::Invalid) => {
2127 drop(cmd_buf_data);
2133 (
2134 RenderPass::new_invalid(self.clone(), &desc.label, err.map_pass_err(scope)),
2135 None,
2136 )
2137 }
2138 Err(SErr::Unlocked) => {
2139 unreachable!("lock_encoder cannot fail due to the encoder being unlocked")
2140 }
2141 }
2142 }
2143}
2144
2145impl RenderPass {
2146 pub fn end(&mut self) -> Result<(), EncoderStateError> {
2147 profiling::scope!(
2148 "CommandEncoder::run_render_pass {}",
2149 self.base.label.as_deref().unwrap_or("")
2150 );
2151
2152 let cmd_enc = self.parent.take().ok_or(EncoderStateError::Ended)?;
2153 let mut cmd_buf_data = cmd_enc.data.lock();
2154
2155 cmd_buf_data.unlock_encoder()?;
2156
2157 let base = self.base.take();
2158
2159 if let Err(RenderPassError { inner, scope: _ }) = &base {
2160 if let RenderPassErrorInner::EncoderState(
2161 err @ (EncoderStateError::Locked | EncoderStateError::Ended),
2162 ) = inner.as_ref()
2163 {
2164 return Err(err.clone());
2171 }
2172 }
2173
2174 cmd_buf_data.push_with(|| -> Result<_, RenderPassError> {
2175 Ok(ArcCommand::RunRenderPass {
2176 pass: base?,
2177 color_attachments: SmallVec::from(self.color_attachments.as_slice()),
2178 depth_stencil_attachment: self.depth_stencil_attachment.take(),
2179 timestamp_writes: self.timestamp_writes.take(),
2180 occlusion_query_set: self.occlusion_query_set.take(),
2181 multiview_mask: self.multiview_mask,
2182 })
2183 })
2184 }
2185}
2186
2187impl Global {
2188 pub fn command_encoder_begin_render_pass(
2199 &self,
2200 encoder_id: id::CommandEncoderId,
2201 desc: &RenderPassDescriptor<'_>,
2202 ) -> (RenderPass, Option<CommandEncoderError>) {
2203 let hub = &self.hub;
2204
2205 let cmd_enc = hub.command_encoders.get(encoder_id);
2206
2207 let texture_views = hub.texture_views.read();
2208 let query_sets = hub.query_sets.read();
2209
2210 let desc = ResolvedRenderPassDescriptor {
2211 label: desc.label.as_deref().map(Cow::Borrowed),
2212 color_attachments: Cow::Owned(
2213 desc.color_attachments
2214 .iter()
2215 .map(|at| {
2216 at.as_ref().map(|at| RenderPassColorAttachment {
2217 view: texture_views.get(at.view),
2218 depth_slice: at.depth_slice,
2219 resolve_target: at
2220 .resolve_target
2221 .as_ref()
2222 .map(|rt| texture_views.get(*rt)),
2223 load_op: at.load_op,
2224 store_op: at.store_op,
2225 })
2226 })
2227 .collect(),
2228 ),
2229 depth_stencil_attachment: desc.depth_stencil_attachment.as_ref().map(|at| {
2230 RenderPassDepthStencilAttachment {
2231 view: texture_views.get(at.view),
2232 depth: at.depth.clone(),
2233 stencil: at.stencil.clone(),
2234 }
2235 }),
2236 timestamp_writes: desc
2237 .timestamp_writes
2238 .as_ref()
2239 .map(|tw| PassTimestampWrites {
2240 query_set: query_sets.get(tw.query_set),
2241 beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
2242 end_of_pass_write_index: tw.end_of_pass_write_index,
2243 }),
2244 occlusion_query_set: desc
2245 .occlusion_query_set
2246 .as_ref()
2247 .map(|query_set| query_sets.get(*query_set)),
2248 multiview_mask: desc.multiview_mask,
2249 };
2250
2251 drop(texture_views);
2252 drop(query_sets);
2253
2254 cmd_enc.begin_render_pass(desc)
2255 }
2256
2257 pub fn command_encoder_begin_render_pass_with_id(
2258 &self,
2259 encoder_id: id::CommandEncoderId,
2260 desc: &RenderPassDescriptor<'_>,
2261 id_in: Option<id::RenderPassEncoderId>,
2262 ) -> (id::RenderPassEncoderId, Option<CommandEncoderError>) {
2263 let hub = &self.hub;
2264 let fid = hub.render_passes.prepare(id_in);
2265 let (render_pass, error) = self.command_encoder_begin_render_pass(encoder_id, desc);
2266 let id = fid.assign(Arc::new(Mutex::new(render_pass)));
2270 (id, error)
2271 }
2272
2273 pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
2274 pass.end()
2275 }
2276
2277 pub fn render_pass_end_with_id(
2278 &self,
2279 pass: id::RenderPassEncoderId,
2280 ) -> Result<(), EncoderStateError> {
2281 let pass = self.hub.render_passes.get(pass);
2282 let mut pass = pass
2283 .try_lock()
2284 .expect("RenderPasses should not be accessed concurrently");
2285 self.render_pass_end(&mut pass)
2286 }
2287
2288 pub fn render_pass_drop(&self, pass: id::RenderPassEncoderId) {
2289 self.hub.render_passes.remove(pass);
2290 }
2291}
2292
2293pub(super) fn encode_render_pass(
2294 parent_state: &mut EncodingState<InnerCommandEncoder>,
2295 mut base: BasePass<ArcRenderCommand, Infallible>,
2296 color_attachments: ColorAttachments<Arc<TextureView>>,
2297 mut depth_stencil_attachment: Option<
2298 ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
2299 >,
2300 mut timestamp_writes: Option<PassTimestampWrites>,
2301 occlusion_query_set: Option<Arc<QuerySet>>,
2302 multiview_mask: Option<NonZeroU32>,
2303) -> Result<(), RenderPassError> {
2304 let pass_scope = PassErrorScope::Pass;
2305
2306 let device = parent_state.device;
2307
2308 let mut indirect_draw_validation_batcher = crate::indirect_validation::DrawBatcher::new();
2309
2310 parent_state
2314 .raw_encoder
2315 .close_if_open()
2316 .map_pass_err(pass_scope)?;
2317 let raw_encoder = parent_state
2318 .raw_encoder
2319 .open_pass(base.label.as_deref())
2320 .map_pass_err(pass_scope)?;
2321
2322 let (scope, pending_discard_init_fixups, mut pending_query_resets) = {
2323 let mut pending_query_resets = QueryResetMap::new();
2324 let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
2325
2326 let info = RenderPassInfo::start(
2327 device,
2328 hal_label(base.label.as_deref(), device.instance_flags),
2329 &color_attachments,
2330 depth_stencil_attachment.take(),
2331 timestamp_writes.take(),
2332 occlusion_query_set.clone(),
2335 raw_encoder,
2336 parent_state.tracker,
2337 parent_state.texture_memory_actions,
2338 &mut pending_query_resets,
2339 &mut pending_discard_init_fixups,
2340 parent_state.snatch_guard,
2341 parent_state.query_set_writes,
2342 multiview_mask,
2343 )
2344 .map_pass_err(pass_scope)?;
2345
2346 let indices = &device.tracker_indices;
2347 parent_state
2348 .tracker
2349 .buffers
2350 .set_size(indices.buffers.size());
2351 parent_state
2352 .tracker
2353 .textures
2354 .set_size(indices.textures.size());
2355
2356 let mut debug_scope_depth = 0;
2357
2358 let mut state = State {
2359 pipeline_flags: PipelineFlags::empty(),
2360 blend_constant: OptionalState::Unused,
2361 stencil_reference: 0,
2362 pipeline: None,
2363 index: IndexState::default(),
2364 vertex: VertexState::default(),
2365
2366 info,
2367
2368 pass: pass::PassState {
2369 base: EncodingState {
2370 device,
2371 raw_encoder,
2372 tracker: parent_state.tracker,
2373 buffer_memory_init_actions: parent_state.buffer_memory_init_actions,
2374 texture_memory_actions: parent_state.texture_memory_actions,
2375 as_actions: parent_state.as_actions,
2376 temp_resources: parent_state.temp_resources,
2377 indirect_draw_validation_resources: parent_state
2378 .indirect_draw_validation_resources,
2379 snatch_guard: parent_state.snatch_guard,
2380 debug_scope_depth: &mut debug_scope_depth,
2381 query_set_writes: parent_state.query_set_writes,
2382 deferred_query_set_resolves: parent_state.deferred_query_set_resolves,
2383 },
2384 pending_discard_init_fixups,
2385 scope: device.new_usage_scope(),
2386 binder: Binder::new(),
2387
2388 temp_offsets: Vec::new(),
2389 dynamic_offset_count: 0,
2390
2391 string_offset: 0,
2392
2393 immediate_state: ImmediateState::default(),
2394 },
2395
2396 active_occlusion_query: None,
2397 active_pipeline_statistics_query: None,
2398 };
2399
2400 for command in base.commands.drain(..) {
2401 match command {
2402 ArcRenderCommand::SetBindGroup {
2403 index,
2404 num_dynamic_offsets,
2405 bind_group,
2406 } => {
2407 let scope = PassErrorScope::SetBindGroup;
2408 pass::set_bind_group::<RenderPassErrorInner>(
2409 &mut state.pass,
2410 device,
2411 &base.dynamic_offsets,
2412 index,
2413 num_dynamic_offsets,
2414 bind_group,
2415 true,
2416 )
2417 .map_pass_err(scope)?;
2418 }
2419 ArcRenderCommand::SetPipeline(pipeline) => {
2420 let scope = PassErrorScope::SetPipelineRender;
2421 set_pipeline(&mut state, device, pipeline).map_pass_err(scope)?;
2422 }
2423 ArcRenderCommand::SetIndexBuffer {
2424 buffer,
2425 index_format,
2426 offset,
2427 size,
2428 } => {
2429 let scope = PassErrorScope::SetIndexBuffer;
2430 set_index_buffer(&mut state, device, buffer, index_format, offset, size)
2431 .map_pass_err(scope)?;
2432 }
2433 ArcRenderCommand::SetVertexBuffer {
2434 slot,
2435 buffer,
2436 offset,
2437 size,
2438 } => {
2439 let scope = PassErrorScope::SetVertexBuffer;
2440 set_vertex_buffer(&mut state, device, slot, buffer, offset, size)
2441 .map_pass_err(scope)?;
2442 }
2443 ArcRenderCommand::SetBlendConstant(ref color) => {
2444 set_blend_constant(&mut state, color);
2445 }
2446 ArcRenderCommand::SetStencilReference(value) => {
2447 set_stencil_reference(&mut state, value);
2448 }
2449 ArcRenderCommand::SetViewport {
2450 rect,
2451 depth_min,
2452 depth_max,
2453 } => {
2454 let scope = PassErrorScope::SetViewport;
2455 set_viewport(&mut state, rect, depth_min, depth_max).map_pass_err(scope)?;
2456 }
2457 ArcRenderCommand::SetImmediate { offset, data } => {
2458 let scope = PassErrorScope::SetImmediate;
2459 state
2460 .pass
2461 .immediate_state
2462 .set_immediates::<RenderPassErrorInner>(
2463 &state.pass.base.device.limits,
2464 offset,
2465 &data,
2466 )
2467 .map_pass_err(scope)?;
2468 }
2469 ArcRenderCommand::SetScissor(rect) => {
2470 let scope = PassErrorScope::SetScissorRect;
2471 set_scissor(&mut state, rect).map_pass_err(scope)?;
2472 }
2473 ArcRenderCommand::Draw {
2474 vertex_count,
2475 instance_count,
2476 first_vertex,
2477 first_instance,
2478 } => {
2479 let scope = PassErrorScope::Draw {
2480 kind: DrawKind::Draw,
2481 family: DrawCommandFamily::Draw,
2482 };
2483 draw(
2484 &mut state,
2485 vertex_count,
2486 instance_count,
2487 first_vertex,
2488 first_instance,
2489 )
2490 .map_pass_err(scope)?;
2491 }
2492 ArcRenderCommand::DrawIndexed {
2493 index_count,
2494 instance_count,
2495 first_index,
2496 base_vertex,
2497 first_instance,
2498 } => {
2499 let scope = PassErrorScope::Draw {
2500 kind: DrawKind::Draw,
2501 family: DrawCommandFamily::DrawIndexed,
2502 };
2503 draw_indexed(
2504 &mut state,
2505 index_count,
2506 instance_count,
2507 first_index,
2508 base_vertex,
2509 first_instance,
2510 )
2511 .map_pass_err(scope)?;
2512 }
2513 ArcRenderCommand::DrawMeshTasks {
2514 group_count_x,
2515 group_count_y,
2516 group_count_z,
2517 } => {
2518 let scope = PassErrorScope::Draw {
2519 kind: DrawKind::Draw,
2520 family: DrawCommandFamily::DrawMeshTasks,
2521 };
2522 draw_mesh_tasks(&mut state, group_count_x, group_count_y, group_count_z)
2523 .map_pass_err(scope)?;
2524 }
2525 ArcRenderCommand::DrawIndirect {
2526 buffer,
2527 offset,
2528 count,
2529 family,
2530
2531 vertex_or_index_limit: _,
2532 instance_limit: _,
2533 } => {
2534 let scope = PassErrorScope::Draw {
2535 kind: if count != 1 {
2536 DrawKind::MultiDrawIndirect
2537 } else {
2538 DrawKind::DrawIndirect
2539 },
2540 family,
2541 };
2542 multi_draw_indirect(
2543 &mut state,
2544 &mut indirect_draw_validation_batcher,
2545 device,
2546 buffer,
2547 offset,
2548 count,
2549 family,
2550 )
2551 .map_pass_err(scope)?;
2552 }
2553 ArcRenderCommand::MultiDrawIndirectCount {
2554 buffer,
2555 offset,
2556 count_buffer,
2557 count_buffer_offset,
2558 max_count,
2559 family,
2560 } => {
2561 let scope = PassErrorScope::Draw {
2562 kind: DrawKind::MultiDrawIndirectCount,
2563 family,
2564 };
2565 multi_draw_indirect_count(
2566 &mut state,
2567 device,
2568 buffer,
2569 offset,
2570 count_buffer,
2571 count_buffer_offset,
2572 max_count,
2573 family,
2574 )
2575 .map_pass_err(scope)?;
2576 }
2577 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2578 pass::push_debug_group(&mut state.pass, &base.string_data, len);
2579 }
2580 ArcRenderCommand::PopDebugGroup => {
2581 let scope = PassErrorScope::PopDebugGroup;
2582 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.pass)
2583 .map_pass_err(scope)?;
2584 }
2585 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2586 pass::insert_debug_marker(&mut state.pass, &base.string_data, len);
2587 }
2588 ArcRenderCommand::WriteTimestamp {
2589 query_set,
2590 query_index,
2591 } => {
2592 let scope = PassErrorScope::WriteTimestamp;
2593 pass::write_timestamp::<RenderPassErrorInner>(
2594 &mut state.pass,
2595 device,
2596 Some(&mut pending_query_resets),
2597 query_set,
2598 query_index,
2599 )
2600 .map_pass_err(scope)?;
2601 }
2602 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2603 api_log!("RenderPass::begin_occlusion_query {query_index}");
2604 let scope = PassErrorScope::BeginOcclusionQuery;
2605
2606 let query_set = occlusion_query_set
2607 .clone()
2608 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2609 .map_pass_err(scope)?;
2610
2611 validate_and_begin_occlusion_query(
2612 query_set,
2613 state.pass.base.raw_encoder,
2614 &mut state.pass.base.tracker.query_sets,
2615 query_index,
2616 Some(&mut pending_query_resets),
2617 &mut state.active_occlusion_query,
2618 state.pass.base.snatch_guard,
2619 )
2620 .map_pass_err(scope)?;
2621 }
2622 ArcRenderCommand::EndOcclusionQuery => {
2623 api_log!("RenderPass::end_occlusion_query");
2624 let scope = PassErrorScope::EndOcclusionQuery;
2625
2626 end_occlusion_query(
2627 state.pass.base.raw_encoder,
2628 &mut state.active_occlusion_query,
2629 state.pass.base.snatch_guard,
2630 state.pass.base.query_set_writes,
2631 )
2632 .map_pass_err(scope)?;
2633 }
2634 ArcRenderCommand::BeginPipelineStatisticsQuery {
2635 query_set,
2636 query_index,
2637 } => {
2638 api_log!(
2639 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2640 query_set.error_ident()
2641 );
2642 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2643
2644 validate_and_begin_pipeline_statistics_query(
2645 query_set,
2646 state.pass.base.raw_encoder,
2647 &mut state.pass.base.tracker.query_sets,
2648 device,
2649 query_index,
2650 Some(&mut pending_query_resets),
2651 &mut state.active_pipeline_statistics_query,
2652 state.pass.base.snatch_guard,
2653 )
2654 .map_pass_err(scope)?;
2655 }
2656 ArcRenderCommand::EndPipelineStatisticsQuery => {
2657 api_log!("RenderPass::end_pipeline_statistics_query");
2658 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2659
2660 end_pipeline_statistics_query(
2661 state.pass.base.raw_encoder,
2662 &mut state.active_pipeline_statistics_query,
2663 state.pass.base.snatch_guard,
2664 state.pass.base.query_set_writes,
2665 )
2666 .map_pass_err(scope)?;
2667 }
2668 ArcRenderCommand::ExecuteBundle(bundle) => {
2669 let scope = PassErrorScope::ExecuteBundle;
2670 execute_bundle(
2671 &mut state,
2672 &mut indirect_draw_validation_batcher,
2673 device,
2674 bundle,
2675 )
2676 .map_pass_err(scope)?;
2677 }
2678 }
2679 }
2680
2681 if *state.pass.base.debug_scope_depth > 0 {
2682 Err(
2683 RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2684 .map_pass_err(pass_scope),
2685 )?;
2686 }
2687 if state.active_occlusion_query.is_some() {
2688 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2689 query_type: super::SimplifiedQueryType::Occlusion,
2690 })
2691 .map_pass_err(pass_scope))?;
2692 }
2693 if state.active_pipeline_statistics_query.is_some() {
2694 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2695 query_type: super::SimplifiedQueryType::PipelineStatistics,
2696 })
2697 .map_pass_err(pass_scope))?;
2698 }
2699
2700 state
2701 .info
2702 .finish(
2703 device,
2704 state.pass.base.raw_encoder,
2705 state.pass.base.snatch_guard,
2706 &mut state.pass.scope,
2707 device.instance_flags,
2708 )
2709 .map_pass_err(pass_scope)?;
2710
2711 let trackers = state.pass.scope;
2712
2713 let pending_discard_init_fixups = state.pass.pending_discard_init_fixups;
2714
2715 parent_state.raw_encoder.close().map_pass_err(pass_scope)?;
2716 (trackers, pending_discard_init_fixups, pending_query_resets)
2717 };
2718
2719 let encoder = &mut parent_state.raw_encoder;
2720 let tracker = &mut parent_state.tracker;
2721
2722 {
2723 let transit = encoder
2724 .open_pass(hal_label(
2725 Some("(wgpu internal) Pre Pass"),
2726 device.instance_flags,
2727 ))
2728 .map_pass_err(pass_scope)?;
2729
2730 fixup_discarded_surfaces(
2731 pending_discard_init_fixups.into_iter(),
2732 transit,
2733 &mut tracker.textures,
2734 device,
2735 parent_state.snatch_guard,
2736 );
2737
2738 pending_query_resets
2739 .reset_queries(transit, parent_state.snatch_guard)
2740 .map_pass_err(pass_scope)?;
2741
2742 CommandEncoder::insert_barriers_from_scope(
2743 transit,
2744 tracker,
2745 &scope,
2746 parent_state.snatch_guard,
2747 );
2748
2749 if let Some(ref indirect_validation) = device.indirect_validation {
2750 indirect_validation
2751 .draw
2752 .inject_validation_pass(
2753 device,
2754 parent_state.snatch_guard,
2755 parent_state.indirect_draw_validation_resources,
2756 parent_state.temp_resources,
2757 transit,
2758 indirect_draw_validation_batcher,
2759 )
2760 .map_pass_err(pass_scope)?;
2761 }
2762 }
2763
2764 encoder.close_and_swap().map_pass_err(pass_scope)?;
2765
2766 Ok(())
2767}
2768
2769fn set_pipeline(
2770 state: &mut State,
2771 device: &Arc<Device>,
2772 pipeline: Arc<RenderPipeline>,
2773) -> Result<(), RenderPassErrorInner> {
2774 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2775
2776 state.pipeline = Some(pipeline.clone());
2777
2778 let pipeline = state
2779 .pass
2780 .base
2781 .tracker
2782 .render_pipelines
2783 .insert_single(pipeline)
2784 .clone();
2785
2786 pipeline.same_device(device)?;
2787
2788 state
2789 .info
2790 .context
2791 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2792 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2793
2794 state.pipeline_flags = pipeline.flags;
2795
2796 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2797 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2798 }
2799 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2800 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2801 }
2802
2803 state
2804 .blend_constant
2805 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2806
2807 unsafe {
2808 state
2809 .pass
2810 .base
2811 .raw_encoder
2812 .set_render_pipeline(pipeline.raw()?);
2813 }
2814
2815 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2816 unsafe {
2817 state
2818 .pass
2819 .base
2820 .raw_encoder
2821 .set_stencil_reference(state.stencil_reference);
2822 }
2823 }
2824
2825 pass::change_pipeline_layout::<RenderPassErrorInner>(
2827 &mut state.pass,
2828 pipeline.layout()?,
2829 &pipeline.late_sized_buffer_groups,
2830 )?;
2831
2832 state.vertex.update_limits(&pipeline.vertex_steps);
2834 Ok(())
2835}
2836
2837fn set_index_buffer(
2839 state: &mut State,
2840 device: &Arc<Device>,
2841 buffer: Arc<Buffer>,
2842 index_format: IndexFormat,
2843 offset: u64,
2844 size: Option<BufferSize>,
2845) -> Result<(), RenderPassErrorInner> {
2846 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2847
2848 state
2849 .pass
2850 .scope
2851 .buffers
2852 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2853
2854 buffer.same_device(device)?;
2855
2856 buffer.check_usage(BufferUsages::INDEX)?;
2857
2858 if !offset.is_multiple_of(u64::from(index_format.byte_size())) {
2859 return Err(RenderCommandError::UnalignedIndexBuffer {
2860 offset,
2861 alignment: index_format.byte_size() as usize,
2862 }
2863 .into());
2864 }
2865 let (binding, resolved_size) = buffer
2866 .binding(offset, size, state.pass.base.snatch_guard)
2867 .map_err(RenderCommandError::from)?;
2868 let end = offset + resolved_size;
2869 state.index.update_buffer(offset..end, index_format);
2870
2871 state.pass.base.buffer_memory_init_actions.extend(
2872 buffer.initialization_status.read().create_action(
2873 &buffer,
2874 offset..end,
2875 MemoryInitKind::NeedsInitializedMemory,
2876 ),
2877 );
2878
2879 unsafe {
2880 hal::DynCommandEncoder::set_index_buffer(
2881 state.pass.base.raw_encoder,
2882 binding,
2883 index_format,
2884 );
2885 }
2886 Ok(())
2887}
2888
2889fn set_vertex_buffer(
2891 state: &mut State,
2892 device: &Arc<Device>,
2893 slot: u32,
2894 buffer: Option<Arc<Buffer>>,
2895 offset: u64,
2896 size: Option<BufferSize>,
2897) -> Result<(), RenderPassErrorInner> {
2898 if let Some(ref buffer) = buffer {
2899 api_log!(
2900 "RenderPass::set_vertex_buffer {slot} {}",
2901 buffer.error_ident()
2902 );
2903 } else {
2904 api_log!("RenderPass::set_vertex_buffer {slot} None");
2905 }
2906
2907 let max_vertex_buffers = state.pass.base.device.limits.max_vertex_buffers;
2908 if slot >= max_vertex_buffers {
2909 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2910 index: slot,
2911 max: max_vertex_buffers,
2912 }
2913 .into());
2914 }
2915
2916 if let Some(buffer) = buffer {
2917 buffer.same_device(device)?;
2918 buffer.check_usage(BufferUsages::VERTEX)?;
2919
2920 if !offset.is_multiple_of(wgt::VERTEX_ALIGNMENT) {
2921 return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2922 }
2923 let binding_size = buffer
2924 .resolve_binding_size(offset, size)
2925 .map_err(RenderCommandError::from)?;
2926 let buffer_range = offset..(offset + binding_size);
2927
2928 state
2929 .pass
2930 .scope
2931 .buffers
2932 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2933
2934 state.pass.base.buffer_memory_init_actions.extend(
2935 buffer.initialization_status.read().create_action(
2936 &buffer,
2937 buffer_range.clone(),
2938 MemoryInitKind::NeedsInitializedMemory,
2939 ),
2940 );
2941
2942 state
2943 .vertex
2944 .set_buffer(slot as usize, buffer, buffer_range.clone());
2945 if let Some(pipeline) = state.pipeline.as_ref() {
2946 state.vertex.update_limits(&pipeline.vertex_steps);
2947 }
2948 } else {
2949 if offset != 0 {
2950 return Err(RenderCommandError::from(
2951 crate::binding_model::BindingError::UnbindingVertexBufferOffsetNotZero {
2952 slot,
2953 offset,
2954 },
2955 )
2956 .into());
2957 }
2958 if let Some(size) = size {
2959 return Err(RenderCommandError::from(
2960 crate::binding_model::BindingError::UnbindingVertexBufferSizeNotZero {
2961 slot,
2962 size: size.get(),
2963 },
2964 )
2965 .into());
2966 }
2967
2968 state.vertex.clear_buffer(slot as usize);
2969 if let Some(pipeline) = state.pipeline.as_ref() {
2970 state.vertex.update_limits(&pipeline.vertex_steps);
2971 }
2972 }
2973
2974 Ok(())
2975}
2976
2977fn set_blend_constant(state: &mut State, color: &Color) {
2978 api_log!("RenderPass::set_blend_constant");
2979
2980 state.blend_constant = OptionalState::Set;
2981 let array = [
2982 color.r as f32,
2983 color.g as f32,
2984 color.b as f32,
2985 color.a as f32,
2986 ];
2987 unsafe {
2988 state.pass.base.raw_encoder.set_blend_constants(&array);
2989 }
2990}
2991
2992fn set_stencil_reference(state: &mut State, value: u32) {
2993 api_log!("RenderPass::set_stencil_reference {value}");
2994
2995 state.stencil_reference = value;
2996 if state
2997 .pipeline_flags
2998 .contains(PipelineFlags::STENCIL_REFERENCE)
2999 {
3000 unsafe {
3001 state.pass.base.raw_encoder.set_stencil_reference(value);
3002 }
3003 }
3004}
3005
3006fn set_viewport(
3007 state: &mut State,
3008 rect: Rect<f32>,
3009 depth_min: f32,
3010 depth_max: f32,
3011) -> Result<(), RenderPassErrorInner> {
3012 api_log!("RenderPass::set_viewport {rect:?}");
3013
3014 if rect.w < 0.0
3015 || rect.h < 0.0
3016 || rect.w > state.pass.base.device.limits.max_texture_dimension_2d as f32
3017 || rect.h > state.pass.base.device.limits.max_texture_dimension_2d as f32
3018 {
3019 return Err(RenderCommandError::InvalidViewportRectSize {
3020 w: rect.w,
3021 h: rect.h,
3022 max: state.pass.base.device.limits.max_texture_dimension_2d,
3023 }
3024 .into());
3025 }
3026
3027 let max_viewport_range = state.pass.base.device.limits.max_texture_dimension_2d as f32 * 2.0;
3028
3029 if rect.x < -max_viewport_range
3030 || rect.y < -max_viewport_range
3031 || rect.x + rect.w > max_viewport_range - 1.0
3032 || rect.y + rect.h > max_viewport_range - 1.0
3033 {
3034 return Err(RenderCommandError::InvalidViewportRectPosition {
3035 rect,
3036 min: -max_viewport_range,
3037 max: max_viewport_range - 1.0,
3038 }
3039 .into());
3040 }
3041 if !(0.0..=1.0).contains(&depth_min)
3042 || !(0.0..=1.0).contains(&depth_max)
3043 || depth_min > depth_max
3044 {
3045 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
3046 }
3047 let r = hal::Rect {
3048 x: rect.x,
3049 y: rect.y,
3050 w: rect.w,
3051 h: rect.h,
3052 };
3053 unsafe {
3054 state
3055 .pass
3056 .base
3057 .raw_encoder
3058 .set_viewport(&r, depth_min..depth_max);
3059 }
3060 Ok(())
3061}
3062
3063fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
3064 api_log!("RenderPass::set_scissor_rect {rect:?}");
3065
3066 if rect.x.saturating_add(rect.w) > state.info.extent.width
3067 || rect.y.saturating_add(rect.h) > state.info.extent.height
3068 {
3069 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
3070 }
3071 let r = hal::Rect {
3072 x: rect.x,
3073 y: rect.y,
3074 w: rect.w,
3075 h: rect.h,
3076 };
3077 unsafe {
3078 state.pass.base.raw_encoder.set_scissor_rect(&r);
3079 }
3080 Ok(())
3081}
3082
3083fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
3084 if let Some(mv) = state.info.multiview_mask {
3085 let highest_bit = 31 - mv.leading_zeros();
3086
3087 let features = state.pass.base.device.features;
3088
3089 if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
3090 || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
3091 {
3092 return Err(RenderPassErrorInner::Draw(
3093 DrawError::MeshPipelineMultiviewLimitsViolated {
3094 highest_view_index: highest_bit,
3095 max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
3096 },
3097 ));
3098 }
3099 }
3100 Ok(())
3101}
3102
3103fn draw(
3104 state: &mut State,
3105 vertex_count: u32,
3106 instance_count: u32,
3107 first_vertex: u32,
3108 first_instance: u32,
3109) -> Result<(), RenderPassErrorInner> {
3110 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
3111
3112 state.is_ready(DrawCommandFamily::Draw)?;
3113 state.flush_vertex_buffers()?;
3114 state.flush_bindings()?;
3115 state.flush_immediates();
3116
3117 state
3118 .vertex
3119 .limits
3120 .validate_vertex_limit(first_vertex, vertex_count)?;
3121 state
3122 .vertex
3123 .limits
3124 .validate_instance_limit(first_instance, instance_count)?;
3125
3126 unsafe {
3127 if instance_count > 0 && vertex_count > 0 {
3128 state.pass.base.raw_encoder.draw(
3129 first_vertex,
3130 vertex_count,
3131 first_instance,
3132 instance_count,
3133 );
3134 }
3135 }
3136 Ok(())
3137}
3138
3139fn draw_indexed(
3140 state: &mut State,
3141 index_count: u32,
3142 instance_count: u32,
3143 first_index: u32,
3144 base_vertex: i32,
3145 first_instance: u32,
3146) -> Result<(), RenderPassErrorInner> {
3147 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
3148
3149 state.is_ready(DrawCommandFamily::DrawIndexed)?;
3150 state.flush_vertex_buffers()?;
3151 state.flush_bindings()?;
3152 state.flush_immediates();
3153
3154 let last_index = first_index as u64 + index_count as u64;
3155 let index_limit = state.index.limit;
3156 if last_index > index_limit {
3157 return Err(DrawError::IndexBeyondLimit {
3158 last_index,
3159 index_limit,
3160 }
3161 .into());
3162 }
3163 state
3164 .vertex
3165 .limits
3166 .validate_instance_limit(first_instance, instance_count)?;
3167
3168 unsafe {
3169 if instance_count > 0 && index_count > 0 {
3170 state.pass.base.raw_encoder.draw_indexed(
3171 first_index,
3172 index_count,
3173 base_vertex,
3174 first_instance,
3175 instance_count,
3176 );
3177 }
3178 }
3179 Ok(())
3180}
3181
3182fn draw_mesh_tasks(
3183 state: &mut State,
3184 group_count_x: u32,
3185 group_count_y: u32,
3186 group_count_z: u32,
3187) -> Result<(), RenderPassErrorInner> {
3188 api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
3189
3190 state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
3191
3192 state.flush_bindings()?;
3193 state.flush_immediates();
3194 validate_mesh_draw_multiview(state)?;
3195
3196 let limits = &state.pass.base.device.limits;
3197 let (groups_size_limit, max_groups) = if state.pipeline.as_ref().unwrap().has_task_shader {
3198 (
3199 limits.max_task_workgroups_per_dimension,
3200 limits.max_task_workgroup_total_count,
3201 )
3202 } else {
3203 (
3204 limits.max_mesh_workgroups_per_dimension,
3205 limits.max_mesh_workgroup_total_count,
3206 )
3207 };
3208
3209 let total_count = WorkgroupSizeCheck {
3210 dimensions: &[group_count_x, group_count_y, group_count_z],
3211 per_dimension_limits: &[groups_size_limit, groups_size_limit, groups_size_limit],
3212 per_dimension_limits_desc: "max_task_mesh_workgroups_per_dimension",
3213
3214 total_limit: max_groups,
3215 total_limit_desc: "max_task_mesh_workgroup_total_count",
3216 }
3217 .check_and_compute_total_invocations()
3218 .map_err(|err| RenderPassErrorInner::Draw(err.into()))?;
3219
3220 unsafe {
3221 if total_count > 0 {
3222 state.pass.base.raw_encoder.draw_mesh_tasks(
3223 group_count_x,
3224 group_count_y,
3225 group_count_z,
3226 );
3227 }
3228 }
3229 Ok(())
3230}
3231
3232fn multi_draw_indirect(
3233 state: &mut State,
3234 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3235 device: &Arc<Device>,
3236 indirect_buffer: Arc<Buffer>,
3237 offset: u64,
3238 count: u32,
3239 family: DrawCommandFamily,
3240) -> Result<(), RenderPassErrorInner> {
3241 api_log!(
3242 "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
3243 indirect_buffer.error_ident()
3244 );
3245
3246 state.is_ready(family)?;
3247 state.flush_vertex_buffers()?;
3248 state.flush_bindings()?;
3249 state.flush_immediates();
3250
3251 if family == DrawCommandFamily::DrawMeshTasks {
3252 validate_mesh_draw_multiview(state)?;
3253 }
3254
3255 state
3256 .pass
3257 .base
3258 .device
3259 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
3260
3261 indirect_buffer.same_device(device)?;
3262 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
3263 indirect_buffer.check_destroyed(state.pass.base.snatch_guard)?;
3264
3265 if !offset.is_multiple_of(4) {
3266 return Err(RenderCommandError::UnalignedIndirectBufferOffset(offset).into());
3267 }
3268
3269 let stride = get_src_stride_of_indirect_args(family);
3270 let args_size = match stride.checked_mul(u64::from(count)) {
3271 Some(sz) if sz <= indirect_buffer.size && indirect_buffer.size - sz >= offset => sz,
3272 args_size => {
3273 return Err(RenderCommandError::IndirectBufferOverrun {
3274 count,
3275 offset,
3276 args_size: args_size.unwrap_or(u64::MAX),
3277 buffer_size: indirect_buffer.size,
3278 }
3279 .into());
3280 }
3281 };
3282
3283 state.pass.base.buffer_memory_init_actions.extend(
3284 indirect_buffer.initialization_status.read().create_action(
3285 &indirect_buffer,
3286 offset..offset + args_size,
3287 MemoryInitKind::NeedsInitializedMemory,
3288 ),
3289 );
3290
3291 fn draw(
3292 raw_encoder: &mut dyn hal::DynCommandEncoder,
3293 family: DrawCommandFamily,
3294 indirect_buffer: &dyn hal::DynBuffer,
3295 offset: u64,
3296 count: u32,
3297 ) {
3298 match family {
3299 DrawCommandFamily::Draw => unsafe {
3300 raw_encoder.draw_indirect(indirect_buffer, offset, count);
3301 },
3302 DrawCommandFamily::DrawIndexed => unsafe {
3303 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
3304 },
3305 DrawCommandFamily::DrawMeshTasks => unsafe {
3306 raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
3307 },
3308 }
3309 }
3310
3311 if state.pass.base.device.indirect_validation.is_some()
3312 && family != DrawCommandFamily::DrawMeshTasks
3313 {
3314 state
3315 .pass
3316 .scope
3317 .buffers
3318 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
3319
3320 struct DrawData {
3321 buffer_index: usize,
3322 offset: u64,
3323 count: u32,
3324 }
3325
3326 struct DrawContext<'a> {
3327 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
3328 device: &'a Device,
3329
3330 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
3331 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
3332
3333 indirect_buffer: Arc<Buffer>,
3334 family: DrawCommandFamily,
3335 vertex_or_index_limit: u64,
3336 instance_limit: u64,
3337 }
3338
3339 impl<'a> DrawContext<'a> {
3340 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
3341 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
3342 self.indirect_draw_validation_resources,
3343 self.device,
3344 &self.indirect_buffer,
3345 offset,
3346 self.family,
3347 self.vertex_or_index_limit,
3348 self.instance_limit,
3349 )?;
3350 Ok(DrawData {
3351 buffer_index: dst_resource_index,
3352 offset: dst_offset,
3353 count: 1,
3354 })
3355 }
3356 fn draw(&mut self, draw_data: DrawData) {
3357 let dst_buffer = self
3358 .indirect_draw_validation_resources
3359 .get_dst_buffer(draw_data.buffer_index);
3360 draw(
3361 self.raw_encoder,
3362 self.family,
3363 dst_buffer,
3364 draw_data.offset,
3365 draw_data.count,
3366 );
3367 }
3368 }
3369
3370 let mut draw_ctx = DrawContext {
3371 raw_encoder: state.pass.base.raw_encoder,
3372 device: state.pass.base.device,
3373 indirect_draw_validation_resources: state.pass.base.indirect_draw_validation_resources,
3374 indirect_draw_validation_batcher,
3375 indirect_buffer,
3376 family,
3377 vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
3378 state.index.limit
3379 } else {
3380 state.vertex.limits.vertex_limit
3381 },
3382 instance_limit: state.vertex.limits.instance_limit,
3383 };
3384
3385 let mut current_draw_data = draw_ctx.add(offset)?;
3386
3387 for i in 1..count {
3388 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
3389
3390 if draw_data.buffer_index == current_draw_data.buffer_index {
3391 #[cfg(debug_assertions)]
3392 {
3393 let dst_stride =
3394 get_dst_stride_of_indirect_args(state.pass.base.device.backend(), family);
3395 debug_assert_eq!(
3396 draw_data.offset,
3397 current_draw_data.offset + dst_stride * current_draw_data.count as u64
3398 );
3399 }
3400 current_draw_data.count += 1;
3401 } else {
3402 draw_ctx.draw(current_draw_data);
3403 current_draw_data = draw_data;
3404 }
3405 }
3406
3407 draw_ctx.draw(current_draw_data);
3408 } else {
3409 state
3410 .pass
3411 .scope
3412 .buffers
3413 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
3414
3415 draw(
3416 state.pass.base.raw_encoder,
3417 family,
3418 indirect_buffer.try_raw(state.pass.base.snatch_guard)?,
3419 offset,
3420 count,
3421 );
3422 };
3423
3424 Ok(())
3425}
3426
3427fn multi_draw_indirect_count(
3428 state: &mut State,
3429 device: &Arc<Device>,
3430 indirect_buffer: Arc<Buffer>,
3431 offset: u64,
3432 count_buffer: Arc<Buffer>,
3433 count_buffer_offset: u64,
3434 max_count: u32,
3435 family: DrawCommandFamily,
3436) -> Result<(), RenderPassErrorInner> {
3437 api_log!(
3438 "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
3439 indirect_buffer.error_ident(),
3440 count_buffer.error_ident()
3441 );
3442
3443 state.is_ready(family)?;
3444 state.flush_vertex_buffers()?;
3445 state.flush_bindings()?;
3446 state.flush_immediates();
3447
3448 if family == DrawCommandFamily::DrawMeshTasks {
3449 validate_mesh_draw_multiview(state)?;
3450 }
3451
3452 let stride = get_src_stride_of_indirect_args(family);
3453
3454 state
3455 .pass
3456 .base
3457 .device
3458 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
3459 state
3460 .pass
3461 .base
3462 .device
3463 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
3464
3465 indirect_buffer.same_device(device)?;
3466 count_buffer.same_device(device)?;
3467
3468 state
3469 .pass
3470 .scope
3471 .buffers
3472 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
3473
3474 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
3475 let indirect_raw = indirect_buffer.try_raw(state.pass.base.snatch_guard)?;
3476
3477 state
3478 .pass
3479 .scope
3480 .buffers
3481 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
3482
3483 count_buffer.check_usage(BufferUsages::INDIRECT)?;
3484 let count_raw = count_buffer.try_raw(state.pass.base.snatch_guard)?;
3485
3486 if !offset.is_multiple_of(4) {
3487 return Err(RenderCommandError::UnalignedIndirectBufferOffset(offset).into());
3488 }
3489
3490 let args_size = match stride.checked_mul(u64::from(max_count)) {
3491 Some(sz) if sz <= indirect_buffer.size && indirect_buffer.size - sz >= offset => sz,
3492 args_size => {
3493 return Err(RenderCommandError::IndirectBufferOverrun {
3494 count: 1,
3495 offset,
3496 args_size: args_size.unwrap_or(u64::MAX),
3497 buffer_size: indirect_buffer.size,
3498 }
3499 .into());
3500 }
3501 };
3502
3503 state.pass.base.buffer_memory_init_actions.extend(
3504 indirect_buffer.initialization_status.read().create_action(
3505 &indirect_buffer,
3506 offset..offset + args_size,
3507 MemoryInitKind::NeedsInitializedMemory,
3508 ),
3509 );
3510
3511 let begin_count_offset = count_buffer_offset;
3512 let count_bytes = 4;
3513 if count_buffer.size < count_bytes || count_buffer.size - count_bytes < count_buffer_offset {
3514 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
3515 begin_count_offset,
3516 count_bytes: 4,
3517 count_buffer_size: count_buffer.size,
3518 });
3519 }
3520 state.pass.base.buffer_memory_init_actions.extend(
3521 count_buffer.initialization_status.read().create_action(
3522 &count_buffer,
3523 count_buffer_offset..count_buffer_offset + count_bytes,
3524 MemoryInitKind::NeedsInitializedMemory,
3525 ),
3526 );
3527
3528 match family {
3529 DrawCommandFamily::Draw => unsafe {
3530 state.pass.base.raw_encoder.draw_indirect_count(
3531 indirect_raw,
3532 offset,
3533 count_raw,
3534 count_buffer_offset,
3535 max_count,
3536 );
3537 },
3538 DrawCommandFamily::DrawIndexed => unsafe {
3539 state.pass.base.raw_encoder.draw_indexed_indirect_count(
3540 indirect_raw,
3541 offset,
3542 count_raw,
3543 count_buffer_offset,
3544 max_count,
3545 );
3546 },
3547 DrawCommandFamily::DrawMeshTasks => unsafe {
3548 state.pass.base.raw_encoder.draw_mesh_tasks_indirect_count(
3549 indirect_raw,
3550 offset,
3551 count_raw,
3552 count_buffer_offset,
3553 max_count,
3554 );
3555 },
3556 }
3557 Ok(())
3558}
3559
3560fn execute_bundle(
3561 state: &mut State,
3562 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3563 device: &Arc<Device>,
3564 bundle: Arc<RenderBundle>,
3565) -> Result<(), RenderPassErrorInner> {
3566 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
3567
3568 let bundle = state.pass.base.tracker.bundles.insert_single(bundle);
3569
3570 let bundle_state = bundle.state()?;
3571 bundle.same_device(device)?;
3572
3573 state
3574 .info
3575 .context
3576 .check_compatible(&bundle_state.context, bundle.as_ref())
3577 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
3578
3579 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3580 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3581 {
3582 return Err(
3583 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3584 pass_depth: state.info.is_depth_read_only,
3585 pass_stencil: state.info.is_stencil_read_only,
3586 bundle_depth: bundle.is_depth_read_only,
3587 bundle_stencil: bundle.is_stencil_read_only,
3588 },
3589 );
3590 }
3591
3592 state.pass.base.buffer_memory_init_actions.extend(
3593 bundle
3594 .buffer_memory_init_actions
3595 .iter()
3596 .filter_map(|action| {
3597 action
3598 .buffer
3599 .initialization_status
3600 .read()
3601 .check_action(action)
3602 }),
3603 );
3604 for action in bundle.texture_memory_init_actions.iter() {
3605 state.pass.pending_discard_init_fixups.extend(
3606 state
3607 .pass
3608 .base
3609 .texture_memory_actions
3610 .register_init_action(action),
3611 );
3612 }
3613
3614 unsafe {
3615 bundle.execute(
3616 state.pass.base.raw_encoder,
3617 state.pass.base.indirect_draw_validation_resources,
3618 indirect_draw_validation_batcher,
3619 state.pass.base.snatch_guard,
3620 )
3621 }
3622 .map_err(|e| match e {
3623 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3624 ExecutionError::DestroyedResource(e) => {
3625 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3626 }
3627 ExecutionError::InvalidResource(e) => {
3628 RenderPassErrorInner::RenderCommand(RenderCommandError::InvalidResource(e))
3629 }
3630 ExecutionError::Unimplemented(what) => {
3631 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3632 }
3633 })?;
3634
3635 unsafe {
3636 state.pass.scope.merge_render_bundle(&bundle_state.used)?;
3637 };
3638 state.reset_bundle();
3639 Ok(())
3640}
3641
3642impl RenderPass {
3655 pub fn set_bind_group(
3656 &mut self,
3657 index: u32,
3658 bind_group: Option<Arc<BindGroup>>,
3659 offsets: &[DynamicOffset],
3660 ) -> Result<(), PassStateError> {
3661 let scope = PassErrorScope::SetBindGroup;
3662
3663 let base = pass_base!(self, scope);
3667
3668 if self.current_bind_groups.set_and_check_redundant(
3669 &bind_group,
3670 index,
3671 &mut base.dynamic_offsets,
3672 offsets,
3673 ) {
3674 return Ok(());
3675 }
3676
3677 let bind_group = if let Some(bind_group) = bind_group {
3678 pass_try!(base, scope, bind_group.check_is_valid());
3679 Some(bind_group)
3680 } else {
3681 None
3682 };
3683
3684 base.commands.push(ArcRenderCommand::SetBindGroup {
3685 index,
3686 num_dynamic_offsets: offsets.len(),
3687 bind_group,
3688 });
3689
3690 Ok(())
3691 }
3692
3693 pub fn set_pipeline(&mut self, pipeline: Arc<RenderPipeline>) -> Result<(), PassStateError> {
3694 let scope = PassErrorScope::SetPipelineRender;
3695
3696 let redundant = self.current_pipeline.set_and_check_redundant(&pipeline);
3697
3698 let base = pass_base!(self, scope);
3701
3702 if redundant {
3703 return Ok(());
3704 }
3705
3706 pass_try!(base, scope, pipeline.check_valid());
3707
3708 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3709
3710 Ok(())
3711 }
3712
3713 pub fn set_index_buffer(
3714 &mut self,
3715 buffer: Arc<Buffer>,
3716 index_format: IndexFormat,
3717 offset: BufferAddress,
3718 size: Option<BufferSize>,
3719 ) -> Result<(), PassStateError> {
3720 let scope = PassErrorScope::SetIndexBuffer;
3721 let base = pass_base!(self, scope);
3722
3723 pass_try!(base, scope, buffer.check_is_valid());
3724
3725 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3726 buffer,
3727 index_format,
3728 offset,
3729 size,
3730 });
3731
3732 Ok(())
3733 }
3734
3735 pub fn set_vertex_buffer(
3736 &mut self,
3737 slot: u32,
3738 buffer: Option<Arc<Buffer>>,
3739 offset: BufferAddress,
3740 size: Option<BufferSize>,
3741 ) -> Result<(), PassStateError> {
3742 let scope = PassErrorScope::SetVertexBuffer;
3743 let base = pass_base!(self, scope);
3744
3745 let buffer = if let Some(buffer) = buffer {
3746 pass_try!(base, scope, buffer.check_is_valid());
3747 Some(buffer)
3748 } else {
3749 None
3750 };
3751
3752 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3753 slot,
3754 buffer,
3755 offset,
3756 size,
3757 });
3758
3759 Ok(())
3760 }
3761
3762 pub fn set_blend_constant(&mut self, color: Color) -> Result<(), PassStateError> {
3763 let scope = PassErrorScope::SetBlendConstant;
3764 let base = pass_base!(self, scope);
3765
3766 base.commands
3767 .push(ArcRenderCommand::SetBlendConstant(color));
3768
3769 Ok(())
3770 }
3771
3772 pub fn set_stencil_reference(&mut self, value: u32) -> Result<(), PassStateError> {
3773 let scope = PassErrorScope::SetStencilReference;
3774 let base = pass_base!(self, scope);
3775 let value = convert_stencil_value(
3776 value,
3777 self.depth_stencil_attachment
3778 .as_ref()
3779 .map(|at| at.view.desc.format),
3780 );
3781 base.commands
3782 .push(ArcRenderCommand::SetStencilReference(value));
3783
3784 Ok(())
3785 }
3786
3787 pub fn set_viewport(
3788 &mut self,
3789 x: f32,
3790 y: f32,
3791 w: f32,
3792 h: f32,
3793 depth_min: f32,
3794 depth_max: f32,
3795 ) -> Result<(), PassStateError> {
3796 let scope = PassErrorScope::SetViewport;
3797 let base = pass_base!(self, scope);
3798
3799 base.commands.push(ArcRenderCommand::SetViewport {
3800 rect: Rect { x, y, w, h },
3801 depth_min,
3802 depth_max,
3803 });
3804
3805 Ok(())
3806 }
3807
3808 pub fn set_scissor_rect(
3809 &mut self,
3810 x: u32,
3811 y: u32,
3812 w: u32,
3813 h: u32,
3814 ) -> Result<(), PassStateError> {
3815 let scope = PassErrorScope::SetScissorRect;
3816 let base = pass_base!(self, scope);
3817
3818 base.commands
3819 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3820
3821 Ok(())
3822 }
3823
3824 pub fn set_immediates(&mut self, offset: u32, data: &[u8]) -> Result<(), PassStateError> {
3825 let scope = PassErrorScope::SetImmediate;
3826 let base = pass_base!(self, scope);
3827
3828 pass_try!(
3829 base,
3830 scope,
3831 pass::validate_immediates_alignment(offset, data.len())
3832 );
3833
3834 base.commands.push(ArcRenderCommand::SetImmediate {
3835 offset,
3836 data: data
3837 .chunks_exact(size_of::<u32>())
3838 .map(|ck| u32::from_le_bytes(ck.try_into().unwrap()))
3839 .collect(),
3840 });
3841
3842 Ok(())
3843 }
3844
3845 pub fn draw(
3846 &mut self,
3847 vertex_count: u32,
3848 instance_count: u32,
3849 first_vertex: u32,
3850 first_instance: u32,
3851 ) -> Result<(), PassStateError> {
3852 let scope = PassErrorScope::Draw {
3853 kind: DrawKind::Draw,
3854 family: DrawCommandFamily::Draw,
3855 };
3856 let base = pass_base!(self, scope);
3857
3858 base.commands.push(ArcRenderCommand::Draw {
3859 vertex_count,
3860 instance_count,
3861 first_vertex,
3862 first_instance,
3863 });
3864
3865 Ok(())
3866 }
3867
3868 pub fn draw_indexed(
3869 &mut self,
3870 index_count: u32,
3871 instance_count: u32,
3872 first_index: u32,
3873 base_vertex: i32,
3874 first_instance: u32,
3875 ) -> Result<(), PassStateError> {
3876 let scope = PassErrorScope::Draw {
3877 kind: DrawKind::Draw,
3878 family: DrawCommandFamily::DrawIndexed,
3879 };
3880 let base = pass_base!(self, scope);
3881
3882 base.commands.push(ArcRenderCommand::DrawIndexed {
3883 index_count,
3884 instance_count,
3885 first_index,
3886 base_vertex,
3887 first_instance,
3888 });
3889
3890 Ok(())
3891 }
3892
3893 pub fn draw_mesh_tasks(
3894 &mut self,
3895 group_count_x: u32,
3896 group_count_y: u32,
3897 group_count_z: u32,
3898 ) -> Result<(), RenderPassError> {
3899 let scope = PassErrorScope::Draw {
3900 kind: DrawKind::Draw,
3901 family: DrawCommandFamily::DrawMeshTasks,
3902 };
3903 let base = pass_base!(self, scope);
3904
3905 base.commands.push(ArcRenderCommand::DrawMeshTasks {
3906 group_count_x,
3907 group_count_y,
3908 group_count_z,
3909 });
3910 Ok(())
3911 }
3912
3913 pub fn draw_indirect(
3914 &mut self,
3915 buffer: Arc<Buffer>,
3916 offset: BufferAddress,
3917 ) -> Result<(), PassStateError> {
3918 let scope = PassErrorScope::Draw {
3919 kind: DrawKind::DrawIndirect,
3920 family: DrawCommandFamily::Draw,
3921 };
3922 let base = pass_base!(self, scope);
3923
3924 pass_try!(base, scope, buffer.check_is_valid());
3925
3926 base.commands.push(ArcRenderCommand::DrawIndirect {
3927 buffer,
3928 offset,
3929 count: 1,
3930 family: DrawCommandFamily::Draw,
3931
3932 vertex_or_index_limit: None,
3933 instance_limit: None,
3934 });
3935
3936 Ok(())
3937 }
3938
3939 pub fn draw_indexed_indirect(
3940 &mut self,
3941 buffer: Arc<Buffer>,
3942 offset: BufferAddress,
3943 ) -> Result<(), PassStateError> {
3944 let scope = PassErrorScope::Draw {
3945 kind: DrawKind::DrawIndirect,
3946 family: DrawCommandFamily::DrawIndexed,
3947 };
3948 let base = pass_base!(self, scope);
3949
3950 pass_try!(base, scope, buffer.check_is_valid());
3951
3952 base.commands.push(ArcRenderCommand::DrawIndirect {
3953 buffer,
3954 offset,
3955 count: 1,
3956 family: DrawCommandFamily::DrawIndexed,
3957
3958 vertex_or_index_limit: None,
3959 instance_limit: None,
3960 });
3961
3962 Ok(())
3963 }
3964
3965 pub fn draw_mesh_tasks_indirect(
3966 &mut self,
3967 buffer: Arc<Buffer>,
3968 offset: BufferAddress,
3969 ) -> Result<(), RenderPassError> {
3970 let scope = PassErrorScope::Draw {
3971 kind: DrawKind::DrawIndirect,
3972 family: DrawCommandFamily::DrawMeshTasks,
3973 };
3974 let base = pass_base!(self, scope);
3975
3976 pass_try!(base, scope, buffer.check_is_valid());
3977
3978 base.commands.push(ArcRenderCommand::DrawIndirect {
3979 buffer,
3980 offset,
3981 count: 1,
3982 family: DrawCommandFamily::DrawMeshTasks,
3983
3984 vertex_or_index_limit: None,
3985 instance_limit: None,
3986 });
3987
3988 Ok(())
3989 }
3990
3991 pub fn multi_draw_indirect(
3992 &mut self,
3993 buffer: Arc<Buffer>,
3994 offset: BufferAddress,
3995 count: u32,
3996 ) -> Result<(), PassStateError> {
3997 let scope = PassErrorScope::Draw {
3998 kind: DrawKind::MultiDrawIndirect,
3999 family: DrawCommandFamily::Draw,
4000 };
4001 let base = pass_base!(self, scope);
4002
4003 pass_try!(base, scope, buffer.check_is_valid());
4004
4005 base.commands.push(ArcRenderCommand::DrawIndirect {
4006 buffer,
4007 offset,
4008 count,
4009 family: DrawCommandFamily::Draw,
4010
4011 vertex_or_index_limit: None,
4012 instance_limit: None,
4013 });
4014
4015 Ok(())
4016 }
4017
4018 pub fn multi_draw_indexed_indirect(
4019 &mut self,
4020 buffer: Arc<Buffer>,
4021 offset: BufferAddress,
4022 count: u32,
4023 ) -> Result<(), PassStateError> {
4024 let scope = PassErrorScope::Draw {
4025 kind: DrawKind::MultiDrawIndirect,
4026 family: DrawCommandFamily::DrawIndexed,
4027 };
4028 let base = pass_base!(self, scope);
4029
4030 pass_try!(base, scope, buffer.check_is_valid());
4031
4032 base.commands.push(ArcRenderCommand::DrawIndirect {
4033 buffer,
4034 offset,
4035 count,
4036 family: DrawCommandFamily::DrawIndexed,
4037
4038 vertex_or_index_limit: None,
4039 instance_limit: None,
4040 });
4041
4042 Ok(())
4043 }
4044
4045 pub fn multi_draw_mesh_tasks_indirect(
4046 &mut self,
4047 buffer: Arc<Buffer>,
4048 offset: BufferAddress,
4049 count: u32,
4050 ) -> Result<(), RenderPassError> {
4051 let scope = PassErrorScope::Draw {
4052 kind: DrawKind::MultiDrawIndirect,
4053 family: DrawCommandFamily::DrawMeshTasks,
4054 };
4055 let base = pass_base!(self, scope);
4056
4057 pass_try!(base, scope, buffer.check_is_valid());
4058
4059 base.commands.push(ArcRenderCommand::DrawIndirect {
4060 buffer,
4061 offset,
4062 count,
4063 family: DrawCommandFamily::DrawMeshTasks,
4064
4065 vertex_or_index_limit: None,
4066 instance_limit: None,
4067 });
4068
4069 Ok(())
4070 }
4071
4072 pub fn multi_draw_indirect_count(
4073 &mut self,
4074 buffer: Arc<Buffer>,
4075 offset: BufferAddress,
4076 count_buffer: Arc<Buffer>,
4077 count_buffer_offset: BufferAddress,
4078 max_count: u32,
4079 ) -> Result<(), PassStateError> {
4080 let scope = PassErrorScope::Draw {
4081 kind: DrawKind::MultiDrawIndirectCount,
4082 family: DrawCommandFamily::Draw,
4083 };
4084 let base = pass_base!(self, scope);
4085 pass_try!(base, scope, buffer.check_is_valid());
4086 pass_try!(base, scope, count_buffer.check_is_valid());
4087
4088 base.commands
4089 .push(ArcRenderCommand::MultiDrawIndirectCount {
4090 buffer,
4091 offset,
4092 count_buffer,
4093 count_buffer_offset,
4094 max_count,
4095 family: DrawCommandFamily::Draw,
4096 });
4097
4098 Ok(())
4099 }
4100
4101 pub fn multi_draw_indexed_indirect_count(
4102 &mut self,
4103 buffer: Arc<Buffer>,
4104 offset: BufferAddress,
4105 count_buffer: Arc<Buffer>,
4106 count_buffer_offset: BufferAddress,
4107 max_count: u32,
4108 ) -> Result<(), PassStateError> {
4109 let scope = PassErrorScope::Draw {
4110 kind: DrawKind::MultiDrawIndirectCount,
4111 family: DrawCommandFamily::DrawIndexed,
4112 };
4113 let base = pass_base!(self, scope);
4114
4115 pass_try!(base, scope, buffer.check_is_valid());
4116 pass_try!(base, scope, count_buffer.check_is_valid());
4117
4118 base.commands
4119 .push(ArcRenderCommand::MultiDrawIndirectCount {
4120 buffer,
4121 offset,
4122 count_buffer,
4123 count_buffer_offset,
4124 max_count,
4125 family: DrawCommandFamily::DrawIndexed,
4126 });
4127
4128 Ok(())
4129 }
4130
4131 pub fn multi_draw_mesh_tasks_indirect_count(
4132 &mut self,
4133 buffer: Arc<Buffer>,
4134 offset: BufferAddress,
4135 count_buffer: Arc<Buffer>,
4136 count_buffer_offset: BufferAddress,
4137 max_count: u32,
4138 ) -> Result<(), RenderPassError> {
4139 let scope = PassErrorScope::Draw {
4140 kind: DrawKind::MultiDrawIndirectCount,
4141 family: DrawCommandFamily::DrawMeshTasks,
4142 };
4143 let base = pass_base!(self, scope);
4144
4145 pass_try!(base, scope, buffer.check_is_valid());
4146 pass_try!(base, scope, count_buffer.check_is_valid());
4147
4148 base.commands
4149 .push(ArcRenderCommand::MultiDrawIndirectCount {
4150 buffer,
4151 offset,
4152 count_buffer,
4153 count_buffer_offset,
4154 max_count,
4155 family: DrawCommandFamily::DrawMeshTasks,
4156 });
4157
4158 Ok(())
4159 }
4160
4161 pub fn push_debug_group(&mut self, label: &str, color: u32) -> Result<(), PassStateError> {
4162 let base = pass_base!(self, PassErrorScope::PushDebugGroup);
4163
4164 let bytes = label.as_bytes();
4165 base.string_data.extend_from_slice(bytes);
4166
4167 base.commands.push(ArcRenderCommand::PushDebugGroup {
4168 color,
4169 len: bytes.len(),
4170 });
4171
4172 Ok(())
4173 }
4174
4175 pub fn pop_debug_group(&mut self) -> Result<(), PassStateError> {
4176 let base = pass_base!(self, PassErrorScope::PopDebugGroup);
4177
4178 base.commands.push(ArcRenderCommand::PopDebugGroup);
4179
4180 Ok(())
4181 }
4182
4183 pub fn insert_debug_marker(&mut self, label: &str, color: u32) -> Result<(), PassStateError> {
4184 let base = pass_base!(self, PassErrorScope::InsertDebugMarker);
4185
4186 let bytes = label.as_bytes();
4187 base.string_data.extend_from_slice(bytes);
4188
4189 base.commands.push(ArcRenderCommand::InsertDebugMarker {
4190 color,
4191 len: bytes.len(),
4192 });
4193
4194 Ok(())
4195 }
4196
4197 pub fn write_timestamp(
4198 &mut self,
4199 query_set: Arc<QuerySet>,
4200 query_index: u32,
4201 ) -> Result<(), PassStateError> {
4202 let scope = PassErrorScope::WriteTimestamp;
4203 let base = pass_base!(self, scope);
4204
4205 pass_try!(base, scope, query_set.check_is_valid());
4206 base.commands.push(ArcRenderCommand::WriteTimestamp {
4207 query_set,
4208 query_index,
4209 });
4210
4211 Ok(())
4212 }
4213
4214 pub fn begin_occlusion_query(&mut self, query_index: u32) -> Result<(), PassStateError> {
4215 let scope = PassErrorScope::BeginOcclusionQuery;
4216 let base = pass_base!(self, scope);
4217
4218 base.commands
4219 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
4220
4221 Ok(())
4222 }
4223
4224 pub fn end_occlusion_query(&mut self) -> Result<(), PassStateError> {
4225 let scope = PassErrorScope::EndOcclusionQuery;
4226 let base = pass_base!(self, scope);
4227
4228 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
4229
4230 Ok(())
4231 }
4232
4233 pub fn begin_pipeline_statistics_query(
4234 &mut self,
4235 query_set: Arc<QuerySet>,
4236 query_index: u32,
4237 ) -> Result<(), PassStateError> {
4238 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
4239 let base = pass_base!(self, scope);
4240
4241 pass_try!(base, scope, query_set.check_is_valid());
4242 base.commands
4243 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
4244 query_set,
4245 query_index,
4246 });
4247
4248 Ok(())
4249 }
4250
4251 pub fn end_pipeline_statistics_query(&mut self) -> Result<(), PassStateError> {
4252 let scope = PassErrorScope::EndPipelineStatisticsQuery;
4253 let base = pass_base!(self, scope);
4254
4255 base.commands
4256 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
4257
4258 Ok(())
4259 }
4260
4261 pub fn execute_bundles(
4262 &mut self,
4263 render_bundles: &[Arc<RenderBundle>],
4264 ) -> Result<(), PassStateError> {
4265 let scope = PassErrorScope::ExecuteBundle;
4266 let base = pass_base!(self, scope);
4267
4268 for bundle in render_bundles {
4269 pass_try!(base, scope, bundle.check_is_valid());
4270
4271 base.commands
4272 .push(ArcRenderCommand::ExecuteBundle(bundle.clone()));
4273 }
4274 self.current_pipeline.reset();
4275 self.current_bind_groups.reset();
4276
4277 Ok(())
4278 }
4279}
4280
4281pub(crate) const fn get_src_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
4282 match family {
4283 DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
4284 DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
4285 DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
4286 }
4287}
4288
4289pub(crate) const fn get_dst_stride_of_indirect_args(
4290 backend: wgt::Backend,
4291 family: DrawCommandFamily,
4292) -> u64 {
4293 let extra = if matches!(backend, wgt::Backend::Dx12) {
4295 3 * size_of::<u32>() as u64
4296 } else {
4297 0
4298 };
4299 extra + get_src_stride_of_indirect_args(family)
4300}
4301
4302impl Global {
4315 pub fn render_pass_set_bind_group(
4316 &self,
4317 pass: &mut RenderPass,
4318 index: u32,
4319 bind_group_id: Option<id::BindGroupId>,
4320 offsets: &[DynamicOffset],
4321 ) -> Result<(), PassStateError> {
4322 pass.set_bind_group(
4323 index,
4324 bind_group_id.map(|id| self.hub.bind_groups.get(id)),
4325 offsets,
4326 )
4327 }
4328
4329 pub fn render_pass_set_bind_group_with_id(
4330 &self,
4331 pass: id::RenderPassEncoderId,
4332 index: u32,
4333 bind_group_id: Option<id::BindGroupId>,
4334 offsets: &[DynamicOffset],
4335 ) -> Result<(), PassStateError> {
4336 let pass = self.hub.render_passes.get(pass);
4337 let mut pass = pass
4338 .try_lock()
4339 .expect("RenderPasses should not be used concurrently");
4340 self.render_pass_set_bind_group(&mut pass, index, bind_group_id, offsets)
4341 }
4342
4343 pub fn render_pass_set_pipeline(
4344 &self,
4345 pass: &mut RenderPass,
4346 pipeline_id: id::RenderPipelineId,
4347 ) -> Result<(), PassStateError> {
4348 let pipeline = self.resolve_render_pipeline_id(pipeline_id);
4349 pass.set_pipeline(pipeline)
4350 }
4351
4352 pub fn render_pass_set_pipeline_with_id(
4353 &self,
4354 pass: id::RenderPassEncoderId,
4355 pipeline_id: id::RenderPipelineId,
4356 ) -> Result<(), PassStateError> {
4357 let pass = self.hub.render_passes.get(pass);
4358 let mut pass = pass
4359 .try_lock()
4360 .expect("RenderPasses should not be used concurrently");
4361 self.render_pass_set_pipeline(&mut pass, pipeline_id)
4362 }
4363
4364 pub fn render_pass_set_index_buffer(
4365 &self,
4366 pass: &mut RenderPass,
4367 buffer_id: id::BufferId,
4368 index_format: IndexFormat,
4369 offset: BufferAddress,
4370 size: Option<BufferSize>,
4371 ) -> Result<(), PassStateError> {
4372 pass.set_index_buffer(
4373 self.resolve_buffer_id(buffer_id),
4374 index_format,
4375 offset,
4376 size,
4377 )
4378 }
4379
4380 pub fn render_pass_set_index_buffer_with_id(
4381 &self,
4382 pass: id::RenderPassEncoderId,
4383 buffer_id: id::BufferId,
4384 index_format: IndexFormat,
4385 offset: BufferAddress,
4386 size: Option<BufferSize>,
4387 ) -> Result<(), PassStateError> {
4388 let pass = self.hub.render_passes.get(pass);
4389 let mut pass = pass
4390 .try_lock()
4391 .expect("RenderPasses should not be used concurrently");
4392 self.render_pass_set_index_buffer(&mut pass, buffer_id, index_format, offset, size)
4393 }
4394
4395 pub fn render_pass_set_vertex_buffer(
4396 &self,
4397 pass: &mut RenderPass,
4398 slot: u32,
4399 buffer_id: Option<id::BufferId>,
4400 offset: BufferAddress,
4401 size: Option<BufferSize>,
4402 ) -> Result<(), PassStateError> {
4403 pass.set_vertex_buffer(
4404 slot,
4405 buffer_id.map(|id| self.resolve_buffer_id(id)),
4406 offset,
4407 size,
4408 )
4409 }
4410
4411 pub fn render_pass_set_vertex_buffer_with_id(
4412 &self,
4413 pass: id::RenderPassEncoderId,
4414 slot: u32,
4415 buffer_id: Option<id::BufferId>,
4416 offset: BufferAddress,
4417 size: Option<BufferSize>,
4418 ) -> Result<(), PassStateError> {
4419 let pass = self.hub.render_passes.get(pass);
4420 let mut pass = pass
4421 .try_lock()
4422 .expect("RenderPasses should not be used concurrently");
4423 self.render_pass_set_vertex_buffer(&mut pass, slot, buffer_id, offset, size)
4424 }
4425
4426 pub fn render_pass_set_blend_constant(
4427 &self,
4428 pass: &mut RenderPass,
4429 color: Color,
4430 ) -> Result<(), PassStateError> {
4431 pass.set_blend_constant(color)
4432 }
4433
4434 pub fn render_pass_set_blend_constant_with_id(
4435 &self,
4436 pass: id::RenderPassEncoderId,
4437 color: Color,
4438 ) -> Result<(), PassStateError> {
4439 let pass = self.hub.render_passes.get(pass);
4440 let mut pass = pass
4441 .try_lock()
4442 .expect("RenderPasses should not be used concurrently");
4443 self.render_pass_set_blend_constant(&mut pass, color)
4444 }
4445
4446 pub fn render_pass_set_stencil_reference(
4447 &self,
4448 pass: &mut RenderPass,
4449 value: u32,
4450 ) -> Result<(), PassStateError> {
4451 pass.set_stencil_reference(value)
4452 }
4453
4454 pub fn render_pass_set_stencil_reference_with_id(
4455 &self,
4456 pass: id::RenderPassEncoderId,
4457 value: u32,
4458 ) -> Result<(), PassStateError> {
4459 let pass = self.hub.render_passes.get(pass);
4460 let mut pass = pass
4461 .try_lock()
4462 .expect("RenderPasses should not be used concurrently");
4463 self.render_pass_set_stencil_reference(&mut pass, value)
4464 }
4465
4466 pub fn render_pass_set_viewport(
4467 &self,
4468 pass: &mut RenderPass,
4469 x: f32,
4470 y: f32,
4471 w: f32,
4472 h: f32,
4473 depth_min: f32,
4474 depth_max: f32,
4475 ) -> Result<(), PassStateError> {
4476 pass.set_viewport(x, y, w, h, depth_min, depth_max)
4477 }
4478
4479 pub fn render_pass_set_viewport_with_id(
4480 &self,
4481 pass: id::RenderPassEncoderId,
4482 x: f32,
4483 y: f32,
4484 w: f32,
4485 h: f32,
4486 depth_min: f32,
4487 depth_max: f32,
4488 ) -> Result<(), PassStateError> {
4489 let pass = self.hub.render_passes.get(pass);
4490 let mut pass = pass
4491 .try_lock()
4492 .expect("RenderPasses should not be used concurrently");
4493 self.render_pass_set_viewport(&mut pass, x, y, w, h, depth_min, depth_max)
4494 }
4495
4496 pub fn render_pass_set_scissor_rect(
4497 &self,
4498 pass: &mut RenderPass,
4499 x: u32,
4500 y: u32,
4501 w: u32,
4502 h: u32,
4503 ) -> Result<(), PassStateError> {
4504 pass.set_scissor_rect(x, y, w, h)
4505 }
4506
4507 pub fn render_pass_set_scissor_rect_with_id(
4508 &self,
4509 pass: id::RenderPassEncoderId,
4510 x: u32,
4511 y: u32,
4512 w: u32,
4513 h: u32,
4514 ) -> Result<(), PassStateError> {
4515 let pass = self.hub.render_passes.get(pass);
4516 let mut pass = pass
4517 .try_lock()
4518 .expect("RenderPasses should not be used concurrently");
4519 self.render_pass_set_scissor_rect(&mut pass, x, y, w, h)
4520 }
4521
4522 pub fn render_pass_set_immediates(
4523 &self,
4524 pass: &mut RenderPass,
4525 offset: u32,
4526 data: &[u8],
4527 ) -> Result<(), PassStateError> {
4528 pass.set_immediates(offset, data)
4529 }
4530
4531 pub fn render_pass_set_immediates_with_id(
4532 &self,
4533 pass: id::RenderPassEncoderId,
4534 offset: u32,
4535 data: &[u8],
4536 ) -> Result<(), PassStateError> {
4537 let pass = self.hub.render_passes.get(pass);
4538 let mut pass = pass
4539 .try_lock()
4540 .expect("RenderPasses should not be used concurrently");
4541 self.render_pass_set_immediates(&mut pass, offset, data)
4542 }
4543
4544 pub fn render_pass_draw(
4545 &self,
4546 pass: &mut RenderPass,
4547 vertex_count: u32,
4548 instance_count: u32,
4549 first_vertex: u32,
4550 first_instance: u32,
4551 ) -> Result<(), PassStateError> {
4552 pass.draw(vertex_count, instance_count, first_vertex, first_instance)
4553 }
4554
4555 pub fn render_pass_draw_with_id(
4556 &self,
4557 pass: id::RenderPassEncoderId,
4558 vertex_count: u32,
4559 instance_count: u32,
4560 first_vertex: u32,
4561 first_instance: u32,
4562 ) -> Result<(), PassStateError> {
4563 let pass = self.hub.render_passes.get(pass);
4564 let mut pass = pass
4565 .try_lock()
4566 .expect("RenderPasses should not be used concurrently");
4567 self.render_pass_draw(
4568 &mut pass,
4569 vertex_count,
4570 instance_count,
4571 first_vertex,
4572 first_instance,
4573 )
4574 }
4575
4576 pub fn render_pass_draw_indexed(
4577 &self,
4578 pass: &mut RenderPass,
4579 index_count: u32,
4580 instance_count: u32,
4581 first_index: u32,
4582 base_vertex: i32,
4583 first_instance: u32,
4584 ) -> Result<(), PassStateError> {
4585 pass.draw_indexed(
4586 index_count,
4587 instance_count,
4588 first_index,
4589 base_vertex,
4590 first_instance,
4591 )
4592 }
4593
4594 pub fn render_pass_draw_indexed_with_id(
4595 &self,
4596 pass: id::RenderPassEncoderId,
4597 index_count: u32,
4598 instance_count: u32,
4599 first_index: u32,
4600 base_vertex: i32,
4601 first_instance: u32,
4602 ) -> Result<(), PassStateError> {
4603 let pass = self.hub.render_passes.get(pass);
4604 let mut pass = pass
4605 .try_lock()
4606 .expect("RenderPasses should not be used concurrently");
4607 self.render_pass_draw_indexed(
4608 &mut pass,
4609 index_count,
4610 instance_count,
4611 first_index,
4612 base_vertex,
4613 first_instance,
4614 )
4615 }
4616
4617 pub fn render_pass_draw_mesh_tasks(
4618 &self,
4619 pass: &mut RenderPass,
4620 group_count_x: u32,
4621 group_count_y: u32,
4622 group_count_z: u32,
4623 ) -> Result<(), RenderPassError> {
4624 pass.draw_mesh_tasks(group_count_x, group_count_y, group_count_z)
4625 }
4626
4627 pub fn render_pass_draw_indirect(
4628 &self,
4629 pass: &mut RenderPass,
4630 buffer_id: id::BufferId,
4631 offset: BufferAddress,
4632 ) -> Result<(), PassStateError> {
4633 pass.draw_indirect(self.resolve_buffer_id(buffer_id), offset)
4634 }
4635
4636 pub fn render_pass_draw_indirect_with_id(
4637 &self,
4638 pass: id::RenderPassEncoderId,
4639 buffer_id: id::BufferId,
4640 offset: BufferAddress,
4641 ) -> Result<(), PassStateError> {
4642 let pass = self.hub.render_passes.get(pass);
4643 let mut pass = pass
4644 .try_lock()
4645 .expect("RenderPasses should not be used concurrently");
4646 self.render_pass_draw_indirect(&mut pass, buffer_id, offset)
4647 }
4648
4649 pub fn render_pass_draw_indexed_indirect(
4650 &self,
4651 pass: &mut RenderPass,
4652 buffer_id: id::BufferId,
4653 offset: BufferAddress,
4654 ) -> Result<(), PassStateError> {
4655 pass.draw_indexed_indirect(self.resolve_buffer_id(buffer_id), offset)
4656 }
4657
4658 pub fn render_pass_draw_indexed_indirect_with_id(
4659 &self,
4660 pass: id::RenderPassEncoderId,
4661 buffer_id: id::BufferId,
4662 offset: BufferAddress,
4663 ) -> Result<(), PassStateError> {
4664 let pass = self.hub.render_passes.get(pass);
4665 let mut pass = pass
4666 .try_lock()
4667 .expect("RenderPasses should not be used concurrently");
4668 self.render_pass_draw_indexed_indirect(&mut pass, buffer_id, offset)
4669 }
4670
4671 pub fn render_pass_draw_mesh_tasks_indirect(
4672 &self,
4673 pass: &mut RenderPass,
4674 buffer_id: id::BufferId,
4675 offset: BufferAddress,
4676 ) -> Result<(), RenderPassError> {
4677 pass.draw_mesh_tasks_indirect(self.resolve_buffer_id(buffer_id), offset)
4678 }
4679
4680 pub fn render_pass_multi_draw_indirect(
4681 &self,
4682 pass: &mut RenderPass,
4683 buffer_id: id::BufferId,
4684 offset: BufferAddress,
4685 count: u32,
4686 ) -> Result<(), PassStateError> {
4687 pass.multi_draw_indirect(self.resolve_buffer_id(buffer_id), offset, count)
4688 }
4689
4690 pub fn render_pass_multi_draw_indexed_indirect(
4691 &self,
4692 pass: &mut RenderPass,
4693 buffer_id: id::BufferId,
4694 offset: BufferAddress,
4695 count: u32,
4696 ) -> Result<(), PassStateError> {
4697 pass.multi_draw_indexed_indirect(self.resolve_buffer_id(buffer_id), offset, count)
4698 }
4699
4700 pub fn render_pass_multi_draw_mesh_tasks_indirect(
4701 &self,
4702 pass: &mut RenderPass,
4703 buffer_id: id::BufferId,
4704 offset: BufferAddress,
4705 count: u32,
4706 ) -> Result<(), RenderPassError> {
4707 pass.multi_draw_mesh_tasks_indirect(self.resolve_buffer_id(buffer_id), offset, count)
4708 }
4709
4710 pub fn render_pass_multi_draw_indirect_count(
4711 &self,
4712 pass: &mut RenderPass,
4713 buffer_id: id::BufferId,
4714 offset: BufferAddress,
4715 count_buffer_id: id::BufferId,
4716 count_buffer_offset: BufferAddress,
4717 max_count: u32,
4718 ) -> Result<(), PassStateError> {
4719 pass.multi_draw_indirect_count(
4720 self.resolve_buffer_id(buffer_id),
4721 offset,
4722 self.resolve_buffer_id(count_buffer_id),
4723 count_buffer_offset,
4724 max_count,
4725 )
4726 }
4727
4728 pub fn render_pass_multi_draw_indexed_indirect_count(
4729 &self,
4730 pass: &mut RenderPass,
4731 buffer_id: id::BufferId,
4732 offset: BufferAddress,
4733 count_buffer_id: id::BufferId,
4734 count_buffer_offset: BufferAddress,
4735 max_count: u32,
4736 ) -> Result<(), PassStateError> {
4737 pass.multi_draw_indexed_indirect_count(
4738 self.resolve_buffer_id(buffer_id),
4739 offset,
4740 self.resolve_buffer_id(count_buffer_id),
4741 count_buffer_offset,
4742 max_count,
4743 )
4744 }
4745
4746 pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
4747 &self,
4748 pass: &mut RenderPass,
4749 buffer_id: id::BufferId,
4750 offset: BufferAddress,
4751 count_buffer_id: id::BufferId,
4752 count_buffer_offset: BufferAddress,
4753 max_count: u32,
4754 ) -> Result<(), RenderPassError> {
4755 pass.multi_draw_mesh_tasks_indirect_count(
4756 self.resolve_buffer_id(buffer_id),
4757 offset,
4758 self.resolve_buffer_id(count_buffer_id),
4759 count_buffer_offset,
4760 max_count,
4761 )
4762 }
4763
4764 pub fn render_pass_push_debug_group(
4765 &self,
4766 pass: &mut RenderPass,
4767 label: &str,
4768 color: u32,
4769 ) -> Result<(), PassStateError> {
4770 pass.push_debug_group(label, color)
4771 }
4772
4773 pub fn render_pass_push_debug_group_with_id(
4774 &self,
4775 pass: id::RenderPassEncoderId,
4776 label: &str,
4777 color: u32,
4778 ) -> Result<(), PassStateError> {
4779 let pass = self.hub.render_passes.get(pass);
4780 let mut pass = pass
4781 .try_lock()
4782 .expect("RenderPasses should not be used concurrently");
4783 self.render_pass_push_debug_group(&mut pass, label, color)
4784 }
4785
4786 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
4787 pass.pop_debug_group()
4788 }
4789
4790 pub fn render_pass_pop_debug_group_with_id(
4791 &self,
4792 pass: id::RenderPassEncoderId,
4793 ) -> Result<(), PassStateError> {
4794 let pass = self.hub.render_passes.get(pass);
4795 let mut pass = pass
4796 .try_lock()
4797 .expect("RenderPasses should not be used concurrently");
4798 self.render_pass_pop_debug_group(&mut pass)
4799 }
4800
4801 pub fn render_pass_insert_debug_marker(
4802 &self,
4803 pass: &mut RenderPass,
4804 label: &str,
4805 color: u32,
4806 ) -> Result<(), PassStateError> {
4807 pass.insert_debug_marker(label, color)
4808 }
4809
4810 pub fn render_pass_insert_debug_marker_with_id(
4811 &self,
4812 pass: id::RenderPassEncoderId,
4813 label: &str,
4814 color: u32,
4815 ) -> Result<(), PassStateError> {
4816 let pass = self.hub.render_passes.get(pass);
4817 let mut pass = pass
4818 .try_lock()
4819 .expect("RenderPasses should not be used concurrently");
4820 self.render_pass_insert_debug_marker(&mut pass, label, color)
4821 }
4822
4823 pub fn render_pass_write_timestamp(
4824 &self,
4825 pass: &mut RenderPass,
4826 query_set_id: id::QuerySetId,
4827 query_index: u32,
4828 ) -> Result<(), PassStateError> {
4829 pass.write_timestamp(self.resolve_query_set_id(query_set_id), query_index)
4830 }
4831
4832 pub fn render_pass_write_timestamp_with_id(
4833 &self,
4834 pass: id::RenderPassEncoderId,
4835 query_set_id: id::QuerySetId,
4836 query_index: u32,
4837 ) -> Result<(), PassStateError> {
4838 let pass = self.hub.render_passes.get(pass);
4839 let mut pass = pass
4840 .try_lock()
4841 .expect("RenderPasses should not be used concurrently");
4842 self.render_pass_write_timestamp(&mut pass, query_set_id, query_index)
4843 }
4844
4845 pub fn render_pass_begin_occlusion_query(
4846 &self,
4847 pass: &mut RenderPass,
4848 query_index: u32,
4849 ) -> Result<(), PassStateError> {
4850 pass.begin_occlusion_query(query_index)
4851 }
4852
4853 pub fn render_pass_begin_occlusion_query_with_id(
4854 &self,
4855 pass: id::RenderPassEncoderId,
4856 query_index: u32,
4857 ) -> Result<(), PassStateError> {
4858 let pass = self.hub.render_passes.get(pass);
4859 let mut pass = pass
4860 .try_lock()
4861 .expect("RenderPasses should not be used concurrently");
4862 self.render_pass_begin_occlusion_query(&mut pass, query_index)
4863 }
4864
4865 pub fn render_pass_end_occlusion_query(
4866 &self,
4867 pass: &mut RenderPass,
4868 ) -> Result<(), PassStateError> {
4869 pass.end_occlusion_query()
4870 }
4871
4872 pub fn render_pass_end_occlusion_query_with_id(
4873 &self,
4874 pass: id::RenderPassEncoderId,
4875 ) -> Result<(), PassStateError> {
4876 let pass = self.hub.render_passes.get(pass);
4877 let mut pass = pass
4878 .try_lock()
4879 .expect("RenderPasses should not be used concurrently");
4880 self.render_pass_end_occlusion_query(&mut pass)
4881 }
4882
4883 pub fn render_pass_begin_pipeline_statistics_query(
4884 &self,
4885 pass: &mut RenderPass,
4886 query_set_id: id::QuerySetId,
4887 query_index: u32,
4888 ) -> Result<(), PassStateError> {
4889 pass.begin_pipeline_statistics_query(self.resolve_query_set_id(query_set_id), query_index)
4890 }
4891
4892 pub fn render_pass_begin_pipeline_statistics_query_with_id(
4893 &self,
4894 pass: id::RenderPassEncoderId,
4895 query_set_id: id::QuerySetId,
4896 query_index: u32,
4897 ) -> Result<(), PassStateError> {
4898 let pass = self.hub.render_passes.get(pass);
4899 let mut pass = pass
4900 .try_lock()
4901 .expect("RenderPasses should not be used concurrently");
4902 self.render_pass_begin_pipeline_statistics_query(&mut pass, query_set_id, query_index)
4903 }
4904
4905 pub fn render_pass_end_pipeline_statistics_query(
4906 &self,
4907 pass: &mut RenderPass,
4908 ) -> Result<(), PassStateError> {
4909 pass.end_pipeline_statistics_query()
4910 }
4911
4912 pub fn render_pass_end_pipeline_statistics_query_with_id(
4913 &self,
4914 pass: id::RenderPassEncoderId,
4915 ) -> Result<(), PassStateError> {
4916 let pass = self.hub.render_passes.get(pass);
4917 let mut pass = pass
4918 .try_lock()
4919 .expect("RenderPasses should not be used concurrently");
4920 self.render_pass_end_pipeline_statistics_query(&mut pass)
4921 }
4922
4923 pub fn render_pass_execute_bundles(
4924 &self,
4925 pass: &mut RenderPass,
4926 render_bundle_ids: &[id::RenderBundleId],
4927 ) -> Result<(), PassStateError> {
4928 let hub = &self.hub;
4929 let bundles = hub.render_bundles.read();
4930 let render_bundles = render_bundle_ids
4931 .iter()
4932 .map(|&id| bundles.get(id))
4933 .collect::<Vec<_>>();
4934
4935 pass.execute_bundles(&render_bundles)
4936 }
4937
4938 pub fn render_pass_execute_bundles_with_id(
4939 &self,
4940 pass: id::RenderPassEncoderId,
4941 render_bundle_ids: &[id::RenderBundleId],
4942 ) -> Result<(), PassStateError> {
4943 let pass = self.hub.render_passes.get(pass);
4944 let mut pass = pass
4945 .try_lock()
4946 .expect("RenderPasses should not be used concurrently");
4947 self.render_pass_execute_bundles(&mut pass, render_bundle_ids)
4948 }
4949}