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