wgpu_core/
resource.rs

1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4    binding_model::BindGroup,
5    device::{
6        queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError,
7        DeviceMismatch, HostMap, MissingDownlevelFlags, MissingFeatures,
8    },
9    global::Global,
10    hal_api::HalApi,
11    id::{AdapterId, BufferId, CommandEncoderId, DeviceId, SurfaceId, TextureId, TextureViewId},
12    init_tracker::{BufferInitTracker, TextureInitTracker},
13    lock::{rank, Mutex, RwLock},
14    resource_log,
15    snatch::{SnatchGuard, Snatchable},
16    track::{SharedTrackerIndexAllocator, TextureSelector, TrackerIndex},
17    weak_vec::WeakVec,
18    Label, LabelHelpers, SubmissionIndex,
19};
20
21use smallvec::SmallVec;
22use thiserror::Error;
23
24use std::num::NonZeroU64;
25use std::{
26    borrow::{Borrow, Cow},
27    fmt::Debug,
28    mem::{self, ManuallyDrop},
29    ops::Range,
30    ptr::NonNull,
31    sync::Arc,
32};
33
34/// Information about the wgpu-core resource.
35///
36/// Each type representing a `wgpu-core` resource, like [`Device`],
37/// [`Buffer`], etc., contains a `ResourceInfo` which contains
38/// its latest submission index and label.
39///
40/// A resource may need to be retained for any of several reasons:
41/// and any lifetime logic will be handled by `Arc<Resource>` refcount
42///
43/// - The user may hold a reference to it (via a `wgpu::Buffer`, say).
44///
45/// - Other resources may depend on it (a texture view's backing
46///   texture, for example).
47///
48/// - It may be used by commands sent to the GPU that have not yet
49///   finished execution.
50///
51/// [`Device`]: crate::device::resource::Device
52/// [`Buffer`]: crate::resource::Buffer
53#[derive(Debug)]
54pub(crate) struct TrackingData {
55    tracker_index: TrackerIndex,
56    tracker_indices: Arc<SharedTrackerIndexAllocator>,
57}
58
59impl Drop for TrackingData {
60    fn drop(&mut self) {
61        self.tracker_indices.free(self.tracker_index);
62    }
63}
64
65impl TrackingData {
66    pub(crate) fn new(tracker_indices: Arc<SharedTrackerIndexAllocator>) -> Self {
67        Self {
68            tracker_index: tracker_indices.alloc(),
69            tracker_indices,
70        }
71    }
72
73    pub(crate) fn tracker_index(&self) -> TrackerIndex {
74        self.tracker_index
75    }
76}
77
78#[derive(Clone, Debug)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80pub struct ResourceErrorIdent {
81    r#type: Cow<'static, str>,
82    label: String,
83}
84
85impl std::fmt::Display for ResourceErrorIdent {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
87        write!(f, "{} with '{}' label", self.r#type, self.label)
88    }
89}
90
91pub trait ParentDevice: Labeled {
92    fn device(&self) -> &Arc<Device>;
93
94    fn is_equal(self: &Arc<Self>, other: &Arc<Self>) -> bool {
95        Arc::ptr_eq(self, other)
96    }
97
98    fn same_device_as<O: ParentDevice>(&self, other: &O) -> Result<(), DeviceError> {
99        if Arc::ptr_eq(self.device(), other.device()) {
100            Ok(())
101        } else {
102            Err(DeviceError::DeviceMismatch(Box::new(DeviceMismatch {
103                res: self.error_ident(),
104                res_device: self.device().error_ident(),
105                target: Some(other.error_ident()),
106                target_device: other.device().error_ident(),
107            })))
108        }
109    }
110
111    fn same_device(&self, device: &Device) -> Result<(), DeviceError> {
112        if std::ptr::eq(&**self.device(), device) {
113            Ok(())
114        } else {
115            Err(DeviceError::DeviceMismatch(Box::new(DeviceMismatch {
116                res: self.error_ident(),
117                res_device: self.device().error_ident(),
118                target: None,
119                target_device: device.error_ident(),
120            })))
121        }
122    }
123}
124
125#[macro_export]
126macro_rules! impl_parent_device {
127    ($ty:ident) => {
128        impl $crate::resource::ParentDevice for $ty {
129            fn device(&self) -> &Arc<Device> {
130                &self.device
131            }
132        }
133    };
134}
135
136pub trait ResourceType {
137    const TYPE: &'static str;
138}
139
140#[macro_export]
141macro_rules! impl_resource_type {
142    ($ty:ident) => {
143        impl $crate::resource::ResourceType for $ty {
144            const TYPE: &'static str = stringify!($ty);
145        }
146    };
147}
148
149pub trait Labeled: ResourceType {
150    /// Returns a string identifying this resource for logging and errors.
151    ///
152    /// It may be a user-provided string or it may be a placeholder from wgpu.
153    ///
154    /// It is non-empty unless the user-provided string was empty.
155    fn label(&self) -> &str;
156
157    fn error_ident(&self) -> ResourceErrorIdent {
158        ResourceErrorIdent {
159            r#type: Cow::Borrowed(Self::TYPE),
160            label: self.label().to_owned(),
161        }
162    }
163}
164
165#[macro_export]
166macro_rules! impl_labeled {
167    ($ty:ident) => {
168        impl $crate::resource::Labeled for $ty {
169            fn label(&self) -> &str {
170                &self.label
171            }
172        }
173    };
174}
175
176pub(crate) trait Trackable {
177    fn tracker_index(&self) -> TrackerIndex;
178}
179
180#[macro_export]
181macro_rules! impl_trackable {
182    ($ty:ident) => {
183        impl $crate::resource::Trackable for $ty {
184            fn tracker_index(&self) -> $crate::track::TrackerIndex {
185                self.tracking_data.tracker_index()
186            }
187        }
188    };
189}
190
191#[derive(Debug)]
192pub(crate) enum BufferMapState {
193    /// Mapped at creation.
194    Init { staging_buffer: StagingBuffer },
195    /// Waiting for GPU to be done before mapping
196    Waiting(BufferPendingMapping),
197    /// Mapped
198    Active {
199        mapping: hal::BufferMapping,
200        range: hal::MemoryRange,
201        host: HostMap,
202    },
203    /// Not mapped
204    Idle,
205}
206
207#[cfg(send_sync)]
208unsafe impl Send for BufferMapState {}
209#[cfg(send_sync)]
210unsafe impl Sync for BufferMapState {}
211
212#[cfg(send_sync)]
213pub type BufferMapCallback = Box<dyn FnOnce(BufferAccessResult) + Send + 'static>;
214#[cfg(not(send_sync))]
215pub type BufferMapCallback = Box<dyn FnOnce(BufferAccessResult) + 'static>;
216
217pub struct BufferMapOperation {
218    pub host: HostMap,
219    pub callback: Option<BufferMapCallback>,
220}
221
222impl Debug for BufferMapOperation {
223    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224        f.debug_struct("BufferMapOperation")
225            .field("host", &self.host)
226            .field("callback", &self.callback.as_ref().map(|_| "?"))
227            .finish()
228    }
229}
230
231#[derive(Clone, Debug, Error)]
232#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
233#[non_exhaustive]
234pub enum BufferAccessError {
235    #[error(transparent)]
236    Device(#[from] DeviceError),
237    #[error("Buffer map failed")]
238    Failed,
239    #[error(transparent)]
240    DestroyedResource(#[from] DestroyedResourceError),
241    #[error("Buffer is already mapped")]
242    AlreadyMapped,
243    #[error("Buffer map is pending")]
244    MapAlreadyPending,
245    #[error(transparent)]
246    MissingBufferUsage(#[from] MissingBufferUsageError),
247    #[error("Buffer is not mapped")]
248    NotMapped,
249    #[error(
250        "Buffer map range must start aligned to `MAP_ALIGNMENT` and end to `COPY_BUFFER_ALIGNMENT`"
251    )]
252    UnalignedRange,
253    #[error("Buffer offset invalid: offset {offset} must be multiple of 8")]
254    UnalignedOffset { offset: wgt::BufferAddress },
255    #[error("Buffer range size invalid: range_size {range_size} must be multiple of 4")]
256    UnalignedRangeSize { range_size: wgt::BufferAddress },
257    #[error("Buffer access out of bounds: index {index} would underrun the buffer (limit: {min})")]
258    OutOfBoundsUnderrun {
259        index: wgt::BufferAddress,
260        min: wgt::BufferAddress,
261    },
262    #[error(
263        "Buffer access out of bounds: last index {index} would overrun the buffer (limit: {max})"
264    )]
265    OutOfBoundsOverrun {
266        index: wgt::BufferAddress,
267        max: wgt::BufferAddress,
268    },
269    #[error("Buffer map range start {start} is greater than end {end}")]
270    NegativeRange {
271        start: wgt::BufferAddress,
272        end: wgt::BufferAddress,
273    },
274    #[error("Buffer map aborted")]
275    MapAborted,
276    #[error(transparent)]
277    InvalidResource(#[from] InvalidResourceError),
278}
279
280#[derive(Clone, Debug, Error)]
281#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
282#[error("Usage flags {actual:?} of {res} do not contain required usage flags {expected:?}")]
283pub struct MissingBufferUsageError {
284    pub(crate) res: ResourceErrorIdent,
285    pub(crate) actual: wgt::BufferUsages,
286    pub(crate) expected: wgt::BufferUsages,
287}
288
289#[derive(Clone, Debug, Error)]
290#[error("Usage flags {actual:?} of {res} do not contain required usage flags {expected:?}")]
291pub struct MissingTextureUsageError {
292    pub(crate) res: ResourceErrorIdent,
293    pub(crate) actual: wgt::TextureUsages,
294    pub(crate) expected: wgt::TextureUsages,
295}
296
297#[derive(Clone, Debug, Error)]
298#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
299#[error("{0} has been destroyed")]
300pub struct DestroyedResourceError(pub ResourceErrorIdent);
301
302#[derive(Clone, Debug, Error)]
303#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
304#[error("{0} is invalid")]
305pub struct InvalidResourceError(pub ResourceErrorIdent);
306
307pub enum Fallible<T: ParentDevice> {
308    Valid(Arc<T>),
309    Invalid(Arc<String>),
310}
311
312impl<T: ParentDevice> Fallible<T> {
313    pub fn get(self) -> Result<Arc<T>, InvalidResourceError> {
314        match self {
315            Fallible::Valid(v) => Ok(v),
316            Fallible::Invalid(label) => Err(InvalidResourceError(ResourceErrorIdent {
317                r#type: Cow::Borrowed(T::TYPE),
318                label: (*label).clone(),
319            })),
320        }
321    }
322}
323
324impl<T: ParentDevice> Clone for Fallible<T> {
325    fn clone(&self) -> Self {
326        match self {
327            Self::Valid(v) => Self::Valid(v.clone()),
328            Self::Invalid(l) => Self::Invalid(l.clone()),
329        }
330    }
331}
332
333impl<T: ParentDevice> ResourceType for Fallible<T> {
334    const TYPE: &'static str = T::TYPE;
335}
336
337impl<T: ParentDevice + crate::storage::StorageItem> crate::storage::StorageItem for Fallible<T> {
338    type Marker = T::Marker;
339}
340
341pub type BufferAccessResult = Result<(), BufferAccessError>;
342
343#[derive(Debug)]
344pub(crate) struct BufferPendingMapping {
345    pub(crate) range: Range<wgt::BufferAddress>,
346    pub(crate) op: BufferMapOperation,
347    // hold the parent alive while the mapping is active
348    pub(crate) _parent_buffer: Arc<Buffer>,
349}
350
351pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
352
353#[derive(Debug)]
354pub struct Buffer {
355    pub(crate) raw: Snatchable<Box<dyn hal::DynBuffer>>,
356    pub(crate) device: Arc<Device>,
357    pub(crate) usage: wgt::BufferUsages,
358    pub(crate) size: wgt::BufferAddress,
359    pub(crate) initialization_status: RwLock<BufferInitTracker>,
360    /// The `label` from the descriptor used to create the resource.
361    pub(crate) label: String,
362    pub(crate) tracking_data: TrackingData,
363    pub(crate) map_state: Mutex<BufferMapState>,
364    pub(crate) bind_groups: Mutex<WeakVec<BindGroup>>,
365    #[cfg(feature = "indirect-validation")]
366    pub(crate) raw_indirect_validation_bind_group: Snatchable<Box<dyn hal::DynBindGroup>>,
367}
368
369impl Drop for Buffer {
370    fn drop(&mut self) {
371        #[cfg(feature = "indirect-validation")]
372        if let Some(raw) = self.raw_indirect_validation_bind_group.take() {
373            unsafe {
374                self.device.raw().destroy_bind_group(raw);
375            }
376        }
377        if let Some(raw) = self.raw.take() {
378            resource_log!("Destroy raw {}", self.error_ident());
379            unsafe {
380                self.device.raw().destroy_buffer(raw);
381            }
382        }
383    }
384}
385
386impl Buffer {
387    pub(crate) fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a dyn hal::DynBuffer> {
388        self.raw.get(guard).map(|b| b.as_ref())
389    }
390
391    pub(crate) fn try_raw<'a>(
392        &'a self,
393        guard: &'a SnatchGuard,
394    ) -> Result<&'a dyn hal::DynBuffer, DestroyedResourceError> {
395        self.raw
396            .get(guard)
397            .map(|raw| raw.as_ref())
398            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
399    }
400
401    pub(crate) fn check_destroyed<'a>(
402        &'a self,
403        guard: &'a SnatchGuard,
404    ) -> Result<(), DestroyedResourceError> {
405        self.raw
406            .get(guard)
407            .map(|_| ())
408            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
409    }
410
411    /// Checks that the given buffer usage contains the required buffer usage,
412    /// returns an error otherwise.
413    pub(crate) fn check_usage(
414        &self,
415        expected: wgt::BufferUsages,
416    ) -> Result<(), MissingBufferUsageError> {
417        if self.usage.contains(expected) {
418            Ok(())
419        } else {
420            Err(MissingBufferUsageError {
421                res: self.error_ident(),
422                actual: self.usage,
423                expected,
424            })
425        }
426    }
427
428    /// Returns the mapping callback in case of error so that the callback can be fired outside
429    /// of the locks that are held in this function.
430    pub(crate) fn map_async(
431        self: &Arc<Self>,
432        offset: wgt::BufferAddress,
433        size: Option<wgt::BufferAddress>,
434        op: BufferMapOperation,
435    ) -> Result<SubmissionIndex, (BufferMapOperation, BufferAccessError)> {
436        let range_size = if let Some(size) = size {
437            size
438        } else if offset > self.size {
439            0
440        } else {
441            self.size - offset
442        };
443
444        if offset % wgt::MAP_ALIGNMENT != 0 {
445            return Err((op, BufferAccessError::UnalignedOffset { offset }));
446        }
447        if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
448            return Err((op, BufferAccessError::UnalignedRangeSize { range_size }));
449        }
450
451        let range = offset..(offset + range_size);
452
453        if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 {
454            return Err((op, BufferAccessError::UnalignedRange));
455        }
456
457        let (pub_usage, internal_use) = match op.host {
458            HostMap::Read => (wgt::BufferUsages::MAP_READ, hal::BufferUses::MAP_READ),
459            HostMap::Write => (wgt::BufferUsages::MAP_WRITE, hal::BufferUses::MAP_WRITE),
460        };
461
462        if let Err(e) = self.check_usage(pub_usage) {
463            return Err((op, e.into()));
464        }
465
466        if range.start > range.end {
467            return Err((
468                op,
469                BufferAccessError::NegativeRange {
470                    start: range.start,
471                    end: range.end,
472                },
473            ));
474        }
475        if range.end > self.size {
476            return Err((
477                op,
478                BufferAccessError::OutOfBoundsOverrun {
479                    index: range.end,
480                    max: self.size,
481                },
482            ));
483        }
484
485        let device = &self.device;
486        if let Err(e) = device.check_is_valid() {
487            return Err((op, e.into()));
488        }
489
490        {
491            let snatch_guard = device.snatchable_lock.read();
492            if let Err(e) = self.check_destroyed(&snatch_guard) {
493                return Err((op, e.into()));
494            }
495        }
496
497        {
498            let map_state = &mut *self.map_state.lock();
499            *map_state = match *map_state {
500                BufferMapState::Init { .. } | BufferMapState::Active { .. } => {
501                    return Err((op, BufferAccessError::AlreadyMapped));
502                }
503                BufferMapState::Waiting(_) => {
504                    return Err((op, BufferAccessError::MapAlreadyPending));
505                }
506                BufferMapState::Idle => BufferMapState::Waiting(BufferPendingMapping {
507                    range,
508                    op,
509                    _parent_buffer: self.clone(),
510                }),
511            };
512        }
513
514        // TODO: we are ignoring the transition here, I think we need to add a barrier
515        // at the end of the submission
516        device
517            .trackers
518            .lock()
519            .buffers
520            .set_single(self, internal_use);
521
522        let submit_index = if let Some(queue) = device.get_queue() {
523            queue.lock_life().map(self).unwrap_or(0) // '0' means no wait is necessary
524        } else {
525            // We can safely unwrap below since we just set the `map_state` to `BufferMapState::Waiting`.
526            let (mut operation, status) = self.map(&device.snatchable_lock.read()).unwrap();
527            if let Some(callback) = operation.callback.take() {
528                callback(status);
529            }
530            0
531        };
532
533        Ok(submit_index)
534    }
535
536    /// This function returns [`None`] only if [`Self::map_state`] is not [`BufferMapState::Waiting`].
537    #[must_use]
538    pub(crate) fn map(&self, snatch_guard: &SnatchGuard) -> Option<BufferMapPendingClosure> {
539        // This _cannot_ be inlined into the match. If it is, the lock will be held
540        // open through the whole match, resulting in a deadlock when we try to re-lock
541        // the buffer back to active.
542        let mapping = mem::replace(&mut *self.map_state.lock(), BufferMapState::Idle);
543        let pending_mapping = match mapping {
544            BufferMapState::Waiting(pending_mapping) => pending_mapping,
545            // Mapping cancelled
546            BufferMapState::Idle => return None,
547            // Mapping queued at least twice by map -> unmap -> map
548            // and was already successfully mapped below
549            BufferMapState::Active { .. } => {
550                *self.map_state.lock() = mapping;
551                return None;
552            }
553            _ => panic!("No pending mapping."),
554        };
555        let status = if pending_mapping.range.start != pending_mapping.range.end {
556            let host = pending_mapping.op.host;
557            let size = pending_mapping.range.end - pending_mapping.range.start;
558            match crate::device::map_buffer(
559                self,
560                pending_mapping.range.start,
561                size,
562                host,
563                snatch_guard,
564            ) {
565                Ok(mapping) => {
566                    *self.map_state.lock() = BufferMapState::Active {
567                        mapping,
568                        range: pending_mapping.range.clone(),
569                        host,
570                    };
571                    Ok(())
572                }
573                Err(e) => Err(e),
574            }
575        } else {
576            *self.map_state.lock() = BufferMapState::Active {
577                mapping: hal::BufferMapping {
578                    ptr: NonNull::dangling(),
579                    is_coherent: true,
580                },
581                range: pending_mapping.range,
582                host: pending_mapping.op.host,
583            };
584            Ok(())
585        };
586        Some((pending_mapping.op, status))
587    }
588
589    // Note: This must not be called while holding a lock.
590    pub(crate) fn unmap(
591        self: &Arc<Self>,
592        #[cfg(feature = "trace")] buffer_id: BufferId,
593    ) -> Result<(), BufferAccessError> {
594        if let Some((mut operation, status)) = self.unmap_inner(
595            #[cfg(feature = "trace")]
596            buffer_id,
597        )? {
598            if let Some(callback) = operation.callback.take() {
599                callback(status);
600            }
601        }
602
603        Ok(())
604    }
605
606    fn unmap_inner(
607        self: &Arc<Self>,
608        #[cfg(feature = "trace")] buffer_id: BufferId,
609    ) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> {
610        let device = &self.device;
611        let snatch_guard = device.snatchable_lock.read();
612        let raw_buf = self.try_raw(&snatch_guard)?;
613        match mem::replace(&mut *self.map_state.lock(), BufferMapState::Idle) {
614            BufferMapState::Init { staging_buffer } => {
615                #[cfg(feature = "trace")]
616                if let Some(ref mut trace) = *device.trace.lock() {
617                    let data = trace.make_binary("bin", staging_buffer.get_data());
618                    trace.add(trace::Action::WriteBuffer {
619                        id: buffer_id,
620                        data,
621                        range: 0..self.size,
622                        queued: true,
623                    });
624                }
625
626                let staging_buffer = staging_buffer.flush();
627
628                if let Some(queue) = device.get_queue() {
629                    let region = wgt::BufferSize::new(self.size).map(|size| hal::BufferCopy {
630                        src_offset: 0,
631                        dst_offset: 0,
632                        size,
633                    });
634                    let transition_src = hal::BufferBarrier {
635                        buffer: staging_buffer.raw(),
636                        usage: hal::StateTransition {
637                            from: hal::BufferUses::MAP_WRITE,
638                            to: hal::BufferUses::COPY_SRC,
639                        },
640                    };
641                    let transition_dst = hal::BufferBarrier::<dyn hal::DynBuffer> {
642                        buffer: raw_buf,
643                        usage: hal::StateTransition {
644                            from: hal::BufferUses::empty(),
645                            to: hal::BufferUses::COPY_DST,
646                        },
647                    };
648                    let mut pending_writes = queue.pending_writes.lock();
649                    let encoder = pending_writes.activate();
650                    unsafe {
651                        encoder.transition_buffers(&[transition_src, transition_dst]);
652                        if self.size > 0 {
653                            encoder.copy_buffer_to_buffer(
654                                staging_buffer.raw(),
655                                raw_buf,
656                                region.as_slice(),
657                            );
658                        }
659                    }
660                    pending_writes.consume(staging_buffer);
661                    pending_writes.insert_buffer(self);
662                }
663            }
664            BufferMapState::Idle => {
665                return Err(BufferAccessError::NotMapped);
666            }
667            BufferMapState::Waiting(pending) => {
668                return Ok(Some((pending.op, Err(BufferAccessError::MapAborted))));
669            }
670            BufferMapState::Active {
671                mapping,
672                range,
673                host,
674            } => {
675                #[allow(clippy::collapsible_if)]
676                if host == HostMap::Write {
677                    #[cfg(feature = "trace")]
678                    if let Some(ref mut trace) = *device.trace.lock() {
679                        let size = range.end - range.start;
680                        let data = trace.make_binary("bin", unsafe {
681                            std::slice::from_raw_parts(mapping.ptr.as_ptr(), size as usize)
682                        });
683                        trace.add(trace::Action::WriteBuffer {
684                            id: buffer_id,
685                            data,
686                            range: range.clone(),
687                            queued: false,
688                        });
689                    }
690                    if !mapping.is_coherent {
691                        unsafe { device.raw().flush_mapped_ranges(raw_buf, &[range]) };
692                    }
693                }
694                unsafe { device.raw().unmap_buffer(raw_buf) };
695            }
696        }
697        Ok(None)
698    }
699
700    pub(crate) fn destroy(self: &Arc<Self>) -> Result<(), DestroyError> {
701        let device = &self.device;
702
703        let temp = {
704            let mut snatch_guard = device.snatchable_lock.write();
705
706            let raw = match self.raw.snatch(&mut snatch_guard) {
707                Some(raw) => raw,
708                None => {
709                    return Err(DestroyError::AlreadyDestroyed);
710                }
711            };
712
713            #[cfg(feature = "indirect-validation")]
714            let raw_indirect_validation_bind_group = self
715                .raw_indirect_validation_bind_group
716                .snatch(&mut snatch_guard);
717
718            drop(snatch_guard);
719
720            let bind_groups = {
721                let mut guard = self.bind_groups.lock();
722                mem::take(&mut *guard)
723            };
724
725            queue::TempResource::DestroyedBuffer(DestroyedBuffer {
726                raw: ManuallyDrop::new(raw),
727                device: Arc::clone(&self.device),
728                label: self.label().to_owned(),
729                bind_groups,
730                #[cfg(feature = "indirect-validation")]
731                raw_indirect_validation_bind_group,
732            })
733        };
734
735        if let Some(queue) = device.get_queue() {
736            let mut pending_writes = queue.pending_writes.lock();
737            if pending_writes.contains_buffer(self) {
738                pending_writes.consume_temp(temp);
739            } else {
740                let mut life_lock = queue.lock_life();
741                let last_submit_index = life_lock.get_buffer_latest_submission_index(self);
742                if let Some(last_submit_index) = last_submit_index {
743                    life_lock.schedule_resource_destruction(temp, last_submit_index);
744                }
745            }
746        }
747
748        Ok(())
749    }
750}
751
752#[derive(Clone, Debug, Error)]
753#[non_exhaustive]
754pub enum CreateBufferError {
755    #[error(transparent)]
756    Device(#[from] DeviceError),
757    #[error("Failed to map buffer while creating: {0}")]
758    AccessError(#[from] BufferAccessError),
759    #[error("Buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
760    UnalignedSize,
761    #[error("Invalid usage flags {0:?}")]
762    InvalidUsage(wgt::BufferUsages),
763    #[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
764    UsageMismatch(wgt::BufferUsages),
765    #[error("Buffer size {requested} is greater than the maximum buffer size ({maximum})")]
766    MaxBufferSize { requested: u64, maximum: u64 },
767    #[error(transparent)]
768    MissingDownlevelFlags(#[from] MissingDownlevelFlags),
769    #[error("Failed to create bind group for indirect buffer validation: {0}")]
770    IndirectValidationBindGroup(DeviceError),
771}
772
773crate::impl_resource_type!(Buffer);
774crate::impl_labeled!(Buffer);
775crate::impl_parent_device!(Buffer);
776crate::impl_storage_item!(Buffer);
777crate::impl_trackable!(Buffer);
778
779/// A buffer that has been marked as destroyed and is staged for actual deletion soon.
780#[derive(Debug)]
781pub struct DestroyedBuffer {
782    raw: ManuallyDrop<Box<dyn hal::DynBuffer>>,
783    device: Arc<Device>,
784    label: String,
785    bind_groups: WeakVec<BindGroup>,
786    #[cfg(feature = "indirect-validation")]
787    raw_indirect_validation_bind_group: Option<Box<dyn hal::DynBindGroup>>,
788}
789
790impl DestroyedBuffer {
791    pub fn label(&self) -> &dyn Debug {
792        &self.label
793    }
794}
795
796impl Drop for DestroyedBuffer {
797    fn drop(&mut self) {
798        let mut deferred = self.device.deferred_destroy.lock();
799        deferred.push(DeferredDestroy::BindGroups(mem::take(
800            &mut self.bind_groups,
801        )));
802        drop(deferred);
803
804        #[cfg(feature = "indirect-validation")]
805        if let Some(raw) = self.raw_indirect_validation_bind_group.take() {
806            unsafe {
807                self.device.raw().destroy_bind_group(raw);
808            }
809        }
810
811        resource_log!("Destroy raw Buffer (destroyed) {:?}", self.label());
812        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
813        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
814        unsafe {
815            hal::DynDevice::destroy_buffer(self.device.raw(), raw);
816        }
817    }
818}
819
820#[cfg(send_sync)]
821unsafe impl Send for StagingBuffer {}
822#[cfg(send_sync)]
823unsafe impl Sync for StagingBuffer {}
824
825/// A temporary buffer, consumed by the command that uses it.
826///
827/// A [`StagingBuffer`] is designed for one-shot uploads of data to the GPU. It
828/// is always created mapped, and the command that uses it destroys the buffer
829/// when it is done.
830///
831/// [`StagingBuffer`]s can be created with [`queue_create_staging_buffer`] and
832/// used with [`queue_write_staging_buffer`]. They are also used internally by
833/// operations like [`queue_write_texture`] that need to upload data to the GPU,
834/// but that don't belong to any particular wgpu command buffer.
835///
836/// Used `StagingBuffer`s are accumulated in [`Device::pending_writes`], to be
837/// freed once their associated operation's queue submission has finished
838/// execution.
839///
840/// [`queue_create_staging_buffer`]: Global::queue_create_staging_buffer
841/// [`queue_write_staging_buffer`]: Global::queue_write_staging_buffer
842/// [`queue_write_texture`]: Global::queue_write_texture
843/// [`Device::pending_writes`]: crate::device::Device
844#[derive(Debug)]
845pub struct StagingBuffer {
846    raw: Box<dyn hal::DynBuffer>,
847    device: Arc<Device>,
848    pub(crate) size: wgt::BufferSize,
849    is_coherent: bool,
850    ptr: NonNull<u8>,
851}
852
853impl StagingBuffer {
854    pub(crate) fn new(device: &Arc<Device>, size: wgt::BufferSize) -> Result<Self, DeviceError> {
855        profiling::scope!("StagingBuffer::new");
856        let stage_desc = hal::BufferDescriptor {
857            label: crate::hal_label(Some("(wgpu internal) Staging"), device.instance_flags),
858            size: size.get(),
859            usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::COPY_SRC,
860            memory_flags: hal::MemoryFlags::TRANSIENT,
861        };
862
863        let raw = unsafe { device.raw().create_buffer(&stage_desc) }
864            .map_err(|e| device.handle_hal_error(e))?;
865        let mapping = unsafe { device.raw().map_buffer(raw.as_ref(), 0..size.get()) }
866            .map_err(|e| device.handle_hal_error(e))?;
867
868        let staging_buffer = StagingBuffer {
869            raw,
870            device: device.clone(),
871            size,
872            is_coherent: mapping.is_coherent,
873            ptr: mapping.ptr,
874        };
875
876        Ok(staging_buffer)
877    }
878
879    /// SAFETY: You must not call any functions of `self`
880    /// until you stopped using the returned pointer.
881    pub(crate) unsafe fn ptr(&self) -> NonNull<u8> {
882        self.ptr
883    }
884
885    #[cfg(feature = "trace")]
886    pub(crate) fn get_data(&self) -> &[u8] {
887        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.size.get() as usize) }
888    }
889
890    pub(crate) fn write_zeros(&mut self) {
891        unsafe { core::ptr::write_bytes(self.ptr.as_ptr(), 0, self.size.get() as usize) };
892    }
893
894    pub(crate) fn write(&mut self, data: &[u8]) {
895        assert!(data.len() >= self.size.get() as usize);
896        // SAFETY: With the assert above, all of `copy_nonoverlapping`'s
897        // requirements are satisfied.
898        unsafe {
899            core::ptr::copy_nonoverlapping(
900                data.as_ptr(),
901                self.ptr.as_ptr(),
902                self.size.get() as usize,
903            );
904        }
905    }
906
907    /// SAFETY: The offsets and size must be in-bounds.
908    pub(crate) unsafe fn write_with_offset(
909        &mut self,
910        data: &[u8],
911        src_offset: isize,
912        dst_offset: isize,
913        size: usize,
914    ) {
915        unsafe {
916            core::ptr::copy_nonoverlapping(
917                data.as_ptr().offset(src_offset),
918                self.ptr.as_ptr().offset(dst_offset),
919                size,
920            );
921        }
922    }
923
924    pub(crate) fn flush(self) -> FlushedStagingBuffer {
925        let device = self.device.raw();
926        if !self.is_coherent {
927            #[allow(clippy::single_range_in_vec_init)]
928            unsafe {
929                device.flush_mapped_ranges(self.raw.as_ref(), &[0..self.size.get()])
930            };
931        }
932        unsafe { device.unmap_buffer(self.raw.as_ref()) };
933
934        let StagingBuffer {
935            raw, device, size, ..
936        } = self;
937
938        FlushedStagingBuffer {
939            raw: ManuallyDrop::new(raw),
940            device,
941            size,
942        }
943    }
944}
945
946crate::impl_resource_type!(StagingBuffer);
947crate::impl_storage_item!(StagingBuffer);
948
949#[derive(Debug)]
950pub struct FlushedStagingBuffer {
951    raw: ManuallyDrop<Box<dyn hal::DynBuffer>>,
952    device: Arc<Device>,
953    pub(crate) size: wgt::BufferSize,
954}
955
956impl FlushedStagingBuffer {
957    pub(crate) fn raw(&self) -> &dyn hal::DynBuffer {
958        self.raw.as_ref()
959    }
960}
961
962impl Drop for FlushedStagingBuffer {
963    fn drop(&mut self) {
964        resource_log!("Destroy raw StagingBuffer");
965        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
966        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
967        unsafe { self.device.raw().destroy_buffer(raw) };
968    }
969}
970
971pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, Vec<wgt::TextureFormat>>;
972
973#[derive(Debug)]
974pub(crate) enum TextureInner {
975    Native {
976        raw: Box<dyn hal::DynTexture>,
977    },
978    Surface {
979        raw: Box<dyn hal::DynSurfaceTexture>,
980    },
981}
982
983impl TextureInner {
984    pub(crate) fn raw(&self) -> &dyn hal::DynTexture {
985        match self {
986            Self::Native { raw } => raw.as_ref(),
987            Self::Surface { raw, .. } => raw.as_ref().borrow(),
988        }
989    }
990}
991
992#[derive(Debug)]
993pub enum TextureClearMode {
994    BufferCopy,
995    // View for clear via RenderPass for every subsurface (mip/layer/slice)
996    RenderPass {
997        clear_views: SmallVec<[ManuallyDrop<Box<dyn hal::DynTextureView>>; 1]>,
998        is_color: bool,
999    },
1000    Surface {
1001        clear_view: ManuallyDrop<Box<dyn hal::DynTextureView>>,
1002    },
1003    // Texture can't be cleared, attempting to do so will cause panic.
1004    // (either because it is impossible for the type of texture or it is being destroyed)
1005    None,
1006}
1007
1008#[derive(Debug)]
1009pub struct Texture {
1010    pub(crate) inner: Snatchable<TextureInner>,
1011    pub(crate) device: Arc<Device>,
1012    pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
1013    pub(crate) hal_usage: hal::TextureUses,
1014    pub(crate) format_features: wgt::TextureFormatFeatures,
1015    pub(crate) initialization_status: RwLock<TextureInitTracker>,
1016    pub(crate) full_range: TextureSelector,
1017    /// The `label` from the descriptor used to create the resource.
1018    pub(crate) label: String,
1019    pub(crate) tracking_data: TrackingData,
1020    pub(crate) clear_mode: TextureClearMode,
1021    pub(crate) views: Mutex<WeakVec<TextureView>>,
1022    pub(crate) bind_groups: Mutex<WeakVec<BindGroup>>,
1023}
1024
1025impl Texture {
1026    pub(crate) fn new(
1027        device: &Arc<Device>,
1028        inner: TextureInner,
1029        hal_usage: hal::TextureUses,
1030        desc: &TextureDescriptor,
1031        format_features: wgt::TextureFormatFeatures,
1032        clear_mode: TextureClearMode,
1033        init: bool,
1034    ) -> Self {
1035        Texture {
1036            inner: Snatchable::new(inner),
1037            device: device.clone(),
1038            desc: desc.map_label(|_| ()),
1039            hal_usage,
1040            format_features,
1041            initialization_status: RwLock::new(
1042                rank::TEXTURE_INITIALIZATION_STATUS,
1043                if init {
1044                    TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count())
1045                } else {
1046                    TextureInitTracker::new(desc.mip_level_count, 0)
1047                },
1048            ),
1049            full_range: TextureSelector {
1050                mips: 0..desc.mip_level_count,
1051                layers: 0..desc.array_layer_count(),
1052            },
1053            label: desc.label.to_string(),
1054            tracking_data: TrackingData::new(device.tracker_indices.textures.clone()),
1055            clear_mode,
1056            views: Mutex::new(rank::TEXTURE_VIEWS, WeakVec::new()),
1057            bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, WeakVec::new()),
1058        }
1059    }
1060
1061    /// Checks that the given texture usage contains the required texture usage,
1062    /// returns an error otherwise.
1063    pub(crate) fn check_usage(
1064        &self,
1065        expected: wgt::TextureUsages,
1066    ) -> Result<(), MissingTextureUsageError> {
1067        if self.desc.usage.contains(expected) {
1068            Ok(())
1069        } else {
1070            Err(MissingTextureUsageError {
1071                res: self.error_ident(),
1072                actual: self.desc.usage,
1073                expected,
1074            })
1075        }
1076    }
1077}
1078
1079impl Drop for Texture {
1080    fn drop(&mut self) {
1081        match self.clear_mode {
1082            TextureClearMode::Surface {
1083                ref mut clear_view, ..
1084            } => {
1085                // SAFETY: We are in the Drop impl and we don't use clear_view anymore after this point.
1086                let raw = unsafe { ManuallyDrop::take(clear_view) };
1087                unsafe {
1088                    self.device.raw().destroy_texture_view(raw);
1089                }
1090            }
1091            TextureClearMode::RenderPass {
1092                ref mut clear_views,
1093                ..
1094            } => {
1095                clear_views.iter_mut().for_each(|clear_view| {
1096                    // SAFETY: We are in the Drop impl and we don't use clear_view anymore after this point.
1097                    let raw = unsafe { ManuallyDrop::take(clear_view) };
1098                    unsafe {
1099                        self.device.raw().destroy_texture_view(raw);
1100                    }
1101                });
1102            }
1103            _ => {}
1104        };
1105
1106        if let Some(TextureInner::Native { raw }) = self.inner.take() {
1107            resource_log!("Destroy raw {}", self.error_ident());
1108            unsafe {
1109                self.device.raw().destroy_texture(raw);
1110            }
1111        }
1112    }
1113}
1114
1115impl Texture {
1116    pub(crate) fn try_inner<'a>(
1117        &'a self,
1118        guard: &'a SnatchGuard,
1119    ) -> Result<&'a TextureInner, DestroyedResourceError> {
1120        self.inner
1121            .get(guard)
1122            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
1123    }
1124
1125    pub(crate) fn raw<'a>(
1126        &'a self,
1127        snatch_guard: &'a SnatchGuard,
1128    ) -> Option<&'a dyn hal::DynTexture> {
1129        Some(self.inner.get(snatch_guard)?.raw())
1130    }
1131
1132    pub(crate) fn try_raw<'a>(
1133        &'a self,
1134        guard: &'a SnatchGuard,
1135    ) -> Result<&'a dyn hal::DynTexture, DestroyedResourceError> {
1136        self.inner
1137            .get(guard)
1138            .map(|t| t.raw())
1139            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
1140    }
1141
1142    pub(crate) fn get_clear_view<'a>(
1143        clear_mode: &'a TextureClearMode,
1144        desc: &'a wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
1145        mip_level: u32,
1146        depth_or_layer: u32,
1147    ) -> &'a dyn hal::DynTextureView {
1148        match *clear_mode {
1149            TextureClearMode::BufferCopy => {
1150                panic!("Given texture is cleared with buffer copies, not render passes")
1151            }
1152            TextureClearMode::None => {
1153                panic!("Given texture can't be cleared")
1154            }
1155            TextureClearMode::Surface { ref clear_view, .. } => clear_view.as_ref(),
1156            TextureClearMode::RenderPass {
1157                ref clear_views, ..
1158            } => {
1159                let index = if desc.dimension == wgt::TextureDimension::D3 {
1160                    (0..mip_level).fold(0, |acc, mip| {
1161                        acc + (desc.size.depth_or_array_layers >> mip).max(1)
1162                    })
1163                } else {
1164                    mip_level * desc.size.depth_or_array_layers
1165                } + depth_or_layer;
1166                clear_views[index as usize].as_ref()
1167            }
1168        }
1169    }
1170
1171    pub(crate) fn destroy(self: &Arc<Self>) -> Result<(), DestroyError> {
1172        let device = &self.device;
1173
1174        let temp = {
1175            let raw = match self.inner.snatch(&mut device.snatchable_lock.write()) {
1176                Some(TextureInner::Native { raw }) => raw,
1177                Some(TextureInner::Surface { .. }) => {
1178                    return Ok(());
1179                }
1180                None => {
1181                    return Err(DestroyError::AlreadyDestroyed);
1182                }
1183            };
1184
1185            let views = {
1186                let mut guard = self.views.lock();
1187                mem::take(&mut *guard)
1188            };
1189
1190            let bind_groups = {
1191                let mut guard = self.bind_groups.lock();
1192                mem::take(&mut *guard)
1193            };
1194
1195            queue::TempResource::DestroyedTexture(DestroyedTexture {
1196                raw: ManuallyDrop::new(raw),
1197                views,
1198                bind_groups,
1199                device: Arc::clone(&self.device),
1200                label: self.label().to_owned(),
1201            })
1202        };
1203
1204        if let Some(queue) = device.get_queue() {
1205            let mut pending_writes = queue.pending_writes.lock();
1206            if pending_writes.contains_texture(self) {
1207                pending_writes.consume_temp(temp);
1208            } else {
1209                let mut life_lock = queue.lock_life();
1210                let last_submit_index = life_lock.get_texture_latest_submission_index(self);
1211                if let Some(last_submit_index) = last_submit_index {
1212                    life_lock.schedule_resource_destruction(temp, last_submit_index);
1213                }
1214            }
1215        }
1216
1217        Ok(())
1218    }
1219}
1220
1221impl Global {
1222    /// # Safety
1223    ///
1224    /// - The raw buffer handle must not be manually destroyed
1225    pub unsafe fn buffer_as_hal<A: HalApi, F: FnOnce(Option<&A::Buffer>) -> R, R>(
1226        &self,
1227        id: BufferId,
1228        hal_buffer_callback: F,
1229    ) -> R {
1230        profiling::scope!("Buffer::as_hal");
1231
1232        let hub = &self.hub;
1233
1234        if let Ok(buffer) = hub.buffers.get(id).get() {
1235            let snatch_guard = buffer.device.snatchable_lock.read();
1236            let hal_buffer = buffer
1237                .raw(&snatch_guard)
1238                .and_then(|b| b.as_any().downcast_ref());
1239            hal_buffer_callback(hal_buffer)
1240        } else {
1241            hal_buffer_callback(None)
1242        }
1243    }
1244
1245    /// # Safety
1246    ///
1247    /// - The raw texture handle must not be manually destroyed
1248    pub unsafe fn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>) -> R, R>(
1249        &self,
1250        id: TextureId,
1251        hal_texture_callback: F,
1252    ) -> R {
1253        profiling::scope!("Texture::as_hal");
1254
1255        let hub = &self.hub;
1256
1257        if let Ok(texture) = hub.textures.get(id).get() {
1258            let snatch_guard = texture.device.snatchable_lock.read();
1259            let hal_texture = texture.raw(&snatch_guard);
1260            let hal_texture = hal_texture
1261                .as_ref()
1262                .and_then(|it| it.as_any().downcast_ref());
1263            hal_texture_callback(hal_texture)
1264        } else {
1265            hal_texture_callback(None)
1266        }
1267    }
1268
1269    /// # Safety
1270    ///
1271    /// - The raw texture view handle must not be manually destroyed
1272    pub unsafe fn texture_view_as_hal<A: HalApi, F: FnOnce(Option<&A::TextureView>) -> R, R>(
1273        &self,
1274        id: TextureViewId,
1275        hal_texture_view_callback: F,
1276    ) -> R {
1277        profiling::scope!("TextureView::as_hal");
1278
1279        let hub = &self.hub;
1280
1281        if let Ok(texture_view) = hub.texture_views.get(id).get() {
1282            let snatch_guard = texture_view.device.snatchable_lock.read();
1283            let hal_texture_view = texture_view.raw(&snatch_guard);
1284            let hal_texture_view = hal_texture_view
1285                .as_ref()
1286                .and_then(|it| it.as_any().downcast_ref());
1287            hal_texture_view_callback(hal_texture_view)
1288        } else {
1289            hal_texture_view_callback(None)
1290        }
1291    }
1292
1293    /// # Safety
1294    ///
1295    /// - The raw adapter handle must not be manually destroyed
1296    pub unsafe fn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
1297        &self,
1298        id: AdapterId,
1299        hal_adapter_callback: F,
1300    ) -> R {
1301        profiling::scope!("Adapter::as_hal");
1302
1303        let hub = &self.hub;
1304        let adapter = hub.adapters.get(id);
1305        let hal_adapter = adapter.raw.adapter.as_any().downcast_ref();
1306
1307        hal_adapter_callback(hal_adapter)
1308    }
1309
1310    /// # Safety
1311    ///
1312    /// - The raw device handle must not be manually destroyed
1313    pub unsafe fn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
1314        &self,
1315        id: DeviceId,
1316        hal_device_callback: F,
1317    ) -> R {
1318        profiling::scope!("Device::as_hal");
1319
1320        let device = self.hub.devices.get(id);
1321        let hal_device = device.raw().as_any().downcast_ref();
1322
1323        hal_device_callback(hal_device)
1324    }
1325
1326    /// # Safety
1327    ///
1328    /// - The raw fence handle must not be manually destroyed
1329    pub unsafe fn device_fence_as_hal<A: HalApi, F: FnOnce(Option<&A::Fence>) -> R, R>(
1330        &self,
1331        id: DeviceId,
1332        hal_fence_callback: F,
1333    ) -> R {
1334        profiling::scope!("Device::fence_as_hal");
1335
1336        let device = self.hub.devices.get(id);
1337        let fence = device.fence.read();
1338        hal_fence_callback(fence.as_any().downcast_ref())
1339    }
1340
1341    /// # Safety
1342    /// - The raw surface handle must not be manually destroyed
1343    pub unsafe fn surface_as_hal<A: HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
1344        &self,
1345        id: SurfaceId,
1346        hal_surface_callback: F,
1347    ) -> R {
1348        profiling::scope!("Surface::as_hal");
1349
1350        let surface = self.surfaces.get(id);
1351        let hal_surface = surface
1352            .raw(A::VARIANT)
1353            .and_then(|surface| surface.as_any().downcast_ref());
1354
1355        hal_surface_callback(hal_surface)
1356    }
1357
1358    /// # Safety
1359    ///
1360    /// - The raw command encoder handle must not be manually destroyed
1361    pub unsafe fn command_encoder_as_hal_mut<
1362        A: HalApi,
1363        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
1364        R,
1365    >(
1366        &self,
1367        id: CommandEncoderId,
1368        hal_command_encoder_callback: F,
1369    ) -> R {
1370        profiling::scope!("CommandEncoder::as_hal");
1371
1372        let hub = &self.hub;
1373
1374        let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
1375        let mut cmd_buf_data = cmd_buf.data.lock();
1376        let cmd_buf_data_guard = cmd_buf_data.record();
1377
1378        if let Ok(mut cmd_buf_data_guard) = cmd_buf_data_guard {
1379            let cmd_buf_raw = cmd_buf_data_guard
1380                .encoder
1381                .open()
1382                .ok()
1383                .and_then(|encoder| encoder.as_any_mut().downcast_mut());
1384            let ret = hal_command_encoder_callback(cmd_buf_raw);
1385            cmd_buf_data_guard.mark_successful();
1386            ret
1387        } else {
1388            hal_command_encoder_callback(None)
1389        }
1390    }
1391}
1392
1393/// A texture that has been marked as destroyed and is staged for actual deletion soon.
1394#[derive(Debug)]
1395pub struct DestroyedTexture {
1396    raw: ManuallyDrop<Box<dyn hal::DynTexture>>,
1397    views: WeakVec<TextureView>,
1398    bind_groups: WeakVec<BindGroup>,
1399    device: Arc<Device>,
1400    label: String,
1401}
1402
1403impl DestroyedTexture {
1404    pub fn label(&self) -> &dyn Debug {
1405        &self.label
1406    }
1407}
1408
1409impl Drop for DestroyedTexture {
1410    fn drop(&mut self) {
1411        let device = &self.device;
1412
1413        let mut deferred = device.deferred_destroy.lock();
1414        deferred.push(DeferredDestroy::TextureViews(mem::take(&mut self.views)));
1415        deferred.push(DeferredDestroy::BindGroups(mem::take(
1416            &mut self.bind_groups,
1417        )));
1418        drop(deferred);
1419
1420        resource_log!("Destroy raw Texture (destroyed) {:?}", self.label());
1421        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
1422        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
1423        unsafe {
1424            self.device.raw().destroy_texture(raw);
1425        }
1426    }
1427}
1428
1429#[derive(Clone, Copy, Debug)]
1430pub enum TextureErrorDimension {
1431    X,
1432    Y,
1433    Z,
1434}
1435
1436#[derive(Clone, Debug, Error)]
1437#[non_exhaustive]
1438pub enum TextureDimensionError {
1439    #[error("Dimension {0:?} is zero")]
1440    Zero(TextureErrorDimension),
1441    #[error("Dimension {dim:?} value {given} exceeds the limit of {limit}")]
1442    LimitExceeded {
1443        dim: TextureErrorDimension,
1444        given: u32,
1445        limit: u32,
1446    },
1447    #[error("Sample count {0} is invalid")]
1448    InvalidSampleCount(u32),
1449    #[error("Width {width} is not a multiple of {format:?}'s block width ({block_width})")]
1450    NotMultipleOfBlockWidth {
1451        width: u32,
1452        block_width: u32,
1453        format: wgt::TextureFormat,
1454    },
1455    #[error("Height {height} is not a multiple of {format:?}'s block height ({block_height})")]
1456    NotMultipleOfBlockHeight {
1457        height: u32,
1458        block_height: u32,
1459        format: wgt::TextureFormat,
1460    },
1461    #[error(
1462        "Width {width} is not a multiple of {format:?}'s width multiple requirement ({multiple})"
1463    )]
1464    WidthNotMultipleOf {
1465        width: u32,
1466        multiple: u32,
1467        format: wgt::TextureFormat,
1468    },
1469    #[error("Height {height} is not a multiple of {format:?}'s height multiple requirement ({multiple})")]
1470    HeightNotMultipleOf {
1471        height: u32,
1472        multiple: u32,
1473        format: wgt::TextureFormat,
1474    },
1475    #[error("Multisampled texture depth or array layers must be 1, got {0}")]
1476    MultisampledDepthOrArrayLayer(u32),
1477}
1478
1479#[derive(Clone, Debug, Error)]
1480#[non_exhaustive]
1481pub enum CreateTextureError {
1482    #[error(transparent)]
1483    Device(#[from] DeviceError),
1484    #[error(transparent)]
1485    CreateTextureView(#[from] CreateTextureViewError),
1486    #[error("Invalid usage flags {0:?}")]
1487    InvalidUsage(wgt::TextureUsages),
1488    #[error(transparent)]
1489    InvalidDimension(#[from] TextureDimensionError),
1490    #[error("Depth texture ({1:?}) can't be created as {0:?}")]
1491    InvalidDepthDimension(wgt::TextureDimension, wgt::TextureFormat),
1492    #[error("Compressed texture ({1:?}) can't be created as {0:?}")]
1493    InvalidCompressedDimension(wgt::TextureDimension, wgt::TextureFormat),
1494    #[error(
1495        "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}"
1496    )]
1497    InvalidMipLevelCount { requested: u32, maximum: u32 },
1498    #[error(
1499        "Texture usages {0:?} are not allowed on a texture of type {1:?}{downlevel_suffix}",
1500        downlevel_suffix = if *.2 { " due to downlevel restrictions" } else { "" }
1501    )]
1502    InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat, bool),
1503    #[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
1504    InvalidViewFormat(wgt::TextureFormat, wgt::TextureFormat),
1505    #[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")]
1506    InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension),
1507    #[error("Texture usage STORAGE_BINDING is not allowed for multisampled textures")]
1508    InvalidMultisampledStorageBinding,
1509    #[error("Format {0:?} does not support multisampling")]
1510    InvalidMultisampledFormat(wgt::TextureFormat),
1511    #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
1512    InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
1513    #[error("Multisampled textures must have RENDER_ATTACHMENT usage")]
1514    MultisampledNotRenderAttachment,
1515    #[error("Texture format {0:?} can't be used due to missing features")]
1516    MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
1517    #[error(transparent)]
1518    MissingDownlevelFlags(#[from] MissingDownlevelFlags),
1519}
1520
1521crate::impl_resource_type!(Texture);
1522crate::impl_labeled!(Texture);
1523crate::impl_parent_device!(Texture);
1524crate::impl_storage_item!(Texture);
1525crate::impl_trackable!(Texture);
1526
1527impl Borrow<TextureSelector> for Texture {
1528    fn borrow(&self) -> &TextureSelector {
1529        &self.full_range
1530    }
1531}
1532
1533/// Describes a [`TextureView`].
1534#[derive(Clone, Debug, Default, Eq, PartialEq)]
1535#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1536#[cfg_attr(feature = "serde", serde(default))]
1537pub struct TextureViewDescriptor<'a> {
1538    /// Debug label of the texture view.
1539    ///
1540    /// This will show up in graphics debuggers for easy identification.
1541    pub label: Label<'a>,
1542    /// Format of the texture view, or `None` for the same format as the texture
1543    /// itself.
1544    ///
1545    /// At this time, it must be the same the underlying format of the texture.
1546    pub format: Option<wgt::TextureFormat>,
1547    /// The dimension of the texture view.
1548    ///
1549    /// - For 1D textures, this must be `D1`.
1550    /// - For 2D textures it must be one of `D2`, `D2Array`, `Cube`, or `CubeArray`.
1551    /// - For 3D textures it must be `D3`.
1552    pub dimension: Option<wgt::TextureViewDimension>,
1553    /// The allowed usage(s) for the texture view. Must be a subset of the usage flags of the texture.
1554    /// If not provided, defaults to the full set of usage flags of the texture.
1555    pub usage: Option<wgt::TextureUsages>,
1556    /// Range within the texture that is accessible via this view.
1557    pub range: wgt::ImageSubresourceRange,
1558}
1559
1560#[derive(Debug)]
1561pub(crate) struct HalTextureViewDescriptor {
1562    pub texture_format: wgt::TextureFormat,
1563    pub format: wgt::TextureFormat,
1564    pub usage: wgt::TextureUsages,
1565    pub dimension: wgt::TextureViewDimension,
1566    pub range: wgt::ImageSubresourceRange,
1567}
1568
1569impl HalTextureViewDescriptor {
1570    pub fn aspects(&self) -> hal::FormatAspects {
1571        hal::FormatAspects::new(self.texture_format, self.range.aspect)
1572    }
1573}
1574
1575#[derive(Debug, Copy, Clone, Error)]
1576pub enum TextureViewNotRenderableReason {
1577    #[error("The texture this view references doesn't include the RENDER_ATTACHMENT usage. Provided usages: {0:?}")]
1578    Usage(wgt::TextureUsages),
1579    #[error("The dimension of this texture view is not 2D. View dimension: {0:?}")]
1580    Dimension(wgt::TextureViewDimension),
1581    #[error("This texture view has more than one mipmap level. View mipmap levels: {0:?}")]
1582    MipLevelCount(u32),
1583    #[error("This texture view has more than one array layer. View array layers: {0:?}")]
1584    ArrayLayerCount(u32),
1585    #[error(
1586        "The aspects of this texture view are a subset of the aspects in the original texture. Aspects: {0:?}"
1587    )]
1588    Aspects(hal::FormatAspects),
1589}
1590
1591#[derive(Debug)]
1592pub struct TextureView {
1593    pub(crate) raw: Snatchable<Box<dyn hal::DynTextureView>>,
1594    // if it's a surface texture - it's none
1595    pub(crate) parent: Arc<Texture>,
1596    pub(crate) device: Arc<Device>,
1597    pub(crate) desc: HalTextureViewDescriptor,
1598    pub(crate) format_features: wgt::TextureFormatFeatures,
1599    /// This is `Err` only if the texture view is not renderable
1600    pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>,
1601    pub(crate) samples: u32,
1602    pub(crate) selector: TextureSelector,
1603    /// The `label` from the descriptor used to create the resource.
1604    pub(crate) label: String,
1605    pub(crate) tracking_data: TrackingData,
1606}
1607
1608impl Drop for TextureView {
1609    fn drop(&mut self) {
1610        if let Some(raw) = self.raw.take() {
1611            resource_log!("Destroy raw {}", self.error_ident());
1612            unsafe {
1613                self.device.raw().destroy_texture_view(raw);
1614            }
1615        }
1616    }
1617}
1618
1619impl TextureView {
1620    pub(crate) fn raw<'a>(
1621        &'a self,
1622        snatch_guard: &'a SnatchGuard,
1623    ) -> Option<&'a dyn hal::DynTextureView> {
1624        self.raw.get(snatch_guard).map(|it| it.as_ref())
1625    }
1626
1627    pub(crate) fn try_raw<'a>(
1628        &'a self,
1629        guard: &'a SnatchGuard,
1630    ) -> Result<&'a dyn hal::DynTextureView, DestroyedResourceError> {
1631        self.raw
1632            .get(guard)
1633            .map(|it| it.as_ref())
1634            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
1635    }
1636
1637    /// Checks that the given texture usage contains the required texture usage,
1638    /// returns an error otherwise.
1639    pub(crate) fn check_usage(
1640        &self,
1641        expected: wgt::TextureUsages,
1642    ) -> Result<(), MissingTextureUsageError> {
1643        if self.desc.usage.contains(expected) {
1644            Ok(())
1645        } else {
1646            Err(MissingTextureUsageError {
1647                res: self.error_ident(),
1648                actual: self.desc.usage,
1649                expected,
1650            })
1651        }
1652    }
1653}
1654
1655#[derive(Clone, Debug, Error)]
1656#[non_exhaustive]
1657pub enum CreateTextureViewError {
1658    #[error(transparent)]
1659    Device(#[from] DeviceError),
1660    #[error(transparent)]
1661    DestroyedResource(#[from] DestroyedResourceError),
1662    #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")]
1663    InvalidTextureViewDimension {
1664        view: wgt::TextureViewDimension,
1665        texture: wgt::TextureDimension,
1666    },
1667    #[error("Texture view format `{0:?}` is not renderable")]
1668    TextureViewFormatNotRenderable(wgt::TextureFormat),
1669    #[error("Texture view format `{0:?}` is not storage bindable")]
1670    TextureViewFormatNotStorage(wgt::TextureFormat),
1671    #[error("Invalid texture view usage `{view:?}` with texture of usage `{texture:?}`")]
1672    InvalidTextureViewUsage {
1673        view: wgt::TextureUsages,
1674        texture: wgt::TextureUsages,
1675    },
1676    #[error("Invalid texture view dimension `{0:?}` of a multisampled texture")]
1677    InvalidMultisampledTextureViewDimension(wgt::TextureViewDimension),
1678    #[error("Invalid texture depth `{depth}` for texture view of dimension `Cubemap`. Cubemap views must use images of size 6.")]
1679    InvalidCubemapTextureDepth { depth: u32 },
1680    #[error("Invalid texture depth `{depth}` for texture view of dimension `CubemapArray`. Cubemap views must use images with sizes which are a multiple of 6.")]
1681    InvalidCubemapArrayTextureDepth { depth: u32 },
1682    #[error("Source texture width and height must be equal for a texture view of dimension `Cube`/`CubeArray`")]
1683    InvalidCubeTextureViewSize,
1684    #[error("Mip level count is 0")]
1685    ZeroMipLevelCount,
1686    #[error("Array layer count is 0")]
1687    ZeroArrayLayerCount,
1688    #[error(
1689        "TextureView mip level count + base mip level {requested} must be <= Texture mip level count {total}"
1690    )]
1691    TooManyMipLevels { requested: u32, total: u32 },
1692    #[error("TextureView array layer count + base array layer {requested} must be <= Texture depth/array layer count {total}")]
1693    TooManyArrayLayers { requested: u32, total: u32 },
1694    #[error("Requested array layer count {requested} is not valid for the target view dimension {dim:?}")]
1695    InvalidArrayLayerCount {
1696        requested: u32,
1697        dim: wgt::TextureViewDimension,
1698    },
1699    #[error("Aspect {requested_aspect:?} is not in the source texture format {texture_format:?}")]
1700    InvalidAspect {
1701        texture_format: wgt::TextureFormat,
1702        requested_aspect: wgt::TextureAspect,
1703    },
1704    #[error("Unable to view texture {texture:?} as {view:?}")]
1705    FormatReinterpretation {
1706        texture: wgt::TextureFormat,
1707        view: wgt::TextureFormat,
1708    },
1709    #[error(transparent)]
1710    InvalidResource(#[from] InvalidResourceError),
1711    #[error(transparent)]
1712    MissingFeatures(#[from] MissingFeatures),
1713}
1714
1715#[derive(Clone, Debug, Error)]
1716#[non_exhaustive]
1717pub enum TextureViewDestroyError {}
1718
1719crate::impl_resource_type!(TextureView);
1720crate::impl_labeled!(TextureView);
1721crate::impl_parent_device!(TextureView);
1722crate::impl_storage_item!(TextureView);
1723crate::impl_trackable!(TextureView);
1724
1725/// Describes a [`Sampler`]
1726#[derive(Clone, Debug, PartialEq)]
1727#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1728pub struct SamplerDescriptor<'a> {
1729    /// Debug label of the sampler.
1730    ///
1731    /// This will show up in graphics debuggers for easy identification.
1732    pub label: Label<'a>,
1733    /// How to deal with out of bounds accesses in the u (i.e. x) direction
1734    pub address_modes: [wgt::AddressMode; 3],
1735    /// How to filter the texture when it needs to be magnified (made larger)
1736    pub mag_filter: wgt::FilterMode,
1737    /// How to filter the texture when it needs to be minified (made smaller)
1738    pub min_filter: wgt::FilterMode,
1739    /// How to filter between mip map levels
1740    pub mipmap_filter: wgt::FilterMode,
1741    /// Minimum level of detail (i.e. mip level) to use
1742    pub lod_min_clamp: f32,
1743    /// Maximum level of detail (i.e. mip level) to use
1744    pub lod_max_clamp: f32,
1745    /// If this is enabled, this is a comparison sampler using the given comparison function.
1746    pub compare: Option<wgt::CompareFunction>,
1747    /// Must be at least 1. If this is not 1, all filter modes must be linear.
1748    pub anisotropy_clamp: u16,
1749    /// Border color to use when address_mode is
1750    /// [`AddressMode::ClampToBorder`](wgt::AddressMode::ClampToBorder)
1751    pub border_color: Option<wgt::SamplerBorderColor>,
1752}
1753
1754#[derive(Debug)]
1755pub struct Sampler {
1756    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynSampler>>,
1757    pub(crate) device: Arc<Device>,
1758    /// The `label` from the descriptor used to create the resource.
1759    pub(crate) label: String,
1760    pub(crate) tracking_data: TrackingData,
1761    /// `true` if this is a comparison sampler
1762    pub(crate) comparison: bool,
1763    /// `true` if this is a filtering sampler
1764    pub(crate) filtering: bool,
1765}
1766
1767impl Drop for Sampler {
1768    fn drop(&mut self) {
1769        resource_log!("Destroy raw {}", self.error_ident());
1770        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
1771        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
1772        unsafe {
1773            self.device.raw().destroy_sampler(raw);
1774        }
1775    }
1776}
1777
1778impl Sampler {
1779    pub(crate) fn raw(&self) -> &dyn hal::DynSampler {
1780        self.raw.as_ref()
1781    }
1782}
1783
1784#[derive(Copy, Clone)]
1785pub enum SamplerFilterErrorType {
1786    MagFilter,
1787    MinFilter,
1788    MipmapFilter,
1789}
1790
1791impl Debug for SamplerFilterErrorType {
1792    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1793        match *self {
1794            SamplerFilterErrorType::MagFilter => write!(f, "magFilter"),
1795            SamplerFilterErrorType::MinFilter => write!(f, "minFilter"),
1796            SamplerFilterErrorType::MipmapFilter => write!(f, "mipmapFilter"),
1797        }
1798    }
1799}
1800
1801#[derive(Clone, Debug, Error)]
1802#[non_exhaustive]
1803pub enum CreateSamplerError {
1804    #[error(transparent)]
1805    Device(#[from] DeviceError),
1806    #[error("Invalid lodMinClamp: {0}. Must be greater or equal to 0.0")]
1807    InvalidLodMinClamp(f32),
1808    #[error("Invalid lodMaxClamp: {lod_max_clamp}. Must be greater or equal to lodMinClamp (which is {lod_min_clamp}).")]
1809    InvalidLodMaxClamp {
1810        lod_min_clamp: f32,
1811        lod_max_clamp: f32,
1812    },
1813    #[error("Invalid anisotropic clamp: {0}. Must be at least 1.")]
1814    InvalidAnisotropy(u16),
1815    #[error("Invalid filter mode for {filter_type:?}: {filter_mode:?}. When anistropic clamp is not 1 (it is {anisotropic_clamp}), all filter modes must be linear.")]
1816    InvalidFilterModeWithAnisotropy {
1817        filter_type: SamplerFilterErrorType,
1818        filter_mode: wgt::FilterMode,
1819        anisotropic_clamp: u16,
1820    },
1821    #[error(transparent)]
1822    MissingFeatures(#[from] MissingFeatures),
1823}
1824
1825crate::impl_resource_type!(Sampler);
1826crate::impl_labeled!(Sampler);
1827crate::impl_parent_device!(Sampler);
1828crate::impl_storage_item!(Sampler);
1829crate::impl_trackable!(Sampler);
1830
1831#[derive(Clone, Debug, Error)]
1832#[non_exhaustive]
1833pub enum CreateQuerySetError {
1834    #[error(transparent)]
1835    Device(#[from] DeviceError),
1836    #[error("QuerySets cannot be made with zero queries")]
1837    ZeroCount,
1838    #[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")]
1839    TooManyQueries { count: u32, maximum: u32 },
1840    #[error(transparent)]
1841    MissingFeatures(#[from] MissingFeatures),
1842}
1843
1844pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
1845
1846#[derive(Debug)]
1847pub struct QuerySet {
1848    pub(crate) raw: ManuallyDrop<Box<dyn hal::DynQuerySet>>,
1849    pub(crate) device: Arc<Device>,
1850    /// The `label` from the descriptor used to create the resource.
1851    pub(crate) label: String,
1852    pub(crate) tracking_data: TrackingData,
1853    pub(crate) desc: wgt::QuerySetDescriptor<()>,
1854}
1855
1856impl Drop for QuerySet {
1857    fn drop(&mut self) {
1858        resource_log!("Destroy raw {}", self.error_ident());
1859        // SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
1860        let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
1861        unsafe {
1862            self.device.raw().destroy_query_set(raw);
1863        }
1864    }
1865}
1866
1867crate::impl_resource_type!(QuerySet);
1868crate::impl_labeled!(QuerySet);
1869crate::impl_parent_device!(QuerySet);
1870crate::impl_storage_item!(QuerySet);
1871crate::impl_trackable!(QuerySet);
1872
1873impl QuerySet {
1874    pub(crate) fn raw(&self) -> &dyn hal::DynQuerySet {
1875        self.raw.as_ref()
1876    }
1877}
1878
1879#[derive(Clone, Debug, Error)]
1880#[non_exhaustive]
1881pub enum DestroyError {
1882    #[error("Resource is already destroyed")]
1883    AlreadyDestroyed,
1884    #[error(transparent)]
1885    InvalidResource(#[from] InvalidResourceError),
1886}
1887
1888pub type BlasDescriptor<'a> = wgt::CreateBlasDescriptor<Label<'a>>;
1889pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;
1890
1891pub(crate) trait AccelerationStructure: Trackable {
1892    fn try_raw<'a>(
1893        &'a self,
1894        guard: &'a SnatchGuard,
1895    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError>;
1896}
1897
1898#[derive(Debug)]
1899pub struct Blas {
1900    pub(crate) raw: Snatchable<Box<dyn hal::DynAccelerationStructure>>,
1901    pub(crate) device: Arc<Device>,
1902    pub(crate) size_info: hal::AccelerationStructureBuildSizes,
1903    pub(crate) sizes: wgt::BlasGeometrySizeDescriptors,
1904    pub(crate) flags: wgt::AccelerationStructureFlags,
1905    pub(crate) update_mode: wgt::AccelerationStructureUpdateMode,
1906    pub(crate) built_index: RwLock<Option<NonZeroU64>>,
1907    pub(crate) handle: u64,
1908    /// The `label` from the descriptor used to create the resource.
1909    pub(crate) label: String,
1910    pub(crate) tracking_data: TrackingData,
1911}
1912
1913impl Drop for Blas {
1914    fn drop(&mut self) {
1915        resource_log!("Destroy raw {}", self.error_ident());
1916        // SAFETY: We are in the Drop impl, and we don't use self.raw anymore after this point.
1917        if let Some(raw) = self.raw.take() {
1918            unsafe {
1919                self.device.raw().destroy_acceleration_structure(raw);
1920            }
1921        }
1922    }
1923}
1924
1925impl AccelerationStructure for Blas {
1926    fn try_raw<'a>(
1927        &'a self,
1928        guard: &'a SnatchGuard,
1929    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> {
1930        self.raw
1931            .get(guard)
1932            .map(|raw| raw.as_ref())
1933            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
1934    }
1935}
1936
1937crate::impl_resource_type!(Blas);
1938crate::impl_labeled!(Blas);
1939crate::impl_parent_device!(Blas);
1940crate::impl_storage_item!(Blas);
1941crate::impl_trackable!(Blas);
1942
1943#[derive(Debug)]
1944pub struct Tlas {
1945    pub(crate) raw: Snatchable<Box<dyn hal::DynAccelerationStructure>>,
1946    pub(crate) device: Arc<Device>,
1947    pub(crate) size_info: hal::AccelerationStructureBuildSizes,
1948    pub(crate) max_instance_count: u32,
1949    pub(crate) flags: wgt::AccelerationStructureFlags,
1950    pub(crate) update_mode: wgt::AccelerationStructureUpdateMode,
1951    pub(crate) built_index: RwLock<Option<NonZeroU64>>,
1952    pub(crate) dependencies: RwLock<Vec<Arc<Blas>>>,
1953    pub(crate) instance_buffer: ManuallyDrop<Box<dyn hal::DynBuffer>>,
1954    /// The `label` from the descriptor used to create the resource.
1955    pub(crate) label: String,
1956    pub(crate) tracking_data: TrackingData,
1957}
1958
1959impl Drop for Tlas {
1960    fn drop(&mut self) {
1961        unsafe {
1962            resource_log!("Destroy raw {}", self.error_ident());
1963            if let Some(structure) = self.raw.take() {
1964                self.device.raw().destroy_acceleration_structure(structure);
1965            }
1966            let buffer = ManuallyDrop::take(&mut self.instance_buffer);
1967            self.device.raw().destroy_buffer(buffer);
1968        }
1969    }
1970}
1971
1972impl AccelerationStructure for Tlas {
1973    fn try_raw<'a>(
1974        &'a self,
1975        guard: &'a SnatchGuard,
1976    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> {
1977        self.raw
1978            .get(guard)
1979            .map(|raw| raw.as_ref())
1980            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
1981    }
1982}
1983
1984crate::impl_resource_type!(Tlas);
1985crate::impl_labeled!(Tlas);
1986crate::impl_parent_device!(Tlas);
1987crate::impl_storage_item!(Tlas);
1988crate::impl_trackable!(Tlas);