use std::error;
use std::fmt;
use std::mem;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;
use device::Device;
use format::Format;
use format::FormatTy;
use image::ImageDimensions;
use image::ImageUsage;
use image::MipmapsCount;
use image::ViewType;
use memory::DeviceMemory;
use memory::MemoryRequirements;
use sync::Sharing;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;
pub struct UnsafeImage {
image: vk::Image,
device: Arc<Device>,
usage: vk::ImageUsageFlagBits,
format: Format,
dimensions: ImageDimensions,
samples: u32,
mipmaps: u32,
format_features: vk::FormatFeatureFlagBits,
needs_destruction: bool,
}
impl UnsafeImage {
#[inline]
pub unsafe fn new<'a, Mi, I>(device: Arc<Device>, usage: ImageUsage, format: Format,
dimensions: ImageDimensions, num_samples: u32, mipmaps: Mi,
sharing: Sharing<I>, linear_tiling: bool,
preinitialized_layout: bool)
-> Result<(UnsafeImage, MemoryRequirements), ImageCreationError>
where Mi: Into<MipmapsCount>, I: Iterator<Item = u32>
{
let sharing = match sharing {
Sharing::Exclusive => (vk::SHARING_MODE_EXCLUSIVE, SmallVec::<[u32; 8]>::new()),
Sharing::Concurrent(ids) => (vk::SHARING_MODE_CONCURRENT, ids.collect()),
};
UnsafeImage::new_impl(device, usage, format, dimensions, num_samples, mipmaps.into(),
sharing, linear_tiling, preinitialized_layout)
}
unsafe fn new_impl(device: Arc<Device>, usage: ImageUsage, format: Format,
dimensions: ImageDimensions, num_samples: u32, mipmaps: MipmapsCount,
(sh_mode, sh_indices): (vk::SharingMode, SmallVec<[u32; 8]>),
linear_tiling: bool, preinitialized_layout: bool)
-> Result<(UnsafeImage, MemoryRequirements), ImageCreationError>
{
let vk = device.pointers();
let vk_i = device.instance().pointers();
let format_features = {
let physical_device = device.physical_device().internal_object();
let mut output = mem::uninitialized();
vk_i.GetPhysicalDeviceFormatProperties(physical_device, format as u32, &mut output);
let features = if linear_tiling {
output.linearTilingFeatures
} else {
output.optimalTilingFeatures
};
if features == 0 {
return Err(ImageCreationError::FormatNotSupported);
}
if usage.sampled && (features & vk::FORMAT_FEATURE_SAMPLED_IMAGE_BIT == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if usage.storage && (features & vk::FORMAT_FEATURE_STORAGE_IMAGE_BIT == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if usage.color_attachment && (features & vk::FORMAT_FEATURE_COLOR_ATTACHMENT_BIT == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if usage.depth_stencil_attachment && (features & vk::FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if usage.input_attachment && (features & (vk::FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if device.loaded_extensions().khr_maintenance1 {
if usage.transfer_source && (features & vk::FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
if usage.transfer_dest && (features & vk::FORMAT_FEATURE_TRANSFER_DST_BIT_KHR == 0) {
return Err(ImageCreationError::UnsupportedUsage);
}
}
features
};
if usage.transient_attachment {
let u = ImageUsage {
transient_attachment: false,
color_attachment: false,
depth_stencil_attachment: false,
input_attachment: false,
.. usage.clone()
};
if u != ImageUsage::none() {
return Err(ImageCreationError::UnsupportedUsage);
}
}
let mut capabilities_error = None;
let max_mipmaps = {
let smallest_dim: u32 = match dimensions {
ImageDimensions::Dim1d { width, .. } => width,
ImageDimensions::Dim2d { width, height, .. } => {
if width < height { width } else { height }
},
ImageDimensions::Dim3d { width, height, depth } => {
if width < height {
if depth < width { depth } else { width }
} else {
if depth < height { depth } else { height }
}
},
};
32 - smallest_dim.leading_zeros()
};
let mipmaps = match mipmaps.into() {
MipmapsCount::Specific(num) => {
if num < 1 {
return Err(ImageCreationError::InvalidMipmapsCount {
obtained: num, valid_range: 1 .. max_mipmaps + 1
});
} else if num > max_mipmaps {
capabilities_error = Some(ImageCreationError::InvalidMipmapsCount {
obtained: num, valid_range: 1 .. max_mipmaps + 1
});
}
num
},
MipmapsCount::Log2 => max_mipmaps,
MipmapsCount::One => 1,
};
if num_samples == 0 {
return Err(ImageCreationError::UnsupportedSamplesCount { obtained: num_samples });
} else if !num_samples.is_power_of_two() {
return Err(ImageCreationError::UnsupportedSamplesCount { obtained: num_samples });
} else {
let mut supported_samples = 0x7f;
if usage.sampled {
match format.ty() {
FormatTy::Float | FormatTy::Compressed => {
supported_samples &= device.physical_device().limits()
.sampled_image_color_sample_counts();
},
FormatTy::Uint | FormatTy::Sint => {
supported_samples &= device.physical_device().limits()
.sampled_image_integer_sample_counts();
},
FormatTy::Depth => {
supported_samples &= device.physical_device().limits()
.sampled_image_depth_sample_counts();
},
FormatTy::Stencil => {
supported_samples &= device.physical_device().limits()
.sampled_image_stencil_sample_counts();
},
FormatTy::DepthStencil => {
supported_samples &= device.physical_device().limits()
.sampled_image_depth_sample_counts();
supported_samples &= device.physical_device().limits()
.sampled_image_stencil_sample_counts();
},
}
}
if usage.storage {
supported_samples &= device.physical_device().limits()
.storage_image_sample_counts();
}
if usage.color_attachment || usage.depth_stencil_attachment || usage.input_attachment ||
usage.transient_attachment
{
match format.ty() {
FormatTy::Float | FormatTy::Compressed | FormatTy::Uint | FormatTy::Sint => {
supported_samples &= device.physical_device().limits()
.framebuffer_color_sample_counts();
},
FormatTy::Depth => {
supported_samples &= device.physical_device().limits()
.framebuffer_depth_sample_counts();
},
FormatTy::Stencil => {
supported_samples &= device.physical_device().limits()
.framebuffer_stencil_sample_counts();
},
FormatTy::DepthStencil => {
supported_samples &= device.physical_device().limits()
.framebuffer_depth_sample_counts();
supported_samples &= device.physical_device().limits()
.framebuffer_stencil_sample_counts();
},
}
}
if (num_samples & supported_samples) == 0 {
let err = ImageCreationError::UnsupportedSamplesCount { obtained: num_samples };
capabilities_error = Some(err);
}
}
if usage.storage && num_samples > 1 {
if !device.enabled_features().shader_storage_image_multisample {
return Err(ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled);
}
}
let (ty, extent, array_layers, flags) = match dimensions {
ImageDimensions::Dim1d { width, array_layers } => {
if width == 0 || array_layers == 0 {
return Err(ImageCreationError::UnsupportedDimensions { dimensions: dimensions });
}
let extent = vk::Extent3D { width: width, height: 1, depth: 1 };
(vk::IMAGE_TYPE_1D, extent, array_layers, 0)
},
ImageDimensions::Dim2d { width, height, array_layers, cubemap_compatible } => {
if width == 0 || height == 0 || array_layers == 0 {
return Err(ImageCreationError::UnsupportedDimensions { dimensions: dimensions });
}
if cubemap_compatible && width != height {
return Err(ImageCreationError::UnsupportedDimensions { dimensions: dimensions });
}
let extent = vk::Extent3D { width: width, height: height, depth: 1 };
let flags = if cubemap_compatible { vk::IMAGE_CREATE_CUBE_COMPATIBLE_BIT }
else { 0 };
(vk::IMAGE_TYPE_2D, extent, array_layers, flags)
},
ImageDimensions::Dim3d { width, height, depth } => {
if width == 0 || height == 0 || depth == 0 {
return Err(ImageCreationError::UnsupportedDimensions { dimensions: dimensions });
}
let extent = vk::Extent3D { width: width, height: height, depth: depth };
(vk::IMAGE_TYPE_3D, extent, 1, 0)
},
};
if array_layers > device.physical_device().limits().max_image_array_layers() {
let err = ImageCreationError::UnsupportedDimensions { dimensions: dimensions };
capabilities_error = Some(err);
}
match ty {
vk::IMAGE_TYPE_1D => {
if extent.width > device.physical_device().limits().max_image_dimension_1d() {
let err = ImageCreationError::UnsupportedDimensions { dimensions: dimensions };
capabilities_error = Some(err);
}
},
vk::IMAGE_TYPE_2D => {
let limit = device.physical_device().limits().max_image_dimension_2d();
if extent.width > limit || extent.height > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions: dimensions };
capabilities_error = Some(err);
}
if (flags & vk::IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0 {
let limit = device.physical_device().limits().max_image_dimension_cube();
debug_assert_eq!(extent.width, extent.height); if extent.width > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions: dimensions };
capabilities_error = Some(err);
}
}
},
vk::IMAGE_TYPE_3D => {
let limit = device.physical_device().limits().max_image_dimension_3d();
if extent.width > limit || extent.height > limit || extent.depth > limit {
let err = ImageCreationError::UnsupportedDimensions { dimensions: dimensions };
capabilities_error = Some(err);
}
},
_ => unreachable!()
};
let usage = usage.to_usage_bits();
if let Some(capabilities_error) = capabilities_error {
let tiling = if linear_tiling {
vk::IMAGE_TILING_LINEAR
} else {
vk::IMAGE_TILING_OPTIMAL
};
let mut output = mem::uninitialized();
let physical_device = device.physical_device().internal_object();
let r = vk_i.GetPhysicalDeviceImageFormatProperties(physical_device, format as u32, ty,
tiling, usage, 0 ,
&mut output);
match check_errors(r) {
Ok(_) => (),
Err(Error::FormatNotSupported) => return Err(ImageCreationError::FormatNotSupported),
Err(err) => return Err(err.into()),
}
if extent.width > output.maxExtent.width || extent.height > output.maxExtent.height ||
extent.depth > output.maxExtent.depth || mipmaps > output.maxMipLevels ||
array_layers > output.maxArrayLayers || (num_samples & output.sampleCounts) == 0
{
return Err(capabilities_error);
}
}
let image = {
let infos = vk::ImageCreateInfo {
sType: vk::STRUCTURE_TYPE_IMAGE_CREATE_INFO,
pNext: ptr::null(),
flags: flags,
imageType: ty,
format: format as u32,
extent: extent,
mipLevels: mipmaps,
arrayLayers: array_layers,
samples: num_samples,
tiling: if linear_tiling {
vk::IMAGE_TILING_LINEAR
} else {
vk::IMAGE_TILING_OPTIMAL
},
usage: usage,
sharingMode: sh_mode,
queueFamilyIndexCount: sh_indices.len() as u32,
pQueueFamilyIndices: sh_indices.as_ptr(),
initialLayout: if preinitialized_layout {
vk::IMAGE_LAYOUT_PREINITIALIZED
} else {
vk::IMAGE_LAYOUT_UNDEFINED
},
};
let mut output = mem::uninitialized();
try!(check_errors(vk.CreateImage(device.internal_object(), &infos,
ptr::null(), &mut output)));
output
};
let mem_reqs: vk::MemoryRequirements = {
let mut output = mem::uninitialized();
vk.GetImageMemoryRequirements(device.internal_object(), image, &mut output);
debug_assert!(output.memoryTypeBits != 0);
output
};
let image = UnsafeImage {
device: device.clone(),
image: image,
usage: usage,
format: format,
dimensions: dimensions,
samples: num_samples,
mipmaps: mipmaps,
format_features: format_features,
needs_destruction: true,
};
Ok((image, mem_reqs.into()))
}
pub unsafe fn from_raw(device: Arc<Device>, handle: u64, usage: u32, format: Format,
dimensions: ImageDimensions, samples: u32, mipmaps: u32)
-> UnsafeImage
{
let vk_i = device.instance().pointers();
let physical_device = device.physical_device().internal_object();
let mut output = mem::uninitialized();
vk_i.GetPhysicalDeviceFormatProperties(physical_device, format as u32, &mut output);
UnsafeImage {
device: device.clone(),
image: handle,
usage: usage,
format: format,
dimensions: dimensions,
samples: samples,
mipmaps: mipmaps,
format_features: output.optimalTilingFeatures,
needs_destruction: false, }
}
pub unsafe fn bind_memory(&self, memory: &DeviceMemory, offset: usize)
-> Result<(), OomError>
{
let vk = self.device.pointers();
debug_assert!({
let mut mem_reqs = mem::uninitialized();
vk.GetImageMemoryRequirements(self.device.internal_object(), self.image,
&mut mem_reqs);
mem_reqs.size <= (memory.size() - offset) as u64 &&
(offset as u64 % mem_reqs.alignment) == 0 &&
mem_reqs.memoryTypeBits & (1 << memory.memory_type().id()) != 0
});
try!(check_errors(vk.BindImageMemory(self.device.internal_object(), self.image,
memory.internal_object(), offset as vk::DeviceSize)));
Ok(())
}
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
#[inline]
pub fn format(&self) -> Format {
self.format
}
#[inline]
pub fn mipmap_levels(&self) -> u32 {
self.mipmaps
}
#[inline]
pub fn dimensions(&self) -> ImageDimensions {
self.dimensions
}
#[inline]
pub fn samples(&self) -> u32 {
self.samples
}
#[inline]
pub fn key(&self) -> u64 {
self.image
}
#[inline]
pub unsafe fn color_linear_layout(&self, mip_level: u32) -> LinearLayout {
self.linear_layout_impl(mip_level, vk::IMAGE_ASPECT_COLOR_BIT)
}
#[inline]
pub unsafe fn depth_linear_layout(&self, mip_level: u32) -> LinearLayout {
self.linear_layout_impl(mip_level, vk::IMAGE_ASPECT_DEPTH_BIT)
}
#[inline]
pub unsafe fn stencil_linear_layout(&self, mip_level: u32) -> LinearLayout {
self.linear_layout_impl(mip_level, vk::IMAGE_ASPECT_STENCIL_BIT)
}
unsafe fn linear_layout_impl(&self, mip_level: u32, aspect: u32) -> LinearLayout {
let vk = self.device.pointers();
assert!(mip_level < self.mipmaps);
let subresource = vk::ImageSubresource {
aspectMask: aspect,
mipLevel: mip_level,
arrayLayer: 0,
};
let mut out = mem::uninitialized();
vk.GetImageSubresourceLayout(self.device.internal_object(), self.image, &subresource,
&mut out);
LinearLayout {
offset: out.offset as usize,
size: out.size as usize,
row_pitch: out.rowPitch as usize,
array_pitch: out.arrayPitch as usize,
depth_pitch: out.depthPitch as usize,
}
}
#[inline]
pub fn supports_blit_source(&self) -> bool {
(self.format_features & vk::FORMAT_FEATURE_BLIT_SRC_BIT) != 0
}
#[inline]
pub fn supports_blit_destination(&self) -> bool {
(self.format_features & vk::FORMAT_FEATURE_BLIT_DST_BIT) != 0
}
#[inline]
pub fn supports_linear_filtering(&self) -> bool {
(self.format_features & vk::FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) != 0
}
#[inline]
pub fn usage_transfer_src(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0
}
#[inline]
pub fn usage_transfer_dest(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0
}
#[inline]
pub fn usage_sampled(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_SAMPLED_BIT) != 0
}
#[inline]
pub fn usage_storage(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_STORAGE_BIT) != 0
}
#[inline]
pub fn usage_color_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_depth_stencil_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_transient_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_input_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0
}
}
unsafe impl VulkanObject for UnsafeImage {
type Object = vk::Image;
#[inline]
fn internal_object(&self) -> vk::Image {
self.image
}
}
impl fmt::Debug for UnsafeImage {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan image {:?}>", self.image)
}
}
impl Drop for UnsafeImage {
#[inline]
fn drop(&mut self) {
if !self.needs_destruction {
return;
}
unsafe {
let vk = self.device.pointers();
vk.DestroyImage(self.device.internal_object(), self.image, ptr::null());
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ImageCreationError {
OomError(OomError),
InvalidMipmapsCount { obtained: u32, valid_range: Range<u32> },
UnsupportedSamplesCount { obtained: u32 },
UnsupportedDimensions { dimensions: ImageDimensions },
FormatNotSupported,
UnsupportedUsage,
ShaderStorageImageMultisampleFeatureNotEnabled,
}
impl error::Error for ImageCreationError {
#[inline]
fn description(&self) -> &str {
match *self {
ImageCreationError::OomError(_) => "not enough memory available",
ImageCreationError::InvalidMipmapsCount { .. } => "a wrong number of mipmaps was \
provided",
ImageCreationError::UnsupportedSamplesCount { .. } => "the requeted number of samples \
is not supported, or is 0",
ImageCreationError::UnsupportedDimensions { .. } => "the dimensions are too large, or \
one of the dimensions is 0",
ImageCreationError::FormatNotSupported => "the requested format is not supported by \
the Vulkan implementation",
ImageCreationError::UnsupportedUsage => "the format is supported, but at least one \
of the requested usages is not supported",
ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled => {
"the `shader_storage_image_multisample` feature must be enabled to create such \
an image"
},
}
}
#[inline]
fn cause(&self) -> Option<&error::Error> {
match *self {
ImageCreationError::OomError(ref err) => Some(err),
_ => None
}
}
}
impl fmt::Display for ImageCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<OomError> for ImageCreationError {
#[inline]
fn from(err: OomError) -> ImageCreationError {
ImageCreationError::OomError(err)
}
}
impl From<Error> for ImageCreationError {
#[inline]
fn from(err: Error) -> ImageCreationError {
match err {
err @ Error::OutOfHostMemory => ImageCreationError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => ImageCreationError::OomError(OomError::from(err)),
_ => panic!("unexpected error: {:?}", err)
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct LinearLayout {
pub offset: usize,
pub size: usize,
pub row_pitch: usize,
pub array_pitch: usize,
pub depth_pitch: usize,
}
pub struct UnsafeImageView {
view: vk::ImageView,
device: Arc<Device>,
usage: vk::ImageUsageFlagBits,
identity_swizzle: bool,
format: Format,
}
impl UnsafeImageView {
pub unsafe fn raw(image: &UnsafeImage, ty: ViewType, mipmap_levels: Range<u32>,
array_layers: Range<u32>) -> Result<UnsafeImageView, OomError>
{
let vk = image.device.pointers();
assert!(mipmap_levels.end > mipmap_levels.start);
assert!(mipmap_levels.end <= image.mipmaps);
assert!(array_layers.end > array_layers.start);
assert!(array_layers.end <= image.dimensions.array_layers());
let aspect_mask = match image.format.ty() {
FormatTy::Float | FormatTy::Uint | FormatTy::Sint | FormatTy::Compressed => {
vk::IMAGE_ASPECT_COLOR_BIT
},
FormatTy::Depth => vk::IMAGE_ASPECT_DEPTH_BIT,
FormatTy::Stencil => vk::IMAGE_ASPECT_STENCIL_BIT,
FormatTy::DepthStencil => vk::IMAGE_ASPECT_DEPTH_BIT | vk::IMAGE_ASPECT_STENCIL_BIT,
};
let view_type = match (image.dimensions(), ty, array_layers.end - array_layers.start) {
(ImageDimensions::Dim1d { .. }, ViewType::Dim1d, 1) => vk::IMAGE_VIEW_TYPE_1D,
(ImageDimensions::Dim1d { .. }, ViewType::Dim1dArray, _) => vk::IMAGE_VIEW_TYPE_1D_ARRAY,
(ImageDimensions::Dim2d { .. }, ViewType::Dim2d, 1) => vk::IMAGE_VIEW_TYPE_2D,
(ImageDimensions::Dim2d { .. }, ViewType::Dim2dArray, _) => vk::IMAGE_VIEW_TYPE_2D_ARRAY,
(ImageDimensions::Dim2d { cubemap_compatible, .. }, ViewType::Cubemap, n) if cubemap_compatible => {
assert_eq!(n, 6);
vk::IMAGE_VIEW_TYPE_CUBE
},
(ImageDimensions::Dim2d { cubemap_compatible, .. }, ViewType::CubemapArray, n) if cubemap_compatible => {
assert_eq!(n % 6, 0);
vk::IMAGE_VIEW_TYPE_CUBE_ARRAY
},
(ImageDimensions::Dim3d { .. }, ViewType::Dim3d, _) => vk::IMAGE_VIEW_TYPE_3D,
_ => panic!()
};
let view = {
let infos = vk::ImageViewCreateInfo {
sType: vk::STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
pNext: ptr::null(),
flags: 0, image: image.internal_object(),
viewType: view_type,
format: image.format as u32,
components: vk::ComponentMapping { r: 0, g: 0, b: 0, a: 0 }, subresourceRange: vk::ImageSubresourceRange {
aspectMask: aspect_mask,
baseMipLevel: mipmap_levels.start,
levelCount: mipmap_levels.end - mipmap_levels.start,
baseArrayLayer: array_layers.start,
layerCount: array_layers.end - array_layers.start,
},
};
let mut output = mem::uninitialized();
try!(check_errors(vk.CreateImageView(image.device.internal_object(), &infos,
ptr::null(), &mut output)));
output
};
Ok(UnsafeImageView {
view: view,
device: image.device.clone(),
usage: image.usage,
identity_swizzle: true, format: image.format,
})
}
#[inline]
pub unsafe fn new(image: &UnsafeImage, ty: ViewType, mipmap_levels: Range<u32>,
array_layers: Range<u32>) -> UnsafeImageView
{
UnsafeImageView::raw(image, ty, mipmap_levels, array_layers).unwrap()
}
#[inline]
pub fn format(&self) -> Format {
self.format
}
#[inline]
pub fn usage_transfer_src(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSFER_SRC_BIT) != 0
}
#[inline]
pub fn usage_transfer_dest(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSFER_DST_BIT) != 0
}
#[inline]
pub fn usage_sampled(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_SAMPLED_BIT) != 0
}
#[inline]
pub fn usage_storage(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_STORAGE_BIT) != 0
}
#[inline]
pub fn usage_color_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_depth_stencil_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_transient_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0
}
#[inline]
pub fn usage_input_attachment(&self) -> bool {
(self.usage & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0
}
}
unsafe impl VulkanObject for UnsafeImageView {
type Object = vk::ImageView;
#[inline]
fn internal_object(&self) -> vk::ImageView {
self.view
}
}
impl fmt::Debug for UnsafeImageView {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan image view {:?}>", self.view)
}
}
impl Drop for UnsafeImageView {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroyImageView(self.device.internal_object(), self.view, ptr::null());
}
}
}
#[cfg(test)]
mod tests {
use std::iter::Empty;
use std::u32;
use super::ImageCreationError;
use super::UnsafeImage;
use super::ImageUsage;
use image::ImageDimensions;
use format::Format;
use sync::Sharing;
#[test]
fn create_sampled() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let (_img, _) = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
}.unwrap();
}
#[test]
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
transient_attachment: true,
color_attachment: true,
.. ImageUsage::none()
};
let (_img, _) = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
}.unwrap();
}
#[test]
fn zero_sample() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 0, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::UnsupportedSamplesCount { .. }) => (),
_ => panic!()
};
}
#[test]
fn non_po2_sample() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 5, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::UnsupportedSamplesCount { .. }) => (),
_ => panic!()
};
}
#[test]
fn zero_mipmap() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 0,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::InvalidMipmapsCount { .. }) => (),
_ => panic!()
};
}
#[test]
#[ignore] fn mipmaps_too_high() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, u32::MAX,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::InvalidMipmapsCount { obtained, valid_range }) => {
assert_eq!(obtained, u32::MAX);
assert_eq!(valid_range.start, 1);
},
_ => panic!()
};
}
#[test]
fn shader_storage_image_multisample() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
storage: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 2, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled) => (),
Err(ImageCreationError::UnsupportedSamplesCount { .. }) => (), _ => panic!()
};
}
#[test]
fn compressed_not_color_attachment() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
color_attachment: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::ASTC_5x4UnormBlock,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, u32::MAX,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::FormatNotSupported) => (),
Err(ImageCreationError::UnsupportedUsage) => (),
_ => panic!()
};
}
#[test]
fn transient_forbidden_with_some_usages() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
transient_attachment: true,
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 32, array_layers: 1,
cubemap_compatible: false }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::UnsupportedUsage) => (),
_ => panic!()
};
}
#[test]
fn cubecompatible_dims_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let usage = ImageUsage {
sampled: true,
.. ImageUsage::none()
};
let res = unsafe {
UnsafeImage::new(device, usage, Format::R8G8B8A8Unorm,
ImageDimensions::Dim2d { width: 32, height: 64, array_layers: 1,
cubemap_compatible: true }, 1, 1,
Sharing::Exclusive::<Empty<_>>, false, false)
};
match res {
Err(ImageCreationError::UnsupportedDimensions { .. }) => (),
_ => panic!()
};
}
}