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 super::{
11     sys::{Image, RawImage},
12     traits::ImageContent,
13     ImageAccess, ImageCreateFlags, ImageDescriptorLayouts, ImageDimensions, ImageError, ImageInner,
14     ImageLayout, ImageSubresourceLayers, ImageUsage, MipmapsCount,
15 };
16 use crate::{
17     buffer::{Buffer, BufferContents, BufferCreateInfo, BufferError, BufferUsage, Subbuffer},
18     command_buffer::{
19         allocator::CommandBufferAllocator, AutoCommandBufferBuilder, BlitImageInfo,
20         BufferImageCopy, CommandBufferBeginError, CopyBufferToImageInfo, ImageBlit,
21     },
22     device::{Device, DeviceOwned},
23     format::Format,
24     image::sys::ImageCreateInfo,
25     memory::{
26         allocator::{
27             AllocationCreateInfo, AllocationCreationError, AllocationType,
28             MemoryAllocatePreference, MemoryAllocator, MemoryUsage,
29         },
30         is_aligned, DedicatedAllocation,
31     },
32     sampler::Filter,
33     sync::Sharing,
34     DeviceSize, VulkanError,
35 };
36 use smallvec::{smallvec, SmallVec};
37 use std::{
38     error::Error,
39     fmt::{Display, Error as FmtError, Formatter},
40     hash::{Hash, Hasher},
41     sync::Arc,
42 };
43 
44 /// Image whose purpose is to be used for read-only purposes. You can write to the image once,
45 /// but then you must only ever read from it.
46 // TODO: type (2D, 3D, array, etc.) as template parameter
47 #[derive(Debug)]
48 pub struct ImmutableImage {
49     inner: Arc<Image>,
50     layout: ImageLayout,
51 }
52 
has_mipmaps(mipmaps: MipmapsCount) -> bool53 fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
54     match mipmaps {
55         MipmapsCount::One => false,
56         MipmapsCount::Log2 => true,
57         MipmapsCount::Specific(x) => x > 1,
58     }
59 }
60 
generate_mipmaps<L, Cba>( cbb: &mut AutoCommandBufferBuilder<L, Cba>, image: Arc<dyn ImageAccess>, dimensions: ImageDimensions, _layout: ImageLayout, ) where Cba: CommandBufferAllocator,61 fn generate_mipmaps<L, Cba>(
62     cbb: &mut AutoCommandBufferBuilder<L, Cba>,
63     image: Arc<dyn ImageAccess>,
64     dimensions: ImageDimensions,
65     _layout: ImageLayout,
66 ) where
67     Cba: CommandBufferAllocator,
68 {
69     for level in 1..image.mip_levels() {
70         let src_size = dimensions
71             .mip_level_dimensions(level - 1)
72             .unwrap()
73             .width_height_depth();
74         let dst_size = dimensions
75             .mip_level_dimensions(level)
76             .unwrap()
77             .width_height_depth();
78 
79         cbb.blit_image(BlitImageInfo {
80             regions: [ImageBlit {
81                 src_subresource: ImageSubresourceLayers {
82                     mip_level: level - 1,
83                     ..image.subresource_layers()
84                 },
85                 src_offsets: [[0; 3], src_size],
86                 dst_subresource: ImageSubresourceLayers {
87                     mip_level: level,
88                     ..image.subresource_layers()
89                 },
90                 dst_offsets: [[0; 3], dst_size],
91                 ..Default::default()
92             }]
93             .into(),
94             filter: Filter::Linear,
95             ..BlitImageInfo::images(image.clone(), image.clone())
96         })
97         .expect("failed to blit a mip map to image!");
98     }
99 }
100 
101 impl ImmutableImage {
102     /// Builds an uninitialized immutable image.
103     ///
104     /// Returns two things: the image, and a special access that should be used for the initial
105     /// upload to the image.
uninitialized( allocator: &(impl MemoryAllocator + ?Sized), dimensions: ImageDimensions, format: Format, mip_levels: impl Into<MipmapsCount>, usage: ImageUsage, flags: ImageCreateFlags, layout: ImageLayout, queue_family_indices: impl IntoIterator<Item = u32>, ) -> Result<(Arc<ImmutableImage>, Arc<ImmutableImageInitialization>), ImmutableImageCreationError>106     pub fn uninitialized(
107         allocator: &(impl MemoryAllocator + ?Sized),
108         dimensions: ImageDimensions,
109         format: Format,
110         mip_levels: impl Into<MipmapsCount>,
111         usage: ImageUsage,
112         flags: ImageCreateFlags,
113         layout: ImageLayout,
114         queue_family_indices: impl IntoIterator<Item = u32>,
115     ) -> Result<(Arc<ImmutableImage>, Arc<ImmutableImageInitialization>), ImmutableImageCreationError>
116     {
117         let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
118         assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
119 
120         let raw_image = RawImage::new(
121             allocator.device().clone(),
122             ImageCreateInfo {
123                 flags,
124                 dimensions,
125                 format: Some(format),
126                 mip_levels: match mip_levels.into() {
127                     MipmapsCount::Specific(num) => num,
128                     MipmapsCount::Log2 => dimensions.max_mip_levels(),
129                     MipmapsCount::One => 1,
130                 },
131                 usage,
132                 sharing: if queue_family_indices.len() >= 2 {
133                     Sharing::Concurrent(queue_family_indices)
134                 } else {
135                     Sharing::Exclusive
136                 },
137                 ..Default::default()
138             },
139         )?;
140         let requirements = raw_image.memory_requirements()[0];
141         let res = unsafe {
142             allocator.allocate_unchecked(
143                 requirements,
144                 AllocationType::NonLinear,
145                 AllocationCreateInfo {
146                     usage: MemoryUsage::DeviceOnly,
147                     allocate_preference: MemoryAllocatePreference::Unknown,
148                     _ne: crate::NonExhaustive(()),
149                 },
150                 Some(DedicatedAllocation::Image(&raw_image)),
151             )
152         };
153 
154         match res {
155             Ok(alloc) => {
156                 debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
157                 debug_assert!(alloc.size() == requirements.layout.size());
158 
159                 let inner = Arc::new(
160                     unsafe { raw_image.bind_memory_unchecked([alloc]) }
161                         .map_err(|(err, _, _)| err)?,
162                 );
163 
164                 let image = Arc::new(ImmutableImage { inner, layout });
165 
166                 let init = Arc::new(ImmutableImageInitialization {
167                     image: image.clone(),
168                 });
169 
170                 Ok((image, init))
171             }
172             Err(err) => Err(err.into()),
173         }
174     }
175 
176     /// Construct an ImmutableImage from the contents of `iter`.
177     ///
178     /// This is a convenience function, equivalent to creating a `CpuAccessibleBuffer`, writing
179     /// `iter` to it, then calling [`from_buffer`](ImmutableImage::from_buffer) to copy the data
180     /// over.
from_iter<Px, I, L, A>( allocator: &(impl MemoryAllocator + ?Sized), iter: I, dimensions: ImageDimensions, mip_levels: MipmapsCount, format: Format, command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>, ) -> Result<Arc<Self>, ImmutableImageCreationError> where Px: BufferContents, I: IntoIterator<Item = Px>, I::IntoIter: ExactSizeIterator, A: CommandBufferAllocator,181     pub fn from_iter<Px, I, L, A>(
182         allocator: &(impl MemoryAllocator + ?Sized),
183         iter: I,
184         dimensions: ImageDimensions,
185         mip_levels: MipmapsCount,
186         format: Format,
187         command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
188     ) -> Result<Arc<Self>, ImmutableImageCreationError>
189     where
190         Px: BufferContents,
191         I: IntoIterator<Item = Px>,
192         I::IntoIter: ExactSizeIterator,
193         A: CommandBufferAllocator,
194     {
195         let source = Buffer::from_iter(
196             allocator,
197             BufferCreateInfo {
198                 usage: BufferUsage::TRANSFER_SRC,
199                 ..Default::default()
200             },
201             AllocationCreateInfo {
202                 usage: MemoryUsage::Upload,
203                 ..Default::default()
204             },
205             iter,
206         )
207         .map_err(|err| match err {
208             BufferError::AllocError(err) => err,
209             // We don't use sparse-binding, concurrent sharing or external memory, therefore the
210             // other errors can't happen.
211             _ => unreachable!(),
212         })?;
213 
214         ImmutableImage::from_buffer(
215             allocator,
216             source,
217             dimensions,
218             mip_levels,
219             format,
220             command_buffer_builder,
221         )
222     }
223 
224     /// Construct an ImmutableImage containing a copy of the data in `source`.
225     ///
226     /// This is a convenience function, equivalent to calling
227     /// [`uninitialized`](ImmutableImage::uninitialized) with the queue family index of
228     /// `command_buffer_builder`, then recording a `copy_buffer_to_image` command to
229     /// `command_buffer_builder`.
230     ///
231     /// `command_buffer_builder` can then be used to record other commands, built, and executed as
232     /// normal. If it is not executed, the image contents will be left undefined.
from_buffer<L, A>( allocator: &(impl MemoryAllocator + ?Sized), source: Subbuffer<impl ?Sized>, dimensions: ImageDimensions, mip_levels: MipmapsCount, format: Format, command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>, ) -> Result<Arc<Self>, ImmutableImageCreationError> where A: CommandBufferAllocator,233     pub fn from_buffer<L, A>(
234         allocator: &(impl MemoryAllocator + ?Sized),
235         source: Subbuffer<impl ?Sized>,
236         dimensions: ImageDimensions,
237         mip_levels: MipmapsCount,
238         format: Format,
239         command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
240     ) -> Result<Arc<Self>, ImmutableImageCreationError>
241     where
242         A: CommandBufferAllocator,
243     {
244         let region = BufferImageCopy {
245             image_subresource: ImageSubresourceLayers::from_parameters(
246                 format,
247                 dimensions.array_layers(),
248             ),
249             image_extent: dimensions.width_height_depth(),
250             ..Default::default()
251         };
252         let required_size = region.buffer_copy_size(format);
253 
254         if source.size() < required_size {
255             return Err(ImmutableImageCreationError::SourceTooSmall {
256                 source_size: source.size(),
257                 required_size,
258             });
259         }
260 
261         let need_to_generate_mipmaps = has_mipmaps(mip_levels);
262         let usage = ImageUsage::TRANSFER_DST
263             | ImageUsage::SAMPLED
264             | if need_to_generate_mipmaps {
265                 ImageUsage::TRANSFER_SRC
266             } else {
267                 ImageUsage::empty()
268             };
269         let flags = ImageCreateFlags::empty();
270         let layout = ImageLayout::ShaderReadOnlyOptimal;
271 
272         let (image, initializer) = ImmutableImage::uninitialized(
273             allocator,
274             dimensions,
275             format,
276             mip_levels,
277             usage,
278             flags,
279             layout,
280             source
281                 .device()
282                 .active_queue_family_indices()
283                 .iter()
284                 .copied(),
285         )?;
286 
287         command_buffer_builder
288             .copy_buffer_to_image(CopyBufferToImageInfo {
289                 regions: smallvec![region],
290                 ..CopyBufferToImageInfo::buffer_image(source, initializer)
291             })
292             .unwrap();
293 
294         if need_to_generate_mipmaps {
295             generate_mipmaps(
296                 command_buffer_builder,
297                 image.clone(),
298                 image.inner.dimensions(),
299                 ImageLayout::ShaderReadOnlyOptimal,
300             );
301         }
302 
303         Ok(image)
304     }
305 }
306 
307 unsafe impl DeviceOwned for ImmutableImage {
308     #[inline]
device(&self) -> &Arc<Device>309     fn device(&self) -> &Arc<Device> {
310         self.inner.device()
311     }
312 }
313 
314 unsafe impl ImageAccess for ImmutableImage {
315     #[inline]
inner(&self) -> ImageInner<'_>316     fn inner(&self) -> ImageInner<'_> {
317         ImageInner {
318             image: &self.inner,
319             first_layer: 0,
320             num_layers: self.inner.dimensions().array_layers(),
321             first_mipmap_level: 0,
322             num_mipmap_levels: self.inner.mip_levels(),
323         }
324     }
325 
326     #[inline]
is_layout_initialized(&self) -> bool327     fn is_layout_initialized(&self) -> bool {
328         true
329     }
330 
331     #[inline]
initial_layout_requirement(&self) -> ImageLayout332     fn initial_layout_requirement(&self) -> ImageLayout {
333         self.layout
334     }
335 
336     #[inline]
final_layout_requirement(&self) -> ImageLayout337     fn final_layout_requirement(&self) -> ImageLayout {
338         self.layout
339     }
340 
341     #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>342     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
343         Some(ImageDescriptorLayouts {
344             storage_image: ImageLayout::General,
345             combined_image_sampler: self.layout,
346             sampled_image: self.layout,
347             input_attachment: self.layout,
348         })
349     }
350 }
351 
352 unsafe impl<P> ImageContent<P> for ImmutableImage {
matches_format(&self) -> bool353     fn matches_format(&self) -> bool {
354         true // FIXME:
355     }
356 }
357 
358 impl PartialEq for ImmutableImage {
359     #[inline]
eq(&self, other: &Self) -> bool360     fn eq(&self, other: &Self) -> bool {
361         self.inner() == other.inner()
362     }
363 }
364 
365 impl Eq for ImmutableImage {}
366 
367 impl Hash for ImmutableImage {
hash<H: Hasher>(&self, state: &mut H)368     fn hash<H: Hasher>(&self, state: &mut H) {
369         self.inner().hash(state);
370     }
371 }
372 
373 // Must not implement Clone, as that would lead to multiple `used` values.
374 pub struct ImmutableImageInitialization {
375     image: Arc<ImmutableImage>,
376 }
377 
378 unsafe impl DeviceOwned for ImmutableImageInitialization {
379     #[inline]
device(&self) -> &Arc<Device>380     fn device(&self) -> &Arc<Device> {
381         self.image.device()
382     }
383 }
384 
385 unsafe impl ImageAccess for ImmutableImageInitialization {
386     #[inline]
inner(&self) -> ImageInner<'_>387     fn inner(&self) -> ImageInner<'_> {
388         self.image.inner()
389     }
390 
391     #[inline]
initial_layout_requirement(&self) -> ImageLayout392     fn initial_layout_requirement(&self) -> ImageLayout {
393         ImageLayout::Undefined
394     }
395 
396     #[inline]
final_layout_requirement(&self) -> ImageLayout397     fn final_layout_requirement(&self) -> ImageLayout {
398         self.image.layout
399     }
400 
401     #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>402     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
403         None
404     }
405 }
406 
407 impl PartialEq for ImmutableImageInitialization {
408     #[inline]
eq(&self, other: &Self) -> bool409     fn eq(&self, other: &Self) -> bool {
410         self.inner() == other.inner()
411     }
412 }
413 
414 impl Eq for ImmutableImageInitialization {}
415 
416 impl Hash for ImmutableImageInitialization {
hash<H: Hasher>(&self, state: &mut H)417     fn hash<H: Hasher>(&self, state: &mut H) {
418         self.inner().hash(state);
419     }
420 }
421 
422 /// Error that can happen when creating an `ImmutableImage`.
423 #[derive(Clone, Debug)]
424 pub enum ImmutableImageCreationError {
425     ImageCreationError(ImageError),
426     AllocError(AllocationCreationError),
427     CommandBufferBeginError(CommandBufferBeginError),
428 
429     /// The size of the provided source data is less than the required size for an image with the
430     /// given format and dimensions.
431     SourceTooSmall {
432         source_size: DeviceSize,
433         required_size: DeviceSize,
434     },
435 }
436 
437 impl Error for ImmutableImageCreationError {
source(&self) -> Option<&(dyn Error + 'static)>438     fn source(&self) -> Option<&(dyn Error + 'static)> {
439         match self {
440             Self::ImageCreationError(err) => Some(err),
441             Self::AllocError(err) => Some(err),
442             Self::CommandBufferBeginError(err) => Some(err),
443             _ => None,
444         }
445     }
446 }
447 
448 impl Display for ImmutableImageCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>449     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
450         match self {
451             Self::ImageCreationError(err) => err.fmt(f),
452             Self::AllocError(err) => err.fmt(f),
453             Self::CommandBufferBeginError(err) => err.fmt(f),
454             Self::SourceTooSmall {
455                 source_size,
456                 required_size,
457             } => write!(
458                 f,
459                 "the size of the provided source data ({} bytes) is less than the required size \
460                 for an image of the given format and dimensions ({} bytes)",
461                 source_size, required_size,
462             ),
463         }
464     }
465 }
466 
467 impl From<ImageError> for ImmutableImageCreationError {
from(err: ImageError) -> Self468     fn from(err: ImageError) -> Self {
469         Self::ImageCreationError(err)
470     }
471 }
472 
473 impl From<AllocationCreationError> for ImmutableImageCreationError {
from(err: AllocationCreationError) -> Self474     fn from(err: AllocationCreationError) -> Self {
475         Self::AllocError(err)
476     }
477 }
478 
479 impl From<VulkanError> for ImmutableImageCreationError {
from(err: VulkanError) -> Self480     fn from(err: VulkanError) -> Self {
481         Self::AllocError(err.into())
482     }
483 }
484 
485 impl From<CommandBufferBeginError> for ImmutableImageCreationError {
from(err: CommandBufferBeginError) -> Self486     fn from(err: CommandBufferBeginError) -> Self {
487         Self::CommandBufferBeginError(err)
488     }
489 }
490