diff options
Diffstat (limited to 'src/image/attachment.rs')
-rw-r--r-- | src/image/attachment.rs | 659 |
1 files changed, 0 insertions, 659 deletions
diff --git a/src/image/attachment.rs b/src/image/attachment.rs deleted file mode 100644 index 5892d3c..0000000 --- a/src/image/attachment.rs +++ /dev/null @@ -1,659 +0,0 @@ -// 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 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::StdMemoryPoolAlloc; -use crate::memory::DedicatedAlloc; -use crate::sync::AccessError; -use crate::sync::Sharing; -use std::hash::Hash; -use std::hash::Hasher; -use std::iter::Empty; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::sync::Arc; - -/// ImageAccess whose purpose is to be used as a framebuffer attachment. -/// -/// The image is always two-dimensional and has only one mipmap, but it can have any kind of -/// format. Trying to use a format that the backend doesn't support for rendering will result in -/// an error being returned when creating the image. Once you have an `AttachmentImage`, you are -/// guaranteed that you will be able to draw on it. -/// -/// The template parameter of `AttachmentImage` is a type that describes the format of the image. -/// -/// # Regular vs transient -/// -/// Calling `AttachmentImage::new` will create a regular image, while calling -/// `AttachmentImage::transient` will create a *transient* image. Transient image are only -/// relevant for images that serve as attachments, so `AttachmentImage` is the only type of -/// image in vulkano that provides a shortcut for this. -/// -/// A transient image is a special kind of image whose content is undefined outside of render -/// passes. Once you finish drawing, reading from it will returned undefined data (which can be -/// either valid or garbage, depending on the implementation). -/// -/// This gives a hint to the Vulkan implementation that it is possible for the image's content to -/// live exclusively in some cache memory, and that no real memory has to be allocated for it. -/// -/// In other words, if you are going to read from the image after drawing to it, use a regular -/// image. If you don't need to read from it (for example if it's some kind of intermediary color, -/// or a depth buffer that is only used once) then use a transient image as it may improve -/// performance. -/// -// TODO: forbid reading transient images outside render passes? -#[derive(Debug)] -pub struct AttachmentImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> { - // Inner implementation. - image: UnsafeImage, - - // Memory used to back the image. - memory: A, - - // Format. - format: Format, - - // Layout to use when the image is used as a framebuffer attachment. - // Must be either "depth-stencil optimal" or "color optimal". - attachment_layout: ImageLayout, - - // If true, then the image is in the layout of `attachment_layout` (above). If false, then it - // is still `Undefined`. - initialized: AtomicBool, - - // Number of times this image is locked on the GPU side. - gpu_lock: AtomicUsize, -} - -impl AttachmentImage { - /// Creates a new image with the given dimensions and format. - /// - /// Returns an error if the dimensions are too large or if the backend doesn't support this - /// format as a framebuffer attachment. - #[inline] - pub fn new( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - ImageUsage::none(), - SampleCount::Sample1, - ) - } - - /// Same as `new`, but creates an image that can be used as an input attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `with_usage`. - #[inline] - pub fn input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - base_usage, - SampleCount::Sample1, - ) - } - - /// Same as `new`, but creates a multisampled image. - /// - /// > **Note**: You can also use this function and pass `1` for the number of samples if you - /// > want a regular image. - #[inline] - pub fn multisampled( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::none(), samples) - } - - /// Same as `multisampled`, but creates an image that can be used as an input attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. - #[inline] - pub fn multisampled_input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) - } - - /// Same as `new`, but lets you specify additional usages. - /// - /// The `color_attachment` or `depth_stencil_attachment` usages are automatically added based - /// on the format of the usage. Therefore the `usage` parameter allows you specify usages in - /// addition to these two. - #[inline] - pub fn with_usage( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - usage: ImageUsage, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - AttachmentImage::new_impl(device, dimensions, 1, format, usage, SampleCount::Sample1) - } - - /// Same as `with_usage`, but creates a multisampled image. - /// - /// > **Note**: You can also use this function and pass `1` for the number of samples if you - /// > want a regular image. - #[inline] - pub fn multisampled_with_usage( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - usage: ImageUsage, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - AttachmentImage::new_impl(device, dimensions, 1, format, usage, samples) - } - - /// Same as `multisampled_with_usage`, but creates an image with multiple layers. - /// - /// > **Note**: You can also use this function and pass `1` for the number of layers if you - /// > want a regular image. - #[inline] - pub fn multisampled_with_usage_with_layers( - device: Arc<Device>, - dimensions: [u32; 2], - array_layers: u32, - samples: SampleCount, - format: Format, - usage: ImageUsage, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - AttachmentImage::new_impl(device, dimensions, array_layers, format, usage, samples) - } - - /// Same as `new`, except that the image can later be sampled. - /// - /// > **Note**: This function is just a convenient shortcut for `with_usage`. - #[inline] - pub fn sampled( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - sampled: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - base_usage, - SampleCount::Sample1, - ) - } - - /// Same as `sampled`, except that the image can be used as an input attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `with_usage`. - #[inline] - pub fn sampled_input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - sampled: true, - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - base_usage, - SampleCount::Sample1, - ) - } - - /// Same as `sampled`, but creates a multisampled image. - /// - /// > **Note**: You can also use this function and pass `1` for the number of samples if you - /// > want a regular image. - /// - /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. - #[inline] - pub fn sampled_multisampled( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - sampled: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) - } - - /// Same as `sampled_multisampled`, but creates an image that can be used as an input - /// attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. - #[inline] - pub fn sampled_multisampled_input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - sampled: true, - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) - } - - /// Same as `new`, except that the image will be transient. - /// - /// A transient image is special because its content is undefined outside of a render pass. - /// This means that the implementation has the possibility to not allocate any memory for it. - /// - /// > **Note**: This function is just a convenient shortcut for `with_usage`. - #[inline] - pub fn transient( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - transient_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - base_usage, - SampleCount::Sample1, - ) - } - - /// Same as `transient`, except that the image can be used as an input attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `with_usage`. - #[inline] - pub fn transient_input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - transient_attachment: true, - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl( - device, - dimensions, - 1, - format, - base_usage, - SampleCount::Sample1, - ) - } - - /// Same as `transient`, but creates a multisampled image. - /// - /// > **Note**: You can also use this function and pass `1` for the number of samples if you - /// > want a regular image. - /// - /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. - #[inline] - pub fn transient_multisampled( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - transient_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) - } - - /// Same as `transient_multisampled`, but creates an image that can be used as an input - /// attachment. - /// - /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. - #[inline] - pub fn transient_multisampled_input_attachment( - device: Arc<Device>, - dimensions: [u32; 2], - samples: SampleCount, - format: Format, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - let base_usage = ImageUsage { - transient_attachment: true, - input_attachment: true, - ..ImageUsage::none() - }; - - AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) - } - - // All constructors dispatch to this one. - fn new_impl( - device: Arc<Device>, - dimensions: [u32; 2], - array_layers: u32, - format: Format, - base_usage: ImageUsage, - samples: SampleCount, - ) -> Result<Arc<AttachmentImage>, ImageCreationError> { - // TODO: check dimensions against the max_framebuffer_width/height/layers limits - - let is_depth = match format.ty() { - FormatTy::Depth => true, - FormatTy::DepthStencil => true, - FormatTy::Stencil => true, - FormatTy::Compressed => panic!(), - _ => false, - }; - - let usage = ImageUsage { - color_attachment: !is_depth, - depth_stencil_attachment: is_depth, - ..base_usage - }; - - let (image, mem_reqs) = unsafe { - let dims = ImageDimensions::Dim2d { - width: dimensions[0], - height: dimensions[1], - array_layers, - }; - - UnsafeImage::new( - device.clone(), - usage, - format, - ImageCreateFlags::none(), - dims, - samples, - 1, - Sharing::Exclusive::<Empty<u32>>, - false, - false, - )? - }; - - 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 - } else { - AllocFromRequirementsFilter::Allowed - } - }, - )?; - debug_assert!((memory.offset() % mem_reqs.alignment) == 0); - unsafe { - image.bind_memory(memory.memory(), memory.offset())?; - } - - Ok(Arc::new(AttachmentImage { - image, - memory, - format, - attachment_layout: if is_depth { - ImageLayout::DepthStencilAttachmentOptimal - } else { - ImageLayout::ColorAttachmentOptimal - }, - initialized: AtomicBool::new(false), - gpu_lock: AtomicUsize::new(0), - })) - } -} - -impl<A> AttachmentImage<A> { - /// Returns the dimensions of the image. - #[inline] - pub fn dimensions(&self) -> [u32; 2] { - let dims = self.image.dimensions(); - [dims.width(), dims.height()] - } -} - -unsafe impl<A> ImageAccess for AttachmentImage<A> { - #[inline] - fn inner(&self) -> ImageInner { - ImageInner { - image: &self.image, - first_layer: 0, - num_layers: self.image.dimensions().array_layers() as usize, - first_mipmap_level: 0, - num_mipmap_levels: 1, - } - } - - #[inline] - fn initial_layout_requirement(&self) -> ImageLayout { - self.attachment_layout - } - - #[inline] - fn final_layout_requirement(&self) -> ImageLayout { - self.attachment_layout - } - - #[inline] - fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { - Some(ImageDescriptorLayouts { - storage_image: ImageLayout::ShaderReadOnlyOptimal, - combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal, - sampled_image: ImageLayout::ShaderReadOnlyOptimal, - input_attachment: ImageLayout::ShaderReadOnlyOptimal, - }) - } - - #[inline] - fn conflict_key(&self) -> u64 { - self.image.key() - } - - #[inline] - fn try_gpu_lock( - &self, - _: bool, - uninitialized_safe: bool, - expected_layout: ImageLayout, - ) -> Result<(), AccessError> { - if expected_layout != self.attachment_layout && expected_layout != ImageLayout::Undefined { - if self.initialized.load(Ordering::SeqCst) { - return Err(AccessError::UnexpectedImageLayout { - requested: expected_layout, - allowed: self.attachment_layout, - }); - } else { - return Err(AccessError::UnexpectedImageLayout { - requested: expected_layout, - allowed: ImageLayout::Undefined, - }); - } - } - - if !uninitialized_safe && expected_layout != ImageLayout::Undefined { - if !self.initialized.load(Ordering::SeqCst) { - return Err(AccessError::ImageNotInitialized { - requested: expected_layout, - }); - } - } - - if self - .gpu_lock - .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) - .unwrap_or_else(|e| e) - == 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>) { - if let Some(new_layout) = new_layout { - debug_assert_eq!(new_layout, self.attachment_layout); - self.initialized.store(true, Ordering::SeqCst); - } - - let prev_val = self.gpu_lock.fetch_sub(1, Ordering::SeqCst); - debug_assert!(prev_val >= 1); - } - - #[inline] - unsafe fn layout_initialized(&self) { - self.initialized.store(true, Ordering::SeqCst); - } - - #[inline] - fn is_layout_initialized(&self) -> bool { - self.initialized.load(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..1 - } -} - -unsafe impl<A> ImageClearValue<ClearValue> for Arc<AttachmentImage<A>> { - #[inline] - fn decode(&self, value: ClearValue) -> Option<ClearValue> { - Some(self.format.decode_clear_value(value)) - } -} - -unsafe impl<P, A> ImageContent<P> for Arc<AttachmentImage<A>> { - #[inline] - fn matches_format(&self) -> bool { - true // FIXME: - } -} - -impl<A> PartialEq for AttachmentImage<A> { - #[inline] - fn eq(&self, other: &Self) -> bool { - ImageAccess::inner(self) == ImageAccess::inner(other) - } -} - -impl<A> Eq for AttachmentImage<A> {} - -impl<A> Hash for AttachmentImage<A> { - #[inline] - fn hash<H: Hasher>(&self, state: &mut H) { - ImageAccess::inner(self).hash(state); - } -} - -#[cfg(test)] -mod tests { - use super::AttachmentImage; - use crate::format::Format; - - #[test] - fn create_regular() { - let (device, _) = gfx_dev_and_queue!(); - let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap(); - } - - #[test] - fn create_transient() { - let (device, _) = gfx_dev_and_queue!(); - let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap(); - } - - #[test] - fn d16_unorm_always_supported() { - let (device, _) = gfx_dev_and_queue!(); - let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap(); - } -} |