1mod allocator;
12mod bind;
13mod bundle;
14mod clear;
15mod compute;
16mod compute_command;
17mod draw;
18mod encoder;
19mod encoder_command;
20pub mod ffi;
21mod memory_init;
22mod pass;
23mod query;
24mod ray_tracing;
25mod render;
26mod render_command;
27mod timestamp_writes;
28mod transfer;
29mod transition_resources;
30
31use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec::Vec};
32use core::convert::Infallible;
33use core::mem::{self, ManuallyDrop};
34use core::{ops, panic};
35
36#[cfg(feature = "serde")]
37pub(crate) use self::encoder_command::serde_object_reference_struct;
38#[cfg(any(feature = "trace", feature = "replay"))]
39#[doc(hidden)]
40pub use self::encoder_command::PointerReferences;
41pub use self::{
45 bundle::{
46 bundle_ffi, CreateRenderBundleError, ExecutionError, RenderBundle, RenderBundleDescriptor,
47 RenderBundleEncoder, RenderBundleEncoderDescriptor, RenderBundleError,
48 RenderBundleErrorInner,
49 },
50 clear::ClearError,
51 compute::{
52 ComputeBasePass, ComputePass, ComputePassDescriptor, ComputePassError,
53 ComputePassErrorInner, DispatchError,
54 },
55 compute_command::ArcComputeCommand,
56 draw::{DrawError, Rect, RenderCommandError},
57 encoder_command::{ArcCommand, ArcReferences, Command, IdReferences, ReferenceType},
58 query::{QueryError, QueryUseError, ResolveError, SimplifiedQueryType},
59 render::{
60 ArcRenderPassColorAttachment, AttachmentError, AttachmentErrorLocation,
61 ColorAttachmentError, ColorAttachments, LoadOp, PassChannel, RenderBasePass, RenderPass,
62 RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
63 RenderPassError, RenderPassErrorInner, ResolvedPassChannel,
64 ResolvedRenderPassDepthStencilAttachment, StoreOp,
65 },
66 render_command::ArcRenderCommand,
67 transfer::{CopySide, TransferError},
68 transition_resources::TransitionResourcesError,
69};
70pub(crate) use self::{
71 clear::clear_texture,
72 encoder::EncodingState,
73 memory_init::CommandBufferTextureMemoryActions,
74 render::{get_stride_of_indirect_args, VertexLimits},
75 transfer::{
76 extract_texture_selector, validate_linear_texture_data, validate_texture_buffer_copy,
77 validate_texture_copy_dst_format, validate_texture_copy_range,
78 },
79};
80
81pub(crate) use allocator::CommandAllocator;
82
83pub use self::{compute_command::ComputeCommand, render_command::RenderCommand};
85
86pub(crate) use timestamp_writes::ArcPassTimestampWrites;
87pub use timestamp_writes::PassTimestampWrites;
88
89use crate::binding_model::BindingError;
90use crate::device::queue::TempResource;
91use crate::device::{Device, DeviceError, MissingFeatures};
92use crate::id::Id;
93use crate::lock::{rank, Mutex};
94use crate::snatch::SnatchGuard;
95
96use crate::init_tracker::BufferInitTrackerAction;
97use crate::ray_tracing::{AsAction, BuildAccelerationStructureError};
98use crate::resource::{
99 DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice as _, QuerySet,
100};
101use crate::storage::Storage;
102use crate::track::{DeviceTracker, ResourceUsageCompatibilityError, Tracker, UsageScope};
103use crate::{api_log, global::Global, id, resource_log, Label};
104use crate::{hal_label, LabelHelpers};
105
106use wgt::error::{ErrorType, WebGpuError};
107
108use thiserror::Error;
109
110pub type TexelCopyBufferInfo = ffi::TexelCopyBufferInfo;
112pub type TexelCopyTextureInfo = ffi::TexelCopyTextureInfo;
114pub type CopyExternalImageDestInfo = ffi::CopyExternalImageDestInfo;
116
117const IMMEDIATES_CLEAR_ARRAY: &[u32] = &[0_u32; 64];
118
119pub(crate) struct EncoderErrorState {
120 error: CommandEncoderError,
121
122 #[cfg(feature = "trace")]
123 trace_commands: Option<Vec<Command<PointerReferences>>>,
124}
125
126fn make_error_state<E: Into<CommandEncoderError>>(error: E) -> CommandEncoderStatus {
136 CommandEncoderStatus::Error(EncoderErrorState {
137 error: error.into(),
138
139 #[cfg(feature = "trace")]
140 trace_commands: None,
141 })
142}
143
144pub(crate) enum CommandEncoderStatus {
150 Recording(CommandBufferMutable),
162
163 Locked(CommandBufferMutable),
172
173 Consumed,
174
175 Finished(CommandBufferMutable),
186
187 Error(EncoderErrorState),
192
193 Transitioning,
196}
197
198impl CommandEncoderStatus {
199 #[doc(hidden)]
200 fn replay(&mut self, commands: Vec<Command<ArcReferences>>) {
201 let Self::Recording(cmd_buf_data) = self else {
202 panic!("encoder should be in the recording state");
203 };
204 cmd_buf_data.commands.extend(commands);
205 }
206
207 fn push_with<F: FnOnce() -> Result<ArcCommand, E>, E: Clone + Into<CommandEncoderError>>(
223 &mut self,
224 f: F,
225 ) -> Result<(), EncoderStateError> {
226 match self {
227 Self::Recording(cmd_buf_data) => {
228 cmd_buf_data.encoder.api.set(EncodingApi::Wgpu);
229 match f() {
230 Ok(cmd) => cmd_buf_data.commands.push(cmd),
231 Err(err) => {
232 self.invalidate(err);
233 }
234 }
235 Ok(())
236 }
237 Self::Locked(_) => {
238 self.invalidate(EncoderStateError::Locked);
241 Ok(())
242 }
243 Self::Finished(_) => Err(self.invalidate(EncoderStateError::Ended)),
246 Self::Consumed => Err(EncoderStateError::Ended),
247 Self::Error(_) => Ok(()),
250 Self::Transitioning => unreachable!(),
251 }
252 }
253
254 fn with_buffer<
268 F: FnOnce(&mut CommandBufferMutable) -> Result<(), E>,
269 E: Clone + Into<CommandEncoderError>,
270 >(
271 &mut self,
272 api: EncodingApi,
273 f: F,
274 ) -> Result<(), EncoderStateError> {
275 match self {
276 Self::Recording(inner) => {
277 inner.encoder.api.set(api);
278 RecordingGuard { inner: self }.record(f);
279 Ok(())
280 }
281 Self::Locked(_) => {
282 self.invalidate(EncoderStateError::Locked);
285 Ok(())
286 }
287 Self::Finished(_) => Err(self.invalidate(EncoderStateError::Ended)),
290 Self::Consumed => Err(EncoderStateError::Ended),
291 Self::Error(_) => Ok(()),
294 Self::Transitioning => unreachable!(),
295 }
296 }
297
298 pub(crate) fn record_as_hal_mut<T, F: FnOnce(Option<&mut CommandBufferMutable>) -> T>(
306 &mut self,
307 f: F,
308 ) -> T {
309 match self {
310 Self::Recording(inner) => {
311 inner.encoder.api.set(EncodingApi::Raw);
312 RecordingGuard { inner: self }.record_as_hal_mut(f)
313 }
314 Self::Locked(_) => {
315 self.invalidate(EncoderStateError::Locked);
316 f(None)
317 }
318 Self::Finished(_) => {
319 self.invalidate(EncoderStateError::Ended);
320 f(None)
321 }
322 Self::Consumed => f(None),
323 Self::Error(_) => f(None),
324 Self::Transitioning => unreachable!(),
325 }
326 }
327
328 fn lock_encoder(&mut self) -> Result<(), EncoderStateError> {
334 match mem::replace(self, Self::Transitioning) {
335 Self::Recording(inner) => {
336 *self = Self::Locked(inner);
337 Ok(())
338 }
339 st @ Self::Finished(_) => {
340 *self = st;
344 Err(EncoderStateError::Ended)
345 }
346 Self::Locked(_) => Err(self.invalidate(EncoderStateError::Locked)),
347 st @ Self::Consumed => {
348 *self = st;
349 Err(EncoderStateError::Ended)
350 }
351 st @ Self::Error(_) => {
352 *self = st;
353 Err(EncoderStateError::Invalid)
354 }
355 Self::Transitioning => unreachable!(),
356 }
357 }
358
359 fn unlock_encoder(&mut self) -> Result<(), EncoderStateError> {
369 match mem::replace(self, Self::Transitioning) {
370 Self::Locked(inner) => {
371 *self = Self::Recording(inner);
372 Ok(())
373 }
374 st @ Self::Finished(_) => {
375 *self = st;
376 Err(EncoderStateError::Ended)
377 }
378 Self::Recording(_) => {
379 *self = make_error_state(EncoderStateError::Unlocked);
380 Err(EncoderStateError::Unlocked)
381 }
382 st @ Self::Consumed => {
383 *self = st;
384 Err(EncoderStateError::Ended)
385 }
386 st @ Self::Error(_) => {
387 *self = st;
390 Ok(())
391 }
392 Self::Transitioning => unreachable!(),
393 }
394 }
395
396 fn finish(&mut self) -> Self {
397 match mem::replace(self, Self::Consumed) {
400 Self::Recording(inner) => {
401 if inner.encoder.api != EncodingApi::Raw {
404 assert!(!inner.encoder.is_open);
405 }
406 Self::Finished(inner)
407 }
408 Self::Consumed | Self::Finished(_) => make_error_state(EncoderStateError::Ended),
409 Self::Locked(_) => make_error_state(EncoderStateError::Locked),
410 st @ Self::Error(_) => st,
411 Self::Transitioning => unreachable!(),
412 }
413 }
414
415 fn invalidate<E: Clone + Into<CommandEncoderError>>(&mut self, err: E) -> E {
423 #[cfg(feature = "trace")]
424 let trace_commands = match self {
425 Self::Recording(cmd_buf_data) => Some(
426 mem::take(&mut cmd_buf_data.commands)
427 .into_iter()
428 .map(crate::device::trace::IntoTrace::into_trace)
429 .collect(),
430 ),
431 _ => None,
432 };
433
434 let enc_err = err.clone().into();
435 api_log!("Invalidating command encoder: {enc_err:?}");
436 *self = Self::Error(EncoderErrorState {
437 error: enc_err,
438 #[cfg(feature = "trace")]
439 trace_commands,
440 });
441 err
442 }
443}
444
445pub(crate) struct RecordingGuard<'a> {
458 inner: &'a mut CommandEncoderStatus,
459}
460
461impl<'a> RecordingGuard<'a> {
462 pub(crate) fn mark_successful(self) {
463 mem::forget(self)
464 }
465
466 fn record<
467 F: FnOnce(&mut CommandBufferMutable) -> Result<(), E>,
468 E: Clone + Into<CommandEncoderError>,
469 >(
470 mut self,
471 f: F,
472 ) {
473 match f(&mut self) {
474 Ok(()) => self.mark_successful(),
475 Err(err) => {
476 self.inner.invalidate(err);
477 }
478 }
479 }
480
481 pub(crate) fn record_as_hal_mut<T, F: FnOnce(Option<&mut CommandBufferMutable>) -> T>(
484 mut self,
485 f: F,
486 ) -> T {
487 let res = f(Some(&mut self));
488 self.mark_successful();
489 res
490 }
491}
492
493impl<'a> Drop for RecordingGuard<'a> {
494 fn drop(&mut self) {
495 if matches!(*self.inner, CommandEncoderStatus::Error(_)) {
496 return;
498 }
499 self.inner.invalidate(EncoderStateError::Invalid);
500 }
501}
502
503impl<'a> ops::Deref for RecordingGuard<'a> {
504 type Target = CommandBufferMutable;
505
506 fn deref(&self) -> &Self::Target {
507 match &*self.inner {
508 CommandEncoderStatus::Recording(command_buffer_mutable) => command_buffer_mutable,
509 _ => unreachable!(),
510 }
511 }
512}
513
514impl<'a> ops::DerefMut for RecordingGuard<'a> {
515 fn deref_mut(&mut self) -> &mut Self::Target {
516 match self.inner {
517 CommandEncoderStatus::Recording(command_buffer_mutable) => command_buffer_mutable,
518 _ => unreachable!(),
519 }
520 }
521}
522
523pub(crate) struct CommandEncoder {
524 pub(crate) device: Arc<Device>,
525
526 pub(crate) label: String,
527
528 pub(crate) data: Mutex<CommandEncoderStatus>,
530}
531
532crate::impl_resource_type!(CommandEncoder);
533crate::impl_labeled!(CommandEncoder);
534crate::impl_parent_device!(CommandEncoder);
535crate::impl_storage_item!(CommandEncoder);
536
537impl Drop for CommandEncoder {
538 fn drop(&mut self) {
539 resource_log!("Drop {}", self.error_ident());
540 }
541}
542
543#[derive(Copy, Clone, Debug, Eq, PartialEq)]
547pub enum EncodingApi {
548 Wgpu,
550
551 Raw,
553
554 Undecided,
556
557 InternalUse,
559}
560
561impl EncodingApi {
562 pub(crate) fn set(&mut self, api: EncodingApi) {
563 match *self {
564 EncodingApi::Undecided => {
565 *self = api;
566 }
567 self_api if self_api != api => {
568 panic!("Mixing the wgpu encoding API with the raw encoding API is not permitted");
569 }
570 _ => {}
571 }
572 }
573}
574
575pub(crate) struct InnerCommandEncoder {
591 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynCommandEncoder>>,
599
600 pub(crate) list: Vec<Box<dyn hal::DynCommandBuffer>>,
612
613 pub(crate) device: Arc<Device>,
614
615 pub(crate) is_open: bool,
622
623 pub(crate) api: EncodingApi,
629
630 pub(crate) label: String,
631}
632
633impl InnerCommandEncoder {
634 fn close_and_swap(&mut self) -> Result<(), DeviceError> {
660 assert!(self.is_open);
661 self.is_open = false;
662
663 let new =
664 unsafe { self.raw.end_encoding() }.map_err(|e| self.device.handle_hal_error(e))?;
665 self.list.insert(self.list.len() - 1, new);
666
667 Ok(())
668 }
669
670 pub(crate) fn close_and_push_front(&mut self) -> Result<(), DeviceError> {
681 assert!(self.is_open);
682 self.is_open = false;
683
684 let new =
685 unsafe { self.raw.end_encoding() }.map_err(|e| self.device.handle_hal_error(e))?;
686 self.list.insert(0, new);
687
688 Ok(())
689 }
690
691 pub(crate) fn close(&mut self) -> Result<(), DeviceError> {
702 assert!(self.is_open);
703 self.is_open = false;
704
705 let cmd_buf =
706 unsafe { self.raw.end_encoding() }.map_err(|e| self.device.handle_hal_error(e))?;
707 self.list.push(cmd_buf);
708
709 Ok(())
710 }
711
712 fn close_if_open(&mut self) -> Result<(), DeviceError> {
723 if self.is_open {
724 self.is_open = false;
725 let cmd_buf =
726 unsafe { self.raw.end_encoding() }.map_err(|e| self.device.handle_hal_error(e))?;
727 self.list.push(cmd_buf);
728 }
729
730 Ok(())
731 }
732
733 fn open_if_closed(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> {
739 if !self.is_open {
740 let hal_label = hal_label(Some(self.label.as_str()), self.device.instance_flags);
741 unsafe { self.raw.begin_encoding(hal_label) }
742 .map_err(|e| self.device.handle_hal_error(e))?;
743 self.is_open = true;
744 }
745
746 Ok(self.raw.as_mut())
747 }
748
749 pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> {
753 if !self.is_open {
754 let hal_label = hal_label(Some(self.label.as_str()), self.device.instance_flags);
755 unsafe { self.raw.begin_encoding(hal_label) }
756 .map_err(|e| self.device.handle_hal_error(e))?;
757 self.is_open = true;
758 }
759
760 Ok(self.raw.as_mut())
761 }
762
763 pub(crate) fn open_pass(
772 &mut self,
773 label: Option<&str>,
774 ) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> {
775 assert!(!self.is_open);
776
777 let hal_label = hal_label(label, self.device.instance_flags);
778 unsafe { self.raw.begin_encoding(hal_label) }
779 .map_err(|e| self.device.handle_hal_error(e))?;
780 self.is_open = true;
781
782 Ok(self.raw.as_mut())
783 }
784}
785
786impl Drop for InnerCommandEncoder {
787 fn drop(&mut self) {
788 if self.is_open {
789 unsafe { self.raw.discard_encoding() };
790 }
791 unsafe {
792 self.raw.reset_all(mem::take(&mut self.list));
793 }
794 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
796 self.device.command_allocator.release_encoder(raw);
797 }
798}
799
800pub(crate) struct BakedCommands {
803 pub(crate) encoder: InnerCommandEncoder,
804 pub(crate) trackers: Tracker,
805 pub(crate) temp_resources: Vec<TempResource>,
806 pub(crate) indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
807 buffer_memory_init_actions: Vec<BufferInitTrackerAction>,
808 texture_memory_actions: CommandBufferTextureMemoryActions,
809}
810
811pub struct CommandBufferMutable {
813 pub(crate) encoder: InnerCommandEncoder,
818
819 pub(crate) trackers: Tracker,
821
822 buffer_memory_init_actions: Vec<BufferInitTrackerAction>,
829 texture_memory_actions: CommandBufferTextureMemoryActions,
830
831 as_actions: Vec<AsAction>,
832 temp_resources: Vec<TempResource>,
833
834 indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
835
836 pub(crate) commands: Vec<Command<ArcReferences>>,
837
838 #[cfg(feature = "trace")]
841 pub(crate) trace_commands: Option<Vec<Command<PointerReferences>>>,
842}
843
844impl CommandBufferMutable {
845 pub(crate) fn into_baked_commands(self) -> BakedCommands {
846 BakedCommands {
847 encoder: self.encoder,
848 trackers: self.trackers,
849 temp_resources: self.temp_resources,
850 indirect_draw_validation_resources: self.indirect_draw_validation_resources,
851 buffer_memory_init_actions: self.buffer_memory_init_actions,
852 texture_memory_actions: self.texture_memory_actions,
853 }
854 }
855}
856
857pub struct CommandBuffer {
863 pub(crate) device: Arc<Device>,
864 label: String,
866
867 pub(crate) data: Mutex<CommandEncoderStatus>,
869}
870
871impl Drop for CommandBuffer {
872 fn drop(&mut self) {
873 resource_log!("Drop {}", self.error_ident());
874 }
875}
876
877impl CommandEncoder {
878 pub(crate) fn new(
879 encoder: Box<dyn hal::DynCommandEncoder>,
880 device: &Arc<Device>,
881 label: &Label,
882 ) -> Self {
883 CommandEncoder {
884 device: device.clone(),
885 label: label.to_string(),
886 data: Mutex::new(
887 rank::COMMAND_BUFFER_DATA,
888 CommandEncoderStatus::Recording(CommandBufferMutable {
889 encoder: InnerCommandEncoder {
890 raw: ManuallyDrop::new(encoder),
891 list: Vec::new(),
892 device: device.clone(),
893 is_open: false,
894 api: EncodingApi::Undecided,
895 label: label.to_string(),
896 },
897 trackers: Tracker::new(),
898 buffer_memory_init_actions: Default::default(),
899 texture_memory_actions: Default::default(),
900 as_actions: Default::default(),
901 temp_resources: Default::default(),
902 indirect_draw_validation_resources:
903 crate::indirect_validation::DrawResources::new(device.clone()),
904 commands: Vec::new(),
905 #[cfg(feature = "trace")]
906 trace_commands: if device.trace.lock().is_some() {
907 Some(Vec::new())
908 } else {
909 None
910 },
911 }),
912 ),
913 }
914 }
915
916 pub(crate) fn new_invalid(
917 device: &Arc<Device>,
918 label: &Label,
919 err: CommandEncoderError,
920 ) -> Self {
921 CommandEncoder {
922 device: device.clone(),
923 label: label.to_string(),
924 data: Mutex::new(rank::COMMAND_BUFFER_DATA, make_error_state(err)),
925 }
926 }
927
928 pub(crate) fn insert_barriers_from_tracker(
929 raw: &mut dyn hal::DynCommandEncoder,
930 base: &mut Tracker,
931 head: &Tracker,
932 snatch_guard: &SnatchGuard,
933 ) {
934 profiling::scope!("insert_barriers");
935
936 base.buffers.set_from_tracker(&head.buffers);
937 base.textures.set_from_tracker(&head.textures);
938
939 Self::drain_barriers(raw, base, snatch_guard);
940 }
941
942 pub(crate) fn insert_barriers_from_scope(
943 raw: &mut dyn hal::DynCommandEncoder,
944 base: &mut Tracker,
945 head: &UsageScope,
946 snatch_guard: &SnatchGuard,
947 ) {
948 profiling::scope!("insert_barriers");
949
950 base.buffers.set_from_usage_scope(&head.buffers);
951 base.textures.set_from_usage_scope(&head.textures);
952
953 Self::drain_barriers(raw, base, snatch_guard);
954 }
955
956 pub(crate) fn drain_barriers(
957 raw: &mut dyn hal::DynCommandEncoder,
958 base: &mut Tracker,
959 snatch_guard: &SnatchGuard,
960 ) {
961 profiling::scope!("drain_barriers");
962
963 let buffer_barriers = base
964 .buffers
965 .drain_transitions(snatch_guard)
966 .collect::<Vec<_>>();
967 let (transitions, textures) = base.textures.drain_transitions(snatch_guard);
968 let texture_barriers = transitions
969 .into_iter()
970 .enumerate()
971 .map(|(i, p)| p.into_hal(textures[i].unwrap().raw()))
972 .collect::<Vec<_>>();
973
974 unsafe {
975 raw.transition_buffers(&buffer_barriers);
976 raw.transition_textures(&texture_barriers);
977 }
978 }
979
980 pub(crate) fn insert_barriers_from_device_tracker(
981 raw: &mut dyn hal::DynCommandEncoder,
982 base: &mut DeviceTracker,
983 head: &Tracker,
984 snatch_guard: &SnatchGuard,
985 ) {
986 profiling::scope!("insert_barriers_from_device_tracker");
987
988 let buffer_barriers = base
989 .buffers
990 .set_from_tracker_and_drain_transitions(&head.buffers, snatch_guard)
991 .collect::<Vec<_>>();
992
993 let texture_barriers = base
994 .textures
995 .set_from_tracker_and_drain_transitions(&head.textures, snatch_guard)
996 .collect::<Vec<_>>();
997
998 unsafe {
999 raw.transition_buffers(&buffer_barriers);
1000 raw.transition_textures(&texture_barriers);
1001 }
1002 }
1003
1004 fn encode_commands(
1005 device: &Arc<Device>,
1006 cmd_buf_data: &mut CommandBufferMutable,
1007 ) -> Result<(), CommandEncoderError> {
1008 device.check_is_valid()?;
1009 let snatch_guard = device.snatchable_lock.read();
1010 let mut debug_scope_depth = 0;
1011
1012 if cmd_buf_data.encoder.api == EncodingApi::Raw {
1013 assert!(cmd_buf_data.commands.is_empty());
1016 }
1017
1018 let commands = mem::take(&mut cmd_buf_data.commands);
1019
1020 #[cfg(feature = "trace")]
1021 if device.trace.lock().is_some() {
1022 cmd_buf_data.trace_commands = Some(
1023 commands
1024 .iter()
1025 .map(crate::device::trace::IntoTrace::to_trace)
1026 .collect(),
1027 );
1028 }
1029
1030 for command in commands {
1031 if matches!(
1032 command,
1033 ArcCommand::RunRenderPass { .. } | ArcCommand::RunComputePass { .. }
1034 ) {
1035 let mut state = EncodingState {
1040 device,
1041 raw_encoder: &mut cmd_buf_data.encoder,
1042 tracker: &mut cmd_buf_data.trackers,
1043 buffer_memory_init_actions: &mut cmd_buf_data.buffer_memory_init_actions,
1044 texture_memory_actions: &mut cmd_buf_data.texture_memory_actions,
1045 as_actions: &mut cmd_buf_data.as_actions,
1046 temp_resources: &mut cmd_buf_data.temp_resources,
1047 indirect_draw_validation_resources: &mut cmd_buf_data
1048 .indirect_draw_validation_resources,
1049 snatch_guard: &snatch_guard,
1050 debug_scope_depth: &mut debug_scope_depth,
1051 };
1052
1053 match command {
1054 ArcCommand::RunRenderPass {
1055 pass,
1056 color_attachments,
1057 depth_stencil_attachment,
1058 timestamp_writes,
1059 occlusion_query_set,
1060 multiview_mask,
1061 } => {
1062 api_log!(
1063 "Begin encoding render pass with '{}' label",
1064 pass.label.as_deref().unwrap_or("")
1065 );
1066 let res = render::encode_render_pass(
1067 &mut state,
1068 pass,
1069 color_attachments,
1070 depth_stencil_attachment,
1071 timestamp_writes,
1072 occlusion_query_set,
1073 multiview_mask,
1074 );
1075 match res.as_ref() {
1076 Err(err) => {
1077 api_log!("Finished encoding render pass ({err:?})")
1078 }
1079 Ok(_) => {
1080 api_log!("Finished encoding render pass (success)")
1081 }
1082 }
1083 res?;
1084 }
1085 ArcCommand::RunComputePass {
1086 pass,
1087 timestamp_writes,
1088 } => {
1089 api_log!(
1090 "Begin encoding compute pass with '{}' label",
1091 pass.label.as_deref().unwrap_or("")
1092 );
1093 let res = compute::encode_compute_pass(&mut state, pass, timestamp_writes);
1094 match res.as_ref() {
1095 Err(err) => {
1096 api_log!("Finished encoding compute pass ({err:?})")
1097 }
1098 Ok(_) => {
1099 api_log!("Finished encoding compute pass (success)")
1100 }
1101 }
1102 res?;
1103 }
1104 _ => unreachable!(),
1105 }
1106 } else {
1107 let raw_encoder = cmd_buf_data.encoder.open_if_closed()?;
1113 let mut state = EncodingState {
1114 device,
1115 raw_encoder,
1116 tracker: &mut cmd_buf_data.trackers,
1117 buffer_memory_init_actions: &mut cmd_buf_data.buffer_memory_init_actions,
1118 texture_memory_actions: &mut cmd_buf_data.texture_memory_actions,
1119 as_actions: &mut cmd_buf_data.as_actions,
1120 temp_resources: &mut cmd_buf_data.temp_resources,
1121 indirect_draw_validation_resources: &mut cmd_buf_data
1122 .indirect_draw_validation_resources,
1123 snatch_guard: &snatch_guard,
1124 debug_scope_depth: &mut debug_scope_depth,
1125 };
1126 match command {
1127 ArcCommand::CopyBufferToBuffer {
1128 src,
1129 src_offset,
1130 dst,
1131 dst_offset,
1132 size,
1133 } => {
1134 transfer::copy_buffer_to_buffer(
1135 &mut state, &src, src_offset, &dst, dst_offset, size,
1136 )?;
1137 }
1138 ArcCommand::CopyBufferToTexture { src, dst, size } => {
1139 transfer::copy_buffer_to_texture(&mut state, &src, &dst, &size)?;
1140 }
1141 ArcCommand::CopyTextureToBuffer { src, dst, size } => {
1142 transfer::copy_texture_to_buffer(&mut state, &src, &dst, &size)?;
1143 }
1144 ArcCommand::CopyTextureToTexture { src, dst, size } => {
1145 transfer::copy_texture_to_texture(&mut state, &src, &dst, &size)?;
1146 }
1147 ArcCommand::ClearBuffer { dst, offset, size } => {
1148 clear::clear_buffer(&mut state, dst, offset, size)?;
1149 }
1150 ArcCommand::ClearTexture {
1151 dst,
1152 subresource_range,
1153 } => {
1154 clear::clear_texture_cmd(&mut state, dst, &subresource_range)?;
1155 }
1156 ArcCommand::WriteTimestamp {
1157 query_set,
1158 query_index,
1159 } => {
1160 query::write_timestamp(&mut state, query_set, query_index)?;
1161 }
1162 ArcCommand::ResolveQuerySet {
1163 query_set,
1164 start_query,
1165 query_count,
1166 destination,
1167 destination_offset,
1168 } => {
1169 query::resolve_query_set(
1170 &mut state,
1171 query_set,
1172 start_query,
1173 query_count,
1174 destination,
1175 destination_offset,
1176 )?;
1177 }
1178 ArcCommand::PushDebugGroup(label) => {
1179 push_debug_group(&mut state, &label)?;
1180 }
1181 ArcCommand::PopDebugGroup => {
1182 pop_debug_group(&mut state)?;
1183 }
1184 ArcCommand::InsertDebugMarker(label) => {
1185 insert_debug_marker(&mut state, &label)?;
1186 }
1187 ArcCommand::BuildAccelerationStructures { blas, tlas } => {
1188 ray_tracing::build_acceleration_structures(&mut state, blas, tlas)?;
1189 }
1190 ArcCommand::TransitionResources {
1191 buffer_transitions,
1192 texture_transitions,
1193 } => {
1194 transition_resources::transition_resources(
1195 &mut state,
1196 buffer_transitions,
1197 texture_transitions,
1198 )?;
1199 }
1200 ArcCommand::RunComputePass { .. } | ArcCommand::RunRenderPass { .. } => {
1201 unreachable!()
1202 }
1203 }
1204 }
1205 }
1206
1207 if debug_scope_depth > 0 {
1208 Err(CommandEncoderError::DebugGroupError(
1209 DebugGroupError::MissingPop,
1210 ))?;
1211 }
1212
1213 cmd_buf_data.encoder.close_if_open()?;
1215
1216 Ok(())
1220 }
1221
1222 fn finish(
1223 self: &Arc<Self>,
1224 desc: &wgt::CommandBufferDescriptor<Label>,
1225 ) -> (Arc<CommandBuffer>, Option<CommandEncoderError>) {
1226 let mut cmd_enc_status = self.data.lock();
1227
1228 let res = match cmd_enc_status.finish() {
1229 CommandEncoderStatus::Finished(mut cmd_buf_data) => {
1230 match Self::encode_commands(&self.device, &mut cmd_buf_data) {
1231 Ok(()) => Ok(cmd_buf_data),
1232 Err(error) => Err(EncoderErrorState {
1233 error,
1234 #[cfg(feature = "trace")]
1235 trace_commands: mem::take(&mut cmd_buf_data.trace_commands),
1236 }),
1237 }
1238 }
1239 CommandEncoderStatus::Error(error_state) => Err(error_state),
1240 _ => unreachable!(),
1241 };
1242
1243 let (data, error) = match res {
1244 Err(EncoderErrorState {
1245 error,
1246 #[cfg(feature = "trace")]
1247 trace_commands,
1248 }) => {
1249 #[cfg(feature = "trace")]
1253 if let Some(trace) = self.device.trace.lock().as_mut() {
1254 use alloc::string::ToString;
1255
1256 trace.add(crate::device::trace::Action::FailedCommands {
1257 commands: trace_commands,
1258 failed_at_submit: None,
1259 error: error.to_string(),
1260 });
1261 }
1262
1263 if error.is_destroyed_error() {
1264 (make_error_state(error), None)
1267 } else {
1268 (make_error_state(error.clone()), Some(error))
1269 }
1270 }
1271
1272 Ok(data) => (CommandEncoderStatus::Finished(data), None),
1273 };
1274
1275 let cmd_buf = Arc::new(CommandBuffer {
1276 device: self.device.clone(),
1277 label: desc.label.to_string(),
1278 data: Mutex::new(rank::COMMAND_BUFFER_DATA, data),
1279 });
1280
1281 (cmd_buf, error)
1282 }
1283}
1284
1285impl CommandBuffer {
1286 #[doc(hidden)]
1292 pub fn from_trace(device: &Arc<Device>, commands: Vec<Command<ArcReferences>>) -> Arc<Self> {
1293 let encoder = device.create_command_encoder(&None).unwrap();
1294 let mut cmd_enc_status = encoder.data.lock();
1295 cmd_enc_status.replay(commands);
1296 drop(cmd_enc_status);
1297
1298 let (cmd_buf, error) = encoder.finish(&wgt::CommandBufferDescriptor { label: None });
1299 if let Some(err) = error {
1300 panic!("CommandEncoder::finish failed: {err}");
1301 }
1302
1303 cmd_buf
1304 }
1305
1306 pub fn take_finished(&self) -> Result<CommandBufferMutable, CommandEncoderError> {
1307 use CommandEncoderStatus as St;
1308 match mem::replace(
1309 &mut *self.data.lock(),
1310 make_error_state(EncoderStateError::Submitted),
1311 ) {
1312 St::Finished(command_buffer_mutable) => Ok(command_buffer_mutable),
1313 St::Error(EncoderErrorState {
1314 #[cfg(feature = "trace")]
1315 trace_commands: _,
1316 error,
1317 }) => Err(error),
1318 St::Recording(_) | St::Locked(_) | St::Consumed | St::Transitioning => unreachable!(),
1319 }
1320 }
1321}
1322
1323crate::impl_resource_type!(CommandBuffer);
1324crate::impl_labeled!(CommandBuffer);
1325crate::impl_parent_device!(CommandBuffer);
1326crate::impl_storage_item!(CommandBuffer);
1327
1328#[doc(hidden)]
1340#[derive(Debug, Clone)]
1341#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1342pub struct BasePass<C, E> {
1343 pub label: Option<String>,
1344
1345 #[cfg_attr(feature = "serde", serde(skip, default = "Option::default"))]
1353 pub error: Option<E>,
1354
1355 pub commands: Vec<C>,
1361
1362 pub dynamic_offsets: Vec<wgt::DynamicOffset>,
1367
1368 pub string_data: Vec<u8>,
1373
1374 pub immediates_data: Vec<u32>,
1379}
1380
1381impl<C: Clone, E: Clone> BasePass<C, E> {
1382 fn new(label: &Label) -> Self {
1383 Self {
1384 label: label.as_deref().map(str::to_owned),
1385 error: None,
1386 commands: Vec::new(),
1387 dynamic_offsets: Vec::new(),
1388 string_data: Vec::new(),
1389 immediates_data: Vec::new(),
1390 }
1391 }
1392
1393 fn new_invalid(label: &Label, err: E) -> Self {
1394 Self {
1395 label: label.as_deref().map(str::to_owned),
1396 error: Some(err),
1397 commands: Vec::new(),
1398 dynamic_offsets: Vec::new(),
1399 string_data: Vec::new(),
1400 immediates_data: Vec::new(),
1401 }
1402 }
1403
1404 fn take(&mut self) -> Result<BasePass<C, Infallible>, E> {
1411 match self.error.as_ref() {
1412 Some(err) => Err(err.clone()),
1413 None => Ok(BasePass {
1414 label: self.label.clone(),
1415 error: None,
1416 commands: mem::take(&mut self.commands),
1417 dynamic_offsets: mem::take(&mut self.dynamic_offsets),
1418 string_data: mem::take(&mut self.string_data),
1419 immediates_data: mem::take(&mut self.immediates_data),
1420 }),
1421 }
1422 }
1423}
1424
1425macro_rules! pass_base {
1448 ($pass:expr, $scope:expr $(,)?) => {
1449 match (&$pass.parent, &$pass.base.error) {
1450 (&None, _) => return Err(EncoderStateError::Ended).map_pass_err($scope),
1452 (&Some(_), &Some(_)) => return Ok(()),
1454 (&Some(_), &None) => &mut $pass.base,
1456 }
1457 };
1458}
1459pub(crate) use pass_base;
1460
1461macro_rules! pass_try {
1473 ($base:expr, $scope:expr, $res:expr $(,)?) => {
1474 match $res.map_pass_err($scope) {
1475 Ok(val) => val,
1476 Err(err) => {
1477 $base.error.get_or_insert(err);
1478 return Ok(());
1479 }
1480 }
1481 };
1482}
1483pub(crate) use pass_try;
1484
1485#[derive(Clone, Debug, Error)]
1490#[non_exhaustive]
1491pub enum EncoderStateError {
1492 #[error("Encoder is invalid")]
1497 Invalid,
1498
1499 #[error("Encoding must not have ended")]
1502 Ended,
1503
1504 #[error("Encoder is locked by a previously created render/compute pass. Before recording any new commands, the pass must be ended.")]
1510 Locked,
1511
1512 #[error(
1515 "Encoder is not currently locked. A pass can only be ended while the encoder is locked."
1516 )]
1517 Unlocked,
1518
1519 #[error("This command buffer has already been submitted.")]
1524 Submitted,
1525}
1526
1527impl WebGpuError for EncoderStateError {
1528 fn webgpu_error_type(&self) -> ErrorType {
1529 match self {
1530 EncoderStateError::Invalid
1531 | EncoderStateError::Ended
1532 | EncoderStateError::Locked
1533 | EncoderStateError::Unlocked
1534 | EncoderStateError::Submitted => ErrorType::Validation,
1535 }
1536 }
1537}
1538
1539#[derive(Clone, Debug, Error)]
1540#[non_exhaustive]
1541pub enum CommandEncoderError {
1542 #[error(transparent)]
1543 State(#[from] EncoderStateError),
1544 #[error(transparent)]
1545 Device(#[from] DeviceError),
1546 #[error(transparent)]
1547 InvalidResource(#[from] InvalidResourceError),
1548 #[error(transparent)]
1549 DestroyedResource(#[from] DestroyedResourceError),
1550 #[error(transparent)]
1551 ResourceUsage(#[from] ResourceUsageCompatibilityError),
1552 #[error(transparent)]
1553 DebugGroupError(#[from] DebugGroupError),
1554 #[error(transparent)]
1555 MissingFeatures(#[from] MissingFeatures),
1556 #[error(transparent)]
1557 Transfer(#[from] TransferError),
1558 #[error(transparent)]
1559 Clear(#[from] ClearError),
1560 #[error(transparent)]
1561 Query(#[from] QueryError),
1562 #[error(transparent)]
1563 BuildAccelerationStructure(#[from] BuildAccelerationStructureError),
1564 #[error(transparent)]
1565 TransitionResources(#[from] TransitionResourcesError),
1566 #[error(transparent)]
1567 ComputePass(#[from] ComputePassError),
1568 #[error(transparent)]
1569 RenderPass(#[from] RenderPassError),
1570}
1571
1572impl CommandEncoderError {
1573 fn is_destroyed_error(&self) -> bool {
1574 matches!(
1575 self,
1576 Self::DestroyedResource(_)
1577 | Self::Clear(ClearError::DestroyedResource(_))
1578 | Self::Query(QueryError::DestroyedResource(_))
1579 | Self::ComputePass(ComputePassError {
1580 inner: ComputePassErrorInner::DestroyedResource(_),
1581 ..
1582 })
1583 | Self::RenderPass(RenderPassError {
1584 inner: RenderPassErrorInner::DestroyedResource(_),
1585 ..
1586 })
1587 | Self::RenderPass(RenderPassError {
1588 inner: RenderPassErrorInner::RenderCommand(
1589 RenderCommandError::DestroyedResource(_)
1590 ),
1591 ..
1592 })
1593 | Self::RenderPass(RenderPassError {
1594 inner: RenderPassErrorInner::RenderCommand(RenderCommandError::BindingError(
1595 BindingError::DestroyedResource(_)
1596 )),
1597 ..
1598 })
1599 )
1600 }
1601}
1602
1603impl WebGpuError for CommandEncoderError {
1604 fn webgpu_error_type(&self) -> ErrorType {
1605 let e: &dyn WebGpuError = match self {
1606 Self::Device(e) => e,
1607 Self::InvalidResource(e) => e,
1608 Self::DebugGroupError(e) => e,
1609 Self::MissingFeatures(e) => e,
1610 Self::State(e) => e,
1611 Self::DestroyedResource(e) => e,
1612 Self::Transfer(e) => e,
1613 Self::Clear(e) => e,
1614 Self::Query(e) => e,
1615 Self::BuildAccelerationStructure(e) => e,
1616 Self::TransitionResources(e) => e,
1617 Self::ResourceUsage(e) => e,
1618 Self::ComputePass(e) => e,
1619 Self::RenderPass(e) => e,
1620 };
1621 e.webgpu_error_type()
1622 }
1623}
1624
1625#[derive(Clone, Debug, Error)]
1626#[non_exhaustive]
1627pub enum DebugGroupError {
1628 #[error("Cannot pop debug group, because number of pushed debug groups is zero")]
1629 InvalidPop,
1630 #[error("A debug group was not popped before the encoder was finished")]
1631 MissingPop,
1632}
1633
1634impl WebGpuError for DebugGroupError {
1635 fn webgpu_error_type(&self) -> ErrorType {
1636 match self {
1637 Self::InvalidPop | Self::MissingPop => ErrorType::Validation,
1638 }
1639 }
1640}
1641
1642#[derive(Clone, Debug, Error)]
1643#[non_exhaustive]
1644pub enum TimestampWritesError {
1645 #[error(
1646 "begin and end indices of pass timestamp writes are both set to {idx}, which is not allowed"
1647 )]
1648 IndicesEqual { idx: u32 },
1649 #[error("no begin or end indices were specified for pass timestamp writes, expected at least one to be set")]
1650 IndicesMissing,
1651}
1652
1653impl WebGpuError for TimestampWritesError {
1654 fn webgpu_error_type(&self) -> ErrorType {
1655 match self {
1656 Self::IndicesEqual { .. } | Self::IndicesMissing => ErrorType::Validation,
1657 }
1658 }
1659}
1660
1661impl Global {
1662 fn resolve_buffer_id(
1663 &self,
1664 buffer_id: Id<id::markers::Buffer>,
1665 ) -> Result<Arc<crate::resource::Buffer>, InvalidResourceError> {
1666 self.hub.buffers.get(buffer_id).get()
1667 }
1668
1669 fn resolve_texture_id(
1670 &self,
1671 texture_id: Id<id::markers::Texture>,
1672 ) -> Result<Arc<crate::resource::Texture>, InvalidResourceError> {
1673 self.hub.textures.get(texture_id).get()
1674 }
1675
1676 fn resolve_query_set(
1677 &self,
1678 query_set_id: Id<id::markers::QuerySet>,
1679 ) -> Result<Arc<QuerySet>, InvalidResourceError> {
1680 self.hub.query_sets.get(query_set_id).get()
1681 }
1682
1683 pub fn command_encoder_finish(
1691 &self,
1692 encoder_id: id::CommandEncoderId,
1693 desc: &wgt::CommandBufferDescriptor<Label>,
1694 id_in: Option<id::CommandBufferId>,
1695 ) -> (id::CommandBufferId, Option<(String, CommandEncoderError)>) {
1696 profiling::scope!("CommandEncoder::finish");
1697
1698 let hub = &self.hub;
1699 let cmd_enc = hub.command_encoders.get(encoder_id);
1700
1701 let (cmd_buf, opt_error) = cmd_enc.finish(desc);
1702 let cmd_buf_id = hub.command_buffers.prepare(id_in).assign(cmd_buf);
1703
1704 (
1705 cmd_buf_id,
1706 opt_error.map(|error| (cmd_enc.label.clone(), error)),
1707 )
1708 }
1709
1710 pub fn command_encoder_push_debug_group(
1711 &self,
1712 encoder_id: id::CommandEncoderId,
1713 label: &str,
1714 ) -> Result<(), EncoderStateError> {
1715 profiling::scope!("CommandEncoder::push_debug_group");
1716 api_log!("CommandEncoder::push_debug_group {label}");
1717
1718 let hub = &self.hub;
1719
1720 let cmd_enc = hub.command_encoders.get(encoder_id);
1721 let mut cmd_buf_data = cmd_enc.data.lock();
1722
1723 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
1724 Ok(ArcCommand::PushDebugGroup(label.to_owned()))
1725 })
1726 }
1727
1728 pub fn command_encoder_insert_debug_marker(
1729 &self,
1730 encoder_id: id::CommandEncoderId,
1731 label: &str,
1732 ) -> Result<(), EncoderStateError> {
1733 profiling::scope!("CommandEncoder::insert_debug_marker");
1734 api_log!("CommandEncoder::insert_debug_marker {label}");
1735
1736 let hub = &self.hub;
1737
1738 let cmd_enc = hub.command_encoders.get(encoder_id);
1739 let mut cmd_buf_data = cmd_enc.data.lock();
1740
1741 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
1742 Ok(ArcCommand::InsertDebugMarker(label.to_owned()))
1743 })
1744 }
1745
1746 pub fn command_encoder_pop_debug_group(
1747 &self,
1748 encoder_id: id::CommandEncoderId,
1749 ) -> Result<(), EncoderStateError> {
1750 profiling::scope!("CommandEncoder::pop_debug_marker");
1751 api_log!("CommandEncoder::pop_debug_group");
1752
1753 let hub = &self.hub;
1754
1755 let cmd_enc = hub.command_encoders.get(encoder_id);
1756 let mut cmd_buf_data = cmd_enc.data.lock();
1757
1758 cmd_buf_data
1759 .push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::PopDebugGroup) })
1760 }
1761
1762 fn validate_pass_timestamp_writes<E>(
1763 device: &Device,
1764 query_sets: &Storage<Fallible<QuerySet>>,
1765 timestamp_writes: &PassTimestampWrites,
1766 ) -> Result<ArcPassTimestampWrites, E>
1767 where
1768 E: From<TimestampWritesError>
1769 + From<QueryUseError>
1770 + From<DeviceError>
1771 + From<MissingFeatures>
1772 + From<InvalidResourceError>,
1773 {
1774 let &PassTimestampWrites {
1775 query_set,
1776 beginning_of_pass_write_index,
1777 end_of_pass_write_index,
1778 } = timestamp_writes;
1779
1780 device.require_features(wgt::Features::TIMESTAMP_QUERY)?;
1781
1782 let query_set = query_sets.get(query_set).get()?;
1783
1784 query_set.same_device(device)?;
1785
1786 for idx in [beginning_of_pass_write_index, end_of_pass_write_index]
1787 .into_iter()
1788 .flatten()
1789 {
1790 query_set.validate_query(SimplifiedQueryType::Timestamp, idx, None)?;
1791 }
1792
1793 if let Some((begin, end)) = beginning_of_pass_write_index.zip(end_of_pass_write_index) {
1794 if begin == end {
1795 return Err(TimestampWritesError::IndicesEqual { idx: begin }.into());
1796 }
1797 }
1798
1799 if beginning_of_pass_write_index
1800 .or(end_of_pass_write_index)
1801 .is_none()
1802 {
1803 return Err(TimestampWritesError::IndicesMissing.into());
1804 }
1805
1806 Ok(ArcPassTimestampWrites {
1807 query_set,
1808 beginning_of_pass_write_index,
1809 end_of_pass_write_index,
1810 })
1811 }
1812}
1813
1814pub(crate) fn push_debug_group(
1815 state: &mut EncodingState,
1816 label: &str,
1817) -> Result<(), CommandEncoderError> {
1818 *state.debug_scope_depth += 1;
1819
1820 if !state
1821 .device
1822 .instance_flags
1823 .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
1824 {
1825 unsafe { state.raw_encoder.begin_debug_marker(label) };
1826 }
1827
1828 Ok(())
1829}
1830
1831pub(crate) fn insert_debug_marker(
1832 state: &mut EncodingState,
1833 label: &str,
1834) -> Result<(), CommandEncoderError> {
1835 if !state
1836 .device
1837 .instance_flags
1838 .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
1839 {
1840 unsafe { state.raw_encoder.insert_debug_marker(label) };
1841 }
1842
1843 Ok(())
1844}
1845
1846pub(crate) fn pop_debug_group(state: &mut EncodingState) -> Result<(), CommandEncoderError> {
1847 if *state.debug_scope_depth == 0 {
1848 return Err(DebugGroupError::InvalidPop.into());
1849 }
1850 *state.debug_scope_depth -= 1;
1851
1852 if !state
1853 .device
1854 .instance_flags
1855 .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS)
1856 {
1857 unsafe { state.raw_encoder.end_debug_marker() };
1858 }
1859
1860 Ok(())
1861}
1862
1863fn immediates_clear<PushFn>(offset: u32, size_bytes: u32, mut push_fn: PushFn)
1864where
1865 PushFn: FnMut(u32, &[u32]),
1866{
1867 let mut count_words = 0_u32;
1868 let size_words = size_bytes / wgt::IMMEDIATE_DATA_ALIGNMENT;
1869 while count_words < size_words {
1870 let count_bytes = count_words * wgt::IMMEDIATE_DATA_ALIGNMENT;
1871 let size_to_write_words =
1872 (size_words - count_words).min(IMMEDIATES_CLEAR_ARRAY.len() as u32);
1873
1874 push_fn(
1875 offset + count_bytes,
1876 &IMMEDIATES_CLEAR_ARRAY[0..size_to_write_words as usize],
1877 );
1878
1879 count_words += size_to_write_words;
1880 }
1881}
1882
1883#[derive(Debug, Copy, Clone)]
1884struct StateChange<T> {
1885 last_state: Option<T>,
1886}
1887
1888impl<T: Copy + PartialEq> StateChange<T> {
1889 fn new() -> Self {
1890 Self { last_state: None }
1891 }
1892 fn set_and_check_redundant(&mut self, new_state: T) -> bool {
1893 let already_set = self.last_state == Some(new_state);
1894 self.last_state = Some(new_state);
1895 already_set
1896 }
1897 fn reset(&mut self) {
1898 self.last_state = None;
1899 }
1900}
1901
1902impl<T: Copy + PartialEq> Default for StateChange<T> {
1903 fn default() -> Self {
1904 Self::new()
1905 }
1906}
1907
1908#[derive(Debug)]
1909struct BindGroupStateChange {
1910 last_states: [StateChange<Option<id::BindGroupId>>; hal::MAX_BIND_GROUPS],
1911}
1912
1913impl BindGroupStateChange {
1914 fn new() -> Self {
1915 Self {
1916 last_states: [StateChange::new(); hal::MAX_BIND_GROUPS],
1917 }
1918 }
1919
1920 fn set_and_check_redundant(
1921 &mut self,
1922 bind_group_id: Option<id::BindGroupId>,
1923 index: u32,
1924 dynamic_offsets: &mut Vec<u32>,
1925 offsets: &[wgt::DynamicOffset],
1926 ) -> bool {
1927 if offsets.is_empty() {
1929 if let Some(current_bind_group) = self.last_states.get_mut(index as usize) {
1932 if current_bind_group.set_and_check_redundant(bind_group_id) {
1934 return true;
1935 }
1936 }
1937 } else {
1938 if let Some(current_bind_group) = self.last_states.get_mut(index as usize) {
1942 current_bind_group.reset();
1943 }
1944 dynamic_offsets.extend_from_slice(offsets);
1945 }
1946 false
1947 }
1948 fn reset(&mut self) {
1949 self.last_states = [StateChange::new(); hal::MAX_BIND_GROUPS];
1950 }
1951}
1952
1953impl Default for BindGroupStateChange {
1954 fn default() -> Self {
1955 Self::new()
1956 }
1957}
1958
1959trait MapPassErr<T> {
1961 fn map_pass_err(self, scope: PassErrorScope) -> T;
1962}
1963
1964impl<T, E, F> MapPassErr<Result<T, F>> for Result<T, E>
1965where
1966 E: MapPassErr<F>,
1967{
1968 fn map_pass_err(self, scope: PassErrorScope) -> Result<T, F> {
1969 self.map_err(|err| err.map_pass_err(scope))
1970 }
1971}
1972
1973impl MapPassErr<PassStateError> for EncoderStateError {
1974 fn map_pass_err(self, scope: PassErrorScope) -> PassStateError {
1975 PassStateError { scope, inner: self }
1976 }
1977}
1978
1979#[derive(Clone, Copy, Debug)]
1980pub enum DrawKind {
1981 Draw,
1982 DrawIndirect,
1983 MultiDrawIndirect,
1984 MultiDrawIndirectCount,
1985}
1986
1987#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1989#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1990pub enum DrawCommandFamily {
1991 Draw,
1992 DrawIndexed,
1993 DrawMeshTasks,
1994}
1995
1996#[derive(Clone, Copy, Debug, Error)]
2006pub enum PassErrorScope {
2007 #[error("In a bundle parameter")]
2010 Bundle,
2011 #[error("In a pass parameter")]
2012 Pass,
2013 #[error("In a set_bind_group command")]
2014 SetBindGroup,
2015 #[error("In a set_pipeline command")]
2016 SetPipelineRender,
2017 #[error("In a set_pipeline command")]
2018 SetPipelineCompute,
2019 #[error("In a set_immediates command")]
2020 SetImmediate,
2021 #[error("In a set_vertex_buffer command")]
2022 SetVertexBuffer,
2023 #[error("In a set_index_buffer command")]
2024 SetIndexBuffer,
2025 #[error("In a set_blend_constant command")]
2026 SetBlendConstant,
2027 #[error("In a set_stencil_reference command")]
2028 SetStencilReference,
2029 #[error("In a set_viewport command")]
2030 SetViewport,
2031 #[error("In a set_scissor_rect command")]
2032 SetScissorRect,
2033 #[error("In a draw command, kind: {kind:?}")]
2034 Draw {
2035 kind: DrawKind,
2036 family: DrawCommandFamily,
2037 },
2038 #[error("In a write_timestamp command")]
2039 WriteTimestamp,
2040 #[error("In a begin_occlusion_query command")]
2041 BeginOcclusionQuery,
2042 #[error("In a end_occlusion_query command")]
2043 EndOcclusionQuery,
2044 #[error("In a begin_pipeline_statistics_query command")]
2045 BeginPipelineStatisticsQuery,
2046 #[error("In a end_pipeline_statistics_query command")]
2047 EndPipelineStatisticsQuery,
2048 #[error("In a execute_bundle command")]
2049 ExecuteBundle,
2050 #[error("In a dispatch command, indirect:{indirect}")]
2051 Dispatch { indirect: bool },
2052 #[error("In a push_debug_group command")]
2053 PushDebugGroup,
2054 #[error("In a pop_debug_group command")]
2055 PopDebugGroup,
2056 #[error("In a insert_debug_marker command")]
2057 InsertDebugMarker,
2058}
2059
2060#[derive(Clone, Debug, Error)]
2062#[error("{scope}")]
2063pub struct PassStateError {
2064 pub scope: PassErrorScope,
2065 #[source]
2066 pub(super) inner: EncoderStateError,
2067}
2068
2069impl WebGpuError for PassStateError {
2070 fn webgpu_error_type(&self) -> ErrorType {
2071 let Self { scope: _, inner } = self;
2072 inner.webgpu_error_type()
2073 }
2074}