1 //! Image related structures.
2 //!
3 //! An image is a block of GPU memory representing a grid of texels.
4 
5 use crate::{
6     buffer::Offset as RawOffset,
7     device, format,
8     pso::{Comparison, Rect},
9 };
10 use std::{f32, hash, ops::Range};
11 
12 /// Dimension size.
13 pub type Size = u32;
14 /// Number of MSAA samples.
15 pub type NumSamples = u8;
16 /// Image layer.
17 pub type Layer = u16;
18 /// Image mipmap level.
19 pub type Level = u8;
20 /// Maximum accessible mipmap level of an image.
21 pub const MAX_LEVEL: Level = 15;
22 /// A texel coordinate in an image.
23 pub 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))]
28 pub 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 
37 impl Extent {
38     /// Return true if one of the dimensions is zero.
is_empty(&self) -> bool39     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.
at_level(&self, level: Level) -> Self43     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.
rect(&self) -> Rect51     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))]
69 pub 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 
78 impl 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.
into_bounds(self, extent: &Extent) -> Range<Offset>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))]
97 pub 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)]
107 pub 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)]
133 pub 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)]
159 pub 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))]
173 pub 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)]
190 pub 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.
200 pub 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))]
214 pub 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 
223 impl Kind {
224     /// Get the image extent.
extent(&self) -> Extent225     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.
level_extent(&self, level: Level) -> Extent246     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.
compute_num_levels(&self) -> Level270     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.
num_layers(&self) -> Layer288     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.
num_samples(&self) -> NumSamples296     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))]
308 pub 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 
328 bitflags!(
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 
342 bitflags!(
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 
368 impl Usage {
369     /// Returns true if this image can be used in transfer operations.
can_transfer(&self) -> bool370     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.
can_target(&self) -> bool375     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))]
383 pub 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))]
403 pub 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))]
418 pub struct Lod(pub f32);
419 
420 impl Lod {
421     /// Possible LOD range.
422     pub const RANGE: Range<Self> = Lod(f32::MIN)..Lod(f32::MAX);
423 }
424 
425 impl Eq for Lod {}
426 impl hash::Hash for Lod {
hash<H: hash::Hasher>(&self, state: &mut H)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))]
435 pub struct PackedColor(pub u32);
436 
437 impl From<[f32; 4]> for PackedColor {
from(c: [f32; 4]) -> PackedColor438     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 
447 impl Into<[f32; 4]> for PackedColor {
into(self) -> [f32; 4]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))]
461 pub enum BorderColor {
462     ///
463     TransparentBlack,
464     ///
465     OpaqueBlack,
466     ///
467     OpaqueWhite,
468 }
469 
470 impl Into<[f32; 4]> for BorderColor {
into(self) -> [f32; 4]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))]
486 pub 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 
516 impl 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.
new(filter: Filter, wrap: WrapMode) -> Self519     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))]
546 pub 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 
574 impl Default for Layout {
default() -> Self575     fn default() -> Self {
576         Self::General
577     }
578 }
579 
580 bitflags!(
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.
617 pub 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))]
622 pub 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))]
634 pub 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))]
646 pub 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 
665 impl From<SubresourceLayers> for SubresourceRange {
from(sub: SubresourceLayers) -> Self666     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 
677 impl SubresourceRange {
678     /// Resolve the concrete level count based on the total number of layers in an image.
resolve_level_count(&self, total: Level) -> Level679     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.
resolve_layer_count(&self, total: Layer) -> Layer684     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))]
692 pub 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))]
708 pub 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)]
721 pub 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
get_tile_size(tile_kind: TileKind, texel_bits: u16) -> (u16, u16, u16)731 pub 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))]
765 pub 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 }
774