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}