blob: 5b5a6a5072e98509a583ceff464abb4e94aa4566 [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{
sys::Image, ImageAspects, ImageDescriptorLayouts, ImageDimensions, ImageLayout,
ImageSubresourceLayers, ImageSubresourceRange, ImageUsage, SampleCount,
};
use crate::{
device::{Device, DeviceOwned},
format::{Format, FormatFeatures},
SafeDeref,
};
use std::{
fmt::{Debug, Error as FmtError, Formatter},
hash::{Hash, Hasher},
sync::Arc,
};
/// Trait for types that represent the way a GPU can access an image.
pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
/// Returns the inner unsafe image object used by this image.
fn inner(&self) -> ImageInner<'_>;
/// Returns the dimensions of the image.
#[inline]
fn dimensions(&self) -> ImageDimensions {
let inner = self.inner();
match self
.inner()
.image
.dimensions()
.mip_level_dimensions(inner.first_mipmap_level)
.unwrap()
{
ImageDimensions::Dim1d {
width,
array_layers: _,
} => ImageDimensions::Dim1d {
width,
array_layers: inner.num_layers,
},
ImageDimensions::Dim2d {
width,
height,
array_layers: _,
} => ImageDimensions::Dim2d {
width,
height,
array_layers: inner.num_layers,
},
ImageDimensions::Dim3d {
width,
height,
depth,
} => ImageDimensions::Dim3d {
width,
height,
depth,
},
}
}
/// Returns the format of this image.
#[inline]
fn format(&self) -> Format {
self.inner().image.format().unwrap()
}
/// Returns the features supported by the image's format.
#[inline]
fn format_features(&self) -> FormatFeatures {
self.inner().image.format_features()
}
/// Returns the number of mipmap levels of this image.
#[inline]
fn mip_levels(&self) -> u32 {
self.inner().num_mipmap_levels
}
/// Returns the number of samples of this image.
#[inline]
fn samples(&self) -> SampleCount {
self.inner().image.samples()
}
/// Returns the usage the image was created with.
#[inline]
fn usage(&self) -> ImageUsage {
self.inner().image.usage()
}
/// Returns the stencil usage the image was created with.
#[inline]
fn stencil_usage(&self) -> ImageUsage {
self.inner().image.stencil_usage()
}
/// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
/// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
fn subresource_layers(&self) -> ImageSubresourceLayers {
ImageSubresourceLayers::from_parameters(self.format(), self.dimensions().array_layers())
}
/// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
/// only the `color` aspect is selected.
#[inline]
fn subresource_range(&self) -> ImageSubresourceRange {
ImageSubresourceRange {
aspects: self.format().aspects()
- (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
mip_levels: 0..self.mip_levels(),
array_layers: 0..self.dimensions().array_layers(),
}
}
/// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
/// This method allows the image memory barrier creation process to signal when an image
/// has been transitioned out of its initial `Undefined` or `Preinitialized` state. This
/// allows vulkano to avoid creating unnecessary image memory barriers between future
/// uses of the image.
///
/// ## Unsafe
///
/// If a user calls this method outside of the intended context and signals that the layout
/// is no longer `Undefined` or `Preinitialized` when it is still in an `Undefined` or
/// `Preinitialized` state, this may result in the vulkan implementation attempting to use
/// an image in an invalid layout. The same problem must be considered by the implementer
/// of the method.
#[inline]
unsafe fn layout_initialized(&self) {}
#[inline]
fn is_layout_initialized(&self) -> bool {
false
}
#[inline]
fn initial_layout(&self) -> ImageLayout {
self.inner().image.initial_layout()
}
/// Returns the layout that the image has when it is first used in a primary command buffer.
///
/// The first time you use an image in an `AutoCommandBufferBuilder`, vulkano will suppose that
/// the image is in the layout returned by this function. Later when the command buffer is
/// submitted vulkano will check whether the image is actually in this layout, and if it is not
/// the case then an error will be returned.
/// TODO: ^ that check is not yet implemented
fn initial_layout_requirement(&self) -> ImageLayout;
/// Returns the layout that the image must be returned to before the end of the command buffer.
///
/// When an image is used in an `AutoCommandBufferBuilder` vulkano will automatically
/// transition this image to the layout returned by this function at the end of the command
/// buffer, if necessary.
///
/// Except for special cases, this value should likely be the same as the one returned by
/// `initial_layout_requirement` so that the user can submit multiple command buffers that use
/// this image one after the other.
fn final_layout_requirement(&self) -> ImageLayout;
/// Wraps around this `ImageAccess` and returns an identical `ImageAccess` but whose initial
/// layout requirement is either `Undefined` or `Preinitialized`.
#[inline]
unsafe fn forced_undefined_initial_layout(
self,
preinitialized: bool,
) -> Arc<ImageAccessFromUndefinedLayout<Self>>
where
Self: Sized,
{
Arc::new(ImageAccessFromUndefinedLayout {
image: self,
preinitialized,
})
}
/// Returns an [`ImageDescriptorLayouts`] structure specifying the image layout to use
/// in descriptors of various kinds.
///
/// This must return `Some` if the image is to be used to create an image view.
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>;
}
/// Inner information about an image.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImageInner<'a> {
/// The underlying image object.
pub image: &'a Arc<Image>,
/// The first layer of `image` to consider.
pub first_layer: u32,
/// The number of layers of `image` to consider.
pub num_layers: u32,
/// The first mipmap level of `image` to consider.
pub first_mipmap_level: u32,
/// The number of mipmap levels of `image` to consider.
pub num_mipmap_levels: u32,
}
impl Debug for dyn ImageAccess {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
f.debug_struct("dyn ImageAccess")
.field("inner", &self.inner())
.finish()
}
}
impl PartialEq for dyn ImageAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner()
}
}
impl Eq for dyn ImageAccess {}
impl Hash for dyn ImageAccess {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
}
}
/// Wraps around an object that implements `ImageAccess` and modifies the initial layout
/// requirement to be either `Undefined` or `Preinitialized`.
#[derive(Debug, Copy, Clone)]
pub struct ImageAccessFromUndefinedLayout<I> {
image: I,
preinitialized: bool,
}
unsafe impl<I> DeviceOwned for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
fn inner(&self) -> ImageInner<'_> {
self.image.inner()
}
fn initial_layout_requirement(&self) -> ImageLayout {
if self.preinitialized {
ImageLayout::Preinitialized
} else {
ImageLayout::Undefined
}
}
fn final_layout_requirement(&self) -> ImageLayout {
self.image.final_layout_requirement()
}
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
self.image.descriptor_layouts()
}
}
impl<I> PartialEq for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner()
}
}
impl<I> Eq for ImageAccessFromUndefinedLayout<I> where I: ImageAccess {}
impl<I> Hash for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
}
}
pub unsafe trait ImageContent<P>: ImageAccess {
/// Checks whether pixels of type `P` match the format of the image.
fn matches_format(&self) -> bool;
}
unsafe impl<T> ImageAccess for T
where
T: SafeDeref + Send + Sync,
T::Target: ImageAccess,
{
fn inner(&self) -> ImageInner<'_> {
(**self).inner()
}
fn initial_layout_requirement(&self) -> ImageLayout {
(**self).initial_layout_requirement()
}
fn final_layout_requirement(&self) -> ImageLayout {
(**self).final_layout_requirement()
}
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
(**self).descriptor_layouts()
}
unsafe fn layout_initialized(&self) {
(**self).layout_initialized();
}
fn is_layout_initialized(&self) -> bool {
(**self).is_layout_initialized()
}
}