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::Device; 11 use crate::format::ClearValue; 12 use crate::format::Format; 13 use crate::format::FormatTy; 14 use crate::image::sys::ImageCreationError; 15 use crate::image::sys::UnsafeImage; 16 use crate::image::traits::ImageAccess; 17 use crate::image::traits::ImageClearValue; 18 use crate::image::traits::ImageContent; 19 use crate::image::ImageCreateFlags; 20 use crate::image::ImageDescriptorLayouts; 21 use crate::image::ImageDimensions; 22 use crate::image::ImageInner; 23 use crate::image::ImageLayout; 24 use crate::image::ImageUsage; 25 use crate::image::SampleCount; 26 use crate::memory::pool::AllocFromRequirementsFilter; 27 use crate::memory::pool::AllocLayout; 28 use crate::memory::pool::MappingRequirement; 29 use crate::memory::pool::MemoryPool; 30 use crate::memory::pool::MemoryPoolAlloc; 31 use crate::memory::pool::PotentialDedicatedAllocation; 32 use crate::memory::pool::StdMemoryPoolAlloc; 33 use crate::memory::DedicatedAlloc; 34 use crate::sync::AccessError; 35 use crate::sync::Sharing; 36 use std::hash::Hash; 37 use std::hash::Hasher; 38 use std::iter::Empty; 39 use std::sync::atomic::AtomicBool; 40 use std::sync::atomic::AtomicUsize; 41 use std::sync::atomic::Ordering; 42 use std::sync::Arc; 43 44 /// ImageAccess whose purpose is to be used as a framebuffer attachment. 45 /// 46 /// The image is always two-dimensional and has only one mipmap, but it can have any kind of 47 /// format. Trying to use a format that the backend doesn't support for rendering will result in 48 /// an error being returned when creating the image. Once you have an `AttachmentImage`, you are 49 /// guaranteed that you will be able to draw on it. 50 /// 51 /// The template parameter of `AttachmentImage` is a type that describes the format of the image. 52 /// 53 /// # Regular vs transient 54 /// 55 /// Calling `AttachmentImage::new` will create a regular image, while calling 56 /// `AttachmentImage::transient` will create a *transient* image. Transient image are only 57 /// relevant for images that serve as attachments, so `AttachmentImage` is the only type of 58 /// image in vulkano that provides a shortcut for this. 59 /// 60 /// A transient image is a special kind of image whose content is undefined outside of render 61 /// passes. Once you finish drawing, reading from it will returned undefined data (which can be 62 /// either valid or garbage, depending on the implementation). 63 /// 64 /// This gives a hint to the Vulkan implementation that it is possible for the image's content to 65 /// live exclusively in some cache memory, and that no real memory has to be allocated for it. 66 /// 67 /// In other words, if you are going to read from the image after drawing to it, use a regular 68 /// image. If you don't need to read from it (for example if it's some kind of intermediary color, 69 /// or a depth buffer that is only used once) then use a transient image as it may improve 70 /// performance. 71 /// 72 // TODO: forbid reading transient images outside render passes? 73 #[derive(Debug)] 74 pub struct AttachmentImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> { 75 // Inner implementation. 76 image: UnsafeImage, 77 78 // Memory used to back the image. 79 memory: A, 80 81 // Format. 82 format: Format, 83 84 // Layout to use when the image is used as a framebuffer attachment. 85 // Must be either "depth-stencil optimal" or "color optimal". 86 attachment_layout: ImageLayout, 87 88 // If true, then the image is in the layout of `attachment_layout` (above). If false, then it 89 // is still `Undefined`. 90 initialized: AtomicBool, 91 92 // Number of times this image is locked on the GPU side. 93 gpu_lock: AtomicUsize, 94 } 95 96 impl AttachmentImage { 97 /// Creates a new image with the given dimensions and format. 98 /// 99 /// Returns an error if the dimensions are too large or if the backend doesn't support this 100 /// format as a framebuffer attachment. 101 #[inline] new( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>102 pub fn new( 103 device: Arc<Device>, 104 dimensions: [u32; 2], 105 format: Format, 106 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 107 AttachmentImage::new_impl( 108 device, 109 dimensions, 110 1, 111 format, 112 ImageUsage::none(), 113 SampleCount::Sample1, 114 ) 115 } 116 117 /// Same as `new`, but creates an image that can be used as an input attachment. 118 /// 119 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 120 #[inline] input_attachment( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>121 pub fn input_attachment( 122 device: Arc<Device>, 123 dimensions: [u32; 2], 124 format: Format, 125 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 126 let base_usage = ImageUsage { 127 input_attachment: true, 128 ..ImageUsage::none() 129 }; 130 131 AttachmentImage::new_impl( 132 device, 133 dimensions, 134 1, 135 format, 136 base_usage, 137 SampleCount::Sample1, 138 ) 139 } 140 141 /// Same as `new`, but creates a multisampled image. 142 /// 143 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 144 /// > want a regular image. 145 #[inline] multisampled( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>146 pub fn multisampled( 147 device: Arc<Device>, 148 dimensions: [u32; 2], 149 samples: SampleCount, 150 format: Format, 151 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 152 AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::none(), samples) 153 } 154 155 /// Same as `multisampled`, but creates an image that can be used as an input attachment. 156 /// 157 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 158 #[inline] multisampled_input_attachment( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>159 pub fn multisampled_input_attachment( 160 device: Arc<Device>, 161 dimensions: [u32; 2], 162 samples: SampleCount, 163 format: Format, 164 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 165 let base_usage = ImageUsage { 166 input_attachment: true, 167 ..ImageUsage::none() 168 }; 169 170 AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) 171 } 172 173 /// Same as `new`, but lets you specify additional usages. 174 /// 175 /// The `color_attachment` or `depth_stencil_attachment` usages are automatically added based 176 /// on the format of the usage. Therefore the `usage` parameter allows you specify usages in 177 /// addition to these two. 178 #[inline] with_usage( device: Arc<Device>, dimensions: [u32; 2], format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageCreationError>179 pub fn with_usage( 180 device: Arc<Device>, 181 dimensions: [u32; 2], 182 format: Format, 183 usage: ImageUsage, 184 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 185 AttachmentImage::new_impl(device, dimensions, 1, format, usage, SampleCount::Sample1) 186 } 187 188 /// Same as `with_usage`, but creates a multisampled image. 189 /// 190 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 191 /// > want a regular image. 192 #[inline] multisampled_with_usage( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageCreationError>193 pub fn multisampled_with_usage( 194 device: Arc<Device>, 195 dimensions: [u32; 2], 196 samples: SampleCount, 197 format: Format, 198 usage: ImageUsage, 199 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 200 AttachmentImage::new_impl(device, dimensions, 1, format, usage, samples) 201 } 202 203 /// Same as `multisampled_with_usage`, but creates an image with multiple layers. 204 /// 205 /// > **Note**: You can also use this function and pass `1` for the number of layers if you 206 /// > want a regular image. 207 #[inline] multisampled_with_usage_with_layers( device: Arc<Device>, dimensions: [u32; 2], array_layers: u32, samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageCreationError>208 pub fn multisampled_with_usage_with_layers( 209 device: Arc<Device>, 210 dimensions: [u32; 2], 211 array_layers: u32, 212 samples: SampleCount, 213 format: Format, 214 usage: ImageUsage, 215 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 216 AttachmentImage::new_impl(device, dimensions, array_layers, format, usage, samples) 217 } 218 219 /// Same as `new`, except that the image can later be sampled. 220 /// 221 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 222 #[inline] sampled( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>223 pub fn sampled( 224 device: Arc<Device>, 225 dimensions: [u32; 2], 226 format: Format, 227 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 228 let base_usage = ImageUsage { 229 sampled: true, 230 ..ImageUsage::none() 231 }; 232 233 AttachmentImage::new_impl( 234 device, 235 dimensions, 236 1, 237 format, 238 base_usage, 239 SampleCount::Sample1, 240 ) 241 } 242 243 /// Same as `sampled`, except that the image can be used as an input attachment. 244 /// 245 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 246 #[inline] sampled_input_attachment( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>247 pub fn sampled_input_attachment( 248 device: Arc<Device>, 249 dimensions: [u32; 2], 250 format: Format, 251 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 252 let base_usage = ImageUsage { 253 sampled: true, 254 input_attachment: true, 255 ..ImageUsage::none() 256 }; 257 258 AttachmentImage::new_impl( 259 device, 260 dimensions, 261 1, 262 format, 263 base_usage, 264 SampleCount::Sample1, 265 ) 266 } 267 268 /// Same as `sampled`, but creates a multisampled image. 269 /// 270 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 271 /// > want a regular image. 272 /// 273 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 274 #[inline] sampled_multisampled( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>275 pub fn sampled_multisampled( 276 device: Arc<Device>, 277 dimensions: [u32; 2], 278 samples: SampleCount, 279 format: Format, 280 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 281 let base_usage = ImageUsage { 282 sampled: true, 283 ..ImageUsage::none() 284 }; 285 286 AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) 287 } 288 289 /// Same as `sampled_multisampled`, but creates an image that can be used as an input 290 /// attachment. 291 /// 292 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 293 #[inline] sampled_multisampled_input_attachment( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>294 pub fn sampled_multisampled_input_attachment( 295 device: Arc<Device>, 296 dimensions: [u32; 2], 297 samples: SampleCount, 298 format: Format, 299 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 300 let base_usage = ImageUsage { 301 sampled: true, 302 input_attachment: true, 303 ..ImageUsage::none() 304 }; 305 306 AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) 307 } 308 309 /// Same as `new`, except that the image will be transient. 310 /// 311 /// A transient image is special because its content is undefined outside of a render pass. 312 /// This means that the implementation has the possibility to not allocate any memory for it. 313 /// 314 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 315 #[inline] transient( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>316 pub fn transient( 317 device: Arc<Device>, 318 dimensions: [u32; 2], 319 format: Format, 320 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 321 let base_usage = ImageUsage { 322 transient_attachment: true, 323 ..ImageUsage::none() 324 }; 325 326 AttachmentImage::new_impl( 327 device, 328 dimensions, 329 1, 330 format, 331 base_usage, 332 SampleCount::Sample1, 333 ) 334 } 335 336 /// Same as `transient`, except that the image can be used as an input attachment. 337 /// 338 /// > **Note**: This function is just a convenient shortcut for `with_usage`. 339 #[inline] transient_input_attachment( device: Arc<Device>, dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>340 pub fn transient_input_attachment( 341 device: Arc<Device>, 342 dimensions: [u32; 2], 343 format: Format, 344 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 345 let base_usage = ImageUsage { 346 transient_attachment: true, 347 input_attachment: true, 348 ..ImageUsage::none() 349 }; 350 351 AttachmentImage::new_impl( 352 device, 353 dimensions, 354 1, 355 format, 356 base_usage, 357 SampleCount::Sample1, 358 ) 359 } 360 361 /// Same as `transient`, but creates a multisampled image. 362 /// 363 /// > **Note**: You can also use this function and pass `1` for the number of samples if you 364 /// > want a regular image. 365 /// 366 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 367 #[inline] transient_multisampled( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>368 pub fn transient_multisampled( 369 device: Arc<Device>, 370 dimensions: [u32; 2], 371 samples: SampleCount, 372 format: Format, 373 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 374 let base_usage = ImageUsage { 375 transient_attachment: true, 376 ..ImageUsage::none() 377 }; 378 379 AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) 380 } 381 382 /// Same as `transient_multisampled`, but creates an image that can be used as an input 383 /// attachment. 384 /// 385 /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`. 386 #[inline] transient_multisampled_input_attachment( device: Arc<Device>, dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageCreationError>387 pub fn transient_multisampled_input_attachment( 388 device: Arc<Device>, 389 dimensions: [u32; 2], 390 samples: SampleCount, 391 format: Format, 392 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 393 let base_usage = ImageUsage { 394 transient_attachment: true, 395 input_attachment: true, 396 ..ImageUsage::none() 397 }; 398 399 AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples) 400 } 401 402 // All constructors dispatch to this one. new_impl( device: Arc<Device>, dimensions: [u32; 2], array_layers: u32, format: Format, base_usage: ImageUsage, samples: SampleCount, ) -> Result<Arc<AttachmentImage>, ImageCreationError>403 fn new_impl( 404 device: Arc<Device>, 405 dimensions: [u32; 2], 406 array_layers: u32, 407 format: Format, 408 base_usage: ImageUsage, 409 samples: SampleCount, 410 ) -> Result<Arc<AttachmentImage>, ImageCreationError> { 411 // TODO: check dimensions against the max_framebuffer_width/height/layers limits 412 413 let is_depth = match format.ty() { 414 FormatTy::Depth => true, 415 FormatTy::DepthStencil => true, 416 FormatTy::Stencil => true, 417 FormatTy::Compressed => panic!(), 418 _ => false, 419 }; 420 421 let usage = ImageUsage { 422 color_attachment: !is_depth, 423 depth_stencil_attachment: is_depth, 424 ..base_usage 425 }; 426 427 let (image, mem_reqs) = unsafe { 428 let dims = ImageDimensions::Dim2d { 429 width: dimensions[0], 430 height: dimensions[1], 431 array_layers, 432 }; 433 434 UnsafeImage::new( 435 device.clone(), 436 usage, 437 format, 438 ImageCreateFlags::none(), 439 dims, 440 samples, 441 1, 442 Sharing::Exclusive::<Empty<u32>>, 443 false, 444 false, 445 )? 446 }; 447 448 let memory = MemoryPool::alloc_from_requirements( 449 &Device::standard_pool(&device), 450 &mem_reqs, 451 AllocLayout::Optimal, 452 MappingRequirement::DoNotMap, 453 DedicatedAlloc::Image(&image), 454 |t| { 455 if t.is_device_local() { 456 AllocFromRequirementsFilter::Preferred 457 } else { 458 AllocFromRequirementsFilter::Allowed 459 } 460 }, 461 )?; 462 debug_assert!((memory.offset() % mem_reqs.alignment) == 0); 463 unsafe { 464 image.bind_memory(memory.memory(), memory.offset())?; 465 } 466 467 Ok(Arc::new(AttachmentImage { 468 image, 469 memory, 470 format, 471 attachment_layout: if is_depth { 472 ImageLayout::DepthStencilAttachmentOptimal 473 } else { 474 ImageLayout::ColorAttachmentOptimal 475 }, 476 initialized: AtomicBool::new(false), 477 gpu_lock: AtomicUsize::new(0), 478 })) 479 } 480 } 481 482 impl<A> AttachmentImage<A> { 483 /// Returns the dimensions of the image. 484 #[inline] dimensions(&self) -> [u32; 2]485 pub fn dimensions(&self) -> [u32; 2] { 486 let dims = self.image.dimensions(); 487 [dims.width(), dims.height()] 488 } 489 } 490 491 unsafe impl<A> ImageAccess for AttachmentImage<A> { 492 #[inline] inner(&self) -> ImageInner493 fn inner(&self) -> ImageInner { 494 ImageInner { 495 image: &self.image, 496 first_layer: 0, 497 num_layers: self.image.dimensions().array_layers() as usize, 498 first_mipmap_level: 0, 499 num_mipmap_levels: 1, 500 } 501 } 502 503 #[inline] initial_layout_requirement(&self) -> ImageLayout504 fn initial_layout_requirement(&self) -> ImageLayout { 505 self.attachment_layout 506 } 507 508 #[inline] final_layout_requirement(&self) -> ImageLayout509 fn final_layout_requirement(&self) -> ImageLayout { 510 self.attachment_layout 511 } 512 513 #[inline] descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>514 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { 515 Some(ImageDescriptorLayouts { 516 storage_image: ImageLayout::ShaderReadOnlyOptimal, 517 combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal, 518 sampled_image: ImageLayout::ShaderReadOnlyOptimal, 519 input_attachment: ImageLayout::ShaderReadOnlyOptimal, 520 }) 521 } 522 523 #[inline] conflict_key(&self) -> u64524 fn conflict_key(&self) -> u64 { 525 self.image.key() 526 } 527 528 #[inline] try_gpu_lock( &self, _: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>529 fn try_gpu_lock( 530 &self, 531 _: bool, 532 uninitialized_safe: bool, 533 expected_layout: ImageLayout, 534 ) -> Result<(), AccessError> { 535 if expected_layout != self.attachment_layout && expected_layout != ImageLayout::Undefined { 536 if self.initialized.load(Ordering::SeqCst) { 537 return Err(AccessError::UnexpectedImageLayout { 538 requested: expected_layout, 539 allowed: self.attachment_layout, 540 }); 541 } else { 542 return Err(AccessError::UnexpectedImageLayout { 543 requested: expected_layout, 544 allowed: ImageLayout::Undefined, 545 }); 546 } 547 } 548 549 if !uninitialized_safe && expected_layout != ImageLayout::Undefined { 550 if !self.initialized.load(Ordering::SeqCst) { 551 return Err(AccessError::ImageNotInitialized { 552 requested: expected_layout, 553 }); 554 } 555 } 556 557 if self 558 .gpu_lock 559 .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) 560 .unwrap_or_else(|e| e) 561 == 0 562 { 563 Ok(()) 564 } else { 565 Err(AccessError::AlreadyInUse) 566 } 567 } 568 569 #[inline] increase_gpu_lock(&self)570 unsafe fn increase_gpu_lock(&self) { 571 let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst); 572 debug_assert!(val >= 1); 573 } 574 575 #[inline] unlock(&self, new_layout: Option<ImageLayout>)576 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) { 577 if let Some(new_layout) = new_layout { 578 debug_assert_eq!(new_layout, self.attachment_layout); 579 self.initialized.store(true, Ordering::SeqCst); 580 } 581 582 let prev_val = self.gpu_lock.fetch_sub(1, Ordering::SeqCst); 583 debug_assert!(prev_val >= 1); 584 } 585 586 #[inline] layout_initialized(&self)587 unsafe fn layout_initialized(&self) { 588 self.initialized.store(true, Ordering::SeqCst); 589 } 590 591 #[inline] is_layout_initialized(&self) -> bool592 fn is_layout_initialized(&self) -> bool { 593 self.initialized.load(Ordering::SeqCst) 594 } 595 596 #[inline] current_miplevels_access(&self) -> std::ops::Range<u32>597 fn current_miplevels_access(&self) -> std::ops::Range<u32> { 598 0..self.mipmap_levels() 599 } 600 601 #[inline] current_layer_levels_access(&self) -> std::ops::Range<u32>602 fn current_layer_levels_access(&self) -> std::ops::Range<u32> { 603 0..1 604 } 605 } 606 607 unsafe impl<A> ImageClearValue<ClearValue> for Arc<AttachmentImage<A>> { 608 #[inline] decode(&self, value: ClearValue) -> Option<ClearValue>609 fn decode(&self, value: ClearValue) -> Option<ClearValue> { 610 Some(self.format.decode_clear_value(value)) 611 } 612 } 613 614 unsafe impl<P, A> ImageContent<P> for Arc<AttachmentImage<A>> { 615 #[inline] matches_format(&self) -> bool616 fn matches_format(&self) -> bool { 617 true // FIXME: 618 } 619 } 620 621 impl<A> PartialEq for AttachmentImage<A> { 622 #[inline] eq(&self, other: &Self) -> bool623 fn eq(&self, other: &Self) -> bool { 624 ImageAccess::inner(self) == ImageAccess::inner(other) 625 } 626 } 627 628 impl<A> Eq for AttachmentImage<A> {} 629 630 impl<A> Hash for AttachmentImage<A> { 631 #[inline] hash<H: Hasher>(&self, state: &mut H)632 fn hash<H: Hasher>(&self, state: &mut H) { 633 ImageAccess::inner(self).hash(state); 634 } 635 } 636 637 #[cfg(test)] 638 mod tests { 639 use super::AttachmentImage; 640 use crate::format::Format; 641 642 #[test] create_regular()643 fn create_regular() { 644 let (device, _) = gfx_dev_and_queue!(); 645 let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap(); 646 } 647 648 #[test] create_transient()649 fn create_transient() { 650 let (device, _) = gfx_dev_and_queue!(); 651 let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap(); 652 } 653 654 #[test] d16_unorm_always_supported()655 fn d16_unorm_always_supported() { 656 let (device, _) = gfx_dev_and_queue!(); 657 let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap(); 658 } 659 } 660