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