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 device = &self.device;
129 let snatch_guard = device.snatchable_lock.read();
130
131 let needs_clear = {
133 let status = texture.initialization_status.read();
134 status
135 .mips
136 .first()
137 .is_some_and(|mip| mip.check(0..1).is_some())
138 };
139
140 let mut fence = device.fence.write();
143 let mut pending_writes = self.pending_writes.lock();
144
145 if needs_clear {
146 let encoder = pending_writes.activate();
147 let mut trackers = device.trackers.lock();
148 crate::command::clear_texture(
149 texture,
150 TextureInitRange {
151 mip_range: 0..1,
152 layer_range: 0..1,
153 },
154 encoder,
155 &mut trackers.textures,
156 &device.alignments,
157 device.zero_buffer.as_ref(),
158 &snatch_guard,
159 device.instance_flags,
160 )
161 .map_err(|e| match e {
162 ClearError::Device(e) => e,
163 _ => DeviceError::Lost,
164 })?;
165 texture.initialization_status.write().mips[0].drain(0..1);
166 }
167
168 let pending = {
174 let mut trackers = device.trackers.lock();
175 let pending: Vec<track::PendingTransition<wgt::TextureUses>> = trackers
176 .textures
177 .set_single(
178 texture,
179 texture.full_range.clone(),
180 wgt::TextureUses::PRESENT,
181 )
182 .collect();
183 pending
184 };
185
186 if pending.is_empty() {
187 return Ok(());
188 }
189
190 {
192 let raw_texture = texture
193 .try_raw(&snatch_guard)
194 .map_err(|_| DeviceError::Lost)?;
195 let barriers: Vec<hal::TextureBarrier<'_, dyn hal::DynTexture>> = pending
196 .into_iter()
197 .map(|pt| pt.into_hal(raw_texture))
198 .collect();
199
200 let encoder = pending_writes.activate();
201 unsafe {
205 encoder.transition_textures(&barriers);
206 }
207 }
208
209 pending_writes.insert_texture(texture);
212
213 let mut surface_textures = FastHashMap::default();
215 surface_textures.insert(Arc::as_ptr(texture), texture.clone());
216
217 let submit_index = {
218 let mut indices = device.command_indices.write();
219 indices.active_submission_index += 1;
220 indices.active_submission_index
221 };
222
223 self.submit_with_pending_writes(
224 &mut pending_writes,
225 Vec::new(),
226 surface_textures,
227 fence.as_mut(),
228 submit_index,
229 &snatch_guard,
230 )
231 }
232
233 pub(crate) fn maintain(
234 &self,
235 submission_index: u64,
236 snatch_guard: &SnatchGuard,
237 ) -> (
238 SmallVec<[SubmittedWorkDoneClosure; 1]>,
239 Vec<super::BufferMapPendingClosure>,
240 Vec<BlasCompactReadyPendingClosure>,
241 bool,
242 ) {
243 let mut life_tracker = self.lock_life();
244 let submission_closures = life_tracker.triage_submissions(submission_index);
245
246 let mapping_closures = life_tracker.handle_mapping(snatch_guard);
247 let blas_closures = life_tracker.handle_compact_read_back();
248
249 let queue_empty = life_tracker.queue_empty();
250
251 (
252 submission_closures,
253 mapping_closures,
254 blas_closures,
255 queue_empty,
256 )
257 }
258}
259
260crate::impl_resource_type!(Queue);
261impl Labeled for Queue {
263 fn label(&self) -> &str {
264 ""
265 }
266}
267crate::impl_parent_device!(Queue);
268crate::impl_storage_item!(Queue);
269
270impl Drop for Queue {
271 fn drop(&mut self) {
272 resource_log!("Drop {}", self.error_ident());
273
274 match unsafe { self.raw.wait_for_idle() } {
277 Ok(()) => {}
278 Err(hal::DeviceError::Lost) => {
279 self.device.handle_hal_error(hal::DeviceError::Lost);
280 }
281 Err(e) => {
282 panic!("Unexpected error while waiting for queue idle on drop: {e:?}");
283 }
284 }
285
286 let last_successful_submission_index = self
287 .device
288 .last_successful_submission_index
289 .load(Ordering::Acquire);
290
291 let snatch_guard = self.device.snatchable_lock.read();
292 let (submission_closures, mapping_closures, blas_compact_ready_closures, queue_empty) =
293 self.maintain(last_successful_submission_index, &snatch_guard);
294 drop(snatch_guard);
295
296 assert!(queue_empty);
297
298 let closures = crate::device::UserClosures {
299 mappings: mapping_closures,
300 blas_compact_ready: blas_compact_ready_closures,
301 submissions: submission_closures,
302 device_lost_invocations: SmallVec::new(),
303 };
304
305 closures.fire();
306 }
307}
308
309#[cfg(send_sync)]
310pub type SubmittedWorkDoneClosure = Box<dyn FnOnce() + Send + 'static>;
311#[cfg(not(send_sync))]
312pub type SubmittedWorkDoneClosure = Box<dyn FnOnce() + 'static>;
313
314#[derive(Debug)]
325pub enum TempResource {
326 StagingBuffer(FlushedStagingBuffer),
327 ScratchBuffer(ScratchBuffer),
328 DestroyedBuffer(DestroyedBuffer),
329 DestroyedTexture(DestroyedTexture),
330}
331
332pub(crate) struct EncoderInFlight {
338 inner: crate::command::InnerCommandEncoder,
339 pub(crate) trackers: Tracker,
340 pub(crate) temp_resources: Vec<TempResource>,
341 _indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
343
344 pub(crate) pending_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
346 pub(crate) pending_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
348 pub(crate) pending_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
350}
351
352#[derive(Debug)]
373pub(crate) struct PendingWrites {
374 pub command_encoder: Box<dyn hal::DynCommandEncoder>,
376
377 pub is_recording: bool,
383
384 temp_resources: Vec<TempResource>,
385 dst_buffers: FastHashMap<TrackerIndex, Arc<Buffer>>,
386 dst_textures: FastHashMap<TrackerIndex, Arc<Texture>>,
387 copied_blas_s: FastHashMap<TrackerIndex, Arc<Blas>>,
388 instance_flags: wgt::InstanceFlags,
389}
390
391impl PendingWrites {
392 pub fn new(
393 command_encoder: Box<dyn hal::DynCommandEncoder>,
394 instance_flags: wgt::InstanceFlags,
395 ) -> Self {
396 Self {
397 command_encoder,
398 is_recording: false,
399 temp_resources: Vec::new(),
400 dst_buffers: FastHashMap::default(),
401 dst_textures: FastHashMap::default(),
402 copied_blas_s: FastHashMap::default(),
403 instance_flags,
404 }
405 }
406
407 pub fn insert_buffer(&mut self, buffer: &Arc<Buffer>) {
408 self.dst_buffers
409 .insert(buffer.tracker_index(), buffer.clone());
410 }
411
412 pub fn insert_texture(&mut self, texture: &Arc<Texture>) {
413 self.dst_textures
414 .insert(texture.tracker_index(), texture.clone());
415 }
416
417 pub fn insert_blas(&mut self, blas: &Arc<Blas>) {
418 self.copied_blas_s
419 .insert(blas.tracker_index(), blas.clone());
420 }
421
422 pub fn contains_buffer(&self, buffer: &Arc<Buffer>) -> bool {
423 self.dst_buffers.contains_key(&buffer.tracker_index())
424 }
425
426 pub fn contains_texture(&self, texture: &Arc<Texture>) -> bool {
427 self.dst_textures.contains_key(&texture.tracker_index())
428 }
429
430 pub fn consume_temp(&mut self, resource: TempResource) {
431 self.temp_resources.push(resource);
432 }
433
434 pub fn consume(&mut self, buffer: FlushedStagingBuffer) {
435 self.temp_resources
436 .push(TempResource::StagingBuffer(buffer));
437 }
438
439 fn pre_submit(
440 &mut self,
441 command_allocator: &CommandAllocator,
442 device: &Arc<Device>,
443 queue: &Queue,
444 ) -> Result<Option<EncoderInFlight>, DeviceError> {
445 if self.is_recording {
446 let pending_buffers = mem::take(&mut self.dst_buffers);
447 let pending_textures = mem::take(&mut self.dst_textures);
448 let pending_blas_s = mem::take(&mut self.copied_blas_s);
449
450 let cmd_buf = unsafe { self.command_encoder.end_encoding() }
451 .map_err(|e| device.handle_hal_error(e))?;
452 self.is_recording = false;
453
454 let new_encoder = command_allocator
455 .acquire_encoder(device.raw(), queue.raw())
456 .map_err(|e| device.handle_hal_error(e))?;
457
458 let encoder = EncoderInFlight {
459 inner: crate::command::InnerCommandEncoder {
460 raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)),
461 list: vec![cmd_buf],
462 device: device.clone(),
463 is_open: false,
464 api: crate::command::EncodingApi::InternalUse,
465 label: "(wgpu internal) PendingWrites command encoder".into(),
466 },
467 trackers: Tracker::new(device.ordered_buffer_usages, device.ordered_texture_usages),
468 temp_resources: mem::take(&mut self.temp_resources),
469 _indirect_draw_validation_resources: crate::indirect_validation::DrawResources::new(
470 device.clone(),
471 ),
472 pending_buffers,
473 pending_textures,
474 pending_blas_s,
475 };
476 Ok(Some(encoder))
477 } else {
478 self.dst_buffers.clear();
479 self.dst_textures.clear();
480 self.copied_blas_s.clear();
481 Ok(None)
482 }
483 }
484
485 pub fn activate(&mut self) -> &mut dyn hal::DynCommandEncoder {
486 if !self.is_recording {
487 unsafe {
488 self.command_encoder
489 .begin_encoding(hal_label(
490 Some("(wgpu internal) PendingWrites"),
491 self.instance_flags,
492 ))
493 .unwrap();
494 }
495 self.is_recording = true;
496 }
497 self.command_encoder.as_mut()
498 }
499}
500
501impl Drop for PendingWrites {
502 fn drop(&mut self) {
503 unsafe {
504 if self.is_recording {
505 self.command_encoder.discard_encoding();
506 }
507 }
508 }
509}
510
511#[derive(Clone, Debug, Error)]
512#[non_exhaustive]
513pub enum QueueWriteError {
514 #[error(transparent)]
515 Queue(#[from] DeviceError),
516 #[error(transparent)]
517 Transfer(#[from] TransferError),
518 #[error(transparent)]
519 MemoryInitFailure(#[from] ClearError),
520 #[error(transparent)]
521 DestroyedResource(#[from] DestroyedResourceError),
522 #[error(transparent)]
523 InvalidResource(#[from] InvalidResourceError),
524}
525
526impl WebGpuError for QueueWriteError {
527 fn webgpu_error_type(&self) -> ErrorType {
528 match self {
529 Self::Queue(e) => e.webgpu_error_type(),
530 Self::Transfer(e) => e.webgpu_error_type(),
531 Self::MemoryInitFailure(e) => e.webgpu_error_type(),
532 Self::DestroyedResource(e) => e.webgpu_error_type(),
533 Self::InvalidResource(e) => e.webgpu_error_type(),
534 }
535 }
536}
537
538#[derive(Clone, Debug, Error)]
539#[non_exhaustive]
540pub enum QueueSubmitError {
541 #[error(transparent)]
542 Queue(#[from] DeviceError),
543 #[error(transparent)]
544 DestroyedResource(#[from] DestroyedResourceError),
545 #[error(transparent)]
546 Unmap(#[from] BufferAccessError),
547 #[error("{0} is still mapped")]
548 BufferStillMapped(ResourceErrorIdent),
549 #[error(transparent)]
550 InvalidResource(#[from] InvalidResourceError),
551 #[error(transparent)]
552 CommandEncoder(#[from] CommandEncoderError),
553 #[error(transparent)]
554 ValidateAsActionsError(#[from] crate::ray_tracing::ValidateAsActionsError),
555}
556
557impl WebGpuError for QueueSubmitError {
558 fn webgpu_error_type(&self) -> ErrorType {
559 match self {
560 Self::Queue(e) => e.webgpu_error_type(),
561 Self::Unmap(e) => e.webgpu_error_type(),
562 Self::CommandEncoder(e) => e.webgpu_error_type(),
563 Self::ValidateAsActionsError(e) => e.webgpu_error_type(),
564 Self::InvalidResource(e) => e.webgpu_error_type(),
565 Self::DestroyedResource(_) | Self::BufferStillMapped(_) => ErrorType::Validation,
566 }
567 }
568}
569
570impl Queue {
573 pub fn write_buffer(
574 &self,
575 buffer: Arc<Buffer>,
576 buffer_offset: wgt::BufferAddress,
577 data: &[u8],
578 ) -> Result<(), QueueWriteError> {
579 profiling::scope!("Queue::write_buffer");
580 api_log!("Queue::write_buffer");
581
582 self.device.check_is_valid()?;
583
584 let data_size = data.len() as wgt::BufferAddress;
585
586 self.same_device_as(buffer.as_ref())?;
587
588 let data_size = if let Some(data_size) = wgt::BufferSize::new(data_size) {
589 data_size
590 } else {
591 self.validate_write_buffer_impl(buffer.as_ref(), buffer_offset, 0)?;
596
597 log::trace!("Ignoring write_buffer of size 0");
598 return Ok(());
599 };
600
601 let mut staging_buffer = StagingBuffer::new(&self.device, data_size)?;
605
606 let staging_buffer = {
607 profiling::scope!("copy");
608 staging_buffer.write(data);
609 staging_buffer.flush()
610 };
611
612 let snatch_guard = self.device.snatchable_lock.read();
613 let mut pending_writes = self.pending_writes.lock();
614
615 let result = self.write_staging_buffer_impl(
616 &snatch_guard,
617 &mut pending_writes,
618 &staging_buffer,
619 buffer,
620 buffer_offset,
621 );
622
623 drop(snatch_guard);
624
625 pending_writes.consume(staging_buffer);
626
627 drop(pending_writes);
628
629 result
630 }
631
632 pub fn create_staging_buffer(
633 &self,
634 buffer_size: wgt::BufferSize,
635 ) -> Result<(StagingBuffer, NonNull<u8>), QueueWriteError> {
636 profiling::scope!("Queue::create_staging_buffer");
637 resource_log!("Queue::create_staging_buffer");
638
639 self.device.check_is_valid()?;
640
641 let staging_buffer = StagingBuffer::new(&self.device, buffer_size)?;
642 let ptr = unsafe { staging_buffer.ptr() };
643
644 Ok((staging_buffer, ptr))
645 }
646
647 pub fn write_staging_buffer(
648 &self,
649 buffer: Fallible<Buffer>,
650 buffer_offset: wgt::BufferAddress,
651 staging_buffer: StagingBuffer,
652 ) -> Result<(), QueueWriteError> {
653 profiling::scope!("Queue::write_staging_buffer");
654
655 self.device.check_is_valid()?;
656
657 let buffer = buffer.get()?;
658
659 let staging_buffer = staging_buffer.flush();
664
665 let snatch_guard = self.device.snatchable_lock.read();
666 let mut pending_writes = self.pending_writes.lock();
667
668 let result = self.write_staging_buffer_impl(
669 &snatch_guard,
670 &mut pending_writes,
671 &staging_buffer,
672 buffer,
673 buffer_offset,
674 );
675
676 drop(snatch_guard);
677
678 pending_writes.consume(staging_buffer);
679
680 drop(pending_writes);
681
682 result
683 }
684
685 pub fn validate_write_buffer(
686 &self,
687 buffer: Fallible<Buffer>,
688 buffer_offset: u64,
689 buffer_size: wgt::BufferSize,
690 ) -> Result<(), QueueWriteError> {
691 profiling::scope!("Queue::validate_write_buffer");
692
693 self.device.check_is_valid()?;
694
695 let buffer = buffer.get()?;
696
697 self.validate_write_buffer_impl(&buffer, buffer_offset, buffer_size.into())?;
698
699 Ok(())
700 }
701
702 fn validate_write_buffer_impl(
703 &self,
704 buffer: &Buffer,
705 buffer_offset: u64,
706 buffer_size: u64,
707 ) -> Result<(), TransferError> {
708 if !matches!(&*buffer.map_state.lock(), BufferMapState::Idle) {
709 return Err(TransferError::BufferNotAvailable);
710 }
711 buffer.check_usage(wgt::BufferUsages::COPY_DST)?;
712 if !buffer_size.is_multiple_of(wgt::COPY_BUFFER_ALIGNMENT) {
713 return Err(TransferError::UnalignedCopySize(buffer_size));
714 }
715 if !buffer_offset.is_multiple_of(wgt::COPY_BUFFER_ALIGNMENT) {
716 return Err(TransferError::UnalignedBufferOffset(buffer_offset));
717 }
718
719 if buffer_offset > buffer.size {
720 return Err(TransferError::BufferStartOffsetOverrun {
721 start_offset: buffer_offset,
722 buffer_size: buffer.size,
723 side: CopySide::Destination,
724 });
725 }
726 if buffer_size > buffer.size - buffer_offset {
727 return Err(TransferError::BufferEndOffsetOverrun {
728 start_offset: buffer_offset,
729 size: buffer_size,
730 buffer_size: buffer.size,
731 side: CopySide::Destination,
732 });
733 }
734
735 Ok(())
736 }
737
738 fn write_staging_buffer_impl(
739 &self,
740 snatch_guard: &SnatchGuard,
741 pending_writes: &mut PendingWrites,
742 staging_buffer: &FlushedStagingBuffer,
743 buffer: Arc<Buffer>,
744 buffer_offset: u64,
745 ) -> Result<(), QueueWriteError> {
746 self.device.check_is_valid()?;
747
748 let transition = {
749 let mut trackers = self.device.trackers.lock();
750 trackers
751 .buffers
752 .set_single(&buffer, wgt::BufferUses::COPY_DST)
753 };
754
755 let dst_raw = buffer.try_raw(snatch_guard)?;
756
757 self.same_device_as(buffer.as_ref())?;
758
759 self.validate_write_buffer_impl(&buffer, buffer_offset, staging_buffer.size.into())?;
760
761 let region = hal::BufferCopy {
762 src_offset: 0,
763 dst_offset: buffer_offset,
764 size: staging_buffer.size,
765 };
766 let barriers = iter::once(hal::BufferBarrier {
767 buffer: staging_buffer.raw(),
768 usage: hal::StateTransition {
769 from: wgt::BufferUses::MAP_WRITE,
770 to: wgt::BufferUses::COPY_SRC,
771 },
772 })
773 .chain(transition.map(|pending| pending.into_hal(&buffer, snatch_guard)))
774 .collect::<Vec<_>>();
775 let encoder = pending_writes.activate();
776 unsafe {
777 encoder.transition_buffers(&barriers);
778 encoder.copy_buffer_to_buffer(staging_buffer.raw(), dst_raw, &[region]);
779 }
780
781 pending_writes.insert_buffer(&buffer);
782
783 {
786 buffer
787 .initialization_status
788 .write()
789 .drain(buffer_offset..(buffer_offset + staging_buffer.size.get()));
790 }
791
792 Ok(())
793 }
794
795 pub fn write_texture(
796 &self,
797 destination: wgt::TexelCopyTextureInfo<Arc<Texture>>,
798 data: &[u8],
799 data_layout: &wgt::TexelCopyBufferLayout,
800 size: &wgt::Extent3d,
801 ) -> Result<(), QueueWriteError> {
802 profiling::scope!("Queue::write_texture");
803 api_log!("Queue::write_texture");
804
805 self.device.check_is_valid()?;
806
807 let dst = destination.texture;
808 let destination = wgt::TexelCopyTextureInfo {
809 texture: (),
810 mip_level: destination.mip_level,
811 origin: destination.origin,
812 aspect: destination.aspect,
813 };
814
815 self.same_device_as(dst.as_ref())?;
816
817 dst.check_usage(wgt::TextureUsages::COPY_DST)
818 .map_err(TransferError::MissingTextureUsage)?;
819
820 let (hal_copy_size, array_layer_count) =
823 validate_texture_copy_range(&destination, &dst.desc, CopySide::Destination, size)?;
824
825 let (selector, dst_base) = extract_texture_selector(&destination, size, &dst)?;
826
827 validate_texture_copy_dst_format(dst.desc.format, destination.aspect)?;
828
829 validate_texture_buffer_copy(
830 &destination,
831 dst_base.aspect,
832 &dst.desc,
833 data_layout,
834 false, )?;
836
837 let (required_bytes_in_copy, _source_bytes_per_array_layer, _) =
840 validate_linear_texture_data(
841 data_layout,
842 dst.desc.format,
843 destination.aspect,
844 data.len() as wgt::BufferAddress,
845 CopySide::Source,
846 size,
847 )?;
848
849 if dst.desc.format.is_depth_stencil_format() {
850 self.device
851 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
852 .map_err(TransferError::from)?;
853 }
854
855 let snatch_guard = self.device.snatchable_lock.read();
856
857 let dst_raw = dst.try_raw(&snatch_guard)?;
858
859 if size.width == 0 || size.height == 0 || size.depth_or_array_layers == 0 {
862 log::trace!("Ignoring write_texture of size 0");
863 return Ok(());
864 }
865
866 let mut pending_writes = self.pending_writes.lock();
867 let encoder = pending_writes.activate();
868
869 let init_layer_range = if dst.desc.dimension == wgt::TextureDimension::D3 {
875 0..1
877 } else {
878 destination.origin.z..destination.origin.z + size.depth_or_array_layers
879 };
880 let mut dst_initialization_status = dst.initialization_status.write();
881 if dst_initialization_status.mips[destination.mip_level as usize]
882 .check(init_layer_range.clone())
883 .is_some()
884 {
885 if has_copy_partial_init_tracker_coverage(size, destination.mip_level, &dst.desc) {
886 for layer_range in dst_initialization_status.mips[destination.mip_level as usize]
887 .drain(init_layer_range)
888 .collect::<Vec<core::ops::Range<u32>>>()
889 {
890 let mut trackers = self.device.trackers.lock();
891 crate::command::clear_texture(
892 &dst,
893 TextureInitRange {
894 mip_range: destination.mip_level..(destination.mip_level + 1),
895 layer_range,
896 },
897 encoder,
898 &mut trackers.textures,
899 &self.device.alignments,
900 self.device.zero_buffer.as_ref(),
901 &snatch_guard,
902 self.device.instance_flags,
903 )
904 .map_err(QueueWriteError::from)?;
905 }
906 } else {
907 dst_initialization_status.mips[destination.mip_level as usize]
908 .drain(init_layer_range);
909 }
910 }
911
912 let (block_width, block_height) = dst.desc.format.block_dimensions();
913 let width_in_blocks = size.width / block_width;
914 let height_in_blocks = size.height / block_height;
915
916 let block_size = dst
917 .desc
918 .format
919 .block_copy_size(Some(destination.aspect))
920 .unwrap();
921 let bytes_in_last_row = width_in_blocks * block_size;
922
923 let bytes_per_row = data_layout.bytes_per_row.unwrap_or(bytes_in_last_row);
924 let rows_per_image = data_layout.rows_per_image.unwrap_or(height_in_blocks);
925
926 let bytes_per_row_alignment = get_lowest_common_denom(
927 self.device.alignments.buffer_copy_pitch.get() as u32,
928 block_size,
929 );
930 assert!(u32::MAX - bytes_in_last_row >= bytes_per_row_alignment);
931 let stage_bytes_per_row = wgt::math::align_to(bytes_in_last_row, bytes_per_row_alignment);
932
933 let staging_buffer = if stage_bytes_per_row == bytes_per_row {
937 profiling::scope!("copy aligned");
938 let stage_size = wgt::BufferSize::new(required_bytes_in_copy).unwrap();
940 let mut staging_buffer = StagingBuffer::new(&self.device, stage_size)?;
941 staging_buffer.write(&data[data_layout.offset as usize..]);
942 staging_buffer
943 } else {
944 profiling::scope!("copy chunked");
945 let block_rows_in_copy = u64::from(size.depth_or_array_layers - 1)
947 * u64::from(rows_per_image)
948 + u64::from(height_in_blocks);
949 let stage_size = u64::from(stage_bytes_per_row)
952 .checked_mul(block_rows_in_copy)
953 .and_then(wgt::BufferSize::new)
954 .unwrap();
955 let mut staging_buffer = StagingBuffer::new(&self.device, stage_size)?;
956 for layer in 0..u64::from(size.depth_or_array_layers) {
957 let rows_offset = layer * u64::from(rows_per_image);
958 for row in rows_offset..rows_offset + u64::from(height_in_blocks) {
959 let src_offset = data_layout.offset + row * u64::from(bytes_per_row);
960 let dst_offset = row * u64::from(stage_bytes_per_row);
961 unsafe {
962 staging_buffer.write_with_offset(
963 data,
964 src_offset as isize,
965 dst_offset as isize,
966 bytes_in_last_row as usize,
967 )
968 }
969 }
970 }
971 staging_buffer
972 };
973
974 let staging_buffer = staging_buffer.flush();
975
976 let regions = (0..array_layer_count)
977 .map(|array_layer_offset| {
978 let mut texture_base = dst_base.clone();
979 texture_base.array_layer += array_layer_offset;
980 hal::BufferTextureCopy {
981 buffer_layout: wgt::TexelCopyBufferLayout {
982 offset: array_layer_offset as u64
983 * rows_per_image as u64
984 * stage_bytes_per_row as u64,
985 bytes_per_row: Some(stage_bytes_per_row),
986 rows_per_image: Some(rows_per_image),
987 },
988 texture_base,
989 size: hal_copy_size,
990 }
991 })
992 .collect::<Vec<_>>();
993
994 {
995 let buffer_barrier = hal::BufferBarrier {
996 buffer: staging_buffer.raw(),
997 usage: hal::StateTransition {
998 from: wgt::BufferUses::MAP_WRITE,
999 to: wgt::BufferUses::COPY_SRC,
1000 },
1001 };
1002
1003 let mut trackers = self.device.trackers.lock();
1004 let transition =
1005 trackers
1006 .textures
1007 .set_single(&dst, selector, wgt::TextureUses::COPY_DST);
1008 let texture_barriers = transition
1009 .map(|pending| pending.into_hal(dst_raw))
1010 .collect::<Vec<_>>();
1011
1012 unsafe {
1013 encoder.transition_textures(&texture_barriers);
1014 encoder.transition_buffers(&[buffer_barrier]);
1015 encoder.copy_buffer_to_texture(staging_buffer.raw(), dst_raw, ®ions);
1016 }
1017 }
1018
1019 pending_writes.consume(staging_buffer);
1020 pending_writes.insert_texture(&dst);
1021
1022 Ok(())
1023 }
1024
1025 #[cfg(webgl)]
1026 pub fn copy_external_image_to_texture(
1027 &self,
1028 source: &wgt::CopyExternalImageSourceInfo,
1029 destination: wgt::CopyExternalImageDestInfo<Fallible<Texture>>,
1030 size: wgt::Extent3d,
1031 ) -> Result<(), QueueWriteError> {
1032 use crate::conv;
1033
1034 profiling::scope!("Queue::copy_external_image_to_texture");
1035
1036 self.device.check_is_valid()?;
1037
1038 let mut needs_flag = false;
1039 needs_flag |= matches!(source.source, wgt::ExternalImageSource::OffscreenCanvas(_));
1040 needs_flag |= source.origin != wgt::Origin2d::ZERO;
1041 needs_flag |= destination.color_space != wgt::PredefinedColorSpace::Srgb;
1042 #[allow(clippy::bool_comparison)]
1043 if matches!(source.source, wgt::ExternalImageSource::ImageBitmap(_)) {
1044 needs_flag |= source.flip_y != false;
1045 needs_flag |= destination.premultiplied_alpha != false;
1046 }
1047
1048 if needs_flag {
1049 self.device
1050 .require_downlevel_flags(wgt::DownlevelFlags::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES)
1051 .map_err(TransferError::from)?;
1052 }
1053
1054 let src_width = source.source.width();
1055 let src_height = source.source.height();
1056
1057 let dst = destination.texture.get()?;
1058 let premultiplied_alpha = destination.premultiplied_alpha;
1059 let destination = wgt::TexelCopyTextureInfo {
1060 texture: (),
1061 mip_level: destination.mip_level,
1062 origin: destination.origin,
1063 aspect: destination.aspect,
1064 };
1065
1066 if !conv::is_valid_external_image_copy_dst_texture_format(dst.desc.format) {
1067 return Err(
1068 TransferError::ExternalCopyToForbiddenTextureFormat(dst.desc.format).into(),
1069 );
1070 }
1071 if dst.desc.dimension != wgt::TextureDimension::D2 {
1072 return Err(TransferError::InvalidDimensionExternal.into());
1073 }
1074 dst.check_usage(wgt::TextureUsages::COPY_DST | wgt::TextureUsages::RENDER_ATTACHMENT)
1075 .map_err(TransferError::MissingTextureUsage)?;
1076 if dst.desc.sample_count != 1 {
1077 return Err(TransferError::InvalidSampleCount {
1078 sample_count: dst.desc.sample_count,
1079 }
1080 .into());
1081 }
1082
1083 if source.origin.x > src_width || src_width - source.origin.x < size.width {
1084 return Err(TransferError::TextureOverrun {
1085 start_offset: source.origin.x,
1086 end_offset: source.origin.x.saturating_add(size.width),
1087 texture_size: src_width,
1088 dimension: crate::resource::TextureErrorDimension::X,
1089 side: CopySide::Source,
1090 }
1091 .into());
1092 }
1093 if source.origin.y > src_height || src_height - source.origin.y < size.height {
1094 return Err(TransferError::TextureOverrun {
1095 start_offset: source.origin.y,
1096 end_offset: source.origin.y.saturating_add(size.height),
1097 texture_size: src_height,
1098 dimension: crate::resource::TextureErrorDimension::Y,
1099 side: CopySide::Source,
1100 }
1101 .into());
1102 }
1103 if size.depth_or_array_layers != 1 {
1104 return Err(TransferError::TextureOverrun {
1105 start_offset: 0,
1106 end_offset: size.depth_or_array_layers,
1107 texture_size: 1,
1108 dimension: crate::resource::TextureErrorDimension::Z,
1109 side: CopySide::Source,
1110 }
1111 .into());
1112 }
1113
1114 let (hal_copy_size, _) =
1117 validate_texture_copy_range(&destination, &dst.desc, CopySide::Destination, &size)?;
1118
1119 let (selector, dst_base) = extract_texture_selector(&destination, &size, &dst)?;
1120
1121 if size.width == 0 || size.height == 0 || size.depth_or_array_layers == 0 {
1124 log::trace!("Ignoring copy_external_image_to_texture of size 0");
1125 return Ok(());
1126 }
1127
1128 let mut pending_writes = self.pending_writes.lock();
1129 let encoder = pending_writes.activate();
1130
1131 let init_layer_range = if dst.desc.dimension == wgt::TextureDimension::D3 {
1137 0..1
1139 } else {
1140 destination.origin.z..destination.origin.z + size.depth_or_array_layers
1141 };
1142 let mut dst_initialization_status = dst.initialization_status.write();
1143 if dst_initialization_status.mips[destination.mip_level as usize]
1144 .check(init_layer_range.clone())
1145 .is_some()
1146 {
1147 if has_copy_partial_init_tracker_coverage(&size, destination.mip_level, &dst.desc) {
1148 for layer_range in dst_initialization_status.mips[destination.mip_level as usize]
1149 .drain(init_layer_range)
1150 .collect::<Vec<core::ops::Range<u32>>>()
1151 {
1152 let mut trackers = self.device.trackers.lock();
1153 crate::command::clear_texture(
1154 &dst,
1155 TextureInitRange {
1156 mip_range: destination.mip_level..(destination.mip_level + 1),
1157 layer_range,
1158 },
1159 encoder,
1160 &mut trackers.textures,
1161 &self.device.alignments,
1162 self.device.zero_buffer.as_ref(),
1163 &self.device.snatchable_lock.read(),
1164 self.device.instance_flags,
1165 )
1166 .map_err(QueueWriteError::from)?;
1167 }
1168 } else {
1169 dst_initialization_status.mips[destination.mip_level as usize]
1170 .drain(init_layer_range);
1171 }
1172 }
1173
1174 let snatch_guard = self.device.snatchable_lock.read();
1175 let dst_raw = dst.try_raw(&snatch_guard)?;
1176
1177 let regions = hal::TextureCopy {
1178 src_base: hal::TextureCopyBase {
1179 mip_level: 0,
1180 array_layer: 0,
1181 origin: source.origin.to_3d(0),
1182 aspect: hal::FormatAspects::COLOR,
1183 },
1184 dst_base,
1185 size: hal_copy_size,
1186 };
1187
1188 let mut trackers = self.device.trackers.lock();
1189 let transitions = trackers
1190 .textures
1191 .set_single(&dst, selector, wgt::TextureUses::COPY_DST);
1192
1193 let encoder_webgl = encoder
1196 .as_any_mut()
1197 .downcast_mut::<hal::gles::CommandEncoder>()
1198 .unwrap();
1199 let dst_raw_webgl = dst_raw
1200 .as_any()
1201 .downcast_ref::<hal::gles::Texture>()
1202 .unwrap();
1203 let transitions_webgl = transitions.map(|pending| {
1204 let dyn_transition = pending.into_hal(dst_raw);
1205 hal::TextureBarrier {
1206 texture: dst_raw_webgl,
1207 range: dyn_transition.range,
1208 usage: dyn_transition.usage,
1209 }
1210 });
1211
1212 use hal::CommandEncoder as _;
1213 unsafe {
1214 encoder_webgl.transition_textures(transitions_webgl);
1215 encoder_webgl.copy_external_image_to_texture(
1216 source,
1217 dst_raw_webgl,
1218 premultiplied_alpha,
1219 iter::once(regions),
1220 );
1221 }
1222
1223 Ok(())
1224 }
1225
1226 #[cfg(feature = "trace")]
1227 fn trace_submission(
1228 &self,
1229 submit_index: SubmissionIndex,
1230 commands: Vec<crate::command::Command<crate::command::PointerReferences>>,
1231 ) {
1232 if let Some(ref mut trace) = *self.device.trace.lock() {
1233 trace.add(Action::Submit(submit_index, commands));
1234 }
1235 }
1236
1237 #[cfg(feature = "trace")]
1238 fn trace_failed_submission(
1239 &self,
1240 submit_index: SubmissionIndex,
1241 commands: Option<Vec<crate::command::Command<crate::command::PointerReferences>>>,
1242 error: alloc::string::String,
1243 ) {
1244 if let Some(ref mut trace) = *self.device.trace.lock() {
1245 trace.add(Action::FailedCommands {
1246 commands,
1247 failed_at_submit: Some(submit_index),
1248 error,
1249 });
1250 }
1251 }
1252
1253 pub fn submit(
1254 &self,
1255 command_buffers: &[Arc<CommandBuffer>],
1256 ) -> Result<SubmissionIndex, (SubmissionIndex, QueueSubmitError)> {
1257 profiling::scope!("Queue::submit");
1258 api_log!("Queue::submit");
1259
1260 let submit_index;
1261
1262 let res = 'error: {
1263 let snatch_guard = self.device.snatchable_lock.read();
1264
1265 let mut fence = self.device.fence.write();
1267
1268 let mut command_index_guard = self.device.command_indices.write();
1269 command_index_guard.active_submission_index += 1;
1270 submit_index = command_index_guard.active_submission_index;
1271
1272 if let Err(e) = self.device.check_is_valid() {
1273 break 'error Err(e.into());
1274 }
1275
1276 let mut active_executions = Vec::new();
1277
1278 let mut used_surface_textures = track::TextureUsageScope::default();
1279
1280 let mut submit_surface_textures_owned = FastHashMap::default();
1283
1284 {
1285 if !command_buffers.is_empty() {
1286 profiling::scope!("prepare");
1287
1288 let mut first_error = None;
1289
1290 for command_buffer in command_buffers {
1296 profiling::scope!("process command buffer");
1297
1298 used_surface_textures.set_size(self.device.tracker_indices.textures.size());
1301
1302 #[allow(unused_mut)]
1305 let mut cmd_buf_data = command_buffer.take_finished();
1306
1307 if first_error.is_some() {
1308 continue;
1309 }
1310
1311 #[cfg(feature = "trace")]
1312 let trace_commands = cmd_buf_data
1313 .as_mut()
1314 .ok()
1315 .and_then(|data| mem::take(&mut data.trace_commands));
1316
1317 let mut baked = match cmd_buf_data {
1318 Ok(cmd_buf_data) => {
1319 let res = validate_command_buffer(
1320 command_buffer,
1321 self,
1322 &cmd_buf_data,
1323 &snatch_guard,
1324 &mut submit_surface_textures_owned,
1325 &mut used_surface_textures,
1326 &mut command_index_guard,
1327 );
1328 if let Err(err) = res {
1329 #[cfg(feature = "trace")]
1330 self.trace_failed_submission(
1331 submit_index,
1332 trace_commands,
1333 err.to_string(),
1334 );
1335 first_error.get_or_insert(err);
1336 continue;
1337 }
1338
1339 #[cfg(feature = "trace")]
1340 if let Some(commands) = trace_commands {
1341 self.trace_submission(submit_index, commands);
1342 }
1343
1344 cmd_buf_data.set_acceleration_structure_dependencies(&snatch_guard);
1345 cmd_buf_data.into_baked_commands()
1346 }
1347 Err(err) => {
1348 #[cfg(feature = "trace")]
1349 self.trace_failed_submission(
1350 submit_index,
1351 trace_commands,
1352 err.to_string(),
1353 );
1354 first_error.get_or_insert(err.into());
1355 continue;
1356 }
1357 };
1358
1359 if let Err(e) = baked.encoder.open_pass(hal_label(
1361 Some("(wgpu internal) Transit"),
1362 self.device.instance_flags,
1363 )) {
1364 break 'error Err(e.into());
1365 }
1366
1367 let mut trackers = self.device.trackers.lock();
1369 if let Err(e) = baked.initialize_buffer_memory(&mut trackers, &snatch_guard)
1370 {
1371 break 'error Err(e.into());
1372 }
1373 if let Err(e) = baked.initialize_texture_memory(
1374 &mut trackers,
1375 &self.device,
1376 &snatch_guard,
1377 ) {
1378 break 'error Err(e.into());
1379 }
1380
1381 CommandEncoder::insert_barriers_from_device_tracker(
1384 baked.encoder.raw.as_mut(),
1385 &mut trackers,
1386 &baked.trackers,
1387 &snatch_guard,
1388 );
1389
1390 if let Err(e) = baked.encoder.close_and_push_front() {
1391 break 'error Err(e.into());
1392 }
1393
1394 if !used_surface_textures.is_empty() {
1398 if let Err(e) = baked.encoder.open_pass(hal_label(
1399 Some("(wgpu internal) Present"),
1400 self.device.instance_flags,
1401 )) {
1402 break 'error Err(e.into());
1403 }
1404 let texture_barriers = trackers
1405 .textures
1406 .set_from_usage_scope_and_drain_transitions(
1407 &used_surface_textures,
1408 &snatch_guard,
1409 )
1410 .collect::<Vec<_>>();
1411 unsafe {
1412 baked.encoder.raw.transition_textures(&texture_barriers);
1413 };
1414 if let Err(e) = baked.encoder.close() {
1415 break 'error Err(e.into());
1416 }
1417 used_surface_textures = track::TextureUsageScope::default();
1418 }
1419
1420 active_executions.push(EncoderInFlight {
1422 inner: baked.encoder,
1423 trackers: baked.trackers,
1424 temp_resources: baked.temp_resources,
1425 _indirect_draw_validation_resources: baked
1426 .indirect_draw_validation_resources,
1427 pending_buffers: FastHashMap::default(),
1428 pending_textures: FastHashMap::default(),
1429 pending_blas_s: FastHashMap::default(),
1430 });
1431 }
1432
1433 if let Some(first_error) = first_error {
1434 break 'error Err(first_error);
1435 }
1436 }
1437 }
1438
1439 let mut pending_writes = self.pending_writes.lock();
1440
1441 if let Err(e) = self.submit_with_pending_writes(
1442 &mut pending_writes,
1443 active_executions,
1444 submit_surface_textures_owned,
1445 fence.as_mut(),
1446 submit_index,
1447 &snatch_guard,
1448 ) {
1449 break 'error Err(e.into());
1450 }
1451
1452 drop(command_index_guard);
1453
1454 drop(pending_writes);
1455
1456 profiling::scope!("cleanup");
1457
1458 let fence_guard = RwLockWriteGuard::downgrade(fence);
1461 let (closures, result) =
1462 self.device
1463 .maintain(fence_guard, wgt::PollType::Poll, snatch_guard);
1464 match result {
1465 Ok(status) => {
1466 debug_assert!(matches!(
1467 status,
1468 wgt::PollStatus::QueueEmpty | wgt::PollStatus::Poll
1469 ));
1470 }
1471 Err(WaitIdleError::Device(err)) => break 'error Err(QueueSubmitError::Queue(err)),
1472 Err(WaitIdleError::WrongSubmissionIndex(..)) => {
1473 unreachable!("Cannot get WrongSubmissionIndex from Poll")
1474 }
1475 Err(WaitIdleError::Timeout) => unreachable!("Cannot get Timeout from Poll"),
1476 };
1477
1478 Ok(closures)
1479 };
1480
1481 let callbacks = match res {
1482 Ok(ok) => ok,
1483 Err(e) => return Err((submit_index, e)),
1484 };
1485
1486 callbacks.fire();
1488
1489 self.device.lose_if_oom();
1490
1491 api_log!("Queue::submit returned submit index {submit_index}");
1492
1493 Ok(submit_index)
1494 }
1495
1496 fn submit_with_pending_writes(
1500 &self,
1501 pending_writes: &mut PendingWrites,
1502 mut active_executions: Vec<EncoderInFlight>,
1503 mut surface_textures: FastHashMap<*const Texture, Arc<Texture>>,
1504 fence: &mut dyn hal::DynFence,
1505 submit_index: SubmissionIndex,
1506 snatch_guard: &SnatchGuard,
1507 ) -> Result<(), DeviceError> {
1508 let mut used_surface_textures = track::TextureUsageScope::default();
1509 used_surface_textures.set_size(self.device.tracker_indices.textures.size());
1510 for texture in pending_writes.dst_textures.values() {
1511 match texture.try_inner(snatch_guard) {
1512 Ok(TextureInner::Native { .. }) => {}
1513 Ok(TextureInner::Surface { .. }) => {
1514 surface_textures.insert(Arc::as_ptr(texture), texture.clone());
1516
1517 unsafe {
1518 used_surface_textures
1519 .merge_single(texture, None, wgt::TextureUses::PRESENT)
1520 .unwrap()
1521 };
1522 }
1523 Err(DestroyedResourceError(_)) => {}
1528 }
1529 }
1530
1531 if !used_surface_textures.is_empty() {
1532 let mut trackers = self.device.trackers.lock();
1533
1534 let texture_barriers = trackers
1535 .textures
1536 .set_from_usage_scope_and_drain_transitions(&used_surface_textures, snatch_guard)
1537 .collect::<Vec<_>>();
1538 unsafe {
1539 pending_writes
1540 .command_encoder
1541 .transition_textures(&texture_barriers);
1542 };
1543 }
1544
1545 match pending_writes.pre_submit(&self.device.command_allocator, &self.device, self) {
1546 Ok(Some(pending_execution)) => {
1547 active_executions.insert(0, pending_execution);
1548 }
1549 Ok(None) => {}
1550 Err(e) => return Err(e),
1551 }
1552 let hal_command_buffers = active_executions
1553 .iter()
1554 .flat_map(|e| e.inner.list.iter().map(|b| b.as_ref()))
1555 .collect::<Vec<_>>();
1556
1557 {
1558 let mut submit_surface_textures =
1559 SmallVec::<[&dyn hal::DynSurfaceTexture; 2]>::with_capacity(surface_textures.len());
1560 for texture in surface_textures.values() {
1561 let raw = match texture.inner.get(snatch_guard) {
1562 Some(TextureInner::Surface { raw, .. }) => raw.as_ref(),
1563 _ => unreachable!(),
1564 };
1565 submit_surface_textures.push(raw);
1566 }
1567
1568 unsafe {
1569 self.raw().submit(
1570 &hal_command_buffers,
1571 &submit_surface_textures,
1572 (fence, submit_index),
1573 )
1574 }
1575 .map_err(|e| self.device.handle_hal_error(e))?;
1576
1577 self.device
1579 .last_successful_submission_index
1580 .fetch_max(submit_index, Ordering::SeqCst);
1581 }
1582 self.lock_life()
1584 .track_submission(submit_index, active_executions);
1585
1586 Ok(())
1587 }
1588
1589 pub fn get_timestamp_period(&self) -> f32 {
1590 unsafe { self.raw().get_timestamp_period() }
1591 }
1592
1593 pub fn on_submitted_work_done(
1595 &self,
1596 closure: SubmittedWorkDoneClosure,
1597 ) -> Option<SubmissionIndex> {
1598 api_log!("Queue::on_submitted_work_done");
1599 self.lock_life().add_work_done_closure(closure)
1601 }
1602
1603 pub fn compact_blas(&self, blas: &Arc<Blas>) -> Result<Arc<Blas>, CompactBlasError> {
1604 profiling::scope!("Queue::compact_blas");
1605 api_log!("Queue::compact_blas");
1606
1607 let new_label = blas.label.clone() + " (compacted)";
1608
1609 self.device.check_is_valid()?;
1610 self.same_device_as(blas.as_ref())?;
1611
1612 let device = blas.device.clone();
1613
1614 let snatch_guard = device.snatchable_lock.read();
1615
1616 let BlasCompactState::Ready { size } = *blas.compacted_state.lock() else {
1617 return Err(CompactBlasError::BlasNotReady);
1618 };
1619
1620 let mut size_info = blas.size_info;
1621 size_info.acceleration_structure_size = size;
1622
1623 let mut pending_writes = self.pending_writes.lock();
1624 let cmd_buf_raw = pending_writes.activate();
1625
1626 let raw = unsafe {
1627 device
1628 .raw()
1629 .create_acceleration_structure(&hal::AccelerationStructureDescriptor {
1630 label: hal_label(Some(&new_label), device.instance_flags),
1631 size: size_info.acceleration_structure_size,
1632 format: hal::AccelerationStructureFormat::BottomLevel,
1633 allow_compaction: false,
1634 })
1635 }
1636 .map_err(DeviceError::from_hal)?;
1637
1638 let src_raw = blas.try_raw(&snatch_guard)?;
1639
1640 unsafe {
1641 cmd_buf_raw.copy_acceleration_structure_to_acceleration_structure(
1642 src_raw,
1643 raw.as_ref(),
1644 wgt::AccelerationStructureCopy::Compact,
1645 )
1646 };
1647
1648 let handle = unsafe {
1649 device
1650 .raw()
1651 .get_acceleration_structure_device_address(raw.as_ref())
1652 };
1653
1654 drop(snatch_guard);
1655
1656 let mut command_indices_lock = device.command_indices.write();
1657 command_indices_lock.next_acceleration_structure_build_command_index += 1;
1658 let built_index =
1659 NonZeroU64::new(command_indices_lock.next_acceleration_structure_build_command_index)
1660 .unwrap();
1661
1662 let new_blas = Arc::new(Blas {
1663 raw: Snatchable::new(raw),
1664 device: device.clone(),
1665 size_info,
1666 sizes: blas.sizes.clone(),
1667 flags: blas.flags & !AccelerationStructureFlags::ALLOW_COMPACTION,
1668 update_mode: blas.update_mode,
1669 built_index: RwLock::new(rank::BLAS_BUILT_INDEX, Some(built_index)),
1671 handle,
1672 label: new_label,
1673 tracking_data: TrackingData::new(blas.device.tracker_indices.blas_s.clone()),
1674 compaction_buffer: None,
1675 compacted_state: Mutex::new(rank::BLAS_COMPACTION_STATE, BlasCompactState::Compacted),
1676 });
1677
1678 pending_writes.insert_blas(blas);
1679 pending_writes.insert_blas(&new_blas);
1680
1681 Ok(new_blas)
1682 }
1683}
1684
1685impl Global {
1686 pub fn queue_write_buffer(
1687 &self,
1688 queue_id: QueueId,
1689 buffer_id: id::BufferId,
1690 buffer_offset: wgt::BufferAddress,
1691 data: &[u8],
1692 ) -> Result<(), QueueWriteError> {
1693 let queue = self.hub.queues.get(queue_id);
1694 let buffer = self.hub.buffers.get(buffer_id).get()?;
1695
1696 #[cfg(feature = "trace")]
1697 if let Some(ref mut trace) = *queue.device.trace.lock() {
1698 use crate::device::trace::DataKind;
1699 let size = data.len() as u64;
1700 let data = trace.make_binary(DataKind::Bin, data);
1701 trace.add(Action::WriteBuffer {
1702 id: buffer.to_trace(),
1703 data,
1704 offset: buffer_offset,
1705 size,
1706 queued: true,
1707 });
1708 }
1709
1710 queue.write_buffer(buffer, buffer_offset, data)
1711 }
1712
1713 pub fn queue_create_staging_buffer(
1714 &self,
1715 queue_id: QueueId,
1716 buffer_size: wgt::BufferSize,
1717 id_in: Option<id::StagingBufferId>,
1718 ) -> Result<(id::StagingBufferId, NonNull<u8>), QueueWriteError> {
1719 let queue = self.hub.queues.get(queue_id);
1720 let (staging_buffer, ptr) = queue.create_staging_buffer(buffer_size)?;
1721
1722 let fid = self.hub.staging_buffers.prepare(id_in);
1723 let id = fid.assign(staging_buffer);
1724
1725 Ok((id, ptr))
1726 }
1727
1728 pub fn queue_write_staging_buffer(
1729 &self,
1730 queue_id: QueueId,
1731 buffer_id: id::BufferId,
1732 buffer_offset: wgt::BufferAddress,
1733 staging_buffer_id: id::StagingBufferId,
1734 ) -> Result<(), QueueWriteError> {
1735 let queue = self.hub.queues.get(queue_id);
1736 let buffer = self.hub.buffers.get(buffer_id);
1737 let staging_buffer = self.hub.staging_buffers.remove(staging_buffer_id);
1738 queue.write_staging_buffer(buffer, buffer_offset, staging_buffer)
1739 }
1740
1741 pub fn queue_validate_write_buffer(
1742 &self,
1743 queue_id: QueueId,
1744 buffer_id: id::BufferId,
1745 buffer_offset: u64,
1746 buffer_size: wgt::BufferSize,
1747 ) -> Result<(), QueueWriteError> {
1748 let queue = self.hub.queues.get(queue_id);
1749 let buffer = self.hub.buffers.get(buffer_id);
1750 queue.validate_write_buffer(buffer, buffer_offset, buffer_size)
1751 }
1752
1753 pub fn queue_write_texture(
1754 &self,
1755 queue_id: QueueId,
1756 destination: &wgt::TexelCopyTextureInfo<id::TextureId>,
1757 data: &[u8],
1758 data_layout: &wgt::TexelCopyBufferLayout,
1759 size: &wgt::Extent3d,
1760 ) -> Result<(), QueueWriteError> {
1761 let queue = self.hub.queues.get(queue_id);
1762 let texture = self.hub.textures.get(destination.texture).get()?;
1763 let destination = wgt::TexelCopyTextureInfo {
1764 texture,
1765 mip_level: destination.mip_level,
1766 origin: destination.origin,
1767 aspect: destination.aspect,
1768 };
1769
1770 #[cfg(feature = "trace")]
1771 if let Some(ref mut trace) = *queue.device.trace.lock() {
1772 use crate::device::trace::DataKind;
1773 let data = trace.make_binary(DataKind::Bin, data);
1774 trace.add(Action::WriteTexture {
1775 to: destination.to_trace(),
1776 data,
1777 layout: *data_layout,
1778 size: *size,
1779 });
1780 }
1781
1782 queue.write_texture(destination, data, data_layout, size)
1783 }
1784
1785 #[cfg(webgl)]
1786 pub fn queue_copy_external_image_to_texture(
1787 &self,
1788 queue_id: QueueId,
1789 source: &wgt::CopyExternalImageSourceInfo,
1790 destination: crate::command::CopyExternalImageDestInfo,
1791 size: wgt::Extent3d,
1792 ) -> Result<(), QueueWriteError> {
1793 let queue = self.hub.queues.get(queue_id);
1794 let destination = wgt::CopyExternalImageDestInfo {
1795 texture: self.hub.textures.get(destination.texture),
1796 mip_level: destination.mip_level,
1797 origin: destination.origin,
1798 aspect: destination.aspect,
1799 color_space: destination.color_space,
1800 premultiplied_alpha: destination.premultiplied_alpha,
1801 };
1802 queue.copy_external_image_to_texture(source, destination, size)
1803 }
1804
1805 pub fn queue_submit(
1806 &self,
1807 queue_id: QueueId,
1808 command_buffer_ids: &[id::CommandBufferId],
1809 ) -> Result<SubmissionIndex, (SubmissionIndex, QueueSubmitError)> {
1810 let queue = self.hub.queues.get(queue_id);
1811 let command_buffer_guard = self.hub.command_buffers.read();
1812 let command_buffers = command_buffer_ids
1813 .iter()
1814 .map(|id| command_buffer_guard.get(*id))
1815 .collect::<Vec<_>>();
1816 drop(command_buffer_guard);
1817 queue.submit(&command_buffers)
1818 }
1819
1820 pub fn queue_get_timestamp_period(&self, queue_id: QueueId) -> f32 {
1821 let queue = self.hub.queues.get(queue_id);
1822
1823 if queue.device.timestamp_normalizer.get().unwrap().enabled() {
1824 return 1.0;
1825 }
1826
1827 queue.get_timestamp_period()
1828 }
1829
1830 pub fn queue_on_submitted_work_done(
1831 &self,
1832 queue_id: QueueId,
1833 closure: SubmittedWorkDoneClosure,
1834 ) -> SubmissionIndex {
1835 api_log!("Queue::on_submitted_work_done {queue_id:?}");
1836
1837 let queue = self.hub.queues.get(queue_id);
1839 let result = queue.on_submitted_work_done(closure);
1840 result.unwrap_or(0) }
1842
1843 pub fn queue_compact_blas(
1844 &self,
1845 queue_id: QueueId,
1846 blas_id: BlasId,
1847 id_in: Option<BlasId>,
1848 ) -> (BlasId, Option<u64>, Option<CompactBlasError>) {
1849 api_log!("Queue::compact_blas {queue_id:?}, {blas_id:?}");
1850
1851 let fid = self.hub.blas_s.prepare(id_in);
1852
1853 let queue = self.hub.queues.get(queue_id);
1854 let blas = self.hub.blas_s.get(blas_id);
1855 let device = &queue.device;
1856
1857 let error = 'error: {
1860 match device.require_features(wgpu_types::Features::EXPERIMENTAL_RAY_QUERY) {
1861 Ok(_) => {}
1862 Err(err) => break 'error err.into(),
1863 }
1864
1865 let blas = match blas.get() {
1866 Ok(blas) => blas,
1867 Err(err) => break 'error err.into(),
1868 };
1869
1870 let new_blas = match queue.compact_blas(&blas) {
1871 Ok(blas) => blas,
1872 Err(err) => break 'error err,
1873 };
1874
1875 let old_blas_size = blas.size_info.acceleration_structure_size;
1877 let new_blas_size = new_blas.size_info.acceleration_structure_size;
1878 let handle = new_blas.handle;
1879
1880 let id = fid.assign(Fallible::Valid(new_blas));
1881
1882 api_log!("CommandEncoder::compact_blas {blas_id:?} (size: {old_blas_size}) -> {id:?} (size: {new_blas_size})");
1883
1884 return (id, Some(handle), None);
1885 };
1886
1887 let id = fid.assign(Fallible::Invalid(Arc::new(error.to_string())));
1888
1889 (id, None, Some(error))
1890 }
1891}
1892
1893fn validate_command_buffer(
1894 command_buffer: &CommandBuffer,
1895 queue: &Queue,
1896 cmd_buf_data: &crate::command::CommandBufferMutable,
1897 snatch_guard: &SnatchGuard,
1898 submit_surface_textures_owned: &mut FastHashMap<*const Texture, Arc<Texture>>,
1899 used_surface_textures: &mut track::TextureUsageScope,
1900 command_index_guard: &mut RwLockWriteGuard<CommandIndices>,
1901) -> Result<(), QueueSubmitError> {
1902 command_buffer.same_device_as(queue)?;
1903
1904 {
1905 profiling::scope!("check resource state");
1906
1907 {
1908 profiling::scope!("buffers");
1909 for buffer in cmd_buf_data.trackers.buffers.used_resources() {
1910 buffer.check_destroyed(snatch_guard)?;
1911
1912 match *buffer.map_state.lock() {
1913 BufferMapState::Idle => (),
1914 _ => return Err(QueueSubmitError::BufferStillMapped(buffer.error_ident())),
1915 }
1916 }
1917 }
1918 {
1919 profiling::scope!("textures");
1920 for texture in cmd_buf_data.trackers.textures.used_resources() {
1921 let should_extend = match texture.try_inner(snatch_guard)? {
1922 TextureInner::Native { .. } => false,
1923 TextureInner::Surface { .. } => {
1924 submit_surface_textures_owned.insert(Arc::as_ptr(texture), texture.clone());
1926
1927 true
1928 }
1929 };
1930 if should_extend {
1931 unsafe {
1932 used_surface_textures
1933 .merge_single(texture, None, wgt::TextureUses::PRESENT)
1934 .unwrap();
1935 };
1936 }
1937 }
1938 }
1939 {
1943 profiling::scope!("bind groups");
1944 for bind_group in &cmd_buf_data.trackers.bind_groups {
1945 bind_group.try_raw(snatch_guard)?;
1947 }
1948 }
1949
1950 if let Err(e) =
1951 cmd_buf_data.validate_acceleration_structure_actions(snatch_guard, command_index_guard)
1952 {
1953 return Err(e.into());
1954 }
1955 }
1956 Ok(())
1957}