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