From 01f62baad2811c1cd6aa254608dfee000c316b46 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 10 Jan 2022 12:10:31 -0500 Subject: [PATCH] Limits 1D texture mips to 1 --- wgpu-core/src/device/mod.rs | 8 +- wgpu-core/src/resource.rs | 8 +- wgpu-types/src/lib.rs | 139 +++++++++++++++++++++++++++-------- wgpu/examples/skybox/main.rs | 2 +- 4 files changed, 122 insertions(+), 35 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2045f22812..043443684c 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -671,8 +671,12 @@ impl Device { )?; let mips = desc.mip_level_count; - if mips == 0 || mips > hal::MAX_MIP_LEVELS || mips > desc.size.max_mips() { - return Err(resource::CreateTextureError::InvalidMipLevelCount(mips)); + let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS); + if mips == 0 || mips > max_levels_allowed { + return Err(resource::CreateTextureError::InvalidMipLevelCount { + requested: mips, + maximum: max_levels_allowed, + }); } // Enforce having COPY_DST/DEPTH_STENCIL_WRIT/COLOR_TARGET otherwise we wouldn't be able to initialize the texture. diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 77df1f1a84..3315162c0f 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -301,9 +301,11 @@ pub enum CreateTextureError { InvalidDimension(#[from] TextureDimensionError), #[error("Depth texture kind {0:?} of format {0:?} can't be created")] InvalidDepthKind(wgt::TextureDimension, wgt::TextureFormat), - #[error("texture descriptor mip level count ({0}) is invalid")] - InvalidMipLevelCount(u32), - #[error("The texture usages {0:?} are not allowed on a texture of type {1:?}")] + #[error( + "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}" + )] + InvalidMipLevelCount { requested: u32, maximum: u32 }, + #[error("Texture usages {0:?} are not allowed on a texture of type {1:?}")] InvalidUsages(wgt::TextureUsages, wgt::TextureFormat), #[error("Texture format {0:?} can't be used")] MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures), diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index e356c1669a..36f62e65bc 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2848,25 +2848,6 @@ impl Extent3d { /// /// This is the texture extent that you must upload at when uploading to _mipmaps_ of compressed textures. /// - /// ```rust - /// # use wgpu_types as wgpu; - /// let format = wgpu::TextureFormat::Bc1RgbaUnormSrgb; // 4x4 blocks - /// assert_eq!( - /// wgpu::Extent3d { width: 7, height: 7, depth_or_array_layers: 1 }.physical_size(format), - /// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 } - /// ); - /// // Doesn't change, already aligned - /// assert_eq!( - /// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 }.physical_size(format), - /// wgpu::Extent3d { width: 8, height: 8, depth_or_array_layers: 1 } - /// ); - /// let format = wgpu::TextureFormat::Astc8x5RgbaUnorm; // 8x5 blocks - /// assert_eq!( - /// wgpu::Extent3d { width: 7, height: 7, depth_or_array_layers: 1 }.physical_size(format), - /// wgpu::Extent3d { width: 8, height: 10, depth_or_array_layers: 1 } - /// ); - /// ``` - /// /// [physical size]: https://gpuweb.github.io/gpuweb/#physical-size pub fn physical_size(&self, format: TextureFormat) -> Self { let (block_width, block_height) = format.describe().block_dimensions; @@ -2887,16 +2868,18 @@ impl Extent3d { /// /// Treats the depth as part of the mipmaps. If calculating /// for a 2DArray texture, which does not mipmap depth, set depth to 1. - /// - /// ```rust - /// # use wgpu_types as wgpu; - /// assert_eq!(wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 }.max_mips(), 1); - /// assert_eq!(wgpu::Extent3d { width: 60, height: 60, depth_or_array_layers: 1 }.max_mips(), 6); - /// assert_eq!(wgpu::Extent3d { width: 240, height: 1, depth_or_array_layers: 1 }.max_mips(), 8); - /// ``` - pub fn max_mips(&self) -> u32 { - let max_dim = self.width.max(self.height.max(self.depth_or_array_layers)); - 32 - max_dim.leading_zeros() + pub fn max_mips(&self, dim: TextureDimension) -> u32 { + match dim { + TextureDimension::D1 => 1, + TextureDimension::D2 => { + let max_dim = self.width.max(self.height); + 32 - max_dim.leading_zeros() + } + TextureDimension::D3 => { + let max_dim = self.width.max(self.height.max(self.depth_or_array_layers)); + 32 - max_dim.leading_zeros() + } + } } /// Calculates the extent at a given mip level. @@ -2913,6 +2896,104 @@ impl Extent3d { } } +#[test] +fn test_physical_size() { + let format = TextureFormat::Bc1RgbaUnormSrgb; // 4x4 blocks + assert_eq!( + Extent3d { + width: 7, + height: 7, + depth_or_array_layers: 1 + } + .physical_size(format), + Extent3d { + width: 8, + height: 8, + depth_or_array_layers: 1 + } + ); + // Doesn't change, already aligned + assert_eq!( + Extent3d { + width: 8, + height: 8, + depth_or_array_layers: 1 + } + .physical_size(format), + Extent3d { + width: 8, + height: 8, + depth_or_array_layers: 1 + } + ); + let format = TextureFormat::Astc8x5RgbaUnorm; // 8x5 blocks + assert_eq!( + Extent3d { + width: 7, + height: 7, + depth_or_array_layers: 1 + } + .physical_size(format), + Extent3d { + width: 8, + height: 10, + depth_or_array_layers: 1 + } + ); +} + +#[test] +fn test_max_mips() { + // 1D + assert_eq!( + Extent3d { + width: 240, + height: 1, + depth_or_array_layers: 1 + } + .max_mips(TextureDimension::D1), + 1 + ); + // 2D + assert_eq!( + Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1 + } + .max_mips(TextureDimension::D2), + 1 + ); + assert_eq!( + Extent3d { + width: 60, + height: 60, + depth_or_array_layers: 1 + } + .max_mips(TextureDimension::D2), + 6 + ); + assert_eq!( + Extent3d { + width: 240, + height: 1, + depth_or_array_layers: 1000 + } + .max_mips(TextureDimension::D2), + 8 + ); + // 3D + assert_eq!( + Extent3d { + width: 16, + height: 30, + depth_or_array_layers: 60 + } + .max_mips(TextureDimension::D3), + 6 + ); +} + /// Describes a [`Texture`]. #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index ac3ed8d565..d569d9d1ff 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -295,7 +295,7 @@ impl framework::Example for Skybox { depth_or_array_layers: 1, ..size }; - let max_mips = layer_size.max_mips(); + let max_mips = layer_size.max_mips(wgpu::TextureDimension::D2); log::debug!( "Copying {:?} skybox images of size {}, {}, 6 with {} mips to gpu",