From 13c89da412941225451225af657dc2e918d60e2b Mon Sep 17 00:00:00 2001
From: Rua <ruawhitepaw@gmail.com>
Date: Sat, 16 Apr 2022 15:25:06 +0200
Subject: [PATCH] Use only the selected range of buffer and image views in
 synchronization

---
 vulkano/src/buffer/view.rs                    |  51 ++--
 vulkano/src/command_buffer/auto.rs            |  12 +-
 .../src/command_buffer/commands/pipeline.rs   | 107 ++++----
 .../command_buffer/commands/render_pass.rs    |  14 +-
 .../src/command_buffer/commands/secondary.rs  |  15 +-
 vulkano/src/command_buffer/synced/builder.rs  |  33 ++-
 vulkano/src/command_buffer/synced/mod.rs      |  23 +-
 vulkano/src/command_buffer/traits.rs          |  22 +-
 vulkano/src/descriptor_set/update.rs          |  41 +--
 vulkano/src/image/attachment.rs               |  11 -
 vulkano/src/image/immutable.rs                |  20 --
 vulkano/src/image/storage.rs                  |  11 -
 vulkano/src/image/swapchain.rs                |  13 +-
 vulkano/src/image/traits.rs                   |  98 ++++---
 vulkano/src/image/view.rs                     | 249 ++++++------------
 vulkano/src/render_pass/framebuffer.rs        |  11 +-
 vulkano/src/sampler/mod.rs                    |   9 +-
 17 files changed, 364 insertions(+), 376 deletions(-)

diff --git a/vulkano/src/buffer/view.rs b/vulkano/src/buffer/view.rs
index 121fdf90ba..0a0c4c56f5 100644
--- a/vulkano/src/buffer/view.rs
+++ b/vulkano/src/buffer/view.rs
@@ -42,22 +42,21 @@
 //! ).unwrap();
 //! ```
 
-use crate::buffer::{BufferAccess, BufferAccessObject, BufferInner};
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::Format;
-use crate::format::FormatFeatures;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use crate::{check_errors, Version};
-use std::error;
-use std::fmt;
-use std::hash::{Hash, Hasher};
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
+use super::{BufferAccess, BufferAccessObject, BufferInner};
+use crate::{
+    check_errors,
+    device::{Device, DeviceOwned},
+    format::{Format, FormatFeatures},
+    DeviceSize, Error, OomError, Version, VulkanObject,
+};
+use std::{
+    error, fmt,
+    hash::{Hash, Hasher},
+    mem::MaybeUninit,
+    ops::Range,
+    ptr,
+    sync::Arc,
+};
 
 /// Represents a way for the GPU to interpret buffer data. See the documentation of the
 /// `view` module.
@@ -71,6 +70,7 @@ where
 
     format: Option<Format>,
     format_features: FormatFeatures,
+    range: Range<DeviceSize>,
 }
 
 impl<B> BufferView<B>
@@ -86,7 +86,7 @@ where
 
         let device = buffer.device();
         let properties = device.physical_device().properties();
-        let range = buffer.size();
+        let size = buffer.size();
         let BufferInner {
             buffer: inner_buffer,
             offset,
@@ -120,15 +120,15 @@ where
         let texels_per_block = format.texels_per_block();
 
         // VUID-VkBufferViewCreateInfo-range-00929
-        if range % block_size != 0 {
+        if size % block_size != 0 {
             return Err(BufferViewCreationError::RangeNotAligned {
-                range,
+                range: size,
                 required_alignment: block_size,
             });
         }
 
         // VUID-VkBufferViewCreateInfo-range-00930
-        if ((range / block_size) * texels_per_block as DeviceSize) as u32
+        if ((size / block_size) * texels_per_block as DeviceSize) as u32
             > properties.max_texel_buffer_elements
         {
             return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded);
@@ -200,7 +200,7 @@ where
             buffer: inner_buffer.internal_object(),
             format: format.into(),
             offset,
-            range,
+            range: size,
             ..Default::default()
         };
 
@@ -222,6 +222,7 @@ where
 
             format: Some(format),
             format_features,
+            range: 0..size,
         }))
     }
 
@@ -411,6 +412,9 @@ pub unsafe trait BufferViewAbstract:
 
     /// Returns the features supported by the buffer view's format.
     fn format_features(&self) -> &FormatFeatures;
+
+    /// Returns the byte range of the wrapped buffer that this view exposes.
+    fn range(&self) -> Range<DeviceSize>;
 }
 
 unsafe impl<B> BufferViewAbstract for BufferView<B>
@@ -432,6 +436,11 @@ where
     fn format_features(&self) -> &FormatFeatures {
         &self.format_features
     }
