aboutsummaryrefslogtreecommitdiff
path: root/src/image/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/image/storage.rs')
-rw-r--r--src/image/storage.rs712
1 files changed, 484 insertions, 228 deletions
diff --git a/src/image/storage.rs b/src/image/storage.rs
index 627d43a..f4fb2e1 100644
--- a/src/image/storage.rs
+++ b/src/image/storage.rs
@@ -7,190 +7,472 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::format::ClearValue;
-use crate::format::Format;
-use crate::format::FormatTy;
-use crate::image::sys::ImageCreationError;
-use crate::image::sys::UnsafeImage;
-use crate::image::traits::ImageAccess;
-use crate::image::traits::ImageClearValue;
-use crate::image::traits::ImageContent;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageDimensions;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::image::ImageUsage;
-use crate::image::SampleCount;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPool;
-use crate::memory::DedicatedAlloc;
-use crate::sync::AccessError;
-use crate::sync::Sharing;
+use super::{
+ sys::{Image, ImageMemory, RawImage},
+ traits::ImageContent,
+ ImageAccess, ImageAspects, ImageCreateFlags, ImageDescriptorLayouts, ImageDimensions,
+ ImageError, ImageInner, ImageLayout, ImageUsage,
+};
+use crate::{
+ device::{Device, DeviceOwned, Queue},
+ format::Format,
+ image::{sys::ImageCreateInfo, view::ImageView, ImageFormatInfo},
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationType, MemoryAllocatePreference, MemoryAllocator,
+ MemoryUsage,
+ },
+ is_aligned, DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
+ ExternalMemoryHandleTypes,
+ },
+ sync::Sharing,
+ DeviceSize,
+};
use smallvec::SmallVec;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
+
+#[cfg(target_os = "linux")]
+use crate::{
+ image::ImageTiling,
+ memory::{allocator::MemoryAlloc, DeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo},
+};
+#[cfg(target_os = "linux")]
+use ash::vk::{ImageDrmFormatModifierExplicitCreateInfoEXT, SubresourceLayout};
+#[cfg(target_os = "linux")]
+use std::os::unix::prelude::{FromRawFd, IntoRawFd, RawFd};
+
+use std::{
+ fs::File,
+ hash::{Hash, Hasher},
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+};
/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
/// specialized image.
#[derive(Debug)]
-pub struct StorageImage<A = Arc<StdMemoryPool>>
-where
- A: MemoryPool,
-{
- // Inner implementation.
- image: UnsafeImage,
-
- // Memory used to back the image.
- memory: PotentialDedicatedAllocation<A::Alloc>,
-
- // Dimensions of the image.
- dimensions: ImageDimensions,
-
- // Format.
- format: Format,
+pub struct StorageImage {
+ inner: Arc<Image>,
- // Queue families allowed to access this image.
- queue_families: SmallVec<[u32; 4]>,
-
- // Number of times this image is locked on the GPU side.
- gpu_lock: AtomicUsize,
+ // If true, then the image is in the layout `General`. If false, then it
+ // is still `Undefined`.
+ layout_initialized: AtomicBool,
}
impl StorageImage {
/// Creates a new image with the given dimensions and format.
- #[inline]
- pub fn new<'a, I>(
- device: Arc<Device>,
+ pub fn new(
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: ImageDimensions,
format: Format,
- queue_families: I,
- ) -> Result<Arc<StorageImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let is_depth = match format.ty() {
- FormatTy::Depth => true,
- FormatTy::DepthStencil => true,
- FormatTy::Stencil => true,
- FormatTy::Compressed => panic!(),
- _ => false,
- };
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let aspects = format.aspects();
+ let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
- let usage = ImageUsage {
- transfer_source: true,
- transfer_destination: true,
- sampled: true,
- storage: true,
- color_attachment: !is_depth,
- depth_stencil_attachment: is_depth,
- input_attachment: true,
- transient_attachment: false,
- };
- let flags = ImageCreateFlags::none();
+ if format.compression().is_some() {
+ panic!() // TODO: message?
+ }
+
+ let usage = ImageUsage::TRANSFER_SRC
+ | ImageUsage::TRANSFER_DST
+ | ImageUsage::SAMPLED
+ | ImageUsage::STORAGE
+ | ImageUsage::INPUT_ATTACHMENT
+ | if is_depth_stencil {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ } else {
+ ImageUsage::COLOR_ATTACHMENT
+ };
+ let flags = ImageCreateFlags::empty();
- StorageImage::with_usage(device, dimensions, format, usage, flags, queue_families)
+ StorageImage::with_usage(
+ allocator,
+ dimensions,
+ format,
+ usage,
+ flags,
+ queue_family_indices,
+ )
}
/// Same as `new`, but allows specifying the usage.
- pub fn with_usage<'a, I>(
- device: Arc<Device>,
+ pub fn with_usage(
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: ImageDimensions,
format: Format,
usage: ImageUsage,
flags: ImageCreateFlags,
- queue_families: I,
- ) -> Result<Arc<StorageImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (image, mem_reqs) = unsafe {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
-
- UnsafeImage::new(
- device.clone(),
- usage,
- format,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+ assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
+
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
flags,
dimensions,
- SampleCount::Sample1,
- 1,
- sharing,
- false,
- false,
- )?
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
+ } else {
+ Sharing::Exclusive
+ },
+ ..Default::default()
+ },
+ )?;
+ let requirements = raw_image.memory_requirements()[0];
+ let res = unsafe {
+ allocator.allocate_unchecked(
+ requirements,
+ AllocationType::NonLinear,
+ AllocationCreateInfo {
+ usage: MemoryUsage::DeviceOnly,
+ allocate_preference: MemoryAllocatePreference::Unknown,
+ _ne: crate::NonExhaustive(()),
+ },
+ Some(DedicatedAllocation::Image(&raw_image)),
+ )
};
- let memory = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Optimal,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Image(&image),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
+ match res {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(
+ unsafe { raw_image.bind_memory_unchecked([alloc]) }
+ .map_err(|(err, _, _)| err)?,
+ );
+
+ Ok(Arc::new(StorageImage {
+ inner,
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
+ }
+ }
+
+ pub fn new_with_exportable_fd(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ dimensions: ImageDimensions,
+ format: Format,
+ usage: ImageUsage,
+ flags: ImageCreateFlags,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+ assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
+
+ let external_memory_properties = allocator
+ .device()
+ .physical_device()
+ .image_format_properties(ImageFormatInfo {
+ flags,
+ format: Some(format),
+ image_type: dimensions.image_type(),
+ usage,
+ external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
+ ..Default::default()
+ })
+ .unwrap()
+ .unwrap()
+ .external_memory_properties;
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
+ assert!(external_memory_properties.exportable);
+
+ // VUID-VkMemoryAllocateInfo-pNext-00639
+ // Guaranteed because we always create a dedicated allocation
+
+ let external_memory_handle_types = ExternalMemoryHandleTypes::OPAQUE_FD;
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
+ flags,
+ dimensions,
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
} else {
- AllocFromRequirementsFilter::Allowed
- }
+ Sharing::Exclusive
+ },
+ external_memory_handle_types,
+ ..Default::default()
},
)?;
- debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
- unsafe {
- image.bind_memory(memory.memory(), memory.offset())?;
+ let requirements = raw_image.memory_requirements()[0];
+ let memory_type_index = allocator
+ .find_memory_type_index(
+ requirements.memory_type_bits,
+ MemoryUsage::DeviceOnly.into(),
+ )
+ .expect("failed to find a suitable memory type");
+
+ match unsafe {
+ allocator.allocate_dedicated_unchecked(
+ memory_type_index,
+ requirements.layout.size(),
+ Some(DedicatedAllocation::Image(&raw_image)),
+ external_memory_handle_types,
+ )
+ } {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(unsafe {
+ raw_image
+ .bind_memory_unchecked([alloc])
+ .map_err(|(err, _, _)| err)?
+ });
+
+ Ok(Arc::new(StorageImage {
+ inner,
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ /// Creates a new image from a set of Linux dma_buf file descriptors. The memory will be imported from the file desciptors, and will be bound to the image.
+ /// # Arguments
+ /// * `fds` - The list of file descriptors to import from. Single planar images should only use one, and multiplanar images can use multiple, for example, for each color.
+ /// * `offset` - The byte offset from the start of the image of the plane where the image subresource begins.
+ /// * `pitch` - Describes the number of bytes between each row of texels in an image.
+ pub fn new_from_dma_buf_fd(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ device: Arc<Device>,
+ dimensions: ImageDimensions,
+ format: Format,
+ usage: ImageUsage,
+ flags: ImageCreateFlags,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ mut subresource_data: Vec<SubresourceData>,
+ drm_format_modifier: u64,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+
+ // TODO: Support multiplanar image importing from Linux FD
+ if subresource_data.len() > 1 {
+ todo!();
}
+ // Create a vector of the layout of each image plane.
+
+ // All of the following are automatically true, since the values are explicitly set as such:
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-size-02267
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-depthPitch-02269
+ let layout: Vec<SubresourceLayout> = subresource_data
+ .iter_mut()
+ .map(
+ |SubresourceData {
+ fd: _,
+ offset,
+ row_pitch,
+ }| {
+ SubresourceLayout {
+ offset: *offset,
+ size: 0,
+ row_pitch: *row_pitch,
+ array_pitch: 0_u64,
+ depth_pitch: 0_u64,
+ }
+ },
+ )
+ .collect();
+
+ let fds: Vec<RawFd> = subresource_data
+ .iter_mut()
+ .map(
+ |SubresourceData {
+ fd,
+ offset: _,
+ row_pitch: _,
+ }| { *fd },
+ )
+ .collect();
+
+ let drm_mod = ImageDrmFormatModifierExplicitCreateInfoEXT::builder()
+ .drm_format_modifier(drm_format_modifier)
+ .plane_layouts(layout.as_ref())
+ .build();
+
+ let external_memory_handle_types = ExternalMemoryHandleTypes::DMA_BUF;
+
+ let image = RawImage::new(
+ device.clone(),
+ ImageCreateInfo {
+ flags,
+ dimensions,
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
+ } else {
+ Sharing::Exclusive
+ },
+ external_memory_handle_types,
+ tiling: ImageTiling::DrmFormatModifier,
+ image_drm_format_modifier_create_info: Some(drm_mod),
+ ..Default::default()
+ },
+ )?;
+
+ let requirements = image.memory_requirements()[0];
+ let memory_type_index = allocator
+ .find_memory_type_index(
+ requirements.memory_type_bits,
+ MemoryUsage::DeviceOnly.into(),
+ )
+ .expect("failed to find a suitable memory type");
+
+ assert!(device.enabled_extensions().khr_external_memory_fd);
+ assert!(device.enabled_extensions().khr_external_memory);
+ assert!(device.enabled_extensions().ext_external_memory_dma_buf);
+
+ let memory = unsafe {
+ // TODO: For completeness, importing memory from muliple file descriptors should be added (In order to support importing multiplanar images). As of now, only single planar image importing will work.
+ if fds.len() != 1 {
+ todo!();
+ }
+
+ // Try cloning underlying fd
+ let file = File::from_raw_fd(*fds.first().expect("file descriptor Vec is empty"));
+ let new_file = file.try_clone().expect("error cloning file descriptor");
+
+ // Turn the original file descriptor back into a raw fd to avoid ownership problems
+ file.into_raw_fd();
+ DeviceMemory::import(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: requirements.layout.size(),
+ memory_type_index,
+ dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
+ export_handle_types: ExternalMemoryHandleTypes::empty(),
+ flags: MemoryAllocateFlags::empty(),
+ ..Default::default()
+ },
+ crate::memory::MemoryImportInfo::Fd {
+ handle_type: crate::memory::ExternalMemoryHandleType::DmaBuf,
+ file: new_file,
+ },
+ )
+ .unwrap() // TODO: Handle
+ };
+
+ let mem_alloc = MemoryAlloc::new(memory).unwrap();
+
+ debug_assert!(mem_alloc.offset() % requirements.layout.alignment().as_nonzero() == 0);
+ debug_assert!(mem_alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(unsafe {
+ image
+ .bind_memory_unchecked([mem_alloc])
+ .map_err(|(err, _, _)| err)?
+ });
Ok(Arc::new(StorageImage {
- image,
- memory,
- dimensions,
- format,
- queue_families,
- gpu_lock: AtomicUsize::new(0),
+ inner,
+ layout_initialized: AtomicBool::new(false),
}))
}
+ /// Allows the creation of a simple 2D general purpose image view from `StorageImage`.
+ #[inline]
+ pub fn general_purpose_image_view(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ queue: Arc<Queue>,
+ size: [u32; 2],
+ format: Format,
+ usage: ImageUsage,
+ ) -> Result<Arc<ImageView<StorageImage>>, ImageError> {
+ let dims = ImageDimensions::Dim2d {
+ width: size[0],
+ height: size[1],
+ array_layers: 1,
+ };
+ let flags = ImageCreateFlags::empty();
+ let image_result = StorageImage::with_usage(
+ allocator,
+ dims,
+ format,
+ usage,
+ flags,
+ Some(queue.queue_family_index()),
+ );
+
+ match image_result {
+ Ok(image) => {
+ let image_view = ImageView::new_default(image);
+ match image_view {
+ Ok(view) => Ok(view),
+ Err(e) => Err(ImageError::DirectImageViewCreationFailed(e)),
+ }
+ }
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Exports posix file descriptor for the allocated memory.
+ /// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
+ #[inline]
+ pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation
+ .device_memory()
+ .export_fd(ExternalMemoryHandleType::OpaqueFd)
+ }
+
+ /// Return the size of the allocated memory (used e.g. with cuda).
+ #[inline]
+ pub fn mem_size(&self) -> DeviceSize {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation.device_memory().allocation_size()
+ }
}
-impl<A> StorageImage<A>
-where
- A: MemoryPool,
-{
- /// Returns the dimensions of the image.
+#[cfg(target_os = "linux")]
+/// Struct that contains a Linux file descriptor for importing, when creating an image. Since a file descriptor is used for each
+/// plane in the case of multiplanar images, each fd needs to have an offset and a row pitch in order to interpret the imported data.
+pub struct SubresourceData {
+ /// The file descriptor handle of a layer of an image.
+ pub fd: RawFd,
+
+ /// The byte offset from the start of the plane where the image subresource begins.
+ pub offset: u64,
+
+ /// Describes the number of bytes between each row of texels in an image plane.
+ pub row_pitch: u64,
+}
+
+unsafe impl DeviceOwned for StorageImage {
#[inline]
- pub fn dimensions(&self) -> ImageDimensions {
- self.dimensions
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
}
-unsafe impl<A> ImageAccess for StorageImage<A>
-where
- A: MemoryPool,
-{
+unsafe impl ImageAccess for StorageImage {
#[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
ImageInner {
- image: &self.image,
+ image: &self.inner,
first_layer: 0,
- num_layers: self.dimensions.array_layers() as usize,
+ num_layers: self.inner.dimensions().array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
@@ -207,6 +489,16 @@ where
}
#[inline]
+ unsafe fn layout_initialized(&self) {
+ self.layout_initialized.store(true, Ordering::Relaxed);
+ }
+
+ #[inline]
+ fn is_layout_initialized(&self) -> bool {
+ self.layout_initialized.load(Ordering::Relaxed)
+ }
+
+ #[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
Some(ImageDescriptorLayouts {
storage_image: ImageLayout::General,
@@ -215,122 +507,86 @@ where
input_attachment: ImageLayout::General,
})
}
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- _: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- // TODO: handle initial layout transition
- if expected_layout != ImageLayout::General && expected_layout != ImageLayout::Undefined {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: ImageLayout::General,
- });
- }
-
- let val = self
- .gpu_lock
- .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst)
- .unwrap_or_else(|e| e);
- if val == 0 {
- Ok(())
- } else {
- Err(AccessError::AlreadyInUse)
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
- debug_assert!(val >= 1);
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- assert!(new_layout.is_none() || new_layout == Some(ImageLayout::General));
- self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
- }
-
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- 0..self.mipmap_levels()
- }
-
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- 0..self.dimensions().array_layers()
- }
}
-unsafe impl<A> ImageClearValue<ClearValue> for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn decode(&self, value: ClearValue) -> Option<ClearValue> {
- Some(self.format.decode_clear_value(value))
- }
-}
-
-unsafe impl<P, A> ImageContent<P> for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
+unsafe impl<P> ImageContent<P> for StorageImage {
fn matches_format(&self) -> bool {
true // FIXME:
}
}
-impl<A> PartialEq for StorageImage<A>
-where
- A: MemoryPool,
-{
+impl PartialEq for StorageImage {
#[inline]
fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+ self.inner() == other.inner()
}
}
-impl<A> Eq for StorageImage<A> where A: MemoryPool {}
+impl Eq for StorageImage {}
-impl<A> Hash for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
+impl Hash for StorageImage {
fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+ self.inner().hash(state);
}
}
#[cfg(test)]
mod tests {
- use super::StorageImage;
- use crate::format::Format;
- use crate::image::ImageDimensions;
+ use super::*;
+ use crate::{image::view::ImageViewCreationError, memory::allocator::StandardMemoryAllocator};
#[test]
fn create() {
let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
let _img = StorageImage::new(
- device,
+ &memory_allocator,
ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- Format::R8G8B8A8Unorm,
- Some(queue.family()),
+ Format::R8G8B8A8_UNORM,
+ Some(queue.queue_family_index()),
)
.unwrap();
}
+
+ #[test]
+ fn create_general_purpose_image_view() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let usage =
+ ImageUsage::TRANSFER_SRC | ImageUsage::TRANSFER_DST | ImageUsage::COLOR_ATTACHMENT;
+ let img_view = StorageImage::general_purpose_image_view(
+ &memory_allocator,
+ queue,
+ [32, 32],
+ Format::R8G8B8A8_UNORM,
+ usage,
+ )
+ .unwrap();
+ assert_eq!(img_view.image().usage(), usage);
+ }
+
+ #[test]
+ fn create_general_purpose_image_view_failed() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ // Not valid for image view...
+ let usage = ImageUsage::TRANSFER_SRC;
+ let img_result = StorageImage::general_purpose_image_view(
+ &memory_allocator,
+ queue,
+ [32, 32],
+ Format::R8G8B8A8_UNORM,
+ usage,
+ );
+ assert_eq!(
+ img_result,
+ Err(ImageError::DirectImageViewCreationFailed(
+ ImageViewCreationError::ImageMissingUsage
+ ))
+ );
+ }
}