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, EncoderStateError, PassStateError,
15 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, CommandBuffer, CommandEncoderError,
28 DrawError, 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::{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<CommandBuffer>>,
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<CommandBuffer>, 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<CommandBuffer>, 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_buf, '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_buf, '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_buf, 'raw_encoder>
514 State<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder>
515{
516 fn is_ready(&self, indexed: bool) -> 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 indexed {
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 Ok(())
560 } else {
561 Err(DrawError::MissingPipeline(pass::MissingPipeline))
562 }
563 }
564
565 fn reset_bundle(&mut self) {
567 self.general.binder.reset();
568 self.pipeline = None;
569 self.index.reset();
570 self.vertex = Default::default();
571 }
572}
573
574#[derive(Debug, Copy, Clone)]
578pub enum AttachmentErrorLocation {
579 Color { index: usize, resolve: bool },
580 Depth,
581}
582
583impl fmt::Display for AttachmentErrorLocation {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 match *self {
586 AttachmentErrorLocation::Color {
587 index,
588 resolve: false,
589 } => write!(f, "color attachment at index {index}'s texture view"),
590 AttachmentErrorLocation::Color {
591 index,
592 resolve: true,
593 } => write!(
594 f,
595 "color attachment at index {index}'s resolve texture view"
596 ),
597 AttachmentErrorLocation::Depth => write!(f, "depth attachment's texture view"),
598 }
599 }
600}
601
602#[derive(Clone, Debug, Error)]
603#[non_exhaustive]
604pub enum ColorAttachmentError {
605 #[error("Attachment format {0:?} is not a color format")]
606 InvalidFormat(wgt::TextureFormat),
607 #[error("The number of color attachments {given} exceeds the limit {limit}")]
608 TooMany { given: usize, limit: usize },
609 #[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
610 TooManyBytesPerSample { total: u32, limit: u32 },
611 #[error("Depth slice must be less than {limit} but is {given}")]
612 DepthSliceLimit { given: u32, limit: u32 },
613 #[error("Color attachment's view is 3D and requires depth slice to be provided")]
614 MissingDepthSlice,
615 #[error("Depth slice was provided but the color attachment's view is not 3D")]
616 UnneededDepthSlice,
617 #[error("{view}'s subresource at mip {mip_level} and depth/array layer {depth_or_array_layer} is already attached to this render pass")]
618 SubresourceOverlap {
619 view: ResourceErrorIdent,
620 mip_level: u32,
621 depth_or_array_layer: u32,
622 },
623}
624
625impl WebGpuError for ColorAttachmentError {
626 fn webgpu_error_type(&self) -> ErrorType {
627 ErrorType::Validation
628 }
629}
630
631#[derive(Clone, Debug, Error)]
632#[non_exhaustive]
633pub enum AttachmentError {
634 #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-or-stencil format")]
635 InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
636 #[error("Read-only attachment with load")]
637 ReadOnlyWithLoad,
638 #[error("Read-only attachment with store")]
639 ReadOnlyWithStore,
640 #[error("Attachment without load")]
641 NoLoad,
642 #[error("Attachment without store")]
643 NoStore,
644 #[error("LoadOp is `Clear` but no clear value was provided")]
645 NoClearValue,
646 #[error("Clear value ({0}) must be between 0.0 and 1.0, inclusive")]
647 ClearValueOutOfRange(f32),
648}
649
650impl WebGpuError for AttachmentError {
651 fn webgpu_error_type(&self) -> ErrorType {
652 ErrorType::Validation
653 }
654}
655
656#[derive(Clone, Debug, Error)]
658pub enum RenderPassErrorInner {
659 #[error(transparent)]
660 Device(#[from] DeviceError),
661 #[error(transparent)]
662 ColorAttachment(#[from] ColorAttachmentError),
663 #[error(transparent)]
664 InvalidAttachment(#[from] AttachmentError),
665 #[error(transparent)]
666 EncoderState(#[from] EncoderStateError),
667 #[error("Parent encoder is invalid")]
668 InvalidParentEncoder,
669 #[error("The format of the {location} ({format:?}) is not resolvable")]
670 UnsupportedResolveTargetFormat {
671 location: AttachmentErrorLocation,
672 format: wgt::TextureFormat,
673 },
674 #[error("No color attachments or depth attachments were provided, at least one attachment of any kind must be provided")]
675 MissingAttachments,
676 #[error("The {location} is not renderable:")]
677 TextureViewIsNotRenderable {
678 location: AttachmentErrorLocation,
679 #[source]
680 reason: TextureViewNotRenderableReason,
681 },
682 #[error("Attachments have differing sizes: the {expected_location} has extent {expected_extent:?} but is followed by the {actual_location} which has {actual_extent:?}")]
683 AttachmentsDimensionMismatch {
684 expected_location: AttachmentErrorLocation,
685 expected_extent: wgt::Extent3d,
686 actual_location: AttachmentErrorLocation,
687 actual_extent: wgt::Extent3d,
688 },
689 #[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:?}")]
690 AttachmentSampleCountMismatch {
691 expected_location: AttachmentErrorLocation,
692 expected_samples: u32,
693 actual_location: AttachmentErrorLocation,
694 actual_samples: u32,
695 },
696 #[error("The resolve source, {location}, must be multi-sampled (has {src} samples) while the resolve destination must not be multisampled (has {dst} samples)")]
697 InvalidResolveSampleCounts {
698 location: AttachmentErrorLocation,
699 src: u32,
700 dst: u32,
701 },
702 #[error(
703 "Resource source, {location}, format ({src:?}) must match the resolve destination format ({dst:?})"
704 )]
705 MismatchedResolveTextureFormat {
706 location: AttachmentErrorLocation,
707 src: wgt::TextureFormat,
708 dst: wgt::TextureFormat,
709 },
710 #[error("Unable to clear non-present/read-only depth")]
711 InvalidDepthOps,
712 #[error("Unable to clear non-present/read-only stencil")]
713 InvalidStencilOps,
714 #[error(transparent)]
715 InvalidValuesOffset(#[from] pass::InvalidValuesOffset),
716 #[error(transparent)]
717 MissingFeatures(#[from] MissingFeatures),
718 #[error(transparent)]
719 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
720 #[error("Indirect buffer offset {0:?} is not a multiple of 4")]
721 UnalignedIndirectBufferOffset(BufferAddress),
722 #[error("Indirect draw uses bytes {offset}..{end_offset} using count {count} which overruns indirect buffer of size {buffer_size}")]
723 IndirectBufferOverrun {
724 count: u32,
725 offset: u64,
726 end_offset: u64,
727 buffer_size: u64,
728 },
729 #[error("Indirect draw uses bytes {begin_count_offset}..{end_count_offset} which overruns indirect buffer of size {count_buffer_size}")]
730 IndirectCountBufferOverrun {
731 begin_count_offset: u64,
732 end_count_offset: u64,
733 count_buffer_size: u64,
734 },
735 #[error(transparent)]
736 InvalidPopDebugGroup(#[from] pass::InvalidPopDebugGroup),
737 #[error(transparent)]
738 ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
739 #[error("Render bundle has incompatible targets, {0}")]
740 IncompatibleBundleTargets(#[from] RenderPassCompatibilityError),
741 #[error(
742 "Render bundle has incompatible read-only flags: \
743 bundle has flags depth = {bundle_depth} and stencil = {bundle_stencil}, \
744 while the pass has flags depth = {pass_depth} and stencil = {pass_stencil}. \
745 Read-only renderpasses are only compatible with read-only bundles for that aspect."
746 )]
747 IncompatibleBundleReadOnlyDepthStencil {
748 pass_depth: bool,
749 pass_stencil: bool,
750 bundle_depth: bool,
751 bundle_stencil: bool,
752 },
753 #[error(transparent)]
754 RenderCommand(#[from] RenderCommandError),
755 #[error(transparent)]
756 Draw(#[from] DrawError),
757 #[error(transparent)]
758 Bind(#[from] BindError),
759 #[error("Push constant offset must be aligned to 4 bytes")]
760 PushConstantOffsetAlignment,
761 #[error("Push constant size must be aligned to 4 bytes")]
762 PushConstantSizeAlignment,
763 #[error("Ran out of push constant space. Don't set 4gb of push constants per ComputePass.")]
764 PushConstantOutOfMemory,
765 #[error(transparent)]
766 QueryUse(#[from] QueryUseError),
767 #[error("Multiview layer count must match")]
768 MultiViewMismatch,
769 #[error(
770 "Multiview pass texture views with more than one array layer must have D2Array dimension"
771 )]
772 MultiViewDimensionMismatch,
773 #[error("missing occlusion query set")]
774 MissingOcclusionQuerySet,
775 #[error(transparent)]
776 DestroyedResource(#[from] DestroyedResourceError),
777 #[error("The compute pass has already been ended and no further commands can be recorded")]
778 PassEnded,
779 #[error(transparent)]
780 InvalidResource(#[from] InvalidResourceError),
781 #[error(transparent)]
782 TimestampWrites(#[from] TimestampWritesError),
783}
784
785impl From<MissingBufferUsageError> for RenderPassErrorInner {
786 fn from(error: MissingBufferUsageError) -> Self {
787 Self::RenderCommand(error.into())
788 }
789}
790
791impl From<MissingTextureUsageError> for RenderPassErrorInner {
792 fn from(error: MissingTextureUsageError) -> Self {
793 Self::RenderCommand(error.into())
794 }
795}
796
797impl From<pass::BindGroupIndexOutOfRange> for RenderPassErrorInner {
798 fn from(error: pass::BindGroupIndexOutOfRange) -> Self {
799 Self::RenderCommand(RenderCommandError::BindGroupIndexOutOfRange(error))
800 }
801}
802
803impl From<pass::MissingPipeline> for RenderPassErrorInner {
804 fn from(error: pass::MissingPipeline) -> Self {
805 Self::Draw(DrawError::MissingPipeline(error))
806 }
807}
808
809impl From<PushConstantUploadError> for RenderPassErrorInner {
810 fn from(error: PushConstantUploadError) -> Self {
811 Self::RenderCommand(error.into())
812 }
813}
814
815#[derive(Clone, Debug, Error)]
817#[error("{scope}")]
818pub struct RenderPassError {
819 pub scope: PassErrorScope,
820 #[source]
821 pub(super) inner: RenderPassErrorInner,
822}
823
824impl<E: Into<RenderPassErrorInner>> MapPassErr<RenderPassError> for E {
825 fn map_pass_err(self, scope: PassErrorScope) -> RenderPassError {
826 RenderPassError {
827 scope,
828 inner: self.into(),
829 }
830 }
831}
832
833impl WebGpuError for RenderPassError {
834 fn webgpu_error_type(&self) -> ErrorType {
835 let Self { scope: _, inner } = self;
836 let e: &dyn WebGpuError = match inner {
837 RenderPassErrorInner::Device(e) => e,
838 RenderPassErrorInner::ColorAttachment(e) => e,
839 RenderPassErrorInner::EncoderState(e) => e,
840 RenderPassErrorInner::MissingFeatures(e) => e,
841 RenderPassErrorInner::MissingDownlevelFlags(e) => e,
842 RenderPassErrorInner::RenderCommand(e) => e,
843 RenderPassErrorInner::Draw(e) => e,
844 RenderPassErrorInner::Bind(e) => e,
845 RenderPassErrorInner::QueryUse(e) => e,
846 RenderPassErrorInner::DestroyedResource(e) => e,
847 RenderPassErrorInner::InvalidResource(e) => e,
848 RenderPassErrorInner::IncompatibleBundleTargets(e) => e,
849 RenderPassErrorInner::InvalidAttachment(e) => e,
850 RenderPassErrorInner::TimestampWrites(e) => e,
851 RenderPassErrorInner::InvalidValuesOffset(e) => e,
852 RenderPassErrorInner::InvalidPopDebugGroup(e) => e,
853
854 RenderPassErrorInner::InvalidParentEncoder
855 | RenderPassErrorInner::UnsupportedResolveTargetFormat { .. }
856 | RenderPassErrorInner::MissingAttachments
857 | RenderPassErrorInner::TextureViewIsNotRenderable { .. }
858 | RenderPassErrorInner::AttachmentsDimensionMismatch { .. }
859 | RenderPassErrorInner::AttachmentSampleCountMismatch { .. }
860 | RenderPassErrorInner::InvalidResolveSampleCounts { .. }
861 | RenderPassErrorInner::MismatchedResolveTextureFormat { .. }
862 | RenderPassErrorInner::InvalidDepthOps
863 | RenderPassErrorInner::InvalidStencilOps
864 | RenderPassErrorInner::UnalignedIndirectBufferOffset(..)
865 | RenderPassErrorInner::IndirectBufferOverrun { .. }
866 | RenderPassErrorInner::IndirectCountBufferOverrun { .. }
867 | RenderPassErrorInner::ResourceUsageCompatibility(..)
868 | RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil { .. }
869 | RenderPassErrorInner::PushConstantOffsetAlignment
870 | RenderPassErrorInner::PushConstantSizeAlignment
871 | RenderPassErrorInner::PushConstantOutOfMemory
872 | RenderPassErrorInner::MultiViewMismatch
873 | RenderPassErrorInner::MultiViewDimensionMismatch
874 | RenderPassErrorInner::MissingOcclusionQuerySet
875 | RenderPassErrorInner::PassEnded => return ErrorType::Validation,
876 };
877 e.webgpu_error_type()
878 }
879}
880
881struct RenderAttachment {
882 texture: Arc<Texture>,
883 selector: TextureSelector,
884 usage: wgt::TextureUses,
885}
886
887impl TextureView {
888 fn to_render_attachment(&self, usage: wgt::TextureUses) -> RenderAttachment {
889 RenderAttachment {
890 texture: self.parent.clone(),
891 selector: self.selector.clone(),
892 usage,
893 }
894 }
895}
896
897const MAX_TOTAL_ATTACHMENTS: usize = hal::MAX_COLOR_ATTACHMENTS + hal::MAX_COLOR_ATTACHMENTS + 1;
898type AttachmentDataVec<T> = ArrayVec<T, MAX_TOTAL_ATTACHMENTS>;
899
900struct RenderPassInfo {
901 context: RenderPassContext,
902 render_attachments: AttachmentDataVec<RenderAttachment>,
904 is_depth_read_only: bool,
905 is_stencil_read_only: bool,
906 extent: wgt::Extent3d,
907
908 divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>,
909 multiview: Option<NonZeroU32>,
910}
911
912impl RenderPassInfo {
913 fn add_pass_texture_init_actions<V>(
914 load_op: LoadOp<V>,
915 store_op: StoreOp,
916 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
917 view: &TextureView,
918 pending_discard_init_fixups: &mut SurfacesInDiscardState,
919 ) {
920 if matches!(load_op, LoadOp::Load) {
921 pending_discard_init_fixups.extend(texture_memory_actions.register_init_action(
922 &TextureInitTrackerAction {
923 texture: view.parent.clone(),
924 range: TextureInitRange::from(view.selector.clone()),
925 kind: MemoryInitKind::NeedsInitializedMemory,
927 },
928 ));
929 } else if store_op == StoreOp::Store {
930 texture_memory_actions.register_implicit_init(
932 &view.parent,
933 TextureInitRange::from(view.selector.clone()),
934 );
935 }
936 if store_op == StoreOp::Discard {
937 texture_memory_actions.discard(TextureSurfaceDiscard {
941 texture: view.parent.clone(),
942 mip_level: view.selector.mips.start,
943 layer: view.selector.layers.start,
944 });
945 }
946 }
947
948 fn start(
949 device: &Arc<Device>,
950 hal_label: Option<&str>,
951 color_attachments: ArrayVec<
952 Option<ArcRenderPassColorAttachment>,
953 { hal::MAX_COLOR_ATTACHMENTS },
954 >,
955 mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
956 mut timestamp_writes: Option<ArcPassTimestampWrites>,
957 mut occlusion_query_set: Option<Arc<QuerySet>>,
958 encoder: &mut CommandEncoder,
959 trackers: &mut Tracker,
960 texture_memory_actions: &mut CommandBufferTextureMemoryActions,
961 pending_query_resets: &mut QueryResetMap,
962 pending_discard_init_fixups: &mut SurfacesInDiscardState,
963 snatch_guard: &SnatchGuard<'_>,
964 ) -> Result<Self, RenderPassErrorInner> {
965 profiling::scope!("RenderPassInfo::start");
966
967 let mut is_depth_read_only = false;
971 let mut is_stencil_read_only = false;
972
973 let mut render_attachments = AttachmentDataVec::<RenderAttachment>::new();
974 let mut discarded_surfaces = AttachmentDataVec::new();
975 let mut divergent_discarded_depth_stencil_aspect = None;
976
977 let mut attachment_location = AttachmentErrorLocation::Color {
978 index: usize::MAX,
979 resolve: false,
980 };
981 let mut extent = None;
982 let mut sample_count = 0;
983
984 let mut detected_multiview: Option<Option<NonZeroU32>> = None;
985
986 let mut check_multiview = |view: &TextureView| {
987 let layers = view.selector.layers.end - view.selector.layers.start;
989 let this_multiview = if layers >= 2 {
990 Some(unsafe { NonZeroU32::new_unchecked(layers) })
992 } else {
993 None
994 };
995
996 if this_multiview.is_some() && view.desc.dimension != TextureViewDimension::D2Array {
998 return Err(RenderPassErrorInner::MultiViewDimensionMismatch);
999 }
1000
1001 if let Some(multiview) = detected_multiview {
1003 if multiview != this_multiview {
1004 return Err(RenderPassErrorInner::MultiViewMismatch);
1005 }
1006 } else {
1007 if this_multiview.is_some() {
1009 device.require_features(wgt::Features::MULTIVIEW)?;
1010 }
1011
1012 detected_multiview = Some(this_multiview);
1013 }
1014
1015 Ok(())
1016 };
1017 let mut add_view = |view: &TextureView, location| {
1018 let render_extent = view.render_extent.map_err(|reason| {
1019 RenderPassErrorInner::TextureViewIsNotRenderable { location, reason }
1020 })?;
1021 if let Some(ex) = extent {
1022 if ex != render_extent {
1023 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1024 expected_location: attachment_location,
1025 expected_extent: ex,
1026 actual_location: location,
1027 actual_extent: render_extent,
1028 });
1029 }
1030 } else {
1031 extent = Some(render_extent);
1032 }
1033 if sample_count == 0 {
1034 sample_count = view.samples;
1035 } else if sample_count != view.samples {
1036 return Err(RenderPassErrorInner::AttachmentSampleCountMismatch {
1037 expected_location: attachment_location,
1038 expected_samples: sample_count,
1039 actual_location: location,
1040 actual_samples: view.samples,
1041 });
1042 }
1043 attachment_location = location;
1044 Ok(())
1045 };
1046
1047 let mut depth_stencil = None;
1048
1049 if let Some(at) = depth_stencil_attachment.as_ref() {
1050 let view = &at.view;
1051 check_multiview(view)?;
1052 add_view(view, AttachmentErrorLocation::Depth)?;
1053
1054 let ds_aspects = view.desc.aspects();
1055
1056 if !ds_aspects.contains(hal::FormatAspects::STENCIL)
1057 || (at.stencil.load_op().eq_variant(at.depth.load_op())
1058 && at.stencil.store_op() == at.depth.store_op())
1059 {
1060 Self::add_pass_texture_init_actions(
1061 at.depth.load_op(),
1062 at.depth.store_op(),
1063 texture_memory_actions,
1064 view,
1065 pending_discard_init_fixups,
1066 );
1067 } else if !ds_aspects.contains(hal::FormatAspects::DEPTH) {
1068 Self::add_pass_texture_init_actions(
1069 at.stencil.load_op(),
1070 at.stencil.store_op(),
1071 texture_memory_actions,
1072 view,
1073 pending_discard_init_fixups,
1074 );
1075 } else {
1076 let need_init_beforehand =
1098 at.depth.load_op() == LoadOp::Load || at.stencil.load_op() == LoadOp::Load;
1099 if need_init_beforehand {
1100 pending_discard_init_fixups.extend(
1101 texture_memory_actions.register_init_action(&TextureInitTrackerAction {
1102 texture: view.parent.clone(),
1103 range: TextureInitRange::from(view.selector.clone()),
1104 kind: MemoryInitKind::NeedsInitializedMemory,
1105 }),
1106 );
1107 }
1108
1109 if at.depth.store_op() != at.stencil.store_op() {
1118 if !need_init_beforehand {
1119 texture_memory_actions.register_implicit_init(
1120 &view.parent,
1121 TextureInitRange::from(view.selector.clone()),
1122 );
1123 }
1124 divergent_discarded_depth_stencil_aspect = Some((
1125 if at.depth.store_op() == StoreOp::Discard {
1126 wgt::TextureAspect::DepthOnly
1127 } else {
1128 wgt::TextureAspect::StencilOnly
1129 },
1130 view.clone(),
1131 ));
1132 } else if at.depth.store_op() == StoreOp::Discard {
1133 discarded_surfaces.push(TextureSurfaceDiscard {
1135 texture: view.parent.clone(),
1136 mip_level: view.selector.mips.start,
1137 layer: view.selector.layers.start,
1138 });
1139 }
1140 }
1141
1142 is_depth_read_only = at.depth.is_readonly();
1143 is_stencil_read_only = at.stencil.is_readonly();
1144
1145 let usage = if is_depth_read_only
1146 && is_stencil_read_only
1147 && device
1148 .downlevel
1149 .flags
1150 .contains(wgt::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
1151 {
1152 wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::RESOURCE
1153 } else {
1154 wgt::TextureUses::DEPTH_STENCIL_WRITE
1155 };
1156 render_attachments.push(view.to_render_attachment(usage));
1157
1158 depth_stencil = Some(hal::DepthStencilAttachment {
1159 target: hal::Attachment {
1160 view: view.try_raw(snatch_guard)?,
1161 usage,
1162 },
1163 depth_ops: at.depth.hal_ops(),
1164 stencil_ops: at.stencil.hal_ops(),
1165 clear_value: (at.depth.clear_value(), at.stencil.clear_value()),
1166 });
1167 }
1168
1169 let mut attachment_set = crate::FastHashSet::default();
1170
1171 let mut color_attachments_hal =
1172 ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
1173 for (index, attachment) in color_attachments.iter().enumerate() {
1174 let at = if let Some(attachment) = attachment.as_ref() {
1175 attachment
1176 } else {
1177 color_attachments_hal.push(None);
1178 continue;
1179 };
1180 let color_view: &TextureView = &at.view;
1181 color_view.same_device(device)?;
1182 check_multiview(color_view)?;
1183 add_view(
1184 color_view,
1185 AttachmentErrorLocation::Color {
1186 index,
1187 resolve: false,
1188 },
1189 )?;
1190
1191 if !color_view
1192 .desc
1193 .aspects()
1194 .contains(hal::FormatAspects::COLOR)
1195 {
1196 return Err(RenderPassErrorInner::ColorAttachment(
1197 ColorAttachmentError::InvalidFormat(color_view.desc.format),
1198 ));
1199 }
1200
1201 if color_view.desc.dimension == TextureViewDimension::D3 {
1202 if let Some(depth_slice) = at.depth_slice {
1203 let mip = color_view.desc.range.base_mip_level;
1204 let mip_size = color_view
1205 .parent
1206 .desc
1207 .size
1208 .mip_level_size(mip, color_view.parent.desc.dimension);
1209 let limit = mip_size.depth_or_array_layers;
1210 if depth_slice >= limit {
1211 return Err(RenderPassErrorInner::ColorAttachment(
1212 ColorAttachmentError::DepthSliceLimit {
1213 given: depth_slice,
1214 limit,
1215 },
1216 ));
1217 }
1218 } else {
1219 return Err(RenderPassErrorInner::ColorAttachment(
1220 ColorAttachmentError::MissingDepthSlice,
1221 ));
1222 }
1223 } else if at.depth_slice.is_some() {
1224 return Err(RenderPassErrorInner::ColorAttachment(
1225 ColorAttachmentError::UnneededDepthSlice,
1226 ));
1227 }
1228
1229 fn check_attachment_overlap(
1230 attachment_set: &mut crate::FastHashSet<(crate::track::TrackerIndex, u32, u32)>,
1231 view: &TextureView,
1232 depth_slice: Option<u32>,
1233 ) -> Result<(), ColorAttachmentError> {
1234 let mut insert = |slice| {
1235 let mip_level = view.desc.range.base_mip_level;
1236 if attachment_set.insert((view.tracking_data.tracker_index(), mip_level, slice))
1237 {
1238 Ok(())
1239 } else {
1240 Err(ColorAttachmentError::SubresourceOverlap {
1241 view: view.error_ident(),
1242 mip_level,
1243 depth_or_array_layer: slice,
1244 })
1245 }
1246 };
1247 match view.desc.dimension {
1248 TextureViewDimension::D2 => {
1249 insert(view.desc.range.base_array_layer)?;
1250 }
1251 TextureViewDimension::D2Array => {
1252 for layer in view.selector.layers.clone() {
1253 insert(layer)?;
1254 }
1255 }
1256 TextureViewDimension::D3 => {
1257 insert(depth_slice.unwrap())?;
1258 }
1259 _ => unreachable!(),
1260 };
1261 Ok(())
1262 }
1263
1264 check_attachment_overlap(&mut attachment_set, color_view, at.depth_slice)?;
1265
1266 Self::add_pass_texture_init_actions(
1267 at.load_op,
1268 at.store_op,
1269 texture_memory_actions,
1270 color_view,
1271 pending_discard_init_fixups,
1272 );
1273 render_attachments
1274 .push(color_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1275
1276 let mut hal_resolve_target = None;
1277 if let Some(resolve_view) = &at.resolve_target {
1278 resolve_view.same_device(device)?;
1279 check_multiview(resolve_view)?;
1280
1281 check_attachment_overlap(&mut attachment_set, resolve_view, None)?;
1282
1283 let resolve_location = AttachmentErrorLocation::Color {
1284 index,
1285 resolve: true,
1286 };
1287
1288 let render_extent = resolve_view.render_extent.map_err(|reason| {
1289 RenderPassErrorInner::TextureViewIsNotRenderable {
1290 location: resolve_location,
1291 reason,
1292 }
1293 })?;
1294 if color_view.render_extent.unwrap() != render_extent {
1295 return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
1296 expected_location: attachment_location,
1297 expected_extent: extent.unwrap_or_default(),
1298 actual_location: resolve_location,
1299 actual_extent: render_extent,
1300 });
1301 }
1302 if color_view.samples == 1 || resolve_view.samples != 1 {
1303 return Err(RenderPassErrorInner::InvalidResolveSampleCounts {
1304 location: resolve_location,
1305 src: color_view.samples,
1306 dst: resolve_view.samples,
1307 });
1308 }
1309 if color_view.desc.format != resolve_view.desc.format {
1310 return Err(RenderPassErrorInner::MismatchedResolveTextureFormat {
1311 location: resolve_location,
1312 src: color_view.desc.format,
1313 dst: resolve_view.desc.format,
1314 });
1315 }
1316 if !resolve_view
1317 .format_features
1318 .flags
1319 .contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE)
1320 {
1321 return Err(RenderPassErrorInner::UnsupportedResolveTargetFormat {
1322 location: resolve_location,
1323 format: resolve_view.desc.format,
1324 });
1325 }
1326
1327 texture_memory_actions.register_implicit_init(
1328 &resolve_view.parent,
1329 TextureInitRange::from(resolve_view.selector.clone()),
1330 );
1331 render_attachments
1332 .push(resolve_view.to_render_attachment(wgt::TextureUses::COLOR_TARGET));
1333
1334 hal_resolve_target = Some(hal::Attachment {
1335 view: resolve_view.try_raw(snatch_guard)?,
1336 usage: wgt::TextureUses::COLOR_TARGET,
1337 });
1338 }
1339
1340 color_attachments_hal.push(Some(hal::ColorAttachment {
1341 target: hal::Attachment {
1342 view: color_view.try_raw(snatch_guard)?,
1343 usage: wgt::TextureUses::COLOR_TARGET,
1344 },
1345 depth_slice: at.depth_slice,
1346 resolve_target: hal_resolve_target,
1347 ops: at.hal_ops(),
1348 clear_value: at.clear_value(),
1349 }));
1350 }
1351
1352 let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
1353 let multiview = detected_multiview.expect("Multiview was not detected, no attachments");
1354
1355 let attachment_formats = AttachmentData {
1356 colors: color_attachments
1357 .iter()
1358 .map(|at| at.as_ref().map(|at| at.view.desc.format))
1359 .collect(),
1360 resolves: color_attachments
1361 .iter()
1362 .filter_map(|at| {
1363 at.as_ref().and_then(|at| {
1364 at.resolve_target
1365 .as_ref()
1366 .map(|resolve| resolve.desc.format)
1367 })
1368 })
1369 .collect(),
1370 depth_stencil: depth_stencil_attachment
1371 .as_ref()
1372 .map(|at| at.view.desc.format),
1373 };
1374
1375 let context = RenderPassContext {
1376 attachments: attachment_formats,
1377 sample_count,
1378 multiview,
1379 };
1380
1381 let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() {
1382 let query_set = &tw.query_set;
1383 query_set.same_device(device)?;
1384
1385 if let Some(index) = tw.beginning_of_pass_write_index {
1386 pending_query_resets.use_query_set(query_set, index);
1387 }
1388 if let Some(index) = tw.end_of_pass_write_index {
1389 pending_query_resets.use_query_set(query_set, index);
1390 }
1391
1392 Some(hal::PassTimestampWrites {
1393 query_set: query_set.raw(),
1394 beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
1395 end_of_pass_write_index: tw.end_of_pass_write_index,
1396 })
1397 } else {
1398 None
1399 };
1400
1401 let occlusion_query_set_hal = if let Some(query_set) = occlusion_query_set.as_ref() {
1402 query_set.same_device(device)?;
1403 Some(query_set.raw())
1404 } else {
1405 None
1406 };
1407
1408 let hal_desc = hal::RenderPassDescriptor {
1409 label: hal_label,
1410 extent,
1411 sample_count,
1412 color_attachments: &color_attachments_hal,
1413 depth_stencil_attachment: depth_stencil,
1414 multiview,
1415 timestamp_writes: timestamp_writes_hal,
1416 occlusion_query_set: occlusion_query_set_hal,
1417 };
1418 unsafe {
1419 encoder
1420 .raw
1421 .begin_render_pass(&hal_desc)
1422 .map_err(|e| device.handle_hal_error(e))?;
1423 };
1424 drop(color_attachments_hal); if let Some(tw) = timestamp_writes.take() {
1428 trackers.query_sets.insert_single(tw.query_set);
1429 };
1430 if let Some(occlusion_query_set) = occlusion_query_set.take() {
1431 trackers.query_sets.insert_single(occlusion_query_set);
1432 };
1433 if let Some(at) = depth_stencil_attachment.take() {
1434 trackers.views.insert_single(at.view.clone());
1435 }
1436 for at in color_attachments.into_iter().flatten() {
1437 trackers.views.insert_single(at.view.clone());
1438 if let Some(resolve_target) = at.resolve_target {
1439 trackers.views.insert_single(resolve_target);
1440 }
1441 }
1442
1443 Ok(Self {
1444 context,
1445 render_attachments,
1446 is_depth_read_only,
1447 is_stencil_read_only,
1448 extent,
1449 divergent_discarded_depth_stencil_aspect,
1450 multiview,
1451 })
1452 }
1453
1454 fn finish(
1455 self,
1456 device: &Device,
1457 raw: &mut dyn hal::DynCommandEncoder,
1458 snatch_guard: &SnatchGuard,
1459 scope: &mut UsageScope<'_>,
1460 ) -> Result<(), RenderPassErrorInner> {
1461 profiling::scope!("RenderPassInfo::finish");
1462 unsafe {
1463 raw.end_render_pass();
1464 }
1465
1466 for ra in self.render_attachments {
1467 let texture = &ra.texture;
1468 texture.check_usage(TextureUsages::RENDER_ATTACHMENT)?;
1469
1470 unsafe {
1472 scope
1473 .textures
1474 .merge_single(texture, Some(ra.selector.clone()), ra.usage)?
1475 };
1476 }
1477
1478 if let Some((aspect, view)) = self.divergent_discarded_depth_stencil_aspect {
1488 let (depth_ops, stencil_ops) = if aspect == wgt::TextureAspect::DepthOnly {
1489 (
1490 hal::AttachmentOps::STORE, hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, )
1493 } else {
1494 (
1495 hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, hal::AttachmentOps::STORE, )
1498 };
1499 let desc = hal::RenderPassDescriptor::<'_, _, dyn hal::DynTextureView> {
1500 label: Some("(wgpu internal) Zero init discarded depth/stencil aspect"),
1501 extent: view.render_extent.unwrap(),
1502 sample_count: view.samples,
1503 color_attachments: &[],
1504 depth_stencil_attachment: Some(hal::DepthStencilAttachment {
1505 target: hal::Attachment {
1506 view: view.try_raw(snatch_guard)?,
1507 usage: wgt::TextureUses::DEPTH_STENCIL_WRITE,
1508 },
1509 depth_ops,
1510 stencil_ops,
1511 clear_value: (0.0, 0),
1512 }),
1513 multiview: self.multiview,
1514 timestamp_writes: None,
1515 occlusion_query_set: None,
1516 };
1517 unsafe {
1518 raw.begin_render_pass(&desc)
1519 .map_err(|e| device.handle_hal_error(e))?;
1520 raw.end_render_pass();
1521 }
1522 }
1523
1524 Ok(())
1525 }
1526}
1527
1528impl Global {
1529 pub fn command_encoder_begin_render_pass(
1540 &self,
1541 encoder_id: id::CommandEncoderId,
1542 desc: &RenderPassDescriptor<'_>,
1543 ) -> (RenderPass, Option<CommandEncoderError>) {
1544 use EncoderStateError as SErr;
1545
1546 fn fill_arc_desc(
1547 hub: &crate::hub::Hub,
1548 desc: &RenderPassDescriptor<'_>,
1549 arc_desc: &mut ArcRenderPassDescriptor,
1550 device: &Device,
1551 ) -> Result<(), RenderPassErrorInner> {
1552 device.check_is_valid()?;
1553
1554 let query_sets = hub.query_sets.read();
1555 let texture_views = hub.texture_views.read();
1556
1557 let max_color_attachments = device.limits.max_color_attachments as usize;
1558 if desc.color_attachments.len() > max_color_attachments {
1559 return Err(RenderPassErrorInner::ColorAttachment(
1560 ColorAttachmentError::TooMany {
1561 given: desc.color_attachments.len(),
1562 limit: max_color_attachments,
1563 },
1564 ));
1565 }
1566
1567 for color_attachment in desc.color_attachments.iter() {
1568 if let Some(RenderPassColorAttachment {
1569 view: view_id,
1570 depth_slice,
1571 resolve_target,
1572 load_op,
1573 store_op,
1574 }) = color_attachment
1575 {
1576 let view = texture_views.get(*view_id).get()?;
1577 view.same_device(device)?;
1578
1579 let resolve_target = if let Some(resolve_target_id) = resolve_target {
1580 let rt_arc = texture_views.get(*resolve_target_id).get()?;
1581 rt_arc.same_device(device)?;
1582
1583 Some(rt_arc)
1584 } else {
1585 None
1586 };
1587
1588 arc_desc
1589 .color_attachments
1590 .push(Some(ArcRenderPassColorAttachment {
1591 view,
1592 depth_slice: *depth_slice,
1593 resolve_target,
1594 load_op: *load_op,
1595 store_op: *store_op,
1596 }));
1597 } else {
1598 arc_desc.color_attachments.push(None);
1599 }
1600 }
1601
1602 arc_desc.depth_stencil_attachment =
1603 if let Some(depth_stencil_attachment) = desc.depth_stencil_attachment {
1605 let view = texture_views.get(depth_stencil_attachment.view).get()?;
1606 view.same_device(device)?;
1607
1608 let format = view.desc.format;
1609 if !format.is_depth_stencil_format() {
1610 return Err(RenderPassErrorInner::InvalidAttachment(AttachmentError::InvalidDepthStencilAttachmentFormat(
1611 view.desc.format,
1612 )));
1613 }
1614
1615 Some(ArcRenderPassDepthStencilAttachment {
1616 view,
1617 depth: if format.has_depth_aspect() {
1618 depth_stencil_attachment.depth.resolve(|clear| if let Some(clear) = clear {
1619 if !(0.0..=1.0).contains(&clear) {
1621 Err(AttachmentError::ClearValueOutOfRange(clear))
1622 } else {
1623 Ok(clear)
1624 }
1625 } else {
1626 Err(AttachmentError::NoClearValue)
1627 })?
1628 } else {
1629 ResolvedPassChannel::ReadOnly
1630 },
1631 stencil: if format.has_stencil_aspect() {
1632 depth_stencil_attachment.stencil.resolve(|clear| Ok(clear.unwrap_or_default()))?
1633 } else {
1634 ResolvedPassChannel::ReadOnly
1635 },
1636 })
1637 } else {
1638 None
1639 };
1640
1641 arc_desc.timestamp_writes = desc
1642 .timestamp_writes
1643 .map(|tw| {
1644 Global::validate_pass_timestamp_writes::<RenderPassErrorInner>(
1645 device,
1646 &query_sets,
1647 tw,
1648 )
1649 })
1650 .transpose()?;
1651
1652 arc_desc.occlusion_query_set =
1653 if let Some(occlusion_query_set) = desc.occlusion_query_set {
1654 let query_set = query_sets.get(occlusion_query_set).get()?;
1655 query_set.same_device(device)?;
1656
1657 Some(query_set)
1658 } else {
1659 None
1660 };
1661
1662 Ok(())
1663 }
1664
1665 let scope = PassErrorScope::Pass;
1666 let hub = &self.hub;
1667
1668 let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
1669 let mut cmd_buf_data = cmd_buf.data.lock();
1670
1671 match cmd_buf_data.lock_encoder() {
1672 Ok(()) => {
1673 drop(cmd_buf_data);
1674 let mut arc_desc = ArcRenderPassDescriptor {
1675 label: &desc.label,
1676 timestamp_writes: None,
1677 color_attachments: ArrayVec::new(),
1678 depth_stencil_attachment: None,
1679 occlusion_query_set: None,
1680 };
1681 match fill_arc_desc(hub, desc, &mut arc_desc, &cmd_buf.device) {
1682 Ok(()) => (RenderPass::new(cmd_buf, arc_desc), None),
1683 Err(err) => (
1684 RenderPass::new_invalid(cmd_buf, &desc.label, err.map_pass_err(scope)),
1685 None,
1686 ),
1687 }
1688 }
1689 Err(err @ SErr::Locked) => {
1690 cmd_buf_data.invalidate(err.clone());
1694 drop(cmd_buf_data);
1695 (
1696 RenderPass::new_invalid(cmd_buf, &desc.label, err.map_pass_err(scope)),
1697 None,
1698 )
1699 }
1700 Err(err @ (SErr::Ended | SErr::Submitted)) => {
1701 drop(cmd_buf_data);
1704 (
1705 RenderPass::new_invalid(cmd_buf, &desc.label, err.clone().map_pass_err(scope)),
1706 Some(err.into()),
1707 )
1708 }
1709 Err(err @ SErr::Invalid) => {
1710 drop(cmd_buf_data);
1716 (
1717 RenderPass::new_invalid(cmd_buf, &desc.label, err.map_pass_err(scope)),
1718 None,
1719 )
1720 }
1721 Err(SErr::Unlocked) => {
1722 unreachable!("lock_encoder cannot fail due to the encoder being unlocked")
1723 }
1724 }
1725 }
1726
1727 #[doc(hidden)]
1730 #[cfg(any(feature = "serde", feature = "replay"))]
1731 pub fn render_pass_end_with_unresolved_commands(
1732 &self,
1733 encoder_id: id::CommandEncoderId,
1734 base: BasePass<super::RenderCommand, core::convert::Infallible>,
1735 color_attachments: &[Option<RenderPassColorAttachment>],
1736 depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
1737 timestamp_writes: Option<&PassTimestampWrites>,
1738 occlusion_query_set: Option<id::QuerySetId>,
1739 ) {
1740 #[cfg(feature = "trace")]
1741 {
1742 let cmd_buf = self
1743 .hub
1744 .command_buffers
1745 .get(encoder_id.into_command_buffer_id());
1746 let mut cmd_buf_data = cmd_buf.data.lock();
1747 let cmd_buf_data = cmd_buf_data.get_inner();
1748
1749 if let Some(ref mut list) = cmd_buf_data.commands {
1750 list.push(crate::device::trace::Command::RunRenderPass {
1751 base: BasePass {
1752 label: base.label.clone(),
1753 error: None,
1754 commands: base.commands.clone(),
1755 dynamic_offsets: base.dynamic_offsets.clone(),
1756 string_data: base.string_data.clone(),
1757 push_constant_data: base.push_constant_data.clone(),
1758 },
1759 target_colors: color_attachments.to_vec(),
1760 target_depth_stencil: depth_stencil_attachment.cloned(),
1761 timestamp_writes: timestamp_writes.cloned(),
1762 occlusion_query_set_id: occlusion_query_set,
1763 });
1764 }
1765 }
1766
1767 let BasePass {
1768 label,
1769 error: _,
1770 commands,
1771 dynamic_offsets,
1772 string_data,
1773 push_constant_data,
1774 } = base;
1775
1776 let (mut render_pass, encoder_error) = self.command_encoder_begin_render_pass(
1777 encoder_id,
1778 &RenderPassDescriptor {
1779 label: label.as_deref().map(Cow::Borrowed),
1780 color_attachments: Cow::Borrowed(color_attachments),
1781 depth_stencil_attachment,
1782 timestamp_writes,
1783 occlusion_query_set,
1784 },
1785 );
1786 if let Some(err) = encoder_error {
1787 panic!("{:?}", err);
1788 };
1789
1790 render_pass.base = BasePass {
1791 label,
1792 error: None,
1793 commands: super::RenderCommand::resolve_render_command_ids(&self.hub, &commands)
1794 .unwrap(),
1795 dynamic_offsets,
1796 string_data,
1797 push_constant_data,
1798 };
1799
1800 self.render_pass_end(&mut render_pass).unwrap();
1801 }
1802
1803 pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
1804 let pass_scope = PassErrorScope::Pass;
1805 profiling::scope!(
1806 "CommandEncoder::run_render_pass {}",
1807 base.label.as_deref().unwrap_or("")
1808 );
1809
1810 let cmd_buf = pass.parent.take().ok_or(EncoderStateError::Ended)?;
1811 let mut cmd_buf_data = cmd_buf.data.lock();
1812
1813 if let Some(err) = pass.base.error.take() {
1814 if matches!(
1815 err,
1816 RenderPassError {
1817 inner: RenderPassErrorInner::EncoderState(EncoderStateError::Ended),
1818 scope: _,
1819 }
1820 ) {
1821 return Err(EncoderStateError::Ended);
1826 } else {
1827 cmd_buf_data.invalidate(err);
1831 return Ok(());
1832 }
1833 }
1834
1835 cmd_buf_data.unlock_and_record(|cmd_buf_data| -> Result<(), RenderPassError> {
1836 let device = &cmd_buf.device;
1837 device.check_is_valid().map_pass_err(pass_scope)?;
1838 let snatch_guard = &device.snatchable_lock.read();
1839
1840 let base = &mut pass.base;
1841
1842 let mut indirect_draw_validation_batcher =
1843 crate::indirect_validation::DrawBatcher::new();
1844
1845 let (scope, pending_discard_init_fixups) = {
1846 let encoder = &mut cmd_buf_data.encoder;
1847 let tracker = &mut cmd_buf_data.trackers;
1848 let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions;
1849 let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
1850 let pending_query_resets = &mut cmd_buf_data.pending_query_resets;
1851 let indirect_draw_validation_resources =
1852 &mut cmd_buf_data.indirect_draw_validation_resources;
1853
1854 encoder.close_if_open().map_pass_err(pass_scope)?;
1858 encoder
1859 .open_pass(base.label.as_deref())
1860 .map_pass_err(pass_scope)?;
1861
1862 let mut pending_discard_init_fixups = SurfacesInDiscardState::new();
1863
1864 let info = RenderPassInfo::start(
1865 device,
1866 hal_label(base.label.as_deref(), device.instance_flags),
1867 pass.color_attachments.take(),
1868 pass.depth_stencil_attachment.take(),
1869 pass.timestamp_writes.take(),
1870 pass.occlusion_query_set.clone(),
1873 encoder,
1874 tracker,
1875 texture_memory_actions,
1876 pending_query_resets,
1877 &mut pending_discard_init_fixups,
1878 snatch_guard,
1879 )
1880 .map_pass_err(pass_scope)?;
1881
1882 let indices = &device.tracker_indices;
1883 tracker.buffers.set_size(indices.buffers.size());
1884 tracker.textures.set_size(indices.textures.size());
1885
1886 let mut state = State {
1887 pipeline_flags: PipelineFlags::empty(),
1888 blend_constant: OptionalState::Unused,
1889 stencil_reference: 0,
1890 pipeline: None,
1891 index: IndexState::default(),
1892 vertex: VertexState::default(),
1893
1894 info,
1895
1896 general: pass::BaseState {
1897 device,
1898 raw_encoder: encoder.raw.as_mut(),
1899 tracker,
1900 buffer_memory_init_actions,
1901 texture_memory_actions,
1902 as_actions: &mut cmd_buf_data.as_actions,
1903 pending_discard_init_fixups,
1904 scope: device.new_usage_scope(),
1905 binder: Binder::new(),
1906
1907 snatch_guard,
1908
1909 temp_offsets: Vec::new(),
1910 dynamic_offset_count: 0,
1911
1912 debug_scope_depth: 0,
1913 string_offset: 0,
1914 },
1915
1916 active_occlusion_query: None,
1917 active_pipeline_statistics_query: None,
1918 };
1919
1920 for command in base.commands.drain(..) {
1921 match command {
1922 ArcRenderCommand::SetBindGroup {
1923 index,
1924 num_dynamic_offsets,
1925 bind_group,
1926 } => {
1927 let scope = PassErrorScope::SetBindGroup;
1928 pass::set_bind_group::<RenderPassErrorInner>(
1929 &mut state.general,
1930 cmd_buf.as_ref(),
1931 &base.dynamic_offsets,
1932 index,
1933 num_dynamic_offsets,
1934 bind_group,
1935 true,
1936 )
1937 .map_pass_err(scope)?;
1938 }
1939 ArcRenderCommand::SetPipeline(pipeline) => {
1940 let scope = PassErrorScope::SetPipelineRender;
1941 set_pipeline(&mut state, &cmd_buf, pipeline).map_pass_err(scope)?;
1942 }
1943 ArcRenderCommand::SetIndexBuffer {
1944 buffer,
1945 index_format,
1946 offset,
1947 size,
1948 } => {
1949 let scope = PassErrorScope::SetIndexBuffer;
1950 set_index_buffer(
1951 &mut state,
1952 &cmd_buf,
1953 buffer,
1954 index_format,
1955 offset,
1956 size,
1957 )
1958 .map_pass_err(scope)?;
1959 }
1960 ArcRenderCommand::SetVertexBuffer {
1961 slot,
1962 buffer,
1963 offset,
1964 size,
1965 } => {
1966 let scope = PassErrorScope::SetVertexBuffer;
1967 set_vertex_buffer(&mut state, &cmd_buf, slot, buffer, offset, size)
1968 .map_pass_err(scope)?;
1969 }
1970 ArcRenderCommand::SetBlendConstant(ref color) => {
1971 set_blend_constant(&mut state, color);
1972 }
1973 ArcRenderCommand::SetStencilReference(value) => {
1974 set_stencil_reference(&mut state, value);
1975 }
1976 ArcRenderCommand::SetViewport {
1977 rect,
1978 depth_min,
1979 depth_max,
1980 } => {
1981 let scope = PassErrorScope::SetViewport;
1982 set_viewport(&mut state, rect, depth_min, depth_max)
1983 .map_pass_err(scope)?;
1984 }
1985 ArcRenderCommand::SetPushConstant {
1986 stages,
1987 offset,
1988 size_bytes,
1989 values_offset,
1990 } => {
1991 let scope = PassErrorScope::SetPushConstant;
1992 pass::set_push_constant::<RenderPassErrorInner, _>(
1993 &mut state.general,
1994 &base.push_constant_data,
1995 stages,
1996 offset,
1997 size_bytes,
1998 values_offset,
1999 |_| {},
2000 )
2001 .map_pass_err(scope)?;
2002 }
2003 ArcRenderCommand::SetScissor(rect) => {
2004 let scope = PassErrorScope::SetScissorRect;
2005 set_scissor(&mut state, rect).map_pass_err(scope)?;
2006 }
2007 ArcRenderCommand::Draw {
2008 vertex_count,
2009 instance_count,
2010 first_vertex,
2011 first_instance,
2012 } => {
2013 let scope = PassErrorScope::Draw {
2014 kind: DrawKind::Draw,
2015 indexed: false,
2016 };
2017 draw(
2018 &mut state,
2019 vertex_count,
2020 instance_count,
2021 first_vertex,
2022 first_instance,
2023 )
2024 .map_pass_err(scope)?;
2025 }
2026 ArcRenderCommand::DrawIndexed {
2027 index_count,
2028 instance_count,
2029 first_index,
2030 base_vertex,
2031 first_instance,
2032 } => {
2033 let scope = PassErrorScope::Draw {
2034 kind: DrawKind::Draw,
2035 indexed: true,
2036 };
2037 draw_indexed(
2038 &mut state,
2039 index_count,
2040 instance_count,
2041 first_index,
2042 base_vertex,
2043 first_instance,
2044 )
2045 .map_pass_err(scope)?;
2046 }
2047 ArcRenderCommand::DrawIndirect {
2048 buffer,
2049 offset,
2050 count,
2051 indexed,
2052
2053 vertex_or_index_limit: _,
2054 instance_limit: _,
2055 } => {
2056 let scope = PassErrorScope::Draw {
2057 kind: if count != 1 {
2058 DrawKind::MultiDrawIndirect
2059 } else {
2060 DrawKind::DrawIndirect
2061 },
2062 indexed,
2063 };
2064 multi_draw_indirect(
2065 &mut state,
2066 indirect_draw_validation_resources,
2067 &mut indirect_draw_validation_batcher,
2068 &cmd_buf,
2069 buffer,
2070 offset,
2071 count,
2072 indexed,
2073 )
2074 .map_pass_err(scope)?;
2075 }
2076 ArcRenderCommand::MultiDrawIndirectCount {
2077 buffer,
2078 offset,
2079 count_buffer,
2080 count_buffer_offset,
2081 max_count,
2082 indexed,
2083 } => {
2084 let scope = PassErrorScope::Draw {
2085 kind: DrawKind::MultiDrawIndirectCount,
2086 indexed,
2087 };
2088 multi_draw_indirect_count(
2089 &mut state,
2090 &cmd_buf,
2091 buffer,
2092 offset,
2093 count_buffer,
2094 count_buffer_offset,
2095 max_count,
2096 indexed,
2097 )
2098 .map_pass_err(scope)?;
2099 }
2100 ArcRenderCommand::PushDebugGroup { color: _, len } => {
2101 pass::push_debug_group(&mut state.general, &base.string_data, len);
2102 }
2103 ArcRenderCommand::PopDebugGroup => {
2104 let scope = PassErrorScope::PopDebugGroup;
2105 pass::pop_debug_group::<RenderPassErrorInner>(&mut state.general)
2106 .map_pass_err(scope)?;
2107 }
2108 ArcRenderCommand::InsertDebugMarker { color: _, len } => {
2109 pass::insert_debug_marker(&mut state.general, &base.string_data, len);
2110 }
2111 ArcRenderCommand::WriteTimestamp {
2112 query_set,
2113 query_index,
2114 } => {
2115 let scope = PassErrorScope::WriteTimestamp;
2116 pass::write_timestamp::<RenderPassErrorInner>(
2117 &mut state.general,
2118 cmd_buf.as_ref(),
2119 Some(&mut cmd_buf_data.pending_query_resets),
2120 query_set,
2121 query_index,
2122 )
2123 .map_pass_err(scope)?;
2124 }
2125 ArcRenderCommand::BeginOcclusionQuery { query_index } => {
2126 api_log!("RenderPass::begin_occlusion_query {query_index}");
2127 let scope = PassErrorScope::BeginOcclusionQuery;
2128
2129 let query_set = pass
2130 .occlusion_query_set
2131 .clone()
2132 .ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
2133 .map_pass_err(scope)?;
2134
2135 validate_and_begin_occlusion_query(
2136 query_set,
2137 state.general.raw_encoder,
2138 &mut state.general.tracker.query_sets,
2139 query_index,
2140 Some(&mut cmd_buf_data.pending_query_resets),
2141 &mut state.active_occlusion_query,
2142 )
2143 .map_pass_err(scope)?;
2144 }
2145 ArcRenderCommand::EndOcclusionQuery => {
2146 api_log!("RenderPass::end_occlusion_query");
2147 let scope = PassErrorScope::EndOcclusionQuery;
2148
2149 end_occlusion_query(
2150 state.general.raw_encoder,
2151 &mut state.active_occlusion_query,
2152 )
2153 .map_pass_err(scope)?;
2154 }
2155 ArcRenderCommand::BeginPipelineStatisticsQuery {
2156 query_set,
2157 query_index,
2158 } => {
2159 api_log!(
2160 "RenderPass::begin_pipeline_statistics_query {query_index} {}",
2161 query_set.error_ident()
2162 );
2163 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
2164
2165 validate_and_begin_pipeline_statistics_query(
2166 query_set,
2167 state.general.raw_encoder,
2168 &mut state.general.tracker.query_sets,
2169 cmd_buf.as_ref(),
2170 query_index,
2171 Some(&mut cmd_buf_data.pending_query_resets),
2172 &mut state.active_pipeline_statistics_query,
2173 )
2174 .map_pass_err(scope)?;
2175 }
2176 ArcRenderCommand::EndPipelineStatisticsQuery => {
2177 api_log!("RenderPass::end_pipeline_statistics_query");
2178 let scope = PassErrorScope::EndPipelineStatisticsQuery;
2179
2180 end_pipeline_statistics_query(
2181 state.general.raw_encoder,
2182 &mut state.active_pipeline_statistics_query,
2183 )
2184 .map_pass_err(scope)?;
2185 }
2186 ArcRenderCommand::ExecuteBundle(bundle) => {
2187 let scope = PassErrorScope::ExecuteBundle;
2188 execute_bundle(
2189 &mut state,
2190 indirect_draw_validation_resources,
2191 &mut indirect_draw_validation_batcher,
2192 &cmd_buf,
2193 bundle,
2194 )
2195 .map_pass_err(scope)?;
2196 }
2197 }
2198 }
2199
2200 state
2201 .info
2202 .finish(
2203 device,
2204 state.general.raw_encoder,
2205 state.general.snatch_guard,
2206 &mut state.general.scope,
2207 )
2208 .map_pass_err(pass_scope)?;
2209
2210 let trackers = state.general.scope;
2211
2212 let pending_discard_init_fixups = state.general.pending_discard_init_fixups;
2213
2214 encoder.close().map_pass_err(pass_scope)?;
2215 (trackers, pending_discard_init_fixups)
2216 };
2217
2218 let encoder = &mut cmd_buf_data.encoder;
2219 let tracker = &mut cmd_buf_data.trackers;
2220
2221 {
2222 let transit = encoder
2223 .open_pass(Some("(wgpu internal) Pre Pass"))
2224 .map_pass_err(pass_scope)?;
2225
2226 fixup_discarded_surfaces(
2227 pending_discard_init_fixups.into_iter(),
2228 transit,
2229 &mut tracker.textures,
2230 &cmd_buf.device,
2231 snatch_guard,
2232 );
2233
2234 cmd_buf_data.pending_query_resets.reset_queries(transit);
2235
2236 CommandBuffer::insert_barriers_from_scope(transit, tracker, &scope, snatch_guard);
2237
2238 if let Some(ref indirect_validation) = device.indirect_validation {
2239 indirect_validation
2240 .draw
2241 .inject_validation_pass(
2242 device,
2243 snatch_guard,
2244 &mut cmd_buf_data.indirect_draw_validation_resources,
2245 &mut cmd_buf_data.temp_resources,
2246 transit,
2247 indirect_draw_validation_batcher,
2248 )
2249 .map_pass_err(pass_scope)?;
2250 }
2251 }
2252
2253 encoder.close_and_swap().map_pass_err(pass_scope)?;
2254
2255 Ok(())
2256 })
2257 }
2258}
2259
2260fn set_pipeline(
2261 state: &mut State,
2262 cmd_buf: &Arc<CommandBuffer>,
2263 pipeline: Arc<RenderPipeline>,
2264) -> Result<(), RenderPassErrorInner> {
2265 api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
2266
2267 state.pipeline = Some(pipeline.clone());
2268
2269 let pipeline = state
2270 .general
2271 .tracker
2272 .render_pipelines
2273 .insert_single(pipeline)
2274 .clone();
2275
2276 pipeline.same_device_as(cmd_buf.as_ref())?;
2277
2278 state
2279 .info
2280 .context
2281 .check_compatible(&pipeline.pass_context, pipeline.as_ref())
2282 .map_err(RenderCommandError::IncompatiblePipelineTargets)?;
2283
2284 state.pipeline_flags = pipeline.flags;
2285
2286 if pipeline.flags.contains(PipelineFlags::WRITES_DEPTH) && state.info.is_depth_read_only {
2287 return Err(RenderCommandError::IncompatibleDepthAccess(pipeline.error_ident()).into());
2288 }
2289 if pipeline.flags.contains(PipelineFlags::WRITES_STENCIL) && state.info.is_stencil_read_only {
2290 return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into());
2291 }
2292
2293 state
2294 .blend_constant
2295 .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT));
2296
2297 unsafe {
2298 state
2299 .general
2300 .raw_encoder
2301 .set_render_pipeline(pipeline.raw());
2302 }
2303
2304 if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) {
2305 unsafe {
2306 state
2307 .general
2308 .raw_encoder
2309 .set_stencil_reference(state.stencil_reference);
2310 }
2311 }
2312
2313 pass::rebind_resources::<RenderPassErrorInner, _>(
2315 &mut state.general,
2316 &pipeline.layout,
2317 &pipeline.late_sized_buffer_groups,
2318 || {},
2319 )?;
2320
2321 state.vertex.update_limits(&pipeline.vertex_steps);
2323 Ok(())
2324}
2325
2326fn set_index_buffer(
2327 state: &mut State,
2328 cmd_buf: &Arc<CommandBuffer>,
2329 buffer: Arc<crate::resource::Buffer>,
2330 index_format: IndexFormat,
2331 offset: u64,
2332 size: Option<BufferSize>,
2333) -> Result<(), RenderPassErrorInner> {
2334 api_log!("RenderPass::set_index_buffer {}", buffer.error_ident());
2335
2336 state
2337 .general
2338 .scope
2339 .buffers
2340 .merge_single(&buffer, wgt::BufferUses::INDEX)?;
2341
2342 buffer.same_device_as(cmd_buf.as_ref())?;
2343
2344 buffer.check_usage(BufferUsages::INDEX)?;
2345 let buf_raw = buffer.try_raw(state.general.snatch_guard)?;
2346
2347 let end = match size {
2348 Some(s) => offset + s.get(),
2349 None => buffer.size,
2350 };
2351 state.index.update_buffer(offset..end, index_format);
2352
2353 state.general.buffer_memory_init_actions.extend(
2354 buffer.initialization_status.read().create_action(
2355 &buffer,
2356 offset..end,
2357 MemoryInitKind::NeedsInitializedMemory,
2358 ),
2359 );
2360
2361 let bb = hal::BufferBinding {
2362 buffer: buf_raw,
2363 offset,
2364 size,
2365 };
2366 unsafe {
2367 hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, bb, index_format);
2368 }
2369 Ok(())
2370}
2371
2372fn set_vertex_buffer(
2373 state: &mut State,
2374 cmd_buf: &Arc<CommandBuffer>,
2375 slot: u32,
2376 buffer: Arc<crate::resource::Buffer>,
2377 offset: u64,
2378 size: Option<BufferSize>,
2379) -> Result<(), RenderPassErrorInner> {
2380 api_log!(
2381 "RenderPass::set_vertex_buffer {slot} {}",
2382 buffer.error_ident()
2383 );
2384
2385 state
2386 .general
2387 .scope
2388 .buffers
2389 .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
2390
2391 buffer.same_device_as(cmd_buf.as_ref())?;
2392
2393 let max_vertex_buffers = state.general.device.limits.max_vertex_buffers;
2394 if slot >= max_vertex_buffers {
2395 return Err(RenderCommandError::VertexBufferIndexOutOfRange {
2396 index: slot,
2397 max: max_vertex_buffers,
2398 }
2399 .into());
2400 }
2401
2402 buffer.check_usage(BufferUsages::VERTEX)?;
2403 let buf_raw = buffer.try_raw(state.general.snatch_guard)?;
2404
2405 let buffer_size = match size {
2407 Some(s) => s.get(),
2408 None => buffer.size - offset,
2409 };
2410 state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
2411
2412 state.general.buffer_memory_init_actions.extend(
2413 buffer.initialization_status.read().create_action(
2414 &buffer,
2415 offset..(offset + buffer_size),
2416 MemoryInitKind::NeedsInitializedMemory,
2417 ),
2418 );
2419
2420 let bb = hal::BufferBinding {
2421 buffer: buf_raw,
2422 offset,
2423 size,
2424 };
2425 unsafe {
2426 hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, bb);
2427 }
2428 if let Some(pipeline) = state.pipeline.as_ref() {
2429 state.vertex.update_limits(&pipeline.vertex_steps);
2430 }
2431 Ok(())
2432}
2433
2434fn set_blend_constant(state: &mut State, color: &Color) {
2435 api_log!("RenderPass::set_blend_constant");
2436
2437 state.blend_constant = OptionalState::Set;
2438 let array = [
2439 color.r as f32,
2440 color.g as f32,
2441 color.b as f32,
2442 color.a as f32,
2443 ];
2444 unsafe {
2445 state.general.raw_encoder.set_blend_constants(&array);
2446 }
2447}
2448
2449fn set_stencil_reference(state: &mut State, value: u32) {
2450 api_log!("RenderPass::set_stencil_reference {value}");
2451
2452 state.stencil_reference = value;
2453 if state
2454 .pipeline_flags
2455 .contains(PipelineFlags::STENCIL_REFERENCE)
2456 {
2457 unsafe {
2458 state.general.raw_encoder.set_stencil_reference(value);
2459 }
2460 }
2461}
2462
2463fn set_viewport(
2464 state: &mut State,
2465 rect: Rect<f32>,
2466 depth_min: f32,
2467 depth_max: f32,
2468) -> Result<(), RenderPassErrorInner> {
2469 api_log!("RenderPass::set_viewport {rect:?}");
2470
2471 if rect.w < 0.0
2472 || rect.h < 0.0
2473 || rect.w > state.general.device.limits.max_texture_dimension_2d as f32
2474 || rect.h > state.general.device.limits.max_texture_dimension_2d as f32
2475 {
2476 return Err(RenderCommandError::InvalidViewportRectSize {
2477 w: rect.w,
2478 h: rect.h,
2479 max: state.general.device.limits.max_texture_dimension_2d,
2480 }
2481 .into());
2482 }
2483
2484 let max_viewport_range = state.general.device.limits.max_texture_dimension_2d as f32 * 2.0;
2485
2486 if rect.x < -max_viewport_range
2487 || rect.y < -max_viewport_range
2488 || rect.x + rect.w > max_viewport_range - 1.0
2489 || rect.y + rect.h > max_viewport_range - 1.0
2490 {
2491 return Err(RenderCommandError::InvalidViewportRectPosition {
2492 rect,
2493 min: -max_viewport_range,
2494 max: max_viewport_range - 1.0,
2495 }
2496 .into());
2497 }
2498 if !(0.0..=1.0).contains(&depth_min) || !(0.0..=1.0).contains(&depth_max) {
2499 return Err(RenderCommandError::InvalidViewportDepth(depth_min, depth_max).into());
2500 }
2501 let r = hal::Rect {
2502 x: rect.x,
2503 y: rect.y,
2504 w: rect.w,
2505 h: rect.h,
2506 };
2507 unsafe {
2508 state
2509 .general
2510 .raw_encoder
2511 .set_viewport(&r, depth_min..depth_max);
2512 }
2513 Ok(())
2514}
2515
2516fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassErrorInner> {
2517 api_log!("RenderPass::set_scissor_rect {rect:?}");
2518
2519 if rect.x.saturating_add(rect.w) > state.info.extent.width
2520 || rect.y.saturating_add(rect.h) > state.info.extent.height
2521 {
2522 return Err(RenderCommandError::InvalidScissorRect(rect, state.info.extent).into());
2523 }
2524 let r = hal::Rect {
2525 x: rect.x,
2526 y: rect.y,
2527 w: rect.w,
2528 h: rect.h,
2529 };
2530 unsafe {
2531 state.general.raw_encoder.set_scissor_rect(&r);
2532 }
2533 Ok(())
2534}
2535
2536fn draw(
2537 state: &mut State,
2538 vertex_count: u32,
2539 instance_count: u32,
2540 first_vertex: u32,
2541 first_instance: u32,
2542) -> Result<(), DrawError> {
2543 api_log!("RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}");
2544
2545 state.is_ready(false)?;
2546
2547 state
2548 .vertex
2549 .limits
2550 .validate_vertex_limit(first_vertex, vertex_count)?;
2551 state
2552 .vertex
2553 .limits
2554 .validate_instance_limit(first_instance, instance_count)?;
2555
2556 unsafe {
2557 if instance_count > 0 && vertex_count > 0 {
2558 state.general.raw_encoder.draw(
2559 first_vertex,
2560 vertex_count,
2561 first_instance,
2562 instance_count,
2563 );
2564 }
2565 }
2566 Ok(())
2567}
2568
2569fn draw_indexed(
2570 state: &mut State,
2571 index_count: u32,
2572 instance_count: u32,
2573 first_index: u32,
2574 base_vertex: i32,
2575 first_instance: u32,
2576) -> Result<(), DrawError> {
2577 api_log!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
2578
2579 state.is_ready(true)?;
2580
2581 let last_index = first_index as u64 + index_count as u64;
2582 let index_limit = state.index.limit;
2583 if last_index > index_limit {
2584 return Err(DrawError::IndexBeyondLimit {
2585 last_index,
2586 index_limit,
2587 });
2588 }
2589 state
2590 .vertex
2591 .limits
2592 .validate_instance_limit(first_instance, instance_count)?;
2593
2594 unsafe {
2595 if instance_count > 0 && index_count > 0 {
2596 state.general.raw_encoder.draw_indexed(
2597 first_index,
2598 index_count,
2599 base_vertex,
2600 first_instance,
2601 instance_count,
2602 );
2603 }
2604 }
2605 Ok(())
2606}
2607
2608fn multi_draw_indirect(
2609 state: &mut State,
2610 indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
2611 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2612 cmd_buf: &Arc<CommandBuffer>,
2613 indirect_buffer: Arc<crate::resource::Buffer>,
2614 offset: u64,
2615 count: u32,
2616 indexed: bool,
2617) -> Result<(), RenderPassErrorInner> {
2618 api_log!(
2619 "RenderPass::draw_indirect (indexed:{indexed}) {} {offset} {count:?}",
2620 indirect_buffer.error_ident()
2621 );
2622
2623 state.is_ready(indexed)?;
2624
2625 if count != 1 {
2626 state
2627 .general
2628 .device
2629 .require_features(wgt::Features::MULTI_DRAW_INDIRECT)?;
2630 }
2631
2632 state
2633 .general
2634 .device
2635 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2636
2637 indirect_buffer.same_device_as(cmd_buf.as_ref())?;
2638 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2639 indirect_buffer.check_destroyed(state.general.snatch_guard)?;
2640
2641 if offset % 4 != 0 {
2642 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2643 }
2644
2645 let stride = get_stride_of_indirect_args(indexed);
2646
2647 let end_offset = offset + stride * count as u64;
2648 if end_offset > indirect_buffer.size {
2649 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2650 count,
2651 offset,
2652 end_offset,
2653 buffer_size: indirect_buffer.size,
2654 });
2655 }
2656
2657 state.general.buffer_memory_init_actions.extend(
2658 indirect_buffer.initialization_status.read().create_action(
2659 &indirect_buffer,
2660 offset..end_offset,
2661 MemoryInitKind::NeedsInitializedMemory,
2662 ),
2663 );
2664
2665 fn draw(
2666 raw_encoder: &mut dyn hal::DynCommandEncoder,
2667 indexed: bool,
2668 indirect_buffer: &dyn hal::DynBuffer,
2669 offset: u64,
2670 count: u32,
2671 ) {
2672 match indexed {
2673 false => unsafe {
2674 raw_encoder.draw_indirect(indirect_buffer, offset, count);
2675 },
2676 true => unsafe {
2677 raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2678 },
2679 }
2680 }
2681
2682 if state.general.device.indirect_validation.is_some() {
2683 state
2684 .general
2685 .scope
2686 .buffers
2687 .merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
2688
2689 struct DrawData {
2690 buffer_index: usize,
2691 offset: u64,
2692 count: u32,
2693 }
2694
2695 struct DrawContext<'a> {
2696 raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2697 device: &'a Device,
2698
2699 indirect_draw_validation_resources: &'a mut crate::indirect_validation::DrawResources,
2700 indirect_draw_validation_batcher: &'a mut crate::indirect_validation::DrawBatcher,
2701
2702 indirect_buffer: Arc<crate::resource::Buffer>,
2703 indexed: bool,
2704 vertex_or_index_limit: u64,
2705 instance_limit: u64,
2706 }
2707
2708 impl<'a> DrawContext<'a> {
2709 fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2710 let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2711 self.indirect_draw_validation_resources,
2712 self.device,
2713 &self.indirect_buffer,
2714 offset,
2715 self.indexed,
2716 self.vertex_or_index_limit,
2717 self.instance_limit,
2718 )?;
2719 Ok(DrawData {
2720 buffer_index: dst_resource_index,
2721 offset: dst_offset,
2722 count: 1,
2723 })
2724 }
2725 fn draw(&mut self, draw_data: DrawData) {
2726 let dst_buffer = self
2727 .indirect_draw_validation_resources
2728 .get_dst_buffer(draw_data.buffer_index);
2729 draw(
2730 self.raw_encoder,
2731 self.indexed,
2732 dst_buffer,
2733 draw_data.offset,
2734 draw_data.count,
2735 );
2736 }
2737 }
2738
2739 let mut draw_ctx = DrawContext {
2740 raw_encoder: state.general.raw_encoder,
2741 device: state.general.device,
2742 indirect_draw_validation_resources,
2743 indirect_draw_validation_batcher,
2744 indirect_buffer,
2745 indexed,
2746 vertex_or_index_limit: if indexed {
2747 state.index.limit
2748 } else {
2749 state.vertex.limits.vertex_limit
2750 },
2751 instance_limit: state.vertex.limits.instance_limit,
2752 };
2753
2754 let mut current_draw_data = draw_ctx.add(offset)?;
2755
2756 for i in 1..count {
2757 let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2758
2759 if draw_data.buffer_index == current_draw_data.buffer_index {
2760 debug_assert_eq!(
2761 draw_data.offset,
2762 current_draw_data.offset + stride * current_draw_data.count as u64
2763 );
2764 current_draw_data.count += 1;
2765 } else {
2766 draw_ctx.draw(current_draw_data);
2767 current_draw_data = draw_data;
2768 }
2769 }
2770
2771 draw_ctx.draw(current_draw_data);
2772 } else {
2773 state
2774 .general
2775 .scope
2776 .buffers
2777 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2778
2779 draw(
2780 state.general.raw_encoder,
2781 indexed,
2782 indirect_buffer.try_raw(state.general.snatch_guard)?,
2783 offset,
2784 count,
2785 );
2786 };
2787
2788 Ok(())
2789}
2790
2791fn multi_draw_indirect_count(
2792 state: &mut State,
2793 cmd_buf: &Arc<CommandBuffer>,
2794 indirect_buffer: Arc<crate::resource::Buffer>,
2795 offset: u64,
2796 count_buffer: Arc<crate::resource::Buffer>,
2797 count_buffer_offset: u64,
2798 max_count: u32,
2799 indexed: bool,
2800) -> Result<(), RenderPassErrorInner> {
2801 api_log!(
2802 "RenderPass::multi_draw_indirect_count (indexed:{indexed}) {} {offset} {} {count_buffer_offset:?} {max_count:?}",
2803 indirect_buffer.error_ident(),
2804 count_buffer.error_ident()
2805 );
2806
2807 state.is_ready(indexed)?;
2808
2809 let stride = get_stride_of_indirect_args(indexed);
2810
2811 state
2812 .general
2813 .device
2814 .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT)?;
2815 state
2816 .general
2817 .device
2818 .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
2819
2820 indirect_buffer.same_device_as(cmd_buf.as_ref())?;
2821 count_buffer.same_device_as(cmd_buf.as_ref())?;
2822
2823 state
2824 .general
2825 .scope
2826 .buffers
2827 .merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
2828
2829 indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
2830 let indirect_raw = indirect_buffer.try_raw(state.general.snatch_guard)?;
2831
2832 state
2833 .general
2834 .scope
2835 .buffers
2836 .merge_single(&count_buffer, wgt::BufferUses::INDIRECT)?;
2837
2838 count_buffer.check_usage(BufferUsages::INDIRECT)?;
2839 let count_raw = count_buffer.try_raw(state.general.snatch_guard)?;
2840
2841 if offset % 4 != 0 {
2842 return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
2843 }
2844
2845 let end_offset = offset + stride * max_count as u64;
2846 if end_offset > indirect_buffer.size {
2847 return Err(RenderPassErrorInner::IndirectBufferOverrun {
2848 count: 1,
2849 offset,
2850 end_offset,
2851 buffer_size: indirect_buffer.size,
2852 });
2853 }
2854 state.general.buffer_memory_init_actions.extend(
2855 indirect_buffer.initialization_status.read().create_action(
2856 &indirect_buffer,
2857 offset..end_offset,
2858 MemoryInitKind::NeedsInitializedMemory,
2859 ),
2860 );
2861
2862 let begin_count_offset = count_buffer_offset;
2863 let end_count_offset = count_buffer_offset + 4;
2864 if end_count_offset > count_buffer.size {
2865 return Err(RenderPassErrorInner::IndirectCountBufferOverrun {
2866 begin_count_offset,
2867 end_count_offset,
2868 count_buffer_size: count_buffer.size,
2869 });
2870 }
2871 state.general.buffer_memory_init_actions.extend(
2872 count_buffer.initialization_status.read().create_action(
2873 &count_buffer,
2874 count_buffer_offset..end_count_offset,
2875 MemoryInitKind::NeedsInitializedMemory,
2876 ),
2877 );
2878
2879 match indexed {
2880 false => unsafe {
2881 state.general.raw_encoder.draw_indirect_count(
2882 indirect_raw,
2883 offset,
2884 count_raw,
2885 count_buffer_offset,
2886 max_count,
2887 );
2888 },
2889 true => unsafe {
2890 state.general.raw_encoder.draw_indexed_indirect_count(
2891 indirect_raw,
2892 offset,
2893 count_raw,
2894 count_buffer_offset,
2895 max_count,
2896 );
2897 },
2898 }
2899 Ok(())
2900}
2901
2902fn execute_bundle(
2903 state: &mut State,
2904 indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
2905 indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
2906 cmd_buf: &Arc<CommandBuffer>,
2907 bundle: Arc<super::RenderBundle>,
2908) -> Result<(), RenderPassErrorInner> {
2909 api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
2910
2911 let bundle = state.general.tracker.bundles.insert_single(bundle);
2912
2913 bundle.same_device_as(cmd_buf.as_ref())?;
2914
2915 state
2916 .info
2917 .context
2918 .check_compatible(&bundle.context, bundle.as_ref())
2919 .map_err(RenderPassErrorInner::IncompatibleBundleTargets)?;
2920
2921 if (state.info.is_depth_read_only && !bundle.is_depth_read_only)
2922 || (state.info.is_stencil_read_only && !bundle.is_stencil_read_only)
2923 {
2924 return Err(
2925 RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil {
2926 pass_depth: state.info.is_depth_read_only,
2927 pass_stencil: state.info.is_stencil_read_only,
2928 bundle_depth: bundle.is_depth_read_only,
2929 bundle_stencil: bundle.is_stencil_read_only,
2930 },
2931 );
2932 }
2933
2934 state.general.buffer_memory_init_actions.extend(
2935 bundle
2936 .buffer_memory_init_actions
2937 .iter()
2938 .filter_map(|action| {
2939 action
2940 .buffer
2941 .initialization_status
2942 .read()
2943 .check_action(action)
2944 }),
2945 );
2946 for action in bundle.texture_memory_init_actions.iter() {
2947 state.general.pending_discard_init_fixups.extend(
2948 state
2949 .general
2950 .texture_memory_actions
2951 .register_init_action(action),
2952 );
2953 }
2954
2955 unsafe {
2956 bundle.execute(
2957 state.general.raw_encoder,
2958 indirect_draw_validation_resources,
2959 indirect_draw_validation_batcher,
2960 state.general.snatch_guard,
2961 )
2962 }
2963 .map_err(|e| match e {
2964 ExecutionError::Device(e) => RenderPassErrorInner::Device(e),
2965 ExecutionError::DestroyedResource(e) => {
2966 RenderPassErrorInner::RenderCommand(RenderCommandError::DestroyedResource(e))
2967 }
2968 ExecutionError::Unimplemented(what) => {
2969 RenderPassErrorInner::RenderCommand(RenderCommandError::Unimplemented(what))
2970 }
2971 })?;
2972
2973 unsafe {
2974 state.general.scope.merge_render_bundle(&bundle.used)?;
2975 };
2976 state.reset_bundle();
2977 Ok(())
2978}
2979
2980impl Global {
2993 fn resolve_render_pass_buffer_id(
2994 &self,
2995 buffer_id: id::Id<id::markers::Buffer>,
2996 ) -> Result<Arc<crate::resource::Buffer>, InvalidResourceError> {
2997 let hub = &self.hub;
2998 let buffer = hub.buffers.get(buffer_id).get()?;
2999
3000 Ok(buffer)
3001 }
3002
3003 fn resolve_render_pass_query_set(
3004 &self,
3005 query_set_id: id::Id<id::markers::QuerySet>,
3006 ) -> Result<Arc<QuerySet>, InvalidResourceError> {
3007 let hub = &self.hub;
3008 let query_set = hub.query_sets.get(query_set_id).get()?;
3009
3010 Ok(query_set)
3011 }
3012
3013 pub fn render_pass_set_bind_group(
3014 &self,
3015 pass: &mut RenderPass,
3016 index: u32,
3017 bind_group_id: Option<id::BindGroupId>,
3018 offsets: &[DynamicOffset],
3019 ) -> Result<(), PassStateError> {
3020 let scope = PassErrorScope::SetBindGroup;
3021
3022 let base = pass_base!(pass, scope);
3026
3027 if pass.current_bind_groups.set_and_check_redundant(
3028 bind_group_id,
3029 index,
3030 &mut base.dynamic_offsets,
3031 offsets,
3032 ) {
3033 return Ok(());
3034 }
3035
3036 let mut bind_group = None;
3037 if bind_group_id.is_some() {
3038 let bind_group_id = bind_group_id.unwrap();
3039
3040 let hub = &self.hub;
3041 bind_group = Some(pass_try!(
3042 base,
3043 scope,
3044 hub.bind_groups.get(bind_group_id).get(),
3045 ));
3046 }
3047
3048 base.commands.push(ArcRenderCommand::SetBindGroup {
3049 index,
3050 num_dynamic_offsets: offsets.len(),
3051 bind_group,
3052 });
3053
3054 Ok(())
3055 }
3056
3057 pub fn render_pass_set_pipeline(
3058 &self,
3059 pass: &mut RenderPass,
3060 pipeline_id: id::RenderPipelineId,
3061 ) -> Result<(), PassStateError> {
3062 let scope = PassErrorScope::SetPipelineRender;
3063
3064 let redundant = pass.current_pipeline.set_and_check_redundant(pipeline_id);
3065
3066 let base = pass_base!(pass, scope);
3069
3070 if redundant {
3071 return Ok(());
3072 }
3073
3074 let hub = &self.hub;
3075 let pipeline = pass_try!(base, scope, hub.render_pipelines.get(pipeline_id).get());
3076
3077 base.commands.push(ArcRenderCommand::SetPipeline(pipeline));
3078
3079 Ok(())
3080 }
3081
3082 pub fn render_pass_set_index_buffer(
3083 &self,
3084 pass: &mut RenderPass,
3085 buffer_id: id::BufferId,
3086 index_format: IndexFormat,
3087 offset: BufferAddress,
3088 size: Option<BufferSize>,
3089 ) -> Result<(), PassStateError> {
3090 let scope = PassErrorScope::SetIndexBuffer;
3091 let base = pass_base!(pass, scope);
3092
3093 base.commands.push(ArcRenderCommand::SetIndexBuffer {
3094 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3095 index_format,
3096 offset,
3097 size,
3098 });
3099
3100 Ok(())
3101 }
3102
3103 pub fn render_pass_set_vertex_buffer(
3104 &self,
3105 pass: &mut RenderPass,
3106 slot: u32,
3107 buffer_id: id::BufferId,
3108 offset: BufferAddress,
3109 size: Option<BufferSize>,
3110 ) -> Result<(), PassStateError> {
3111 let scope = PassErrorScope::SetVertexBuffer;
3112 let base = pass_base!(pass, scope);
3113
3114 base.commands.push(ArcRenderCommand::SetVertexBuffer {
3115 slot,
3116 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3117 offset,
3118 size,
3119 });
3120
3121 Ok(())
3122 }
3123
3124 pub fn render_pass_set_blend_constant(
3125 &self,
3126 pass: &mut RenderPass,
3127 color: Color,
3128 ) -> Result<(), PassStateError> {
3129 let scope = PassErrorScope::SetBlendConstant;
3130 let base = pass_base!(pass, scope);
3131
3132 base.commands
3133 .push(ArcRenderCommand::SetBlendConstant(color));
3134
3135 Ok(())
3136 }
3137
3138 pub fn render_pass_set_stencil_reference(
3139 &self,
3140 pass: &mut RenderPass,
3141 value: u32,
3142 ) -> Result<(), PassStateError> {
3143 let scope = PassErrorScope::SetStencilReference;
3144 let base = pass_base!(pass, scope);
3145
3146 base.commands
3147 .push(ArcRenderCommand::SetStencilReference(value));
3148
3149 Ok(())
3150 }
3151
3152 pub fn render_pass_set_viewport(
3153 &self,
3154 pass: &mut RenderPass,
3155 x: f32,
3156 y: f32,
3157 w: f32,
3158 h: f32,
3159 depth_min: f32,
3160 depth_max: f32,
3161 ) -> Result<(), PassStateError> {
3162 let scope = PassErrorScope::SetViewport;
3163 let base = pass_base!(pass, scope);
3164
3165 base.commands.push(ArcRenderCommand::SetViewport {
3166 rect: Rect { x, y, w, h },
3167 depth_min,
3168 depth_max,
3169 });
3170
3171 Ok(())
3172 }
3173
3174 pub fn render_pass_set_scissor_rect(
3175 &self,
3176 pass: &mut RenderPass,
3177 x: u32,
3178 y: u32,
3179 w: u32,
3180 h: u32,
3181 ) -> Result<(), PassStateError> {
3182 let scope = PassErrorScope::SetScissorRect;
3183 let base = pass_base!(pass, scope);
3184
3185 base.commands
3186 .push(ArcRenderCommand::SetScissor(Rect { x, y, w, h }));
3187
3188 Ok(())
3189 }
3190
3191 pub fn render_pass_set_push_constants(
3192 &self,
3193 pass: &mut RenderPass,
3194 stages: ShaderStages,
3195 offset: u32,
3196 data: &[u8],
3197 ) -> Result<(), PassStateError> {
3198 let scope = PassErrorScope::SetPushConstant;
3199 let base = pass_base!(pass, scope);
3200
3201 if offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 {
3202 pass_try!(
3203 base,
3204 scope,
3205 Err(RenderPassErrorInner::PushConstantOffsetAlignment)
3206 );
3207 }
3208 if data.len() as u32 & (wgt::PUSH_CONSTANT_ALIGNMENT - 1) != 0 {
3209 pass_try!(
3210 base,
3211 scope,
3212 Err(RenderPassErrorInner::PushConstantSizeAlignment)
3213 );
3214 }
3215
3216 let value_offset = pass_try!(
3217 base,
3218 scope,
3219 base.push_constant_data
3220 .len()
3221 .try_into()
3222 .map_err(|_| RenderPassErrorInner::PushConstantOutOfMemory),
3223 );
3224
3225 base.push_constant_data.extend(
3226 data.chunks_exact(wgt::PUSH_CONSTANT_ALIGNMENT as usize)
3227 .map(|arr| u32::from_ne_bytes([arr[0], arr[1], arr[2], arr[3]])),
3228 );
3229
3230 base.commands.push(ArcRenderCommand::SetPushConstant {
3231 stages,
3232 offset,
3233 size_bytes: data.len() as u32,
3234 values_offset: Some(value_offset),
3235 });
3236
3237 Ok(())
3238 }
3239
3240 pub fn render_pass_draw(
3241 &self,
3242 pass: &mut RenderPass,
3243 vertex_count: u32,
3244 instance_count: u32,
3245 first_vertex: u32,
3246 first_instance: u32,
3247 ) -> Result<(), PassStateError> {
3248 let scope = PassErrorScope::Draw {
3249 kind: DrawKind::Draw,
3250 indexed: false,
3251 };
3252 let base = pass_base!(pass, scope);
3253
3254 base.commands.push(ArcRenderCommand::Draw {
3255 vertex_count,
3256 instance_count,
3257 first_vertex,
3258 first_instance,
3259 });
3260
3261 Ok(())
3262 }
3263
3264 pub fn render_pass_draw_indexed(
3265 &self,
3266 pass: &mut RenderPass,
3267 index_count: u32,
3268 instance_count: u32,
3269 first_index: u32,
3270 base_vertex: i32,
3271 first_instance: u32,
3272 ) -> Result<(), PassStateError> {
3273 let scope = PassErrorScope::Draw {
3274 kind: DrawKind::Draw,
3275 indexed: true,
3276 };
3277 let base = pass_base!(pass, scope);
3278
3279 base.commands.push(ArcRenderCommand::DrawIndexed {
3280 index_count,
3281 instance_count,
3282 first_index,
3283 base_vertex,
3284 first_instance,
3285 });
3286
3287 Ok(())
3288 }
3289
3290 pub fn render_pass_draw_indirect(
3291 &self,
3292 pass: &mut RenderPass,
3293 buffer_id: id::BufferId,
3294 offset: BufferAddress,
3295 ) -> Result<(), PassStateError> {
3296 let scope = PassErrorScope::Draw {
3297 kind: DrawKind::DrawIndirect,
3298 indexed: false,
3299 };
3300 let base = pass_base!(pass, scope);
3301
3302 base.commands.push(ArcRenderCommand::DrawIndirect {
3303 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3304 offset,
3305 count: 1,
3306 indexed: false,
3307
3308 vertex_or_index_limit: 0,
3309 instance_limit: 0,
3310 });
3311
3312 Ok(())
3313 }
3314
3315 pub fn render_pass_draw_indexed_indirect(
3316 &self,
3317 pass: &mut RenderPass,
3318 buffer_id: id::BufferId,
3319 offset: BufferAddress,
3320 ) -> Result<(), PassStateError> {
3321 let scope = PassErrorScope::Draw {
3322 kind: DrawKind::DrawIndirect,
3323 indexed: true,
3324 };
3325 let base = pass_base!(pass, scope);
3326
3327 base.commands.push(ArcRenderCommand::DrawIndirect {
3328 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3329 offset,
3330 count: 1,
3331 indexed: true,
3332
3333 vertex_or_index_limit: 0,
3334 instance_limit: 0,
3335 });
3336
3337 Ok(())
3338 }
3339
3340 pub fn render_pass_multi_draw_indirect(
3341 &self,
3342 pass: &mut RenderPass,
3343 buffer_id: id::BufferId,
3344 offset: BufferAddress,
3345 count: u32,
3346 ) -> Result<(), PassStateError> {
3347 let scope = PassErrorScope::Draw {
3348 kind: DrawKind::MultiDrawIndirect,
3349 indexed: false,
3350 };
3351 let base = pass_base!(pass, scope);
3352
3353 base.commands.push(ArcRenderCommand::DrawIndirect {
3354 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3355 offset,
3356 count,
3357 indexed: false,
3358
3359 vertex_or_index_limit: 0,
3360 instance_limit: 0,
3361 });
3362
3363 Ok(())
3364 }
3365
3366 pub fn render_pass_multi_draw_indexed_indirect(
3367 &self,
3368 pass: &mut RenderPass,
3369 buffer_id: id::BufferId,
3370 offset: BufferAddress,
3371 count: u32,
3372 ) -> Result<(), PassStateError> {
3373 let scope = PassErrorScope::Draw {
3374 kind: DrawKind::MultiDrawIndirect,
3375 indexed: true,
3376 };
3377 let base = pass_base!(pass, scope);
3378
3379 base.commands.push(ArcRenderCommand::DrawIndirect {
3380 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3381 offset,
3382 count,
3383 indexed: true,
3384
3385 vertex_or_index_limit: 0,
3386 instance_limit: 0,
3387 });
3388
3389 Ok(())
3390 }
3391
3392 pub fn render_pass_multi_draw_indirect_count(
3393 &self,
3394 pass: &mut RenderPass,
3395 buffer_id: id::BufferId,
3396 offset: BufferAddress,
3397 count_buffer_id: id::BufferId,
3398 count_buffer_offset: BufferAddress,
3399 max_count: u32,
3400 ) -> Result<(), PassStateError> {
3401 let scope = PassErrorScope::Draw {
3402 kind: DrawKind::MultiDrawIndirectCount,
3403 indexed: false,
3404 };
3405 let base = pass_base!(pass, scope);
3406
3407 base.commands
3408 .push(ArcRenderCommand::MultiDrawIndirectCount {
3409 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3410 offset,
3411 count_buffer: pass_try!(
3412 base,
3413 scope,
3414 self.resolve_render_pass_buffer_id(count_buffer_id)
3415 ),
3416 count_buffer_offset,
3417 max_count,
3418 indexed: false,
3419 });
3420
3421 Ok(())
3422 }
3423
3424 pub fn render_pass_multi_draw_indexed_indirect_count(
3425 &self,
3426 pass: &mut RenderPass,
3427 buffer_id: id::BufferId,
3428 offset: BufferAddress,
3429 count_buffer_id: id::BufferId,
3430 count_buffer_offset: BufferAddress,
3431 max_count: u32,
3432 ) -> Result<(), PassStateError> {
3433 let scope = PassErrorScope::Draw {
3434 kind: DrawKind::MultiDrawIndirectCount,
3435 indexed: true,
3436 };
3437 let base = pass_base!(pass, scope);
3438
3439 base.commands
3440 .push(ArcRenderCommand::MultiDrawIndirectCount {
3441 buffer: pass_try!(base, scope, self.resolve_render_pass_buffer_id(buffer_id)),
3442 offset,
3443 count_buffer: pass_try!(
3444 base,
3445 scope,
3446 self.resolve_render_pass_buffer_id(count_buffer_id)
3447 ),
3448 count_buffer_offset,
3449 max_count,
3450 indexed: true,
3451 });
3452
3453 Ok(())
3454 }
3455
3456 pub fn render_pass_push_debug_group(
3457 &self,
3458 pass: &mut RenderPass,
3459 label: &str,
3460 color: u32,
3461 ) -> Result<(), PassStateError> {
3462 let base = pass_base!(pass, PassErrorScope::PushDebugGroup);
3463
3464 let bytes = label.as_bytes();
3465 base.string_data.extend_from_slice(bytes);
3466
3467 base.commands.push(ArcRenderCommand::PushDebugGroup {
3468 color,
3469 len: bytes.len(),
3470 });
3471
3472 Ok(())
3473 }
3474
3475 pub fn render_pass_pop_debug_group(&self, pass: &mut RenderPass) -> Result<(), PassStateError> {
3476 let base = pass_base!(pass, PassErrorScope::PopDebugGroup);
3477
3478 base.commands.push(ArcRenderCommand::PopDebugGroup);
3479
3480 Ok(())
3481 }
3482
3483 pub fn render_pass_insert_debug_marker(
3484 &self,
3485 pass: &mut RenderPass,
3486 label: &str,
3487 color: u32,
3488 ) -> Result<(), PassStateError> {
3489 let base = pass_base!(pass, PassErrorScope::InsertDebugMarker);
3490
3491 let bytes = label.as_bytes();
3492 base.string_data.extend_from_slice(bytes);
3493
3494 base.commands.push(ArcRenderCommand::InsertDebugMarker {
3495 color,
3496 len: bytes.len(),
3497 });
3498
3499 Ok(())
3500 }
3501
3502 pub fn render_pass_write_timestamp(
3503 &self,
3504 pass: &mut RenderPass,
3505 query_set_id: id::QuerySetId,
3506 query_index: u32,
3507 ) -> Result<(), PassStateError> {
3508 let scope = PassErrorScope::WriteTimestamp;
3509 let base = pass_base!(pass, scope);
3510
3511 base.commands.push(ArcRenderCommand::WriteTimestamp {
3512 query_set: pass_try!(
3513 base,
3514 scope,
3515 self.resolve_render_pass_query_set(query_set_id)
3516 ),
3517 query_index,
3518 });
3519
3520 Ok(())
3521 }
3522
3523 pub fn render_pass_begin_occlusion_query(
3524 &self,
3525 pass: &mut RenderPass,
3526 query_index: u32,
3527 ) -> Result<(), PassStateError> {
3528 let scope = PassErrorScope::BeginOcclusionQuery;
3529 let base = pass_base!(pass, scope);
3530
3531 base.commands
3532 .push(ArcRenderCommand::BeginOcclusionQuery { query_index });
3533
3534 Ok(())
3535 }
3536
3537 pub fn render_pass_end_occlusion_query(
3538 &self,
3539 pass: &mut RenderPass,
3540 ) -> Result<(), PassStateError> {
3541 let scope = PassErrorScope::EndOcclusionQuery;
3542 let base = pass_base!(pass, scope);
3543
3544 base.commands.push(ArcRenderCommand::EndOcclusionQuery);
3545
3546 Ok(())
3547 }
3548
3549 pub fn render_pass_begin_pipeline_statistics_query(
3550 &self,
3551 pass: &mut RenderPass,
3552 query_set_id: id::QuerySetId,
3553 query_index: u32,
3554 ) -> Result<(), PassStateError> {
3555 let scope = PassErrorScope::BeginPipelineStatisticsQuery;
3556 let base = pass_base!(pass, scope);
3557
3558 base.commands
3559 .push(ArcRenderCommand::BeginPipelineStatisticsQuery {
3560 query_set: pass_try!(
3561 base,
3562 scope,
3563 self.resolve_render_pass_query_set(query_set_id)
3564 ),
3565 query_index,
3566 });
3567
3568 Ok(())
3569 }
3570
3571 pub fn render_pass_end_pipeline_statistics_query(
3572 &self,
3573 pass: &mut RenderPass,
3574 ) -> Result<(), PassStateError> {
3575 let scope = PassErrorScope::EndPipelineStatisticsQuery;
3576 let base = pass_base!(pass, scope);
3577
3578 base.commands
3579 .push(ArcRenderCommand::EndPipelineStatisticsQuery);
3580
3581 Ok(())
3582 }
3583
3584 pub fn render_pass_execute_bundles(
3585 &self,
3586 pass: &mut RenderPass,
3587 render_bundle_ids: &[id::RenderBundleId],
3588 ) -> Result<(), PassStateError> {
3589 let scope = PassErrorScope::ExecuteBundle;
3590 let base = pass_base!(pass, scope);
3591
3592 let hub = &self.hub;
3593 let bundles = hub.render_bundles.read();
3594
3595 for &bundle_id in render_bundle_ids {
3596 let bundle = pass_try!(base, scope, bundles.get(bundle_id).get());
3597
3598 base.commands.push(ArcRenderCommand::ExecuteBundle(bundle));
3599 }
3600 pass.current_pipeline.reset();
3601 pass.current_bind_groups.reset();
3602
3603 Ok(())
3604 }
3605}
3606
3607pub(crate) const fn get_stride_of_indirect_args(indexed: bool) -> u64 {
3608 match indexed {
3609 false => size_of::<wgt::DrawIndirectArgs>() as u64,
3610 true => size_of::<wgt::DrawIndexedIndirectArgs>() as u64,
3611 }
3612}