use super::ImageFormatInfo;
use crate::device::{Device, DeviceOwned};
use crate::format::{ChromaSampling, Format, FormatFeatures};
use crate::image::{
ImageAccess, ImageAspects, ImageDimensions, ImageTiling, ImageType, ImageUsage, SampleCount,
};
use crate::sampler::ycbcr::SamplerYcbcrConversion;
use crate::sampler::ComponentMapping;
use crate::OomError;
use crate::VulkanObject;
use crate::{check_errors, Error};
use std::error;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::mem::MaybeUninit;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
pub struct ImageView<I>
where
I: ImageAccess + ?Sized,
{
handle: ash::vk::ImageView,
image: Arc<I>,
array_layers: Range<u32>,
aspects: ImageAspects,
component_mapping: ComponentMapping,
format: Option<Format>,
format_features: FormatFeatures,
mip_levels: Range<u32>,
sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
usage: ImageUsage,
view_type: ImageViewType,
filter_cubic: bool,
filter_cubic_minmax: bool,
}
impl<I> ImageView<I>
where
I: ImageAccess + ?Sized,
{
pub fn new(
image: Arc<I>,
mut create_info: ImageViewCreateInfo,
) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
let (format_features, usage) = Self::validate(&image, &mut create_info)?;
let handle = unsafe { Self::create(&image, &create_info)? };
let ImageViewCreateInfo {
view_type,
format,
component_mapping,
aspects,
array_layers,
mip_levels,
sampler_ycbcr_conversion,
_ne: _,
} = create_info;
let image_inner = image.inner().image;
let image_type = image.dimensions().image_type();
let (filter_cubic, filter_cubic_minmax) = if let Some(properties) = image_inner
.device()
.physical_device()
.image_format_properties(ImageFormatInfo {
format: image_inner.format(),
image_type,
tiling: image_inner.tiling(),
usage: *image_inner.usage(),
image_view_type: Some(view_type),
mutable_format: image_inner.mutable_format(),
cube_compatible: image_inner.cube_compatible(),
array_2d_compatible: image_inner.array_2d_compatible(),
block_texel_view_compatible: image_inner.block_texel_view_compatible(),
..Default::default()
})? {
(properties.filter_cubic, properties.filter_cubic_minmax)
} else {
(false, false)
};
Ok(Arc::new(ImageView {
handle,
image,
view_type,
format,
format_features,
component_mapping,
aspects,
array_layers,
mip_levels,
usage,
sampler_ycbcr_conversion,
filter_cubic,
filter_cubic_minmax,
}))
}
fn validate(
image: &I,
create_info: &mut ImageViewCreateInfo,
) -> Result<(FormatFeatures, ImageUsage), ImageViewCreationError> {
let &mut ImageViewCreateInfo {
view_type,
format,
component_mapping,
aspects,
ref array_layers,
ref mip_levels,
ref sampler_ycbcr_conversion,
_ne: _,
} = create_info;
let format = format.unwrap();
let image_inner = image.inner().image;
let level_count = mip_levels.end - mip_levels.start;
let layer_count = array_layers.end - array_layers.start;
assert!(level_count != 0);
assert!(layer_count != 0);
{
let ImageAspects {
color,
depth,
stencil,
metadata,
plane0,
plane1,
plane2,
memory_plane0,
memory_plane1,
memory_plane2,
} = aspects;
assert!(!(metadata || memory_plane0 || memory_plane1 || memory_plane2));
assert!({
let num_bits = color as u8
+ depth as u8
+ stencil as u8
+ plane0 as u8
+ plane1 as u8
+ plane2 as u8;
num_bits == 1 || depth && stencil && !(color || plane0 || plane1 || plane2)
});
}
let format_features = {
let format_features = if Some(format) != image_inner.format() {
let format_properties = image_inner
.device()
.physical_device()
.format_properties(format);
match image_inner.tiling() {
ImageTiling::Optimal => format_properties.optimal_tiling_features,
ImageTiling::Linear => format_properties.linear_tiling_features,
}
} else {
*image_inner.format_features()
};
if image_inner
.device()
.enabled_extensions()
.khr_format_feature_flags2
{
format_features
} else {
let is_without_format = format.shader_storage_image_without_format();
FormatFeatures {
sampled_image_depth_comparison: format.type_color().is_none()
&& format_features.sampled_image,
storage_read_without_format: is_without_format
&& image_inner
.device()
.enabled_features()
.shader_storage_image_read_without_format,
storage_write_without_format: is_without_format
&& image_inner
.device()
.enabled_features()
.shader_storage_image_write_without_format,
..format_features
}
}
};
if !image_inner.format().unwrap().aspects().contains(&aspects) {
return Err(ImageViewCreationError::ImageAspectsNotCompatible {
aspects,
image_aspects: image_inner.format().unwrap().aspects(),
});
}
if format_features == FormatFeatures::default() {
return Err(ImageViewCreationError::FormatNotSupported);
}
let usage = *image_inner.usage();
let image_type = image.dimensions().image_type();
if !view_type.is_compatible_with(image_type) {
return Err(ImageViewCreationError::ImageTypeNotCompatible);
}
if (view_type == ImageViewType::Cube || view_type == ImageViewType::CubeArray)
&& !image_inner.cube_compatible()
{
return Err(ImageViewCreationError::ImageNotCubeCompatible);
}
if view_type == ImageViewType::CubeArray
&& !image_inner.device().enabled_features().image_cube_array
{
return Err(ImageViewCreationError::FeatureNotEnabled {
feature: "image_cube_array",
reason: "the `CubeArray` view type was requested",
});
}
if mip_levels.end > image_inner.mip_levels() {
return Err(ImageViewCreationError::MipLevelsOutOfRange {
range_end: mip_levels.end,
max: image_inner.mip_levels(),
});
}
if image_type == ImageType::Dim3d
&& (view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray)
{
if !image_inner.array_2d_compatible() {
return Err(ImageViewCreationError::ImageNotArray2dCompatible);
}
if level_count != 1 {
return Err(ImageViewCreationError::Array2dCompatibleMultipleMipLevels);
}
let max = image_inner
.dimensions()
.mip_level_dimensions(mip_levels.start)
.unwrap()
.depth();
if array_layers.end > max {
return Err(ImageViewCreationError::ArrayLayersOutOfRange {
range_end: array_layers.end,
max,
});
}
} else {
if array_layers.end > image_inner.dimensions().array_layers() {
return Err(ImageViewCreationError::ArrayLayersOutOfRange {
range_end: array_layers.end,
max: image_inner.dimensions().array_layers(),
});
}
}
if image_inner.samples() != SampleCount::Sample1
&& !(view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray)
{
return Err(ImageViewCreationError::MultisamplingNot2d);
}
if !(image_inner.usage().sampled
|| image_inner.usage().storage
|| image_inner.usage().color_attachment
|| image_inner.usage().depth_stencil_attachment
|| image_inner.usage().input_attachment
|| image_inner.usage().transient_attachment)
{
return Err(ImageViewCreationError::ImageMissingUsage);
}
if usage.sampled && !format_features.sampled_image {
return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "sampled" });
}
if usage.storage && !format_features.storage_image {
return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "storage" });
}
if usage.color_attachment && !format_features.color_attachment {
return Err(ImageViewCreationError::FormatUsageNotSupported {
usage: "color_attachment",
});
}
if usage.depth_stencil_attachment && !format_features.depth_stencil_attachment {
return Err(ImageViewCreationError::FormatUsageNotSupported {
usage: "depth_stencil_attachment",
});
}
if usage.input_attachment
&& !(format_features.color_attachment || format_features.depth_stencil_attachment)
{
return Err(ImageViewCreationError::FormatUsageNotSupported {
usage: "input_attachment",
});
}
if image_inner.block_texel_view_compatible() {
if !(format.compatibility() == image_inner.format().unwrap().compatibility()
|| format.block_size() == image_inner.format().unwrap().block_size())
{
return Err(ImageViewCreationError::FormatNotCompatible);
}
if layer_count != 1 {
return Err(ImageViewCreationError::BlockTexelViewCompatibleMultipleArrayLayers);
}
if level_count != 1 {
return Err(ImageViewCreationError::BlockTexelViewCompatibleMultipleMipLevels);
}
if format.compression().is_none() && view_type == ImageViewType::Dim3d {
return Err(ImageViewCreationError::BlockTexelViewCompatibleUncompressedIs3d);
}
}
else if image_inner.mutable_format()
&& image_inner.format().unwrap().planes().is_empty()
&& format.compatibility() != image_inner.format().unwrap().compatibility()
{
return Err(ImageViewCreationError::FormatNotCompatible);
}
if image_inner.mutable_format()
&& !image_inner.format().unwrap().planes().is_empty()
&& !aspects.color
{
let plane = if aspects.plane0 {
0
} else if aspects.plane1 {
1
} else if aspects.plane2 {
2
} else {
unreachable!()
};
let plane_format = image_inner.format().unwrap().planes()[plane];
if format.compatibility() != plane_format.compatibility() {
return Err(ImageViewCreationError::FormatNotCompatible);
}
}
else if Some(format) != image_inner.format() {
return Err(ImageViewCreationError::FormatNotCompatible);
}
if (view_type == ImageViewType::Dim1d
|| view_type == ImageViewType::Dim2d
|| view_type == ImageViewType::Dim3d)
&& layer_count != 1
{
return Err(ImageViewCreationError::TypeNonArrayedMultipleArrayLayers);
}
else if view_type == ImageViewType::Cube && layer_count != 6 {
return Err(ImageViewCreationError::TypeCubeNot6ArrayLayers);
}
else if view_type == ImageViewType::CubeArray && layer_count % 6 != 0 {
return Err(ImageViewCreationError::TypeCubeArrayNotMultipleOf6ArrayLayers);
}
match format.ycbcr_chroma_sampling() {
Some(ChromaSampling::Mode422) => {
if image_inner.dimensions().width() % 2 != 0 {
return Err(
ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions,
);
}
}
Some(ChromaSampling::Mode420) => {
if image_inner.dimensions().width() % 2 != 0
|| image_inner.dimensions().height() % 2 != 0
{
return Err(
ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions,
);
}
}
_ => (),
}
if let Some(conversion) = &sampler_ycbcr_conversion {
assert_eq!(image_inner.device(), conversion.device());
if !component_mapping.is_identity() {
return Err(
ImageViewCreationError::SamplerYcbcrConversionComponentMappingNotIdentity {
component_mapping,
},
);
}
} else {
if format.ycbcr_chroma_sampling().is_some() {
return Err(
ImageViewCreationError::FormatRequiresSamplerYcbcrConversion { format },
);
}
}
Ok((format_features, usage))
}
unsafe fn create(
image: &I,
create_info: &ImageViewCreateInfo,
) -> Result<ash::vk::ImageView, ImageViewCreationError> {
let &ImageViewCreateInfo {
view_type,
format,
component_mapping,
aspects,
ref array_layers,
ref mip_levels,
ref sampler_ycbcr_conversion,
_ne: _,
} = create_info;
let image_inner = image.inner().image;
let mut create_info = ash::vk::ImageViewCreateInfo {
flags: ash::vk::ImageViewCreateFlags::empty(),
image: image_inner.internal_object(),
view_type: view_type.into(),
format: format.unwrap().into(),
components: component_mapping.into(),
subresource_range: ash::vk::ImageSubresourceRange {
aspect_mask: aspects.into(),
base_mip_level: mip_levels.start,
level_count: mip_levels.end - mip_levels.start,
base_array_layer: array_layers.start,
layer_count: array_layers.end - array_layers.start,
},
..Default::default()
};
let mut sampler_ycbcr_conversion_info = if let Some(conversion) = sampler_ycbcr_conversion {
Some(ash::vk::SamplerYcbcrConversionInfo {
conversion: conversion.internal_object(),
..Default::default()
})
} else {
None
};
if let Some(sampler_ycbcr_conversion_info) = sampler_ycbcr_conversion_info.as_mut() {
sampler_ycbcr_conversion_info.p_next = create_info.p_next;
create_info.p_next = sampler_ycbcr_conversion_info as *const _ as *const _;
}
let handle = {
let fns = image_inner.device().fns();
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_image_view(
image_inner.device().internal_object(),
&create_info,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(handle)
}
#[inline]
pub fn new_default(image: Arc<I>) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
let create_info = ImageViewCreateInfo::from_image(&image);
Self::new(image, create_info)
}
#[inline]
pub fn image(&self) -> &Arc<I> {
&self.image
}
}
unsafe impl<I> VulkanObject for ImageView<I>
where
I: ImageAccess + ?Sized,
{
type Object = ash::vk::ImageView;
#[inline]
fn internal_object(&self) -> ash::vk::ImageView {
self.handle
}
}
unsafe impl<I> DeviceOwned for ImageView<I>
where
I: ImageAccess + ?Sized,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.image.inner().image.device()
}
}
impl<I> fmt::Debug for ImageView<I>
where
I: ImageAccess + ?Sized,
{
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan image view {:?}>", self.handle)
}
}
impl<I> Drop for ImageView<I>
where
I: ImageAccess + ?Sized,
{
#[inline]
fn drop(&mut self) {
unsafe {
let device = self.device();
let fns = device.fns();
fns.v1_0
.destroy_image_view(device.internal_object(), self.handle, ptr::null());
}
}
}
impl<I> PartialEq for ImageView<I>
where
I: ImageAccess + ?Sized,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle && self.device() == other.device()
}
}
impl<I> Eq for ImageView<I> where I: ImageAccess + ?Sized {}
impl<I> Hash for ImageView<I>
where
I: ImageAccess + ?Sized,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle.hash(state);
self.device().hash(state);
}
}
#[derive(Debug)]
pub struct ImageViewCreateInfo {
pub view_type: ImageViewType,
pub format: Option<Format>,
pub component_mapping: ComponentMapping,
pub aspects: ImageAspects,
pub array_layers: Range<u32>,
pub mip_levels: Range<u32>,
pub sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
pub _ne: crate::NonExhaustive,
}
impl Default for ImageViewCreateInfo {
#[inline]
fn default() -> Self {
Self {
view_type: ImageViewType::Dim2d,
format: None,
component_mapping: ComponentMapping::identity(),
aspects: ImageAspects::none(),
array_layers: 0..1,
mip_levels: 0..1,
sampler_ycbcr_conversion: None,
_ne: crate::NonExhaustive(()),
}
}
}
impl ImageViewCreateInfo {
pub fn from_image<I>(image: &I) -> Self
where
I: ImageAccess + ?Sized,
{
Self {
view_type: match image.dimensions() {
ImageDimensions::Dim1d {
array_layers: 1, ..
} => ImageViewType::Dim1d,
ImageDimensions::Dim1d { .. } => ImageViewType::Dim1dArray,
ImageDimensions::Dim2d {
array_layers: 1, ..
} => ImageViewType::Dim2d,
ImageDimensions::Dim2d { .. } => ImageViewType::Dim2dArray,
ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d,
},
format: Some(image.format()),
aspects: {
let aspects = image.format().aspects();
if aspects.depth || aspects.stencil {
debug_assert!(!aspects.color);
ImageAspects {
depth: aspects.depth,
stencil: aspects.stencil,
..Default::default()
}
} else {
debug_assert!(aspects.color);
ImageAspects {
color: true,
..Default::default()
}
}
},
array_layers: 0..image.dimensions().array_layers(),
mip_levels: 0..image.mip_levels(),
..Default::default()
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ImageViewCreationError {
OomError(OomError),
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
},
Array2dCompatibleMultipleMipLevels,
ArrayLayersOutOfRange { range_end: u32, max: u32 },
BlockTexelViewCompatibleMultipleArrayLayers,
BlockTexelViewCompatibleMultipleMipLevels,
BlockTexelViewCompatibleUncompressedIs3d,
FormatChromaSubsamplingInvalidImageDimensions,
FormatNotCompatible,
FormatNotSupported,
FormatRequiresSamplerYcbcrConversion { format: Format },
FormatUsageNotSupported { usage: &'static str },
ImageAspectsNotCompatible {
aspects: ImageAspects,
image_aspects: ImageAspects,
},
ImageMissingUsage,
ImageNotArray2dCompatible,
ImageNotCubeCompatible,
ImageTypeNotCompatible,
IncompatibleType,
MipLevelsOutOfRange { range_end: u32, max: u32 },
MultisamplingNot2d,
SamplerYcbcrConversionComponentMappingNotIdentity { component_mapping: ComponentMapping },
TypeCubeArrayNotMultipleOf6ArrayLayers,
TypeCubeNot6ArrayLayers,
TypeNonArrayedMultipleArrayLayers,
}
impl error::Error for ImageViewCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
ImageViewCreationError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for ImageViewCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::OomError(err) => write!(
fmt,
"allocating memory failed",
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::Array2dCompatibleMultipleMipLevels => write!(
fmt,
"a 2D image view was requested from a 3D image, but a range of multiple mip levels was specified",
),
Self::ArrayLayersOutOfRange { .. } => write!(
fmt,
"the specified range of array layers was not a subset of those in the image",
),
Self::BlockTexelViewCompatibleMultipleArrayLayers => write!(
fmt,
"the image has the `block_texel_view_compatible` flag, but a range of multiple array layers was specified",
),
Self::BlockTexelViewCompatibleMultipleMipLevels => write!(
fmt,
"the image has the `block_texel_view_compatible` flag, but a range of multiple mip levels was specified",
),
Self::BlockTexelViewCompatibleUncompressedIs3d => write!(
fmt,
"the image has the `block_texel_view_compatible` flag, and an uncompressed format was requested, and the image view type was `Dim3d`",
),
Self::FormatChromaSubsamplingInvalidImageDimensions => write!(
fmt,
"the requested format has chroma subsampling, but the width and/or height of the image was not a multiple of 2",
),
Self::FormatNotCompatible => write!(
fmt,
"the requested format was not compatible with the image",
),
Self::FormatNotSupported => write!(
fmt,
"the given format was not supported by the device"
),
Self::FormatRequiresSamplerYcbcrConversion { .. } => write!(
fmt,
"the format requires a sampler YCbCr conversion, but none was provided",
),
Self::FormatUsageNotSupported { usage } => write!(
fmt,
"a requested usage flag was not supported by the given format"
),
Self::ImageAspectsNotCompatible { .. } => write!(
fmt,
"an aspect was selected that was not present in the image",
),
Self::ImageMissingUsage => write!(
fmt,
"the image was not created with one of the required usages for image views",
),
Self::ImageNotArray2dCompatible => write!(
fmt,
"a 2D image view was requested from a 3D image, but the image was not created with the `array_2d_compatible` flag",
),
Self::ImageNotCubeCompatible => write!(
fmt,
"a cube image view type was requested, but the image was not created with the `cube_compatible` flag",
),
Self::ImageTypeNotCompatible => write!(
fmt,
"the given image view type was not compatible with the type of the image",
),
Self::IncompatibleType => write!(
fmt,
"image view type is not compatible with image, array layers or mipmap levels",
),
Self::MipLevelsOutOfRange { .. } => write!(
fmt,
"the specified range of mip levels was not a subset of those in the image",
),
Self::MultisamplingNot2d => write!(
fmt,
"the image has multisampling enabled, but the image view type was not `Dim2d` or `Dim2dArray`",
),
Self::SamplerYcbcrConversionComponentMappingNotIdentity { .. } => write!(
fmt,
"sampler YCbCr conversion was enabled, but `component_mapping` was not the identity mapping",
),
Self::TypeCubeArrayNotMultipleOf6ArrayLayers => write!(
fmt,
"the `CubeArray` image view type was specified, but the range of array layers did not have a size that is a multiple 6"
),
Self::TypeCubeNot6ArrayLayers => write!(
fmt,
"the `Cube` image view type was specified, but the range of array layers did not have a size of 6"
),
Self::TypeNonArrayedMultipleArrayLayers => write!(
fmt,
"a non-arrayed image view type was specified, but a range of multiple array layers was specified"
)
}
}
}
impl From<OomError> for ImageViewCreationError {
#[inline]
fn from(err: OomError) -> ImageViewCreationError {
ImageViewCreationError::OomError(err)
}
}
impl From<Error> for ImageViewCreationError {
#[inline]
fn from(err: Error) -> ImageViewCreationError {
match err {
err @ Error::OutOfHostMemory => OomError::from(err).into(),
err @ Error::OutOfDeviceMemory => OomError::from(err).into(),
_ => panic!("unexpected error: {:?}", err),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(i32)]
pub enum ImageViewType {
Dim1d = ash::vk::ImageViewType::TYPE_1D.as_raw(),
Dim1dArray = ash::vk::ImageViewType::TYPE_1D_ARRAY.as_raw(),
Dim2d = ash::vk::ImageViewType::TYPE_2D.as_raw(),
Dim2dArray = ash::vk::ImageViewType::TYPE_2D_ARRAY.as_raw(),
Dim3d = ash::vk::ImageViewType::TYPE_3D.as_raw(),
Cube = ash::vk::ImageViewType::CUBE.as_raw(),
CubeArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(),
}
impl ImageViewType {
#[inline]
pub fn is_arrayed(&self) -> bool {
match self {
Self::Dim1d | Self::Dim2d | Self::Dim3d | Self::Cube => false,
Self::Dim1dArray | Self::Dim2dArray | Self::CubeArray => true,
}
}
#[inline]
pub fn is_compatible_with(&self, image_type: ImageType) -> bool {
matches!(
(*self, image_type,),
(
ImageViewType::Dim1d | ImageViewType::Dim1dArray,
ImageType::Dim1d
) | (
ImageViewType::Dim2d | ImageViewType::Dim2dArray,
ImageType::Dim2d | ImageType::Dim3d
) | (
ImageViewType::Cube | ImageViewType::CubeArray,
ImageType::Dim2d
) | (ImageViewType::Dim3d, ImageType::Dim3d)
)
}
}
impl From<ImageViewType> for ash::vk::ImageViewType {
fn from(val: ImageViewType) -> Self {
Self::from_raw(val as i32)
}
}
pub unsafe trait ImageViewAbstract:
VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + Debug + Send + Sync
{
fn image(&self) -> Arc<dyn ImageAccess>;
fn array_layers(&self) -> Range<u32>;
fn aspects(&self) -> &ImageAspects;
fn component_mapping(&self) -> ComponentMapping;
fn filter_cubic(&self) -> bool;
fn filter_cubic_minmax(&self) -> bool;
fn format(&self) -> Option<Format>;
fn format_features(&self) -> &FormatFeatures;
fn mip_levels(&self) -> Range<u32>;
fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>;
fn usage(&self) -> &ImageUsage;
fn view_type(&self) -> ImageViewType;
}
unsafe impl<I> ImageViewAbstract for ImageView<I>
where
I: ImageAccess + 'static,
{
#[inline]
fn image(&self) -> Arc<dyn ImageAccess> {
self.image.clone()
}
#[inline]
fn array_layers(&self) -> Range<u32> {
self.array_layers.clone()
}
#[inline]
fn aspects(&self) -> &ImageAspects {
&self.aspects
}
#[inline]
fn component_mapping(&self) -> ComponentMapping {
self.component_mapping
}
#[inline]
fn filter_cubic(&self) -> bool {
self.filter_cubic
}
#[inline]
fn filter_cubic_minmax(&self) -> bool {
self.filter_cubic_minmax
}
#[inline]
fn format(&self) -> Option<Format> {
self.format
}
#[inline]
fn format_features(&self) -> &FormatFeatures {
&self.format_features
}
#[inline]
fn mip_levels(&self) -> Range<u32> {
self.mip_levels.clone()
}
#[inline]
fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
self.sampler_ycbcr_conversion.as_ref()
}
#[inline]
fn usage(&self) -> &ImageUsage {
&self.usage
}
#[inline]
fn view_type(&self) -> ImageViewType {
self.view_type
}
}
unsafe impl ImageViewAbstract for ImageView<dyn ImageAccess> {
#[inline]
fn image(&self) -> Arc<dyn ImageAccess> {
self.image.clone()
}
#[inline]
fn array_layers(&self) -> Range<u32> {
self.array_layers.clone()
}
#[inline]
fn aspects(&self) -> &ImageAspects {
&self.aspects
}
#[inline]
fn component_mapping(&self) -> ComponentMapping {
self.component_mapping
}
#[inline]
fn filter_cubic(&self) -> bool {
self.filter_cubic
}
#[inline]
fn filter_cubic_minmax(&self) -> bool {
self.filter_cubic_minmax
}
#[inline]
fn format(&self) -> Option<Format> {
self.format
}
#[inline]
fn format_features(&self) -> &FormatFeatures {
&self.format_features
}
#[inline]
fn mip_levels(&self) -> Range<u32> {
self.mip_levels.clone()
}
#[inline]
fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
self.sampler_ycbcr_conversion.as_ref()
}
#[inline]
fn usage(&self) -> &ImageUsage {
&self.usage
}
#[inline]
fn view_type(&self) -> ImageViewType {
self.view_type
}
}
impl PartialEq for dyn ImageViewAbstract {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.internal_object() == other.internal_object() && self.device() == other.device()
}
}
impl Eq for dyn ImageViewAbstract {}
impl Hash for dyn ImageViewAbstract {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.internal_object().hash(state);
self.device().hash(state);
}
}