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