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 pass, pass_base, pass_try, validate_and_begin_occlusion_query,
14 validate_and_begin_pipeline_statistics_query, DebugGroupError, EncoderStateError,
15 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 general: pass::BaseState<'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.general.binder.check_compatibility(pipeline.as_ref())?;
519 self.general.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.general.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.commands {
1756 list.push(crate::device::trace::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 let pass_scope = PassErrorScope::Pass;
1811 profiling::scope!(
1812 "CommandEncoder::run_render_pass {}",
1813 pass.base.label.as_deref().unwrap_or("")
1814 );
1815
1816 let cmd_enc = pass.parent.take().ok_or(EncoderStateError::Ended)?;
1817 let mut cmd_buf_data = cmd_enc.data.lock();
1818
1819 if let Some(err) = pass.base.error.take() {
1820 if matches!(
1821 err,
1822 RenderPassError {
1823 inner: RenderPassErrorInner::EncoderState(EncoderStateError::Ended),
1824 scope: _,
1825 }
1826 ) {
1827 return Err(EncoderStateError::Ended);
1832 } else {
1833 cmd_buf_data.invalidate(err);
1837 return Ok(());
1838 }
1839 }
1840
1841 cmd_buf_data.unlock_and_record(|cmd_buf_data| -> Result<(), RenderPassError> {
1842 let device = &cmd_enc.device;
1843 device.check_is_valid().map_pass_err(pass_scope)?;
1844 let snatch_guard = &device.snatchable_lock.read();
1845
1846 let base = &mut pass.base;
1847
1848 let mut indirect_draw_validation_batcher =
1849 crate::indirect_validation::DrawBatcher::new();
1850
1851 let (scope, pending_discard_init_fixups) = {
1852 let encoder = &mut cmd_buf_data.encoder;
1853 let tracker = &mut cmd_buf_data.trackers;
1854 let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions;
1855 let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
1856 let pending_query_resets = &mut cmd_buf_data.pending_query_resets;
1857 let indirect_draw_validation_resources =
1858 &mut cmd_buf_data.indirect_draw_validation_resources;
1859
1860 encoder.close_if_open().map_pass_err(pass_scope)?;
1864 encoder
1865 .open_pass(base.label.as_deref())
1866 .map_pass_err(pass_scope)?;
1867
1868 let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
1869
1870 let info = RenderPassInfo::start(
1871 device,
1872 hal_label(base.label.as_deref(), device.instance_flags),
1873 pass.color_attachments.take(),
1874 pass.depth_stencil_attachment.take(),
1875 pass.timestamp_writes.take(),
1876 pass.occlusion_query_set.clone(),
1879 encoder,
1880 tracker,
1881 texture_memory_actions,
1882 pending_query_resets,
1883 &mut pending_discard_init_fixups,
1884 snatch_guard,
1885 )
1886 .map_pass_err(pass_scope)?;
1887
1888 let indices = &device.tracker_indices;
1889 tracker.buffers.set_size(indices.buffers.size());
1890 tracker.textures.set_size(indices.textures.size());
1891
1892 let mut state = State {
1893 pipeline_flags: PipelineFlags::empty(),
1894 blend_constant: OptionalState::Unused,
1895 stencil_reference: 0,
1896 pipeline: None,
1897 index: IndexState::default(),
1898 vertex: VertexState::default(),
1899
1900 info,
1901
1902 general: pass::BaseState {
1903 device,
1904 raw_encoder: encoder.raw.as_mut(),
1905 tracker,
1906 buffer_memory_init_actions,
1907 texture_memory_actions,
1908 as_actions: &mut cmd_buf_data.as_actions,
1909 pending_discard_init_fixups,
1910 scope: device.new_usage_scope(),
1911 binder: Binder::new(),
1912
1913 snatch_guard,
1914
1915 temp_offsets: Vec::new(),
1916 dynamic_offset_count: 0,
1917
1918 debug_scope_depth: 0,
1919 string_offset: 0,
1920 },
1921
1922 active_occlusion_query: None,
1923 active_pipeline_statistics_query: None,
1924 };
1925
1926 for command in base.commands.drain(..) {
1927 match command {
1928 ArcRenderCommand::SetBindGroup {
1929 index,
1930 num_dynamic_offsets,
1931 bind_group,
1932 } => {
1933 let scope = PassErrorScope::SetBindGroup;
1934 pass::set_bind_group::<RenderPassErrorInner>(
1935 &mut state.general,
1936 cmd_enc.as_ref(),
1937 &base.dynamic_offsets,
1938 index,
1939 num_dynamic_offsets,
1940 bind_group,
1941 true,
1942 )
1943 .map_pass_err(scope)?;
1944 }
1945 ArcRenderCommand::SetPipeline(pipeline) => {
1946 let scope = PassErrorScope::SetPipelineRender;
1947 set_pipeline(&mut state, &cmd_enc, pipeline).map_pass_err(scope)?;
1948 }
1949 ArcRenderCommand::SetIndexBuffer {
1950 buffer,
1951 index_format,
1952 offset,
1953 size,
1954 } => {
1955 let scope = PassErrorScope::SetIndexBuffer;
1956 set_index_buffer(
1957 &mut state,
1958 &cmd_enc,
1959 buffer,
1960 index_format,
1961 offset,
1962 size,
1963 )
1964 .map_pass_err(scope)?;
1965 }
1966 ArcRenderCommand::SetVertexBuffer {
1967 slot,
1968 buffer,
1969 offset,
1970 size,
1971 } => {
1972 let scope = PassErrorScope::SetVertexBuffer;
1973 set_vertex_buffer(&mut state, &cmd_enc, slot, buffer, offset, size)
1974 .map_pass_err(scope)?;
1975 }
1976 ArcRenderCommand::SetBlendConstant(ref color) => {
1977 set_blend_constant(&mut state, color);
1978 }
1979 ArcRenderCommand::SetStencilReference(value) => {
1980 set_stencil_reference(&mut state, value);
1981 }
1982 ArcRenderCommand::SetViewport {
1983 rect,
1984 depth_min,
1985 depth_max,
1986 } => {
1987 let scope = PassErrorScope::SetViewport;
1988 set_viewport(&mut state, rect, depth_min, depth_max)
1989 .map_pass_err(scope)?;
1990 }
1991 ArcRenderCommand::SetPushConstant {
1992 stages,
1993 offset,
1994 size_bytes,
1995 values_offset,
1996 } => {
1997 let scope = PassErrorScope::SetPushConstant;
1998 pass::set_push_constant::<RenderPassErrorInner, _>(
1999 &mut state.general,
2000 &base.push_constant_data,
2001 stages,
2002 offset,
2003 size_bytes,
2004 values_offset,
2005 |_| {},
2006 )
2007 .map_pass_err(scope)?;
2008 }
2009 ArcRenderCommand::SetScissor(rect) => {
2010 let scope = PassErrorScope::SetScissorRect;
2011 set_scissor(&mut state, rect).map_pass_err(scope)?;
2012 }
2013 ArcRenderCommand::Draw {
2014 vertex_count,
2015 instance_count,
2016 first_vertex,
2017 first_instance,
2018 } => {
2019 let scope = PassErrorScope::Draw {
2020 kind: DrawKind::Draw,
2021 family: DrawCommandFamily::Draw,
2022 };
2023 draw(
2024 &mut state,
2025 vertex_count,
2026 instance_count,
2027 first_vertex,
2028 first_instance,
2029 )
2030 .map_pass_err(scope)?;
2031 }
2032 ArcRenderCommand::DrawIndexed {
2033 index_count,
2034 instance_count,
2035 first_index,
2036 base_vertex,
2037 first_instance,
2038 } => {
2039 let scope = PassErrorScope::Draw {
2040 kind: DrawKind::Draw,
2041 family: DrawCommandFamily::DrawIndexed,
2042 };
2043 draw_indexed(
2044 &mut state,
2045 index_count,
2046 instance_count,
2047 first_index,
2048 base_vertex,
2049 first_instance,
2050 )
2051 .map_pass_err(scope)?;
2052 }
2053 ArcRenderCommand::DrawMeshTasks {
2054 group_count_x,
2055 group_count_y,
2056 group_count_z,
2057 } => {
2058 let scope = PassErrorScope::Draw {
2059 kind: DrawKind::Draw,
2060 family: DrawCommandFamily::DrawMeshTasks,
2061 };
2062 draw_mesh_tasks(
2063 &mut state,
2064 group_count_x,
2065 group_count_y,
2066 group_count_z,
2067 )
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 indirect_draw_validation_resources,
2090 &mut indirect_draw_validation_batcher,
2091 &cmd_enc,
2092 buffer,
2093 offset,
2094 count,
2095 family,
2096 )
2097 .map_pass_err(scope)?;
2098 }
2099 ArcRenderCommand::MultiDrawIndirectCount {
2100 buffer,
2101 offset,
2102 count_buffer,
2103 count_buffer_offset,
2104 max_count,
2105 family,
2106 } => {
2107 let scope = PassErrorScope::Draw {
2108 kind: DrawKind::MultiDrawIndirectCount,
2109 family,
2110 };
2111 multi_draw_indirect_count(
2112 &mut state,
2113 &cmd_enc,
2114 buffer,
2115 offset,
2116 count_buffer,
2117 count_buffer_offset,
2118 max_count,
2119 family,
2120 )
2121 .map_pass_err(scope)?;
2122 }
2123 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2124 pass::push_debug_group(&mut state.general, &base.string_data, len);
2125 }
2126 ArcRenderCommand::PopDebugGroup => {
2127 let scope = PassErrorScope::PopDebugGroup;
2128 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.general)
2129 .map_pass_err(scope)?;
2130 }
2131 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2132 pass::insert_debug_marker(&mut state.general, &base.string_data, len);
2133 }
2134 ArcRenderCommand::WriteTimestamp {
2135 query_set,
2136 query_index,
2137 } => {
2138 let scope = PassErrorScope::WriteTimestamp;
2139 pass::write_timestamp::<RenderPassErrorInner>(
2140 &mut state.general,
2141 cmd_enc.as_ref(),
2142 Some(&mut cmd_buf_data.pending_query_resets),
2143 query_set,
2144 query_index,
2145 )
2146 .map_pass_err(scope)?;
2147 }
2148 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2149 api_log!("RenderPass::begin_occlusion_query {query_index}");
2150 let scope = PassErrorScope::BeginOcclusionQuery;
2151
2152 let query_set = pass
2153 .occlusion_query_set
2154 .clone()
2155 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2156 .map_pass_err(scope)?;
2157
2158 validate_and_begin_occlusion_query(
2159 query_set,
2160 state.general.raw_encoder,
2161 &mut state.general.tracker.query_sets,
2162 query_index,
2163 Some(&mut cmd_buf_data.pending_query_resets),
2164 &mut state.active_occlusion_query,
2165 )
2166 .map_pass_err(scope)?;
2167 }
2168 ArcRenderCommand::EndOcclusionQuery => {
2169 api_log!("RenderPass::end_occlusion_query");
2170 let scope = PassErrorScope::EndOcclusionQuery;
2171
2172 end_occlusion_query(
2173 state.general.raw_encoder,
2174 &mut state.active_occlusion_query,
2175 )
2176 .map_pass_err(scope)?;
2177 }
2178 ArcRenderCommand::BeginPipelineStatisticsQuery {
2179 query_set,
2180 query_index,
2181 } => {
2182 api_log!(
2183 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2184 query_set.error_ident()
2185 );
2186 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2187
2188 validate_and_begin_pipeline_statistics_query(
2189 query_set,
2190 state.general.raw_encoder,
2191 &mut state.general.tracker.query_sets,
2192 cmd_enc.as_ref(),
2193 query_index,
2194 Some(&mut cmd_buf_data.pending_query_resets),
2195 &mut state.active_pipeline_statistics_query,
2196 )
2197 .map_pass_err(scope)?;
2198 }
2199 ArcRenderCommand::EndPipelineStatisticsQuery => {
2200 api_log!("RenderPass::end_pipeline_statistics_query");
2201 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2202
2203 end_pipeline_statistics_query(
2204 state.general.raw_encoder,
2205 &mut state.active_pipeline_statistics_query,
2206 )
2207 .map_pass_err(scope)?;
2208 }
2209 ArcRenderCommand::ExecuteBundle(bundle) => {
2210 let scope = PassErrorScope::ExecuteBundle;
2211 execute_bundle(
2212 &mut state,
2213 indirect_draw_validation_resources,
2214 &mut indirect_draw_validation_batcher,
2215 &cmd_enc,
2216 bundle,
2217 )
2218 .map_pass_err(scope)?;
2219 }
2220 }
2221 }
2222
2223 if state.general.debug_scope_depth > 0 {
2224 Err(
2225 RenderPassErrorInner::DebugGroupError(DebugGroupError::MissingPop)
2226 .map_pass_err(pass_scope),
2227 )?;
2228 }
2229
2230 state
2231 .info
2232 .finish(
2233 device,
2234 state.general.raw_encoder,
2235 state.general.snatch_guard,
2236 &mut state.general.scope,
2237 self.instance.flags,
2238 )
2239 .map_pass_err(pass_scope)?;
2240
2241 let trackers = state.general.scope;
2242
2243 let pending_discard_init_fixups = state.general.pending_discard_init_fixups;
2244
2245 encoder.close().map_pass_err(pass_scope)?;
2246 (trackers, pending_discard_init_fixups)
2247 };
2248
2249 let encoder = &mut cmd_buf_data.encoder;
2250 let tracker = &mut cmd_buf_data.trackers;
2251
2252 {
2253 let transit = encoder
2254 .open_pass(hal_label(
2255 Some("(wgpu internal) Pre Pass"),
2256 self.instance.flags,
2257 ))
2258 .map_pass_err(pass_scope)?;
2259
2260 fixup_discarded_surfaces(
2261 pending_discard_init_fixups.into_iter(),
2262 transit,
2263 &mut tracker.textures,
2264 &cmd_enc.device,
2265 snatch_guard,
2266 );
2267
2268 cmd_buf_data.pending_query_resets.reset_queries(transit);
2269
2270 CommandEncoder::insert_barriers_from_scope(transit, tracker, &scope, snatch_guard);
2271
2272 if let Some(ref indirect_validation) = device.indirect_validation {
2273 indirect_validation
2274 .draw
2275 .inject_validation_pass(
2276 device,
2277 snatch_guard,
2278 &mut cmd_buf_data.indirect_draw_validation_resources,
2279 &mut cmd_buf_data.temp_resources,
2280 transit,
2281 indirect_draw_validation_batcher,
2282 )
2283 .map_pass_err(pass_scope)?;
2284 }
2285 }
2286
2287 encoder.close_and_swap().map_pass_err(pass_scope)?;
2288
2289 Ok(())
2290 })
2291 }
2292}
2293
2294fn set_pipeline(
2295 state: &mut State,
2296 cmd_enc: &Arc<CommandEncoder>,
2297 pipeline: Arc<RenderPipeline>,
2298) -> Result<(), RenderPassErrorInner> {
2299 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2300
2301 state.pipeline = Some(pipeline.clone());
2302
2303 let pipeline = state
2304 .general
2305 .tracker
2306 .render_pipelines
2307 .insert_single(pipeline)
2308 .clone();
2309
2310 pipeline.same_device_as(cmd_enc.as_ref())?;
2311
2312 state
2313 .info
2314 .context
2315 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2316 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2317
2318 state.pipeline_flags = pipeline.flags;
2319
2320 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2321 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2322 }
2323 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2324 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2325 }
2326
2327 state
2328 .blend_constant
2329 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2330
2331 unsafe {
2332 state
2333 .general
2334 .raw_encoder
2335 .set_render_pipeline(pipeline.raw());
2336 }
2337
2338 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2339 unsafe {
2340 state
2341 .general
2342 .raw_encoder
2343 .set_stencil_reference(state.stencil_reference);
2344 }
2345 }
2346
2347 pass::rebind_resources::<RenderPassErrorInner, _>(
2349 &mut state.general,
2350 &pipeline.layout,
2351 &pipeline.late_sized_buffer_groups,
2352 || {},
2353 )?;
2354
2355 state.vertex.update_limits(&pipeline.vertex_steps);
2357 Ok(())
2358}
2359
2360fn set_index_buffer(
2362 state: &mut State,
2363 cmd_enc: &Arc<CommandEncoder>,
2364 buffer: Arc<crate::resource::Buffer>,
2365 index_format: IndexFormat,
2366 offset: u64,
2367 size: Option<BufferSize>,
2368) -> Result<(), RenderPassErrorInner> {
2369 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2370
2371 state
2372 .general
2373 .scope
2374 .buffers
2375 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2376
2377 buffer.same_device_as(cmd_enc.as_ref())?;
2378
2379 buffer.check_usage(BufferUsages::INDEX)?;
2380
2381 if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
2382 return Err(RenderCommandError::UnalignedIndexBuffer {
2383 offset,
2384 alignment: index_format.byte_size(),
2385 }
2386 .into());
2387 }
2388 let (binding, resolved_size) = buffer
2389 .binding(offset, size, state.general.snatch_guard)
2390 .map_err(RenderCommandError::from)?;
2391 let end = offset + resolved_size;
2392 state.index.update_buffer(offset..end, index_format);
2393
2394 state.general.buffer_memory_init_actions.extend(
2395 buffer.initialization_status.read().create_action(
2396 &buffer,
2397 offset..end,
2398 MemoryInitKind::NeedsInitializedMemory,
2399 ),
2400 );
2401
2402 unsafe {
2403 hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, binding, index_format);
2404 }
2405 Ok(())
2406}
2407
2408fn set_vertex_buffer(
2410 state: &mut State,
2411 cmd_enc: &Arc<CommandEncoder>,
2412 slot: u32,
2413 buffer: Arc<crate::resource::Buffer>,
2414 offset: u64,
2415 size: Option<BufferSize>,
2416) -> Result<(), RenderPassErrorInner> {
2417 api_log!(
2418 "RenderPass::set_vertex_buffer {slot} {}",
2419 buffer.error_ident()
2420 );
2421
2422 state
2423 .general
2424 .scope
2425 .buffers
2426 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2427
2428 buffer.same_device_as(cmd_enc.as_ref())?;
2429
2430 let max_vertex_buffers = state.general.device.limits.max_vertex_buffers;
2431 if slot >= max_vertex_buffers {
2432 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2433 index: slot,
2434 max: max_vertex_buffers,
2435 }
2436 .into());
2437 }
2438
2439 buffer.check_usage(BufferUsages::VERTEX)?;
2440
2441 if offset % wgt::VERTEX_ALIGNMENT != 0 {
2442 return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2443 }
2444 let (binding, buffer_size) = buffer
2445 .binding(offset, size, state.general.snatch_guard)
2446 .map_err(RenderCommandError::from)?;
2447 state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
2448
2449 state.general.buffer_memory_init_actions.extend(
2450 buffer.initialization_status.read().create_action(
2451 &buffer,
2452 offset..(offset + buffer_size),
2453 MemoryInitKind::NeedsInitializedMemory,
2454 ),
2455 );
2456
2457 unsafe {
2458 hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, binding);
2459 }
2460 if let Some(pipeline) = state.pipeline.as_ref() {
2461 state.vertex.update_limits(&pipeline.vertex_steps);
2462 }
2463 Ok(())
2464}
2465
2466fn set_blend_constant(state: &mut State, color: &Color) {
2467 api_log!("RenderPass::set_blend_constant");
2468
2469 state.blend_constant = OptionalState::Set;
2470 let array = [
2471 color.r as f32,
2472 color.g as f32,
2473 color.b as f32,
2474 color.a as f32,
2475 ];
2476 unsafe {
2477 state.general.raw_encoder.set_blend_constants(&array);
2478 }
2479}
2480
2481fn set_stencil_reference(state: &mut State, value: u32) {
2482 api_log!("RenderPass::set_stencil_reference {value}");
2483
2484 state.stencil_reference = value;
2485 if state
2486 .pipeline_flags
2487 .contains(PipelineFlags::STENCIL_REFERENCE)
2488 {
2489 unsafe {
2490 state.general.raw_encoder.set_stencil_reference(value);
2491 }
2492 }
2493}
2494
2495fn set_viewport(
2496 state: &mut State,
2497 rect: Rect<f32>,
2498 depth_min: f32,
2499 depth_max: f32,
2500) -> Result<(), RenderPassErrorInner> {
2501 api_log!("RenderPass::set_viewport {rect:?}");
2502
2503 if rect.w < 0.0
2504 || rect.h < 0.0
2505 || rect.w > state.general.device.limits.max_texture_dimension_2d as f32
2506 || rect.h > state.general.device.limits.max_texture_dimension_2d as f32
2507 {
2508 return Err(RenderCommandError::InvalidViewportRectSize {
2509 w: rect.w,
2510 h: rect.h,
2511 max: state.general.device.limits.max_texture_dimension_2d,
2512 }
2513 .into());
2514 }
2515
2516 let max_viewport_range = state.general.device.limits.max_texture_dimension_2d as f32 * 2.0;
2517
2518 if rect.x < -max_viewport_range
2519 || rect.y < -max_viewport_range
2520 || rect.x + rect.w > max_viewport_range - 1.0
2521 || rect.y + rect.h > max_viewport_range - 1.0
2522 {
2523 return Err(RenderCommandError::InvalidViewportRectPosition {
2524 rect,
2525 min: -max_viewport_range,
2526 max: max_viewport_range - 1.0,
2527 }
2528 .into());
2529 }
2530 if !(0.0..=1.0).contains(&depth_min)
2531 || !(0.0..=1.0).contains(&depth_max)
2532 || depth_min > depth_max
2533 {
2534 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
2535 }
2536 let r = hal::Rect {
2537 x: rect.x,
2538 y: rect.y,
2539 w: rect.w,
2540 h: rect.h,
2541 };
2542 unsafe {
2543 state
2544 .general
2545 .raw_encoder
2546 .set_viewport(&r, depth_min..depth_max);
2547 }
2548 Ok(())
2549}
2550
2551fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
2552 api_log!("RenderPass::set_scissor_rect {rect:?}");
2553
2554 if rect.x.saturating_add(rect.w) > state.info.extent.width
2555 || rect.y.saturating_add(rect.h) > state.info.extent.height
2556 {
2557 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
2558 }
2559 let r = hal::Rect {
2560 x: rect.x,
2561 y: rect.y,
2562 w: rect.w,
2563 h: rect.h,
2564 };
2565 unsafe {
2566 state.general.raw_encoder.set_scissor_rect(&r);
2567 }
2568 Ok(())
2569}
2570
2571fn draw(
2572 state: &mut State,
2573 vertex_count: u32,
2574 instance_count: u32,
2575 first_vertex: u32,
2576 first_instance: u32,
2577) -> Result<(), DrawError> {
2578 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
2579
2580 state.is_ready(DrawCommandFamily::Draw)?;
2581
2582 state
2583 .vertex
2584 .limits
2585 .validate_vertex_limit(first_vertex, vertex_count)?;
2586 state
2587 .vertex
2588 .limits
2589 .validate_instance_limit(first_instance, instance_count)?;
2590
2591 unsafe {
2592 if instance_count > 0 && vertex_count > 0 {
2593 state.general.raw_encoder.draw(
2594 first_vertex,
2595 vertex_count,
2596 first_instance,
2597 instance_count,
2598 );
2599 }
2600 }
2601 Ok(())
2602}
2603
2604fn draw_indexed(
2605 state: &mut State,
2606 index_count: u32,
2607 instance_count: u32,
2608 first_index: u32,
2609 base_vertex: i32,
2610 first_instance: u32,
2611) -> Result<(), DrawError> {
2612 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
2613
2614 state.is_ready(DrawCommandFamily::DrawIndexed)?;
2615
2616 let last_index = first_index as u64 + index_count as u64;
2617 let index_limit = state.index.limit;
2618 if last_index > index_limit {
2619 return Err(DrawError::IndexBeyondLimit {
2620 last_index,
2621 index_limit,
2622 });
2623 }
2624 state
2625 .vertex
2626 .limits
2627 .validate_instance_limit(first_instance, instance_count)?;
2628
2629 unsafe {
2630 if instance_count > 0 && index_count > 0 {
2631 state.general.raw_encoder.draw_indexed(
2632 first_index,
2633 index_count,
2634 base_vertex,
2635 first_instance,
2636 instance_count,
2637 );
2638 }
2639 }
2640 Ok(())
2641}
2642
2643fn draw_mesh_tasks(
2644 state: &mut State,
2645 group_count_x: u32,
2646 group_count_y: u32,
2647 group_count_z: u32,
2648) -> Result<(), DrawError> {
2649 api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
2650
2651 state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
2652
2653 let groups_size_limit = state
2654 .general
2655 .device
2656 .limits
2657 .max_task_workgroups_per_dimension;
2658 let max_groups = state.general.device.limits.max_task_workgroup_total_count;
2659 if group_count_x > groups_size_limit
2660 || group_count_y > groups_size_limit
2661 || group_count_z > groups_size_limit
2662 || group_count_x * group_count_y * group_count_z > max_groups
2663 {
2664 return Err(DrawError::InvalidGroupSize {
2665 current: [group_count_x, group_count_y, group_count_z],
2666 limit: groups_size_limit,
2667 max_total: max_groups,
2668 });
2669 }
2670
2671 unsafe {
2672 if group_count_x > 0 && group_count_y > 0 && group_count_z > 0 {
2673 state
2674 .general
2675 .raw_encoder
2676 .draw_mesh_tasks(group_count_x, group_count_y, group_count_z);
2677 }
2678 }
2679 Ok(())
2680}
2681
2682fn multi_draw_indirect(
2683 state: &mut State,
2684 indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
2685 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2686 cmd_enc: &Arc<CommandEncoder>,
2687 indirect_buffer: Arc<crate::resource::Buffer>,
2688 offset: u64,
2689 count: u32,
2690 family: DrawCommandFamily,
2691) -> Result<(), RenderPassErrorInner> {
2692 api_log!(
2693 "RenderPass::draw_indirect (family:{family:?}) {} {offset} {count:?}",
2694 indirect_buffer.error_ident()
2695 );
2696
2697 state.is_ready(family)?;
2698
2699 state
2700 .general
2701 .device
2702 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2703
2704 indirect_buffer.same_device_as(cmd_enc.as_ref())?;
2705 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2706 indirect_buffer.check_destroyed(state.general.snatch_guard)?;
2707
2708 if offset % 4 != 0 {
2709 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2710 }
2711
2712 let stride = get_stride_of_indirect_args(family);
2713
2714 let end_offset = offset + stride * count as u64;
2715 if end_offset > indirect_buffer.size {
2716 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2717 count,
2718 offset,
2719 end_offset,
2720 buffer_size: indirect_buffer.size,
2721 });
2722 }
2723
2724 state.general.buffer_memory_init_actions.extend(
2725 indirect_buffer.initialization_status.read().create_action(
2726 &indirect_buffer,
2727 offset..end_offset,
2728 MemoryInitKind::NeedsInitializedMemory,
2729 ),
2730 );
2731
2732 fn draw(
2733 raw_encoder: &mut dyn hal::DynCommandEncoder,
2734 family: DrawCommandFamily,
2735 indirect_buffer: &dyn hal::DynBuffer,
2736 offset: u64,
2737 count: u32,
2738 ) {
2739 match family {
2740 DrawCommandFamily::Draw => unsafe {
2741 raw_encoder.draw_indirect(indirect_buffer, offset, count);
2742 },
2743 DrawCommandFamily::DrawIndexed => unsafe {
2744 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2745 },
2746 DrawCommandFamily::DrawMeshTasks => unsafe {
2747 raw_encoder.draw_mesh_tasks_indirect(indirect_buffer, offset, count);
2748 },
2749 }
2750 }
2751
2752 if state.general.device.indirect_validation.is_some() {
2753 state
2754 .general
2755 .scope
2756 .buffers
2757 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
2758
2759 struct DrawData {
2760 buffer_index: usize,
2761 offset: u64,
2762 count: u32,
2763 }
2764
2765 struct DrawContext<'a> {
2766 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2767 device: &'a Device,
2768
2769 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
2770 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
2771
2772 indirect_buffer: Arc<crate::resource::Buffer>,
2773 family: DrawCommandFamily,
2774 vertex_or_index_limit: u64,
2775 instance_limit: u64,
2776 }
2777
2778 impl<'a> DrawContext<'a> {
2779 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2780 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2781 self.indirect_draw_validation_resources,
2782 self.device,
2783 &self.indirect_buffer,
2784 offset,
2785 self.family,
2786 self.vertex_or_index_limit,
2787 self.instance_limit,
2788 )?;
2789 Ok(DrawData {
2790 buffer_index: dst_resource_index,
2791 offset: dst_offset,
2792 count: 1,
2793 })
2794 }
2795 fn draw(&mut self, draw_data: DrawData) {
2796 let dst_buffer = self
2797 .indirect_draw_validation_resources
2798 .get_dst_buffer(draw_data.buffer_index);
2799 draw(
2800 self.raw_encoder,
2801 self.family,
2802 dst_buffer,
2803 draw_data.offset,
2804 draw_data.count,
2805 );
2806 }
2807 }
2808
2809 let mut draw_ctx = DrawContext {
2810 raw_encoder: state.general.raw_encoder,
2811 device: state.general.device,
2812 indirect_draw_validation_resources,
2813 indirect_draw_validation_batcher,
2814 indirect_buffer,
2815 family,
2816 vertex_or_index_limit: if family == DrawCommandFamily::DrawIndexed {
2817 state.index.limit
2818 } else {
2819 state.vertex.limits.vertex_limit
2820 },
2821 instance_limit: state.vertex.limits.instance_limit,
2822 };
2823
2824 let mut current_draw_data = draw_ctx.add(offset)?;
2825
2826 for i in 1..count {
2827 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2828
2829 if draw_data.buffer_index == current_draw_data.buffer_index {
2830 debug_assert_eq!(
2831 draw_data.offset,
2832 current_draw_data.offset + stride * current_draw_data.count as u64
2833 );
2834 current_draw_data.count += 1;
2835 } else {
2836 draw_ctx.draw(current_draw_data);
2837 current_draw_data = draw_data;
2838 }
2839 }
2840
2841 draw_ctx.draw(current_draw_data);
2842 } else {
2843 state
2844 .general
2845 .scope
2846 .buffers
2847 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2848
2849 draw(
2850 state.general.raw_encoder,
2851 family,
2852 indirect_buffer.try_raw(state.general.snatch_guard)?,
2853 offset,
2854 count,
2855 );
2856 };
2857
2858 Ok(())
2859}
2860
2861fn multi_draw_indirect_count(
2862 state: &mut State,
2863 cmd_enc: &Arc<CommandEncoder>,
2864 indirect_buffer: Arc<crate::resource::Buffer>,
2865 offset: u64,
2866 count_buffer: Arc<crate::resource::Buffer>,
2867 count_buffer_offset: u64,
2868 max_count: u32,
2869 family: DrawCommandFamily,
2870) -> Result<(), RenderPassErrorInner> {
2871 api_log!(
2872 "RenderPass::multi_draw_indirect_count (family:{family:?}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
2873 indirect_buffer.error_ident(),
2874 count_buffer.error_ident()
2875 );
2876
2877 state.is_ready(family)?;
2878
2879 let stride = get_stride_of_indirect_args(family);
2880
2881 state
2882 .general
2883 .device
2884 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
2885 state
2886 .general
2887 .device
2888 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2889
2890 indirect_buffer.same_device_as(cmd_enc.as_ref())?;
2891 count_buffer.same_device_as(cmd_enc.as_ref())?;
2892
2893 state
2894 .general
2895 .scope
2896 .buffers
2897 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2898
2899 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2900 let indirect_raw = indirect_buffer.try_raw(state.general.snatch_guard)?;
2901
2902 state
2903 .general
2904 .scope
2905 .buffers
2906 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
2907
2908 count_buffer.check_usage(BufferUsages::INDIRECT)?;
2909 let count_raw = count_buffer.try_raw(state.general.snatch_guard)?;
2910
2911 if offset % 4 != 0 {
2912 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2913 }
2914
2915 let end_offset = offset + stride * max_count as u64;
2916 if end_offset > indirect_buffer.size {
2917 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2918 count: 1,
2919 offset,
2920 end_offset,
2921 buffer_size: indirect_buffer.size,
2922 });
2923 }
2924 state.general.buffer_memory_init_actions.extend(
2925 indirect_buffer.initialization_status.read().create_action(
2926 &indirect_buffer,
2927 offset..end_offset,
2928 MemoryInitKind::NeedsInitializedMemory,
2929 ),
2930 );
2931
2932 let begin_count_offset = count_buffer_offset;
2933 let end_count_offset = count_buffer_offset + 4;
2934 if end_count_offset > count_buffer.size {
2935 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
2936 begin_count_offset,
2937 end_count_offset,
2938 count_buffer_size: count_buffer.size,
2939 });
2940 }
2941 state.general.buffer_memory_init_actions.extend(
2942 count_buffer.initialization_status.read().create_action(
2943 &count_buffer,
2944 count_buffer_offset..end_count_offset,
2945 MemoryInitKind::NeedsInitializedMemory,
2946 ),
2947 );
2948
2949 match family {
2950 DrawCommandFamily::Draw => unsafe {
2951 state.general.raw_encoder.draw_indirect_count(
2952 indirect_raw,
2953 offset,
2954 count_raw,
2955 count_buffer_offset,
2956 max_count,
2957 );
2958 },
2959 DrawCommandFamily::DrawIndexed => unsafe {
2960 state.general.raw_encoder.draw_indexed_indirect_count(
2961 indirect_raw,
2962 offset,
2963 count_raw,
2964 count_buffer_offset,
2965 max_count,
2966 );
2967 },
2968 DrawCommandFamily::DrawMeshTasks => unsafe {
2969 state.general.raw_encoder.draw_mesh_tasks_indirect_count(
2970 indirect_raw,
2971 offset,
2972 count_raw,
2973 count_buffer_offset,
2974 max_count,
2975 );
2976 },
2977 }
2978 Ok(())
2979}
2980
2981fn execute_bundle(
2982 state: &mut State,
2983 indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
2984 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2985 cmd_enc: &Arc<CommandEncoder>,
2986 bundle: Arc<super::RenderBundle>,
2987) -> Result<(), RenderPassErrorInner> {
2988 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
2989
2990 let bundle = state.general.tracker.bundles.insert_single(bundle);
2991
2992 bundle.same_device_as(cmd_enc.as_ref())?;
2993
2994 state
2995 .info
2996 .context
2997 .check_compatible(&bundle.context, bundle.as_ref())
2998 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
2999
3000 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
3001 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
3002 {
3003 return Err(
3004 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
3005 pass_depth: state.info.is_depth_read_only,
3006 pass_stencil: state.info.is_stencil_read_only,
3007 bundle_depth: bundle.is_depth_read_only,
3008 bundle_stencil: bundle.is_stencil_read_only,
3009 },
3010 );
3011 }
3012
3013 state.general.buffer_memory_init_actions.extend(
3014 bundle
3015 .buffer_memory_init_actions
3016 .iter()
3017 .filter_map(|action| {
3018 action
3019 .buffer
3020 .initialization_status
3021 .read()
3022 .check_action(action)
3023 }),
3024 );
3025 for action in bundle.texture_memory_init_actions.iter() {
3026 state.general.pending_discard_init_fixups.extend(
3027 state
3028 .general
3029 .texture_memory_actions
3030 .register_init_action(action),
3031 );
3032 }
3033
3034 unsafe {
3035 bundle.execute(
3036 state.general.raw_encoder,
3037 indirect_draw_validation_resources,
3038 indirect_draw_validation_batcher,
3039 state.general.snatch_guard,
3040 )
3041 }
3042 .map_err(|e| match e {
3043 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
3044 ExecutionError::DestroyedResource(e) => {
3045 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
3046 }
3047 ExecutionError::Unimplemented(what) => {
3048 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
3049 }
3050 })?;
3051
3052 unsafe {
3053 state.general.scope.merge_render_bundle(&bundle.used)?;
3054 };
3055 state.reset_bundle();
3056 Ok(())
3057}
3058
3059impl Global {
3072 fn resolve_render_pass_buffer_id(
3073 &self,
3074 buffer_id: id::Id<id::markers::Buffer>,
3075 ) -> Result<Arc<crate::resource::Buffer>, InvalidResourceError> {
3076 let hub = &self.hub;
3077 let buffer = hub.buffers.get(buffer_id).get()?;
3078
3079 Ok(buffer)
3080 }
3081
3082 fn resolve_render_pass_query_set(
3083 &self,
3084 query_set_id: id::Id<id::markers::QuerySet>,
3085 ) -> Result<Arc<QuerySet>, InvalidResourceError> {
3086 let hub = &self.hub;
3087 let query_set = hub.query_sets.get(query_set_id).get()?;
3088
3089 Ok(query_set)
3090 }
3091
3092 pub fn render_pass_set_bind_group(
3093 &self,
3094 pass: &mut RenderPass,
3095 index: u32,
3096 bind_group_id: Option<id::BindGroupId>,
3097 offsets: &[DynamicOffset],
3098 ) -> Result<(), PassStateError> {
3099 let scope = PassErrorScope::SetBindGroup;
3100
3101 let base = pass_base!(pass, scope);
3105
3106 if pass.current_bind_groups.set_and_check_redundant(
3107 bind_group_id,
3108 index,
3109 &mut base.dynamic_offsets,
3110 offsets,
3111 ) {
3112 return Ok(());
3113 }
3114
3115 let mut bind_group = None;
3116 if bind_group_id.is_some() {
3117 let bind_group_id = bind_group_id.unwrap();
3118
3119 let hub = &self.hub;
3120 bind_group = Some(pass_try!(
3121 base,
3122 scope,
3123 hub.bind_groups.get(bind_group_id).get(),
3124 ));
3125 }
3126
3127 base.commands.push(ArcRenderCommand::SetBindGroup {
3128 index,
3129 num_dynamic_offsets: offsets.len(),
3130 bind_group,
3131 });
3132
3133 Ok(())
3134 }
3135
3136 pub fn render_pass_set_pipeline(
3137 &self,
3138 pass: &mut RenderPass,
3139 pipeline_id: id::RenderPipelineId,
3140 ) -> Result<(), PassStateError> {
3141 let scope = PassErrorScope::SetPipelineRender;
3142
3143 let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3144
3145 let base = pass_base!(pass, scope);
3148
3149 if redundant {
3150 return Ok(());
3151 }
3152
3153 let hub = &self.hub;
3154 let pipeline = pass_try!(base, scope, hub.render_pipelines.get(pipeline_id).get());
3155
3156 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3157
3158 Ok(())
3159 }
3160
3161 pub fn render_pass_set_index_buffer(
3162 &self,
3163 pass: &mut RenderPass,
3164 buffer_id: id::BufferId,
3165 index_format: IndexFormat,
3166 offset: BufferAddress,
3167 size: Option<BufferSize>,
3168 ) -> Result<(), PassStateError> {
3169 let scope = PassErrorScope::SetIndexBuffer;
3170 let base = pass_base!(pass, scope);
3171
3172 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3173 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3174 index_format,
3175 offset,
3176 size,
3177 });
3178
3179 Ok(())
3180 }
3181
3182 pub fn render_pass_set_vertex_buffer(
3183 &self,
3184 pass: &mut RenderPass,
3185 slot: u32,
3186 buffer_id: id::BufferId,
3187 offset: BufferAddress,
3188 size: Option<BufferSize>,
3189 ) -> Result<(), PassStateError> {
3190 let scope = PassErrorScope::SetVertexBuffer;
3191 let base = pass_base!(pass, scope);
3192
3193 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3194 slot,
3195 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3196 offset,
3197 size,
3198 });
3199
3200 Ok(())
3201 }
3202
3203 pub fn render_pass_set_blend_constant(
3204 &self,
3205 pass: &mut RenderPass,
3206 color: Color,
3207 ) -> Result<(), PassStateError> {
3208 let scope = PassErrorScope::SetBlendConstant;
3209 let base = pass_base!(pass, scope);
3210
3211 base.commands
3212 .push(ArcRenderCommand::SetBlendConstant(color));
3213
3214 Ok(())
3215 }
3216
3217 pub fn render_pass_set_stencil_reference(
3218 &self,
3219 pass: &mut RenderPass,
3220 value: u32,
3221 ) -> Result<(), PassStateError> {
3222 let scope = PassErrorScope::SetStencilReference;
3223 let base = pass_base!(pass, scope);
3224
3225 base.commands
3226 .push(ArcRenderCommand::SetStencilReference(value));
3227
3228 Ok(())
3229 }
3230
3231 pub fn render_pass_set_viewport(
3232 &self,
3233 pass: &mut RenderPass,
3234 x: f32,
3235 y: f32,
3236 w: f32,
3237 h: f32,
3238 depth_min: f32,
3239 depth_max: f32,
3240 ) -> Result<(), PassStateError> {
3241 let scope = PassErrorScope::SetViewport;
3242 let base = pass_base!(pass, scope);
3243
3244 base.commands.push(ArcRenderCommand::SetViewport {
3245 rect: Rect { x, y, w, h },
3246 depth_min,
3247 depth_max,
3248 });
3249
3250 Ok(())
3251 }
3252
3253 pub fn render_pass_set_scissor_rect(
3254 &self,
3255 pass: &mut RenderPass,
3256 x: u32,
3257 y: u32,
3258 w: u32,
3259 h: u32,
3260 ) -> Result<(), PassStateError> {
3261 let scope = PassErrorScope::SetScissorRect;
3262 let base = pass_base!(pass, scope);
3263
3264 base.commands
3265 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3266
3267 Ok(())
3268 }
3269
3270 pub fn render_pass_set_push_constants(
3271 &self,
3272 pass: &mut RenderPass,
3273 stages: ShaderStages,
3274 offset: u32,
3275 data: &[u8],
3276 ) -> Result<(), PassStateError> {
3277 let scope = PassErrorScope::SetPushConstant;
3278 let base = pass_base!(pass, scope);
3279
3280 if offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 {
3281 pass_try!(
3282 base,
3283 scope,
3284 Err(RenderPassErrorInner::PushConstantOffsetAlignment)
3285 );
3286 }
3287 if data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 {
3288 pass_try!(
3289 base,
3290 scope,
3291 Err(RenderPassErrorInner::PushConstantSizeAlignment)
3292 );
3293 }
3294
3295 let value_offset = pass_try!(
3296 base,
3297 scope,
3298 base.push_constant_data
3299 .len()
3300 .try_into()
3301 .map_err(|_| RenderPassErrorInner::PushConstantOutOfMemory),
3302 );
3303
3304 base.push_constant_data.extend(
3305 data.chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize)
3306 .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3307 );
3308
3309 base.commands.push(ArcRenderCommand::SetPushConstant {
3310 stages,
3311 offset,
3312 size_bytes: data.len() as u32,
3313 values_offset: Some(value_offset),
3314 });
3315
3316 Ok(())
3317 }
3318
3319 pub fn render_pass_draw(
3320 &self,
3321 pass: &mut RenderPass,
3322 vertex_count: u32,
3323 instance_count: u32,
3324 first_vertex: u32,
3325 first_instance: u32,
3326 ) -> Result<(), PassStateError> {
3327 let scope = PassErrorScope::Draw {
3328 kind: DrawKind::Draw,
3329 family: DrawCommandFamily::Draw,
3330 };
3331 let base = pass_base!(pass, scope);
3332
3333 base.commands.push(ArcRenderCommand::Draw {
3334 vertex_count,
3335 instance_count,
3336 first_vertex,
3337 first_instance,
3338 });
3339
3340 Ok(())
3341 }
3342
3343 pub fn render_pass_draw_indexed(
3344 &self,
3345 pass: &mut RenderPass,
3346 index_count: u32,
3347 instance_count: u32,
3348 first_index: u32,
3349 base_vertex: i32,
3350 first_instance: u32,
3351 ) -> Result<(), PassStateError> {
3352 let scope = PassErrorScope::Draw {
3353 kind: DrawKind::Draw,
3354 family: DrawCommandFamily::DrawIndexed,
3355 };
3356 let base = pass_base!(pass, scope);
3357
3358 base.commands.push(ArcRenderCommand::DrawIndexed {
3359 index_count,
3360 instance_count,
3361 first_index,
3362 base_vertex,
3363 first_instance,
3364 });
3365
3366 Ok(())
3367 }
3368
3369 pub fn render_pass_draw_mesh_tasks(
3370 &self,
3371 pass: &mut RenderPass,
3372 group_count_x: u32,
3373 group_count_y: u32,
3374 group_count_z: u32,
3375 ) -> Result<(), RenderPassError> {
3376 let scope = PassErrorScope::Draw {
3377 kind: DrawKind::Draw,
3378 family: DrawCommandFamily::DrawMeshTasks,
3379 };
3380 let base = pass_base!(pass, scope);
3381
3382 base.commands.push(ArcRenderCommand::DrawMeshTasks {
3383 group_count_x,
3384 group_count_y,
3385 group_count_z,
3386 });
3387 Ok(())
3388 }
3389
3390 pub fn render_pass_draw_indirect(
3391 &self,
3392 pass: &mut RenderPass,
3393 buffer_id: id::BufferId,
3394 offset: BufferAddress,
3395 ) -> Result<(), PassStateError> {
3396 let scope = PassErrorScope::Draw {
3397 kind: DrawKind::DrawIndirect,
3398 family: DrawCommandFamily::Draw,
3399 };
3400 let base = pass_base!(pass, scope);
3401
3402 base.commands.push(ArcRenderCommand::DrawIndirect {
3403 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3404 offset,
3405 count: 1,
3406 family: DrawCommandFamily::Draw,
3407
3408 vertex_or_index_limit: 0,
3409 instance_limit: 0,
3410 });
3411
3412 Ok(())
3413 }
3414
3415 pub fn render_pass_draw_indexed_indirect(
3416 &self,
3417 pass: &mut RenderPass,
3418 buffer_id: id::BufferId,
3419 offset: BufferAddress,
3420 ) -> Result<(), PassStateError> {
3421 let scope = PassErrorScope::Draw {
3422 kind: DrawKind::DrawIndirect,
3423 family: DrawCommandFamily::DrawIndexed,
3424 };
3425 let base = pass_base!(pass, scope);
3426
3427 base.commands.push(ArcRenderCommand::DrawIndirect {
3428 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3429 offset,
3430 count: 1,
3431 family: DrawCommandFamily::DrawIndexed,
3432
3433 vertex_or_index_limit: 0,
3434 instance_limit: 0,
3435 });
3436
3437 Ok(())
3438 }
3439
3440 pub fn render_pass_draw_mesh_tasks_indirect(
3441 &self,
3442 pass: &mut RenderPass,
3443 buffer_id: id::BufferId,
3444 offset: BufferAddress,
3445 ) -> Result<(), RenderPassError> {
3446 let scope = PassErrorScope::Draw {
3447 kind: DrawKind::DrawIndirect,
3448 family: DrawCommandFamily::DrawMeshTasks,
3449 };
3450 let base = pass_base!(pass, scope);
3451
3452 base.commands.push(ArcRenderCommand::DrawIndirect {
3453 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3454 offset,
3455 count: 1,
3456 family: DrawCommandFamily::DrawMeshTasks,
3457
3458 vertex_or_index_limit: 0,
3459 instance_limit: 0,
3460 });
3461
3462 Ok(())
3463 }
3464
3465 pub fn render_pass_multi_draw_indirect(
3466 &self,
3467 pass: &mut RenderPass,
3468 buffer_id: id::BufferId,
3469 offset: BufferAddress,
3470 count: u32,
3471 ) -> Result<(), PassStateError> {
3472 let scope = PassErrorScope::Draw {
3473 kind: DrawKind::MultiDrawIndirect,
3474 family: DrawCommandFamily::Draw,
3475 };
3476 let base = pass_base!(pass, scope);
3477
3478 base.commands.push(ArcRenderCommand::DrawIndirect {
3479 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3480 offset,
3481 count,
3482 family: DrawCommandFamily::Draw,
3483
3484 vertex_or_index_limit: 0,
3485 instance_limit: 0,
3486 });
3487
3488 Ok(())
3489 }
3490
3491 pub fn render_pass_multi_draw_indexed_indirect(
3492 &self,
3493 pass: &mut RenderPass,
3494 buffer_id: id::BufferId,
3495 offset: BufferAddress,
3496 count: u32,
3497 ) -> Result<(), PassStateError> {
3498 let scope = PassErrorScope::Draw {
3499 kind: DrawKind::MultiDrawIndirect,
3500 family: DrawCommandFamily::DrawIndexed,
3501 };
3502 let base = pass_base!(pass, scope);
3503
3504 base.commands.push(ArcRenderCommand::DrawIndirect {
3505 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3506 offset,
3507 count,
3508 family: DrawCommandFamily::DrawIndexed,
3509
3510 vertex_or_index_limit: 0,
3511 instance_limit: 0,
3512 });
3513
3514 Ok(())
3515 }
3516
3517 pub fn render_pass_multi_draw_mesh_tasks_indirect(
3518 &self,
3519 pass: &mut RenderPass,
3520 buffer_id: id::BufferId,
3521 offset: BufferAddress,
3522 count: u32,
3523 ) -> Result<(), RenderPassError> {
3524 let scope = PassErrorScope::Draw {
3525 kind: DrawKind::MultiDrawIndirect,
3526 family: DrawCommandFamily::DrawMeshTasks,
3527 };
3528 let base = pass_base!(pass, scope);
3529
3530 base.commands.push(ArcRenderCommand::DrawIndirect {
3531 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3532 offset,
3533 count,
3534 family: DrawCommandFamily::DrawMeshTasks,
3535
3536 vertex_or_index_limit: 0,
3537 instance_limit: 0,
3538 });
3539
3540 Ok(())
3541 }
3542
3543 pub fn render_pass_multi_draw_indirect_count(
3544 &self,
3545 pass: &mut RenderPass,
3546 buffer_id: id::BufferId,
3547 offset: BufferAddress,
3548 count_buffer_id: id::BufferId,
3549 count_buffer_offset: BufferAddress,
3550 max_count: u32,
3551 ) -> Result<(), PassStateError> {
3552 let scope = PassErrorScope::Draw {
3553 kind: DrawKind::MultiDrawIndirectCount,
3554 family: DrawCommandFamily::Draw,
3555 };
3556 let base = pass_base!(pass, scope);
3557
3558 base.commands
3559 .push(ArcRenderCommand::MultiDrawIndirectCount {
3560 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3561 offset,
3562 count_buffer: pass_try!(
3563 base,
3564 scope,
3565 self.resolve_render_pass_buffer_id(count_buffer_id)
3566 ),
3567 count_buffer_offset,
3568 max_count,
3569 family: DrawCommandFamily::Draw,
3570 });
3571
3572 Ok(())
3573 }
3574
3575 pub fn render_pass_multi_draw_indexed_indirect_count(
3576 &self,
3577 pass: &mut RenderPass,
3578 buffer_id: id::BufferId,
3579 offset: BufferAddress,
3580 count_buffer_id: id::BufferId,
3581 count_buffer_offset: BufferAddress,
3582 max_count: u32,
3583 ) -> Result<(), PassStateError> {
3584 let scope = PassErrorScope::Draw {
3585 kind: DrawKind::MultiDrawIndirectCount,
3586 family: DrawCommandFamily::DrawIndexed,
3587 };
3588 let base = pass_base!(pass, scope);
3589
3590 base.commands
3591 .push(ArcRenderCommand::MultiDrawIndirectCount {
3592 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3593 offset,
3594 count_buffer: pass_try!(
3595 base,
3596 scope,
3597 self.resolve_render_pass_buffer_id(count_buffer_id)
3598 ),
3599 count_buffer_offset,
3600 max_count,
3601 family: DrawCommandFamily::DrawIndexed,
3602 });
3603
3604 Ok(())
3605 }
3606
3607 pub fn render_pass_multi_draw_mesh_tasks_indirect_count(
3608 &self,
3609 pass: &mut RenderPass,
3610 buffer_id: id::BufferId,
3611 offset: BufferAddress,
3612 count_buffer_id: id::BufferId,
3613 count_buffer_offset: BufferAddress,
3614 max_count: u32,
3615 ) -> Result<(), RenderPassError> {
3616 let scope = PassErrorScope::Draw {
3617 kind: DrawKind::MultiDrawIndirectCount,
3618 family: DrawCommandFamily::DrawMeshTasks,
3619 };
3620 let base = pass_base!(pass, scope);
3621
3622 base.commands
3623 .push(ArcRenderCommand::MultiDrawIndirectCount {
3624 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3625 offset,
3626 count_buffer: pass_try!(
3627 base,
3628 scope,
3629 self.resolve_render_pass_buffer_id(count_buffer_id)
3630 ),
3631 count_buffer_offset,
3632 max_count,
3633 family: DrawCommandFamily::DrawMeshTasks,
3634 });
3635
3636 Ok(())
3637 }
3638
3639 pub fn render_pass_push_debug_group(
3640 &self,
3641 pass: &mut RenderPass,
3642 label: &str,
3643 color: u32,
3644 ) -> Result<(), PassStateError> {
3645 let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
3646
3647 let bytes = label.as_bytes();
3648 base.string_data.extend_from_slice(bytes);
3649
3650 base.commands.push(ArcRenderCommand::PushDebugGroup {
3651 color,
3652 len: bytes.len(),
3653 });
3654
3655 Ok(())
3656 }
3657
3658 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
3659 let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
3660
3661 base.commands.push(ArcRenderCommand::PopDebugGroup);
3662
3663 Ok(())
3664 }
3665
3666 pub fn render_pass_insert_debug_marker(
3667 &self,
3668 pass: &mut RenderPass,
3669 label: &str,
3670 color: u32,
3671 ) -> Result<(), PassStateError> {
3672 let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
3673
3674 let bytes = label.as_bytes();
3675 base.string_data.extend_from_slice(bytes);
3676
3677 base.commands.push(ArcRenderCommand::InsertDebugMarker {
3678 color,
3679 len: bytes.len(),
3680 });
3681
3682 Ok(())
3683 }
3684
3685 pub fn render_pass_write_timestamp(
3686 &self,
3687 pass: &mut RenderPass,
3688 query_set_id: id::QuerySetId,
3689 query_index: u32,
3690 ) -> Result<(), PassStateError> {
3691 let scope = PassErrorScope::WriteTimestamp;
3692 let base = pass_base!(pass, scope);
3693
3694 base.commands.push(ArcRenderCommand::WriteTimestamp {
3695 query_set: pass_try!(
3696 base,
3697 scope,
3698 self.resolve_render_pass_query_set(query_set_id)
3699 ),
3700 query_index,
3701 });
3702
3703 Ok(())
3704 }
3705
3706 pub fn render_pass_begin_occlusion_query(
3707 &self,
3708 pass: &mut RenderPass,
3709 query_index: u32,
3710 ) -> Result<(), PassStateError> {
3711 let scope = PassErrorScope::BeginOcclusionQuery;
3712 let base = pass_base!(pass, scope);
3713
3714 base.commands
3715 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
3716
3717 Ok(())
3718 }
3719
3720 pub fn render_pass_end_occlusion_query(
3721 &self,
3722 pass: &mut RenderPass,
3723 ) -> Result<(), PassStateError> {
3724 let scope = PassErrorScope::EndOcclusionQuery;
3725 let base = pass_base!(pass, scope);
3726
3727 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
3728
3729 Ok(())
3730 }
3731
3732 pub fn render_pass_begin_pipeline_statistics_query(
3733 &self,
3734 pass: &mut RenderPass,
3735 query_set_id: id::QuerySetId,
3736 query_index: u32,
3737 ) -> Result<(), PassStateError> {
3738 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
3739 let base = pass_base!(pass, scope);
3740
3741 base.commands
3742 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
3743 query_set: pass_try!(
3744 base,
3745 scope,
3746 self.resolve_render_pass_query_set(query_set_id)
3747 ),
3748 query_index,
3749 });
3750
3751 Ok(())
3752 }
3753
3754 pub fn render_pass_end_pipeline_statistics_query(
3755 &self,
3756 pass: &mut RenderPass,
3757 ) -> Result<(), PassStateError> {
3758 let scope = PassErrorScope::EndPipelineStatisticsQuery;
3759 let base = pass_base!(pass, scope);
3760
3761 base.commands
3762 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
3763
3764 Ok(())
3765 }
3766
3767 pub fn render_pass_execute_bundles(
3768 &self,
3769 pass: &mut RenderPass,
3770 render_bundle_ids: &[id::RenderBundleId],
3771 ) -> Result<(), PassStateError> {
3772 let scope = PassErrorScope::ExecuteBundle;
3773 let base = pass_base!(pass, scope);
3774
3775 let hub = &self.hub;
3776 let bundles = hub.render_bundles.read();
3777
3778 for &bundle_id in render_bundle_ids {
3779 let bundle = pass_try!(base, scope, bundles.get(bundle_id).get());
3780
3781 base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
3782 }
3783 pass.current_pipeline.reset();
3784 pass.current_bind_groups.reset();
3785
3786 Ok(())
3787 }
3788}
3789
3790pub(crate) const fn get_stride_of_indirect_args(family: DrawCommandFamily) -> u64 {
3791 match family {
3792 DrawCommandFamily::Draw => size_of::<wgt::DrawIndirectArgs>() as u64,
3793 DrawCommandFamily::DrawIndexed => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
3794 DrawCommandFamily::DrawMeshTasks => size_of::<wgt::DispatchIndirectArgs>() as u64,
3795 }
3796}