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#[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 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 Init { staging_buffer: StagingBuffer },
195 Waiting(BufferPendingMapping),
197 Active {
199 mapping: hal::BufferMapping,
200 range: hal::MemoryRange,
201 host: HostMap,
202 },
203 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 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 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 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 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 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) } else {
525 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 #[must_use]
538 pub(crate) fn map(&self, snatch_guard: &SnatchGuard) -> Option<BufferMapPendingClosure> {
539 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 BufferMapState::Idle => return None,
547 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 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#[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 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#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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#[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 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#[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 pub label: Label<'a>,
1542 pub format: Option<wgt::TextureFormat>,
1547 pub dimension: Option<wgt::TextureViewDimension>,
1553 pub usage: Option<wgt::TextureUsages>,
1556 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 pub(crate) parent: Arc<Texture>,
1596 pub(crate) device: Arc<Device>,
1597 pub(crate) desc: HalTextureViewDescriptor,
1598 pub(crate) format_features: wgt::TextureFormatFeatures,
1599 pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>,
1601 pub(crate) samples: u32,
1602 pub(crate) selector: TextureSelector,
1603 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 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#[derive(Clone, Debug, PartialEq)]
1727#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1728pub struct SamplerDescriptor<'a> {
1729 pub label: Label<'a>,
1733 pub address_modes: [wgt::AddressMode; 3],
1735 pub mag_filter: wgt::FilterMode,
1737 pub min_filter: wgt::FilterMode,
1739 pub mipmap_filter: wgt::FilterMode,
1741 pub lod_min_clamp: f32,
1743 pub lod_max_clamp: f32,
1745 pub compare: Option<wgt::CompareFunction>,
1747 pub anisotropy_clamp: u16,
1749 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 pub(crate) label: String,
1760 pub(crate) tracking_data: TrackingData,
1761 pub(crate) comparison: bool,
1763 pub(crate) filtering: bool,
1765}
1766
1767impl Drop for Sampler {
1768 fn drop(&mut self) {
1769 resource_log!("Destroy raw {}", self.error_ident());
1770 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 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 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 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 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 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);