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