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