+
+    #[inline]
+    fn range(&self) -> Range<DeviceSize> {
+        self.range.clone()
+    }
 }
 
 impl PartialEq for dyn BufferViewAbstract {
diff --git a/vulkano/src/command_buffer/auto.rs b/vulkano/src/command_buffer/auto.rs
index 7bf8b681fc..4cebca3b50 100644
--- a/vulkano/src/command_buffer/auto.rs
+++ b/vulkano/src/command_buffer/auto.rs
@@ -35,7 +35,7 @@ use super::{
 use crate::{
     buffer::{sys::UnsafeBuffer, BufferAccess},
     device::{physical::QueueFamily, Device, DeviceOwned, Queue},
-    image::{sys::UnsafeImage, ImageAccess, ImageLayout},
+    image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange},
     pipeline::GraphicsPipeline,
     query::{QueryControlFlags, QueryPipelineStatisticFlags, QueryType},
     render_pass::Subpass,
@@ -684,7 +684,14 @@ where
     }
 
     #[inline]
-    fn buffer(&self, index: usize) -> Option<(&Arc<dyn BufferAccess>, PipelineMemoryAccess)> {
+    fn buffer(
+        &self,
+        index: usize,
+    ) -> Option<(
+        &Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )> {
         self.inner.buffer(index)
     }
 
@@ -699,6 +706,7 @@ where
         index: usize,
     ) -> Option<(
         &Arc<dyn ImageAccess>,
+        &ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
diff --git a/vulkano/src/command_buffer/commands/pipeline.rs b/vulkano/src/command_buffer/commands/pipeline.rs
index 0a043f28c4..8b3a0ac0b5 100644
--- a/vulkano/src/command_buffer/commands/pipeline.rs
+++ b/vulkano/src/command_buffer/commands/pipeline.rs
@@ -39,7 +39,7 @@ use crate::{
     sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
     DeviceSize, VulkanObject,
 };
-use std::{borrow::Cow, error, fmt, mem::size_of, sync::Arc};
+use std::{borrow::Cow, error, fmt, mem::size_of, ops::Range, sync::Arc};
 
 /// # Commands to execute a bound pipeline.
 ///
@@ -482,7 +482,7 @@ fn check_descriptor_sets_validity<'a, P: Pipeline>(
             // - If the signedness of any read or sample operation does not match the signedness of
             //   the image’s format.
             if let Some(scalar_type) = reqs.image_scalar_type {
-                let aspects = image_view.aspects();
+                let aspects = image_view.subresource_range().aspects;
                 let view_scalar_type = ShaderScalarType::from(
                     if aspects.color || aspects.plane0 || aspects.plane1 || aspects.plane2 {
                         image_view.format().unwrap().type_color().unwrap()
@@ -2025,41 +2025,40 @@ impl SyncCommandBufferBuilder {
                 access
             });
 
-            let buffer_resource =
-                move |(memory, buffer): (PipelineMemoryAccess, Arc<dyn BufferAccess>)| {
-                    let range = 0..buffer.size(); // TODO:
-                    (
-                        format!("Buffer bound to set {} descriptor {}", set, binding).into(),
-                        Resource::Buffer {
-                            buffer,
-                            range,
-                            memory,
-                        },
-                    )
-                };
-            let image_resource =
-                move |(memory, image): (PipelineMemoryAccess, Arc<dyn ImageAccess>)| {
-                    let subresource_range = ImageSubresourceRange {
-                        // TODO:
-                        aspects: image.format().aspects(),
-                        mip_levels: image.current_mip_levels_access(),
-                        array_layers: image.current_array_layers_access(),
-                    };
-                    let layout = image
-                        .descriptor_layouts()
-                        .expect("descriptor_layouts must return Some when used in an image view")
-                        .layout_for(descriptor_type);
-                    (
-                        format!("Image bound to set {} descriptor {}", set, binding).into(),
-                        Resource::Image {
-                            image,
-                            subresource_range,
-                            memory,
-                            start_layout: layout,
-                            end_layout: layout,
-                        },
-                    )
-                };
+            let buffer_resource = move |(buffer, range, memory): (
+                Arc<dyn BufferAccess>,
+                Range<DeviceSize>,
+                PipelineMemoryAccess,
+            )| {
+                (
+                    format!("Buffer bound to set {} descriptor {}", set, binding).into(),
+                    Resource::Buffer {
+                        buffer,
+                        range,
+                        memory,
+                    },
+                )
+            };
+            let image_resource = move |(image, subresource_range, memory): (
+                Arc<dyn ImageAccess>,
+                ImageSubresourceRange,
+                PipelineMemoryAccess,
+            )| {
+                let layout = image
+                    .descriptor_layouts()
+                    .expect("descriptor_layouts must return Some when used in an image view")
+                    .layout_for(descriptor_type);
+                (
+                    format!("Image bound to set {} descriptor {}", set, binding).into(),
+                    Resource::Image {
+                        image,
+                        subresource_range,
+                        memory,
+                        start_layout: layout,
+                        end_layout: layout,
+                    },
+                )
+            };
 
             match state.descriptor_sets[&set]
                 .resources()
@@ -2072,7 +2071,13 @@ impl SyncCommandBufferBuilder {
                         access
                             .zip(elements)
                             .filter_map(|(access, element)| {
-                                element.as_ref().map(|buffer| (access, buffer.clone()))
+                                element.as_ref().map(|buffer| {
+                                    (
+                                        buffer.clone(),
+                                        0..buffer.size(), // TODO:
+                                        access,
+                                    )
+                                })
                             })
                             .map(buffer_resource),
                     );
@@ -2082,9 +2087,9 @@ impl SyncCommandBufferBuilder {
                         access
                             .zip(elements)
                             .filter_map(|(access, element)| {
-                                element
-                                    .as_ref()
-                                    .map(|buffer_view| (access, buffer_view.buffer()))
+                                element.as_ref().map(|buffer_view| {
+                                    (buffer_view.buffer(), buffer_view.range(), access)
+                                })
                             })
                             .map(buffer_resource),
                     );
@@ -2094,9 +2099,13 @@ impl SyncCommandBufferBuilder {
                         access
                             .zip(elements)
                             .filter_map(|(access, element)| {
-                                element
-                                    .as_ref()
-                                    .map(|image_view| (access, image_view.image()))
+                                element.as_ref().map(|image_view| {
+                                    (
+                                        image_view.image(),
+                                        image_view.subresource_range().clone(),
+                                        access,
+                                    )
+                                })
                             })
                             .map(image_resource),
                     );
@@ -2106,9 +2115,13 @@ impl SyncCommandBufferBuilder {
                         access
                             .zip(elements)
                             .filter_map(|(access, element)| {
-                                element
-                                    .as_ref()
-                                    .map(|(image_view, _)| (access, image_view.image()))
+                                element.as_ref().map(|(image_view, _)| {
+                                    (
+                                        image_view.image(),
+                                        image_view.subresource_range().clone(),
+                                        access,
+                                    )
+                                })
                             })
                             .map(image_resource),
                     );
diff --git a/vulkano/src/command_buffer/commands/render_pass.rs b/vulkano/src/command_buffer/commands/render_pass.rs
index 9f061fbd8c..6cf6870c2b 100644
--- a/vulkano/src/command_buffer/commands/render_pass.rs
+++ b/vulkano/src/command_buffer/commands/render_pass.rs
@@ -23,7 +23,7 @@ use crate::{
     format::{ClearValue, NumericType},
     image::{
         attachment::{ClearAttachment, ClearRect},
-        ImageAspects, ImageSubresourceRange,
+        ImageAspects,
     },
     pipeline::GraphicsPipeline,
     render_pass::{Framebuffer, LoadOp},
@@ -402,19 +402,13 @@ impl SyncCommandBufferBuilder {
             .iter()
             .enumerate()
             .map(|(num, desc)| {
-                let image = render_pass_begin_info.framebuffer.attachments()[num].image();
-                let subresource_range = ImageSubresourceRange {
-                    // TODO:
-                    aspects: image.format().aspects(),
-                    mip_levels: image.current_mip_levels_access(),
-                    array_layers: image.current_array_layers_access(),
-                };
+                let image_view = &render_pass_begin_info.framebuffer.attachments()[num];
 
                 (
                     format!("attachment {}", num).into(),
                     Resource::Image {
-                        image,
-                        subresource_range,
+                        image: image_view.image(),
+                        subresource_range: image_view.subresource_range().clone(),
                         memory: PipelineMemoryAccess {
                             stages: PipelineStages {
                                 all_commands: true,
diff --git a/vulkano/src/command_buffer/commands/secondary.rs b/vulkano/src/command_buffer/commands/secondary.rs
index 42ba5a061b..619c772707 100644
--- a/vulkano/src/command_buffer/commands/secondary.rs
+++ b/vulkano/src/command_buffer/commands/secondary.rs
@@ -16,7 +16,6 @@ use crate::{
         CommandBufferInheritanceRenderPassInfo, CommandBufferUsage, ExecuteCommandsError,
         PrimaryAutoCommandBuffer, SecondaryCommandBuffer, SubpassContents,
     },
-    image::ImageSubresourceRange,
     query::QueryType,
     SafeDeref, VulkanObject,
 };
@@ -248,28 +247,24 @@ impl<'a> SyncCommandBufferBuilderExecuteCommands<'a> {
             let mut resources = Vec::new();
             for (cbuf_num, cbuf) in self.inner.iter().enumerate() {
                 for buf_num in 0..cbuf.num_buffers() {
-                    let (buffer, memory) = cbuf.buffer(buf_num).unwrap();
+                    let (buffer, range, memory) = cbuf.buffer(buf_num).unwrap();
                     resources.push((
                         format!("Buffer bound to secondary command buffer {}", cbuf_num).into(),
                         Resource::Buffer {
                             buffer: buffer.clone(),
-                            range: 0..buffer.size(), // TODO:
+                            range,
                             memory,
                         },
                     ));
                 }
                 for img_num in 0..cbuf.num_images() {
-                    let (image, memory, start_layout, end_layout) = cbuf.image(img_num).unwrap();
+                    let (image, subresource_range, memory, start_layout, end_layout) =
+                        cbuf.image(img_num).unwrap();
                     resources.push((
                         format!("Image bound to secondary command buffer {}", cbuf_num).into(),
                         Resource::Image {
                             image: image.clone(),
-                            subresource_range: ImageSubresourceRange {
-                                // TODO:
-                                aspects: image.format().aspects(),
-                                mip_levels: image.current_mip_levels_access(),
-                                array_layers: image.current_array_layers_access(),
-                            },
+                            subresource_range: subresource_range.clone(),
                             memory,
                             start_layout,
                             end_layout,
diff --git a/vulkano/src/command_buffer/synced/builder.rs b/vulkano/src/command_buffer/synced/builder.rs
index 773572fb2f..4c46492450 100644
--- a/vulkano/src/command_buffer/synced/builder.rs
+++ b/vulkano/src/command_buffer/synced/builder.rs
@@ -96,9 +96,14 @@ pub struct SyncCommandBufferBuilder {
     images2: HashMap<Arc<UnsafeImage>, RangeMap<DeviceSize, Option<ImageState>>>,
 
     // Resources and their accesses. Used for executing secondary command buffers in a primary.
-    buffers: Vec<(Arc<dyn BufferAccess>, PipelineMemoryAccess)>,
+    buffers: Vec<(
+        Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )>,
     images: Vec<(
         Arc<dyn ImageAccess>,
+        ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
@@ -288,7 +293,7 @@ impl SyncCommandBufferBuilder {
     fn find_image_conflict(
         &self,
         image: &dyn ImageAccess,
-        subresource_range: ImageSubresourceRange,
+        mut subresource_range: ImageSubresourceRange,
         memory: &PipelineMemoryAccess,
         start_layout: ImageLayout,
         end_layout: ImageLayout,
@@ -299,6 +304,10 @@ impl SyncCommandBufferBuilder {
             self.latest_render_pass_enter.unwrap_or(self.commands.len());
 
         let inner = image.inner();
+        subresource_range.array_layers.start += inner.first_layer;
+        subresource_range.array_layers.end += inner.first_layer;
+        subresource_range.mip_levels.start += inner.first_mipmap_level;
+        subresource_range.mip_levels.end += inner.first_mipmap_level;
 
         let range_map = self.images2.get(inner.image)?;
 
@@ -383,6 +392,8 @@ impl SyncCommandBufferBuilder {
         mut range: Range<DeviceSize>,
         memory: PipelineMemoryAccess,
     ) {
+        self.buffers.push((buffer.clone(), range.clone(), memory));
+
         // Barriers work differently in render passes, so if we're in one, we can only insert a
         // barrier before the start of the render pass.
         let last_allowed_barrier_index = self
@@ -480,19 +491,25 @@ impl SyncCommandBufferBuilder {
                 }
             }
         }
-
-        self.buffers.push((buffer, memory));
     }
 
     fn add_image(
         &mut self,
         resource_name: Cow<'static, str>,
         image: Arc<dyn ImageAccess>,
-        subresource_range: ImageSubresourceRange,
+        mut subresource_range: ImageSubresourceRange,
         memory: PipelineMemoryAccess,
         start_layout: ImageLayout,
         end_layout: ImageLayout,
     ) {
+        self.images.push((
+            image.clone(),
+            subresource_range.clone(),
+            memory,
+            start_layout,
+            end_layout,
+        ));
+
         // Barriers work differently in render passes, so if we're in one, we can only insert a
         // barrier before the start of the render pass.
         let last_allowed_barrier_index = self
@@ -500,6 +517,10 @@ impl SyncCommandBufferBuilder {
             .unwrap_or(self.commands.len() - 1);
 
         let inner = image.inner();
+        subresource_range.array_layers.start += inner.first_layer;
+        subresource_range.array_layers.end += inner.first_layer;
+        subresource_range.mip_levels.start += inner.first_mipmap_level;
+        subresource_range.mip_levels.end += inner.first_mipmap_level;
 
         let range_map = self.images2.entry(inner.image.clone()).or_insert_with(|| {
             [(
@@ -672,8 +693,6 @@ impl SyncCommandBufferBuilder {
                 }
             }
         }
-
-        self.images.push((image, memory, start_layout, end_layout));
     }
 
     /// Builds the command buffer and turns it into a `SyncCommandBuffer`.
diff --git a/vulkano/src/command_buffer/synced/mod.rs b/vulkano/src/command_buffer/synced/mod.rs
index 8264b63bfd..c709f91779 100644
--- a/vulkano/src/command_buffer/synced/mod.rs
+++ b/vulkano/src/command_buffer/synced/mod.rs
@@ -107,9 +107,14 @@ pub struct SyncCommandBuffer {
     images2: HashMap<Arc<UnsafeImage>, RangeMap<DeviceSize, ImageFinalState>>,
 
     // Resources and their accesses. Used for executing secondary command buffers in a primary.
-    buffers: Vec<(Arc<dyn BufferAccess>, PipelineMemoryAccess)>,
+    buffers: Vec<(
+        Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )>,
     images: Vec<(
         Arc<dyn ImageAccess>,
+        ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
@@ -381,10 +386,17 @@ impl SyncCommandBuffer {
     }
 
     #[inline]
-    pub fn buffer(&self, index: usize) -> Option<(&Arc<dyn BufferAccess>, PipelineMemoryAccess)> {
+    pub fn buffer(
+        &self,
+        index: usize,
+    ) -> Option<(
+        &Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )> {
         self.buffers
             .get(index)
-            .map(|(buffer, memory)| (buffer, *memory))
+            .map(|(buffer, range, memory)| (buffer, range.clone(), *memory))
     }
 
     #[inline]
@@ -398,14 +410,15 @@ impl SyncCommandBuffer {
         index: usize,
     ) -> Option<(
         &Arc<dyn ImageAccess>,
+        &ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
     )> {
         self.images
             .get(index)
-            .map(|(image, memory, start_layout, end_layout)| {
-                (image, *memory, *start_layout, *end_layout)
+            .map(|(image, range, memory, start_layout, end_layout)| {
+                (image, range, *memory, *start_layout, *end_layout)
             })
     }
 }
diff --git a/vulkano/src/command_buffer/traits.rs b/vulkano/src/command_buffer/traits.rs
index 0691032cdc..9f4740559b 100644
--- a/vulkano/src/command_buffer/traits.rs
+++ b/vulkano/src/command_buffer/traits.rs
@@ -15,7 +15,7 @@ use super::{
 use crate::{
     buffer::{sys::UnsafeBuffer, BufferAccess},
     device::{Device, DeviceOwned, Queue},
-    image::{sys::UnsafeImage, ImageAccess, ImageLayout},
+    image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange},
     sync::{
         now, AccessCheckError, AccessError, AccessFlags, FlushError, GpuFuture, NowFuture,
         PipelineMemoryAccess, PipelineStages,
@@ -229,7 +229,14 @@ pub unsafe trait SecondaryCommandBuffer: DeviceOwned + Send + Sync {
     /// Returns the `index`th buffer of this command buffer, or `None` if out of range.
     ///
     /// The valid range is between 0 and `num_buffers()`.
-    fn buffer(&self, index: usize) -> Option<(&Arc<dyn BufferAccess>, PipelineMemoryAccess)>;
+    fn buffer(
+        &self,
+        index: usize,
+    ) -> Option<(
+        &Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )>;
 
     /// Returns the number of images accessed by this command buffer.
     fn num_images(&self) -> usize;
@@ -242,6 +249,7 @@ pub unsafe trait SecondaryCommandBuffer: DeviceOwned + Send + Sync {
         index: usize,
     ) -> Option<(
         &Arc<dyn ImageAccess>,
+        &ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
@@ -279,7 +287,14 @@ where
     }
 
     #[inline]
-    fn buffer(&self, index: usize) -> Option<(&Arc<dyn BufferAccess>, PipelineMemoryAccess)> {
+    fn buffer(
+        &self,
+        index: usize,
+    ) -> Option<(
+        &Arc<dyn BufferAccess>,
+        Range<DeviceSize>,
+        PipelineMemoryAccess,
+    )> {
         (**self).buffer(index)
     }
 
@@ -294,6 +309,7 @@ where
         index: usize,
     ) -> Option<(
         &Arc<dyn ImageAccess>,
+        &ImageSubresourceRange,
         PipelineMemoryAccess,
         ImageLayout,
         ImageLayout,
diff --git a/vulkano/src/descriptor_set/update.rs b/vulkano/src/descriptor_set/update.rs
index 32e21713d2..8acff83f34 100644
--- a/vulkano/src/descriptor_set/update.rs
+++ b/vulkano/src/descriptor_set/update.rs
@@ -7,19 +7,16 @@
 // notice may not be copied, modified, or distributed except
 // according to those terms.
 
-use crate::buffer::view::BufferViewAbstract;
-use crate::buffer::{BufferAccess, BufferInner};
-use crate::descriptor_set::layout::{DescriptorSetLayoutBinding, DescriptorType};
-use crate::descriptor_set::DescriptorSetLayout;
-use crate::device::DeviceOwned;
-use crate::image::view::{ImageViewAbstract, ImageViewType};
-use crate::image::ImageType;
-use crate::sampler::{Sampler, SamplerImageViewIncompatibleError};
-use crate::DeviceSize;
-use crate::VulkanObject;
+use super::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType};
+use crate::{
+    buffer::{view::BufferViewAbstract, BufferAccess, BufferInner},
+    device::DeviceOwned,
+    image::{view::ImageViewType, ImageType, ImageViewAbstract},
+    sampler::{Sampler, SamplerImageViewIncompatibleError},
+    DeviceSize, VulkanObject,
+};
 use smallvec::SmallVec;
-use std::ptr;
-use std::sync::Arc;
+use std::{ptr, sync::Arc};
 
 /// Represents a single write operation to the binding of a descriptor set.
 ///
@@ -585,7 +582,9 @@ pub(crate) fn check_descriptor_write<'a>(
                     }
 
                     // VUID-VkDescriptorImageInfo-imageView-01976
-                    if image_view.aspects().depth && image_view.aspects().stencil {
+                    if image_view.subresource_range().aspects.depth
+                        && image_view.subresource_range().aspects.stencil
+                    {
                         return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
                             binding: write.binding(),
                             index: descriptor_range_start + index as u32,
@@ -631,7 +630,9 @@ pub(crate) fn check_descriptor_write<'a>(
                     }
 
                     // VUID-VkDescriptorImageInfo-imageView-01976
-                    if image_view.aspects().depth && image_view.aspects().stencil {
+                    if image_view.subresource_range().aspects.depth
+                        && image_view.subresource_range().aspects.stencil
+                    {
                         return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
                             binding: write.binding(),
                             index: descriptor_range_start + index as u32,
@@ -679,7 +680,9 @@ pub(crate) fn check_descriptor_write<'a>(
                     }
 
                     // VUID-VkDescriptorImageInfo-imageView-01976
-                    if image_view.aspects().depth && image_view.aspects().stencil {
+                    if image_view.subresource_range().aspects.depth
+                        && image_view.subresource_range().aspects.stencil
+                    {
                         return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
                             binding: write.binding(),
                             index: descriptor_range_start + index as u32,
@@ -735,7 +738,9 @@ pub(crate) fn check_descriptor_write<'a>(
                     }
 
                     // VUID-VkDescriptorImageInfo-imageView-01976
-                    if image_view.aspects().depth && image_view.aspects().stencil {
+                    if image_view.subresource_range().aspects.depth
+                        && image_view.subresource_range().aspects.stencil
+                    {
                         return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
                             binding: write.binding(),
                             index: descriptor_range_start + index as u32,
@@ -818,7 +823,9 @@ pub(crate) fn check_descriptor_write<'a>(
                     }
 
                     // VUID-VkDescriptorImageInfo-imageView-01976
-                    if image_view.aspects().depth && image_view.aspects().stencil {
+                    if image_view.subresource_range().aspects.depth
+                        && image_view.subresource_range().aspects.stencil
+                    {
                         return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
                             binding: write.binding(),
                             index: descriptor_range_start + index as u32,
diff --git a/vulkano/src/image/attachment.rs b/vulkano/src/image/attachment.rs
index 5afbb034ca..6cc038a962 100644
--- a/vulkano/src/image/attachment.rs
+++ b/vulkano/src/image/attachment.rs
@@ -30,7 +30,6 @@ use crate::{
 use std::{
     fs::File,
     hash::{Hash, Hasher},
-    ops::Range,
     sync::{
         atomic::{AtomicBool, AtomicUsize, Ordering},
         Arc,
@@ -596,16 +595,6 @@ where
     fn is_layout_initialized(&self) -> bool {
         self.initialized.load(Ordering::SeqCst)
     }
-
-    #[inline]
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        0..self.mip_levels()
-    }
-
-    #[inline]
-    fn current_array_layers_access(&self) -> Range<u32> {
-        0..self.dimensions().array_layers()
-    }
 }
 
 unsafe impl<A> DeviceOwned for AttachmentImage<A> {
diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs
index e55c5fcaa1..6af119b3ed 100644
--- a/vulkano/src/image/immutable.rs
+++ b/vulkano/src/image/immutable.rs
@@ -373,16 +373,6 @@ where
             input_attachment: self.layout,
         })
     }
-
-    #[inline]
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        0..self.mip_levels()
-    }
-
-    #[inline]
-    fn current_array_layers_access(&self) -> Range<u32> {
-        0..self.dimensions().array_layers()
-    }
 }
 
 unsafe impl<P, A> ImageContent<P> for ImmutableImage<A>
@@ -453,16 +443,6 @@ where
     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
         None
     }
-
-    #[inline]
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        self.mip_levels_access.clone()
-    }
-
-    #[inline]
-    fn current_array_layers_access(&self) -> Range<u32> {
-        self.array_layers_access.clone()
-    }
 }
 
 impl<A> PartialEq for ImmutableImageInitialization<A>
diff --git a/vulkano/src/image/storage.rs b/vulkano/src/image/storage.rs
index 7d1edc8384..aaceb0bb98 100644
--- a/vulkano/src/image/storage.rs
+++ b/vulkano/src/image/storage.rs
@@ -32,7 +32,6 @@ use smallvec::SmallVec;
 use std::{
     fs::File,
     hash::{Hash, Hasher},
-    ops::Range,
     sync::Arc,
 };
 
@@ -283,16 +282,6 @@ where
             input_attachment: ImageLayout::General,
         })
     }
-
-    #[inline]
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        0..self.mip_levels()
-    }
-
-    #[inline]
-    fn current_array_layers_access(&self) -> Range<u32> {
-        0..self.dimensions().array_layers()
-    }
 }
 
 unsafe impl<A> ImageClearValue<ClearValue> for StorageImage<A>
diff --git a/vulkano/src/image/swapchain.rs b/vulkano/src/image/swapchain.rs
index 9cfbfa8fd6..cc0846300b 100644
--- a/vulkano/src/image/swapchain.rs
+++ b/vulkano/src/image/swapchain.rs
@@ -19,7 +19,6 @@ use crate::{
 };
 use std::{
     hash::{Hash, Hasher},
-    ops::Range,
     sync::Arc,
 };
 
@@ -36,7 +35,7 @@ use std::{
 /// method on the swapchain), which will have the effect of showing the content of the image to
 /// the screen. Once an image has been presented, it can no longer be used unless it is acquired
 /// again.
-// TODO: #[derive(Debug)]
+#[derive(Debug)]
 pub struct SwapchainImage<W> {
     swapchain: Arc<Swapchain<W>>,
     image_offset: usize,
@@ -125,16 +124,6 @@ where
     fn is_layout_initialized(&self) -> bool {
         self.is_layout_initialized()
     }
-
-    #[inline]
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        0..self.mip_levels()
-    }
-
-    #[inline]
-    fn current_array_layers_access(&self) -> Range<u32> {
-        0..1
-    }
 }
 
 unsafe impl<W> ImageClearValue<ClearValue> for SwapchainImage<W>
diff --git a/vulkano/src/image/traits.rs b/vulkano/src/image/traits.rs
index e85f758ff0..fd3fca3570 100644
--- a/vulkano/src/image/traits.rs
+++ b/vulkano/src/image/traits.rs
@@ -8,8 +8,8 @@
 // according to those terms.
 
 use super::{
-    sys::UnsafeImage, ImageDescriptorLayouts, ImageDimensions, ImageLayout, ImageSubresourceLayers,
-    ImageSubresourceRange, ImageUsage, SampleCount,
+    sys::UnsafeImage, ImageAspects, ImageDescriptorLayouts, ImageDimensions, ImageLayout,
+    ImageSubresourceLayers, ImageSubresourceRange, ImageUsage, SampleCount,
 };
 use crate::{
     device::{Device, DeviceOwned},
@@ -19,7 +19,6 @@ use crate::{
 use std::{
     fmt,
     hash::{Hash, Hasher},
-    ops::Range,
     sync::Arc,
 };
 
@@ -31,8 +30,41 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
     /// Returns the dimensions of the image.
     #[inline]
     fn dimensions(&self) -> ImageDimensions {
-        // TODO: not necessarily correct because of the new inner() design?
-        self.inner().image.dimensions()
+        let inner = self.inner();
+
+        match self
+            .inner()
+            .image
+            .dimensions()
+            .mip_level_dimensions(inner.first_mipmap_level)
+            .unwrap()
+        {
+            ImageDimensions::Dim1d {
+                width,
+                array_layers: _,
+            } => ImageDimensions::Dim1d {
+                width,
+                array_layers: inner.num_layers,
+            },
+            ImageDimensions::Dim2d {
+                width,
+                height,
+                array_layers: _,
+            } => ImageDimensions::Dim2d {
+                width,
+                height,
+                array_layers: inner.num_layers,
+            },
+            ImageDimensions::Dim3d {
+                width,
+                height,
+                depth,
+            } => ImageDimensions::Dim3d {
+                width,
+                height,
+                depth,
+            },
+        }
     }
 
     /// Returns the format of this image.
@@ -50,8 +82,7 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
     /// Returns the number of mipmap levels of this image.
     #[inline]
     fn mip_levels(&self) -> u32 {
-        // TODO: not necessarily correct because of the new inner() design?
-        self.inner().image.mip_levels()
+        self.inner().num_mipmap_levels
     }
 
     /// Returns the number of samples of this image.
@@ -70,14 +101,38 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
     /// of the image are selected, or `plane0` if the image is multi-planar.
     #[inline]
     fn subresource_layers(&self) -> ImageSubresourceLayers {
-        self.inner().image.subresource_layers()
+        ImageSubresourceLayers {
+            aspects: {
+                let aspects = self.format().aspects();
+
+                if aspects.plane0 {
+                    ImageAspects {
+                        plane0: true,
+                        ..ImageAspects::none()
+                    }
+                } else {
+                    aspects
+                }
+            },
+            mip_level: 0,
+            array_layers: 0..self.dimensions().array_layers(),
+        }
     }
 
     /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
     /// only the `color` aspect is selected.
     #[inline]
     fn subresource_range(&self) -> ImageSubresourceRange {
-        self.inner().image.subresource_range()
+        ImageSubresourceRange {
+            aspects: ImageAspects {
+                plane0: false,
+                plane1: false,
+                plane2: false,
+                ..self.format().aspects()
+            },
+            mip_levels: 0..self.mip_levels(),
+            array_layers: 0..self.dimensions().array_layers(),
+        }
     }
 
     /// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
@@ -93,12 +148,15 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
     /// `Preinitialized` state, this may result in the vulkan implementation attempting to use
     /// an image in an invalid layout. The same problem must be considered by the implementer
     /// of the method.
+    #[inline]
     unsafe fn layout_initialized(&self) {}
 
+    #[inline]
     fn is_layout_initialized(&self) -> bool {
         false
     }
 
+    #[inline]
     fn initial_layout(&self) -> ImageLayout {
         self.inner().image.initial_layout()
     }
@@ -144,12 +202,6 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
     ///
     /// This must return `Some` if the image is to be used to create an image view.
     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>;
-
-    /// Returns the current mip level that is accessed by the gpu
-    fn current_mip_levels_access(&self) -> Range<u32>;
-
-    /// Returns the current array layer that is accessed by the gpu
-    fn current_array_layers_access(&self) -> Range<u32>;
 }
 
 /// Inner information about an image.
@@ -239,14 +291,6 @@ where
     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
         self.image.descriptor_layouts()
     }
-
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        self.image.current_mip_levels_access()
-    }
-
-    fn current_array_layers_access(&self) -> Range<u32> {
-        self.image.current_array_layers_access()
-    }
 }
 
 impl<I> PartialEq for ImageAccessFromUndefinedLayout<I>
@@ -317,12 +361,4 @@ where
     fn is_layout_initialized(&self) -> bool {
         (**self).is_layout_initialized()
     }
-
-    fn current_mip_levels_access(&self) -> Range<u32> {
-        (**self).current_mip_levels_access()
-    }
-
-    fn current_array_layers_access(&self) -> Range<u32> {
-        (**self).current_array_layers_access()
-    }
 }
diff --git a/vulkano/src/image/view.rs b/vulkano/src/image/view.rs
index 20a97ae48c..94c78719e9 100644
--- a/vulkano/src/image/view.rs
+++ b/vulkano/src/image/view.rs
@@ -13,27 +13,25 @@
 //! an image and describes how the GPU should interpret the data. It is needed when an image is
 //! to be used in a shader descriptor or as a framebuffer attachment.
 
-use super::ImageFormatInfo;
-use crate::device::{Device, DeviceOwned};
-use crate::format::{ChromaSampling, Format, FormatFeatures};
-use crate::image::{
-    ImageAccess, ImageAspects, ImageDimensions, ImageTiling, ImageType, ImageUsage, SampleCount,
+use super::{ImageAccess, ImageDimensions, ImageFormatInfo, ImageSubresourceRange, ImageUsage};
+use crate::{
+    check_errors,
+    device::{Device, DeviceOwned},
+    format::{ChromaSampling, Format, FormatFeatures},
+    image::{ImageAspects, ImageTiling, ImageType, SampleCount},
+    sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping},
+    Error, OomError, VulkanObject,
+};
+use std::{
+    error, fmt,
+    hash::{Hash, Hasher},
+    mem::MaybeUninit,
+    ptr,
+    sync::Arc,
 };
-use crate::sampler::ycbcr::SamplerYcbcrConversion;
-use crate::sampler::ComponentMapping;
-use crate::OomError;
-use crate::VulkanObject;
-use crate::{check_errors, Error};
-use std::error;
-use std::fmt;
-use std::fmt::Debug;
-use std::hash::{Hash, Hasher};
-use std::mem::MaybeUninit;
-use std::ops::Range;
-use std::ptr;
-use std::sync::Arc;
 
 /// A wrapper around an image that makes it available to shaders or framebuffers.
+#[derive(Debug)]
 pub struct ImageView<I>
 where
     I: ImageAccess + ?Sized,
@@ -41,13 +39,11 @@ where
     handle: ash::vk::ImageView,
     image: Arc<I>,
 
-    array_layers: Range<u32>,
-    aspects: ImageAspects,
     component_mapping: ComponentMapping,
     format: Option<Format>,
     format_features: FormatFeatures,
-    mip_levels: Range<u32>,
     sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
+    subresource_range: ImageSubresourceRange,
     usage: ImageUsage,
     view_type: ImageViewType,
 
@@ -73,16 +69,14 @@ where
         image: Arc<I>,
         mut create_info: ImageViewCreateInfo,
     ) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
-        let (format_features, usage) = Self::validate(&image, &mut create_info)?;
-        let handle = unsafe { Self::create(&image, &create_info)? };
+        let (format_features, usage) = Self::validate_create(&image, &mut create_info)?;
+        let handle = unsafe { Self::record_create(&image, &create_info)? };
 
         let ImageViewCreateInfo {
             view_type,
             format,
             component_mapping,
-            aspects,
-            array_layers,
-            mip_levels,
+            subresource_range,
             sampler_ycbcr_conversion,
             _ne: _,
         } = create_info;
@@ -118,9 +112,7 @@ where
             format,
             format_features,
             component_mapping,
-            aspects,
-            array_layers,
-            mip_levels,
+            subresource_range,
             usage,
             sampler_ycbcr_conversion,
 
@@ -129,7 +121,7 @@ where
         }))
     }
 
-    fn validate(
+    fn validate_create(
         image: &I,
         create_info: &mut ImageViewCreateInfo,
     ) -> Result<(FormatFeatures, ImageUsage), ImageViewCreationError> {
@@ -137,17 +129,15 @@ where
             view_type,
             format,
             component_mapping,
-            aspects,
-            ref array_layers,
-            ref mip_levels,
+            ref subresource_range,
             ref sampler_ycbcr_conversion,
             _ne: _,
         } = create_info;
 
         let format = format.unwrap();
         let image_inner = image.inner().image;
-        let level_count = mip_levels.end - mip_levels.start;
-        let layer_count = array_layers.end - array_layers.start;
+        let level_count = subresource_range.mip_levels.end - subresource_range.mip_levels.start;
+        let layer_count = subresource_range.array_layers.end - subresource_range.array_layers.start;
 
         assert!(level_count != 0);
         assert!(layer_count != 0);
@@ -164,7 +154,7 @@ where
                 memory_plane0,
                 memory_plane1,
                 memory_plane2,
-            } = aspects;
+            } = subresource_range.aspects;
 
             assert!(!(metadata || memory_plane0 || memory_plane1 || memory_plane2));
             assert!({
@@ -223,9 +213,14 @@ where
         };
 
         // No VUID apparently, but this seems like something we want to check?
-        if !image_inner.format().unwrap().aspects().contains(&aspects) {
+        if !image_inner
+            .format()
+            .unwrap()
+            .aspects()
+            .contains(&subresource_range.aspects)
+        {
             return Err(ImageViewCreationError::ImageAspectsNotCompatible {
-                aspects,
+                aspects: subresource_range.aspects,
                 image_aspects: image_inner.format().unwrap().aspects(),
             });
         }
@@ -266,9 +261,9 @@ where
         }
 
         // VUID-VkImageViewCreateInfo-subresourceRange-01718
-        if mip_levels.end > image_inner.mip_levels() {
+        if subresource_range.mip_levels.end > image_inner.mip_levels() {
             return Err(ImageViewCreationError::MipLevelsOutOfRange {
-                range_end: mip_levels.end,
+                range_end: subresource_range.mip_levels.end,
                 max: image_inner.mip_levels(),
             });
         }
@@ -293,21 +288,21 @@ where
             // higher.
             let max = image_inner
                 .dimensions()
-                .mip_level_dimensions(mip_levels.start)
+                .mip_level_dimensions(subresource_range.mip_levels.start)
                 .unwrap()
                 .depth();
-            if array_layers.end > max {
+            if subresource_range.array_layers.end > max {
                 return Err(ImageViewCreationError::ArrayLayersOutOfRange {
-                    range_end: array_layers.end,
+                    range_end: subresource_range.array_layers.end,
                     max,
                 });
             }
         } else {
             // VUID-VkImageViewCreateInfo-image-01482
             // VUID-VkImageViewCreateInfo-subresourceRange-01483
-            if array_layers.end > image_inner.dimensions().array_layers() {
+            if subresource_range.array_layers.end > image_inner.dimensions().array_layers() {
                 return Err(ImageViewCreationError::ArrayLayersOutOfRange {
-                    range_end: array_layers.end,
+                    range_end: subresource_range.array_layers.end,
                     max: image_inner.dimensions().array_layers(),
                 });
             }
@@ -401,13 +396,13 @@ where
 
         if image_inner.mutable_format()
             && !image_inner.format().unwrap().planes().is_empty()
-            && !aspects.color
+            && !subresource_range.aspects.color
         {
-            let plane = if aspects.plane0 {
+            let plane = if subresource_range.aspects.plane0 {
                 0
-            } else if aspects.plane1 {
+            } else if subresource_range.aspects.plane1 {
                 1
-            } else if aspects.plane2 {
+            } else if subresource_range.aspects.plane2 {
                 2
             } else {
                 unreachable!()
@@ -488,7 +483,7 @@ where
         Ok((format_features, usage))
     }
 
-    unsafe fn create(
+    unsafe fn record_create(
         image: &I,
         create_info: &ImageViewCreateInfo,
     ) -> Result<ash::vk::ImageView, ImageViewCreationError> {
@@ -496,9 +491,7 @@ where
             view_type,
             format,
             component_mapping,
-            aspects,
-            ref array_layers,
-            ref mip_levels,
+            ref subresource_range,
             ref sampler_ycbcr_conversion,
             _ne: _,
         } = create_info;
@@ -511,13 +504,7 @@ where
             view_type: view_type.into(),
             format: format.unwrap().into(),
             components: component_mapping.into(),
-            subresource_range: ash::vk::ImageSubresourceRange {
-                aspect_mask: aspects.into(),
-                base_mip_level: mip_levels.start,
-                level_count: mip_levels.end - mip_levels.start,
-                base_array_layer: array_layers.start,
-                layer_count: array_layers.end - array_layers.start,
-            },
+            subresource_range: subresource_range.clone().into(),
             ..Default::default()
         };
 
@@ -551,7 +538,7 @@ where
     }
 
     /// Creates a default `ImageView`. Equivalent to
-    /// `ImageView::new_default(image, ImageViewCreateInfo::from_image(image))`.
+    /// `ImageView::new(image, ImageViewCreateInfo::from_image(image))`.
     #[inline]
     pub fn new_default(image: Arc<I>) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
         let create_info = ImageViewCreateInfo::from_image(&image);
@@ -565,50 +552,40 @@ where
     }
 }
 
-unsafe impl<I> VulkanObject for ImageView<I>
+impl<I> Drop for ImageView<I>
 where
     I: ImageAccess + ?Sized,
 {
-    type Object = ash::vk::ImageView;
-
     #[inline]
-    fn internal_object(&self) -> ash::vk::ImageView {
-        self.handle
+    fn drop(&mut self) {
+        unsafe {
+            let device = self.device();
+            let fns = device.fns();
+            fns.v1_0
+                .destroy_image_view(device.internal_object(), self.handle, ptr::null());
+        }
     }
 }
 
-unsafe impl<I> DeviceOwned for ImageView<I>
+unsafe impl<I> VulkanObject for ImageView<I>
 where
     I: ImageAccess + ?Sized,
 {
-    #[inline]
-    fn device(&self) -> &Arc<Device> {
-        self.image.inner().image.device()
-    }
-}
+    type Object = ash::vk::ImageView;
 
-impl<I> fmt::Debug for ImageView<I>
-where
-    I: ImageAccess + ?Sized,
-{
     #[inline]
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        write!(fmt, "<Vulkan image view {:?}>", self.handle)
+    fn internal_object(&self) -> ash::vk::ImageView {
+        self.handle
     }
 }
 
-impl<I> Drop for ImageView<I>
+unsafe impl<I> DeviceOwned for ImageView<I>
 where
     I: ImageAccess + ?Sized,
 {
     #[inline]
-    fn drop(&mut self) {
-        unsafe {
-            let device = self.device();
-            let fns = device.fns();
-            fns.v1_0
-                .destroy_image_view(device.internal_object(), self.handle, ptr::null());
-        }
+    fn device(&self) -> &Arc<Device> {
+        self.image.inner().image.device()
     }
 }
 
@@ -659,20 +636,10 @@ pub struct ImageViewCreateInfo {
     /// The default value is [`ComponentMapping::identity()`].
     pub component_mapping: ComponentMapping,
 
-    /// The aspects of the image that the view should cover.
-    ///
-    /// The default value is [`ImageAspects::none()`], which must be overridden.
-    pub aspects: ImageAspects,
-
-    /// The range of array layers of the image that the view should cover.
-    ///
-    /// The default value is `0..1`.
-    pub array_layers: Range<u32>,
-
-    /// The range of mipmap levels of the image that the view should cover.
+    /// The subresource range of the image that the view should cover.
     ///
-    /// The default value is `0..1`.
-    pub mip_levels: Range<u32>,
+    /// The default value is empty, which must be overridden.
+    pub subresource_range: ImageSubresourceRange,
 
     /// The sampler YCbCr conversion to be used with the image view.
     ///
@@ -696,9 +663,11 @@ impl Default for ImageViewCreateInfo {
             view_type: ImageViewType::Dim2d,
             format: None,
             component_mapping: ComponentMapping::identity(),
-            aspects: ImageAspects::none(),
-            array_layers: 0..1,
-            mip_levels: 0..1,
+            subresource_range: ImageSubresourceRange {
+                aspects: ImageAspects::none(),
+                array_layers: 0..0,
+                mip_levels: 0..0,
+            },
             sampler_ycbcr_conversion: None,
             _ne: crate::NonExhaustive(()),
         }
@@ -707,8 +676,8 @@ impl Default for ImageViewCreateInfo {
 
 impl ImageViewCreateInfo {
     /// Returns an `ImageViewCreateInfo` with the `view_type` determined from the image type and
-    /// array layers, `aspects` determined from the image format, and `array_layers` and
-    /// `mip_levels` covering the whole image.
+    /// array layers, and `subresource_range` determined from the image format and covering the
+    /// whole image.
     pub fn from_image<I>(image: &I) -> Self
     where
         I: ImageAccess + ?Sized,
@@ -726,25 +695,7 @@ impl ImageViewCreateInfo {
                 ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d,
             },
             format: Some(image.format()),
-            aspects: {
-                let aspects = image.format().aspects();
-                if aspects.depth || aspects.stencil {
-                    debug_assert!(!aspects.color);
-                    ImageAspects {
-                        depth: aspects.depth,
-                        stencil: aspects.stencil,
-                        ..Default::default()
-                    }
-                } else {
-                    debug_assert!(aspects.color);
-                    ImageAspects {
-                        color: true,
-                        ..Default::default()
-                    }
-                }
-            },
-            array_layers: 0..image.dimensions().array_layers(),
-            mip_levels: 0..image.mip_levels(),
+            subresource_range: image.subresource_range(),
             ..Default::default()
         }
     }
@@ -1026,17 +977,11 @@ impl From<ImageViewType> for ash::vk::ImageViewType {
 
 /// Trait for types that represent the GPU can access an image view.
 pub unsafe trait ImageViewAbstract:
-    VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + Debug + Send + Sync
+    VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + fmt::Debug + Send + Sync
 {
     /// Returns the wrapped image that this image view was created from.
     fn image(&self) -> Arc<dyn ImageAccess>;
 
-    /// Returns the range of array layers of the wrapped image that this view exposes.
-    fn array_layers(&self) -> Range<u32>;
-
-    /// Returns the aspects of the wrapped image that this view exposes.
-    fn aspects(&self) -> &ImageAspects;
-
     /// Returns the component mapping of this view.
     fn component_mapping(&self) -> ComponentMapping;
 
@@ -1056,12 +1001,12 @@ pub unsafe trait ImageViewAbstract:
     /// Returns the features supported by the image view's format.
     fn format_features(&self) -> &FormatFeatures;
 
-    /// Returns the range of mip levels of the wrapped image that this view exposes.
-    fn mip_levels(&self) -> Range<u32>;
-
     /// Returns the sampler YCbCr conversion that this image view was created with, if any.
     fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>;
 
+    /// Returns the subresource range of the wrapped image that this view exposes.
+    fn subresource_range(&self) -> &ImageSubresourceRange;
+
     /// Returns the usage of the image view.
     fn usage(&self) -> &ImageUsage;
 
@@ -1071,23 +1016,13 @@ pub unsafe trait ImageViewAbstract:
 
 unsafe impl<I> ImageViewAbstract for ImageView<I>
 where
-    I: ImageAccess + 'static,
+    I: ImageAccess + fmt::Debug + 'static,
 {
     #[inline]
     fn image(&self) -> Arc<dyn ImageAccess> {
         self.image.clone()
     }
 
-    #[inline]
-    fn array_layers(&self) -> Range<u32> {
-        self.array_layers.clone()
-    }
-
-    #[inline]
-    fn aspects(&self) -> &ImageAspects {
-        &self.aspects
-    }
-
     #[inline]
     fn component_mapping(&self) -> ComponentMapping {
         self.component_mapping
@@ -1114,13 +1049,13 @@ where
     }
 
     #[inline]
-    fn mip_levels(&self) -> Range<u32> {
-        self.mip_levels.clone()
+    fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
+        self.sampler_ycbcr_conversion.as_ref()
     }
 
     #[inline]
-    fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
-        self.sampler_ycbcr_conversion.as_ref()
+    fn subresource_range(&self) -> &ImageSubresourceRange {
+        &self.subresource_range
     }
 
     #[inline]
@@ -1140,16 +1075,6 @@ unsafe impl ImageViewAbstract for ImageView<dyn ImageAccess> {
         self.image.clone()
     }
 
-    #[inline]
-    fn array_layers(&self) -> Range<u32> {
-        self.array_layers.clone()
-    }
-
-    #[inline]
-    fn aspects(&self) -> &ImageAspects {
-        &self.aspects
-    }
-
     #[inline]
     fn component_mapping(&self) -> ComponentMapping {
         self.component_mapping
@@ -1176,13 +1101,13 @@ unsafe impl ImageViewAbstract for ImageView<dyn ImageAccess> {
     }
 
     #[inline]
-    fn mip_levels(&self) -> Range<u32> {
-        self.mip_levels.clone()
+    fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
+        self.sampler_ycbcr_conversion.as_ref()
     }
 
     #[inline]
-    fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
-        self.sampler_ycbcr_conversion.as_ref()
+    fn subresource_range(&self) -> &ImageSubresourceRange {
+        &self.subresource_range
     }
 
     #[inline]
diff --git a/vulkano/src/render_pass/framebuffer.rs b/vulkano/src/render_pass/framebuffer.rs
index f090edd032..2f49ab035a 100644
--- a/vulkano/src/render_pass/framebuffer.rs
+++ b/vulkano/src/render_pass/framebuffer.rs
@@ -188,8 +188,8 @@ impl Framebuffer {
                 }
 
                 let image_view_extent = image_view.image().dimensions().width_height();
-                let image_view_array_layers =
-                    image_view.array_layers().end - attachments[0].array_layers().start;
+                let image_view_array_layers = image_view.subresource_range().array_layers.end
+                    - attachments[0].subresource_range().array_layers.start;
 
                 // VUID-VkFramebufferCreateInfo-renderPass-04536
                 if image_view_array_layers < render_pass.views_used() {
@@ -227,7 +227,10 @@ impl Framebuffer {
                 }
 
                 // VUID-VkFramebufferCreateInfo-pAttachments-00883
-                if image_view.mip_levels().end - image_view.mip_levels().start != 1 {
+                if image_view.subresource_range().mip_levels.end
+                    - image_view.subresource_range().mip_levels.start
+                    != 1
+                {
                     return Err(FramebufferCreationError::AttachmentMultipleMipLevels {
                         attachment: attachment_num,
                     });
@@ -357,7 +360,7 @@ impl Framebuffer {
     pub fn attached_layers_ranges(&self) -> SmallVec<[Range<u32>; 4]> {
         self.attachments
             .iter()
-            .map(|img| img.array_layers())
+            .map(|img| img.subresource_range().array_layers.clone())
             .collect()
     }
 }
diff --git a/vulkano/src/sampler/mod.rs b/vulkano/src/sampler/mod.rs
index edcbd1b244..56c95efc9c 100644
--- a/vulkano/src/sampler/mod.rs
+++ b/vulkano/src/sampler/mod.rs
@@ -447,7 +447,7 @@ impl Sampler {
             // The SPIR-V instruction is one of the OpImage*Dref* instructions, the image
             // view format is one of the depth/stencil formats, and the image view aspect
             // is not VK_IMAGE_ASPECT_DEPTH_BIT.
-            if !image_view.aspects().depth {
+            if !image_view.subresource_range().aspects.depth {
                 return Err(SamplerImageViewIncompatibleError::DepthComparisonWrongAspect);
             }
         } else {
@@ -486,7 +486,7 @@ impl Sampler {
         }
 
         if let Some(border_color) = self.border_color {
-            let aspects = image_view.aspects();
+            let aspects = image_view.subresource_range().aspects;
             let view_scalar_type = ShaderScalarType::from(
                 if aspects.color || aspects.plane0 || aspects.plane1 || aspects.plane2 {
                     image_view.format().unwrap().type_color().unwrap()
@@ -566,7 +566,10 @@ impl Sampler {
             }
 
             // The image view must have a single layer and a single mip level.
-            if image_view.mip_levels().end - image_view.mip_levels().start != 1 {
+            if image_view.subresource_range().mip_levels.end
+                - image_view.subresource_range().mip_levels.start
+                != 1
+            {
                 return Err(
                     SamplerImageViewIncompatibleError::UnnormalizedCoordinatesMultipleMipLevels,
                 );