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