From aa46e82f4087209b6a331220e37dca142d4ffed5 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 21 Dec 2022 13:25:45 -0500 Subject: [PATCH] Fix texture view creation with full-resource views when using an explicit `mip_level_count` or `array_layer_count` --- CHANGELOG.md | 3 ++ wgpu-hal/src/metal/device.rs | 13 +++++---- wgpu-types/src/lib.rs | 55 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6249300fcf..ba0e7d3cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -171,6 +171,9 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non - Evaluate `gfx_select!`'s `#[cfg]` conditions at the right time. By @jimblandy in [#3253](https://github.com/gfx-rs/wgpu/pull/3253) - Improve error messages when binding bind group with dynamic offsets. By @cwfitzgerald in [#3294](https://github.com/gfx-rs/wgpu/pull/3294) +#### Metal +- Fix texture view creation with full-resource views when using an explicit `mip_level_count` or `array_layer_count`. By @cwfitzgerald in [#3323](https://github.com/gfx-rs/wgpu/pull/3323) + #### WebGPU - Use `log` instead of `println` in hello example by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858) diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index a2d151c02c..2a994bb579 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -358,12 +358,13 @@ impl crate::Device for super::Device { conv::map_texture_view_dimension(desc.dimension) }; - //Note: this doesn't check properly if the mipmap level count or array layer count - // is explicitly set to 1. - let raw = if raw_format == texture.raw_format - && raw_type == texture.raw_type - && desc.range == wgt::ImageSubresourceRange::default() - { + let format_equal = raw_format == texture.raw_format; + let type_equal = raw_type == texture.raw_type; + let range_full_resource = desc + .range + .is_full_resource(texture.mip_levels, texture.array_layers); + + let raw = if format_equal && type_equal && range_full_resource { // Some images are marked as framebuffer-only, and we can't create aliases of them. // Also helps working around Metal bugs with aliased array textures. texture.raw.to_owned() diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index f2570f5fb0..6a12bad9c1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5019,6 +5019,61 @@ pub struct ImageSubresourceRange { } impl ImageSubresourceRange { + /// Returns if the given range represents a full resource, with a texture of the given + /// layer count and mip count. + /// + /// ```rust + /// # use wgpu_types as wgpu; + /// use std::num::NonZeroU32; + /// + /// let range_none = wgpu::ImageSubresourceRange { + /// aspect: wgpu::TextureAspect::All, + /// base_mip_level: 0, + /// mip_level_count: None, + /// base_array_layer: 0, + /// array_layer_count: None, + /// }; + /// assert_eq!(range_none.is_full_resource(5, 10), true); + /// + /// let range_some = wgpu::ImageSubresourceRange { + /// aspect: wgpu::TextureAspect::All, + /// base_mip_level: 0, + /// mip_level_count: NonZeroU32::new(5), + /// base_array_layer: 0, + /// array_layer_count: NonZeroU32::new(10), + /// }; + /// assert_eq!(range_some.is_full_resource(5, 10), true); + /// + /// let range_mixed = wgpu::ImageSubresourceRange { + /// aspect: wgpu::TextureAspect::All, + /// base_mip_level: 0, + /// // Only partial resource + /// mip_level_count: NonZeroU32::new(3), + /// base_array_layer: 0, + /// array_layer_count: None, + /// }; + /// assert_eq!(range_mixed.is_full_resource(5, 10), false); + /// ``` + pub fn is_full_resource(&self, mip_levels: u32, array_layers: u32) -> bool { + // Mip level count and array layer count need to deal with both the None and Some(count) case. + let mip_level_count = self.mip_level_count.map_or(mip_levels, NonZeroU32::get); + let array_layer_count = self.array_layer_count.map_or(array_layers, NonZeroU32::get); + + let aspect_eq = self.aspect == TextureAspect::All; + + let base_mip_level_eq = self.base_mip_level == 0; + let mip_level_count_eq = mip_level_count == mip_levels; + + let base_array_layer_eq = self.base_array_layer == 0; + let array_layer_count_eq = array_layer_count == array_layers; + + aspect_eq + && base_mip_level_eq + && mip_level_count_eq + && base_array_layer_eq + && array_layer_count_eq + } + /// Returns the mip level range of a subresource range describes for a specific texture. pub fn mip_range(&self, texture_desc: &TextureDescriptor) -> Range { self.base_mip_level..match self.mip_level_count {