1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4 binding_model::BindGroup,
5 device::{
6 queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError, HostMap,
7 MissingDownlevelFlags, MissingFeatures,
8 },
9 global::Global,
10 hal_api::HalApi,
11 id::{
12 AdapterId, BufferId, CommandEncoderId, DeviceId, Id, Marker, SurfaceId, TextureId,
13 TextureViewId,
14 },
15 init_tracker::{BufferInitTracker, TextureInitTracker},
16 lock::{Mutex, RwLock},
17 resource, resource_log,
18 snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable},
19 track::{SharedTrackerIndexAllocator, TextureSelector, TrackerIndex},
20 validation::MissingBufferUsageError,
21 Label, SubmissionIndex,
22};
23
24use hal::CommandEncoder;
25use smallvec::SmallVec;
26use thiserror::Error;
27use wgt::WasmNotSendSync;
28
29use std::{
30 borrow::Borrow,
31 fmt::Debug,
32 iter, mem,
33 ops::Range,
34 ptr::NonNull,
35 sync::{
36 atomic::{AtomicUsize, Ordering},
37 Arc, Weak,
38 },
39};
40
41#[derive(Debug)]
61pub(crate) struct ResourceInfo<T: Resource> {
62 id: Option<Id<T::Marker>>,
63 tracker_index: TrackerIndex,
64 tracker_indices: Option<Arc<SharedTrackerIndexAllocator>>,
65 submission_index: AtomicUsize,
73
74 pub(crate) label: String,
76}
77
78impl<T: Resource> Drop for ResourceInfo<T> {
79 fn drop(&mut self) {
80 if let Some(indices) = &self.tracker_indices {
81 indices.free(self.tracker_index);
82 }
83 }
84}
85
86impl<T: Resource> ResourceInfo<T> {
87 #[allow(unused_variables)]
88 pub(crate) fn new(
89 label: &str,
90 tracker_indices: Option<Arc<SharedTrackerIndexAllocator>>,
91 ) -> Self {
92 let tracker_index = tracker_indices
93 .as_ref()
94 .map(|indices| indices.alloc())
95 .unwrap_or(TrackerIndex::INVALID);
96 Self {
97 id: None,
98 tracker_index,
99 tracker_indices,
100 submission_index: AtomicUsize::new(0),
101 label: label.to_string(),
102 }
103 }
104
105 pub(crate) fn label(&self) -> &dyn Debug
106 where
107 Id<T::Marker>: Debug,
108 {
109 if !self.label.is_empty() {
110 return &self.label;
111 }
112
113 if let Some(id) = &self.id {
114 return id;
115 }
116
117 &""
118 }
119
120 pub(crate) fn id(&self) -> Id<T::Marker> {
121 self.id.unwrap()
122 }
123
124 pub(crate) fn tracker_index(&self) -> TrackerIndex {
125 debug_assert!(self.tracker_index != TrackerIndex::INVALID);
126 self.tracker_index
127 }
128
129 pub(crate) fn set_id(&mut self, id: Id<T::Marker>) {
130 self.id = Some(id);
131 }
132
133 pub(crate) fn use_at(&self, submit_index: SubmissionIndex) {
136 self.submission_index
137 .store(submit_index as _, Ordering::Release);
138 }
139
140 pub(crate) fn submission_index(&self) -> SubmissionIndex {
141 self.submission_index.load(Ordering::Acquire) as _
142 }
143}
144
145pub(crate) type ResourceType = &'static str;
146
147pub(crate) trait Resource: 'static + Sized + WasmNotSendSync {
148 type Marker: Marker;
149 const TYPE: ResourceType;
150 fn as_info(&self) -> &ResourceInfo<Self>;
151 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self>;
152 fn label(&self) -> String {
153 self.as_info().label.clone()
154 }
155 fn ref_count(self: &Arc<Self>) -> usize {
156 Arc::strong_count(self)
157 }
158 fn is_unique(self: &Arc<Self>) -> bool {
159 self.ref_count() == 1
160 }
161 fn is_equal(&self, other: &Self) -> bool {
162 self.as_info().id().unzip() == other.as_info().id().unzip()
163 }
164}
165
166#[repr(C)]
170#[derive(Debug)]
171pub enum BufferMapAsyncStatus {
172 Success,
176 AlreadyMapped,
180 MapAlreadyPending,
182 Error,
184 Aborted,
187 ContextLost,
189 Invalid,
191 InvalidRange,
193 InvalidAlignment,
195 InvalidUsageFlags,
197}
198
199#[derive(Debug)]
200pub(crate) enum BufferMapState<A: HalApi> {
201 Init {
203 ptr: NonNull<u8>,
204 stage_buffer: Arc<Buffer<A>>,
205 needs_flush: bool,
206 },
207 Waiting(BufferPendingMapping<A>),
209 Active {
211 ptr: NonNull<u8>,
212 range: hal::MemoryRange,
213 host: HostMap,
214 },
215 Idle,
217}
218
219#[cfg(send_sync)]
220unsafe impl<A: HalApi> Send for BufferMapState<A> {}
221#[cfg(send_sync)]
222unsafe impl<A: HalApi> Sync for BufferMapState<A> {}
223
224#[repr(C)]
225pub struct BufferMapCallbackC {
226 pub callback: unsafe extern "C" fn(status: BufferMapAsyncStatus, user_data: *mut u8),
227 pub user_data: *mut u8,
228}
229
230#[cfg(send_sync)]
231unsafe impl Send for BufferMapCallbackC {}
232
233#[derive(Debug)]
234pub struct BufferMapCallback {
235 inner: BufferMapCallbackInner,
238}
239
240#[cfg(send_sync)]
241type BufferMapCallbackCallback = Box<dyn FnOnce(BufferAccessResult) + Send + 'static>;
242#[cfg(not(send_sync))]
243type BufferMapCallbackCallback = Box<dyn FnOnce(BufferAccessResult) + 'static>;
244
245enum BufferMapCallbackInner {
246 Rust { callback: BufferMapCallbackCallback },
247 C { inner: BufferMapCallbackC },
248}
249
250impl Debug for BufferMapCallbackInner {
251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252 match *self {
253 BufferMapCallbackInner::Rust { callback: _ } => f.debug_struct("Rust").finish(),
254 BufferMapCallbackInner::C { inner: _ } => f.debug_struct("C").finish(),
255 }
256 }
257}
258
259impl BufferMapCallback {
260 pub fn from_rust(callback: BufferMapCallbackCallback) -> Self {
261 Self {
262 inner: BufferMapCallbackInner::Rust { callback },
263 }
264 }
265
266 pub unsafe fn from_c(inner: BufferMapCallbackC) -> Self {
274 Self {
275 inner: BufferMapCallbackInner::C { inner },
276 }
277 }
278
279 pub(crate) fn call(self, result: BufferAccessResult) {
280 match self.inner {
281 BufferMapCallbackInner::Rust { callback } => {
282 callback(result);
283 }
284 BufferMapCallbackInner::C { inner } => unsafe {
286 let status = match result {
287 Ok(()) => BufferMapAsyncStatus::Success,
288 Err(BufferAccessError::Device(_)) => BufferMapAsyncStatus::ContextLost,
289 Err(BufferAccessError::Invalid) | Err(BufferAccessError::Destroyed) => {
290 BufferMapAsyncStatus::Invalid
291 }
292 Err(BufferAccessError::AlreadyMapped) => BufferMapAsyncStatus::AlreadyMapped,
293 Err(BufferAccessError::MapAlreadyPending) => {
294 BufferMapAsyncStatus::MapAlreadyPending
295 }
296 Err(BufferAccessError::MissingBufferUsage(_)) => {
297 BufferMapAsyncStatus::InvalidUsageFlags
298 }
299 Err(BufferAccessError::UnalignedRange)
300 | Err(BufferAccessError::UnalignedRangeSize { .. })
301 | Err(BufferAccessError::UnalignedOffset { .. }) => {
302 BufferMapAsyncStatus::InvalidAlignment
303 }
304 Err(BufferAccessError::OutOfBoundsUnderrun { .. })
305 | Err(BufferAccessError::OutOfBoundsOverrun { .. })
306 | Err(BufferAccessError::NegativeRange { .. }) => {
307 BufferMapAsyncStatus::InvalidRange
308 }
309 Err(_) => BufferMapAsyncStatus::Error,
310 };
311
312 (inner.callback)(status, inner.user_data);
313 },
314 }
315 }
316}
317
318#[derive(Debug)]
319pub struct BufferMapOperation {
320 pub host: HostMap,
321 pub callback: Option<BufferMapCallback>,
322}
323
324#[derive(Clone, Debug, Error)]
325#[non_exhaustive]
326pub enum BufferAccessError {
327 #[error(transparent)]
328 Device(#[from] DeviceError),
329 #[error("Buffer map failed")]
330 Failed,
331 #[error("Buffer is invalid")]
332 Invalid,
333 #[error("Buffer is destroyed")]
334 Destroyed,
335 #[error("Buffer is already mapped")]
336 AlreadyMapped,
337 #[error("Buffer map is pending")]
338 MapAlreadyPending,
339 #[error(transparent)]
340 MissingBufferUsage(#[from] MissingBufferUsageError),
341 #[error("Buffer is not mapped")]
342 NotMapped,
343 #[error(
344 "Buffer map range must start aligned to `MAP_ALIGNMENT` and end to `COPY_BUFFER_ALIGNMENT`"
345 )]
346 UnalignedRange,
347 #[error("Buffer offset invalid: offset {offset} must be multiple of 8")]
348 UnalignedOffset { offset: wgt::BufferAddress },
349 #[error("Buffer range size invalid: range_size {range_size} must be multiple of 4")]
350 UnalignedRangeSize { range_size: wgt::BufferAddress },
351 #[error("Buffer access out of bounds: index {index} would underrun the buffer (limit: {min})")]
352 OutOfBoundsUnderrun {
353 index: wgt::BufferAddress,
354 min: wgt::BufferAddress,
355 },
356 #[error(
357 "Buffer access out of bounds: last index {index} would overrun the buffer (limit: {max})"
358 )]
359 OutOfBoundsOverrun {
360 index: wgt::BufferAddress,
361 max: wgt::BufferAddress,
362 },
363 #[error("Buffer map range start {start} is greater than end {end}")]
364 NegativeRange {
365 start: wgt::BufferAddress,
366 end: wgt::BufferAddress,
367 },
368 #[error("Buffer map aborted")]
369 MapAborted,
370}
371
372pub type BufferAccessResult = Result<(), BufferAccessError>;
373
374#[derive(Debug)]
375pub(crate) struct BufferPendingMapping<A: HalApi> {
376 pub(crate) range: Range<wgt::BufferAddress>,
377 pub(crate) op: BufferMapOperation,
378 pub(crate) _parent_buffer: Arc<Buffer<A>>,
380}
381
382pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
383
384#[derive(Debug)]
385pub struct Buffer<A: HalApi> {
386 pub(crate) raw: Snatchable<A::Buffer>,
387 pub(crate) device: Arc<Device<A>>,
388 pub(crate) usage: wgt::BufferUsages,
389 pub(crate) size: wgt::BufferAddress,
390 pub(crate) initialization_status: RwLock<BufferInitTracker>,
391 pub(crate) sync_mapped_writes: Mutex<Option<hal::MemoryRange>>,
392 pub(crate) info: ResourceInfo<Buffer<A>>,
393 pub(crate) map_state: Mutex<BufferMapState<A>>,
394 pub(crate) bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
395}
396
397impl<A: HalApi> Drop for Buffer<A> {
398 fn drop(&mut self) {
399 if let Some(raw) = self.raw.take() {
400 resource_log!("Destroy raw Buffer (dropped) {:?}", self.info.label());
401
402 #[cfg(feature = "trace")]
403 if let Some(t) = self.device.trace.lock().as_mut() {
404 t.add(trace::Action::DestroyBuffer(self.info.id()));
405 }
406
407 unsafe {
408 use hal::Device;
409 self.device.raw().destroy_buffer(raw);
410 }
411 }
412 }
413}
414
415impl<A: HalApi> Buffer<A> {
416 pub(crate) fn raw(&self, guard: &SnatchGuard) -> Option<&A::Buffer> {
417 self.raw.get(guard)
418 }
419
420 pub(crate) fn is_destroyed(&self, guard: &SnatchGuard) -> bool {
421 self.raw.get(guard).is_none()
422 }
423
424 pub(crate) fn unmap(self: &Arc<Self>) -> Result<(), BufferAccessError> {
426 if let Some((mut operation, status)) = self.unmap_inner()? {
427 if let Some(callback) = operation.callback.take() {
428 callback.call(status);
429 }
430 }
431
432 Ok(())
433 }
434
435 fn unmap_inner(self: &Arc<Self>) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> {
436 use hal::Device;
437
438 let device = &self.device;
439 let snatch_guard = device.snatchable_lock.read();
440 let raw_buf = self
441 .raw(&snatch_guard)
442 .ok_or(BufferAccessError::Destroyed)?;
443 let buffer_id = self.info.id();
444 log::debug!("Buffer {:?} map state -> Idle", buffer_id);
445 match mem::replace(&mut *self.map_state.lock(), resource::BufferMapState::Idle) {
446 resource::BufferMapState::Init {
447 ptr,
448 stage_buffer,
449 needs_flush,
450 } => {
451 #[cfg(feature = "trace")]
452 if let Some(ref mut trace) = *device.trace.lock() {
453 let data = trace.make_binary("bin", unsafe {
454 std::slice::from_raw_parts(ptr.as_ptr(), self.size as usize)
455 });
456 trace.add(trace::Action::WriteBuffer {
457 id: buffer_id,
458 data,
459 range: 0..self.size,
460 queued: true,
461 });
462 }
463 let _ = ptr;
464 if needs_flush {
465 unsafe {
466 device.raw().flush_mapped_ranges(
467 stage_buffer.raw(&snatch_guard).unwrap(),
468 iter::once(0..self.size),
469 );
470 }
471 }
472
473 self.info
474 .use_at(device.active_submission_index.load(Ordering::Relaxed) + 1);
475 let region = wgt::BufferSize::new(self.size).map(|size| hal::BufferCopy {
476 src_offset: 0,
477 dst_offset: 0,
478 size,
479 });
480 let transition_src = hal::BufferBarrier {
481 buffer: stage_buffer.raw(&snatch_guard).unwrap(),
482 usage: hal::BufferUses::MAP_WRITE..hal::BufferUses::COPY_SRC,
483 };
484 let transition_dst = hal::BufferBarrier {
485 buffer: raw_buf,
486 usage: hal::BufferUses::empty()..hal::BufferUses::COPY_DST,
487 };
488 let mut pending_writes = device.pending_writes.lock();
489 let pending_writes = pending_writes.as_mut().unwrap();
490 let encoder = pending_writes.activate();
491 unsafe {
492 encoder.transition_buffers(
493 iter::once(transition_src).chain(iter::once(transition_dst)),
494 );
495 if self.size > 0 {
496 encoder.copy_buffer_to_buffer(
497 stage_buffer.raw(&snatch_guard).unwrap(),
498 raw_buf,
499 region.into_iter(),
500 );
501 }
502 }
503 pending_writes.consume_temp(queue::TempResource::Buffer(stage_buffer));
504 pending_writes.dst_buffers.insert(buffer_id, self.clone());
505 }
506 resource::BufferMapState::Idle => {
507 return Err(BufferAccessError::NotMapped);
508 }
509 resource::BufferMapState::Waiting(pending) => {
510 return Ok(Some((pending.op, Err(BufferAccessError::MapAborted))));
511 }
512 resource::BufferMapState::Active { ptr, range, host } => {
513 if host == HostMap::Write {
514 #[cfg(feature = "trace")]
515 if let Some(ref mut trace) = *device.trace.lock() {
516 let size = range.end - range.start;
517 let data = trace.make_binary("bin", unsafe {
518 std::slice::from_raw_parts(ptr.as_ptr(), size as usize)
519 });
520 trace.add(trace::Action::WriteBuffer {
521 id: buffer_id,
522 data,
523 range: range.clone(),
524 queued: false,
525 });
526 }
527 let _ = (ptr, range);
528 }
529 unsafe {
530 device
531 .raw()
532 .unmap_buffer(raw_buf)
533 .map_err(DeviceError::from)?
534 };
535 }
536 }
537 Ok(None)
538 }
539
540 pub(crate) fn destroy(self: &Arc<Self>) -> Result<(), DestroyError> {
541 let device = &self.device;
542 let buffer_id = self.info.id();
543
544 #[cfg(feature = "trace")]
545 if let Some(ref mut trace) = *device.trace.lock() {
546 trace.add(trace::Action::FreeBuffer(buffer_id));
547 }
548
549 let temp = {
550 let snatch_guard = device.snatchable_lock.write();
551 let raw = match self.raw.snatch(snatch_guard) {
552 Some(raw) => raw,
553 None => {
554 return Err(resource::DestroyError::AlreadyDestroyed);
555 }
556 };
557
558 let bind_groups = {
559 let mut guard = self.bind_groups.lock();
560 std::mem::take(&mut *guard)
561 };
562
563 queue::TempResource::DestroyedBuffer(Arc::new(DestroyedBuffer {
564 raw: Some(raw),
565 device: Arc::clone(&self.device),
566 submission_index: self.info.submission_index(),
567 id: self.info.id.unwrap(),
568 tracker_index: self.info.tracker_index(),
569 label: self.info.label.clone(),
570 bind_groups,
571 }))
572 };
573
574 let mut pending_writes = device.pending_writes.lock();
575 let pending_writes = pending_writes.as_mut().unwrap();
576 if pending_writes.dst_buffers.contains_key(&buffer_id) {
577 pending_writes.temp_resources.push(temp);
578 } else {
579 let last_submit_index = self.info.submission_index();
580 device
581 .lock_life()
582 .schedule_resource_destruction(temp, last_submit_index);
583 }
584
585 Ok(())
586 }
587}
588
589#[derive(Clone, Debug, Error)]
590#[non_exhaustive]
591pub enum CreateBufferError {
592 #[error(transparent)]
593 Device(#[from] DeviceError),
594 #[error("Failed to map buffer while creating: {0}")]
595 AccessError(#[from] BufferAccessError),
596 #[error("Buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
597 UnalignedSize,
598 #[error("Invalid usage flags {0:?}")]
599 InvalidUsage(wgt::BufferUsages),
600 #[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
601 UsageMismatch(wgt::BufferUsages),
602 #[error("Buffer size {requested} is greater than the maximum buffer size ({maximum})")]
603 MaxBufferSize { requested: u64, maximum: u64 },
604 #[error(transparent)]
605 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
606}
607
608impl<A: HalApi> Resource for Buffer<A> {
609 const TYPE: ResourceType = "Buffer";
610
611 type Marker = crate::id::markers::Buffer;
612
613 fn as_info(&self) -> &ResourceInfo<Self> {
614 &self.info
615 }
616
617 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
618 &mut self.info
619 }
620}
621
622#[derive(Debug)]
624pub struct DestroyedBuffer<A: HalApi> {
625 raw: Option<A::Buffer>,
626 device: Arc<Device<A>>,
627 label: String,
628 pub(crate) id: BufferId,
629 pub(crate) tracker_index: TrackerIndex,
630 pub(crate) submission_index: u64,
631 bind_groups: Vec<Weak<BindGroup<A>>>,
632}
633
634impl<A: HalApi> DestroyedBuffer<A> {
635 pub fn label(&self) -> &dyn Debug {
636 if !self.label.is_empty() {
637 return &self.label;
638 }
639
640 &self.id
641 }
642}
643
644impl<A: HalApi> Drop for DestroyedBuffer<A> {
645 fn drop(&mut self) {
646 let mut deferred = self.device.deferred_destroy.lock();
647 for bind_group in self.bind_groups.drain(..) {
648 deferred.push(DeferredDestroy::BindGroup(bind_group));
649 }
650 drop(deferred);
651
652 if let Some(raw) = self.raw.take() {
653 resource_log!("Destroy raw Buffer (destroyed) {:?}", self.label());
654
655 #[cfg(feature = "trace")]
656 if let Some(t) = self.device.trace.lock().as_mut() {
657 t.add(trace::Action::DestroyBuffer(self.id));
658 }
659
660 unsafe {
661 use hal::Device;
662 self.device.raw().destroy_buffer(raw);
663 }
664 }
665 }
666}
667
668#[derive(Debug)]
688pub struct StagingBuffer<A: HalApi> {
689 pub(crate) raw: Mutex<Option<A::Buffer>>,
690 pub(crate) device: Arc<Device<A>>,
691 pub(crate) size: wgt::BufferAddress,
692 pub(crate) is_coherent: bool,
693 pub(crate) info: ResourceInfo<StagingBuffer<A>>,
694}
695
696impl<A: HalApi> Drop for StagingBuffer<A> {
697 fn drop(&mut self) {
698 if let Some(raw) = self.raw.lock().take() {
699 resource_log!("Destroy raw StagingBuffer {:?}", self.info.label());
700 unsafe {
701 use hal::Device;
702 self.device.raw().destroy_buffer(raw);
703 }
704 }
705 }
706}
707
708impl<A: HalApi> Resource for StagingBuffer<A> {
709 const TYPE: ResourceType = "StagingBuffer";
710
711 type Marker = crate::id::markers::StagingBuffer;
712
713 fn as_info(&self) -> &ResourceInfo<Self> {
714 &self.info
715 }
716
717 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
718 &mut self.info
719 }
720
721 fn label(&self) -> String {
722 String::from("<StagingBuffer>")
723 }
724}
725
726pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, Vec<wgt::TextureFormat>>;
727
728#[derive(Debug)]
729pub(crate) enum TextureInner<A: HalApi> {
730 Native {
731 raw: A::Texture,
732 },
733 Surface {
734 raw: Option<A::SurfaceTexture>,
735 parent_id: SurfaceId,
736 },
737}
738
739impl<A: HalApi> TextureInner<A> {
740 pub(crate) fn raw(&self) -> Option<&A::Texture> {
741 match self {
742 Self::Native { raw } => Some(raw),
743 Self::Surface { raw: Some(tex), .. } => Some(tex.borrow()),
744 _ => None,
745 }
746 }
747}
748
749#[derive(Debug)]
750pub enum TextureClearMode<A: HalApi> {
751 BufferCopy,
752 RenderPass {
754 clear_views: SmallVec<[Option<A::TextureView>; 1]>,
755 is_color: bool,
756 },
757 Surface {
758 clear_view: Option<A::TextureView>,
759 },
760 None,
763}
764
765#[derive(Debug)]
766pub struct Texture<A: HalApi> {
767 pub(crate) inner: Snatchable<TextureInner<A>>,
768 pub(crate) device: Arc<Device<A>>,
769 pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
770 pub(crate) hal_usage: hal::TextureUses,
771 pub(crate) format_features: wgt::TextureFormatFeatures,
772 pub(crate) initialization_status: RwLock<TextureInitTracker>,
773 pub(crate) full_range: TextureSelector,
774 pub(crate) info: ResourceInfo<Texture<A>>,
775 pub(crate) clear_mode: RwLock<TextureClearMode<A>>,
776 pub(crate) views: Mutex<Vec<Weak<TextureView<A>>>>,
777 pub(crate) bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
778}
779
780impl<A: HalApi> Drop for Texture<A> {
781 fn drop(&mut self) {
782 resource_log!("Destroy raw Texture {:?}", self.info.label());
783 use hal::Device;
784 let mut clear_mode = self.clear_mode.write();
785 let clear_mode = &mut *clear_mode;
786 match *clear_mode {
787 TextureClearMode::Surface {
788 ref mut clear_view, ..
789 } => {
790 if let Some(view) = clear_view.take() {
791 unsafe {
792 self.device.raw().destroy_texture_view(view);
793 }
794 }
795 }
796 TextureClearMode::RenderPass {
797 ref mut clear_views,
798 ..
799 } => {
800 clear_views.iter_mut().for_each(|clear_view| {
801 if let Some(view) = clear_view.take() {
802 unsafe {
803 self.device.raw().destroy_texture_view(view);
804 }
805 }
806 });
807 }
808 _ => {}
809 };
810
811 if let Some(TextureInner::Native { raw }) = self.inner.take() {
812 #[cfg(feature = "trace")]
813 if let Some(t) = self.device.trace.lock().as_mut() {
814 t.add(trace::Action::DestroyTexture(self.info.id()));
815 }
816
817 unsafe {
818 self.device.raw().destroy_texture(raw);
819 }
820 }
821 }
822}
823
824impl<A: HalApi> Texture<A> {
825 pub(crate) fn raw<'a>(&'a self, snatch_guard: &'a SnatchGuard) -> Option<&'a A::Texture> {
826 self.inner.get(snatch_guard)?.raw()
827 }
828
829 pub(crate) fn is_destroyed(&self, guard: &SnatchGuard) -> bool {
830 self.inner.get(guard).is_none()
831 }
832
833 pub(crate) fn inner_mut<'a>(
834 &'a self,
835 guard: &mut ExclusiveSnatchGuard,
836 ) -> Option<&'a mut TextureInner<A>> {
837 self.inner.get_mut(guard)
838 }
839 pub(crate) fn get_clear_view<'a>(
840 clear_mode: &'a TextureClearMode<A>,
841 desc: &'a wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
842 mip_level: u32,
843 depth_or_layer: u32,
844 ) -> &'a A::TextureView {
845 match *clear_mode {
846 TextureClearMode::BufferCopy => {
847 panic!("Given texture is cleared with buffer copies, not render passes")
848 }
849 TextureClearMode::None => {
850 panic!("Given texture can't be cleared")
851 }
852 TextureClearMode::Surface { ref clear_view, .. } => clear_view.as_ref().unwrap(),
853 TextureClearMode::RenderPass {
854 ref clear_views, ..
855 } => {
856 let index = if desc.dimension == wgt::TextureDimension::D3 {
857 (0..mip_level).fold(0, |acc, mip| {
858 acc + (desc.size.depth_or_array_layers >> mip).max(1)
859 })
860 } else {
861 mip_level * desc.size.depth_or_array_layers
862 } + depth_or_layer;
863 clear_views[index as usize].as_ref().unwrap()
864 }
865 }
866 }
867
868 pub(crate) fn destroy(self: &Arc<Self>) -> Result<(), DestroyError> {
869 let device = &self.device;
870 let texture_id = self.info.id();
871
872 #[cfg(feature = "trace")]
873 if let Some(ref mut trace) = *device.trace.lock() {
874 trace.add(trace::Action::FreeTexture(texture_id));
875 }
876
877 let temp = {
878 let snatch_guard = device.snatchable_lock.write();
879 let raw = match self.inner.snatch(snatch_guard) {
880 Some(TextureInner::Native { raw }) => raw,
881 Some(TextureInner::Surface { .. }) => {
882 return Ok(());
883 }
884 None => {
885 return Err(resource::DestroyError::AlreadyDestroyed);
886 }
887 };
888
889 let views = {
890 let mut guard = self.views.lock();
891 std::mem::take(&mut *guard)
892 };
893
894 let bind_groups = {
895 let mut guard = self.bind_groups.lock();
896 std::mem::take(&mut *guard)
897 };
898
899 queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture {
900 raw: Some(raw),
901 views,
902 bind_groups,
903 device: Arc::clone(&self.device),
904 tracker_index: self.info.tracker_index(),
905 submission_index: self.info.submission_index(),
906 id: self.info.id.unwrap(),
907 label: self.info.label.clone(),
908 }))
909 };
910
911 let mut pending_writes = device.pending_writes.lock();
912 let pending_writes = pending_writes.as_mut().unwrap();
913 if pending_writes.dst_textures.contains_key(&texture_id) {
914 pending_writes.temp_resources.push(temp);
915 } else {
916 let last_submit_index = self.info.submission_index();
917 device
918 .lock_life()
919 .schedule_resource_destruction(temp, last_submit_index);
920 }
921
922 Ok(())
923 }
924}
925
926impl Global {
927 pub unsafe fn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>) -> R, R>(
931 &self,
932 id: TextureId,
933 hal_texture_callback: F,
934 ) -> R {
935 profiling::scope!("Texture::as_hal");
936
937 let hub = A::hub(self);
938 let texture_opt = { hub.textures.try_get(id).ok().flatten() };
939 let texture = texture_opt.as_ref().unwrap();
940 let snatch_guard = texture.device.snatchable_lock.read();
941 let hal_texture = texture.raw(&snatch_guard);
942
943 hal_texture_callback(hal_texture)
944 }
945
946 pub unsafe fn texture_view_as_hal<A: HalApi, F: FnOnce(Option<&A::TextureView>) -> R, R>(
950 &self,
951 id: TextureViewId,
952 hal_texture_view_callback: F,
953 ) -> R {
954 profiling::scope!("TextureView::as_hal");
955
956 let hub = A::hub(self);
957 let texture_view_opt = { hub.texture_views.try_get(id).ok().flatten() };
958 let texture_view = texture_view_opt.as_ref().unwrap();
959 let snatch_guard = texture_view.device.snatchable_lock.read();
960 let hal_texture_view = texture_view.raw(&snatch_guard);
961
962 hal_texture_view_callback(hal_texture_view)
963 }
964
965 pub unsafe fn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
969 &self,
970 id: AdapterId,
971 hal_adapter_callback: F,
972 ) -> R {
973 profiling::scope!("Adapter::as_hal");
974
975 let hub = A::hub(self);
976 let adapter = hub.adapters.try_get(id).ok().flatten();
977 let hal_adapter = adapter.as_ref().map(|adapter| &adapter.raw.adapter);
978
979 hal_adapter_callback(hal_adapter)
980 }
981
982 pub unsafe fn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
986 &self,
987 id: DeviceId,
988 hal_device_callback: F,
989 ) -> R {
990 profiling::scope!("Device::as_hal");
991
992 let hub = A::hub(self);
993 let device = hub.devices.try_get(id).ok().flatten();
994 let hal_device = device.as_ref().map(|device| device.raw());
995
996 hal_device_callback(hal_device)
997 }
998
999 pub unsafe fn device_fence_as_hal<A: HalApi, F: FnOnce(Option<&A::Fence>) -> R, R>(
1003 &self,
1004 id: DeviceId,
1005 hal_fence_callback: F,
1006 ) -> R {
1007 profiling::scope!("Device::fence_as_hal");
1008
1009 let hub = A::hub(self);
1010 let device = hub.devices.try_get(id).ok().flatten();
1011 let hal_fence = device.as_ref().map(|device| device.fence.read());
1012
1013 hal_fence_callback(hal_fence.as_deref().unwrap().as_ref())
1014 }
1015
1016 pub unsafe fn surface_as_hal<A: HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
1019 &self,
1020 id: SurfaceId,
1021 hal_surface_callback: F,
1022 ) -> R {
1023 profiling::scope!("Surface::as_hal");
1024
1025 let surface = self.surfaces.get(id).ok();
1026 let hal_surface = surface
1027 .as_ref()
1028 .and_then(|surface| A::surface_as_hal(surface));
1029
1030 hal_surface_callback(hal_surface)
1031 }
1032
1033 pub unsafe fn command_encoder_as_hal_mut<
1037 A: HalApi,
1038 F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
1039 R,
1040 >(
1041 &self,
1042 id: CommandEncoderId,
1043 hal_command_encoder_callback: F,
1044 ) -> R {
1045 profiling::scope!("CommandEncoder::as_hal");
1046
1047 let hub = A::hub(self);
1048 let cmd_buf = hub
1049 .command_buffers
1050 .get(id.into_command_buffer_id())
1051 .unwrap();
1052 let mut cmd_buf_data = cmd_buf.data.lock();
1053 let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
1054 let cmd_buf_raw = cmd_buf_data.encoder.open().ok();
1055
1056 hal_command_encoder_callback(cmd_buf_raw)
1057 }
1058}
1059
1060#[derive(Debug)]
1062pub struct DestroyedTexture<A: HalApi> {
1063 raw: Option<A::Texture>,
1064 views: Vec<Weak<TextureView<A>>>,
1065 bind_groups: Vec<Weak<BindGroup<A>>>,
1066 device: Arc<Device<A>>,
1067 label: String,
1068 pub(crate) id: TextureId,
1069 pub(crate) tracker_index: TrackerIndex,
1070 pub(crate) submission_index: u64,
1071}
1072
1073impl<A: HalApi> DestroyedTexture<A> {
1074 pub fn label(&self) -> &dyn Debug {
1075 if !self.label.is_empty() {
1076 return &self.label;
1077 }
1078
1079 &self.id
1080 }
1081}
1082
1083impl<A: HalApi> Drop for DestroyedTexture<A> {
1084 fn drop(&mut self) {
1085 let device = &self.device;
1086
1087 let mut deferred = device.deferred_destroy.lock();
1088 for view in self.views.drain(..) {
1089 deferred.push(DeferredDestroy::TextureView(view));
1090 }
1091 for bind_group in self.bind_groups.drain(..) {
1092 deferred.push(DeferredDestroy::BindGroup(bind_group));
1093 }
1094 drop(deferred);
1095
1096 if let Some(raw) = self.raw.take() {
1097 resource_log!("Destroy raw Texture (destroyed) {:?}", self.label());
1098
1099 #[cfg(feature = "trace")]
1100 if let Some(t) = self.device.trace.lock().as_mut() {
1101 t.add(trace::Action::DestroyTexture(self.id));
1102 }
1103
1104 unsafe {
1105 use hal::Device;
1106 self.device.raw().destroy_texture(raw);
1107 }
1108 }
1109 }
1110}
1111
1112#[derive(Clone, Copy, Debug)]
1113pub enum TextureErrorDimension {
1114 X,
1115 Y,
1116 Z,
1117}
1118
1119#[derive(Clone, Debug, Error)]
1120#[non_exhaustive]
1121pub enum TextureDimensionError {
1122 #[error("Dimension {0:?} is zero")]
1123 Zero(TextureErrorDimension),
1124 #[error("Dimension {dim:?} value {given} exceeds the limit of {limit}")]
1125 LimitExceeded {
1126 dim: TextureErrorDimension,
1127 given: u32,
1128 limit: u32,
1129 },
1130 #[error("Sample count {0} is invalid")]
1131 InvalidSampleCount(u32),
1132 #[error("Width {width} is not a multiple of {format:?}'s block width ({block_width})")]
1133 NotMultipleOfBlockWidth {
1134 width: u32,
1135 block_width: u32,
1136 format: wgt::TextureFormat,
1137 },
1138 #[error("Height {height} is not a multiple of {format:?}'s block height ({block_height})")]
1139 NotMultipleOfBlockHeight {
1140 height: u32,
1141 block_height: u32,
1142 format: wgt::TextureFormat,
1143 },
1144 #[error(
1145 "Width {width} is not a multiple of {format:?}'s width multiple requirement ({multiple})"
1146 )]
1147 WidthNotMultipleOf {
1148 width: u32,
1149 multiple: u32,
1150 format: wgt::TextureFormat,
1151 },
1152 #[error("Height {height} is not a multiple of {format:?}'s height multiple requirement ({multiple})")]
1153 HeightNotMultipleOf {
1154 height: u32,
1155 multiple: u32,
1156 format: wgt::TextureFormat,
1157 },
1158 #[error("Multisampled texture depth or array layers must be 1, got {0}")]
1159 MultisampledDepthOrArrayLayer(u32),
1160}
1161
1162#[derive(Clone, Debug, Error)]
1163#[non_exhaustive]
1164pub enum CreateTextureError {
1165 #[error(transparent)]
1166 Device(#[from] DeviceError),
1167 #[error(transparent)]
1168 CreateTextureView(#[from] CreateTextureViewError),
1169 #[error("Invalid usage flags {0:?}")]
1170 InvalidUsage(wgt::TextureUsages),
1171 #[error(transparent)]
1172 InvalidDimension(#[from] TextureDimensionError),
1173 #[error("Depth texture ({1:?}) can't be created as {0:?}")]
1174 InvalidDepthDimension(wgt::TextureDimension, wgt::TextureFormat),
1175 #[error("Compressed texture ({1:?}) can't be created as {0:?}")]
1176 InvalidCompressedDimension(wgt::TextureDimension, wgt::TextureFormat),
1177 #[error(
1178 "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}"
1179 )]
1180 InvalidMipLevelCount { requested: u32, maximum: u32 },
1181 #[error(
1182 "Texture usages {0:?} are not allowed on a texture of type {1:?}{}",
1183 if *.2 { " due to downlevel restrictions" } else { "" }
1184 )]
1185 InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat, bool),
1186 #[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
1187 InvalidViewFormat(wgt::TextureFormat, wgt::TextureFormat),
1188 #[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")]
1189 InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension),
1190 #[error("Texture usage STORAGE_BINDING is not allowed for multisampled textures")]
1191 InvalidMultisampledStorageBinding,
1192 #[error("Format {0:?} does not support multisampling")]
1193 InvalidMultisampledFormat(wgt::TextureFormat),
1194 #[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:?}.")]
1195 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
1196 #[error("Multisampled textures must have RENDER_ATTACHMENT usage")]
1197 MultisampledNotRenderAttachment,
1198 #[error("Texture format {0:?} can't be used due to missing features")]
1199 MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
1200 #[error(transparent)]
1201 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
1202}
1203
1204impl<A: HalApi> Resource for Texture<A> {
1205 const TYPE: ResourceType = "Texture";
1206
1207 type Marker = crate::id::markers::Texture;
1208
1209 fn as_info(&self) -> &ResourceInfo<Self> {
1210 &self.info
1211 }
1212
1213 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
1214 &mut self.info
1215 }
1216}
1217
1218impl<A: HalApi> Borrow<TextureSelector> for Texture<A> {
1219 fn borrow(&self) -> &TextureSelector {
1220 &self.full_range
1221 }
1222}
1223
1224#[derive(Clone, Debug, Default, Eq, PartialEq)]
1226#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1227#[cfg_attr(feature = "serde", serde(default))]
1228pub struct TextureViewDescriptor<'a> {
1229 pub label: Label<'a>,
1233 pub format: Option<wgt::TextureFormat>,
1238 pub dimension: Option<wgt::TextureViewDimension>,
1244 pub range: wgt::ImageSubresourceRange,
1246}
1247
1248#[derive(Debug)]
1249pub(crate) struct HalTextureViewDescriptor {
1250 pub texture_format: wgt::TextureFormat,
1251 pub format: wgt::TextureFormat,
1252 pub dimension: wgt::TextureViewDimension,
1253 pub range: wgt::ImageSubresourceRange,
1254}
1255
1256impl HalTextureViewDescriptor {
1257 pub fn aspects(&self) -> hal::FormatAspects {
1258 hal::FormatAspects::new(self.texture_format, self.range.aspect)
1259 }
1260}
1261
1262#[derive(Debug, Copy, Clone, Error)]
1263pub enum TextureViewNotRenderableReason {
1264 #[error("The texture this view references doesn't include the RENDER_ATTACHMENT usage. Provided usages: {0:?}")]
1265 Usage(wgt::TextureUsages),
1266 #[error("The dimension of this texture view is not 2D. View dimension: {0:?}")]
1267 Dimension(wgt::TextureViewDimension),
1268 #[error("This texture view has more than one mipmap level. View mipmap levels: {0:?}")]
1269 MipLevelCount(u32),
1270 #[error("This texture view has more than one array layer. View array layers: {0:?}")]
1271 ArrayLayerCount(u32),
1272 #[error(
1273 "The aspects of this texture view are a subset of the aspects in the original texture. Aspects: {0:?}"
1274 )]
1275 Aspects(hal::FormatAspects),
1276}
1277
1278#[derive(Debug)]
1279pub struct TextureView<A: HalApi> {
1280 pub(crate) raw: Snatchable<A::TextureView>,
1281 pub(crate) parent: Arc<Texture<A>>,
1283 pub(crate) device: Arc<Device<A>>,
1284 pub(crate) desc: HalTextureViewDescriptor,
1286 pub(crate) format_features: wgt::TextureFormatFeatures,
1287 pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>,
1289 pub(crate) samples: u32,
1290 pub(crate) selector: TextureSelector,
1291 pub(crate) info: ResourceInfo<TextureView<A>>,
1292}
1293
1294impl<A: HalApi> Drop for TextureView<A> {
1295 fn drop(&mut self) {
1296 if let Some(raw) = self.raw.take() {
1297 resource_log!("Destroy raw TextureView {:?}", self.info.label());
1298
1299 #[cfg(feature = "trace")]
1300 if let Some(t) = self.device.trace.lock().as_mut() {
1301 t.add(trace::Action::DestroyTextureView(self.info.id()));
1302 }
1303
1304 unsafe {
1305 use hal::Device;
1306 self.device.raw().destroy_texture_view(raw);
1307 }
1308 }
1309 }
1310}
1311
1312impl<A: HalApi> TextureView<A> {
1313 pub(crate) fn raw<'a>(&'a self, snatch_guard: &'a SnatchGuard) -> Option<&'a A::TextureView> {
1314 self.raw.get(snatch_guard)
1315 }
1316}
1317
1318#[derive(Clone, Debug, Error)]
1319#[non_exhaustive]
1320pub enum CreateTextureViewError {
1321 #[error("Parent texture is invalid or destroyed")]
1322 InvalidTexture,
1323 #[error("Not enough memory left to create texture view")]
1324 OutOfMemory,
1325 #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")]
1326 InvalidTextureViewDimension {
1327 view: wgt::TextureViewDimension,
1328 texture: wgt::TextureDimension,
1329 },
1330 #[error("Invalid texture view dimension `{0:?}` of a multisampled texture")]
1331 InvalidMultisampledTextureViewDimension(wgt::TextureViewDimension),
1332 #[error("Invalid texture depth `{depth}` for texture view of dimension `Cubemap`. Cubemap views must use images of size 6.")]
1333 InvalidCubemapTextureDepth { depth: u32 },
1334 #[error("Invalid texture depth `{depth}` for texture view of dimension `CubemapArray`. Cubemap views must use images with sizes which are a multiple of 6.")]
1335 InvalidCubemapArrayTextureDepth { depth: u32 },
1336 #[error("Source texture width and height must be equal for a texture view of dimension `Cube`/`CubeArray`")]
1337 InvalidCubeTextureViewSize,
1338 #[error("Mip level count is 0")]
1339 ZeroMipLevelCount,
1340 #[error("Array layer count is 0")]
1341 ZeroArrayLayerCount,
1342 #[error(
1343 "TextureView mip level count + base mip level {requested} must be <= Texture mip level count {total}"
1344 )]
1345 TooManyMipLevels { requested: u32, total: u32 },
1346 #[error("TextureView array layer count + base array layer {requested} must be <= Texture depth/array layer count {total}")]
1347 TooManyArrayLayers { requested: u32, total: u32 },
1348 #[error("Requested array layer count {requested} is not valid for the target view dimension {dim:?}")]
1349 InvalidArrayLayerCount {
1350 requested: u32,
1351 dim: wgt::TextureViewDimension,
1352 },
1353 #[error("Aspect {requested_aspect:?} is not in the source texture format {texture_format:?}")]
1354 InvalidAspect {
1355 texture_format: wgt::TextureFormat,
1356 requested_aspect: wgt::TextureAspect,
1357 },
1358 #[error("Unable to view texture {texture:?} as {view:?}")]
1359 FormatReinterpretation {
1360 texture: wgt::TextureFormat,
1361 view: wgt::TextureFormat,
1362 },
1363}
1364
1365#[derive(Clone, Debug, Error)]
1366#[non_exhaustive]
1367pub enum TextureViewDestroyError {}
1368
1369impl<A: HalApi> Resource for TextureView<A> {
1370 const TYPE: ResourceType = "TextureView";
1371
1372 type Marker = crate::id::markers::TextureView;
1373
1374 fn as_info(&self) -> &ResourceInfo<Self> {
1375 &self.info
1376 }
1377
1378 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
1379 &mut self.info
1380 }
1381}
1382
1383#[derive(Clone, Debug, PartialEq)]
1385#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1386pub struct SamplerDescriptor<'a> {
1387 pub label: Label<'a>,
1391 pub address_modes: [wgt::AddressMode; 3],
1393 pub mag_filter: wgt::FilterMode,
1395 pub min_filter: wgt::FilterMode,
1397 pub mipmap_filter: wgt::FilterMode,
1399 pub lod_min_clamp: f32,
1401 pub lod_max_clamp: f32,
1403 pub compare: Option<wgt::CompareFunction>,
1405 pub anisotropy_clamp: u16,
1407 pub border_color: Option<wgt::SamplerBorderColor>,
1410}
1411
1412#[derive(Debug)]
1413pub struct Sampler<A: HalApi> {
1414 pub(crate) raw: Option<A::Sampler>,
1415 pub(crate) device: Arc<Device<A>>,
1416 pub(crate) info: ResourceInfo<Self>,
1417 pub(crate) comparison: bool,
1419 pub(crate) filtering: bool,
1421}
1422
1423impl<A: HalApi> Drop for Sampler<A> {
1424 fn drop(&mut self) {
1425 resource_log!("Destroy raw Sampler {:?}", self.info.label());
1426 if let Some(raw) = self.raw.take() {
1427 #[cfg(feature = "trace")]
1428 if let Some(t) = self.device.trace.lock().as_mut() {
1429 t.add(trace::Action::DestroySampler(self.info.id()));
1430 }
1431
1432 unsafe {
1433 use hal::Device;
1434 self.device.raw().destroy_sampler(raw);
1435 }
1436 }
1437 }
1438}
1439
1440impl<A: HalApi> Sampler<A> {
1441 pub(crate) fn raw(&self) -> &A::Sampler {
1442 self.raw.as_ref().unwrap()
1443 }
1444}
1445
1446#[derive(Copy, Clone)]
1447pub enum SamplerFilterErrorType {
1448 MagFilter,
1449 MinFilter,
1450 MipmapFilter,
1451}
1452
1453impl Debug for SamplerFilterErrorType {
1454 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1455 match *self {
1456 SamplerFilterErrorType::MagFilter => write!(f, "magFilter"),
1457 SamplerFilterErrorType::MinFilter => write!(f, "minFilter"),
1458 SamplerFilterErrorType::MipmapFilter => write!(f, "mipmapFilter"),
1459 }
1460 }
1461}
1462
1463#[derive(Clone, Debug, Error)]
1464#[non_exhaustive]
1465pub enum CreateSamplerError {
1466 #[error(transparent)]
1467 Device(#[from] DeviceError),
1468 #[error("Invalid lodMinClamp: {0}. Must be greater or equal to 0.0")]
1469 InvalidLodMinClamp(f32),
1470 #[error("Invalid lodMaxClamp: {lod_max_clamp}. Must be greater or equal to lodMinClamp (which is {lod_min_clamp}).")]
1471 InvalidLodMaxClamp {
1472 lod_min_clamp: f32,
1473 lod_max_clamp: f32,
1474 },
1475 #[error("Invalid anisotropic clamp: {0}. Must be at least 1.")]
1476 InvalidAnisotropy(u16),
1477 #[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.")]
1478 InvalidFilterModeWithAnisotropy {
1479 filter_type: SamplerFilterErrorType,
1480 filter_mode: wgt::FilterMode,
1481 anisotropic_clamp: u16,
1482 },
1483 #[error("Cannot create any more samplers")]
1484 TooManyObjects,
1485 #[error(transparent)]
1487 MissingFeatures(#[from] MissingFeatures),
1488}
1489
1490impl<A: HalApi> Resource for Sampler<A> {
1491 const TYPE: ResourceType = "Sampler";
1492
1493 type Marker = crate::id::markers::Sampler;
1494
1495 fn as_info(&self) -> &ResourceInfo<Self> {
1496 &self.info
1497 }
1498
1499 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
1500 &mut self.info
1501 }
1502}
1503
1504#[derive(Clone, Debug, Error)]
1505#[non_exhaustive]
1506pub enum CreateQuerySetError {
1507 #[error(transparent)]
1508 Device(#[from] DeviceError),
1509 #[error("QuerySets cannot be made with zero queries")]
1510 ZeroCount,
1511 #[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")]
1512 TooManyQueries { count: u32, maximum: u32 },
1513 #[error(transparent)]
1514 MissingFeatures(#[from] MissingFeatures),
1515}
1516
1517pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
1518
1519#[derive(Debug)]
1520pub struct QuerySet<A: HalApi> {
1521 pub(crate) raw: Option<A::QuerySet>,
1522 pub(crate) device: Arc<Device<A>>,
1523 pub(crate) info: ResourceInfo<Self>,
1524 pub(crate) desc: wgt::QuerySetDescriptor<()>,
1525}
1526
1527impl<A: HalApi> Drop for QuerySet<A> {
1528 fn drop(&mut self) {
1529 resource_log!("Destroy raw QuerySet {:?}", self.info.label());
1530 if let Some(raw) = self.raw.take() {
1531 #[cfg(feature = "trace")]
1532 if let Some(t) = self.device.trace.lock().as_mut() {
1533 t.add(trace::Action::DestroyQuerySet(self.info.id()));
1534 }
1535
1536 unsafe {
1537 use hal::Device;
1538 self.device.raw().destroy_query_set(raw);
1539 }
1540 }
1541 }
1542}
1543
1544impl<A: HalApi> Resource for QuerySet<A> {
1545 const TYPE: ResourceType = "QuerySet";
1546
1547 type Marker = crate::id::markers::QuerySet;
1548
1549 fn as_info(&self) -> &ResourceInfo<Self> {
1550 &self.info
1551 }
1552
1553 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
1554 &mut self.info
1555 }
1556}
1557
1558impl<A: HalApi> QuerySet<A> {
1559 pub(crate) fn raw(&self) -> &A::QuerySet {
1560 self.raw.as_ref().unwrap()
1561 }
1562}
1563
1564#[derive(Clone, Debug, Error)]
1565#[non_exhaustive]
1566pub enum DestroyError {
1567 #[error("Resource is invalid")]
1568 Invalid,
1569 #[error("Resource is already destroyed")]
1570 AlreadyDestroyed,
1571}