1use crate::{
2 device::{DeviceError, HostMap, MissingDownlevelFlags, MissingFeatures},
3 global::Global,
4 hal_api::HalApi,
5 hub::Token,
6 id::{AdapterId, DeviceId, SurfaceId, TextureId, Valid},
7 identity::GlobalIdentityHandlerFactory,
8 init_tracker::{BufferInitTracker, TextureInitTracker},
9 track::TextureSelector,
10 validation::MissingBufferUsageError,
11 Label, LifeGuard, RefCount, Stored,
12};
13
14use smallvec::SmallVec;
15use thiserror::Error;
16
17use std::{borrow::Borrow, ops::Range, ptr::NonNull};
18
19pub trait Resource {
20 const TYPE: &'static str;
21 fn life_guard(&self) -> &LifeGuard;
22 fn label(&self) -> &str {
23 #[cfg(debug_assertions)]
24 return &self.life_guard().label;
25 #[cfg(not(debug_assertions))]
26 return "";
27 }
28}
29
30#[repr(C)]
34#[derive(Debug)]
35pub enum BufferMapAsyncStatus {
36 Success,
40 AlreadyMapped,
44 MapAlreadyPending,
46 Error,
48 Aborted,
51 ContextLost,
53 Invalid,
55 InvalidRange,
57 InvalidAlignment,
59 InvalidUsageFlags,
61}
62
63pub(crate) enum BufferMapState<A: hal::Api> {
64 Init {
66 ptr: NonNull<u8>,
67 stage_buffer: A::Buffer,
68 needs_flush: bool,
69 },
70 Waiting(BufferPendingMapping),
72 Active {
74 ptr: NonNull<u8>,
75 range: hal::MemoryRange,
76 host: HostMap,
77 },
78 Idle,
80}
81
82#[cfg(any(
83 not(target_arch = "wasm32"),
84 all(
85 feature = "fragile-send-sync-non-atomic-wasm",
86 not(target_feature = "atomics")
87 )
88))]
89unsafe impl<A: hal::Api> Send for BufferMapState<A> {}
90#[cfg(any(
91 not(target_arch = "wasm32"),
92 all(
93 feature = "fragile-send-sync-non-atomic-wasm",
94 not(target_feature = "atomics")
95 )
96))]
97unsafe impl<A: hal::Api> Sync for BufferMapState<A> {}
98
99#[repr(C)]
100pub struct BufferMapCallbackC {
101 pub callback: unsafe extern "C" fn(status: BufferMapAsyncStatus, user_data: *mut u8),
102 pub user_data: *mut u8,
103}
104
105#[cfg(any(
106 not(target_arch = "wasm32"),
107 all(
108 feature = "fragile-send-sync-non-atomic-wasm",
109 not(target_feature = "atomics")
110 )
111))]
112unsafe impl Send for BufferMapCallbackC {}
113
114pub struct BufferMapCallback {
115 inner: Option<BufferMapCallbackInner>,
118}
119
120#[cfg(any(
121 not(target_arch = "wasm32"),
122 all(
123 feature = "fragile-send-sync-non-atomic-wasm",
124 not(target_feature = "atomics")
125 )
126))]
127type BufferMapCallbackCallback = Box<dyn FnOnce(BufferAccessResult) + Send + 'static>;
128#[cfg(not(any(
129 not(target_arch = "wasm32"),
130 all(
131 feature = "fragile-send-sync-non-atomic-wasm",
132 not(target_feature = "atomics")
133 )
134)))]
135type BufferMapCallbackCallback = Box<dyn FnOnce(BufferAccessResult) + 'static>;
136
137enum BufferMapCallbackInner {
138 Rust { callback: BufferMapCallbackCallback },
139 C { inner: BufferMapCallbackC },
140}
141
142impl BufferMapCallback {
143 pub fn from_rust(callback: BufferMapCallbackCallback) -> Self {
144 Self {
145 inner: Some(BufferMapCallbackInner::Rust { callback }),
146 }
147 }
148
149 pub unsafe fn from_c(inner: BufferMapCallbackC) -> Self {
157 Self {
158 inner: Some(BufferMapCallbackInner::C { inner }),
159 }
160 }
161
162 pub(crate) fn call(mut self, result: BufferAccessResult) {
163 match self.inner.take() {
164 Some(BufferMapCallbackInner::Rust { callback }) => {
165 callback(result);
166 }
167 Some(BufferMapCallbackInner::C { inner }) => unsafe {
169 let status = match result {
170 Ok(()) => BufferMapAsyncStatus::Success,
171 Err(BufferAccessError::Device(_)) => BufferMapAsyncStatus::ContextLost,
172 Err(BufferAccessError::Invalid) | Err(BufferAccessError::Destroyed) => {
173 BufferMapAsyncStatus::Invalid
174 }
175 Err(BufferAccessError::AlreadyMapped) => BufferMapAsyncStatus::AlreadyMapped,
176 Err(BufferAccessError::MapAlreadyPending) => {
177 BufferMapAsyncStatus::MapAlreadyPending
178 }
179 Err(BufferAccessError::MissingBufferUsage(_)) => {
180 BufferMapAsyncStatus::InvalidUsageFlags
181 }
182 Err(BufferAccessError::UnalignedRange)
183 | Err(BufferAccessError::UnalignedRangeSize { .. })
184 | Err(BufferAccessError::UnalignedOffset { .. }) => {
185 BufferMapAsyncStatus::InvalidAlignment
186 }
187 Err(BufferAccessError::OutOfBoundsUnderrun { .. })
188 | Err(BufferAccessError::OutOfBoundsOverrun { .. })
189 | Err(BufferAccessError::NegativeRange { .. }) => {
190 BufferMapAsyncStatus::InvalidRange
191 }
192 Err(_) => BufferMapAsyncStatus::Error,
193 };
194
195 (inner.callback)(status, inner.user_data);
196 },
197 None => {
198 panic!("Map callback invoked twice");
199 }
200 }
201 }
202}
203
204impl Drop for BufferMapCallback {
205 fn drop(&mut self) {
206 if self.inner.is_some() {
207 panic!("Map callback was leaked");
208 }
209 }
210}
211
212pub struct BufferMapOperation {
213 pub host: HostMap,
214 pub callback: BufferMapCallback,
215}
216
217#[derive(Clone, Debug, Error)]
218#[non_exhaustive]
219pub enum BufferAccessError {
220 #[error(transparent)]
221 Device(#[from] DeviceError),
222 #[error("Buffer map failed")]
223 Failed,
224 #[error("Buffer is invalid")]
225 Invalid,
226 #[error("Buffer is destroyed")]
227 Destroyed,
228 #[error("Buffer is already mapped")]
229 AlreadyMapped,
230 #[error("Buffer map is pending")]
231 MapAlreadyPending,
232 #[error(transparent)]
233 MissingBufferUsage(#[from] MissingBufferUsageError),
234 #[error("Buffer is not mapped")]
235 NotMapped,
236 #[error(
237 "Buffer map range must start aligned to `MAP_ALIGNMENT` and end to `COPY_BUFFER_ALIGNMENT`"
238 )]
239 UnalignedRange,
240 #[error("Buffer offset invalid: offset {offset} must be multiple of 8")]
241 UnalignedOffset { offset: wgt::BufferAddress },
242 #[error("Buffer range size invalid: range_size {range_size} must be multiple of 4")]
243 UnalignedRangeSize { range_size: wgt::BufferAddress },
244 #[error("Buffer access out of bounds: index {index} would underrun the buffer (limit: {min})")]
245 OutOfBoundsUnderrun {
246 index: wgt::BufferAddress,
247 min: wgt::BufferAddress,
248 },
249 #[error(
250 "Buffer access out of bounds: last index {index} would overrun the buffer (limit: {max})"
251 )]
252 OutOfBoundsOverrun {
253 index: wgt::BufferAddress,
254 max: wgt::BufferAddress,
255 },
256 #[error("Buffer map range start {start} is greater than end {end}")]
257 NegativeRange {
258 start: wgt::BufferAddress,
259 end: wgt::BufferAddress,
260 },
261 #[error("Buffer map aborted")]
262 MapAborted,
263}
264
265pub type BufferAccessResult = Result<(), BufferAccessError>;
266pub(crate) struct BufferPendingMapping {
267 pub range: Range<wgt::BufferAddress>,
268 pub op: BufferMapOperation,
269 pub _parent_ref_count: RefCount,
271}
272
273pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
274
275pub struct Buffer<A: hal::Api> {
276 pub(crate) raw: Option<A::Buffer>,
277 pub(crate) device_id: Stored<DeviceId>,
278 pub(crate) usage: wgt::BufferUsages,
279 pub(crate) size: wgt::BufferAddress,
280 pub(crate) initialization_status: BufferInitTracker,
281 pub(crate) sync_mapped_writes: Option<hal::MemoryRange>,
282 pub(crate) life_guard: LifeGuard,
283 pub(crate) map_state: BufferMapState<A>,
284}
285
286#[derive(Clone, Debug, Error)]
287#[non_exhaustive]
288pub enum CreateBufferError {
289 #[error(transparent)]
290 Device(#[from] DeviceError),
291 #[error("Failed to map buffer while creating: {0}")]
292 AccessError(#[from] BufferAccessError),
293 #[error("Buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
294 UnalignedSize,
295 #[error("Invalid usage flags {0:?}")]
296 InvalidUsage(wgt::BufferUsages),
297 #[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
298 UsageMismatch(wgt::BufferUsages),
299 #[error("Buffer size {requested} is greater than the maximum buffer size ({maximum})")]
300 MaxBufferSize { requested: u64, maximum: u64 },
301 #[error(transparent)]
302 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
303}
304
305impl<A: hal::Api> Resource for Buffer<A> {
306 const TYPE: &'static str = "Buffer";
307
308 fn life_guard(&self) -> &LifeGuard {
309 &self.life_guard
310 }
311}
312
313pub struct StagingBuffer<A: hal::Api> {
333 pub(crate) raw: A::Buffer,
334 pub(crate) size: wgt::BufferAddress,
335 pub(crate) is_coherent: bool,
336}
337
338impl<A: hal::Api> Resource for StagingBuffer<A> {
339 const TYPE: &'static str = "StagingBuffer";
340
341 fn life_guard(&self) -> &LifeGuard {
342 unreachable!()
343 }
344
345 fn label(&self) -> &str {
346 "<StagingBuffer>"
347 }
348}
349
350pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, Vec<wgt::TextureFormat>>;
351
352#[derive(Debug)]
353pub(crate) enum TextureInner<A: hal::Api> {
354 Native {
355 raw: Option<A::Texture>,
356 },
357 Surface {
358 raw: A::SurfaceTexture,
359 parent_id: Valid<SurfaceId>,
360 has_work: bool,
361 },
362}
363
364impl<A: hal::Api> TextureInner<A> {
365 pub fn as_raw(&self) -> Option<&A::Texture> {
366 match *self {
367 Self::Native { raw: Some(ref tex) } => Some(tex),
368 Self::Native { raw: None } => None,
369 Self::Surface { ref raw, .. } => Some(raw.borrow()),
370 }
371 }
372}
373
374#[derive(Debug)]
375pub enum TextureClearMode<A: hal::Api> {
376 BufferCopy,
377 RenderPass {
379 clear_views: SmallVec<[A::TextureView; 1]>,
380 is_color: bool,
381 },
382 None,
385}
386
387impl<A: hal::Api> TextureClearMode<A> {
388 pub(crate) fn destroy_clear_views(self, device: &A::Device) {
389 if let TextureClearMode::RenderPass { clear_views, .. } = self {
390 for clear_view in clear_views {
391 unsafe {
392 hal::Device::destroy_texture_view(device, clear_view);
393 }
394 }
395 }
396 }
397}
398
399#[derive(Debug)]
400pub struct Texture<A: hal::Api> {
401 pub(crate) inner: TextureInner<A>,
402 pub(crate) device_id: Stored<DeviceId>,
403 pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
404 pub(crate) hal_usage: hal::TextureUses,
405 pub(crate) format_features: wgt::TextureFormatFeatures,
406 pub(crate) initialization_status: TextureInitTracker,
407 pub(crate) full_range: TextureSelector,
408 pub(crate) life_guard: LifeGuard,
409 pub(crate) clear_mode: TextureClearMode<A>,
410}
411
412impl<A: hal::Api> Texture<A> {
413 pub(crate) fn get_clear_view(&self, mip_level: u32, depth_or_layer: u32) -> &A::TextureView {
414 match self.clear_mode {
415 TextureClearMode::BufferCopy => {
416 panic!("Given texture is cleared with buffer copies, not render passes")
417 }
418 TextureClearMode::None => {
419 panic!("Given texture can't be cleared")
420 }
421 TextureClearMode::RenderPass {
422 ref clear_views, ..
423 } => {
424 let index = if self.desc.dimension == wgt::TextureDimension::D3 {
425 (0..mip_level).fold(0, |acc, mip| {
426 acc + (self.desc.size.depth_or_array_layers >> mip).max(1)
427 })
428 } else {
429 mip_level * self.desc.size.depth_or_array_layers
430 } + depth_or_layer;
431 &clear_views[index as usize]
432 }
433 }
434 }
435}
436
437impl<G: GlobalIdentityHandlerFactory> Global<G> {
438 pub unsafe fn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>)>(
442 &self,
443 id: TextureId,
444 hal_texture_callback: F,
445 ) {
446 profiling::scope!("Texture::as_hal");
447
448 let hub = A::hub(self);
449 let mut token = Token::root();
450 let (guard, _) = hub.textures.read(&mut token);
451 let texture = guard.try_get(id).ok().flatten();
452 let hal_texture = texture.and_then(|tex| tex.inner.as_raw());
453
454 hal_texture_callback(hal_texture);
455 }
456
457 pub unsafe fn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
461 &self,
462 id: AdapterId,
463 hal_adapter_callback: F,
464 ) -> R {
465 profiling::scope!("Adapter::as_hal");
466
467 let hub = A::hub(self);
468 let mut token = Token::root();
469
470 let (guard, _) = hub.adapters.read(&mut token);
471 let adapter = guard.try_get(id).ok().flatten();
472 let hal_adapter = adapter.map(|adapter| &adapter.raw.adapter);
473
474 hal_adapter_callback(hal_adapter)
475 }
476
477 pub unsafe fn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
481 &self,
482 id: DeviceId,
483 hal_device_callback: F,
484 ) -> R {
485 profiling::scope!("Device::as_hal");
486
487 let hub = A::hub(self);
488 let mut token = Token::root();
489 let (guard, _) = hub.devices.read(&mut token);
490 let device = guard.try_get(id).ok().flatten();
491 let hal_device = device.map(|device| &device.raw);
492
493 hal_device_callback(hal_device)
494 }
495
496 pub unsafe fn surface_as_hal_mut<A: HalApi, F: FnOnce(Option<&mut A::Surface>) -> R, R>(
499 &self,
500 id: SurfaceId,
501 hal_surface_callback: F,
502 ) -> R {
503 profiling::scope!("Surface::as_hal_mut");
504
505 let mut token = Token::root();
506 let (mut guard, _) = self.surfaces.write(&mut token);
507 let surface = guard.get_mut(id).ok();
508 let hal_surface = surface
509 .and_then(|surface| A::get_surface_mut(surface))
510 .map(|surface| &mut surface.raw);
511
512 hal_surface_callback(hal_surface)
513 }
514}
515
516#[derive(Clone, Copy, Debug)]
517pub enum TextureErrorDimension {
518 X,
519 Y,
520 Z,
521}
522
523#[derive(Clone, Debug, Error)]
524#[non_exhaustive]
525pub enum TextureDimensionError {
526 #[error("Dimension {0:?} is zero")]
527 Zero(TextureErrorDimension),
528 #[error("Dimension {dim:?} value {given} exceeds the limit of {limit}")]
529 LimitExceeded {
530 dim: TextureErrorDimension,
531 given: u32,
532 limit: u32,
533 },
534 #[error("Sample count {0} is invalid")]
535 InvalidSampleCount(u32),
536 #[error("Width {width} is not a multiple of {format:?}'s block width ({block_width})")]
537 NotMultipleOfBlockWidth {
538 width: u32,
539 block_width: u32,
540 format: wgt::TextureFormat,
541 },
542 #[error("Height {height} is not a multiple of {format:?}'s block height ({block_height})")]
543 NotMultipleOfBlockHeight {
544 height: u32,
545 block_height: u32,
546 format: wgt::TextureFormat,
547 },
548 #[error("Multisampled texture depth or array layers must be 1, got {0}")]
549 MultisampledDepthOrArrayLayer(u32),
550}
551
552#[derive(Clone, Debug, Error)]
553#[non_exhaustive]
554pub enum CreateTextureError {
555 #[error(transparent)]
556 Device(#[from] DeviceError),
557 #[error("Invalid usage flags {0:?}")]
558 InvalidUsage(wgt::TextureUsages),
559 #[error(transparent)]
560 InvalidDimension(#[from] TextureDimensionError),
561 #[error("Depth texture ({1:?}) can't be created as {0:?}")]
562 InvalidDepthDimension(wgt::TextureDimension, wgt::TextureFormat),
563 #[error("Compressed texture ({1:?}) can't be created as {0:?}")]
564 InvalidCompressedDimension(wgt::TextureDimension, wgt::TextureFormat),
565 #[error(
566 "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}"
567 )]
568 InvalidMipLevelCount { requested: u32, maximum: u32 },
569 #[error(
570 "Texture usages {0:?} are not allowed on a texture of type {1:?}{}",
571 if *.2 { " due to downlevel restrictions" } else { "" }
572 )]
573 InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat, bool),
574 #[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
575 InvalidViewFormat(wgt::TextureFormat, wgt::TextureFormat),
576 #[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")]
577 InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension),
578 #[error("Texture usage STORAGE_BINDING is not allowed for multisampled textures")]
579 InvalidMultisampledStorageBinding,
580 #[error("Format {0:?} does not support multisampling")]
581 InvalidMultisampledFormat(wgt::TextureFormat),
582 #[error("Sample count {0} is not supported by format {1:?} on this device. It may be supported by your adapter through the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature.")]
583 InvalidSampleCount(u32, wgt::TextureFormat),
584 #[error("Multisampled textures must have RENDER_ATTACHMENT usage")]
585 MultisampledNotRenderAttachment,
586 #[error("Texture format {0:?} can't be used due to missing features")]
587 MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
588 #[error(transparent)]
589 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
590}
591
592impl<A: hal::Api> Resource for Texture<A> {
593 const TYPE: &'static str = "Texture";
594
595 fn life_guard(&self) -> &LifeGuard {
596 &self.life_guard
597 }
598}
599
600impl<A: hal::Api> Borrow<TextureSelector> for Texture<A> {
601 fn borrow(&self) -> &TextureSelector {
602 &self.full_range
603 }
604}
605
606#[derive(Clone, Debug, Default, Eq, PartialEq)]
608#[cfg_attr(feature = "trace", derive(serde::Serialize))]
609#[cfg_attr(feature = "replay", derive(serde::Deserialize), serde(default))]
610pub struct TextureViewDescriptor<'a> {
611 pub label: Label<'a>,
615 pub format: Option<wgt::TextureFormat>,
620 pub dimension: Option<wgt::TextureViewDimension>,
626 pub range: wgt::ImageSubresourceRange,
628}
629
630#[derive(Debug)]
631pub(crate) struct HalTextureViewDescriptor {
632 pub format: wgt::TextureFormat,
633 pub dimension: wgt::TextureViewDimension,
634 pub range: wgt::ImageSubresourceRange,
635}
636
637impl HalTextureViewDescriptor {
638 pub fn aspects(&self) -> hal::FormatAspects {
639 hal::FormatAspects::new(self.format, self.range.aspect)
640 }
641}
642
643#[derive(Debug, Copy, Clone, Error)]
644pub enum TextureViewNotRenderableReason {
645 #[error("The texture this view references doesn't include the RENDER_ATTACHMENT usage. Provided usages: {0:?}")]
646 Usage(wgt::TextureUsages),
647 #[error("The dimension of this texture view is not 2D. View dimension: {0:?}")]
648 Dimension(wgt::TextureViewDimension),
649 #[error("This texture view has more than one mipmap level. View mipmap levels: {0:?}")]
650 MipLevelCount(u32),
651 #[error("This texture view has more than one array layer. View array layers: {0:?}")]
652 ArrayLayerCount(u32),
653 #[error(
654 "The aspects of this texture view are a subset of the aspects in the original texture. Aspects: {0:?}"
655 )]
656 Aspects(hal::FormatAspects),
657}
658
659#[derive(Debug)]
660pub struct TextureView<A: hal::Api> {
661 pub(crate) raw: A::TextureView,
662 pub(crate) parent_id: Stored<TextureId>,
665 pub(crate) device_id: Stored<DeviceId>,
666 pub(crate) desc: HalTextureViewDescriptor,
668 pub(crate) format_features: wgt::TextureFormatFeatures,
669 pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>,
671 pub(crate) samples: u32,
672 pub(crate) selector: TextureSelector,
673 pub(crate) life_guard: LifeGuard,
674}
675
676#[derive(Clone, Debug, Error)]
677#[non_exhaustive]
678pub enum CreateTextureViewError {
679 #[error("Parent texture is invalid or destroyed")]
680 InvalidTexture,
681 #[error("Not enough memory left")]
682 OutOfMemory,
683 #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")]
684 InvalidTextureViewDimension {
685 view: wgt::TextureViewDimension,
686 texture: wgt::TextureDimension,
687 },
688 #[error("Invalid texture view dimension `{0:?}` of a multisampled texture")]
689 InvalidMultisampledTextureViewDimension(wgt::TextureViewDimension),
690 #[error("Invalid texture depth `{depth}` for texture view of dimension `Cubemap`. Cubemap views must use images of size 6.")]
691 InvalidCubemapTextureDepth { depth: u32 },
692 #[error("Invalid texture depth `{depth}` for texture view of dimension `CubemapArray`. Cubemap views must use images with sizes which are a multiple of 6.")]
693 InvalidCubemapArrayTextureDepth { depth: u32 },
694 #[error("Source texture width and height must be equal for a texture view of dimension `Cube`/`CubeArray`")]
695 InvalidCubeTextureViewSize,
696 #[error("Mip level count is 0")]
697 ZeroMipLevelCount,
698 #[error("Array layer count is 0")]
699 ZeroArrayLayerCount,
700 #[error(
701 "TextureView mip level count + base mip level {requested} must be <= Texture mip level count {total}"
702 )]
703 TooManyMipLevels { requested: u32, total: u32 },
704 #[error("TextureView array layer count + base array layer {requested} must be <= Texture depth/array layer count {total}")]
705 TooManyArrayLayers { requested: u32, total: u32 },
706 #[error("Requested array layer count {requested} is not valid for the target view dimension {dim:?}")]
707 InvalidArrayLayerCount {
708 requested: u32,
709 dim: wgt::TextureViewDimension,
710 },
711 #[error("Aspect {requested_aspect:?} is not in the source texture format {texture_format:?}")]
712 InvalidAspect {
713 texture_format: wgt::TextureFormat,
714 requested_aspect: wgt::TextureAspect,
715 },
716 #[error("Unable to view texture {texture:?} as {view:?}")]
717 FormatReinterpretation {
718 texture: wgt::TextureFormat,
719 view: wgt::TextureFormat,
720 },
721}
722
723#[derive(Clone, Debug, Error)]
724#[non_exhaustive]
725pub enum TextureViewDestroyError {}
726
727impl<A: hal::Api> Resource for TextureView<A> {
728 const TYPE: &'static str = "TextureView";
729
730 fn life_guard(&self) -> &LifeGuard {
731 &self.life_guard
732 }
733}
734
735#[derive(Clone, Debug, PartialEq)]
737#[cfg_attr(feature = "trace", derive(serde::Serialize))]
738#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
739pub struct SamplerDescriptor<'a> {
740 pub label: Label<'a>,
744 pub address_modes: [wgt::AddressMode; 3],
746 pub mag_filter: wgt::FilterMode,
748 pub min_filter: wgt::FilterMode,
750 pub mipmap_filter: wgt::FilterMode,
752 pub lod_min_clamp: f32,
754 pub lod_max_clamp: f32,
756 pub compare: Option<wgt::CompareFunction>,
758 pub anisotropy_clamp: u16,
760 pub border_color: Option<wgt::SamplerBorderColor>,
763}
764
765#[derive(Debug)]
766pub struct Sampler<A: hal::Api> {
767 pub(crate) raw: A::Sampler,
768 pub(crate) device_id: Stored<DeviceId>,
769 pub(crate) life_guard: LifeGuard,
770 pub(crate) comparison: bool,
772 pub(crate) filtering: bool,
774}
775
776#[derive(Copy, Clone)]
777pub enum SamplerFilterErrorType {
778 MagFilter,
779 MinFilter,
780 MipmapFilter,
781}
782
783impl std::fmt::Debug for SamplerFilterErrorType {
784 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
785 match *self {
786 SamplerFilterErrorType::MagFilter => write!(f, "magFilter"),
787 SamplerFilterErrorType::MinFilter => write!(f, "minFilter"),
788 SamplerFilterErrorType::MipmapFilter => write!(f, "mipmapFilter"),
789 }
790 }
791}
792
793#[derive(Clone, Debug, Error)]
794#[non_exhaustive]
795pub enum CreateSamplerError {
796 #[error(transparent)]
797 Device(#[from] DeviceError),
798 #[error("Invalid lodMinClamp: {0}. Must be greater or equal to 0.0")]
799 InvalidLodMinClamp(f32),
800 #[error("Invalid lodMaxClamp: {lod_max_clamp}. Must be greater or equal to lodMinClamp (which is {lod_min_clamp}).")]
801 InvalidLodMaxClamp {
802 lod_min_clamp: f32,
803 lod_max_clamp: f32,
804 },
805 #[error("Invalid anisotropic clamp: {0}. Must be at least 1.")]
806 InvalidAnisotropy(u16),
807 #[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.")]
808 InvalidFilterModeWithAnisotropy {
809 filter_type: SamplerFilterErrorType,
810 filter_mode: wgt::FilterMode,
811 anisotropic_clamp: u16,
812 },
813 #[error("Cannot create any more samplers")]
814 TooManyObjects,
815 #[error(transparent)]
817 MissingFeatures(#[from] MissingFeatures),
818}
819
820impl<A: hal::Api> Resource for Sampler<A> {
821 const TYPE: &'static str = "Sampler";
822
823 fn life_guard(&self) -> &LifeGuard {
824 &self.life_guard
825 }
826}
827
828#[derive(Clone, Debug, Error)]
829#[non_exhaustive]
830pub enum CreateQuerySetError {
831 #[error(transparent)]
832 Device(#[from] DeviceError),
833 #[error("QuerySets cannot be made with zero queries")]
834 ZeroCount,
835 #[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")]
836 TooManyQueries { count: u32, maximum: u32 },
837 #[error(transparent)]
838 MissingFeatures(#[from] MissingFeatures),
839}
840
841pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
842
843#[derive(Debug)]
844pub struct QuerySet<A: hal::Api> {
845 pub(crate) raw: A::QuerySet,
846 pub(crate) device_id: Stored<DeviceId>,
847 pub(crate) life_guard: LifeGuard,
848 pub(crate) desc: wgt::QuerySetDescriptor<()>,
849}
850
851impl<A: hal::Api> Resource for QuerySet<A> {
852 const TYPE: &'static str = "QuerySet";
853
854 fn life_guard(&self) -> &LifeGuard {
855 &self.life_guard
856 }
857}
858
859#[derive(Clone, Debug, Error)]
860#[non_exhaustive]
861pub enum DestroyError {
862 #[error("Resource is invalid")]
863 Invalid,
864 #[error("Resource is already destroyed")]
865 AlreadyDestroyed,
866}