diff --git a/cts_runner/test.lst b/cts_runner/test.lst index b8cd5f679..b45529e38 100644 --- a/cts_runner/test.lst +++ b/cts_runner/test.lst @@ -126,9 +126,7 @@ fails-if(dx12) webgpu:api,validation,image_copy,layout_related:offset_alignment: webgpu:api,validation,image_copy,texture_related:format:dimension="1d";* webgpu:api,validation,queue,submit:command_buffer,* webgpu:api,validation,render_pass,render_pass_descriptor:attachments,* -webgpu:api,validation,render_pass,render_pass_descriptor:color_attachments,depthSlice,bound_check:* -// Fails due to missing validation. -// FAIL: webgpu:api,validation,render_pass,render_pass_descriptor:color_attachments,depthSlice,overlaps,diff_miplevel:* +webgpu:api,validation,render_pass,render_pass_descriptor:color_attachments,depthSlice,* webgpu:api,validation,render_pass,render_pass_descriptor:resolveTarget,* webgpu:api,validation,render_pass,resolve:resolve_attachment:* webgpu:api,validation,resource_usages,buffer,in_pass_encoder:* @@ -141,6 +139,7 @@ webgpu:api,validation,resource_usages,texture,in_pass_encoder:unused_bindings_in webgpu:api,validation,resource_usages,texture,in_render_common:subresources,multiple_bind_groups:bg0Levels={"base":0,"count":1};* webgpu:api,validation,texture,rg11b10ufloat_renderable:* webgpu:api,operation,render_pipeline,overrides:* +webgpu:api,operation,rendering,3d_texture_slices:* webgpu:api,operation,rendering,basic:clear:* webgpu:api,operation,rendering,basic:fullscreen_quad:* //FAIL: webgpu:api,operation,rendering,basic:large_draw:* diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 39dc2026b..08bfb5cd0 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1360,8 +1360,25 @@ impl Device { } } + let mips = desc.mip_level_count; + let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS); + if mips == 0 || mips > max_levels_allowed { + return Err(CreateTextureError::InvalidMipLevelCount { + requested: mips, + maximum: max_levels_allowed, + }); + } + { - let (width_multiple, height_multiple) = desc.format.size_multiple_requirement(); + let (mut width_multiple, mut height_multiple) = desc.format.size_multiple_requirement(); + + if desc.format.is_multi_planar_format() { + // TODO(https://github.com/gfx-rs/wgpu/issues/8491): fix + // `mip_level_size` calculation for these formats and relax this + // restriction. + width_multiple <<= desc.mip_level_count.saturating_sub(1); + height_multiple <<= desc.mip_level_count.saturating_sub(1); + } if desc.size.width % width_multiple != 0 { return Err(CreateTextureError::InvalidDimension( @@ -1456,15 +1473,6 @@ impl Device { }; } - let mips = desc.mip_level_count; - let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS); - if mips == 0 || mips > max_levels_allowed { - return Err(CreateTextureError::InvalidMipLevelCount { - requested: mips, - maximum: max_levels_allowed, - }); - } - let missing_allowed_usages = match desc.format.planes() { Some(planes) => { let mut planes_usages = wgt::TextureUsages::all(); diff --git a/wgpu-info/src/texture.rs b/wgpu-info/src/texture.rs index 883a827a0..402ac88ec 100644 --- a/wgpu-info/src/texture.rs +++ b/wgpu-info/src/texture.rs @@ -158,6 +158,56 @@ fn test_compute_render_extent() { let _ = desc.compute_render_extent(0, None); } } + + for format in [wgpu::TextureFormat::NV12, wgpu::TextureFormat::P010] { + let desc = wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: 8, + height: 4, + depth_or_array_layers: 1, + }, + mip_level_count: 2, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: wgpu::TextureUsages::empty(), + view_formats: &[], + }; + + assert_eq!( + desc.compute_render_extent(0, Some(0)), + wgpu::Extent3d { + width: 8, + height: 4, + depth_or_array_layers: 1, + } + ); + assert_eq!( + desc.compute_render_extent(0, Some(1)), + wgpu::Extent3d { + width: 4, + height: 2, + depth_or_array_layers: 1, + } + ); + assert_eq!( + desc.compute_render_extent(1, Some(0)), + wgpu::Extent3d { + width: 4, + height: 2, + depth_or_array_layers: 1, + } + ); + assert_eq!( + desc.compute_render_extent(1, Some(1)), + wgpu::Extent3d { + width: 2, + height: 1, + depth_or_array_layers: 1, + } + ); + } } pub fn max_texture_format_string_size() -> usize { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 2187bf674..33d2bf1eb 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2881,6 +2881,20 @@ impl TextureFormat { } } + /// Returns the subsampling factor for the indicated plane of a multi-planar format. + #[must_use] + pub fn subsampling_factors(&self, plane: Option) -> (u32, u32) { + match *self { + Self::NV12 | Self::P010 => match plane { + Some(0) => (1, 1), + Some(1) => (2, 2), + Some(plane) => unreachable!("plane {plane} is not valid for {self:?}"), + None => unreachable!("the plane must be specified for multi-planar formats"), + }, + _ => (1, 1), + } + } + /// Returns `true` if the format has a color aspect #[must_use] pub fn has_color_aspect(&self) -> bool { @@ -2910,6 +2924,10 @@ impl TextureFormat { } /// Returns the size multiple requirement for a texture using this format. + /// + /// `create_texture` currently enforces a stricter restriction than this for + /// mipmapped multi-planar formats. + /// TODO(): Remove this note. #[must_use] pub fn size_multiple_requirement(&self) -> (u32, u32) { match *self { @@ -6186,9 +6204,17 @@ impl Extent3d { } /// Calculates the extent at a given mip level. - /// Does *not* account for memory size being a multiple of block size. + /// + /// This is a low-level helper for internal use. + /// + /// It does *not* account for memory size being a multiple of block size. + /// + /// TODO(): It also does not + /// consider whether an even dimension is required due to chroma + /// subsampling, but it probably should. /// /// + #[doc(hidden)] #[must_use] pub fn mip_level_size(&self, level: u32, dim: TextureDimension) -> Self { Self { @@ -6459,20 +6485,26 @@ impl TextureDescriptor { /// Computes the render extent of this texture. /// + /// This is a low-level helper exported for use by wgpu-core. + /// /// + /// + /// # Panics + /// + /// If the mip level is out of range. + #[doc(hidden)] #[must_use] pub fn compute_render_extent(&self, mip_level: u32, plane: Option) -> Extent3d { - let width = self.size.width >> mip_level; - let height = self.size.height >> mip_level; + let Extent3d { + width, + height, + depth_or_array_layers: _, + } = self.mip_level_size(mip_level).expect("invalid mip level"); - let (width, height) = match (self.format, plane) { - (TextureFormat::NV12 | TextureFormat::P010, Some(0)) => (width, height), - (TextureFormat::NV12 | TextureFormat::P010, Some(1)) => (width / 2, height / 2), - _ => { - debug_assert!(!self.format.is_multi_planar_format()); - (width, height) - } - }; + let (w_subsampling, h_subsampling) = self.format.subsampling_factors(plane); + + let width = width / w_subsampling; + let height = height / h_subsampling; Extent3d { width,