1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 use crate::device::physical::QueueFamily; 11 use crate::device::Device; 12 use crate::format::ClearValue; 13 use crate::format::Format; 14 use crate::format::FormatTy; 15 use crate::image::sys::ImageCreationError; 16 use crate::image::sys::UnsafeImage; 17 use crate::image::traits::ImageAccess; 18 use crate::image::traits::ImageClearValue; 19 use crate::image::traits::ImageContent; 20 use crate::image::ImageCreateFlags; 21 use crate::image::ImageDescriptorLayouts; 22 use crate::image::ImageDimensions; 23 use crate::image::ImageInner; 24 use crate::image::ImageLayout; 25 use crate::image::ImageUsage; 26 use crate::image::SampleCount; 27 use crate::memory::pool::AllocFromRequirementsFilter; 28 use crate::memory::pool::AllocLayout; 29 use crate::memory::pool::MappingRequirement; 30 use crate::memory::pool::MemoryPool; 31 use crate::memory::pool::MemoryPoolAlloc; 32 use crate::memory::pool::PotentialDedicatedAllocation; 33 use crate::memory::pool::StdMemoryPool; 34 use crate::memory::DedicatedAlloc; 35 use crate::sync::AccessError; 36 use crate::sync::Sharing; 37 use smallvec::SmallVec; 38 use std::hash::Hash; 39 use std::hash::Hasher; 40 use std::sync::atomic::AtomicUsize; 41 use std::sync::atomic::Ordering; 42 use std::sync::Arc; 43 44 /// General-purpose image in device memory. Can be used for any usage, but will be slower than a 45 /// specialized image. 46 #[derive(Debug)] 47 pub struct StorageImage<A = Arc<StdMemoryPool>> 48 where 49 A: MemoryPool, 50 { 51 // Inner implementation. 52 image: UnsafeImage, 53 54 // Memory used to back the image. 55 memory: PotentialDedicatedAllocation<A::Alloc>, 56 57 // Dimensions of the image. 58 dimensions: ImageDimensions, 59 60 // Format. 61 format: Format, 62 63 // Queue families allowed to access this image. 64 queue_families: SmallVec<[u32; 4]>, 65 66 // Number of times this image is locked on the GPU side. 67 gpu_lock: AtomicUsize, 68 } 69 70 impl StorageImage { 71 /// Creates a new image with the given dimensions and format. 72 #[inline] new<'a, I>( device: Arc<Device>, dimensions: ImageDimensions, format: Format, queue_families: I, ) -> Result<Arc<StorageImage>, ImageCreationError> where I: IntoIterator<Item = QueueFamily<'a>>,73 pub fn new<'a, I>( 74 device: Arc<Device>, 75 dimensions: ImageDimensions, 76 format: Format, 77 queue_families: I, 78 ) -> Result<Arc<StorageImage>, ImageCreationError> 79 where 80 I: IntoIterator<Item = QueueFamily<'a>>, 81 { 82 let is_depth = match format.ty() { 83 FormatTy::Depth => true, 84 FormatTy::DepthStencil => true, 85 FormatTy::Stencil => true, 86 FormatTy::Compressed => panic!(), 87 _ => false, 88 }; 89 90 let usage = ImageUsage { 91 transfer_source: true, 92 transfer_destination: true, 93 sampled: true, 94 storage: true, 95 color_attachment: !is_depth, 96 depth_stencil_attachment: is_depth, 97 input_attachment: true, 98 transient_attachment: false, 99 }; 100 let flags = ImageCreateFlags::none(); 101 102 StorageImage::with_usage(device, dimensions, format, usage, flags, queue_families) 103 } 104 105 /// Same as `new`, but allows specifying the usage. with_usage<'a, I>( device: Arc<Device>, dimensions: ImageDimensions, format: Format, usage: ImageUsage, flags: ImageCreateFlags, queue_families: I, ) -> Result<Arc<StorageImage>, ImageCreationError> where I: IntoIterator<Item = QueueFamily<'a>>,106 pub fn with_usage<'a, I>( 107 device: Arc<Device>, 108 dimensions: ImageDimensions, 109 format: Format, 110 usage: ImageUsage, 111 flags: ImageCreateFlags, 112 queue_families: I, 113 ) -> Result<Arc<StorageImage>, ImageCreationError> 114 where 115 I: IntoIterator<Item = QueueFamily<'a>>, 116 { 117 let queue_families = queue_families 118 .into_iter() 119 .map(|f| f.id()) 120 .collect::<SmallVec<[u32; 4]>>(); 121 122 let (image, mem_reqs) = unsafe { 123 let sharing = if queue_families.len() >= 2 { 124 Sharing::Concurrent(queue_families.iter().cloned()) 125 } else { 126 Sharing::Exclusive 127 }; 128 129 UnsafeImage::new( 130 device.clone(), 131 usage, 132 format, 133 flags, 134 dimensions, 135 SampleCount::Sample1, 136 1, 137 sharing, 138 false, 139 false, 140 )? 141 }; 142 143 let memory = MemoryPool::alloc_from_requirements( 144 &Device::standard_pool(&device), 145 &mem_reqs, 146 AllocLayout::Optimal, 147 MappingRequirement::DoNotMap, 148 DedicatedAlloc::Image(&image), 149 |t| { 150 if t.is_device_local() { 151 AllocFromRequirementsFilter::Preferred 152 } else { 153 AllocFromRequirementsFilter::Allowed 154 } 155 }, 156 )?; 157 debug_assert!((memory.offset() % mem_reqs.alignment) == 0); 158 unsafe { 159 image.bind_memory(memory.memory(), memory.offset())?; 160 } 161 162 Ok(Arc::new(StorageImage { 163 image, 164 memory, 165 dimensions, 166 format, 167 queue_families, 168 gpu_lock: AtomicUsize::new(0), 169 })) 170 } 171 } 172 173 impl<A> StorageImage<A> 174 where 175 A: MemoryPool, 176 { 177 /// Returns the dimensions of the image. 178 #[inline] dimensions(&self) -> ImageDimensions179 pub fn dimensions(&self) -> ImageDimensions { 180 self.dimensions 181 } 182 } 183 184 unsafe impl<A> ImageAccess for StorageImage<A> 185 where 186 A: MemoryPool, 187 { 188 #[inline] inner(&self) -> ImageInner189 fn inner(&self) -> ImageInner { 190 ImageInner { 191 image: &self.image, 192 first_layer: 0, 193 num_layers: self.dimensions.array_layers() as usize, 194 first_mipmap_level: 0, 195 num_mipmap_levels: 1, 196 } 197 } 198 199 #[inline] initial_layout_requirement(&self) -> ImageLayout200 fn initial_layout_requirement(&self) -> ImageLayout { 201 ImageLayout::General 202 } 203 204 #[inline] final_layout_requirement(&self) -> ImageLayout205 fn final_layout_requirement(&self) -> ImageLayout { 206 ImageLayout::General 207 } 208 209 #[inline] descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>210 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { 211 Some(ImageDescriptorLayouts { 212 storage_image: ImageLayout::General, 213 combined_image_sampler: ImageLayout::General, 214 sampled_image: ImageLayout::General, 215 input_attachment: ImageLayout::General, 216 }) 217 } 218 219 #[inline] conflict_key(&self) -> u64220 fn conflict_key(&self) -> u64 { 221 self.image.key() 222 } 223 224 #[inline] try_gpu_lock( &self, _: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>225 fn try_gpu_lock( 226 &self, 227 _: bool, 228 uninitialized_safe: bool, 229 expected_layout: ImageLayout, 230 ) -> Result<(), AccessError> { 231 // TODO: handle initial layout transition 232 if expected_layout != ImageLayout::General && expected_layout != ImageLayout::Undefined { 233 return Err(AccessError::UnexpectedImageLayout { 234 requested: expected_layout, 235 allowed: ImageLayout::General, 236 }); 237 } 238 239 let val = self 240 .gpu_lock 241 .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) 242 .unwrap_or_else(|e| e); 243 if val == 0 { 244 Ok(()) 245 } else { 246 Err(AccessError::AlreadyInUse) 247 } 248 } 249 250 #[inline] increase_gpu_lock(&self)251 unsafe fn increase_gpu_lock(&self) { 252 let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst); 253 debug_assert!(val >= 1); 254 } 255 256 #[inline] unlock(&self, new_layout: Option<ImageLayout>)257 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) { 258 assert!(new_layout.is_none() || new_layout == Some(ImageLayout::General)); 259 self.gpu_lock.fetch_sub(1, Ordering::SeqCst); 260 } 261 262 #[inline] current_miplevels_access(&self) -> std::ops::Range<u32>263 fn current_miplevels_access(&self) -> std::ops::Range<u32> { 264 0..self.mipmap_levels() 265 } 266 267 #[inline] current_layer_levels_access(&self) -> std::ops::Range<u32>268 fn current_layer_levels_access(&self) -> std::ops::Range<u32> { 269 0..self.dimensions().array_layers() 270 } 271 } 272 273 unsafe impl<A> ImageClearValue<ClearValue> for StorageImage<A> 274 where 275 A: MemoryPool, 276 { 277 #[inline] decode(&self, value: ClearValue) -> Option<ClearValue>278 fn decode(&self, value: ClearValue) -> Option<ClearValue> { 279 Some(self.format.decode_clear_value(value)) 280 } 281 } 282 283 unsafe impl<P, A> ImageContent<P> for StorageImage<A> 284 where 285 A: MemoryPool, 286 { 287 #[inline] matches_format(&self) -> bool288 fn matches_format(&self) -> bool { 289 true // FIXME: 290 } 291 } 292 293 impl<A> PartialEq for StorageImage<A> 294 where 295 A: MemoryPool, 296 { 297 #[inline] eq(&self, other: &Self) -> bool298 fn eq(&self, other: &Self) -> bool { 299 ImageAccess::inner(self) == ImageAccess::inner(other) 300 } 301 } 302 303 impl<A> Eq for StorageImage<A> where A: MemoryPool {} 304 305 impl<A> Hash for StorageImage<A> 306 where 307 A: MemoryPool, 308 { 309 #[inline] hash<H: Hasher>(&self, state: &mut H)310 fn hash<H: Hasher>(&self, state: &mut H) { 311 ImageAccess::inner(self).hash(state); 312 } 313 } 314 315 #[cfg(test)] 316 mod tests { 317 use super::StorageImage; 318 use crate::format::Format; 319 use crate::image::ImageDimensions; 320 321 #[test] create()322 fn create() { 323 let (device, queue) = gfx_dev_and_queue!(); 324 let _img = StorageImage::new( 325 device, 326 ImageDimensions::Dim2d { 327 width: 32, 328 height: 32, 329 array_layers: 1, 330 }, 331 Format::R8G8B8A8Unorm, 332 Some(queue.family()), 333 ) 334 .unwrap(); 335 } 336 } 337