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