gfx_hal/
image.rs

1//! Image related structures.
2//!
3//! An image is a block of GPU memory representing a grid of texels.
4
5use crate::{
6    buffer::Offset as RawOffset,
7    device, format,
8    pso::{Comparison, Rect},
9};
10use std::{f32, hash, ops::Range};
11
12/// Dimension size.
13pub type Size = u32;
14/// Number of MSAA samples.
15pub type NumSamples = u8;
16/// Image layer.
17pub type Layer = u16;
18/// Image mipmap level.
19pub type Level = u8;
20/// Maximum accessible mipmap level of an image.
21pub const MAX_LEVEL: Level = 15;
22/// A texel coordinate in an image.
23pub type TexelCoordinate = i32;
24
25/// Describes the size of an image, which may be up to three dimensional.
26#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub struct Extent {
29    /// Image width
30    pub width: Size,
31    /// Image height
32    pub height: Size,
33    /// Image depth.
34    pub depth: Size,
35}
36
37impl Extent {
38    /// Return true if one of the dimensions is zero.
39    pub fn is_empty(&self) -> bool {
40        self.width == 0 || self.height == 0 || self.depth == 0
41    }
42    /// Get the extent at a particular mipmap level.
43    pub fn at_level(&self, level: Level) -> Self {
44        Extent {
45            width: 1.max(self.width >> level),
46            height: 1.max(self.height >> level),
47            depth: 1.max(self.depth >> level),
48        }
49    }
50    /// Get a rectangle for the full area of extent.
51    pub fn rect(&self) -> Rect {
52        Rect {
53            x: 0,
54            y: 0,
55            w: self.width as i16,
56            h: self.height as i16,
57        }
58    }
59}
60
61/// An offset into an `Image` used for image-to-image
62/// copy operations.  All offsets are in texels, and
63/// specifying offsets other than 0 for dimensions
64/// that do not exist is undefined behavior -- for
65/// example, specifying a `z` offset of `1` in a
66/// two-dimensional image.
67#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69pub struct Offset {
70    /// X offset.
71    pub x: TexelCoordinate,
72    /// Y offset.
73    pub y: TexelCoordinate,
74    /// Z offset.
75    pub z: TexelCoordinate,
76}
77
78impl Offset {
79    /// Zero offset shortcut.
80    pub const ZERO: Self = Offset { x: 0, y: 0, z: 0 };
81
82    /// Convert the offset into 2-sided bounds given the extent.
83    pub fn into_bounds(self, extent: &Extent) -> Range<Offset> {
84        let end = Offset {
85            x: self.x + extent.width as i32,
86            y: self.y + extent.height as i32,
87            z: self.z + extent.depth as i32,
88        };
89        self..end
90    }
91}
92
93/// Image tiling modes.
94#[repr(u32)]
95#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97pub enum Tiling {
98    /// Optimal tiling for GPU memory access. Implementation-dependent.
99    Optimal = 0,
100    /// Optimal for CPU read/write. Texels are laid out in row-major order,
101    /// possibly with some padding on each row.
102    Linear = 1,
103}
104
105/// Pure image object creation error.
106#[derive(Clone, Debug, PartialEq, thiserror::Error)]
107pub enum CreationError {
108    /// Out of either host or device memory.
109    #[error(transparent)]
110    OutOfMemory(#[from] device::OutOfMemory),
111    /// The format is not supported by the device.
112    #[error("Unsupported format: {0:?}")]
113    Format(format::Format),
114    /// The kind doesn't support a particular operation.
115    #[error("Specified kind doesn't support particular operation")]
116    Kind,
117    /// Failed to map a given multisampled kind to the device.
118    #[error("Specified format doesn't support specified sampling {0:}")]
119    Samples(NumSamples),
120    /// Unsupported size in one of the dimensions.
121    #[error("Unsupported size in one of the dimensions {0:}")]
122    Size(Size),
123    /// The given data has a different size than the target image slice.
124    #[error("The given data has a different size ({0:}) than the target image slice")]
125    Data(usize),
126    /// The mentioned usage mode is not supported
127    #[error("Unsupported usage: {0:?}")]
128    Usage(Usage),
129}
130
131/// Error creating an `ImageView`.
132#[derive(Clone, Debug, PartialEq, thiserror::Error)]
133pub enum ViewCreationError {
134    /// Out of either Host or Device memory
135    #[error(transparent)]
136    OutOfMemory(#[from] device::OutOfMemory),
137    /// The required usage flag is not present in the image.
138    #[error("Specified usage flags are not present in the image {0:?}")]
139    Usage(Usage),
140    /// Selected mip level doesn't exist.
141    #[error("Selected level doesn't exist in the image {0:}")]
142    Level(Level),
143    /// Selected array layer doesn't exist.
144    #[error(transparent)]
145    Layer(#[from] LayerError),
146    /// An incompatible format was requested for the view.
147    #[error("Incompatible format: {0:?}")]
148    BadFormat(format::Format),
149    /// An incompatible view kind was requested for the view.
150    #[error("Incompatible kind: {0:?}")]
151    BadKind(ViewKind),
152    /// The backend refused for some reason.
153    #[error("Implementation specific error occurred")]
154    Unsupported,
155}
156
157/// An error associated with selected image layer.
158#[derive(Clone, Debug, PartialEq, thiserror::Error)]
159pub enum LayerError {
160    /// The source image kind doesn't support array slices.
161    #[error("Source image doesn't support view kind {0:?}")]
162    NotExpected(Kind),
163    /// Selected layers are outside of the provided range.
164    #[error("Selected layers are out of bounds")]
165    OutOfBounds,
166}
167
168/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
169/// image when sampling. They correspond to increasing levels of quality,
170/// but also cost.
171#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173pub enum Filter {
174    /// Selects a single texel from the current mip level and uses its value.
175    ///
176    /// Mip filtering selects the filtered value from one level.
177    Nearest,
178    /// Selects multiple texels and calculates the value via multivariate interpolation.
179    ///     * 1D: Linear interpolation
180    ///     * 2D/Cube: Bilinear interpolation
181    ///     * 3D: Trilinear interpolation
182    Linear,
183}
184
185/// The face of a cube image to do an operation on.
186#[allow(missing_docs)]
187#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
189#[repr(u8)]
190pub enum CubeFace {
191    PosX,
192    NegX,
193    PosY,
194    NegY,
195    PosZ,
196    NegZ,
197}
198
199/// A constant array of cube faces in the order they map to the hardware.
200pub const CUBE_FACES: [CubeFace; 6] = [
201    CubeFace::PosX,
202    CubeFace::NegX,
203    CubeFace::PosY,
204    CubeFace::NegY,
205    CubeFace::PosZ,
206    CubeFace::NegZ,
207];
208
209/// Specifies the dimensionality of an image to be allocated,
210/// along with the number of mipmap layers and MSAA samples
211/// if applicable.
212#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
213#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
214pub enum Kind {
215    /// A single one-dimensional row of texels.
216    D1(Size, Layer),
217    /// Two-dimensional image.
218    D2(Size, Size, Layer, NumSamples),
219    /// Volumetric image.
220    D3(Size, Size, Size),
221}
222
223impl Kind {
224    /// Get the image extent.
225    pub fn extent(&self) -> Extent {
226        match *self {
227            Kind::D1(width, _) => Extent {
228                width,
229                height: 1,
230                depth: 1,
231            },
232            Kind::D2(width, height, _, _) => Extent {
233                width,
234                height,
235                depth: 1,
236            },
237            Kind::D3(width, height, depth) => Extent {
238                width,
239                height,
240                depth,
241            },
242        }
243    }
244
245    /// Get the extent of a particular mipmap level.
246    pub fn level_extent(&self, level: Level) -> Extent {
247        use std::cmp::{max, min};
248        // must be at least 1
249        let map = |val| max(min(val, 1), val >> min(level, MAX_LEVEL));
250        match *self {
251            Kind::D1(w, _) => Extent {
252                width: map(w),
253                height: 1,
254                depth: 1,
255            },
256            Kind::D2(w, h, _, _) => Extent {
257                width: map(w),
258                height: map(h),
259                depth: 1,
260            },
261            Kind::D3(w, h, d) => Extent {
262                width: map(w),
263                height: map(h),
264                depth: map(d),
265            },
266        }
267    }
268
269    /// Count the number of mipmap levels.
270    pub fn compute_num_levels(&self) -> Level {
271        use std::cmp::max;
272        match *self {
273            Kind::D2(_, _, _, s) if s > 1 => {
274                // anti-aliased images can't have mipmaps
275                1
276            }
277            _ => {
278                let extent = self.extent();
279                let dominant = max(max(extent.width, extent.height), extent.depth);
280                (1..).find(|level| dominant >> level == 0).unwrap()
281            }
282        }
283    }
284
285    /// Return the number of layers in an array type.
286    ///
287    /// Each cube face counts as separate layer.
288    pub fn num_layers(&self) -> Layer {
289        match *self {
290            Kind::D1(_, a) | Kind::D2(_, _, a, _) => a,
291            Kind::D3(..) => 1,
292        }
293    }
294
295    /// Return the number of MSAA samples for the kind.
296    pub fn num_samples(&self) -> NumSamples {
297        match *self {
298            Kind::D1(..) => 1,
299            Kind::D2(_, _, _, s) => s,
300            Kind::D3(..) => 1,
301        }
302    }
303}
304
305/// Specifies the kind/dimensionality of an image view.
306#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
307#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
308pub enum ViewKind {
309    /// A single one-dimensional row of texels.
310    D1,
311    /// An array of rows of texels. Equivalent to `D2` except that texels
312    /// in different rows are not sampled, so filtering will be constrained
313    /// to a single row of texels at a time.
314    D1Array,
315    /// A traditional 2D image, with rows arranged contiguously.
316    D2,
317    /// An array of 2D images. Equivalent to `D3` except that texels in
318    /// a different depth level are not sampled.
319    D2Array,
320    /// A volume image, with each 2D layer arranged contiguously.
321    D3,
322    /// A set of 6 2D images, one for each face of a cube.
323    Cube,
324    /// An array of Cube images.
325    CubeArray,
326}
327
328bitflags!(
329    /// Capabilities to create views into an image.
330    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
331    #[derive(Default)]
332    pub struct ViewCapabilities: u32 {
333        /// Support creation of views with different formats.
334        const MUTABLE_FORMAT = 0x0000_0008;
335        /// Support creation of `Cube` and `CubeArray` kinds of views.
336        const KIND_CUBE      = 0x0000_0010;
337        /// Support creation of `D2Array` kind of view.
338        const KIND_2D_ARRAY  = 0x0000_0020;
339    }
340);
341
342bitflags!(
343    /// TODO: Find out if TRANSIENT_ATTACHMENT + INPUT_ATTACHMENT
344    /// are applicable on backends other than Vulkan. --AP
345    /// Image usage flags
346    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
347    pub struct Usage: u32 {
348        /// The image is used as a transfer source.
349        const TRANSFER_SRC = 0x1;
350        /// The image is used as a transfer destination.
351        const TRANSFER_DST = 0x2;
352        /// The image is a [sampled image](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#descriptorsets-sampledimage)
353        const SAMPLED = 0x4;
354        /// The image is a [storage image](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#descriptorsets-storageimage)
355        const STORAGE = 0x8;
356        /// The image is used as a color attachment -- that is, color input to a rendering pass.
357        const COLOR_ATTACHMENT = 0x10;
358        /// The image is used as a depth attachment.
359        const DEPTH_STENCIL_ATTACHMENT = 0x20;
360        ///
361        const TRANSIENT_ATTACHMENT = 0x40;
362        ///
363        const INPUT_ATTACHMENT = 0x80;
364
365    }
366);
367
368impl Usage {
369    /// Returns true if this image can be used in transfer operations.
370    pub fn can_transfer(&self) -> bool {
371        self.intersects(Usage::TRANSFER_SRC | Usage::TRANSFER_DST)
372    }
373
374    /// Returns true if this image can be used as a target.
375    pub fn can_target(&self) -> bool {
376        self.intersects(Usage::COLOR_ATTACHMENT | Usage::DEPTH_STENCIL_ATTACHMENT)
377    }
378}
379
380/// Specifies how image coordinates outside the range `[0, 1]` are handled.
381#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
382#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
383pub enum WrapMode {
384    /// Tile the image, that is, sample the coordinate modulo `1.0`, so
385    /// addressing the image beyond an edge will "wrap" back from the
386    /// other edge.
387    Tile,
388    /// Mirror the image. Like tile, but uses abs(coord) before the modulo.
389    Mirror,
390    /// Clamp the image to the value at `0.0` or `1.0` respectively.
391    Clamp,
392    /// Use border color.
393    Border,
394    /// Mirror once and clamp to edge otherwise.
395    ///
396    /// Only valid if `Features::SAMPLER_MIRROR_CLAMP_EDGE` is enabled.
397    MirrorClamp,
398}
399
400/// Specifies how the image texels in the filter kernel are reduced to a single value.
401#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
402#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
403pub enum ReductionMode {
404    ///
405    WeightedAverage,
406    ///
407    /// Only valid if `Features::SAMPLER_FILTER_MINMAX` is enabled.
408    Minimum,
409    ///
410    /// Only valid if `Features::SAMPLER_FILTER_MINMAX` is enabled.
411    Maximum,
412}
413
414/// A wrapper for the LOD level of an image. Needed so that we can
415/// implement Eq and Hash for it.
416#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
417#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
418pub struct Lod(pub f32);
419
420impl Lod {
421    /// Possible LOD range.
422    pub const RANGE: Range<Self> = Lod(f32::MIN)..Lod(f32::MAX);
423}
424
425impl Eq for Lod {}
426impl hash::Hash for Lod {
427    fn hash<H: hash::Hasher>(&self, state: &mut H) {
428        self.0.to_bits().hash(state)
429    }
430}
431
432/// A wrapper for an RGBA color with 8 bits per texel, encoded as a u32.
433#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
434#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
435pub struct PackedColor(pub u32);
436
437impl From<[f32; 4]> for PackedColor {
438    fn from(c: [f32; 4]) -> PackedColor {
439        PackedColor(
440            c.iter()
441                .rev()
442                .fold(0, |u, &c| (u << 8) + (c * 255.0) as u32),
443        )
444    }
445}
446
447impl Into<[f32; 4]> for PackedColor {
448    fn into(self) -> [f32; 4] {
449        let mut out = [0.0; 4];
450        for (i, channel) in out.iter_mut().enumerate() {
451            let byte = (self.0 >> (i << 3)) & 0xFF;
452            *channel = byte as f32 / 255.0;
453        }
454        out
455    }
456}
457
458/// The border color for `WrapMode::Border` wrap mode.
459#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
460#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
461pub enum BorderColor {
462    ///
463    TransparentBlack,
464    ///
465    OpaqueBlack,
466    ///
467    OpaqueWhite,
468}
469
470impl Into<[f32; 4]> for BorderColor {
471    fn into(self) -> [f32; 4] {
472        match self {
473            BorderColor::TransparentBlack => [0.0, 0.0, 0.0, 0.0],
474            BorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0],
475            BorderColor::OpaqueWhite => [1.0, 1.0, 1.0, 1.0],
476        }
477    }
478}
479
480/// Specifies how to sample from an image.  These are all the parameters
481/// available that alter how the GPU goes from a coordinate in an image
482/// to producing an actual value from the texture, including filtering/
483/// scaling, wrap mode, etc.
484#[derive(Clone, Debug, Eq, Hash, PartialEq)]
485#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
486pub struct SamplerDesc {
487    /// Minification filter method to use.
488    pub min_filter: Filter,
489    /// Magnification filter method to use.
490    pub mag_filter: Filter,
491    /// Mip filter method to use.
492    pub mip_filter: Filter,
493    /// Reduction mode over the filter.
494    pub reduction_mode: ReductionMode,
495    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
496    /// speak).
497    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
498    /// This bias is added to every computed mipmap level (N + lod_bias). For
499    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
500    /// use mipmap level 3.
501    pub lod_bias: Lod,
502    /// This range is used to clamp LOD level used for sampling.
503    pub lod_range: Range<Lod>,
504    /// Comparison mode, used primary for a shadow map.
505    pub comparison: Option<Comparison>,
506    /// Border color is used when one of the wrap modes is set to border.
507    pub border: BorderColor,
508    /// Specifies whether the texture coordinates are normalized.
509    pub normalized: bool,
510    /// Anisotropic filtering.
511    ///
512    /// Can be `Some(_)` only if `Features::SAMPLER_ANISOTROPY` is enabled.
513    pub anisotropy_clamp: Option<u8>,
514}
515
516impl SamplerDesc {
517    /// Create a new sampler description with a given filter method for all filtering operations
518    /// and a wrapping mode, using no LOD modifications.
519    pub fn new(filter: Filter, wrap: WrapMode) -> Self {
520        SamplerDesc {
521            min_filter: filter,
522            mag_filter: filter,
523            mip_filter: filter,
524            reduction_mode: ReductionMode::WeightedAverage,
525            wrap_mode: (wrap, wrap, wrap),
526            lod_bias: Lod(0.0),
527            lod_range: Lod::RANGE.clone(),
528            comparison: None,
529            border: BorderColor::TransparentBlack,
530            normalized: true,
531            anisotropy_clamp: None,
532        }
533    }
534}
535
536/// Specifies options for how memory for an image is arranged.
537/// These are hints to the GPU driver and may or may not have actual
538/// performance effects, but describe constraints on how the data
539/// may be used that a program *must* obey. They do not specify
540/// how channel values or such are laid out in memory; the actual
541/// image data is considered opaque.
542///
543/// Details may be found in [the Vulkan spec](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#resources-image-layouts)
544#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
546pub enum Layout {
547    /// General purpose, no restrictions on usage.
548    General,
549    /// Must only be used as a color attachment in a framebuffer.
550    ColorAttachmentOptimal,
551    /// Must only be used as a depth attachment in a framebuffer.
552    DepthStencilAttachmentOptimal,
553    /// Must only be used as a depth attachment in a framebuffer,
554    /// or as a read-only depth or stencil buffer in a shader.
555    DepthStencilReadOnlyOptimal,
556    /// Must only be used as a read-only image in a shader.
557    ShaderReadOnlyOptimal,
558    /// Must only be used as the source for a transfer command.
559    TransferSrcOptimal,
560    /// Must only be used as the destination for a transfer command.
561    TransferDstOptimal,
562    /// No layout, does not support device access.  Only valid as a
563    /// source layout when transforming data to a specific destination
564    /// layout or initializing data.  Does NOT guarentee that the contents
565    /// of the source buffer are preserved.
566    Undefined,
567    /// Like `Undefined`, but does guarentee that the contents of the source
568    /// buffer are preserved.
569    Preinitialized,
570    /// The layout that an image must be in to be presented to the display.
571    Present,
572}
573
574impl Default for Layout {
575    fn default() -> Self {
576        Self::General
577    }
578}
579
580bitflags!(
581    /// Bitflags to describe how memory in an image or buffer can be accessed.
582    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
583    pub struct Access: u32 {
584        /// Read access to an input attachment from within a fragment shader.
585        const INPUT_ATTACHMENT_READ = 0x10;
586        /// Read-only state for SRV access, or combine with `SHADER_WRITE` to have r/w access to UAV.
587        const SHADER_READ = 0x20;
588        /// Writeable state for UAV access.
589        /// Combine with `SHADER_READ` to have r/w access to UAV.
590        const SHADER_WRITE = 0x40;
591        /// Read state but can only be combined with `COLOR_ATTACHMENT_WRITE`.
592        const COLOR_ATTACHMENT_READ = 0x80;
593        /// Write-only state but can be combined with `COLOR_ATTACHMENT_READ`.
594        const COLOR_ATTACHMENT_WRITE = 0x100;
595        /// Read access to a depth/stencil attachment in a depth or stencil operation.
596        const DEPTH_STENCIL_ATTACHMENT_READ = 0x200;
597        /// Write access to a depth/stencil attachment in a depth or stencil operation.
598        const DEPTH_STENCIL_ATTACHMENT_WRITE = 0x400;
599        /// Read access to the buffer in a copy operation.
600        const TRANSFER_READ = 0x800;
601        /// Write access to the buffer in a copy operation.
602        const TRANSFER_WRITE = 0x1000;
603        /// Read access for raw memory to be accessed by the host system (ie, CPU).
604        const HOST_READ = 0x2000;
605        /// Write access for raw memory to be accessed by the host system.
606        const HOST_WRITE = 0x4000;
607        /// Read access for memory to be accessed by a non-specific entity.  This may
608        /// be the host system, or it may be something undefined or specified by an
609        /// extension.
610        const MEMORY_READ = 0x8000;
611        /// Write access for memory to be accessed by a non-specific entity.
612        const MEMORY_WRITE = 0x10000;
613    }
614);
615
616/// Image state, combining access methods and the image's layout.
617pub type State = (Access, Layout);
618
619/// Selector of a concrete subresource in an image.
620#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
621#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
622pub struct Subresource {
623    /// Included aspects: color/depth/stencil
624    pub aspects: format::Aspects,
625    /// Selected mipmap level
626    pub level: Level,
627    /// Selected array level
628    pub layer: Layer,
629}
630
631/// A subset of resource layers contained within an image's level.
632#[derive(Clone, Debug, Hash, PartialEq, Eq)]
633#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
634pub struct SubresourceLayers {
635    /// Included aspects: color/depth/stencil
636    pub aspects: format::Aspects,
637    /// Selected mipmap level
638    pub level: Level,
639    /// Included array levels
640    pub layers: Range<Layer>,
641}
642
643/// A subset of resources contained within an image.
644#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
645#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
646pub struct SubresourceRange {
647    /// Included aspects: color/depth/stencil
648    pub aspects: format::Aspects,
649    /// First mipmap level in this subresource
650    pub level_start: Level,
651    /// Number of sequential levels in this subresource.
652    ///
653    /// A value of `None` indicates the subresource contains
654    /// all of the remaining levels.
655    pub level_count: Option<Level>,
656    /// First layer in this subresource
657    pub layer_start: Layer,
658    /// Number of sequential layers in this subresource.
659    ///
660    /// A value of `None` indicates the subresource contains
661    /// all of the remaining layers.
662    pub layer_count: Option<Layer>,
663}
664
665impl From<SubresourceLayers> for SubresourceRange {
666    fn from(sub: SubresourceLayers) -> Self {
667        SubresourceRange {
668            aspects: sub.aspects,
669            level_start: sub.level,
670            level_count: Some(1),
671            layer_start: sub.layers.start,
672            layer_count: Some(sub.layers.end - sub.layers.start),
673        }
674    }
675}
676
677impl SubresourceRange {
678    /// Resolve the concrete level count based on the total number of layers in an image.
679    pub fn resolve_level_count(&self, total: Level) -> Level {
680        self.level_count.unwrap_or(total - self.level_start)
681    }
682
683    /// Resolve the concrete layer count based on the total number of layer in an image.
684    pub fn resolve_layer_count(&self, total: Layer) -> Layer {
685        self.layer_count.unwrap_or(total - self.layer_start)
686    }
687}
688
689/// Image format properties.
690#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
691#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
692pub struct FormatProperties {
693    /// Maximum extent.
694    pub max_extent: Extent,
695    /// Max number of mipmap levels.
696    pub max_levels: Level,
697    /// Max number of array layers.
698    pub max_layers: Layer,
699    /// Bit mask of supported sample counts.
700    pub sample_count_mask: NumSamples,
701    /// Maximum size of the resource in bytes.
702    pub max_resource_size: usize,
703}
704
705/// Footprint of a subresource in memory.
706#[derive(Debug, Clone, PartialEq, Eq, Hash)]
707#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
708pub struct SubresourceFootprint {
709    /// Byte slice occupied by the subresource.
710    pub slice: Range<RawOffset>,
711    /// Byte distance between rows.
712    pub row_pitch: RawOffset,
713    /// Byte distance between array layers.
714    pub array_pitch: RawOffset,
715    /// Byte distance between depth slices.
716    pub depth_pitch: RawOffset,
717}
718
719/// The type of tile to check for with `get_tile_size`.
720#[derive(Debug)]
721pub enum TileKind {
722    /// A volume or 3D image tile kind.
723    Volume,
724    /// A flat or 2D image tile kind, with the number of samples for MSAA.
725    Flat(NumSamples),
726}
727
728// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#sparsememory-standard-shapes
729// https://docs.microsoft.com/en-us/windows/win32/direct3d11/texture2d-and-texture2darray-subresource-tiling
730/// Tile or block size for sparse binding
731pub fn get_tile_size(tile_kind: TileKind, texel_bits: u16) -> (u16, u16, u16) {
732    match tile_kind {
733        TileKind::Flat(samples) => {
734            let sizes = match texel_bits {
735                8 => (256, 256, 1),
736                16 => (256, 128, 1),
737                32 => (128, 128, 1),
738                64 => (128, 64, 1),
739                128 => (64, 64, 1),
740                _ => unimplemented!(),
741            };
742            match samples {
743                1 => sizes,
744                2 => (sizes.0 / 2, sizes.1, 1),
745                4 => (sizes.0 / 2, sizes.1 / 2, 1),
746                8 => (sizes.0 / 4, sizes.1 / 2, 1),
747                16 => (sizes.0 / 4, sizes.1 / 4, 1),
748                _ => unimplemented!(),
749            }
750        }
751        TileKind::Volume => match texel_bits {
752            8 => (64, 32, 32),
753            16 => (32, 32, 32),
754            32 => (32, 32, 16),
755            64 => (32, 16, 16),
756            128 => (16, 16, 16),
757            _ => unimplemented!(),
758        },
759    }
760}
761
762/// Description of a framebuffer attachment.
763#[derive(Debug, Clone, PartialEq, Eq, Hash)]
764#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
765pub struct FramebufferAttachment {
766    /// Usage that an image is created with.
767    pub usage: Usage,
768    /// View capabilities that an image is created with.
769    pub view_caps: ViewCapabilities,
770    //TODO: make this a list
771    /// The image view format.
772    pub format: format::Format,
773}