1use alloc::{borrow::Cow, 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, ImmediateUploadError},
17 command::{
18 bind::Binder,
19 memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState, TextureSurfaceDiscard},
20 pass::{self, flush_bindings_helper},
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, 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, InvalidResourceError, Labeled, MissingBufferUsageError,
44 MissingTextureUsageError, ParentDevice, QuerySet, RawResourceAccess, ResourceErrorIdent,
45 Texture, TextureView, TextureViewNotRenderableReason,
46 },
47 snatch::SnatchGuard,
48 track::{ResourceUsageCompatibilityError, Tracker, UsageScope},
49 validation::{self, WorkgroupSizeCheck},
50 Label,
51};
52
53#[cfg(feature = "serde")]
54use serde::Deserialize;
55#[cfg(feature = "serde")]
56use serde::Serialize;
57
58pub use wgt::{LoadOp, StoreOp};
59
60fn load_hal_ops<V>(load: LoadOp<V>) -> hal::AttachmentOps {
61 match load {
62 LoadOp::Load => hal::AttachmentOps::LOAD,
63 LoadOp::Clear(_) => hal::AttachmentOps::LOAD_CLEAR,
64 LoadOp::DontCare(_) => hal::AttachmentOps::LOAD_DONT_CARE,
65 }
66}
67
68fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps {
69 match store {
70 StoreOp::Store => hal::AttachmentOps::STORE,
71 StoreOp::Discard => hal::AttachmentOps::STORE_DISCARD,
72 }
73}
74
75fn convert_stencil_value(value: u32, format: Option<wgt::TextureFormat>) -> u32 {
77 let Some(format) = format else {
78 return value;
79 };
80 let Some(stencil_format) = format.aspect_specific_format(wgt::TextureAspect::StencilOnly)
81 else {
82 return value;
83 };
84 assert_eq!(stencil_format, wgt::TextureFormat::Stencil8);
86 value & 255
87}
88
89#[repr(C)]
94#[derive(Clone, Debug, Eq, PartialEq)]
95#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
96pub struct PassChannel<V> {
97 pub load_op: Option<LoadOp<V>>,
103 pub store_op: Option<StoreOp>,
105 pub read_only: bool,
109}
110
111impl<V: Copy + Default> PassChannel<Option<V>> {
112 fn resolve(
113 &self,
114 instance_flags: InstanceFlags,
115 handle_clear: impl Fn(Option<V>) -> Result<V, AttachmentError>,
116 ) -> Result<ResolvedPassChannel<V>, AttachmentError> {
117 if self.read_only {
118 if self.load_op.is_some() {
119 return Err(AttachmentError::ReadOnlyWithLoad);
120 }
121 if self.store_op.is_some() {
122 return Err(AttachmentError::ReadOnlyWithStore);
123 }
124 Ok(ResolvedPassChannel::ReadOnly)
125 } else {
126 Ok(ResolvedPassChannel::Operational(wgt::Operations {
127 load: match self.load_op.ok_or(AttachmentError::NoLoad)? {
128 LoadOp::Clear(clear_value) => LoadOp::Clear(handle_clear(clear_value)?),
129 LoadOp::DontCare(token) => {
130 if instance_flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
131 return Err(AttachmentError::LoadOpDontCareUnderStrictWebgpuCompliance);
132 }
133 LoadOp::DontCare(token)
134 }
135 LoadOp::Load => LoadOp::Load,
136 },
137 store: self.store_op.ok_or(AttachmentError::NoStore)?,
138 }))
139 }
140 }
141}
142
143#[derive(Clone, Debug)]
148#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149pub enum ResolvedPassChannel<V> {
150 ReadOnly,
151 Operational(wgt::Operations<V>),
152}
153
154impl<V: Copy + Default> ResolvedPassChannel<V> {
155 fn load_op(&self) -> LoadOp<V> {
156 match self {
157 ResolvedPassChannel::ReadOnly => LoadOp::Load,
158 ResolvedPassChannel::Operational(wgt::Operations { load, .. }) => *load,
159 }
160 }
161
162 fn store_op(&self) -> StoreOp {
163 match self {
164 ResolvedPassChannel::ReadOnly => StoreOp::Store,
165 ResolvedPassChannel::Operational(wgt::Operations { store, .. }) => *store,
166 }
167 }
168
169 fn clear_value(&self) -> V {
170 match self {
171 Self::Operational(wgt::Operations {
172 load: LoadOp::Clear(clear_value),
173 ..
174 }) => *clear_value,
175 _ => Default::default(),
176 }
177 }
178
179 fn is_readonly(&self) -> bool {
180 matches!(self, Self::ReadOnly)
181 }
182
183 fn hal_ops(&self) -> hal::AttachmentOps {
184 load_hal_ops(self.load_op()) | store_hal_ops(self.store_op())
185 }
186}
187
188#[repr(C)]
190#[derive(Clone, Debug, PartialEq)]
191#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
192pub struct RenderPassColorAttachment<TV = id::TextureViewId> {
193 pub view: TV,
195 pub depth_slice: Option<u32>,
197 pub resolve_target: Option<TV>,
199 pub load_op: LoadOp<Color>,
205 pub store_op: StoreOp,
207}
208
209pub type ArcRenderPassColorAttachment = RenderPassColorAttachment<Arc<TextureView>>;
210
211pub type ColorAttachments<TV = Arc<TextureView>> =
214 SmallVec<[Option<RenderPassColorAttachment<TV>>; 1]>;
215
216impl ArcRenderPassColorAttachment {
217 fn hal_ops(&self) -> hal::AttachmentOps {
218 load_hal_ops(self.load_op) | store_hal_ops(self.store_op)
219 }
220
221 fn clear_value(&self) -> Color {
222 match self.load_op {
223 LoadOp::Clear(clear_value) => clear_value,
224 LoadOp::DontCare(_) | LoadOp::Load => Color::default(),
225 }
226 }
227}
228
229#[repr(C)]
233#[derive(Clone, Debug, PartialEq)]
234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235pub struct RenderPassDepthStencilAttachment<TV> {
236 pub view: TV,
238 pub depth: PassChannel<Option<f32>>,
240 pub stencil: PassChannel<Option<u32>>,
242}
243
244#[derive(Clone, Debug)]
248#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
249pub struct ResolvedRenderPassDepthStencilAttachment<TV> {
250 pub view: TV,
252 pub depth: ResolvedPassChannel<f32>,
254 pub stencil: ResolvedPassChannel<u32>,
256}
257
258#[derive(Clone, Debug, Default, PartialEq)]
260#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
261pub struct RenderPassDescriptor<'a> {
262 pub label: Label<'a>,
263 pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
265 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<id::TextureViewId>>,
267 pub timestamp_writes: Option<PassTimestampWrites>,
269 pub occlusion_query_set: Option<id::QuerySetId>,
271 pub multiview_mask: Option<NonZeroU32>,
273}
274
275#[derive(Clone, Default)]
277pub struct ResolvedRenderPassDescriptor<'a> {
278 pub label: Label<'a>,
279 pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment<Arc<TextureView>>>]>,
281 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<Arc<TextureView>>>,
283 pub timestamp_writes: Option<PassTimestampWrites<Arc<QuerySet>>>,
285 pub occlusion_query_set: Option<Arc<QuerySet>>,
287 pub multiview_mask: Option<NonZeroU32>,
289}
290
291struct ArcRenderPassDescriptor<'a> {
293 pub label: &'a Label<'a>,
294 pub color_attachments:
296 ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
297 pub depth_stencil_attachment:
299 Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
300 pub timestamp_writes: Option<ArcPassTimestampWrites>,
302 pub occlusion_query_set: Option<Arc<QuerySet>>,
304 pub multiview_mask: Option<NonZeroU32>,
306}
307
308pub type RenderBasePass = BasePass<ArcRenderCommand, RenderPassError>;
309
310pub struct RenderPass {
318 base: BasePass<ArcRenderCommand, RenderPassError>,
320
321 parent: Option<Arc<CommandEncoder>>,
327
328 color_attachments:
329 ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
330 depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
331 timestamp_writes: Option<ArcPassTimestampWrites>,
332 occlusion_query_set: Option<Arc<QuerySet>>,
333 multiview_mask: Option<NonZeroU32>,
334
335 current_bind_groups: BindGroupStateChange,
337 current_pipeline: StateChange<id::RenderPipelineId>,
338}
339
340impl_resource_type!(RenderPass);
341
342impl crate::storage::StorageItem for RenderPass {
343 type Marker = id::markers::RenderPassEncoder;
344}
345
346impl RenderPass {
347 fn new(parent: Arc<CommandEncoder>, desc: ArcRenderPassDescriptor) -> Self {
349 let ArcRenderPassDescriptor {
350 label,
351 timestamp_writes,
352 color_attachments,
353 depth_stencil_attachment,
354 occlusion_query_set,
355 multiview_mask,
356 } = desc;
357
358 Self {
359 base: BasePass::new(label),
360 parent: Some(parent),
361 color_attachments,
362 depth_stencil_attachment,
363 timestamp_writes,
364 occlusion_query_set,
365 multiview_mask,
366
367 current_bind_groups: BindGroupStateChange::new(),
368 current_pipeline: StateChange::new(),
369 }
370 }
371
372 fn new_invalid(parent: Arc<CommandEncoder>, label: &Label, err: RenderPassError) -> Self {
373 Self {
374 base: BasePass::new_invalid(label, err),
375 parent: Some(parent),
376 color_attachments: ArrayVec::new(),
377 depth_stencil_attachment: None,
378 timestamp_writes: None,
379 occlusion_query_set: None,
380 multiview_mask: None,
381 current_bind_groups: BindGroupStateChange::new(),
382 current_pipeline: StateChange::new(),
383 }
384 }
385
386 #[inline]
387 pub fn label(&self) -> Option<&str> {
388 self.base.label.as_deref()
389 }
390}
391
392impl fmt::Debug for RenderPass {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 f.debug_struct("RenderPass")
395 .field("label", &self.label())
396 .field("color_attachments", &self.color_attachments)
397 .field("depth_stencil_target", &self.depth_stencil_attachment)
398 .field("command count", &self.base.commands.len())
399 .field("dynamic offset count", &self.base.dynamic_offsets.len())
400 .field("immediate data u32 count", &self.base.immediates_data.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 immediate_slots_set: naga::valid::ImmediateSlots,
687
688 active_occlusion_query: Option<(Arc<QuerySet>, u32)>,
689 active_pipeline_statistics_query: Option<(Arc<QuerySet>, u32)>,
690}
691
692impl<'scope, 'snatch_guard, 'cmd_enc> State<'scope, 'snatch_guard, 'cmd_enc> {
693 fn is_ready(&self, family: DrawCommandFamily) -> Result<(), DrawError> {
694 if let Some(pipeline) = self.pipeline.as_ref() {
695 self.pass.binder.check_compatibility(pipeline.as_ref())?;
696 self.pass.binder.check_late_buffer_bindings()?;
697
698 if self.blend_constant == OptionalState::Required {
699 return Err(DrawError::MissingBlendConstant);
700 }
701
702 self.vertex.validate(pipeline.as_ref(), &self.pass.binder)?;
703
704 if family == DrawCommandFamily::DrawIndexed {
705 let buffer_index_format = self
708 .index
709 .buffer_format
710 .ok_or(DrawError::MissingIndexBuffer)?;
711
712 if pipeline.topology.is_strip()
713 && pipeline.strip_index_format != Some(buffer_index_format)
714 {
715 return Err(DrawError::UnmatchedStripIndexFormat {
716 pipeline: pipeline.error_ident(),
717 strip_index_format: pipeline.strip_index_format,
718 buffer_format: buffer_index_format,
719 });
720 }
721 }
722 if (family == DrawCommandFamily::DrawMeshTasks) != pipeline.is_mesh {
723 return Err(DrawError::WrongPipelineType {
724 wanted_mesh_pipeline: !pipeline.is_mesh,
725 });
726 }
727 if !self
728 .immediate_slots_set
729 .contains(pipeline.immediate_slots_required)
730 {
731 return Err(DrawError::MissingImmediateData {
732 missing: pipeline
733 .immediate_slots_required
734 .difference(self.immediate_slots_set),
735 });
736 }
737 Ok(())
738 } else {
739 Err(DrawError::MissingPipeline(pass::MissingPipeline))
740 }
741 }
742
743 fn flush_bindings(&mut self) -> Result<(), RenderPassErrorInner> {
748 flush_bindings_helper(&mut self.pass)?;
749 Ok(())
750 }
751
752 fn reset_bundle(&mut self) {
754 self.pass.binder.reset();
755 self.pipeline = None;
756 self.index.reset();
757 self.vertex = Default::default();
758 self.immediate_slots_set = Default::default();
759 }
760
761 fn flush_vertex_buffers(&mut self) -> Result<(), RenderPassErrorInner> {
763 let vertex = &mut self.vertex;
764 let raw_encoder: &mut dyn hal::DynCommandEncoder = self.pass.base.raw_encoder;
765 let snatch_guard = self.pass.base.snatch_guard;
766 let mut result = Ok(());
767 vertex.flush(|slot, buffer, offset, size| {
768 if result.is_err() {
769 return;
770 }
771 match buffer.try_raw(snatch_guard) {
772 Ok(raw) => unsafe {
773 raw_encoder.set_vertex_buffer(
775 slot,
776 hal::BufferBinding::new_unchecked(raw, offset, size),
777 );
778 },
779 Err(e) => result = Err(e.into()),
780 }
781 });
782 result
783 }
784}
785
786#[derive(Debug, Copy, Clone)]
790pub enum AttachmentErrorLocation {
791 Color { index: usize, resolve: bool },
792 Depth,
793}
794
795impl fmt::Display for AttachmentErrorLocation {
796 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
797 match *self {
798 AttachmentErrorLocation::Color {
799 index,
800 resolve: false,
801 } => write!(f, "color attachment at index {index}'s texture view"),
802 AttachmentErrorLocation::Color {
803 index,
804 resolve: true,
805 } => write!(
806 f,
807 "color attachment at index {index}'s resolve texture view"
808 ),
809 AttachmentErrorLocation::Depth => write!(f, "depth attachment's texture view"),
810 }
811 }
812}
813
814#[derive(Clone, Debug, Error)]
815#[non_exhaustive]
816pub enum ColorAttachmentError {
817 #[error("Attachment format {0:?} is not a color format")]
818 InvalidFormat(wgt::TextureFormat),
819 #[error("The number of color attachments {given} exceeds the limit {limit}")]
820 TooMany { given: usize, limit: usize },
821 #[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
822 TooManyBytesPerSample { total: u32, limit: u32 },
823 #[error("Depth slice must be less than {limit} but is {given}")]
824 DepthSliceLimit { given: u32, limit: u32 },
825 #[error("Color attachment's view is 3D and requires depth slice to be provided")]
826 MissingDepthSlice,
827 #[error("Depth slice was provided but the color attachment's view is not 3D")]
828 UnneededDepthSlice,
829 #[error("{view}'s subresource at mip {mip_level} and depth/array layer {depth_or_array_layer} is already attached to this render pass")]
830 SubresourceOverlap {
831 view: ResourceErrorIdent,
832 mip_level: u32,
833 depth_or_array_layer: u32,
834 },
835 #[error(
836 "Color attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
837 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
838 )]
839 InvalidTransientAttachmentOp((LoadOp<Color>, StoreOp)),
840 #[error("Color attachment's load op is `LoadOp::DontCare` but `InstanceFlags::STRICT_WEBGPU_COMPLIANCE` is set")]
841 LoadOpDontCareUnderStrictWebgpuCompliance,
842}
843
844impl WebGpuError for ColorAttachmentError {
845 fn webgpu_error_type(&self) -> ErrorType {
846 ErrorType::Validation
847 }
848}
849
850#[derive(Clone, Debug, Error)]
851#[non_exhaustive]
852pub enum AttachmentError {
853 #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-or-stencil format")]
854 InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
855 #[error(
856 "Depth attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
857 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
858 )]
859 InvalidTransientDepthAttachmentOps((LoadOp<Option<f32>>, StoreOp)),
860 #[error("Depth attachment with `TRANSIENT_ATTACHMENT` usage cannot be read-only")]
861 ReadOnlyTransientDepthAttachment,
862 #[error(
863 "Stencil attachment with `TRANSIENT_ATTACHMENT` usage can only be used with \
864 `LoadOp::Clear` or `LoadOp::DontCare` (if it is available) and `StoreOp::Discard`. Operations `{0:?}` were provided"
865 )]
866 InvalidTransientStencilAttachmentOps((LoadOp<Option<u32>>, StoreOp)),
867 #[error("Stencil attachment with `TRANSIENT_ATTACHMENT` usage cannot be read-only")]
868 ReadOnlyTransientStencilAttachment,
869 #[error("LoadOp must be None for read-only attachments")]
870 ReadOnlyWithLoad,
871 #[error("StoreOp must be None for read-only attachments")]
872 ReadOnlyWithStore,
873 #[error("Depth `LoadOp` and `StoreOp` (`{ops:?}`) must be `None` for attachments (`{format:?}`) without depth aspect")]
874 DepthOpsWithoutAspect {
875 format: wgt::TextureFormat,
876 ops: (Option<LoadOp<Option<f32>>>, Option<StoreOp>),
877 },
878 #[error("Stencil `LoadOp` and `StoreOp` (`{ops:?}`) must be `None` for attachments (`{format:?}`) without stencil aspect")]
879 StencilOpsWithoutAspect {
880 format: wgt::TextureFormat,
881 ops: (Option<LoadOp<Option<u32>>>, Option<StoreOp>),
882 },
883 #[error("Attachment without load")]
884 NoLoad,
885 #[error("Attachment without store")]
886 NoStore,
887 #[error("LoadOp is `Clear` but no clear value was provided")]
888 NoClearValue,
889 #[error("Clear value ({0}) must be between 0.0 and 1.0, inclusive")]
890 ClearValueOutOfRange(f32),
891 #[error("Load op is `DontCare` but `InstanceFlags::STRICT_WEBGPU_COMPLIANCE` is set")]
892 LoadOpDontCareUnderStrictWebgpuCompliance,
893}
894
895impl WebGpuError for AttachmentError {
896 fn webgpu_error_type(&self) -> ErrorType {
897 ErrorType::Validation
898 }
899}
900
901#[derive(Clone, Debug, Error)]
903pub enum RenderPassErrorInner {
904 #[error(transparent)]
905 Device(#[from] DeviceError),
906 #[error(transparent)]
907 ColorAttachment(#[from] ColorAttachmentError),
908 #[error(transparent)]
909 InvalidAttachment(#[from] AttachmentError),
910 #[error(transparent)]
911 EncoderState(#[from] EncoderStateError),
912 #[error("Parent encoder is invalid")]
913 InvalidParentEncoder,
914 #[error(transparent)]
915 DebugGroupError(#[from] DebugGroupError),
916 #[error("The format of the {location} ({format:?}) is not resolvable")]
917 UnsupportedResolveTargetFormat {
918 location: AttachmentErrorLocation,
919 format: wgt::TextureFormat,
920 },
921 #[error("The {location} is not valid, because the texture has `TRANSIENT_ATTACHMENT` usage")]
922 InvalidTransientResolveTarget { location: AttachmentErrorLocation },
923 #[error("No color attachments or depth attachments were provided, at least one attachment of any kind must be provided")]
924 MissingAttachments,
925 #[error("The {location} is not renderable:")]
926 TextureViewIsNotRenderable {
927 location: AttachmentErrorLocation,
928 #[source]
929 reason: TextureViewNotRenderableReason,
930 },
931 #[error("Attachments have differing sizes: the {expected_location} has extent {expected_extent:?} but is followed by the {actual_location} which has {actual_extent:?}")]
932 AttachmentsDimensionMismatch {
933 expected_location: AttachmentErrorLocation,
934 expected_extent: wgt::Extent3d,
935 actual_location: AttachmentErrorLocation,
936 actual_extent: wgt::Extent3d,
937 },
938 #[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:?}")]
939 AttachmentSampleCountMismatch {
940 expected_location: AttachmentErrorLocation,
941 expected_samples: u32,
942 actual_location: AttachmentErrorLocation,
943 actual_samples: u32,
944 },
945 #[error("The resolve source, {location}, must be multi-sampled (has {src} samples) while the resolve destination must not be multisampled (has {dst} samples)")]
946 InvalidResolveSampleCounts {
947 location: AttachmentErrorLocation,
948 src: u32,
949 dst: u32,
950 },
951 #[error(
952 "Resource source, {location}, format ({src:?}) must match the resolve destination format ({dst:?})"
953 )]
954 MismatchedResolveTextureFormat {
955 location: AttachmentErrorLocation,
956 src: wgt::TextureFormat,
957 dst: wgt::TextureFormat,
958 },
959 #[error("Unable to clear non-present/read-only depth")]
960 InvalidDepthOps,
961 #[error("Unable to clear non-present/read-only stencil")]
962 InvalidStencilOps,
963 #[error(transparent)]
964 InvalidValuesOffset(#[from] pass::InvalidValuesOffset),
965 #[error(transparent)]
966 MissingFeatures(#[from] MissingFeatures),
967 #[error(transparent)]
968 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
969 #[error("Indirect buffer offset {0:?} is not a multiple of 4")]
970 UnalignedIndirectBufferOffset(BufferAddress),
971 #[error("Indirect draw arguments of {args_size} bytes (count = {count}) starting at {offset} would overrun buffer size of {buffer_size}")]
972 IndirectBufferOverrun {
973 count: u32,
974 offset: u64,
975 args_size: u64,
976 buffer_size: u64,
977 },
978 #[error("Indirect draw count of {count_bytes} bytes starting at {begin_count_offset} would overrun buffer of size {count_buffer_size}")]
979 IndirectCountBufferOverrun {
980 count_bytes: u64,
981 begin_count_offset: u64,
982 count_buffer_size: u64,
983 },
984 #[error(transparent)]
985 ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
986 #[error("Render bundle has incompatible targets, {0}")]
987 IncompatibleBundleTargets(#[from] RenderPassCompatibilityError),
988 #[error(
989 "Render bundle has incompatible read-only flags: \
990 bundle has flags depth = {bundle_depth} and stencil = {bundle_stencil}, \
991 while the pass has flags depth = {pass_depth} and stencil = {pass_stencil}. \
992 Read-only renderpasses are only compatible with read-only bundles for that aspect."
993 )]
994 IncompatibleBundleReadOnlyDepthStencil {
995 pass_depth: bool,
996 pass_stencil: bool,
997 bundle_depth: bool,
998 bundle_stencil: bool,
999 },
1000 #[error(transparent)]
1001 RenderCommand(#[from] RenderCommandError),
1002 #[error(transparent)]
1003 Draw(#[from] DrawError),
1004 #[error(transparent)]
1005 Bind(#[from] BindError),
1006 #[error(transparent)]
1007 QueryUse(#[from] QueryUseError),
1008 #[error("Multiview layer count must match")]
1009 MultiViewMismatch,
1010 #[error(
1011 "Multiview pass texture views with more than one array layer must have D2Array dimension"
1012 )]
1013 MultiViewDimensionMismatch,
1014 #[error("Multiview view count limit violated")]
1015 TooManyMultiviewViews,
1016 #[error("missing occlusion query set")]
1017 MissingOcclusionQuerySet,
1018 #[error(transparent)]
1019 DestroyedResource(#[from] DestroyedResourceError),
1020 #[error("The compute pass has already been ended and no further commands can be recorded")]
1021 PassEnded,
1022 #[error(transparent)]
1023 InvalidResource(#[from] InvalidResourceError),
1024 #[error(transparent)]
1025 TimestampWrites(#[from] TimestampWritesError),
1026}
1027
1028impl From<MissingBufferUsageError> for RenderPassErrorInner {
1029 fn from(error: MissingBufferUsageError) -> Self {
1030 Self::RenderCommand(error.into())
1031 }
1032}
1033
1034impl From<MissingTextureUsageError> for RenderPassErrorInner {
1035 fn from(error: MissingTextureUsageError) -> Self {
1036 Self::RenderCommand(error.into())
1037 }
1038}
1039
1040impl From<pass::BindGroupIndexOutOfRange> for RenderPassErrorInner {
1041 fn from(error: pass::BindGroupIndexOutOfRange) -> Self {
1042 Self::RenderCommand(RenderCommandError::BindGroupIndexOutOfRange(error))
1043 }
1044}
1045
1046impl From<pass::MissingPipeline> for RenderPassErrorInner {
1047 fn from(error: pass::MissingPipeline) -> Self {
1048 Self::Draw(DrawError::MissingPipeline(error))
1049 }
1050}
1051
1052impl From<ImmediateUploadError> for RenderPassErrorInner {
1053 fn from(error: ImmediateUploadError) -> Self {
1054 Self::RenderCommand(error.into())
1055 }
1056}
1057
1058#[derive(Clone, Debug, Error)]
1060#[error("{scope}")]
1061pub struct RenderPassError {
1062 pub scope: PassErrorScope,
1063 #[source]
1064 pub(super) inner: RenderPassErrorInner,
1065}
1066
1067impl<E: Into<RenderPassErrorInner>> MapPassErr<RenderPassError> for E {
1068 fn map_pass_err(self, scope: PassErrorScope) -> RenderPassError {
1069 RenderPassError {
1070 scope,
1071 inner: self.into(),
1072 }
1073 }
1074}
1075
1076impl WebGpuError for RenderPassError {
1077 fn webgpu_error_type(&self) -> ErrorType {
1078 let Self { scope: _, inner } = self;
1079 match inner {
1080 RenderPassErrorInner::Device(e) => e.webgpu_error_type(),
1081 RenderPassErrorInner::ColorAttachment(e) => e.webgpu_error_type(),
1082 RenderPassErrorInner::EncoderState(e) => e.webgpu_error_type(),
1083 RenderPassErrorInner::DebugGroupError(e) => e.webgpu_error_type(),
1084 RenderPassErrorInner::MissingFeatures(e) => e.webgpu_error_type(),
1085 RenderPassErrorInner::MissingDownlevelFlags(e) => e.webgpu_error_type(),
1086 RenderPassErrorInner::RenderCommand(e) => e.webgpu_error_type(),
1087 RenderPassErrorInner::Draw(e) => e.webgpu_error_type(),
1088 RenderPassErrorInner::Bind(e) => e.webgpu_error_type(),
1089 RenderPassErrorInner::QueryUse(e) => e.webgpu_error_type(),
1090 RenderPassErrorInner::DestroyedResource(e) => e.webgpu_error_type(),
1091 RenderPassErrorInner::InvalidResource(e) => e.webgpu_error_type(),
1092 RenderPassErrorInner::IncompatibleBundleTargets(e) => e.webgpu_error_type(),
1093 RenderPassErrorInner::InvalidAttachment(e) => e.webgpu_error_type(),
1094 RenderPassErrorInner::TimestampWrites(e) => e.webgpu_error_type(),
1095 RenderPassErrorInner::InvalidValuesOffset(e) => e.webgpu_error_type(),
1096
1097 RenderPassErrorInner::InvalidParentEncoder
1098 | RenderPassErrorInner::UnsupportedResolveTargetFormat { .. }
1099 | RenderPassErrorInner::InvalidTransientResolveTarget { .. }
1100 | RenderPassErrorInner::MissingAttachments
1101 | RenderPassErrorInner::TextureViewIsNotRenderable { .. }
1102 | RenderPassErrorInner::AttachmentsDimensionMismatch { .. }
1103 | RenderPassErrorInner::AttachmentSampleCountMismatch { .. }
1104 | RenderPassErrorInner::InvalidResolveSampleCounts { .. }
1105 | RenderPassErrorInner::MismatchedResolveTextureFormat { .. }
1106 | RenderPassErrorInner::InvalidDepthOps
1107 | RenderPassErrorInner::InvalidStencilOps
1108 | RenderPassErrorInner::UnalignedIndirectBufferOffset(..)
1109 | RenderPassErrorInner::IndirectBufferOverrun { .. }
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 Global {
2145 pub fn command_encoder_begin_render_pass(
2156 &self,
2157 encoder_id: id::CommandEncoderId,
2158 desc: &RenderPassDescriptor<'_>,
2159 ) -> (RenderPass, Option<CommandEncoderError>) {
2160 let hub = &self.hub;
2161
2162 let cmd_enc = hub.command_encoders.get(encoder_id);
2163
2164 let texture_views = hub.texture_views.read();
2165 let query_sets = hub.query_sets.read();
2166
2167 let desc = ResolvedRenderPassDescriptor {
2168 label: desc.label.as_deref().map(Cow::Borrowed),
2169 color_attachments: Cow::Owned(
2170 desc.color_attachments
2171 .iter()
2172 .map(|at| {
2173 at.as_ref().map(|at| RenderPassColorAttachment {
2174 view: texture_views.get(at.view),
2175 depth_slice: at.depth_slice,
2176 resolve_target: at
2177 .resolve_target
2178 .as_ref()
2179 .map(|rt| texture_views.get(*rt)),
2180 load_op: at.load_op,
2181 store_op: at.store_op,
2182 })
2183 })
2184 .collect(),
2185 ),
2186 depth_stencil_attachment: desc.depth_stencil_attachment.as_ref().map(|at| {
2187 RenderPassDepthStencilAttachment {
2188 view: texture_views.get(at.view),
2189 depth: at.depth.clone(),
2190 stencil: at.stencil.clone(),
2191 }
2192 }),
2193 timestamp_writes: desc
2194 .timestamp_writes
2195 .as_ref()
2196 .map(|tw| PassTimestampWrites {
2197 query_set: query_sets.get(tw.query_set),
2198 beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
2199 end_of_pass_write_index: tw.end_of_pass_write_index,
2200 }),
2201 occlusion_query_set: desc
2202 .occlusion_query_set
2203 .as_ref()
2204 .map(|query_set| query_sets.get(*query_set)),
2205 multiview_mask: desc.multiview_mask,
2206 };
2207
2208 drop(texture_views);
2209 drop(query_sets);
2210
2211 cmd_enc.begin_render_pass(desc)
2212 }
2213
2214 pub fn command_encoder_begin_render_pass_with_id(
2215 &self,
2216 encoder_id: id::CommandEncoderId,
2217 desc: &RenderPassDescriptor<'_>,
2218 id_in: Option<id::RenderPassEncoderId>,
2219 ) -> (id::RenderPassEncoderId, Option<CommandEncoderError>) {
2220 let hub = &self.hub;
2221 let fid = hub.render_passes.prepare(id_in);
2222 let (render_pass, error) = self.command_encoder_begin_render_pass(encoder_id, desc);
2223 let id = fid.assign(Arc::new(Mutex::new(render_pass)));
2227 (id, error)
2228 }
2229
2230 pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
2231 profiling::scope!(
2232 "CommandEncoder::run_render_pass {}",
2233 pass.base.label.as_deref().unwrap_or("")
2234 );
2235
2236 let cmd_enc = pass.parent.take().ok_or(EncoderStateError::Ended)?;
2237 let mut cmd_buf_data = cmd_enc.data.lock();
2238
2239 cmd_buf_data.unlock_encoder()?;
2240
2241 let base = pass.base.take();
2242
2243 if let Err(RenderPassError {
2244 inner:
2245 RenderPassErrorInner::EncoderState(
2246 err @ (EncoderStateError::Locked | EncoderStateError::Ended),
2247 ),
2248 scope: _,
2249 }) = base
2250 {
2251 return Err(err.clone());
2258 }
2259
2260 cmd_buf_data.push_with(|| -> Result<_, RenderPassError> {
2261 Ok(ArcCommand::RunRenderPass {
2262 pass: base?,
2263 color_attachments: SmallVec::from(pass.color_attachments.as_slice()),
2264 depth_stencil_attachment: pass.depth_stencil_attachment.take(),
2265 timestamp_writes: pass.timestamp_writes.take(),
2266 occlusion_query_set: pass.occlusion_query_set.take(),
2267 multiview_mask: pass.multiview_mask,
2268 })
2269 })
2270 }
2271
2272 pub fn render_pass_end_with_id(
2273 &self,
2274 pass: id::RenderPassEncoderId,
2275 ) -> Result<(), EncoderStateError> {
2276 let pass = self.hub.render_passes.get(pass);
2277 let mut pass = pass
2278 .try_lock()
2279 .expect("RenderPasses should not be accessed concurrently");
2280 self.render_pass_end(&mut pass)
2281 }
2282
2283 pub fn render_pass_drop(&self, pass: id::RenderPassEncoderId) {
2284 self.hub.render_passes.remove(pass);
2285 }
2286}
2287
2288pub(super) fn encode_render_pass(
2289 parent_state: &mut EncodingState<InnerCommandEncoder>,
2290 mut base: BasePass<ArcRenderCommand, Infallible>,
2291 color_attachments: ColorAttachments<Arc<TextureView>>,
2292 mut depth_stencil_attachment: Option<
2293 ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>,
2294 >,
2295 mut timestamp_writes: Option<ArcPassTimestampWrites>,
2296 occlusion_query_set: Option<Arc<QuerySet>>,
2297 multiview_mask: Option<NonZeroU32>,
2298) -> Result<(), RenderPassError> {
2299 let pass_scope = PassErrorScope::Pass;
2300
2301 let device = parent_state.device;
2302
2303 let mut indirect_draw_validation_batcher = crate::indirect_validation::DrawBatcher::new();
2304
2305 parent_state
2309 .raw_encoder
2310 .close_if_open()
2311 .map_pass_err(pass_scope)?;
2312 let raw_encoder = parent_state
2313 .raw_encoder
2314 .open_pass(base.label.as_deref())
2315 .map_pass_err(pass_scope)?;
2316
2317 let (scope, pending_discard_init_fixups, mut pending_query_resets) = {
2318 let mut pending_query_resets = QueryResetMap::new();
2319 let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
2320
2321 let info = RenderPassInfo::start(
2322 device,
2323 hal_label(base.label.as_deref(), device.instance_flags),
2324 &color_attachments,
2325 depth_stencil_attachment.take(),
2326 timestamp_writes.take(),
2327 occlusion_query_set.clone(),
2330 raw_encoder,
2331 parent_state.tracker,
2332 parent_state.texture_memory_actions,
2333 &mut pending_query_resets,
2334 &mut pending_discard_init_fixups,
2335 parent_state.snatch_guard,
2336 parent_state.query_set_writes,
2337 multiview_mask,
2338 )
2339 .map_pass_err(pass_scope)?;
2340
2341 let indices = &device.tracker_indices;
2342 parent_state
2343 .tracker
2344 .buffers
2345 .set_size(indices.buffers.size());
2346 parent_state
2347 .tracker
2348 .textures
2349 .set_size(indices.textures.size());
2350
2351 let mut debug_scope_depth = 0;
2352
2353 let mut state = State {
2354 pipeline_flags: PipelineFlags::empty(),
2355 blend_constant: OptionalState::Unused,
2356 stencil_reference: 0,
2357 pipeline: None,
2358 index: IndexState::default(),
2359 vertex: VertexState::default(),
2360
2361 info,
2362
2363 pass: pass::PassState {
2364 base: EncodingState {
2365 device,
2366 raw_encoder,
2367 tracker: parent_state.tracker,
2368 buffer_memory_init_actions: parent_state.buffer_memory_init_actions,
2369 texture_memory_actions: parent_state.texture_memory_actions,
2370 as_actions: parent_state.as_actions,
2371 temp_resources: parent_state.temp_resources,
2372 indirect_draw_validation_resources: parent_state
2373 .indirect_draw_validation_resources,
2374 snatch_guard: parent_state.snatch_guard,
2375 debug_scope_depth: &mut debug_scope_depth,
2376 query_set_writes: parent_state.query_set_writes,
2377 deferred_query_set_resolves: parent_state.deferred_query_set_resolves,
2378 },
2379 pending_discard_init_fixups,
2380 scope: device.new_usage_scope(),
2381 binder: Binder::new(),
2382
2383 temp_offsets: Vec::new(),
2384 dynamic_offset_count: 0,
2385
2386 string_offset: 0,
2387 },
2388
2389 immediate_slots_set: Default::default(),
2390
2391 active_occlusion_query: None,
2392 active_pipeline_statistics_query: None,
2393 };
2394
2395 for command in base.commands.drain(..) {
2396 match command {
2397 ArcRenderCommand::SetBindGroup {
2398 index,
2399 num_dynamic_offsets,
2400 bind_group,
2401 } => {
2402 let scope = PassErrorScope::SetBindGroup;
2403 pass::set_bind_group::<RenderPassErrorInner>(
2404 &mut state.pass,
2405 device,
2406 &base.dynamic_offsets,
2407 index,
2408 num_dynamic_offsets,
2409 bind_group,
2410 true,
2411 )
2412 .map_pass_err(scope)?;
2413 }
2414 ArcRenderCommand::SetPipeline(pipeline) => {
2415 let scope = PassErrorScope::SetPipelineRender;
2416 set_pipeline(&mut state, device, pipeline).map_pass_err(scope)?;
2417 }
2418 ArcRenderCommand::SetIndexBuffer {
2419 buffer,
2420 index_format,
2421 offset,
2422 size,
2423 } => {
2424 let scope = PassErrorScope::SetIndexBuffer;
2425 set_index_buffer(&mut state, device, buffer, index_format, offset, size)
2426 .map_pass_err(scope)?;
2427 }
2428 ArcRenderCommand::SetVertexBuffer {
2429 slot,
2430 buffer,
2431 offset,
2432 size,
2433 } => {
2434 let scope = PassErrorScope::SetVertexBuffer;
2435 set_vertex_buffer(&mut state, device, slot, buffer, offset, size)
2436 .map_pass_err(scope)?;
2437 }
2438 ArcRenderCommand::SetBlendConstant(ref color) => {
2439 set_blend_constant(&mut state, color);
2440 }
2441 ArcRenderCommand::SetStencilReference(value) => {
2442 set_stencil_reference(&mut state, value);
2443 }
2444 ArcRenderCommand::SetViewport {
2445 rect,
2446 depth_min,
2447 depth_max,
2448 } => {
2449 let scope = PassErrorScope::SetViewport;
2450 set_viewport(&mut state, rect, depth_min, depth_max).map_pass_err(scope)?;
2451 }
2452 ArcRenderCommand::SetImmediate {
2453 offset,
2454 size_bytes,
2455 values_offset,
2456 } => {
2457 let scope = PassErrorScope::SetImmediate;
2458 pass::set_immediates::<RenderPassErrorInner, _>(
2459 &mut state.pass,
2460 &base.immediates_data,
2461 offset,
2462 size_bytes,
2463 values_offset,
2464 |_| {},
2465 )
2466 .map_pass_err(scope)?;
2467 state.immediate_slots_set |=
2468 naga::valid::ImmediateSlots::from_range(offset, size_bytes);
2469 }
2470 ArcRenderCommand::SetScissor(rect) => {
2471 let scope = PassErrorScope::SetScissorRect;
2472 set_scissor(&mut state, rect).map_pass_err(scope)?;
2473 }
2474 ArcRenderCommand::Draw {
2475 vertex_count,
2476 instance_count,
2477 first_vertex,
2478 first_instance,
2479 } => {
2480 let scope = PassErrorScope::Draw {
2481 kind: DrawKind::Draw,
2482 family: DrawCommandFamily::Draw,
2483 };
2484 draw(
2485 &mut state,
2486 vertex_count,
2487 instance_count,
2488 first_vertex,
2489 first_instance,
2490 )
2491 .map_pass_err(scope)?;
2492 }
2493 ArcRenderCommand::DrawIndexed {
2494 index_count,
2495 instance_count,
2496 first_index,
2497 base_vertex,
2498 first_instance,
2499 } => {
2500 let scope = PassErrorScope::Draw {
2501 kind: DrawKind::Draw,
2502 family: DrawCommandFamily::DrawIndexed,
2503 };
2504 draw_indexed(
2505 &mut state,
2506 index_count,
2507 instance_count,
2508 first_index,
2509 base_vertex,
2510 first_instance,
2511 )
2512 .map_pass_err(scope)?;
2513 }
2514 ArcRenderCommand::DrawMeshTasks {
2515 group_count_x,
2516 group_count_y,
2517 group_count_z,
2518 } => {
2519 let scope = PassErrorScope::Draw {
2520 kind: DrawKind::Draw,
2521 family: DrawCommandFamily::DrawMeshTasks,
2522 };
2523 draw_mesh_tasks(&mut state, group_count_x, group_count_y, group_count_z)
2524 .map_pass_err(scope)?;
2525 }
2526 ArcRenderCommand::DrawIndirect {
2527 buffer,
2528 offset,
2529 count,
2530 family,
2531
2532 vertex_or_index_limit: _,
2533 instance_limit: _,
2534 } => {
2535 let scope = PassErrorScope::Draw {
2536 kind: if count != 1 {
2537 DrawKind::MultiDrawIndirect
2538 } else {
2539 DrawKind::DrawIndirect
2540 },
2541 family,
2542 };
2543 multi_draw_indirect(
2544 &mut state,
2545 &mut indirect_draw_validation_batcher,
2546 device,
2547 buffer,
2548 offset,
2549 count,
2550 family,
2551 )
2552 .map_pass_err(scope)?;
2553 }
2554 ArcRenderCommand::MultiDrawIndirectCount {
2555 buffer,
2556 offset,
2557 count_buffer,
2558 count_buffer_offset,
2559 max_count,
2560 family,
2561 } => {
2562 let scope = PassErrorScope::Draw {
2563 kind: DrawKind::MultiDrawIndirectCount,
2564 family,
2565 };
2566 multi_draw_indirect_count(
2567 &mut state,
2568 device,
2569 buffer,
2570 offset,
2571 count_buffer,
2572 count_buffer_offset,
2573 max_count,
2574 family,
2575 )
2576 .map_pass_err(scope)?;
2577 }
2578 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2579 pass::push_debug_group(&mut state.pass, &base.string_data, len);
2580 }
2581 ArcRenderCommand::PopDebugGroup => {
2582 let scope = PassErrorScope::PopDebugGroup;
2583 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.pass)
2584 .map_pass_err(scope)?;
2585 }
2586 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2587 pass::insert_debug_marker(&mut state.pass, &base.string_data, len);
2588 }
2589 ArcRenderCommand::WriteTimestamp {
2590 query_set,
2591 query_index,
2592 } => {
2593 let scope = PassErrorScope::WriteTimestamp;
2594 pass::write_timestamp::<RenderPassErrorInner>(
2595 &mut state.pass,
2596 device,
2597 Some(&mut pending_query_resets),
2598 query_set,
2599 query_index,
2600 )
2601 .map_pass_err(scope)?;
2602 }
2603 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2604 api_log!("RenderPass::begin_occlusion_query {query_index}");
2605 let scope = PassErrorScope::BeginOcclusionQuery;
2606
2607 let query_set = occlusion_query_set
2608 .clone()
2609 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2610 .map_pass_err(scope)?;
2611
2612 validate_and_begin_occlusion_query(
2613 query_set,
2614 state.pass.base.raw_encoder,
2615 &mut state.pass.base.tracker.query_sets,
2616 query_index,
2617 Some(&mut pending_query_resets),
2618 &mut state.active_occlusion_query,
2619 state.pass.base.snatch_guard,
2620 )
2621 .map_pass_err(scope)?;
2622 }
2623 ArcRenderCommand::EndOcclusionQuery => {
2624 api_log!("RenderPass::end_occlusion_query");
2625 let scope = PassErrorScope::EndOcclusionQuery;
2626
2627 end_occlusion_query(
2628 state.pass.base.raw_encoder,
2629 &mut state.active_occlusion_query,
2630 state.pass.base.snatch_guard,
2631 state.pass.base.query_set_writes,
2632 )
2633 .map_pass_err(scope)?;
2634 }
2635 ArcRenderCommand::BeginPipelineStatisticsQuery {
2636 query_set,
2637 query_index,
2638 } => {
2639 api_log!(
2640 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2641 query_set.error_ident()
2642 );
2643 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2644
2645 validate_and_begin_pipeline_statistics_query(
2646 query_set,
2647 state.pass.base.raw_encoder,
2648 &mut state.pass.base.tracker.query_sets,
2649 device,
2650 query_index,
2651 Some(&mut pending_query_resets),
2652 &mut state.active_pipeline_statistics_query,
2653 state.pass.base.snatch_guard,
2654 )
2655 .map_pass_err(scope)?;
2656 }
2657 ArcRenderCommand::EndPipelineStatisticsQuery => {
2658 api_log!("RenderPass::end_pipeline_statistics_query");
2659 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2660
2661 end_pipeline_statistics_query(
2662 state.pass.base.raw_encoder,
2663 &mut state.active_pipeline_statistics_query,
2664 state.pass.base.snatch_guard,
2665 state.pass.base.query_set_writes,
2666 )
2667 .map_pass_err(scope)?;
2668 }
2669 ArcRenderCommand::ExecuteBundle(bundle) => {
2670 let scope = PassErrorScope::ExecuteBundle;
2671 execute_bundle(
2672 &mut state,
2673 &mut indirect_draw_validation_batcher,
2674 device,
2675 bundle,
2676 )
2677 .map_pass_err(scope)?;
2678 }
2679 }
2680 }
2681
2682 if *state.pass.base.debug_scope_depth > 0 {
2683 Err(
2684 RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2685 .map_pass_err(pass_scope),
2686 )?;
2687 }
2688 if state.active_occlusion_query.is_some() {
2689 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2690 query_type: super::SimplifiedQueryType::Occlusion,
2691 })
2692 .map_pass_err(pass_scope))?;
2693 }
2694 if state.active_pipeline_statistics_query.is_some() {
2695 Err(RenderPassErrorInner::QueryUse(QueryUseError::MissingEnd {
2696 query_type: super::SimplifiedQueryType::PipelineStatistics,
2697 })
2698 .map_pass_err(pass_scope))?;
2699 }
2700
2701 state
2702 .info
2703 .finish(
2704 device,
2705 state.pass.base.raw_encoder,
2706 state.pass.base.snatch_guard,
2707 &mut state.pass.scope,
2708 device.instance_flags,
2709 )
2710 .map_pass_err(pass_scope)?;
2711
2712 let trackers = state.pass.scope;
2713
2714 let pending_discard_init_fixups = state.pass.pending_discard_init_fixups;
2715
2716 parent_state.raw_encoder.close().map_pass_err(pass_scope)?;
2717 (trackers, pending_discard_init_fixups, pending_query_resets)
2718 };
2719
2720 let encoder = &mut parent_state.raw_encoder;
2721 let tracker = &mut parent_state.tracker;
2722
2723 {
2724 let transit = encoder
2725 .open_pass(hal_label(
2726 Some("(wgpu internal) Pre Pass"),
2727 device.instance_flags,
2728 ))
2729 .map_pass_err(pass_scope)?;
2730
2731 fixup_discarded_surfaces(
2732 pending_discard_init_fixups.into_iter(),
2733 transit,
2734 &mut tracker.textures,
2735 device,
2736 parent_state.snatch_guard,
2737 );
2738
2739 pending_query_resets
2740 .reset_queries(transit, parent_state.snatch_guard)
2741 .map_pass_err(pass_scope)?;
2742
2743 CommandEncoder::insert_barriers_from_scope(
2744 transit,
2745 tracker,
2746 &scope,
2747 parent_state.snatch_guard,
2748 );
2749
2750 if let Some(ref indirect_validation) = device.indirect_validation {
2751 indirect_validation
2752 .draw
2753 .inject_validation_pass(
2754 device,
2755 parent_state.snatch_guard,
2756 parent_state.indirect_draw_validation_resources,
2757 parent_state.temp_resources,
2758 transit,
2759 indirect_draw_validation_batcher,
2760 )
2761 .map_pass_err(pass_scope)?;
2762 }
2763 }
2764
2765 encoder.close_and_swap().map_pass_err(pass_scope)?;
2766
2767 Ok(())
2768}
2769
2770fn set_pipeline(
2771 state: &mut State,
2772 device: &Arc<Device>,
2773 pipeline: Arc<RenderPipeline>,
2774) -> Result<(), RenderPassErrorInner> {
2775 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2776
2777 state.pipeline = Some(pipeline.clone());
2778
2779 let pipeline = state
2780 .pass
2781 .base
2782 .tracker
2783 .render_pipelines
2784 .insert_single(pipeline)
2785 .clone();
2786
2787 pipeline.same_device(device)?;
2788
2789 state
2790 .info
2791 .context
2792 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2793 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2794
2795 state.pipeline_flags = pipeline.flags;
2796
2797 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2798 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2799 }
2800 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2801 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2802 }
2803
2804 state
2805 .blend_constant
2806 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2807
2808 unsafe {
2809 state
2810 .pass
2811 .base
2812 .raw_encoder
2813 .set_render_pipeline(pipeline.raw()?);
2814 }
2815
2816 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2817 unsafe {
2818 state
2819 .pass
2820 .base
2821 .raw_encoder
2822 .set_stencil_reference(state.stencil_reference);
2823 }
2824 }
2825
2826 pass::change_pipeline_layout::<RenderPassErrorInner, _>(
2828 &mut state.pass,
2829 pipeline.layout()?,
2830 &pipeline.late_sized_buffer_groups,
2831 || {},
2832 )?;
2833
2834 state.vertex.update_limits(&pipeline.vertex_steps);
2836 Ok(())
2837}
2838
2839fn set_index_buffer(
2841 state: &mut State,
2842 device: &Arc<Device>,
2843 buffer: Arc<Buffer>,
2844 index_format: IndexFormat,
2845 offset: u64,
2846 size: Option<BufferSize>,
2847) -> Result<(), RenderPassErrorInner> {
2848 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2849
2850 state
2851 .pass
2852 .scope
2853 .buffers
2854 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2855
2856 buffer.same_device(device)?;
2857
2858 buffer.check_usage(BufferUsages::INDEX)?;
2859
2860 if !offset.is_multiple_of(u64::from(index_format.byte_size())) {
2861 return Err(RenderCommandError::UnalignedIndexBuffer {
2862 offset,
2863 alignment: index_format.byte_size() as usize,
2864 }
2865 .into());
2866 }
2867 let (binding, resolved_size) = buffer
2868 .binding(offset, size, state.pass.base.snatch_guard)
2869 .map_err(RenderCommandError::from)?;
2870 let end = offset + resolved_size;
2871 state.index.update_buffer(offset..end, index_format);
2872
2873 state.pass.base.buffer_memory_init_actions.extend(
2874 buffer.initialization_status.read().create_action(
2875 &buffer,
2876 offset..end,
2877 MemoryInitKind::NeedsInitializedMemory,
2878 ),
2879 );
2880
2881 unsafe {
2882 hal::DynCommandEncoder::set_index_buffer(
2883 state.pass.base.raw_encoder,
2884 binding,
2885 index_format,
2886 );
2887 }
2888 Ok(())
2889}
2890
2891fn set_vertex_buffer(
2893 state: &mut State,
2894 device: &Arc<Device>,
2895 slot: u32,
2896 buffer: Option<Arc<Buffer>>,
2897 offset: u64,
2898 size: Option<BufferSize>,
2899) -> Result<(), RenderPassErrorInner> {
2900 if let Some(ref buffer) = buffer {
2901 api_log!(
2902 "RenderPass::set_vertex_buffer {slot} {}",
2903 buffer.error_ident()
2904 );
2905 } else {
2906 api_log!("RenderPass::set_vertex_buffer {slot} None");
2907 }
2908
2909 let max_vertex_buffers = state.pass.base.device.limits.max_vertex_buffers;
2910 if slot >= max_vertex_buffers {
2911 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2912 index: slot,
2913 max: max_vertex_buffers,
2914 }
2915 .into());
2916 }
2917
2918 if let Some(buffer) = buffer {
2919 buffer.same_device(device)?;
2920 buffer.check_usage(BufferUsages::VERTEX)?;
2921
2922 if !offset.is_multiple_of(wgt::VERTEX_ALIGNMENT) {
2923 return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2924 }
2925 let binding_size = buffer
2926 .resolve_binding_size(offset, size)
2927 .map_err(RenderCommandError::from)?;
2928 let buffer_range = offset..(offset + binding_size);
2929
2930 state
2931 .pass
2932 .scope
2933 .buffers
2934 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2935
2936 state.pass.base.buffer_memory_init_actions.extend(
2937 buffer.initialization_status.read().create_action(
2938 &buffer,
2939 buffer_range.clone(),
2940 MemoryInitKind::NeedsInitializedMemory,
2941 ),
2942 );
2943
2944 state
2945 .vertex
2946 .set_buffer(slot as usize, buffer, buffer_range.clone());
2947 if let Some(pipeline) = state.pipeline.as_ref() {
2948 state.vertex.update_limits(&pipeline.vertex_steps);
2949 }
2950 } else {
2951 if offset != 0 {
2952 return Err(RenderCommandError::from(
2953 crate::binding_model::BindingError::UnbindingVertexBufferOffsetNotZero {
2954 slot,
2955 offset,
2956 },
2957 )
2958 .into());
2959 }
2960 if let Some(size) = size {
2961 return Err(RenderCommandError::from(
2962 crate::binding_model::BindingError::UnbindingVertexBufferSizeNotZero {
2963 slot,
2964 size: size.get(),
2965 },
2966 )
2967 .into());
2968 }
2969
2970 state.vertex.clear_buffer(slot as usize);
2971 if let Some(pipeline) = state.pipeline.as_ref() {
2972 state.vertex.update_limits(&pipeline.vertex_steps);
2973 }
2974 }
2975
2976 Ok(())
2977}
2978
2979fn set_blend_constant(state: &mut State, color: &Color) {
2980 api_log!("RenderPass::set_blend_constant");
2981
2982 state.blend_constant = OptionalState::Set;
2983 let array = [
2984 color.r as f32,
2985 color.g as f32,
2986 color.b as f32,
2987 color.a as f32,
2988 ];
2989 unsafe {
2990 state.pass.base.raw_encoder.set_blend_constants(&array);
2991 }
2992}
2993
2994fn set_stencil_reference(state: &mut State, value: u32) {
2995 api_log!("RenderPass::set_stencil_reference {value}");
2996
2997 state.stencil_reference = value;
2998 if state
2999 .pipeline_flags
3000 .contains(PipelineFlags::STENCIL_REFERENCE)
3001 {
3002 unsafe {
3003 state.pass.base.raw_encoder.set_stencil_reference(value);
3004 }
3005 }
3006}
3007
3008fn set_viewport(
3009 state: &mut State,
3010 rect: Rect<f32>,
3011 depth_min: f32,
3012 depth_max: f32,
3013) -> Result<(), RenderPassErrorInner> {
3014 api_log!("RenderPass::set_viewport {rect:?}");
3015
3016 if rect.w < 0.0
3017 || rect.h < 0.0
3018 || rect.w > state.pass.base.device.limits.max_texture_dimension_2d as f32
3019 || rect.h > state.pass.base.device.limits.max_texture_dimension_2d as f32
3020 {
3021 return Err(RenderCommandError::InvalidViewportRectSize {
3022 w: rect.w,
3023 h: rect.h,
3024 max: state.pass.base.device.limits.max_texture_dimension_2d,
3025 }
3026 .into());
3027 }
3028
3029 let max_viewport_range = state.pass.base.device.limits.max_texture_dimension_2d as f32 * 2.0;
3030
3031 if rect.x < -max_viewport_range
3032 || rect.y < -max_viewport_range
3033 || rect.x + rect.w > max_viewport_range - 1.0
3034 || rect.y + rect.h > max_viewport_range - 1.0
3035 {
3036 return Err(RenderCommandError::InvalidViewportRectPosition {
3037 rect,
3038 min: -max_viewport_range,
3039 max: max_viewport_range - 1.0,
3040 }
3041 .into());
3042 }
3043 if !(0.0..=1.0).contains(&depth_min)
3044 || !(0.0..=1.0).contains(&depth_max)
3045 || depth_min > depth_max
3046 {
3047 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
3048 }
3049 let r = hal::Rect {
3050 x: rect.x,
3051 y: rect.y,
3052 w: rect.w,
3053 h: rect.h,
3054 };
3055 unsafe {
3056 state
3057 .pass
3058 .base
3059 .raw_encoder
3060 .set_viewport(&r, depth_min..depth_max);
3061 }
3062 Ok(())
3063}
3064
3065fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
3066 api_log!("RenderPass::set_scissor_rect {rect:?}");
3067
3068 if rect.x.saturating_add(rect.w) > state.info.extent.width
3069 || rect.y.saturating_add(rect.h) > state.info.extent.height
3070 {
3071 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
3072 }
3073 let r = hal::Rect {
3074 x: rect.x,
3075 y: rect.y,
3076 w: rect.w,
3077 h: rect.h,
3078 };
3079 unsafe {
3080 state.pass.base.raw_encoder.set_scissor_rect(&r);
3081 }
3082 Ok(())
3083}
3084
3085fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
3086 if let Some(mv) = state.info.multiview_mask {
3087 let highest_bit = 31 - mv.leading_zeros();
3088
3089 let features = state.pass.base.device.features;
3090
3091 if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
3092 || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
3093 {
3094 return Err(RenderPassErrorInner::Draw(
3095 DrawError::MeshPipelineMultiviewLimitsViolated {
3096 highest_view_index: highest_bit,
3097 max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
3098 },
3099 ));
3100 }
3101 }
3102 Ok(())
3103}
3104
3105fn draw(
3106 state: &mut State,
3107 vertex_count: u32,
3108 instance_count: u32,
3109 first_vertex: u32,
3110 first_instance: u32,
3111) -> Result<(), RenderPassErrorInner> {
3112 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
3113
3114 state.is_ready(DrawCommandFamily::Draw)?;
3115 state.flush_vertex_buffers()?;
3116 state.flush_bindings()?;
3117
3118 state
3119 .vertex
3120 .limits
3121 .validate_vertex_limit(first_vertex, vertex_count)?;
3122 state
3123 .vertex
3124 .limits
3125 .validate_instance_limit(first_instance, instance_count)?;
3126
3127 unsafe {
3128 if instance_count > 0 && vertex_count > 0 {
3129 state.pass.base.raw_encoder.draw(
3130 first_vertex,
3131 vertex_count,
3132 first_instance,
3133 instance_count,
3134 );
3135 }
3136 }
3137 Ok(())
3138}
3139
3140fn draw_indexed(
3141 state: &mut State,
3142 index_count: u32,
3143 instance_count: u32,
3144 first_index: u32,
3145 base_vertex: i32,
3146 first_instance: u32,
3147) -> Result<(), RenderPassErrorInner> {
3148 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
3149
3150 state.is_ready(DrawCommandFamily::DrawIndexed)?;
3151 state.flush_vertex_buffers()?;
3152 state.flush_bindings()?;
3153
3154 let last_index = first_index as u64 + index_count as u64;
3155 let index_limit = state.index.limit;
3156 if last_index > index_limit {
3157 return Err(DrawError::IndexBeyondLimit {
3158 last_index,
3159 index_limit,
3160 }
3161 .into());
3162 }
3163 state
3164 .vertex
3165 .limits
3166 .validate_instance_limit(first_instance, instance_count)?;
3167
3168 unsafe {
3169 if instance_count > 0 && index_count > 0 {
3170 state.pass.base.raw_encoder.draw_indexed(
3171 first_index,
3172 index_count,
3173 base_vertex,
3174 first_instance,
3175 instance_count,
3176 );
3177 }
3178 }
3179 Ok(())
3180}
3181
3182fn draw_mesh_tasks(
3183 state: &mut State,
3184 group_count_x: u32,
3185 group_count_y: u32,
3186 group_count_z: u32,
3187) -> Result<(), RenderPassErrorInner> {
3188 api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
3189
3190 state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
3191
3192 state.flush_bindings()?;
3193 validate_mesh_draw_multiview(state)?;
3194
3195 let limits = &state.pass.base.device.limits;
3196 let (groups_size_limit, max_groups) = if state.pipeline.as_ref().unwrap().has_task_shader {
3197 (
3198 limits.max_task_workgroups_per_dimension,
3199 limits.max_task_workgroup_total_count,
3200 )
3201 } else {
3202 (
3203 limits.max_mesh_workgroups_per_dimension,
3204 limits.max_mesh_workgroup_total_count,
3205 )
3206 };
3207
3208 let total_count = WorkgroupSizeCheck {
3209 dimensions: &[group_count_x, group_count_y, group_count_z],
3210 per_dimension_limits: &[groups_size_limit, groups_size_limit, groups_size_limit],
3211 per_dimension_limits_desc: "max_task_mesh_workgroups_per_dimension",
3212
3213 total_limit: max_groups,
3214 total_limit_desc: "max_task_mesh_workgroup_total_count",
3215 }
3216 .check_and_compute_total_invocations()
3217 .map_err(|err| RenderPassErrorInner::Draw(err.into()))?;
3218
3219 unsafe {
3220 if total_count > 0 {
3221 state.pass.base.raw_encoder.draw_mesh_tasks(
3222 group_count_x,
3223 group_count_y,
3224 group_count_z,
3225 );
3226 }
3227 }
3228 Ok(())
3229}
3230
3231fn multi_draw_indirect(
3232 state: &mut State,
3233 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3234 device: &Arc<Device>,
3235 indirect_buffer: Arc<Buffer>,
3236 offset: u64,
3237 count: u32,
3238 family: DrawCommandFamily,
3239) -> Result<(), RenderPassErrorInner> {
3240 api_log!(
3241 "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
3242 indirect_buffer.error_ident()
3243 );
3244
3245 state.is_ready(family)?;
3246 state.flush_vertex_buffers()?;
3247 state.flush_bindings()?;
3248
3249 if family == DrawCommandFamily::DrawMeshTasks {
3250 validate_mesh_draw_multiview(state)?;
3251 }
3252
3253 state
3254 .pass
3255 .base
3256 .device
3257 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
3258
3259 indirect_buffer.same_device(device)?;
3260 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
3261 indirect_buffer.check_destroyed(state.pass.base.snatch_guard)?;
3262
3263 if !offset.is_multiple_of(4) {
3264 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
3265 }
3266
3267 let stride = get_src_stride_of_indirect_args(family);
3268 let args_size = match stride.checked_mul(u64::from(count)) {
3269 Some(sz) if sz <= indirect_buffer.size && indirect_buffer.size - sz >= offset => sz,
3270 args_size => {
3271 return Err(RenderPassErrorInner::IndirectBufferOverrun {
3272 count,
3273 offset,
3274 args_size: args_size.unwrap_or(u64::MAX),
3275 buffer_size: indirect_buffer.size,
3276 });
3277 }
3278 };
3279
3280 state.pass.base.buffer_memory_init_actions.extend(
3281 indirect_buffer.initialization_status.read().create_action(
3282 &indirect_buffer,
3283 offset..offset + args_size,
3284 MemoryInitKind::NeedsInitializedMemory,
3285 ),
3286 );
3287
3288 fn draw(
3289 raw_encoder: &mut dyn hal::DynCommandEncoder,
3290 family: DrawCommandFamily,
3291 indirect_buffer: &dyn hal::DynBuffer,
3292 offset: u64,
3293 count: u32,
3294 ) {
3295 match family {
3296 DrawCommandFamily::Draw => unsafe {
3297 raw_encoder.draw_indirect(indirect_buffer, offset, count);
3298 },
3299 DrawCommandFamily::DrawIndexed => unsafe {
3300 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
3301 },
3302 DrawCommandFamily::DrawMeshTasks => unsafe {
3303 raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
3304 },
3305 }
3306 }
3307
3308 if state.pass.base.device.indirect_validation.is_some()
3309 && family != DrawCommandFamily::DrawMeshTasks
3310 {
3311 state
3312 .pass
3313 .scope
3314 .buffers
3315 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
3316
3317 struct DrawData {
3318 buffer_index: usize,
3319 offset: u64,
3320 count: u32,
3321 }
3322
3323 struct DrawContext<'a> {
3324 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
3325 device: &'a Device,
3326
3327 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
3328 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
3329
3330 indirect_buffer: Arc<Buffer>,
3331 family: DrawCommandFamily,
3332 vertex_or_index_limit: u64,
3333 instance_limit: u64,
3334 }
3335
3336 impl<'a> DrawContext<'a> {
3337 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
3338 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
3339 self.indirect_draw_validation_resources,
3340 self.device,
3341 &self.indirect_buffer,
3342 offset,
3343 self.family,
3344 self.vertex_or_index_limit,
3345 self.instance_limit,
3346 )?;
3347 Ok(DrawData {
3348 buffer_index: dst_resource_index,
3349 offset: dst_offset,
3350 count: 1,
3351 })
3352 }
3353 fn draw(&mut self, draw_data: DrawData) {
3354 let dst_buffer = self
3355 .indirect_draw_validation_resources
3356 .get_dst_buffer(draw_data.buffer_index);
3357 draw(
3358 self.raw_encoder,
3359 self.family,
3360 dst_buffer,
3361 draw_data.offset,
3362 draw_data.count,
3363 );
3364 }
3365 }
3366
3367 let mut draw_ctx = DrawContext {
3368 raw_encoder: state.pass.base.raw_encoder,
3369 device: state.pass.base.device,
3370 indirect_draw_validation_resources: state.pass.base.indirect_draw_validation_resources,
3371 indirect_draw_validation_batcher,
3372 indirect_buffer,
3373 family,
3374 vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
3375 state.index.limit
3376 } else {
3377 state.vertex.limits.vertex_limit
3378 },
3379 instance_limit: state.vertex.limits.instance_limit,
3380 };
3381
3382 let mut current_draw_data = draw_ctx.add(offset)?;
3383
3384 for i in 1..count {
3385 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
3386
3387 if draw_data.buffer_index == current_draw_data.buffer_index {
3388 #[cfg(debug_assertions)]
3389 {
3390 let dst_stride =
3391 get_dst_stride_of_indirect_args(state.pass.base.device.backend(), family);
3392 debug_assert_eq!(
3393 draw_data.offset,
3394 current_draw_data.offset + dst_stride * current_draw_data.count as u64
3395 );
3396 }
3397 current_draw_data.count += 1;
3398 } else {
3399 draw_ctx.draw(current_draw_data);
3400 current_draw_data = draw_data;
3401 }
3402 }
3403
3404 draw_ctx.draw(current_draw_data);
3405 } else {
3406 state
3407 .pass
3408 .scope
3409 .buffers
3410 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
3411
3412 draw(
3413 state.pass.base.raw_encoder,
3414 family,
3415 indirect_buffer.try_raw(state.pass.base.snatch_guard)?,
3416 offset,
3417 count,
3418 );
3419 };
3420
3421 Ok(())
3422}
3423
3424fn multi_draw_indirect_count(
3425 state: &mut State,
3426 device: &Arc<Device>,
3427 indirect_buffer: Arc<Buffer>,
3428 offset: u64,
3429 count_buffer: Arc<Buffer>,
3430 count_buffer_offset: u64,
3431 max_count: u32,
3432 family: DrawCommandFamily,
3433) -> Result<(), RenderPassErrorInner> {
3434 api_log!(
3435 "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
3436 indirect_buffer.error_ident(),
3437 count_buffer.error_ident()
3438 );
3439
3440 state.is_ready(family)?;
3441 state.flush_vertex_buffers()?;
3442 state.flush_bindings()?;
3443
3444 if family == DrawCommandFamily::DrawMeshTasks {
3445 validate_mesh_draw_multiview(state)?;
3446 }
3447
3448 let stride = get_src_stride_of_indirect_args(family);
3449
3450 state
3451 .pass
3452 .base
3453 .device
3454 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
3455 state
3456 .pass
3457 .base
3458 .device
3459 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
3460
3461 indirect_buffer.same_device(device)?;
3462 count_buffer.same_device(device)?;
3463
3464 state
3465 .pass
3466 .scope
3467 .buffers
3468 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
3469
3470 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
3471 let indirect_raw = indirect_buffer.try_raw(state.pass.base.snatch_guard)?;
3472
3473 state
3474 .pass
3475 .scope
3476 .buffers
3477 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
3478
3479 count_buffer.check_usage(BufferUsages::INDIRECT)?;
3480 let count_raw = count_buffer.try_raw(state.pass.base.snatch_guard)?;
3481
3482 if !offset.is_multiple_of(4) {
3483 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
3484 }
3485
3486 let args_size = match stride.checked_mul(u64::from(max_count)) {
3487 Some(sz) if sz <= indirect_buffer.size && indirect_buffer.size - sz >= offset => sz,
3488 args_size => {
3489 return Err(RenderPassErrorInner::IndirectBufferOverrun {
3490 count: 1,
3491 offset,
3492 args_size: args_size.unwrap_or(u64::MAX),
3493 buffer_size: indirect_buffer.size,
3494 });
3495 }
3496 };
3497
3498 state.pass.base.buffer_memory_init_actions.extend(
3499 indirect_buffer.initialization_status.read().create_action(
3500 &indirect_buffer,
3501 offset..offset + args_size,
3502 MemoryInitKind::NeedsInitializedMemory,
3503 ),
3504 );
3505
3506 let begin_count_offset = count_buffer_offset;
3507 let count_bytes = 4;
3508 if count_buffer.size < count_bytes || count_buffer.size - count_bytes < count_buffer_offset {
3509 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
3510 begin_count_offset,
3511 count_bytes: 4,
3512 count_buffer_size: count_buffer.size,
3513 });
3514 }
3515 state.pass.base.buffer_memory_init_actions.extend(
3516 count_buffer.initialization_status.read().create_action(
3517 &count_buffer,
3518 count_buffer_offset..count_buffer_offset + count_bytes,
3519 MemoryInitKind::NeedsInitializedMemory,
3520 ),
3521 );
3522
3523 match family {
3524 DrawCommandFamily::Draw => unsafe {
3525 state.pass.base.raw_encoder.draw_indirect_count(
3526 indirect_raw,
3527 offset,
3528 count_raw,
3529 count_buffer_offset,
3530 max_count,
3531 );
3532 },
3533 DrawCommandFamily::DrawIndexed => unsafe {
3534 state.pass.base.raw_encoder.draw_indexed_indirect_count(
3535 indirect_raw,
3536 offset,
3537 count_raw,
3538 count_buffer_offset,
3539 max_count,
3540 );
3541 },
3542 DrawCommandFamily::DrawMeshTasks => unsafe {
3543 state.pass.base.raw_encoder.draw_mesh_tasks_indirect_count(
3544 indirect_raw,
3545 offset,
3546 count_raw,
3547 count_buffer_offset,
3548 max_count,
3549 );
3550 },
3551 }
3552 Ok(())
3553}
3554
3555fn execute_bundle(
3556 state: &mut State,
3557 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
3558 device: &Arc<Device>,
3559 bundle: Arc<super::RenderBundle>,
3560) -> Result<(), RenderPassErrorInner> {
3561 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
3562
3563 let bundle = state.pass.base.tracker.bundles.insert_single(bundle);
3564
3565 let bundle_state = bundle.state()?;
3566 bundle.same_device(device)?;
3567
3568 state
3569 .info
3570 .context
3571 .check_compatible(&bundle_state.context, bundle.as_ref())
3572 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
3573
3574 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3575 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3576 {
3577 return Err(
3578 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3579 pass_depth: state.info.is_depth_read_only,
3580 pass_stencil: state.info.is_stencil_read_only,
3581 bundle_depth: bundle.is_depth_read_only,
3582 bundle_stencil: bundle.is_stencil_read_only,
3583 },
3584 );
3585 }
3586
3587 state.pass.base.buffer_memory_init_actions.extend(
3588 bundle
3589 .buffer_memory_init_actions
3590 .iter()
3591 .filter_map(|action| {
3592 action
3593 .buffer
3594 .initialization_status
3595 .read()
3596 .check_action(action)
3597 }),
3598 );
3599 for action in bundle.texture_memory_init_actions.iter() {
3600 state.pass.pending_discard_init_fixups.extend(
3601 state
3602 .pass
3603 .base
3604 .texture_memory_actions
3605 .register_init_action(action),
3606 );
3607 }
3608
3609 unsafe {
3610 bundle.execute(
3611 state.pass.base.raw_encoder,
3612 state.pass.base.indirect_draw_validation_resources,
3613 indirect_draw_validation_batcher,
3614 state.pass.base.snatch_guard,
3615 )
3616 }
3617 .map_err(|e| match e {
3618 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3619 ExecutionError::DestroyedResource(e) => {
3620 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3621 }
3622 ExecutionError::Unimplemented(what) => {
3623 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3624 }
3625 })?;
3626
3627 unsafe {
3628 state.pass.scope.merge_render_bundle(&bundle_state.used)?;
3629 };
3630 state.reset_bundle();
3631 Ok(())
3632}
3633
3634impl Global {
3647 pub fn render_pass_set_bind_group(
3648 &self,
3649 pass: &mut RenderPass,
3650 index: u32,
3651 bind_group_id: Option<id::BindGroupId>,
3652 offsets: &[DynamicOffset],
3653 ) -> Result<(), PassStateError> {
3654 let scope = PassErrorScope::SetBindGroup;
3655
3656 let base = pass_base!(pass, scope);
3660
3661 if pass.current_bind_groups.set_and_check_redundant(
3662 bind_group_id,
3663 index,
3664 &mut base.dynamic_offsets,
3665 offsets,
3666 ) {
3667 return Ok(());
3668 }
3669
3670 let mut bind_group = None;
3671 if let Some(bind_group_id) = bind_group_id {
3672 let hub = &self.hub;
3673 bind_group = Some(pass_try!(
3674 base,
3675 scope,
3676 hub.bind_groups.get(bind_group_id).get(),
3677 ));
3678 }
3679
3680 base.commands.push(ArcRenderCommand::SetBindGroup {
3681 index,
3682 num_dynamic_offsets: offsets.len(),
3683 bind_group,
3684 });
3685
3686 Ok(())
3687 }
3688
3689 pub fn render_pass_set_bind_group_with_id(
3690 &self,
3691 pass: id::RenderPassEncoderId,
3692 index: u32,
3693 bind_group_id: Option<id::BindGroupId>,
3694 offsets: &[DynamicOffset],
3695 ) -> Result<(), PassStateError> {
3696 let pass = self.hub.render_passes.get(pass);
3697 let mut pass = pass
3698 .try_lock()
3699 .expect("RenderPasses should not be used concurrently");
3700 self.render_pass_set_bind_group(&mut pass, index, bind_group_id, offsets)
3701 }
3702
3703 pub fn render_pass_set_pipeline(
3704 &self,
3705 pass: &mut RenderPass,
3706 pipeline_id: id::RenderPipelineId,
3707 ) -> Result<(), PassStateError> {
3708 let scope = PassErrorScope::SetPipelineRender;
3709
3710 let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3711
3712 let base = pass_base!(pass, scope);
3715
3716 if redundant {
3717 return Ok(());
3718 }
3719
3720 let hub = &self.hub;
3721 let pipeline = hub.render_pipelines.get(pipeline_id);
3722 pass_try!(base, scope, pipeline.check_valid());
3723
3724 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3725
3726 Ok(())
3727 }
3728
3729 pub fn render_pass_set_pipeline_with_id(
3730 &self,
3731 pass: id::RenderPassEncoderId,
3732 pipeline_id: id::RenderPipelineId,
3733 ) -> Result<(), PassStateError> {
3734 let pass = self.hub.render_passes.get(pass);
3735 let mut pass = pass
3736 .try_lock()
3737 .expect("RenderPasses should not be used concurrently");
3738 self.render_pass_set_pipeline(&mut pass, pipeline_id)
3739 }
3740
3741 pub fn render_pass_set_index_buffer(
3742 &self,
3743 pass: &mut RenderPass,
3744 buffer_id: id::BufferId,
3745 index_format: IndexFormat,
3746 offset: BufferAddress,
3747 size: Option<BufferSize>,
3748 ) -> Result<(), PassStateError> {
3749 let scope = PassErrorScope::SetIndexBuffer;
3750 let base = pass_base!(pass, scope);
3751
3752 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3753 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
3754 index_format,
3755 offset,
3756 size,
3757 });
3758
3759 Ok(())
3760 }
3761
3762 pub fn render_pass_set_index_buffer_with_id(
3763 &self,
3764 pass: id::RenderPassEncoderId,
3765 buffer_id: id::BufferId,
3766 index_format: IndexFormat,
3767 offset: BufferAddress,
3768 size: Option<BufferSize>,
3769 ) -> Result<(), PassStateError> {
3770 let pass = self.hub.render_passes.get(pass);
3771 let mut pass = pass
3772 .try_lock()
3773 .expect("RenderPasses should not be used concurrently");
3774 self.render_pass_set_index_buffer(&mut pass, buffer_id, index_format, offset, size)
3775 }
3776
3777 pub fn render_pass_set_vertex_buffer(
3778 &self,
3779 pass: &mut RenderPass,
3780 slot: u32,
3781 buffer_id: Option<id::BufferId>,
3782 offset: BufferAddress,
3783 size: Option<BufferSize>,
3784 ) -> Result<(), PassStateError> {
3785 let scope = PassErrorScope::SetVertexBuffer;
3786 let base = pass_base!(pass, scope);
3787
3788 let buffer = if let Some(buffer_id) = buffer_id {
3789 Some(pass_try!(base, scope, self.resolve_buffer_id(buffer_id)))
3790 } else {
3791 None
3792 };
3793
3794 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3795 slot,
3796 buffer,
3797 offset,
3798 size,
3799 });
3800
3801 Ok(())
3802 }
3803
3804 pub fn render_pass_set_vertex_buffer_with_id(
3805 &self,
3806 pass: id::RenderPassEncoderId,
3807 slot: u32,
3808 buffer_id: Option<id::BufferId>,
3809 offset: BufferAddress,
3810 size: Option<BufferSize>,
3811 ) -> Result<(), PassStateError> {
3812 let pass = self.hub.render_passes.get(pass);
3813 let mut pass = pass
3814 .try_lock()
3815 .expect("RenderPasses should not be used concurrently");
3816 self.render_pass_set_vertex_buffer(&mut pass, slot, buffer_id, offset, size)
3817 }
3818
3819 pub fn render_pass_set_blend_constant(
3820 &self,
3821 pass: &mut RenderPass,
3822 color: Color,
3823 ) -> Result<(), PassStateError> {
3824 let scope = PassErrorScope::SetBlendConstant;
3825 let base = pass_base!(pass, scope);
3826
3827 base.commands
3828 .push(ArcRenderCommand::SetBlendConstant(color));
3829
3830 Ok(())
3831 }
3832
3833 pub fn render_pass_set_blend_constant_with_id(
3834 &self,
3835 pass: id::RenderPassEncoderId,
3836 color: Color,
3837 ) -> Result<(), PassStateError> {
3838 let pass = self.hub.render_passes.get(pass);
3839 let mut pass = pass
3840 .try_lock()
3841 .expect("RenderPasses should not be used concurrently");
3842 self.render_pass_set_blend_constant(&mut pass, color)
3843 }
3844
3845 pub fn render_pass_set_stencil_reference(
3846 &self,
3847 pass: &mut RenderPass,
3848 value: u32,
3849 ) -> Result<(), PassStateError> {
3850 let scope = PassErrorScope::SetStencilReference;
3851 let base = pass_base!(pass, scope);
3852 let value = convert_stencil_value(
3853 value,
3854 pass.depth_stencil_attachment
3855 .as_ref()
3856 .map(|at| at.view.desc.format),
3857 );
3858 base.commands
3859 .push(ArcRenderCommand::SetStencilReference(value));
3860
3861 Ok(())
3862 }
3863
3864 pub fn render_pass_set_stencil_reference_with_id(
3865 &self,
3866 pass: id::RenderPassEncoderId,
3867 value: u32,
3868 ) -> Result<(), PassStateError> {
3869 let pass = self.hub.render_passes.get(pass);
3870 let mut pass = pass
3871 .try_lock()
3872 .expect("RenderPasses should not be used concurrently");
3873 self.render_pass_set_stencil_reference(&mut pass, value)
3874 }
3875
3876 pub fn render_pass_set_viewport(
3877 &self,
3878 pass: &mut RenderPass,
3879 x: f32,
3880 y: f32,
3881 w: f32,
3882 h: f32,
3883 depth_min: f32,
3884 depth_max: f32,
3885 ) -> Result<(), PassStateError> {
3886 let scope = PassErrorScope::SetViewport;
3887 let base = pass_base!(pass, scope);
3888
3889 base.commands.push(ArcRenderCommand::SetViewport {
3890 rect: Rect { x, y, w, h },
3891 depth_min,
3892 depth_max,
3893 });
3894
3895 Ok(())
3896 }
3897
3898 pub fn render_pass_set_viewport_with_id(
3899 &self,
3900 pass: id::RenderPassEncoderId,
3901 x: f32,
3902 y: f32,
3903 w: f32,
3904 h: f32,
3905 depth_min: f32,
3906 depth_max: f32,
3907 ) -> Result<(), PassStateError> {
3908 let pass = self.hub.render_passes.get(pass);
3909 let mut pass = pass
3910 .try_lock()
3911 .expect("RenderPasses should not be used concurrently");
3912 self.render_pass_set_viewport(&mut pass, x, y, w, h, depth_min, depth_max)
3913 }
3914
3915 pub fn render_pass_set_scissor_rect(
3916 &self,
3917 pass: &mut RenderPass,
3918 x: u32,
3919 y: u32,
3920 w: u32,
3921 h: u32,
3922 ) -> Result<(), PassStateError> {
3923 let scope = PassErrorScope::SetScissorRect;
3924 let base = pass_base!(pass, scope);
3925
3926 base.commands
3927 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3928
3929 Ok(())
3930 }
3931
3932 pub fn render_pass_set_scissor_rect_with_id(
3933 &self,
3934 pass: id::RenderPassEncoderId,
3935 x: u32,
3936 y: u32,
3937 w: u32,
3938 h: u32,
3939 ) -> Result<(), PassStateError> {
3940 let pass = self.hub.render_passes.get(pass);
3941 let mut pass = pass
3942 .try_lock()
3943 .expect("RenderPasses should not be used concurrently");
3944 self.render_pass_set_scissor_rect(&mut pass, x, y, w, h)
3945 }
3946
3947 pub fn render_pass_set_immediates(
3948 &self,
3949 pass: &mut RenderPass,
3950 offset: u32,
3951 data: &[u8],
3952 ) -> Result<(), PassStateError> {
3953 let scope = PassErrorScope::SetImmediate;
3954 let base = pass_base!(pass, scope);
3955
3956 let size_bytes = pass_try!(
3957 base,
3958 scope,
3959 u32::try_from(data.len()).map_err(|_| ImmediateUploadError::ImmediateOutOfMemory)
3960 );
3961 pass_try!(
3962 base,
3963 scope,
3964 pass::validate_immediates_alignment(offset, size_bytes)
3965 );
3966
3967 let values_offset = base.immediates_data.len().try_into().unwrap();
3968
3969 base.immediates_data.extend(
3970 data.chunks_exact(wgt::IMMEDIATE_DATA_ALIGNMENT as usize)
3971 .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3972 );
3973
3974 base.commands.push(ArcRenderCommand::SetImmediate {
3975 offset,
3976 size_bytes: data.len() as u32,
3977 values_offset: Some(values_offset),
3978 });
3979
3980 Ok(())
3981 }
3982
3983 pub fn render_pass_set_immediates_with_id(
3984 &self,
3985 pass: id::RenderPassEncoderId,
3986 offset: u32,
3987 data: &[u8],
3988 ) -> Result<(), PassStateError> {
3989 let pass = self.hub.render_passes.get(pass);
3990 let mut pass = pass
3991 .try_lock()
3992 .expect("RenderPasses should not be used concurrently");
3993 self.render_pass_set_immediates(&mut pass, offset, data)
3994 }
3995
3996 pub fn render_pass_draw(
3997 &self,
3998 pass: &mut RenderPass,
3999 vertex_count: u32,
4000 instance_count: u32,
4001 first_vertex: u32,
4002 first_instance: u32,
4003 ) -> Result<(), PassStateError> {
4004 let scope = PassErrorScope::Draw {
4005 kind: DrawKind::Draw,
4006 family: DrawCommandFamily::Draw,
4007 };
4008 let base = pass_base!(pass, scope);
4009
4010 base.commands.push(ArcRenderCommand::Draw {
4011 vertex_count,
4012 instance_count,
4013 first_vertex,
4014 first_instance,
4015 });
4016
4017 Ok(())
4018 }
4019
4020 pub fn render_pass_draw_with_id(
4021 &self,
4022 pass: id::RenderPassEncoderId,
4023 vertex_count: u32,
4024 instance_count: u32,
4025 first_vertex: u32,
4026 first_instance: u32,
4027 ) -> Result<(), PassStateError> {
4028 let pass = self.hub.render_passes.get(pass);
4029 let mut pass = pass
4030 .try_lock()
4031 .expect("RenderPasses should not be used concurrently");
4032 self.render_pass_draw(
4033 &mut pass,
4034 vertex_count,
4035 instance_count,
4036 first_vertex,
4037 first_instance,
4038 )
4039 }
4040
4041 pub fn render_pass_draw_indexed(
4042 &self,
4043 pass: &mut RenderPass,
4044 index_count: u32,
4045 instance_count: u32,
4046 first_index: u32,
4047 base_vertex: i32,
4048 first_instance: u32,
4049 ) -> Result<(), PassStateError> {
4050 let scope = PassErrorScope::Draw {
4051 kind: DrawKind::Draw,
4052 family: DrawCommandFamily::DrawIndexed,
4053 };
4054 let base = pass_base!(pass, scope);
4055
4056 base.commands.push(ArcRenderCommand::DrawIndexed {
4057 index_count,
4058 instance_count,
4059 first_index,
4060 base_vertex,
4061 first_instance,
4062 });
4063
4064 Ok(())
4065 }
4066
4067 pub fn render_pass_draw_indexed_with_id(
4068 &self,
4069 pass: id::RenderPassEncoderId,
4070 index_count: u32,
4071 instance_count: u32,
4072 first_index: u32,
4073 base_vertex: i32,
4074 first_instance: u32,
4075 ) -> Result<(), PassStateError> {
4076 let pass = self.hub.render_passes.get(pass);
4077 let mut pass = pass
4078 .try_lock()
4079 .expect("RenderPasses should not be used concurrently");
4080 self.render_pass_draw_indexed(
4081 &mut pass,
4082 index_count,
4083 instance_count,
4084 first_index,
4085 base_vertex,
4086 first_instance,
4087 )
4088 }
4089
4090 pub fn render_pass_draw_mesh_tasks(
4091 &self,
4092 pass: &mut RenderPass,
4093 group_count_x: u32,
4094 group_count_y: u32,
4095 group_count_z: u32,
4096 ) -> Result<(), RenderPassError> {
4097 let scope = PassErrorScope::Draw {
4098 kind: DrawKind::Draw,
4099 family: DrawCommandFamily::DrawMeshTasks,
4100 };
4101 let base = pass_base!(pass, scope);
4102
4103 base.commands.push(ArcRenderCommand::DrawMeshTasks {
4104 group_count_x,
4105 group_count_y,
4106 group_count_z,
4107 });
4108 Ok(())
4109 }
4110
4111 pub fn render_pass_draw_indirect(
4112 &self,
4113 pass: &mut RenderPass,
4114 buffer_id: id::BufferId,
4115 offset: BufferAddress,
4116 ) -> Result<(), PassStateError> {
4117 let scope = PassErrorScope::Draw {
4118 kind: DrawKind::DrawIndirect,
4119 family: DrawCommandFamily::Draw,
4120 };
4121 let base = pass_base!(pass, scope);
4122
4123 base.commands.push(ArcRenderCommand::DrawIndirect {
4124 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4125 offset,
4126 count: 1,
4127 family: DrawCommandFamily::Draw,
4128
4129 vertex_or_index_limit: None,
4130 instance_limit: None,
4131 });
4132
4133 Ok(())
4134 }
4135
4136 pub fn render_pass_draw_indirect_with_id(
4137 &self,
4138 pass: id::RenderPassEncoderId,
4139 buffer_id: id::BufferId,
4140 offset: BufferAddress,
4141 ) -> Result<(), PassStateError> {
4142 let pass = self.hub.render_passes.get(pass);
4143 let mut pass = pass
4144 .try_lock()
4145 .expect("RenderPasses should not be used concurrently");
4146 self.render_pass_draw_indirect(&mut pass, buffer_id, offset)
4147 }
4148
4149 pub fn render_pass_draw_indexed_indirect(
4150 &self,
4151 pass: &mut RenderPass,
4152 buffer_id: id::BufferId,
4153 offset: BufferAddress,
4154 ) -> Result<(), PassStateError> {
4155 let scope = PassErrorScope::Draw {
4156 kind: DrawKind::DrawIndirect,
4157 family: DrawCommandFamily::DrawIndexed,
4158 };
4159 let base = pass_base!(pass, scope);
4160
4161 base.commands.push(ArcRenderCommand::DrawIndirect {
4162 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4163 offset,
4164 count: 1,
4165 family: DrawCommandFamily::DrawIndexed,
4166
4167 vertex_or_index_limit: None,
4168 instance_limit: None,
4169 });
4170
4171 Ok(())
4172 }
4173
4174 pub fn render_pass_draw_indexed_indirect_with_id(
4175 &self,
4176 pass: id::RenderPassEncoderId,
4177 buffer_id: id::BufferId,
4178 offset: BufferAddress,
4179 ) -> Result<(), PassStateError> {
4180 let pass = self.hub.render_passes.get(pass);
4181 let mut pass = pass
4182 .try_lock()
4183 .expect("RenderPasses should not be used concurrently");
4184 self.render_pass_draw_indexed_indirect(&mut pass, buffer_id, offset)
4185 }
4186
4187 pub fn render_pass_draw_mesh_tasks_indirect(
4188 &self,
4189 pass: &mut RenderPass,
4190 buffer_id: id::BufferId,
4191 offset: BufferAddress,
4192 ) -> Result<(), RenderPassError> {
4193 let scope = PassErrorScope::Draw {
4194 kind: DrawKind::DrawIndirect,
4195 family: DrawCommandFamily::DrawMeshTasks,
4196 };
4197 let base = pass_base!(pass, scope);
4198
4199 base.commands.push(ArcRenderCommand::DrawIndirect {
4200 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4201 offset,
4202 count: 1,
4203 family: DrawCommandFamily::DrawMeshTasks,
4204
4205 vertex_or_index_limit: None,
4206 instance_limit: None,
4207 });
4208
4209 Ok(())
4210 }
4211
4212 pub fn render_pass_multi_draw_indirect(
4213 &self,
4214 pass: &mut RenderPass,
4215 buffer_id: id::BufferId,
4216 offset: BufferAddress,
4217 count: u32,
4218 ) -> Result<(), PassStateError> {
4219 let scope = PassErrorScope::Draw {
4220 kind: DrawKind::MultiDrawIndirect,
4221 family: DrawCommandFamily::Draw,
4222 };
4223 let base = pass_base!(pass, scope);
4224
4225 base.commands.push(ArcRenderCommand::DrawIndirect {
4226 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4227 offset,
4228 count,
4229 family: DrawCommandFamily::Draw,
4230
4231 vertex_or_index_limit: None,
4232 instance_limit: None,
4233 });
4234
4235 Ok(())
4236 }
4237
4238 pub fn render_pass_multi_draw_indexed_indirect(
4239 &self,
4240 pass: &mut RenderPass,
4241 buffer_id: id::BufferId,
4242 offset: BufferAddress,
4243 count: u32,
4244 ) -> Result<(), PassStateError> {
4245 let scope = PassErrorScope::Draw {
4246 kind: DrawKind::MultiDrawIndirect,
4247 family: DrawCommandFamily::DrawIndexed,
4248 };
4249 let base = pass_base!(pass, scope);
4250
4251 base.commands.push(ArcRenderCommand::DrawIndirect {
4252 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4253 offset,
4254 count,
4255 family: DrawCommandFamily::DrawIndexed,
4256
4257 vertex_or_index_limit: None,
4258 instance_limit: None,
4259 });
4260
4261 Ok(())
4262 }
4263
4264 pub fn render_pass_multi_draw_mesh_tasks_indirect(
4265 &self,
4266 pass: &mut RenderPass,
4267 buffer_id: id::BufferId,
4268 offset: BufferAddress,
4269 count: u32,
4270 ) -> Result<(), RenderPassError> {
4271 let scope = PassErrorScope::Draw {
4272 kind: DrawKind::MultiDrawIndirect,
4273 family: DrawCommandFamily::DrawMeshTasks,
4274 };
4275 let base = pass_base!(pass, scope);
4276
4277 base.commands.push(ArcRenderCommand::DrawIndirect {
4278 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4279 offset,
4280 count,
4281 family: DrawCommandFamily::DrawMeshTasks,
4282
4283 vertex_or_index_limit: None,
4284 instance_limit: None,
4285 });
4286
4287 Ok(())
4288 }
4289
4290 pub fn render_pass_multi_draw_indirect_count(
4291 &self,
4292 pass: &mut RenderPass,
4293 buffer_id: id::BufferId,
4294 offset: BufferAddress,
4295 count_buffer_id: id::BufferId,
4296 count_buffer_offset: BufferAddress,
4297 max_count: u32,
4298 ) -> Result<(), PassStateError> {
4299 let scope = PassErrorScope::Draw {
4300 kind: DrawKind::MultiDrawIndirectCount,
4301 family: DrawCommandFamily::Draw,
4302 };
4303 let base = pass_base!(pass, scope);
4304
4305 base.commands
4306 .push(ArcRenderCommand::MultiDrawIndirectCount {
4307 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4308 offset,
4309 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
4310 count_buffer_offset,
4311 max_count,
4312 family: DrawCommandFamily::Draw,
4313 });
4314
4315 Ok(())
4316 }
4317
4318 pub fn render_pass_multi_draw_indexed_indirect_count(
4319 &self,
4320 pass: &mut RenderPass,
4321 buffer_id: id::BufferId,
4322 offset: BufferAddress,
4323 count_buffer_id: id::BufferId,
4324 count_buffer_offset: BufferAddress,
4325 max_count: u32,
4326 ) -> Result<(), PassStateError> {
4327 let scope = PassErrorScope::Draw {
4328 kind: DrawKind::MultiDrawIndirectCount,
4329 family: DrawCommandFamily::DrawIndexed,
4330 };
4331 let base = pass_base!(pass, scope);
4332
4333 base.commands
4334 .push(ArcRenderCommand::MultiDrawIndirectCount {
4335 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4336 offset,
4337 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
4338 count_buffer_offset,
4339 max_count,
4340 family: DrawCommandFamily::DrawIndexed,
4341 });
4342
4343 Ok(())
4344 }
4345
4346 pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
4347 &self,
4348 pass: &mut RenderPass,
4349 buffer_id: id::BufferId,
4350 offset: BufferAddress,
4351 count_buffer_id: id::BufferId,
4352 count_buffer_offset: BufferAddress,
4353 max_count: u32,
4354 ) -> Result<(), RenderPassError> {
4355 let scope = PassErrorScope::Draw {
4356 kind: DrawKind::MultiDrawIndirectCount,
4357 family: DrawCommandFamily::DrawMeshTasks,
4358 };
4359 let base = pass_base!(pass, scope);
4360
4361 base.commands
4362 .push(ArcRenderCommand::MultiDrawIndirectCount {
4363 buffer: pass_try!(base, scope, self.resolve_buffer_id(buffer_id)),
4364 offset,
4365 count_buffer: pass_try!(base, scope, self.resolve_buffer_id(count_buffer_id)),
4366 count_buffer_offset,
4367 max_count,
4368 family: DrawCommandFamily::DrawMeshTasks,
4369 });
4370
4371 Ok(())
4372 }
4373
4374 pub fn render_pass_push_debug_group(
4375 &self,
4376 pass: &mut RenderPass,
4377 label: &str,
4378 color: u32,
4379 ) -> Result<(), PassStateError> {
4380 let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
4381
4382 let bytes = label.as_bytes();
4383 base.string_data.extend_from_slice(bytes);
4384
4385 base.commands.push(ArcRenderCommand::PushDebugGroup {
4386 color,
4387 len: bytes.len(),
4388 });
4389
4390 Ok(())
4391 }
4392
4393 pub fn render_pass_push_debug_group_with_id(
4394 &self,
4395 pass: id::RenderPassEncoderId,
4396 label: &str,
4397 color: u32,
4398 ) -> Result<(), PassStateError> {
4399 let pass = self.hub.render_passes.get(pass);
4400 let mut pass = pass
4401 .try_lock()
4402 .expect("RenderPasses should not be used concurrently");
4403 self.render_pass_push_debug_group(&mut pass, label, color)
4404 }
4405
4406 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
4407 let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
4408
4409 base.commands.push(ArcRenderCommand::PopDebugGroup);
4410
4411 Ok(())
4412 }
4413
4414 pub fn render_pass_pop_debug_group_with_id(
4415 &self,
4416 pass: id::RenderPassEncoderId,
4417 ) -> Result<(), PassStateError> {
4418 let pass = self.hub.render_passes.get(pass);
4419 let mut pass = pass
4420 .try_lock()
4421 .expect("RenderPasses should not be used concurrently");
4422 self.render_pass_pop_debug_group(&mut pass)
4423 }
4424
4425 pub fn render_pass_insert_debug_marker(
4426 &self,
4427 pass: &mut RenderPass,
4428 label: &str,
4429 color: u32,
4430 ) -> Result<(), PassStateError> {
4431 let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
4432
4433 let bytes = label.as_bytes();
4434 base.string_data.extend_from_slice(bytes);
4435
4436 base.commands.push(ArcRenderCommand::InsertDebugMarker {
4437 color,
4438 len: bytes.len(),
4439 });
4440
4441 Ok(())
4442 }
4443
4444 pub fn render_pass_insert_debug_marker_with_id(
4445 &self,
4446 pass: id::RenderPassEncoderId,
4447 label: &str,
4448 color: u32,
4449 ) -> Result<(), PassStateError> {
4450 let pass = self.hub.render_passes.get(pass);
4451 let mut pass = pass
4452 .try_lock()
4453 .expect("RenderPasses should not be used concurrently");
4454 self.render_pass_insert_debug_marker(&mut pass, label, color)
4455 }
4456
4457 pub fn render_pass_write_timestamp(
4458 &self,
4459 pass: &mut RenderPass,
4460 query_set_id: id::QuerySetId,
4461 query_index: u32,
4462 ) -> Result<(), PassStateError> {
4463 let scope = PassErrorScope::WriteTimestamp;
4464 let base = pass_base!(pass, scope);
4465
4466 let query_set = self.resolve_query_set_id(query_set_id);
4467 pass_try!(base, scope, query_set.check_is_valid());
4468 base.commands.push(ArcRenderCommand::WriteTimestamp {
4469 query_set,
4470 query_index,
4471 });
4472
4473 Ok(())
4474 }
4475
4476 pub fn render_pass_write_timestamp_with_id(
4477 &self,
4478 pass: id::RenderPassEncoderId,
4479 query_set_id: id::QuerySetId,
4480 query_index: u32,
4481 ) -> Result<(), PassStateError> {
4482 let pass = self.hub.render_passes.get(pass);
4483 let mut pass = pass
4484 .try_lock()
4485 .expect("RenderPasses should not be used concurrently");
4486 self.render_pass_write_timestamp(&mut pass, query_set_id, query_index)
4487 }
4488
4489 pub fn render_pass_begin_occlusion_query(
4490 &self,
4491 pass: &mut RenderPass,
4492 query_index: u32,
4493 ) -> Result<(), PassStateError> {
4494 let scope = PassErrorScope::BeginOcclusionQuery;
4495 let base = pass_base!(pass, scope);
4496
4497 base.commands
4498 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
4499
4500 Ok(())
4501 }
4502
4503 pub fn render_pass_begin_occlusion_query_with_id(
4504 &self,
4505 pass: id::RenderPassEncoderId,
4506 query_index: u32,
4507 ) -> Result<(), PassStateError> {
4508 let pass = self.hub.render_passes.get(pass);
4509 let mut pass = pass
4510 .try_lock()
4511 .expect("RenderPasses should not be used concurrently");
4512 self.render_pass_begin_occlusion_query(&mut pass, query_index)
4513 }
4514
4515 pub fn render_pass_end_occlusion_query(
4516 &self,
4517 pass: &mut RenderPass,
4518 ) -> Result<(), PassStateError> {
4519 let scope = PassErrorScope::EndOcclusionQuery;
4520 let base = pass_base!(pass, scope);
4521
4522 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
4523
4524 Ok(())
4525 }
4526
4527 pub fn render_pass_end_occlusion_query_with_id(
4528 &self,
4529 pass: id::RenderPassEncoderId,
4530 ) -> Result<(), PassStateError> {
4531 let pass = self.hub.render_passes.get(pass);
4532 let mut pass = pass
4533 .try_lock()
4534 .expect("RenderPasses should not be used concurrently");
4535 self.render_pass_end_occlusion_query(&mut pass)
4536 }
4537
4538 pub fn render_pass_begin_pipeline_statistics_query(
4539 &self,
4540 pass: &mut RenderPass,
4541 query_set_id: id::QuerySetId,
4542 query_index: u32,
4543 ) -> Result<(), PassStateError> {
4544 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
4545 let base = pass_base!(pass, scope);
4546
4547 let query_set = self.resolve_query_set_id(query_set_id);
4548 pass_try!(base, scope, query_set.check_is_valid());
4549 base.commands
4550 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
4551 query_set,
4552 query_index,
4553 });
4554
4555 Ok(())
4556 }
4557
4558 pub fn render_pass_begin_pipeline_statistics_query_with_id(
4559 &self,
4560 pass: id::RenderPassEncoderId,
4561 query_set_id: id::QuerySetId,
4562 query_index: u32,
4563 ) -> Result<(), PassStateError> {
4564 let pass = self.hub.render_passes.get(pass);
4565 let mut pass = pass
4566 .try_lock()
4567 .expect("RenderPasses should not be used concurrently");
4568 self.render_pass_begin_pipeline_statistics_query(&mut pass, query_set_id, query_index)
4569 }
4570
4571 pub fn render_pass_end_pipeline_statistics_query(
4572 &self,
4573 pass: &mut RenderPass,
4574 ) -> Result<(), PassStateError> {
4575 let scope = PassErrorScope::EndPipelineStatisticsQuery;
4576 let base = pass_base!(pass, scope);
4577
4578 base.commands
4579 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
4580
4581 Ok(())
4582 }
4583
4584 pub fn render_pass_end_pipeline_statistics_query_with_id(
4585 &self,
4586 pass: id::RenderPassEncoderId,
4587 ) -> Result<(), PassStateError> {
4588 let pass = self.hub.render_passes.get(pass);
4589 let mut pass = pass
4590 .try_lock()
4591 .expect("RenderPasses should not be used concurrently");
4592 self.render_pass_end_pipeline_statistics_query(&mut pass)
4593 }
4594
4595 pub fn render_pass_execute_bundles(
4596 &self,
4597 pass: &mut RenderPass,
4598 render_bundle_ids: &[id::RenderBundleId],
4599 ) -> Result<(), PassStateError> {
4600 let scope = PassErrorScope::ExecuteBundle;
4601 let base = pass_base!(pass, scope);
4602
4603 let hub = &self.hub;
4604 let bundles = hub.render_bundles.read();
4605
4606 for &bundle_id in render_bundle_ids {
4607 let bundle = bundles.get(bundle_id);
4608 pass_try!(base, scope, bundle.check_is_valid());
4609
4610 base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
4611 }
4612 pass.current_pipeline.reset();
4613 pass.current_bind_groups.reset();
4614
4615 Ok(())
4616 }
4617
4618 pub fn render_pass_execute_bundles_with_id(
4619 &self,
4620 pass: id::RenderPassEncoderId,
4621 render_bundle_ids: &[id::RenderBundleId],
4622 ) -> Result<(), PassStateError> {
4623 let pass = self.hub.render_passes.get(pass);
4624 let mut pass = pass
4625 .try_lock()
4626 .expect("RenderPasses should not be used concurrently");
4627 self.render_pass_execute_bundles(&mut pass, render_bundle_ids)
4628 }
4629}
4630
4631pub(crate) const fn get_src_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
4632 match family {
4633 DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
4634 DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
4635 DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
4636 }
4637}
4638
4639pub(crate) const fn get_dst_stride_of_indirect_args(
4640 backend: wgt::Backend,
4641 family: DrawCommandFamily,
4642) -> u64 {
4643 let extra = if matches!(backend, wgt::Backend::Dx12) {
4645 3 * size_of::<u32>() as u64
4646 } else {
4647 0
4648 };
4649 extra + get_src_stride_of_indirect_args(family)
4650}