1use alloc::{boxed::Box, string::ToString, sync::Arc, vec, vec::Vec};
2use core::{
3 iter,
4 mem::{self, ManuallyDrop},
5 num::NonZeroU64,
6 ptr::NonNull,
7 sync::atomic::Ordering,
8};
9use smallvec::SmallVec;
10use thiserror::Error;
11use wgt::{
12 error::{ErrorType, WebGpuError},
13 AccelerationStructureFlags,
14};
15
16use super::{life::LifetimeTracker, Device};
17#[cfg(feature = "trace")]
18use crate::device::trace::{Action, IntoTrace};
19use crate::{
20 api_log,
21 command::{
22 extract_texture_selector, validate_linear_texture_data, validate_texture_buffer_copy,
23 validate_texture_copy_dst_format, validate_texture_copy_range, ClearError,
24 CommandAllocator, CommandBuffer, CommandEncoder, CommandEncoderError, CopySide,
25 TransferError,
26 },
27 device::{DeviceError, WaitIdleError},
28 get_lowest_common_denom,
29 global::Global,
30 hal_label,
31 id::{self, BlasId, QueueId},
32 init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
33 lock::{rank, Mutex, MutexGuard, RwLock, RwLockWriteGuard},
34 ray_tracing::{BlasCompactReadyPendingClosure, CompactBlasError},
35 resource::{
36 Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, DestroyedBuffer,
37 DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer,
38 InvalidResourceError, Labeled, ParentDevice, ResourceErrorIdent, StagingBuffer, Texture,
39 TextureInner, Trackable, TrackingData,
40 },
41 resource_log,
42 scratch::ScratchBuffer,
43 snatch::{SnatchGuard, Snatchable},
44 track::{self, Tracker, TrackerIndex},
45 FastHashMap, SubmissionIndex,
46};
47use crate::{device::resource::CommandIndices, resource::RawResourceAccess};
48
49pub struct Queue {
50 raw: Box<dyn hal::DynQueue>,
51 pub(crate) pending_writes: Mutex<PendingWrites>,
52 life_tracker: Mutex<LifetimeTracker>,
53 pub(crate) device: Arc<Device>,
55}
56
57impl Queue {
58 pub(crate) fn new(
59 device: Arc<Device>,
60 raw: Box<dyn hal::DynQueue>,
61 instance_flags: wgt::InstanceFlags,
62 ) -> Result<Self, DeviceError> {
63 let pending_encoder = device
64 .command_allocator
65 .acquire_encoder(device.raw(), raw.as_ref())
66 .map_err(DeviceError::from_hal);
67
68 let pending_encoder = match pending_encoder {
69 Ok(pending_encoder) => pending_encoder,
70 Err(e) => {
71 return Err(e);
72 }
73 };
74
75 let mut pending_writes = PendingWrites::new(pending_encoder, instance_flags);
76
77 let zero_buffer = device.zero_buffer.as_ref();
78 pending_writes.activate();
79 unsafe {
80 pending_writes
81 .command_encoder
82 .transition_buffers(&[hal::BufferBarrier {
83 buffer: zero_buffer,
84 usage: hal::StateTransition {
85 from: wgt::BufferUses::empty(),
86 to: wgt::BufferUses::COPY_DST,
87 },
88 }]);
89 pending_writes
90 .command_encoder
91 .clear_buffer(zero_buffer, 0..super::ZERO_BUFFER_SIZE);
92 pending_writes
93 .command_encoder
94 .transition_buffers(&[hal::BufferBarrier {
95 buffer: zero_buffer,
96 usage: hal::StateTransition {
97 from: wgt::BufferUses::COPY_DST,
98 to: wgt::BufferUses::COPY_SRC,
99 },
100 }]);
101 }
102
103 Ok(Queue {
104 raw,
105 device,
106 pending_writes: Mutex::new(rank::QUEUE_PENDING_WRITES, pending_writes),
107 life_tracker: Mutex::new(rank::QUEUE_LIFE_TRACKER, LifetimeTracker::new()),
108 })
109 }
110
111 pub(crate) fn raw(&self) -> &dyn hal::DynQueue {
112 self.raw.as_ref()
113 }
114
115 #[track_caller]
116 pub(crate) fn lock_life<'a>(&'a self) -> MutexGuard<'a, LifetimeTracker> {
117 self.life_tracker.lock()
118 }
119
120 pub(crate) fn prepare_surface_texture_for_present(
125 &self,
126 texture: &Arc<Texture>,
127 ) -> Result<(), DeviceError> {
128 let snatch_guard = self.device.snatchable_lock.read();
129 let submission = self
130 .allocate_submission(snatch_guard)
131 .map_err(|(_index, e)| e)?;
132 let device = &self.device;
133
134 let needs_clear = {
136 let status = texture.initialization_status.read();
137 status
138 .mips
139 .first()
140 .is_some_and(|mip| mip.check(0..1).is_some())
141 };
142
143 let mut pending_writes = self.pending_writes.lock();
144
145 if needs_clear {
146 let encoder = pending_writes.activate();
149 let mut trackers = device.trackers.lock();
150 crate::command::clear_texture(
151 texture,
152 TextureInitRange {
153 mip_range: 0..1,
154 layer_range: 0..1,
155 },
156 encoder,
157 &mut trackers.textures,
158 &device.alignments,
159 device.zero_buffer.as_ref(),
160 &submission.snatch_guard,
161 device.instance_flags,
162 )
163 .map_err(|e| match e {
164 ClearError::Device(e) => e,
165 _ => DeviceError::Lost,
166 })?;
167 texture.initialization_status.write().mips[0].drain(0..1);
168 }
169
170 let pending = {
176 let mut trackers = device.trackers.lock();
177 let pending: Vec<track::PendingTransition<wgt::TextureUses>> = trackers
178 .textures
179 .set_single(
180 texture,
181 texture.full_range.clone(),
182 wgt::TextureUses::PRESENT,
183 )
184 .collect();
185 pending
186 };
187
188 if pending.is_empty() {
189 debug_assert!(!needs_clear);
195 return Ok(());
196 }
197
198 {
200 let raw_texture = texture
201 .try_raw(&submission.snatch_guard)
202 .map_err(|_| DeviceError::Lost)?;
203 let barriers: Vec<hal::TextureBarrier<'_, dyn hal::DynTexture>> = pending
204 .into_iter()
205 .map(|pt| pt.into_hal(raw_texture))
206 .collect();
207
208 let encoder = pending_writes.activate();
209 unsafe {
213 encoder.transition_textures(&barriers);
214 }
215 }
216
217 pending_writes.insert_texture(texture);
224
225 submission.submit(pending_writes)?;
226
227 Ok(())
228 }
229
230 pub(crate) fn maintain(
238 &self,
239 submission_index: u64,
240 snatch_guard: &SnatchGuard,
241 ) -> (
242 SmallVec<[SubmittedWorkDoneClosure; 1]>,
243 Vec<super::BufferMapPendingClosure>,
244 Vec<BlasCompactReadyPendingClosure>,
245 bool,
246 ) {
247 let mut life_tracker = self.lock_life();
248 let submission_closures = life_tracker.triage_submissions(submission_index);
249
250 let mapping_closures = life_tracker.handle_mapping(snatch_guard);
251 let blas_closures = life_tracker.handle_compact_read_back();
252
253 let queue_empty = life_tracker.queue_empty();
254
255 (
256 submission_closures,
257 mapping_closures,
258 blas_closures,
259 queue_empty,
260 )
261 }
262}
263
264crate::impl_resource_type!(Queue);
265impl Labeled for Queue {
267 fn label(&self) -> &str {
268 ""
269 }
270}
271crate::impl_parent_device!(Queue);
272crate::impl_storage_item!(Queue);
273
274impl Drop for Queue {
275 fn drop(&mut self) {
276 resource_log!("Drop {}", self.error_ident());
277
278 match unsafe { self.raw.wait_for_idle() } {
281 Ok(()) => {}
282 Err(hal::DeviceError::Lost) => {
283 self.device.handle_hal_error(hal::DeviceError::Lost);
284 }
285 Err(e) => {
286 panic!("Unexpected error while waiting for queue idle on drop: {e:?}");
287 }
288 }
289
290 let last_successful_submission_index = self
291 .device
292 .last_successful_submission_index
293 .load(Ordering::Acquire);
294
295 let snatch_guard = self.device.snatchable_lock.read();
296 let (submission_closures, mapping_closures, blas_compact_ready_closures, queue_empty) =
297 self.maintain(last_successful_submission_index, &snatch_guard);
298 drop(snatch_guard);
299
300 assert!(queue_empty);
301
302 let closures = crate::device::UserClosures {
303 mappings: mapping_closures,
304 blas_compact_ready: blas_compact_ready_closures,
305 submissions: submission_closures,
306 device_lost_invocations: SmallVec::new(),
307 };
308
309 closures.fire();
310 }
311}
312
313#[cfg(send_sync)]
314pub type SubmittedWorkDoneClosure = Box<dyn FnOnce() + Send + 'static>;
315#[cfg(not(send_sync))]
316pub type SubmittedWorkDoneClosure = Box<dyn FnOnce() + 'static>;
317
318#[derive(Debug)]
329pub enum TempResource {
330 StagingBuffer(FlushedStagingBuffer),
331 ScratchBuffer(ScratchBuffer),
332 DestroyedBuffer(DestroyedBuffer),
333 DestroyedTexture(DestroyedTexture),
334}
335
336pub(crate) struct EncoderInFlight {
342 inner: crate::command::InnerCommandEncoder,
343 pub(crate) trackers: Tracker,
344 pub(crate) temp_resources: Vec<TempResource>,
345 _indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
347
348 pub(crate) pending_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
350 pub(crate) pending_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
352 pub(crate) pending_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
354}
355
356#[derive(Debug)]
381pub(crate) struct PendingWrites {
382 pub command_encoder: Box<dyn hal::DynCommandEncoder>,
384
385 pub is_recording: bool,
391
392 temp_resources: Vec<TempResource>,
393 dst_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
394 dst_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
395 copied_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
396 instance_flags: wgt::InstanceFlags,
397}
398
399impl PendingWrites {
400 pub fn new(
401 command_encoder: Box<dyn hal::DynCommandEncoder>,
402 instance_flags: wgt::InstanceFlags,
403 ) -> Self {
404 Self {
405 command_encoder,
406 is_recording: false,
407 temp_resources: Vec::new(),
408 dst_buffers: FastHashMap::default(),
409 dst_textures: FastHashMap::default(),
410 copied_blas_s: FastHashMap::default(),
411 instance_flags,
412 }
413 }
414
415 pub fn insert_buffer(&mut self, buffer: &Arc<Buffer>) {
416 self.dst_buffers
417 .insert(buffer.tracker_index(), buffer.clone());
418 }
419
420 pub fn insert_texture(&mut self, texture: &Arc<Texture>) {
421 self.dst_textures
422 .insert(texture.tracker_index(), texture.clone());
423 }
424
425 pub fn insert_blas(&mut self, blas: &Arc<Blas>) {
426 self.copied_blas_s
427 .insert(blas.tracker_index(), blas.clone());
428 }
429
430 pub fn contains_buffer(&self, buffer: &Arc<Buffer>) -> bool {
431 self.dst_buffers.contains_key(&buffer.tracker_index())
432 }
433
434 pub fn contains_texture(&self, texture: &Arc<Texture>) -> bool {
435 self.dst_textures.contains_key(&texture.tracker_index())
436 }
437
438 pub fn consume_temp(&mut self, resource: TempResource) {
439 self.temp_resources.push(resource);
440 }
441
442 pub fn consume(&mut self, buffer: FlushedStagingBuffer) {
443 self.temp_resources
444 .push(TempResource::StagingBuffer(buffer));
445 }
446
447 fn pre_submit(
448 &mut self,
449 command_allocator: &CommandAllocator,
450 device: &Arc<Device>,
451 queue: &Queue,
452 ) -> Result<Option<EncoderInFlight>, DeviceError> {
453 if self.is_recording {
454 let pending_buffers = mem::take(&mut self.dst_buffers);
455 let pending_textures = mem::take(&mut self.dst_textures);
456 let pending_blas_s = mem::take(&mut self.copied_blas_s);
457
458 let cmd_buf = unsafe { self.command_encoder.end_encoding() }
459 .map_err(|e| device.handle_hal_error(e))?;
460 self.is_recording = false;
461
462 let new_encoder = command_allocator
463 .acquire_encoder(device.raw(), queue.raw())
464 .map_err(|e| device.handle_hal_error(e))?;
465
466 let encoder = EncoderInFlight {
467 inner: crate::command::InnerCommandEncoder {
468 raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)),
469 list: vec![cmd_buf],
470 device: device.clone(),
471 is_open: false,
472 api: crate::command::EncodingApi::InternalUse,
473 label: "(wgpu internal) PendingWrites command encoder".into(),
474 },
475 trackers: Tracker::new(device.ordered_buffer_usages, device.ordered_texture_usages),
476 temp_resources: mem::take(&mut self.temp_resources),
477 _indirect_draw_validation_resources: crate::indirect_validation::DrawResources::new(
478 device.clone(),
479 ),
480 pending_buffers,
481 pending_textures,
482 pending_blas_s,
483 };
484 Ok(Some(encoder))
485 } else {
486 self.dst_buffers.clear();
487 self.dst_textures.clear();
488 self.copied_blas_s.clear();
489 Ok(None)
490 }
491 }
492
493 pub fn activate(&mut self) -> &mut dyn hal::DynCommandEncoder {
494 if !self.is_recording {
495 unsafe {
496 self.command_encoder
497 .begin_encoding(hal_label(
498 Some("(wgpu internal) PendingWrites"),
499 self.instance_flags,
500 ))
501 .unwrap();
502 }
503 self.is_recording = true;
504 }
505 self.command_encoder.as_mut()
506 }
507}
508
509impl Drop for PendingWrites {
510 fn drop(&mut self) {
511 unsafe {
512 if self.is_recording {
513 self.command_encoder.discard_encoding();
514 }
515 }
516 }
517}
518
519#[derive(Clone, Debug, Error)]
520#[non_exhaustive]
521pub enum QueueWriteError {
522 #[error(transparent)]
523 Queue(#[from] DeviceError),
524 #[error(transparent)]
525 Transfer(#[from] TransferError),
526 #[error(transparent)]
527 MemoryInitFailure(#[from] ClearError),
528 #[error(transparent)]
529 DestroyedResource(#[from] DestroyedResourceError),
530 #[error(transparent)]
531 InvalidResource(#[from] InvalidResourceError),
532}
533
534impl WebGpuError for QueueWriteError {
535 fn webgpu_error_type(&self) -> ErrorType {
536 match self {
537 Self::Queue(e) => e.webgpu_error_type(),
538 Self::Transfer(e) => e.webgpu_error_type(),
539 Self::MemoryInitFailure(e) => e.webgpu_error_type(),
540 Self::DestroyedResource(e) => e.webgpu_error_type(),
541 Self::InvalidResource(e) => e.webgpu_error_type(),
542 }
543 }
544}
545
546#[derive(Clone, Debug, Error)]
547#[non_exhaustive]
548pub enum QueueSubmitError {
549 #[error(transparent)]
550 Queue(#[from] DeviceError),
551 #[error(transparent)]
552 DestroyedResource(#[from] DestroyedResourceError),
553 #[error("{0} is still mapped")]
554 BufferStillMapped(ResourceErrorIdent),
555 #[error(transparent)]
556 InvalidResource(#[from] InvalidResourceError),
557 #[error(transparent)]
558 CommandEncoder(#[from] CommandEncoderError),
559 #[error(transparent)]
560 ValidateAsActionsError(#[from] crate::ray_tracing::ValidateAsActionsError),
561}
562
563impl WebGpuError for QueueSubmitError {
564 fn webgpu_error_type(&self) -> ErrorType {
565 match self {
566 Self::Queue(e) => e.webgpu_error_type(),
567 Self::CommandEncoder(e) => e.webgpu_error_type(),
568 Self::ValidateAsActionsError(e) => e.webgpu_error_type(),
569 Self::InvalidResource(e) => e.webgpu_error_type(),
570 Self::DestroyedResource(_) | Self::BufferStillMapped(_) => ErrorType::Validation,
571 }
572 }
573}
574
575pub(crate) struct PendingSubmission<'a> {
583 queue: &'a Queue,
584 snatch_guard: SnatchGuard<'a>,
585 command_index_guard: RwLockWriteGuard<'a, CommandIndices>,
586 pub executions: Vec<EncoderInFlight>,
588 surface_textures: FastHashMap<*const Texture, Arc<Texture>>,
592 pub index: SubmissionIndex,
593}
594
595pub(crate) struct SubmissionResult<'a> {
596 pub snatch_guard: SnatchGuard<'a>,
597}
598
599impl<'a> PendingSubmission<'a> {
600 fn submit(
601 self,
602 pending_writes: MutexGuard<'a, PendingWrites>,
603 ) -> Result<SubmissionResult<'a>, DeviceError> {
604 self.queue.submit_pending_submission(pending_writes, self)
605 }
606}
607
608impl Queue {
611 pub fn write_buffer(
612 &self,
613 buffer: Arc<Buffer>,
614 buffer_offset: wgt::BufferAddress,
615 data: &[u8],
616 ) -> Result<(), QueueWriteError> {
617 profiling::scope!("Queue::write_buffer");
618 api_log!("Queue::write_buffer");
619
620 self.device.check_is_valid()?;
621
622 let data_size = data.len() as wgt::BufferAddress;
623
624 self.same_device_as(buffer.as_ref())?;
625
626 let data_size = if let Some(data_size) = wgt::BufferSize::new(data_size) {
627 data_size
628 } else {
629 self.validate_write_buffer_impl(buffer.as_ref(), buffer_offset, 0)?;
634
635 log::trace!("Ignoring write_buffer of size 0");
636 return Ok(());
637 };
638
639 let mut staging_buffer = StagingBuffer::new(&self.device, data_size)?;
643
644 let staging_buffer = {
645 profiling::scope!("copy");
646 staging_buffer.write(data);
647 staging_buffer.flush()
648 };
649
650 let snatch_guard = self.device.snatchable_lock.read();
651 let mut pending_writes = self.pending_writes.lock();
652
653 let result = self.write_staging_buffer_impl(
654 &snatch_guard,
655 &mut pending_writes,
656 &staging_buffer,
657 buffer,
658 buffer_offset,
659 );
660
661 drop(snatch_guard);
662
663 pending_writes.consume(staging_buffer);
664
665 drop(pending_writes);
666
667 result
668 }
669
670 pub fn create_staging_buffer(
671 &self,
672 buffer_size: wgt::BufferSize,
673 ) -> Result<(StagingBuffer, NonNull<u8>), QueueWriteError> {
674 profiling::scope!("Queue::create_staging_buffer");
675 resource_log!("Queue::create_staging_buffer");
676
677 self.device.check_is_valid()?;
678
679 let staging_buffer = StagingBuffer::new(&self.device, buffer_size)?;
680 let ptr = unsafe { staging_buffer.ptr() };
681
682 Ok((staging_buffer, ptr))
683 }
684
685 pub fn write_staging_buffer(
686 &self,
687 buffer: Fallible<Buffer>,
688 buffer_offset: wgt::BufferAddress,
689 staging_buffer: StagingBuffer,
690 ) -> Result<(), QueueWriteError> {
691 profiling::scope!("Queue::write_staging_buffer");
692
693 self.device.check_is_valid()?;
694
695 let buffer = buffer.get()?;
696
697 let staging_buffer = staging_buffer.flush();
702
703 let snatch_guard = self.device.snatchable_lock.read();
704 let mut pending_writes = self.pending_writes.lock();
705
706 let result = self.write_staging_buffer_impl(
707 &snatch_guard,
708 &mut pending_writes,
709 &staging_buffer,
710 buffer,
711 buffer_offset,
712 );
713
714 drop(snatch_guard);
715
716 pending_writes.consume(staging_buffer);
717
718 drop(pending_writes);
719
720 result
721 }
722
723 pub fn validate_write_buffer(
724 &self,
725 buffer: Fallible<Buffer>,
726 buffer_offset: u64,
727 buffer_size: wgt::BufferSize,
728 ) -> Result<(), QueueWriteError> {
729 profiling::scope!("Queue::validate_write_buffer");
730
731 self.device.check_is_valid()?;
732
733 let buffer = buffer.get()?;
734
735 self.validate_write_buffer_impl(&buffer, buffer_offset, buffer_size.into())?;
736
737 Ok(())
738 }
739
740 fn validate_write_buffer_impl(
741 &self,
742 buffer: &Buffer,
743 buffer_offset: u64,
744 buffer_size: u64,
745 ) -> Result<(), TransferError> {
746 if !matches!(&*buffer.map_state.lock(), BufferMapState::Idle) {
747 return Err(TransferError::BufferNotAvailable);
748 }
749 buffer.check_usage(wgt::BufferUsages::COPY_DST)?;
750 if !buffer_size.is_multiple_of(wgt::COPY_BUFFER_ALIGNMENT) {
751 return Err(TransferError::UnalignedCopySize(buffer_size));
752 }
753 if !buffer_offset.is_multiple_of(wgt::COPY_BUFFER_ALIGNMENT) {
754 return Err(TransferError::UnalignedBufferOffset(buffer_offset));
755 }
756
757 if buffer_offset > buffer.size {
758 return Err(TransferError::BufferStartOffsetOverrun {
759 start_offset: buffer_offset,
760 buffer_size: buffer.size,
761 side: CopySide::Destination,
762 });
763 }
764 if buffer_size > buffer.size - buffer_offset {
765 return Err(TransferError::BufferEndOffsetOverrun {
766 start_offset: buffer_offset,
767 size: buffer_size,
768 buffer_size: buffer.size,
769 side: CopySide::Destination,
770 });
771 }
772
773 Ok(())
774 }
775
776 fn write_staging_buffer_impl(
777 &self,
778 snatch_guard: &SnatchGuard,
779 pending_writes: &mut PendingWrites,
780 staging_buffer: &FlushedStagingBuffer,
781 buffer: Arc<Buffer>,
782 buffer_offset: u64,
783 ) -> Result<(), QueueWriteError> {
784 self.device.check_is_valid()?;
785
786 let transition = {
787 let mut trackers = self.device.trackers.lock();
788 trackers
789 .buffers
790 .set_single(&buffer, wgt::BufferUses::COPY_DST)
791 };
792
793 let dst_raw = buffer.try_raw(snatch_guard)?;
794
795 self.same_device_as(buffer.as_ref())?;
796
797 self.validate_write_buffer_impl(&buffer, buffer_offset, staging_buffer.size.into())?;
798
799 let region = hal::BufferCopy {
800 src_offset: 0,
801 dst_offset: buffer_offset,
802 size: staging_buffer.size,
803 };
804 let barriers = iter::once(hal::BufferBarrier {
805 buffer: staging_buffer.raw(),
806 usage: hal::StateTransition {
807 from: wgt::BufferUses::MAP_WRITE,
808 to: wgt::BufferUses::COPY_SRC,
809 },
810 })
811 .chain(transition.map(|pending| pending.into_hal(&buffer, snatch_guard)))
812 .collect::<Vec<_>>();
813 let encoder = pending_writes.activate();
814 unsafe {
815 encoder.transition_buffers(&barriers);
816 encoder.copy_buffer_to_buffer(staging_buffer.raw(), dst_raw, &[region]);
817 }
818
819 pending_writes.insert_buffer(&buffer);
820
821 {
824 buffer
825 .initialization_status
826 .write()
827 .drain(buffer_offset..(buffer_offset + staging_buffer.size.get()));
828 }
829
830 Ok(())
831 }
832
833 pub fn write_texture(
834 &self,
835 destination: wgt::TexelCopyTextureInfo<Arc<Texture>>,
836 data: &[u8],
837 data_layout: &wgt::TexelCopyBufferLayout,
838 size: &wgt::Extent3d,
839 ) -> Result<(), QueueWriteError> {
840 profiling::scope!("Queue::write_texture");
841 api_log!("Queue::write_texture");
842
843 self.device.check_is_valid()?;
844
845 let dst = destination.texture;
846 let destination = wgt::TexelCopyTextureInfo {
847 texture: (),
848 mip_level: destination.mip_level,
849 origin: destination.origin,
850 aspect: destination.aspect,
851 };
852
853 self.same_device_as(dst.as_ref())?;
854
855 dst.check_usage(wgt::TextureUsages::COPY_DST)
856 .map_err(TransferError::MissingTextureUsage)?;
857
858 let (hal_copy_size, array_layer_count) =
861 validate_texture_copy_range(&destination, &dst.desc, CopySide::Destination, size)?;
862
863 let (selector, dst_base) = extract_texture_selector(&destination, size, &dst)?;
864
865 validate_texture_copy_dst_format(dst.desc.format, destination.aspect)?;
866
867 validate_texture_buffer_copy(
868 &destination,
869 dst_base.aspect,
870 &dst.desc,
871 data_layout,
872 false, )?;
874
875 let (required_bytes_in_copy, _source_bytes_per_array_layer, _) =
878 validate_linear_texture_data(
879 data_layout,
880 dst.desc.format,
881 destination.aspect,
882 data.len() as wgt::BufferAddress,
883 CopySide::Source,
884 size,
885 )?;
886
887 if dst.desc.format.is_depth_stencil_format() {
888 self.device
889 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
890 .map_err(TransferError::from)?;
891 }
892
893 let snatch_guard = self.device.snatchable_lock.read();
894
895 let dst_raw = dst.try_raw(&snatch_guard)?;
896
897 if size.width == 0 || size.height == 0 || size.depth_or_array_layers == 0 {
900 log::trace!("Ignoring write_texture of size 0");
901 return Ok(());
902 }
903
904 let mut pending_writes = self.pending_writes.lock();
905 let encoder = pending_writes.activate();
906
907 let init_layer_range = if dst.desc.dimension == wgt::TextureDimension::D3 {
913 0..1
915 } else {
916 destination.origin.z..destination.origin.z + size.depth_or_array_layers
917 };
918 let mut dst_initialization_status = dst.initialization_status.write();
919 if dst_initialization_status.mips[destination.mip_level as usize]
920 .check(init_layer_range.clone())
921 .is_some()
922 {
923 if has_copy_partial_init_tracker_coverage(size, &destination, &dst.desc) {
924 for layer_range in dst_initialization_status.mips[destination.mip_level as usize]
925 .drain(init_layer_range)
926 .collect::<Vec<core::ops::Range<u32>>>()
927 {
928 let mut trackers = self.device.trackers.lock();
929 crate::command::clear_texture(
930 &dst,
931 TextureInitRange {
932 mip_range: destination.mip_level..(destination.mip_level + 1),
933 layer_range,
934 },
935 encoder,
936 &mut trackers.textures,
937 &self.device.alignments,
938 self.device.zero_buffer.as_ref(),
939 &snatch_guard,
940 self.device.instance_flags,
941 )
942 .map_err(QueueWriteError::from)?;
943 }
944 } else {
945 dst_initialization_status.mips[destination.mip_level as usize]
946 .drain(init_layer_range);
947 }
948 }
949
950 let (block_width, block_height) = dst.desc.format.block_dimensions();
951 let width_in_blocks = size.width / block_width;
952 let height_in_blocks = size.height / block_height;
953
954 let block_size = dst
955 .desc
956 .format
957 .block_copy_size(Some(destination.aspect))
958 .unwrap();
959 let bytes_in_last_row = width_in_blocks * block_size;
960
961 let bytes_per_row = data_layout.bytes_per_row.unwrap_or(bytes_in_last_row);
962 let rows_per_image = data_layout.rows_per_image.unwrap_or(height_in_blocks);
963
964 let bytes_per_row_alignment = get_lowest_common_denom(
965 self.device.alignments.buffer_copy_pitch.get() as u32,
966 block_size,
967 );
968 assert!(u32::MAX - bytes_in_last_row >= bytes_per_row_alignment);
969 let stage_bytes_per_row = wgt::math::align_to(bytes_in_last_row, bytes_per_row_alignment);
970
971 let staging_buffer = if stage_bytes_per_row == bytes_per_row {
975 profiling::scope!("copy aligned");
976 let stage_size = wgt::BufferSize::new(required_bytes_in_copy).unwrap();
978 let mut staging_buffer = StagingBuffer::new(&self.device, stage_size)?;
979 staging_buffer.write(&data[data_layout.offset as usize..]);
980 staging_buffer
981 } else {
982 profiling::scope!("copy chunked");
983 let block_rows_in_copy = u64::from(size.depth_or_array_layers - 1)
985 * u64::from(rows_per_image)
986 + u64::from(height_in_blocks);
987 let stage_size = u64::from(stage_bytes_per_row)
990 .checked_mul(block_rows_in_copy)
991 .and_then(wgt::BufferSize::new)
992 .unwrap();
993 let mut staging_buffer = StagingBuffer::new(&self.device, stage_size)?;
994 for layer in 0..u64::from(size.depth_or_array_layers) {
995 let rows_offset = layer * u64::from(rows_per_image);
996 for row in rows_offset..rows_offset + u64::from(height_in_blocks) {
997 let src_offset = data_layout.offset + row * u64::from(bytes_per_row);
998 let dst_offset = row * u64::from(stage_bytes_per_row);
999 unsafe {
1000 staging_buffer.write_with_offset(
1001 data,
1002 src_offset as isize,
1003 dst_offset as isize,
1004 bytes_in_last_row as usize,
1005 )
1006 }
1007 }
1008 }
1009 staging_buffer
1010 };
1011
1012 let staging_buffer = staging_buffer.flush();
1013
1014 let regions = (0..array_layer_count)
1015 .map(|array_layer_offset| {
1016 let mut texture_base = dst_base.clone();
1017 texture_base.array_layer += array_layer_offset;
1018 hal::BufferTextureCopy {
1019 buffer_layout: wgt::TexelCopyBufferLayout {
1020 offset: array_layer_offset as u64
1021 * rows_per_image as u64
1022 * stage_bytes_per_row as u64,
1023 bytes_per_row: Some(stage_bytes_per_row),
1024 rows_per_image: Some(rows_per_image),
1025 },
1026 texture_base,
1027 size: hal_copy_size,
1028 }
1029 })
1030 .collect::<Vec<_>>();
1031
1032 {
1033 let buffer_barrier = hal::BufferBarrier {
1034 buffer: staging_buffer.raw(),
1035 usage: hal::StateTransition {
1036 from: wgt::BufferUses::MAP_WRITE,
1037 to: wgt::BufferUses::COPY_SRC,
1038 },
1039 };
1040
1041 let mut trackers = self.device.trackers.lock();
1042 let transition =
1043 trackers
1044 .textures
1045 .set_single(&dst, selector, wgt::TextureUses::COPY_DST);
1046 let texture_barriers = transition
1047 .map(|pending| pending.into_hal(dst_raw))
1048 .collect::<Vec<_>>();
1049
1050 unsafe {
1051 encoder.transition_textures(&texture_barriers);
1052 encoder.transition_buffers(&[buffer_barrier]);
1053 encoder.copy_buffer_to_texture(staging_buffer.raw(), dst_raw, ®ions);
1054 }
1055 }
1056
1057 pending_writes.consume(staging_buffer);
1058 pending_writes.insert_texture(&dst);
1059
1060 Ok(())
1061 }
1062
1063 #[cfg(webgl)]
1064 pub fn copy_external_image_to_texture(
1065 &self,
1066 source: &wgt::CopyExternalImageSourceInfo,
1067 destination: wgt::CopyExternalImageDestInfo<Fallible<Texture>>,
1068 size: wgt::Extent3d,
1069 ) -> Result<(), QueueWriteError> {
1070 use crate::conv;
1071
1072 profiling::scope!("Queue::copy_external_image_to_texture");
1073
1074 self.device.check_is_valid()?;
1075
1076 let mut needs_flag = false;
1077 needs_flag |= matches!(source.source, wgt::ExternalImageSource::OffscreenCanvas(_));
1078 needs_flag |= source.origin != wgt::Origin2d::ZERO;
1079 needs_flag |= destination.color_space != wgt::PredefinedColorSpace::Srgb;
1080 #[allow(clippy::bool_comparison)]
1081 if matches!(source.source, wgt::ExternalImageSource::ImageBitmap(_)) {
1082 needs_flag |= source.flip_y != false;
1083 needs_flag |= destination.premultiplied_alpha != false;
1084 }
1085
1086 if needs_flag {
1087 self.device
1088 .require_downlevel_flags(wgt::DownlevelFlags::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES)
1089 .map_err(TransferError::from)?;
1090 }
1091
1092 let src_width = source.source.width();
1093 let src_height = source.source.height();
1094
1095 let dst = destination.texture.get()?;
1096 let premultiplied_alpha = destination.premultiplied_alpha;
1097 let destination = wgt::TexelCopyTextureInfo {
1098 texture: (),
1099 mip_level: destination.mip_level,
1100 origin: destination.origin,
1101 aspect: destination.aspect,
1102 };
1103
1104 if !conv::is_valid_external_image_copy_dst_texture_format(dst.desc.format) {
1105 return Err(
1106 TransferError::ExternalCopyToForbiddenTextureFormat(dst.desc.format).into(),
1107 );
1108 }
1109 if dst.desc.dimension != wgt::TextureDimension::D2 {
1110 return Err(TransferError::InvalidDimensionExternal.into());
1111 }
1112 dst.check_usage(wgt::TextureUsages::COPY_DST | wgt::TextureUsages::RENDER_ATTACHMENT)
1113 .map_err(TransferError::MissingTextureUsage)?;
1114 if dst.desc.sample_count != 1 {
1115 return Err(TransferError::InvalidSampleCount {
1116 sample_count: dst.desc.sample_count,
1117 }
1118 .into());
1119 }
1120
1121 if source.origin.x > src_width || src_width - source.origin.x < size.width {
1122 return Err(TransferError::TextureOverrun {
1123 start_offset: source.origin.x,
1124 end_offset: source.origin.x.saturating_add(size.width),
1125 texture_size: src_width,
1126 dimension: crate::resource::TextureErrorDimension::X,
1127 side: CopySide::Source,
1128 }
1129 .into());
1130 }
1131 if source.origin.y > src_height || src_height - source.origin.y < size.height {
1132 return Err(TransferError::TextureOverrun {
1133 start_offset: source.origin.y,
1134 end_offset: source.origin.y.saturating_add(size.height),
1135 texture_size: src_height,
1136 dimension: crate::resource::TextureErrorDimension::Y,
1137 side: CopySide::Source,
1138 }
1139 .into());
1140 }
1141 if size.depth_or_array_layers != 1 {
1142 return Err(TransferError::TextureOverrun {
1143 start_offset: 0,
1144 end_offset: size.depth_or_array_layers,
1145 texture_size: 1,
1146 dimension: crate::resource::TextureErrorDimension::Z,
1147 side: CopySide::Source,
1148 }
1149 .into());
1150 }
1151
1152 let (hal_copy_size, _) =
1155 validate_texture_copy_range(&destination, &dst.desc, CopySide::Destination, &size)?;
1156
1157 let (selector, dst_base) = extract_texture_selector(&destination, &size, &dst)?;
1158
1159 if size.width == 0 || size.height == 0 || size.depth_or_array_layers == 0 {
1162 log::trace!("Ignoring copy_external_image_to_texture of size 0");
1163 return Ok(());
1164 }
1165
1166 let mut pending_writes = self.pending_writes.lock();
1167 let encoder = pending_writes.activate();
1168
1169 let init_layer_range = if dst.desc.dimension == wgt::TextureDimension::D3 {
1175 0..1
1177 } else {
1178 destination.origin.z..destination.origin.z + size.depth_or_array_layers
1179 };
1180 let mut dst_initialization_status = dst.initialization_status.write();
1181 if dst_initialization_status.mips[destination.mip_level as usize]
1182 .check(init_layer_range.clone())
1183 .is_some()
1184 {
1185 if has_copy_partial_init_tracker_coverage(&size, &destination, &dst.desc) {
1186 for layer_range in dst_initialization_status.mips[destination.mip_level as usize]
1187 .drain(init_layer_range)
1188 .collect::<Vec<core::ops::Range<u32>>>()
1189 {
1190 let mut trackers = self.device.trackers.lock();
1191 crate::command::clear_texture(
1192 &dst,
1193 TextureInitRange {
1194 mip_range: destination.mip_level..(destination.mip_level + 1),
1195 layer_range,
1196 },
1197 encoder,
1198 &mut trackers.textures,
1199 &self.device.alignments,
1200 self.device.zero_buffer.as_ref(),
1201 &self.device.snatchable_lock.read(),
1202 self.device.instance_flags,
1203 )
1204 .map_err(QueueWriteError::from)?;
1205 }
1206 } else {
1207 dst_initialization_status.mips[destination.mip_level as usize]
1208 .drain(init_layer_range);
1209 }
1210 }
1211
1212 let snatch_guard = self.device.snatchable_lock.read();
1213 let dst_raw = dst.try_raw(&snatch_guard)?;
1214
1215 let regions = hal::TextureCopy {
1216 src_base: hal::TextureCopyBase {
1217 mip_level: 0,
1218 array_layer: 0,
1219 origin: source.origin.to_3d(0),
1220 aspect: hal::FormatAspects::COLOR,
1221 },
1222 dst_base,
1223 size: hal_copy_size,
1224 };
1225
1226 let mut trackers = self.device.trackers.lock();
1227 let transitions = trackers
1228 .textures
1229 .set_single(&dst, selector, wgt::TextureUses::COPY_DST);
1230
1231 let encoder_webgl = encoder
1234 .as_any_mut()
1235 .downcast_mut::<hal::gles::CommandEncoder>()
1236 .unwrap();
1237 let dst_raw_webgl = dst_raw
1238 .as_any()
1239 .downcast_ref::<hal::gles::Texture>()
1240 .unwrap();
1241 let transitions_webgl = transitions.map(|pending| {
1242 let dyn_transition = pending.into_hal(dst_raw);
1243 hal::TextureBarrier {
1244 texture: dst_raw_webgl,
1245 range: dyn_transition.range,
1246 usage: dyn_transition.usage,
1247 }
1248 });
1249
1250 use hal::CommandEncoder as _;
1251 unsafe {
1252 encoder_webgl.transition_textures(transitions_webgl);
1253 encoder_webgl.copy_external_image_to_texture(
1254 source,
1255 dst_raw_webgl,
1256 premultiplied_alpha,
1257 iter::once(regions),
1258 );
1259 }
1260
1261 Ok(())
1262 }
1263
1264 pub fn flush_writes_for_buffer(
1266 &self,
1267 buffer: &Arc<Buffer>,
1268 snatch_guard: SnatchGuard,
1269 ) -> Result<(), BufferAccessError> {
1270 let submission = self
1271 .allocate_submission(snatch_guard)
1272 .map_err(|(_index, e)| e)?;
1273
1274 let pending_writes = self.pending_writes.lock();
1275 if !pending_writes.contains_buffer(buffer) {
1276 return Ok(());
1277 }
1278
1279 submission.submit(pending_writes)?;
1280
1281 Ok(())
1282 }
1283
1284 fn flush_pending_writes(&self) -> Result<Option<SubmissionIndex>, DeviceError> {
1285 let snatch_guard = self.device.snatchable_lock.read();
1286 let submission = self
1287 .allocate_submission(snatch_guard)
1288 .map_err(|(_index, e)| e)?;
1289 let submit_index = submission.index;
1290 let pending_writes = self.pending_writes.lock();
1291 if pending_writes.is_recording {
1292 submission.submit(pending_writes)?;
1293 Ok(Some(submit_index))
1294 } else {
1295 Ok(None)
1296 }
1297 }
1298
1299 #[cfg(feature = "trace")]
1300 fn trace_submission(
1301 &self,
1302 submit_index: SubmissionIndex,
1303 commands: Vec<crate::command::Command<crate::command::PointerReferences>>,
1304 ) {
1305 if let Some(ref mut trace) = *self.device.trace.lock() {
1306 trace.add(Action::Submit(submit_index, commands));
1307 }
1308 }
1309
1310 #[cfg(feature = "trace")]
1311 fn trace_failed_submission(
1312 &self,
1313 submit_index: SubmissionIndex,
1314 commands: Option<Vec<crate::command::Command<crate::command::PointerReferences>>>,
1315 error: alloc::string::String,
1316 ) {
1317 if let Some(ref mut trace) = *self.device.trace.lock() {
1318 trace.add(Action::FailedCommands {
1319 commands,
1320 failed_at_submit: Some(submit_index),
1321 error,
1322 });
1323 }
1324 }
1325
1326 pub fn submit(
1327 &self,
1328 command_buffers: &[Arc<CommandBuffer>],
1329 ) -> Result<SubmissionIndex, (SubmissionIndex, QueueSubmitError)> {
1330 profiling::scope!("Queue::submit");
1331 api_log!("Queue::submit");
1332
1333 let snatch_guard = self.device.snatchable_lock.read();
1334 let mut submission = self
1335 .allocate_submission(snatch_guard)
1336 .map_err(|(index, e)| (index, e.into()))?;
1337 let submit_index = submission.index;
1338
1339 let res = 'error: {
1340 let mut used_surface_textures = track::TextureUsageScope::default();
1341
1342 {
1343 if !command_buffers.is_empty() {
1344 profiling::scope!("prepare");
1345
1346 let mut first_error = None;
1347
1348 for command_buffer in command_buffers {
1354 profiling::scope!("process command buffer");
1355
1356 used_surface_textures.set_size(self.device.tracker_indices.textures.size());
1359
1360 #[allow(unused_mut)]
1363 let mut cmd_buf_data = command_buffer.take_finished();
1364
1365 if first_error.is_some() {
1366 continue;
1367 }
1368
1369 #[cfg(feature = "trace")]
1370 let trace_commands = cmd_buf_data
1371 .as_mut()
1372 .ok()
1373 .and_then(|data| mem::take(&mut data.trace_commands));
1374
1375 let mut baked = match cmd_buf_data {
1376 Ok(cmd_buf_data) => {
1377 let res = validate_command_buffer(
1378 command_buffer,
1379 self,
1380 &cmd_buf_data,
1381 &submission.snatch_guard,
1382 &mut submission.surface_textures,
1383 &mut used_surface_textures,
1384 &mut submission.command_index_guard,
1385 );
1386 if let Err(err) = res {
1387 #[cfg(feature = "trace")]
1388 self.trace_failed_submission(
1389 submit_index,
1390 trace_commands,
1391 err.to_string(),
1392 );
1393 first_error.get_or_insert(err);
1394 continue;
1395 }
1396
1397 #[cfg(feature = "trace")]
1398 if let Some(commands) = trace_commands {
1399 self.trace_submission(submit_index, commands);
1400 }
1401
1402 cmd_buf_data.set_acceleration_structure_dependencies(
1403 &submission.snatch_guard,
1404 );
1405 cmd_buf_data.into_baked_commands()
1406 }
1407 Err(err) => {
1408 #[cfg(feature = "trace")]
1409 self.trace_failed_submission(
1410 submit_index,
1411 trace_commands,
1412 err.to_string(),
1413 );
1414 first_error.get_or_insert(err.into());
1415 continue;
1416 }
1417 };
1418
1419 if let Err(e) = baked.encoder.open_pass(hal_label(
1421 Some("(wgpu internal) Transit"),
1422 self.device.instance_flags,
1423 )) {
1424 break 'error Err(e.into());
1425 }
1426
1427 let mut trackers = self.device.trackers.lock();
1429 if let Err(e) =
1430 baked.initialize_buffer_memory(&mut trackers, &submission.snatch_guard)
1431 {
1432 break 'error Err(e.into());
1433 }
1434 if let Err(e) = baked.initialize_texture_memory(
1435 &mut trackers,
1436 &self.device,
1437 &submission.snatch_guard,
1438 ) {
1439 break 'error Err(e.into());
1440 }
1441
1442 CommandEncoder::insert_barriers_from_device_tracker(
1445 baked.encoder.raw.as_mut(),
1446 &mut trackers,
1447 &baked.trackers,
1448 &submission.snatch_guard,
1449 );
1450
1451 if let Err(e) = baked.encoder.close_and_push_front() {
1452 break 'error Err(e.into());
1453 }
1454
1455 if !used_surface_textures.is_empty() {
1459 if let Err(e) = baked.encoder.open_pass(hal_label(
1460 Some("(wgpu internal) Present"),
1461 self.device.instance_flags,
1462 )) {
1463 break 'error Err(e.into());
1464 }
1465 let texture_barriers = trackers
1466 .textures
1467 .set_from_usage_scope_and_drain_transitions(
1468 &used_surface_textures,
1469 &submission.snatch_guard,
1470 )
1471 .collect::<Vec<_>>();
1472 unsafe {
1473 baked.encoder.raw.transition_textures(&texture_barriers);
1474 };
1475 if let Err(e) = baked.encoder.close() {
1476 break 'error Err(e.into());
1477 }
1478 used_surface_textures = track::TextureUsageScope::default();
1479 }
1480
1481 submission.executions.push(EncoderInFlight {
1483 inner: baked.encoder,
1484 trackers: baked.trackers,
1485 temp_resources: baked.temp_resources,
1486 _indirect_draw_validation_resources: baked
1487 .indirect_draw_validation_resources,
1488 pending_buffers: FastHashMap::default(),
1489 pending_textures: FastHashMap::default(),
1490 pending_blas_s: FastHashMap::default(),
1491 });
1492 }
1493
1494 if let Some(first_error) = first_error {
1495 break 'error Err(first_error);
1496 }
1497 }
1498 }
1499
1500 let pending_writes = self.pending_writes.lock();
1501
1502 let SubmissionResult { snatch_guard } = match submission.submit(pending_writes) {
1503 Ok(result) => result,
1504 Err(e) => break 'error Err(e.into()),
1505 };
1506
1507 profiling::scope!("cleanup");
1508
1509 let (closures, result) = self.device.maintain(wgt::PollType::Poll, snatch_guard);
1513 match result {
1514 Ok(status) => {
1515 debug_assert!(matches!(
1516 status,
1517 wgt::PollStatus::QueueEmpty | wgt::PollStatus::Poll
1518 ));
1519 }
1520 Err(WaitIdleError::Device(err)) => break 'error Err(QueueSubmitError::Queue(err)),
1521 Err(WaitIdleError::WrongSubmissionIndex(..)) => {
1522 unreachable!("Cannot get WrongSubmissionIndex from Poll")
1523 }
1524 Err(WaitIdleError::Timeout) => unreachable!("Cannot get Timeout from Poll"),
1525 };
1526
1527 Ok(closures)
1528 };
1529
1530 let callbacks = match res {
1531 Ok(ok) => ok,
1532 Err(e) => return Err((submit_index, e)),
1533 };
1534
1535 callbacks.fire();
1537
1538 self.device.lose_if_oom();
1539
1540 api_log!("Queue::submit returned submit index {submit_index}");
1541
1542 Ok(submit_index)
1543 }
1544
1545 fn allocate_submission<'a>(
1568 &'a self,
1569 snatch_guard: SnatchGuard<'a>,
1570 ) -> Result<PendingSubmission<'a>, (SubmissionIndex, DeviceError)> {
1571 let mut command_index_guard = self.device.command_indices.write();
1572 command_index_guard.active_submission_index += 1;
1573 let index = command_index_guard.active_submission_index;
1574
1575 if let Err(e) = self.device.check_is_valid() {
1576 return Err((index, e));
1577 }
1578
1579 let submission = PendingSubmission {
1580 queue: self,
1581 snatch_guard,
1582 command_index_guard,
1583 executions: Vec::new(),
1584 surface_textures: FastHashMap::default(),
1585 index,
1586 };
1587
1588 Ok(submission)
1589 }
1590
1591 fn submit_pending_submission<'a>(
1607 &self,
1608 mut pending_writes: MutexGuard<'_, PendingWrites>,
1609 prepared: PendingSubmission<'a>,
1610 ) -> Result<SubmissionResult<'a>, DeviceError> {
1611 let PendingSubmission {
1612 queue: _,
1613 snatch_guard,
1614 command_index_guard,
1615 mut executions,
1616 mut surface_textures,
1617 index: submit_index,
1618 } = prepared;
1619
1620 let mut used_surface_textures = track::TextureUsageScope::default();
1621 used_surface_textures.set_size(self.device.tracker_indices.textures.size());
1622 for texture in pending_writes.dst_textures.values() {
1623 match texture.try_inner(&snatch_guard) {
1624 Ok(TextureInner::Native { .. }) => {}
1625 Ok(TextureInner::Surface { .. }) => {
1626 surface_textures.insert(Arc::as_ptr(texture), texture.clone());
1628
1629 unsafe {
1630 used_surface_textures
1631 .merge_single(texture, None, wgt::TextureUses::PRESENT)
1632 .unwrap()
1633 };
1634 }
1635 Err(DestroyedResourceError(_)) => {}
1640 }
1641 }
1642
1643 if !used_surface_textures.is_empty() {
1644 let mut trackers = self.device.trackers.lock();
1645
1646 let texture_barriers = trackers
1647 .textures
1648 .set_from_usage_scope_and_drain_transitions(&used_surface_textures, &snatch_guard)
1649 .collect::<Vec<_>>();
1650 unsafe {
1651 pending_writes
1652 .command_encoder
1653 .transition_textures(&texture_barriers);
1654 };
1655 }
1656
1657 match pending_writes.pre_submit(&self.device.command_allocator, &self.device, self) {
1658 Ok(Some(pending_execution)) => {
1659 executions.insert(0, pending_execution);
1660 }
1661 Ok(None) => {}
1662 Err(e) => return Err(e),
1663 }
1664 let hal_command_buffers = executions
1665 .iter()
1666 .flat_map(|e| e.inner.list.iter().map(|b| b.as_ref()))
1667 .collect::<Vec<_>>();
1668
1669 {
1670 let mut submit_surface_textures =
1671 SmallVec::<[&dyn hal::DynSurfaceTexture; 2]>::with_capacity(surface_textures.len());
1672 for texture in surface_textures.values() {
1673 let raw = match texture.inner.get(&snatch_guard) {
1674 Some(TextureInner::Surface { raw, .. }) => raw.as_ref(),
1675 _ => unreachable!(),
1676 };
1677 submit_surface_textures.push(raw);
1678 }
1679
1680 unsafe {
1681 self.raw().submit(
1682 &hal_command_buffers,
1683 &submit_surface_textures,
1684 (self.device.fence.as_ref(), submit_index),
1685 )
1686 }
1687 .map_err(|e| self.device.handle_hal_error(e))?;
1688
1689 drop(pending_writes);
1693
1694 self.device
1696 .last_successful_submission_index
1697 .fetch_max(submit_index, Ordering::SeqCst);
1698 }
1699
1700 self.lock_life().track_submission(submit_index, executions);
1702
1703 drop(command_index_guard);
1709
1710 Ok(SubmissionResult { snatch_guard })
1711 }
1712
1713 pub fn get_timestamp_period(&self) -> f32 {
1714 unsafe { self.raw().get_timestamp_period() }
1715 }
1716
1717 pub fn on_submitted_work_done(
1719 &self,
1720 closure: SubmittedWorkDoneClosure,
1721 ) -> Option<SubmissionIndex> {
1722 api_log!("Queue::on_submitted_work_done");
1723
1724 let _: Result<_, DeviceError> = self.flush_pending_writes();
1728
1729 self.lock_life().add_work_done_closure(closure)
1730 }
1731
1732 pub fn compact_blas(&self, blas: &Arc<Blas>) -> Result<Arc<Blas>, CompactBlasError> {
1733 profiling::scope!("Queue::compact_blas");
1734 api_log!("Queue::compact_blas");
1735
1736 let new_label = blas.label.clone() + " (compacted)";
1737
1738 self.device.check_is_valid()?;
1739 self.same_device_as(blas.as_ref())?;
1740
1741 let device = blas.device.clone();
1742
1743 let snatch_guard = device.snatchable_lock.read();
1744
1745 let BlasCompactState::Ready { size } = *blas.compacted_state.lock() else {
1746 return Err(CompactBlasError::BlasNotReady);
1747 };
1748
1749 let mut size_info = blas.size_info;
1750 size_info.acceleration_structure_size = size;
1751
1752 let mut pending_writes = self.pending_writes.lock();
1753 let cmd_buf_raw = pending_writes.activate();
1754
1755 let raw = unsafe {
1756 device
1757 .raw()
1758 .create_acceleration_structure(&hal::AccelerationStructureDescriptor {
1759 label: hal_label(Some(&new_label), device.instance_flags),
1760 size: size_info.acceleration_structure_size,
1761 format: hal::AccelerationStructureFormat::BottomLevel,
1762 allow_compaction: false,
1763 })
1764 }
1765 .map_err(DeviceError::from_hal)?;
1766
1767 let src_raw = blas.try_raw(&snatch_guard)?;
1768
1769 unsafe {
1770 cmd_buf_raw.copy_acceleration_structure_to_acceleration_structure(
1771 src_raw,
1772 raw.as_ref(),
1773 wgt::AccelerationStructureCopy::Compact,
1774 )
1775 };
1776
1777 let handle = unsafe {
1778 device
1779 .raw()
1780 .get_acceleration_structure_device_address(raw.as_ref())
1781 };
1782
1783 drop(snatch_guard);
1784
1785 let mut command_indices_lock = device.command_indices.write();
1786 command_indices_lock.next_acceleration_structure_build_command_index += 1;
1787 let built_index =
1788 NonZeroU64::new(command_indices_lock.next_acceleration_structure_build_command_index)
1789 .unwrap();
1790
1791 let new_blas = Arc::new(Blas {
1792 raw: Snatchable::new(raw),
1793 device: device.clone(),
1794 size_info,
1795 sizes: blas.sizes.clone(),
1796 flags: blas.flags & !AccelerationStructureFlags::ALLOW_COMPACTION,
1797 update_mode: blas.update_mode,
1798 built_index: RwLock::new(rank::BLAS_BUILT_INDEX, Some(built_index)),
1800 handle,
1801 label: new_label,
1802 tracking_data: TrackingData::new(blas.device.tracker_indices.blas_s.clone()),
1803 compaction_buffer: None,
1804 compacted_state: Mutex::new(rank::BLAS_COMPACTION_STATE, BlasCompactState::Compacted),
1805 });
1806
1807 pending_writes.insert_blas(blas);
1808 pending_writes.insert_blas(&new_blas);
1809
1810 Ok(new_blas)
1811 }
1812}
1813
1814impl Global {
1815 pub fn queue_write_buffer(
1816 &self,
1817 queue_id: QueueId,
1818 buffer_id: id::BufferId,
1819 buffer_offset: wgt::BufferAddress,
1820 data: &[u8],
1821 ) -> Result<(), QueueWriteError> {
1822 let queue = self.hub.queues.get(queue_id);
1823 let buffer = self.hub.buffers.get(buffer_id).get()?;
1824
1825 #[cfg(feature = "trace")]
1826 if let Some(ref mut trace) = *queue.device.trace.lock() {
1827 use crate::device::trace::DataKind;
1828 let size = data.len() as u64;
1829 let data = trace.make_binary(DataKind::Bin, data);
1830 trace.add(Action::WriteBuffer {
1831 id: buffer.to_trace(),
1832 data,
1833 offset: buffer_offset,
1834 size,
1835 queued: true,
1836 });
1837 }
1838
1839 queue.write_buffer(buffer, buffer_offset, data)
1840 }
1841
1842 pub fn queue_create_staging_buffer(
1843 &self,
1844 queue_id: QueueId,
1845 buffer_size: wgt::BufferSize,
1846 id_in: Option<id::StagingBufferId>,
1847 ) -> Result<(id::StagingBufferId, NonNull<u8>), QueueWriteError> {
1848 let queue = self.hub.queues.get(queue_id);
1849 let (staging_buffer, ptr) = queue.create_staging_buffer(buffer_size)?;
1850
1851 let fid = self.hub.staging_buffers.prepare(id_in);
1852 let id = fid.assign(staging_buffer);
1853
1854 Ok((id, ptr))
1855 }
1856
1857 pub fn queue_write_staging_buffer(
1858 &self,
1859 queue_id: QueueId,
1860 buffer_id: id::BufferId,
1861 buffer_offset: wgt::BufferAddress,
1862 staging_buffer_id: id::StagingBufferId,
1863 ) -> Result<(), QueueWriteError> {
1864 let queue = self.hub.queues.get(queue_id);
1865 let buffer = self.hub.buffers.get(buffer_id);
1866 let staging_buffer = self.hub.staging_buffers.remove(staging_buffer_id);
1867 queue.write_staging_buffer(buffer, buffer_offset, staging_buffer)
1868 }
1869
1870 pub fn queue_validate_write_buffer(
1871 &self,
1872 queue_id: QueueId,
1873 buffer_id: id::BufferId,
1874 buffer_offset: u64,
1875 buffer_size: wgt::BufferSize,
1876 ) -> Result<(), QueueWriteError> {
1877 let queue = self.hub.queues.get(queue_id);
1878 let buffer = self.hub.buffers.get(buffer_id);
1879 queue.validate_write_buffer(buffer, buffer_offset, buffer_size)
1880 }
1881
1882 pub fn queue_write_texture(
1883 &self,
1884 queue_id: QueueId,
1885 destination: &wgt::TexelCopyTextureInfo<id::TextureId>,
1886 data: &[u8],
1887 data_layout: &wgt::TexelCopyBufferLayout,
1888 size: &wgt::Extent3d,
1889 ) -> Result<(), QueueWriteError> {
1890 let queue = self.hub.queues.get(queue_id);
1891 let texture = self.hub.textures.get(destination.texture).get()?;
1892 let destination = wgt::TexelCopyTextureInfo {
1893 texture,
1894 mip_level: destination.mip_level,
1895 origin: destination.origin,
1896 aspect: destination.aspect,
1897 };
1898
1899 #[cfg(feature = "trace")]
1900 if let Some(ref mut trace) = *queue.device.trace.lock() {
1901 use crate::device::trace::DataKind;
1902 let data = trace.make_binary(DataKind::Bin, data);
1903 trace.add(Action::WriteTexture {
1904 to: destination.to_trace(),
1905 data,
1906 layout: *data_layout,
1907 size: *size,
1908 });
1909 }
1910
1911 queue.write_texture(destination, data, data_layout, size)
1912 }
1913
1914 #[cfg(webgl)]
1915 pub fn queue_copy_external_image_to_texture(
1916 &self,
1917 queue_id: QueueId,
1918 source: &wgt::CopyExternalImageSourceInfo,
1919 destination: crate::command::CopyExternalImageDestInfo,
1920 size: wgt::Extent3d,
1921 ) -> Result<(), QueueWriteError> {
1922 let queue = self.hub.queues.get(queue_id);
1923 let destination = wgt::CopyExternalImageDestInfo {
1924 texture: self.hub.textures.get(destination.texture),
1925 mip_level: destination.mip_level,
1926 origin: destination.origin,
1927 aspect: destination.aspect,
1928 color_space: destination.color_space,
1929 premultiplied_alpha: destination.premultiplied_alpha,
1930 };
1931 queue.copy_external_image_to_texture(source, destination, size)
1932 }
1933
1934 pub fn queue_submit(
1935 &self,
1936 queue_id: QueueId,
1937 command_buffer_ids: &[id::CommandBufferId],
1938 ) -> Result<SubmissionIndex, (SubmissionIndex, QueueSubmitError)> {
1939 let queue = self.hub.queues.get(queue_id);
1940 let command_buffer_guard = self.hub.command_buffers.read();
1941 let command_buffers = command_buffer_ids
1942 .iter()
1943 .map(|id| command_buffer_guard.get(*id))
1944 .collect::<Vec<_>>();
1945 drop(command_buffer_guard);
1946 queue.submit(&command_buffers)
1947 }
1948
1949 pub fn queue_get_timestamp_period(&self, queue_id: QueueId) -> f32 {
1950 let queue = self.hub.queues.get(queue_id);
1951
1952 if queue.device.timestamp_normalizer.get().unwrap().enabled() {
1953 return 1.0;
1954 }
1955
1956 queue.get_timestamp_period()
1957 }
1958
1959 pub fn queue_on_submitted_work_done(
1960 &self,
1961 queue_id: QueueId,
1962 closure: SubmittedWorkDoneClosure,
1963 ) -> SubmissionIndex {
1964 api_log!("Queue::on_submitted_work_done {queue_id:?}");
1965
1966 let queue = self.hub.queues.get(queue_id);
1967 let result = queue.on_submitted_work_done(closure);
1968 result.unwrap_or(0) }
1970
1971 pub fn queue_compact_blas(
1972 &self,
1973 queue_id: QueueId,
1974 blas_id: BlasId,
1975 id_in: Option<BlasId>,
1976 ) -> (BlasId, Option<u64>, Option<CompactBlasError>) {
1977 api_log!("Queue::compact_blas {queue_id:?}, {blas_id:?}");
1978
1979 let fid = self.hub.blas_s.prepare(id_in);
1980
1981 let queue = self.hub.queues.get(queue_id);
1982 let blas = self.hub.blas_s.get(blas_id);
1983 let device = &queue.device;
1984
1985 let error = 'error: {
1988 match device.require_features(wgpu_types::Features::EXPERIMENTAL_RAY_QUERY) {
1989 Ok(_) => {}
1990 Err(err) => break 'error err.into(),
1991 }
1992
1993 let blas = match blas.get() {
1994 Ok(blas) => blas,
1995 Err(err) => break 'error err.into(),
1996 };
1997
1998 let new_blas = match queue.compact_blas(&blas) {
1999 Ok(blas) => blas,
2000 Err(err) => break 'error err,
2001 };
2002
2003 let old_blas_size = blas.size_info.acceleration_structure_size;
2005 let new_blas_size = new_blas.size_info.acceleration_structure_size;
2006 let handle = new_blas.handle;
2007
2008 let id = fid.assign(Fallible::Valid(new_blas));
2009
2010 api_log!("CommandEncoder::compact_blas {blas_id:?} (size: {old_blas_size}) -> {id:?} (size: {new_blas_size})");
2011
2012 return (id, Some(handle), None);
2013 };
2014
2015 let id = fid.assign(Fallible::Invalid(Arc::new(error.to_string())));
2016
2017 (id, None, Some(error))
2018 }
2019}
2020
2021fn validate_command_buffer(
2022 command_buffer: &CommandBuffer,
2023 queue: &Queue,
2024 cmd_buf_data: &crate::command::CommandBufferMutable,
2025 snatch_guard: &SnatchGuard,
2026 surface_textures: &mut FastHashMap<*const Texture, Arc<Texture>>,
2027 used_surface_textures: &mut track::TextureUsageScope,
2028 command_index_guard: &mut RwLockWriteGuard<CommandIndices>,
2029) -> Result<(), QueueSubmitError> {
2030 command_buffer.same_device_as(queue)?;
2031
2032 {
2033 profiling::scope!("check resource state");
2034
2035 {
2036 profiling::scope!("buffers");
2037 for buffer in cmd_buf_data.trackers.buffers.used_resources() {
2038 buffer.check_destroyed(snatch_guard)?;
2039
2040 match *buffer.map_state.lock() {
2041 BufferMapState::Idle => (),
2042 _ => return Err(QueueSubmitError::BufferStillMapped(buffer.error_ident())),
2043 }
2044 }
2045 }
2046 {
2047 profiling::scope!("textures");
2048 for texture in cmd_buf_data.trackers.textures.used_resources() {
2049 let should_extend = match texture.try_inner(snatch_guard)? {
2050 TextureInner::Native { .. } => false,
2051 TextureInner::Surface { .. } => {
2052 surface_textures.insert(Arc::as_ptr(texture), texture.clone());
2054
2055 true
2056 }
2057 };
2058 if should_extend {
2059 unsafe {
2060 used_surface_textures
2061 .merge_single(texture, None, wgt::TextureUses::PRESENT)
2062 .unwrap();
2063 };
2064 }
2065 }
2066 }
2067 {
2071 profiling::scope!("bind groups");
2072 for bind_group in &cmd_buf_data.trackers.bind_groups {
2073 bind_group.try_raw(snatch_guard)?;
2075 }
2076 }
2077
2078 if let Err(e) =
2079 cmd_buf_data.validate_acceleration_structure_actions(snatch_guard, command_index_guard)
2080 {
2081 return Err(e.into());
2082 }
2083 }
2084 Ok(())
2085}