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, ImageMemory, RawImage}, 12 traits::ImageContent, 13 ImageAccess, ImageAspects, ImageDescriptorLayouts, ImageError, ImageInner, ImageLayout, 14 ImageUsage, SampleCount, 15 }; 16 use crate::{ 17 device::{Device, DeviceOwned}, 18 format::Format, 19 image::{sys::ImageCreateInfo, ImageCreateFlags, ImageDimensions, ImageFormatInfo}, 20 memory::{ 21 allocator::{ 22 AllocationCreateInfo, AllocationType, MemoryAllocatePreference, MemoryAllocator, 23 MemoryUsage, 24 }, 25 is_aligned, DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType, 26 ExternalMemoryHandleTypes, 27 }, 28 DeviceSize, 29 }; 30 use std::{ 31 fs::File, 32 hash::{Hash, Hasher}, 33 sync::{ 34 atomic::{AtomicBool, Ordering}, 35 Arc, 36 }, 37 }; 38 39 /// ImageAccess whose purpose is to be used as a framebuffer attachment. 40 /// 41 /// The image is always two-dimensional and has only one mipmap, but it can have any kind of 42 /// format. Trying to use a format that the backend doesn't support for rendering will result in 43 /// an error being returned when creating the image. Once you have an `AttachmentImage`, you are 44 /// guaranteed that you will be able to draw on it. 45 /// 46 /// The template parameter of `AttachmentImage` is a type that describes the format of the image. 47 /// 48 /// # Regular vs transient 49 /// 50 /// Calling `AttachmentImage::new` will create a regular image, while calling 51 /// `AttachmentImage::transient` will create a *transient* image. Transient image are only 52 /// relevant for images that serve as attachments, so `AttachmentImage` is the only type of 53 /// image in vulkano that provides a shortcut for this. 54 /// 55 /// A transient image is a special kind of image whose content is undefined outside of render 56 /// passes. Once you finish drawing, reading from it will returned undefined data (which can be 57 /// either valid or garbage, depending on the implementation). 58 /// 59 /// This gives a hint to the Vulkan implementation that it is possible for the image's content to 60 /// live exclusively in some cache memory, and that no real memory has to be allocated for it. 61 /// 62 /// In other words, if you are going to read from the image after drawing to it, use a regular 63 /// image. If you don't need to read from it (for example if it's some kind of intermediary color, 64 /// or a depth buffer that is only used once) then use a transient image as it may improve 65 /// performance. 66 /// 67 // TODO: forbid reading transient images outside render passes? 68 #[derive(Debug)] 69 pub struct AttachmentImage { 70 inner: Arc<Image>, 71 72 // Layout to use when the image is used as a framebuffer attachment. 73 // Must be either "depth-stencil optimal" or "color optimal". 74 attachment_layout: ImageLayout, 75 76 // If true, then the image is in the layout of `attachment_layout` (above). If false, then it 77 // is still `Undefined`. 78 layout_initialized: AtomicBool, 79 } 80 81 impl AttachmentImage { 82 /// Creates a new image with the given dimensions and format. 83 /// 84 /// Returns an error if the dimensions are too large or if the backend doesn't support this 85 /// format as a framebuffer attachment. 86 #[inline] new( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>87 pub fn new( 88 allocator: &(impl MemoryAllocator + ?Sized), 89 dimensions: [u32; 2], 90 format: Format, 91 ) -> Result<Arc<AttachmentImage>, ImageError> { 92 AttachmentImage::new_impl( 93 allocator, 94 dimensions, 95 1, 96 format, 97 ImageUsage::empty(), 98 SampleCount::Sample1, 99 ) 100 } 101 102 /// Same as `new`, but creates an image that can be used as an input attachment. 103 /// 104 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 105 #[inline] input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>106 pub fn input_attachment( 107 allocator: &(impl MemoryAllocator + ?Sized), 108 dimensions: [u32; 2], 109 format: Format, 110 ) -> Result<Arc<AttachmentImage>, ImageError> { 111 let base_usage = ImageUsage::INPUT_ATTACHMENT; 112 113 AttachmentImage::new_impl( 114 allocator, 115 dimensions, 116 1, 117 format, 118 base_usage, 119 SampleCount::Sample1, 120 ) 121 } 122 123 /// Same as `new`, but creates a multisampled image. 124 /// 125 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 126 /// > want a regular image. 127 #[inline] multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>128 pub fn multisampled( 129 allocator: &(impl MemoryAllocator + ?Sized), 130 dimensions: [u32; 2], 131 samples: SampleCount, 132 format: Format, 133 ) -> Result<Arc<AttachmentImage>, ImageError> { 134 AttachmentImage::new_impl( 135 allocator, 136 dimensions, 137 1, 138 format, 139 ImageUsage::empty(), 140 samples, 141 ) 142 } 143 144 /// Same as `multisampled`, but creates an image that can be used as an input attachment. 145 /// 146 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 147 #[inline] multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>148 pub fn multisampled_input_attachment( 149 allocator: &(impl MemoryAllocator + ?Sized), 150 dimensions: [u32; 2], 151 samples: SampleCount, 152 format: Format, 153 ) -> Result<Arc<AttachmentImage>, ImageError> { 154 let base_usage = ImageUsage::INPUT_ATTACHMENT; 155 156 AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples) 157 } 158 159 /// Same as `new`, but lets you specify additional usages. 160 /// 161 /// The `color_attachment` or `depth_stencil_attachment` usages are automatically added based 162 /// on the format of the usage. Therefore the `usage` parameter allows you specify usages in 163 /// addition to these two. 164 #[inline] with_usage( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>165 pub fn with_usage( 166 allocator: &(impl MemoryAllocator + ?Sized), 167 dimensions: [u32; 2], 168 format: Format, 169 usage: ImageUsage, 170 ) -> Result<Arc<AttachmentImage>, ImageError> { 171 AttachmentImage::new_impl( 172 allocator, 173 dimensions, 174 1, 175 format, 176 usage, 177 SampleCount::Sample1, 178 ) 179 } 180 181 /// Same as `with_usage`, but creates a multisampled image. 182 /// 183 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 184 /// > want a regular image. 185 #[inline] multisampled_with_usage( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>186 pub fn multisampled_with_usage( 187 allocator: &(impl MemoryAllocator + ?Sized), 188 dimensions: [u32; 2], 189 samples: SampleCount, 190 format: Format, 191 usage: ImageUsage, 192 ) -> Result<Arc<AttachmentImage>, ImageError> { 193 AttachmentImage::new_impl(allocator, dimensions, 1, format, usage, samples) 194 } 195 196 /// Same as `multisampled_with_usage`, but creates an image with multiple layers. 197 /// 198 /// > **Note**: You can also use this function and pass `1` for the number of layers if you 199 /// > want a regular image. 200 #[inline] multisampled_with_usage_with_layers( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>201 pub fn multisampled_with_usage_with_layers( 202 allocator: &(impl MemoryAllocator + ?Sized), 203 dimensions: [u32; 2], 204 array_layers: u32, 205 samples: SampleCount, 206 format: Format, 207 usage: ImageUsage, 208 ) -> Result<Arc<AttachmentImage>, ImageError> { 209 AttachmentImage::new_impl(allocator, dimensions, array_layers, format, usage, samples) 210 } 211 212 /// Same as `new`, except that the image can later be sampled. 213 /// 214 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 215 #[inline] sampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>216 pub fn sampled( 217 allocator: &(impl MemoryAllocator + ?Sized), 218 dimensions: [u32; 2], 219 format: Format, 220 ) -> Result<Arc<AttachmentImage>, ImageError> { 221 let base_usage = ImageUsage::SAMPLED; 222 223 AttachmentImage::new_impl( 224 allocator, 225 dimensions, 226 1, 227 format, 228 base_usage, 229 SampleCount::Sample1, 230 ) 231 } 232 233 /// Same as `sampled`, except that the image can be used as an input attachment. 234 /// 235 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 236 #[inline] sampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>237 pub fn sampled_input_attachment( 238 allocator: &(impl MemoryAllocator + ?Sized), 239 dimensions: [u32; 2], 240 format: Format, 241 ) -> Result<Arc<AttachmentImage>, ImageError> { 242 let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT; 243 244 AttachmentImage::new_impl( 245 allocator, 246 dimensions, 247 1, 248 format, 249 base_usage, 250 SampleCount::Sample1, 251 ) 252 } 253 254 /// Same as `sampled`, but creates a multisampled image. 255 /// 256 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 257 /// > want a regular image. 258 /// 259 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 260 #[inline] sampled_multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>261 pub fn sampled_multisampled( 262 allocator: &(impl MemoryAllocator + ?Sized), 263 dimensions: [u32; 2], 264 samples: SampleCount, 265 format: Format, 266 ) -> Result<Arc<AttachmentImage>, ImageError> { 267 let base_usage = ImageUsage::SAMPLED; 268 269 AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples) 270 } 271 272 /// Same as `sampled_multisampled`, but creates an image that can be used as an input 273 /// attachment. 274 /// 275 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 276 #[inline] sampled_multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>277 pub fn sampled_multisampled_input_attachment( 278 allocator: &(impl MemoryAllocator + ?Sized), 279 dimensions: [u32; 2], 280 samples: SampleCount, 281 format: Format, 282 ) -> Result<Arc<AttachmentImage>, ImageError> { 283 let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT; 284 285 AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples) 286 } 287 288 /// Same as `new`, except that the image will be transient. 289 /// 290 /// A transient image is special because its content is undefined outside of a render pass. 291 /// This means that the implementation has the possibility to not allocate any memory for it. 292 /// 293 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 294 #[inline] transient( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>295 pub fn transient( 296 allocator: &(impl MemoryAllocator + ?Sized), 297 dimensions: [u32; 2], 298 format: Format, 299 ) -> Result<Arc<AttachmentImage>, ImageError> { 300 let base_usage = ImageUsage::TRANSIENT_ATTACHMENT; 301 302 AttachmentImage::new_impl( 303 allocator, 304 dimensions, 305 1, 306 format, 307 base_usage, 308 SampleCount::Sample1, 309 ) 310 } 311 312 /// Same as `transient`, except that the image can be used as an input attachment. 313 /// 314 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 315 #[inline] transient_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>316 pub fn transient_input_attachment( 317 allocator: &(impl MemoryAllocator + ?Sized), 318 dimensions: [u32; 2], 319 format: Format, 320 ) -> Result<Arc<AttachmentImage>, ImageError> { 321 let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT; 322 323 AttachmentImage::new_impl( 324 allocator, 325 dimensions, 326 1, 327 format, 328 base_usage, 329 SampleCount::Sample1, 330 ) 331 } 332 333 /// Same as `transient`, but creates a multisampled image. 334 /// 335 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 336 /// > want a regular image. 337 /// 338 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 339 #[inline] transient_multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>340 pub fn transient_multisampled( 341 allocator: &(impl MemoryAllocator + ?Sized), 342 dimensions: [u32; 2], 343 samples: SampleCount, 344 format: Format, 345 ) -> Result<Arc<AttachmentImage>, ImageError> { 346 let base_usage = ImageUsage::TRANSIENT_ATTACHMENT; 347 348 AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples) 349 } 350 351 /// Same as `transient_multisampled`, but creates an image that can be used as an input 352 /// attachment. 353 /// 354 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 355 #[inline] transient_multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>356 pub fn transient_multisampled_input_attachment( 357 allocator: &(impl MemoryAllocator + ?Sized), 358 dimensions: [u32; 2], 359 samples: SampleCount, 360 format: Format, 361 ) -> Result<Arc<AttachmentImage>, ImageError> { 362 let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT; 363 364 AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples) 365 } 366 367 // All constructors dispatch to this one. new_impl( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, format: Format, mut usage: ImageUsage, samples: SampleCount, ) -> Result<Arc<AttachmentImage>, ImageError>368 fn new_impl( 369 allocator: &(impl MemoryAllocator + ?Sized), 370 dimensions: [u32; 2], 371 array_layers: u32, 372 format: Format, 373 mut usage: ImageUsage, 374 samples: SampleCount, 375 ) -> Result<Arc<AttachmentImage>, ImageError> { 376 let physical_device = allocator.device().physical_device(); 377 let device_properties = physical_device.properties(); 378 379 if dimensions[0] > device_properties.max_framebuffer_height { 380 panic!("AttachmentImage height exceeds physical device's max_framebuffer_height"); 381 } 382 if dimensions[1] > device_properties.max_framebuffer_width { 383 panic!("AttachmentImage width exceeds physical device's max_framebuffer_width"); 384 } 385 if array_layers > device_properties.max_framebuffer_layers { 386 panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers"); 387 } 388 389 let aspects = format.aspects(); 390 let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL); 391 392 if is_depth_stencil { 393 usage -= ImageUsage::COLOR_ATTACHMENT; 394 usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT; 395 } else { 396 usage |= ImageUsage::COLOR_ATTACHMENT; 397 usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT; 398 } 399 400 if format.compression().is_some() { 401 panic!() // TODO: message? 402 } 403 404 let raw_image = RawImage::new( 405 allocator.device().clone(), 406 ImageCreateInfo { 407 dimensions: ImageDimensions::Dim2d { 408 width: dimensions[0], 409 height: dimensions[1], 410 array_layers, 411 }, 412 format: Some(format), 413 samples, 414 usage, 415 ..Default::default() 416 }, 417 )?; 418 let requirements = raw_image.memory_requirements()[0]; 419 let res = unsafe { 420 allocator.allocate_unchecked( 421 requirements, 422 AllocationType::NonLinear, 423 AllocationCreateInfo { 424 usage: MemoryUsage::DeviceOnly, 425 allocate_preference: MemoryAllocatePreference::Unknown, 426 _ne: crate::NonExhaustive(()), 427 }, 428 Some(DedicatedAllocation::Image(&raw_image)), 429 ) 430 }; 431 432 match res { 433 Ok(alloc) => { 434 debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment())); 435 debug_assert!(alloc.size() == requirements.layout.size()); 436 437 let inner = Arc::new( 438 unsafe { raw_image.bind_memory_unchecked([alloc]) } 439 .map_err(|(err, _, _)| err)?, 440 ); 441 442 Ok(Arc::new(AttachmentImage { 443 inner, 444 attachment_layout: if is_depth_stencil { 445 ImageLayout::DepthStencilAttachmentOptimal 446 } else { 447 ImageLayout::ColorAttachmentOptimal 448 }, 449 layout_initialized: AtomicBool::new(false), 450 })) 451 } 452 Err(err) => Err(err.into()), 453 } 454 } 455 new_with_exportable_fd( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, format: Format, mut usage: ImageUsage, samples: SampleCount, ) -> Result<Arc<AttachmentImage>, ImageError>456 pub fn new_with_exportable_fd( 457 allocator: &(impl MemoryAllocator + ?Sized), 458 dimensions: [u32; 2], 459 array_layers: u32, 460 format: Format, 461 mut usage: ImageUsage, 462 samples: SampleCount, 463 ) -> Result<Arc<AttachmentImage>, ImageError> { 464 let physical_device = allocator.device().physical_device(); 465 let device_properties = physical_device.properties(); 466 467 if dimensions[0] > device_properties.max_framebuffer_height { 468 panic!("AttachmentImage height exceeds physical device's max_framebuffer_height"); 469 } 470 if dimensions[1] > device_properties.max_framebuffer_width { 471 panic!("AttachmentImage width exceeds physical device's max_framebuffer_width"); 472 } 473 if array_layers > device_properties.max_framebuffer_layers { 474 panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers"); 475 } 476 477 let aspects = format.aspects(); 478 let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL); 479 480 if is_depth_stencil { 481 usage -= ImageUsage::COLOR_ATTACHMENT; 482 usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT; 483 } else { 484 usage |= ImageUsage::COLOR_ATTACHMENT; 485 usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT; 486 } 487 488 let external_memory_properties = allocator 489 .device() 490 .physical_device() 491 .image_format_properties(ImageFormatInfo { 492 flags: ImageCreateFlags::MUTABLE_FORMAT, 493 format: Some(format), 494 usage, 495 external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd), 496 ..Default::default() 497 }) 498 .unwrap() 499 .unwrap() 500 .external_memory_properties; 501 // VUID-VkExportMemoryAllocateInfo-handleTypes-00656 502 assert!(external_memory_properties.exportable); 503 504 // VUID-VkMemoryAllocateInfo-pNext-00639 505 // Guaranteed because we always create a dedicated allocation 506 507 let external_memory_handle_types = ExternalMemoryHandleTypes::OPAQUE_FD; 508 let raw_image = RawImage::new( 509 allocator.device().clone(), 510 ImageCreateInfo { 511 flags: ImageCreateFlags::MUTABLE_FORMAT, 512 dimensions: ImageDimensions::Dim2d { 513 width: dimensions[0], 514 height: dimensions[1], 515 array_layers, 516 }, 517 format: Some(format), 518 samples, 519 usage, 520 external_memory_handle_types, 521 ..Default::default() 522 }, 523 )?; 524 let requirements = raw_image.memory_requirements()[0]; 525 let memory_type_index = allocator 526 .find_memory_type_index( 527 requirements.memory_type_bits, 528 MemoryUsage::DeviceOnly.into(), 529 ) 530 .expect("failed to find a suitable memory type"); 531 532 match unsafe { 533 allocator.allocate_dedicated_unchecked( 534 memory_type_index, 535 requirements.layout.size(), 536 Some(DedicatedAllocation::Image(&raw_image)), 537 external_memory_handle_types, 538 ) 539 } { 540 Ok(alloc) => { 541 debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment())); 542 debug_assert!(alloc.size() == requirements.layout.size()); 543 544 let inner = Arc::new(unsafe { 545 raw_image 546 .bind_memory_unchecked([alloc]) 547 .map_err(|(err, _, _)| err)? 548 }); 549 550 Ok(Arc::new(AttachmentImage { 551 inner, 552 attachment_layout: if is_depth_stencil { 553 ImageLayout::DepthStencilAttachmentOptimal 554 } else { 555 ImageLayout::ColorAttachmentOptimal 556 }, 557 layout_initialized: AtomicBool::new(false), 558 })) 559 } 560 Err(err) => Err(err.into()), 561 } 562 } 563 564 /// Exports posix file descriptor for the allocated memory. 565 /// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded. 566 #[inline] export_posix_fd(&self) -> Result<File, DeviceMemoryError>567 pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> { 568 let allocation = match self.inner.memory() { 569 ImageMemory::Normal(a) => &a[0], 570 _ => unreachable!(), 571 }; 572 573 allocation 574 .device_memory() 575 .export_fd(ExternalMemoryHandleType::OpaqueFd) 576 } 577 578 /// Return the size of the allocated memory (used e.g. with cuda). 579 #[inline] mem_size(&self) -> DeviceSize580 pub fn mem_size(&self) -> DeviceSize { 581 let allocation = match self.inner.memory() { 582 ImageMemory::Normal(a) => &a[0], 583 _ => unreachable!(), 584 }; 585 586 allocation.device_memory().allocation_size() 587 } 588 } 589 590 unsafe impl ImageAccess for AttachmentImage { 591 #[inline] inner(&self) -> ImageInner<'_>592 fn inner(&self) -> ImageInner<'_> { 593 ImageInner { 594 image: &self.inner, 595 first_layer: 0, 596 num_layers: self.inner.dimensions().array_layers(), 597 first_mipmap_level: 0, 598 num_mipmap_levels: 1, 599 } 600 } 601 602 #[inline] initial_layout_requirement(&self) -> ImageLayout603 fn initial_layout_requirement(&self) -> ImageLayout { 604 self.attachment_layout 605 } 606 607 #[inline] final_layout_requirement(&self) -> ImageLayout608 fn final_layout_requirement(&self) -> ImageLayout { 609 self.attachment_layout 610 } 611 612 #[inline] descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>613 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { 614 Some(ImageDescriptorLayouts { 615 storage_image: ImageLayout::General, 616 combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal, 617 sampled_image: ImageLayout::ShaderReadOnlyOptimal, 618 input_attachment: ImageLayout::ShaderReadOnlyOptimal, 619 }) 620 } 621 622 #[inline] layout_initialized(&self)623 unsafe fn layout_initialized(&self) { 624 self.layout_initialized.store(true, Ordering::SeqCst); 625 } 626 627 #[inline] is_layout_initialized(&self) -> bool628 fn is_layout_initialized(&self) -> bool { 629 self.layout_initialized.load(Ordering::SeqCst) 630 } 631 } 632 633 unsafe impl DeviceOwned for AttachmentImage { 634 #[inline] device(&self) -> &Arc<Device>635 fn device(&self) -> &Arc<Device> { 636 self.inner.device() 637 } 638 } 639 640 unsafe impl<P> ImageContent<P> for AttachmentImage { matches_format(&self) -> bool641 fn matches_format(&self) -> bool { 642 true // FIXME: 643 } 644 } 645 646 impl PartialEq for AttachmentImage { 647 #[inline] eq(&self, other: &Self) -> bool648 fn eq(&self, other: &Self) -> bool { 649 self.inner() == other.inner() 650 } 651 } 652 653 impl Eq for AttachmentImage {} 654 655 impl Hash for AttachmentImage { hash<H: Hasher>(&self, state: &mut H)656 fn hash<H: Hasher>(&self, state: &mut H) { 657 self.inner().hash(state); 658 } 659 } 660 661 #[cfg(test)] 662 mod tests { 663 use super::*; 664 use crate::memory::allocator::StandardMemoryAllocator; 665 666 #[test] create_regular()667 fn create_regular() { 668 let (device, _) = gfx_dev_and_queue!(); 669 let memory_allocator = StandardMemoryAllocator::new_default(device); 670 let _img = 671 AttachmentImage::new(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM).unwrap(); 672 } 673 674 #[test] create_transient()675 fn create_transient() { 676 let (device, _) = gfx_dev_and_queue!(); 677 let memory_allocator = StandardMemoryAllocator::new_default(device); 678 let _img = AttachmentImage::transient(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM) 679 .unwrap(); 680 } 681 682 #[test] d16_unorm_always_supported()683 fn d16_unorm_always_supported() { 684 let (device, _) = gfx_dev_and_queue!(); 685 let memory_allocator = StandardMemoryAllocator::new_default(device); 686 let _img = AttachmentImage::new(&memory_allocator, [32, 32], Format::D16_UNORM).unwrap(); 687 } 688 } 689