From 0cbabcf22971e995f04cdb8ebe9c85d791b9f9a2 Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:06:56 +0100 Subject: [PATCH] Update multi-planar texture API (#4837) --- deno_webgpu/texture.rs | 1 - examples/src/mipmap/mod.rs | 1 - examples/src/shadow/mod.rs | 1 - tests/tests/bgra8unorm_storage.rs | 1 - tests/tests/nv12_texture/mod.rs | 41 ++------- wgpu-core/src/command/clear.rs | 5 +- wgpu-core/src/device/resource.rs | 83 +++++++---------- wgpu-core/src/present.rs | 1 - wgpu-core/src/resource.rs | 29 +++--- wgpu-hal/examples/halmark/main.rs | 2 - wgpu-hal/examples/raw-gles.rs | 1 - wgpu-hal/examples/ray-traced-triangle/main.rs | 2 - wgpu-hal/src/auxil/dxgi/conv.rs | 6 +- wgpu-hal/src/dx12/command.rs | 9 ++ wgpu-hal/src/dx12/device.rs | 6 +- wgpu-hal/src/dx12/mod.rs | 1 + wgpu-hal/src/dx12/view.rs | 24 +++-- wgpu-hal/src/lib.rs | 15 ++- wgpu-hal/src/metal/device.rs | 2 +- wgpu-hal/src/vulkan/adapter.rs | 57 +++++++++--- wgpu-hal/src/vulkan/conv.rs | 32 +++---- wgpu-hal/src/vulkan/device.rs | 10 +- wgpu-types/src/lib.rs | 92 +++++++++++++++---- wgpu/src/backend/direct.rs | 1 - wgpu/src/backend/web.rs | 3 + wgpu/src/lib.rs | 2 - 26 files changed, 247 insertions(+), 181 deletions(-) diff --git a/deno_webgpu/texture.rs b/deno_webgpu/texture.rs index fb9640f59..5eadd5b3c 100644 --- a/deno_webgpu/texture.rs +++ b/deno_webgpu/texture.rs @@ -124,7 +124,6 @@ pub fn op_webgpu_create_texture_view( format: args.format, dimension: args.dimension, range: args.range, - plane: None, }; gfx_put!(texture => instance.texture_create_view( diff --git a/examples/src/mipmap/mod.rs b/examples/src/mipmap/mod.rs index 59c9aab4d..c6dc7fa25 100644 --- a/examples/src/mipmap/mod.rs +++ b/examples/src/mipmap/mod.rs @@ -133,7 +133,6 @@ impl Example { mip_level_count: Some(1), base_array_layer: 0, array_layer_count: None, - ..Default::default() }) }) .collect::>(); diff --git a/examples/src/shadow/mod.rs b/examples/src/shadow/mod.rs index 3c4aa8806..485d0d78d 100644 --- a/examples/src/shadow/mod.rs +++ b/examples/src/shadow/mod.rs @@ -398,7 +398,6 @@ impl crate::framework::Example for Example { mip_level_count: None, base_array_layer: i as u32, array_layer_count: Some(1), - ..Default::default() })) }) .collect::>(); diff --git a/tests/tests/bgra8unorm_storage.rs b/tests/tests/bgra8unorm_storage.rs index 942b6c5a8..91f7b4928 100644 --- a/tests/tests/bgra8unorm_storage.rs +++ b/tests/tests/bgra8unorm_storage.rs @@ -49,7 +49,6 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() base_array_layer: 0, mip_level_count: Some(1), array_layer_count: Some(1), - ..Default::default() }); let readback_buffer = device.create_buffer(&wgpu::BufferDescriptor { diff --git a/tests/tests/nv12_texture/mod.rs b/tests/tests/nv12_texture/mod.rs index 0d9b4b5d4..aba12e02b 100644 --- a/tests/tests/nv12_texture/mod.rs +++ b/tests/tests/nv12_texture/mod.rs @@ -49,16 +49,16 @@ static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati usage: wgpu::TextureUsages::TEXTURE_BINDING, mip_level_count: 1, sample_count: 1, - view_formats: &[wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::Rg8Unorm], + view_formats: &[], }); let y_view = tex.create_view(&wgpu::TextureViewDescriptor { format: Some(wgpu::TextureFormat::R8Unorm), - plane: Some(0), + aspect: wgpu::TextureAspect::Plane0, ..Default::default() }); let uv_view = tex.create_view(&wgpu::TextureViewDescriptor { format: Some(wgpu::TextureFormat::Rg8Unorm), - plane: Some(1), + aspect: wgpu::TextureAspect::Plane1, ..Default::default() }); let sampler = ctx.device.create_sampler(&wgpu::SamplerDescriptor { @@ -118,29 +118,6 @@ static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfigurati ctx.queue.submit(Some(encoder.finish())); }); -#[gpu_test] -static NV12_TEXTURE_CREATION_BAD_VIEW_FORMATS: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters(TestParameters::default().features(wgpu::Features::TEXTURE_FORMAT_NV12)) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 256, - height: 256, - depth_or_array_layers: 1, - }; - fail(&ctx.device, || { - let _ = ctx.device.create_texture(&wgpu::TextureDescriptor { - label: None, - dimension: wgpu::TextureDimension::D2, - size, - format: wgpu::TextureFormat::NV12, - usage: wgpu::TextureUsages::TEXTURE_BINDING, - mip_level_count: 1, - sample_count: 1, - view_formats: &[wgpu::TextureFormat::Rgba8Unorm], - }); - }); - }); - #[gpu_test] static NV12_TEXTURE_VIEW_PLANE_ON_NON_PLANAR_FORMAT: GpuTestConfiguration = GpuTestConfiguration::new() @@ -163,7 +140,7 @@ static NV12_TEXTURE_VIEW_PLANE_ON_NON_PLANAR_FORMAT: GpuTestConfiguration = }); fail(&ctx.device, || { let _ = tex.create_view(&wgpu::TextureViewDescriptor { - plane: Some(0), + aspect: wgpu::TextureAspect::Plane0, ..Default::default() }); }); @@ -186,12 +163,12 @@ static NV12_TEXTURE_VIEW_PLANE_OUT_OF_BOUNDS: GpuTestConfiguration = GpuTestConf usage: wgpu::TextureUsages::TEXTURE_BINDING, mip_level_count: 1, sample_count: 1, - view_formats: &[wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::Rg8Unorm], + view_formats: &[], }); fail(&ctx.device, || { let _ = tex.create_view(&wgpu::TextureViewDescriptor { format: Some(wgpu::TextureFormat::R8Unorm), - plane: Some(2), + aspect: wgpu::TextureAspect::Plane2, ..Default::default() }); }); @@ -214,12 +191,12 @@ static NV12_TEXTURE_BAD_FORMAT_VIEW_PLANE: GpuTestConfiguration = GpuTestConfigu usage: wgpu::TextureUsages::TEXTURE_BINDING, mip_level_count: 1, sample_count: 1, - view_formats: &[wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::Rg8Unorm], + view_formats: &[], }); fail(&ctx.device, || { let _ = tex.create_view(&wgpu::TextureViewDescriptor { format: Some(wgpu::TextureFormat::Rg8Unorm), - plane: Some(0), + aspect: wgpu::TextureAspect::Plane0, ..Default::default() }); }); @@ -244,7 +221,7 @@ static NV12_TEXTURE_BAD_SIZE: GpuTestConfiguration = GpuTestConfiguration::new() usage: wgpu::TextureUsages::TEXTURE_BINDING, mip_level_count: 1, sample_count: 1, - view_formats: &[wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::Rg8Unorm], + view_formats: &[], }); }); }); diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 620911c18..d2dd1bbe1 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -332,10 +332,7 @@ fn clear_texture_via_buffer_copies( encoder: &mut A::CommandEncoder, dst_raw: &A::Texture, ) { - assert_eq!( - hal::FormatAspects::from(texture_desc.format), - hal::FormatAspects::COLOR - ); + assert!(!texture_desc.format.is_depth_stencil_format()); if texture_desc.format == wgt::TextureFormat::NV12 { // TODO: Currently COPY_DST for NV12 textures is unsupported. diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 815cdd80a..a3dd162bf 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -666,6 +666,30 @@ impl Device { } } + { + let (width_multiple, height_multiple) = desc.format.size_multiple_requirement(); + + if desc.size.width % width_multiple != 0 { + return Err(CreateTextureError::InvalidDimension( + TextureDimensionError::WidthNotMultipleOf { + width: desc.size.width, + multiple: width_multiple, + format: desc.format, + }, + )); + } + + if desc.size.height % height_multiple != 0 { + return Err(CreateTextureError::InvalidDimension( + TextureDimensionError::HeightNotMultipleOf { + height: desc.size.height, + multiple: height_multiple, + format: desc.format, + }, + )); + } + } + let format_features = self .describe_format_features(adapter, desc.format) .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?; @@ -751,8 +775,7 @@ impl Device { if desc.format == *format { continue; } - - if !check_texture_view_format_compatible(desc.format, *format) { + if desc.format.remove_srgb_suffix() != format.remove_srgb_suffix() { return Err(CreateTextureError::InvalidViewFormat(*format, desc.format)); } hal_view_formats.push(*format); @@ -806,20 +829,19 @@ impl Device { for mip_level in 0..desc.mip_level_count { for array_layer in 0..desc.size.depth_or_array_layers { macro_rules! push_clear_view { - ($format:expr, $plane:expr) => { + ($format:expr, $aspect:expr) => { let desc = hal::TextureViewDescriptor { label: clear_label, format: $format, dimension, usage, range: wgt::ImageSubresourceRange { - aspect: wgt::TextureAspect::All, + aspect: $aspect, base_mip_level: mip_level, mip_level_count: Some(1), base_array_layer: array_layer, array_layer_count: Some(1), }, - plane: $plane, }; clear_views.push(Some( unsafe { self.raw().create_texture_view(&raw_texture, &desc) } @@ -828,11 +850,14 @@ impl Device { }; } - if desc.format == wgt::TextureFormat::NV12 { - push_clear_view!(wgt::TextureFormat::R8Unorm, Some(0)); - push_clear_view!(wgt::TextureFormat::Rg8Unorm, Some(1)); + if let Some(planes) = desc.format.planes() { + for plane in 0..planes { + let aspect = wgt::TextureAspect::from_plane(plane).unwrap(); + let format = desc.format.aspect_specific_format(aspect).unwrap(); + push_clear_view!(format, aspect); + } } else { - push_clear_view!(desc.format, None); + push_clear_view!(desc.format, wgt::TextureAspect::All); } } } @@ -1028,8 +1053,6 @@ impl Device { }); }; - validate_texture_view_plane(texture.desc.format, resolved_format, desc.plane)?; - // https://gpuweb.github.io/gpuweb/#abstract-opdef-renderable-texture-view let render_extent = 'b: loop { if !texture @@ -1121,7 +1144,6 @@ impl Device { dimension: resolved_dimension, usage, range: resolved_range, - plane: desc.plane, }; let raw = unsafe { @@ -1142,6 +1164,7 @@ impl Device { parent: RwLock::new(Some(texture.clone())), device: self.clone(), desc: resource::HalTextureViewDescriptor { + texture_format: texture.desc.format, format: resolved_format, dimension: resolved_dimension, range: resolved_range, @@ -3383,39 +3406,3 @@ impl Resource for Device { &mut self.info } } - -fn check_texture_view_format_compatible( - texture_format: TextureFormat, - view_format: TextureFormat, -) -> bool { - use TextureFormat::*; - - match (texture_format, view_format) { - (NV12, R8Unorm | R8Uint | Rg8Unorm | Rg8Uint) => true, - _ => texture_format.remove_srgb_suffix() == view_format.remove_srgb_suffix(), - } -} - -fn validate_texture_view_plane( - texture_format: TextureFormat, - view_format: TextureFormat, - plane: Option, -) -> Result<(), resource::CreateTextureViewError> { - use TextureFormat::*; - - match (texture_format, view_format, plane) { - (NV12, R8Unorm | R8Uint, Some(0)) => Ok(()), - (NV12, Rg8Unorm | Rg8Uint, Some(1)) => Ok(()), - (NV12, _, _) => { - Err(resource::CreateTextureViewError::InvalidTextureViewPlane { plane, view_format }) - } - - (_, _, Some(_)) => Err( - resource::CreateTextureViewError::InvalidTextureViewPlaneOnNonplanarTexture { - plane, - texture_format, - }, - ), - _ => Ok(()), - } -} diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 0e0ca9a1a..4c2a042b1 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -202,7 +202,6 @@ impl Global { dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::COLOR_TARGET, range: wgt::ImageSubresourceRange::default(), - plane: None, }; let clear_view = unsafe { hal::Device::create_texture_view( diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index db9a376d4..587b47920 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -892,6 +892,20 @@ pub enum TextureDimensionError { block_height: u32, format: wgt::TextureFormat, }, + #[error( + "Width {width} is not a multiple of {format:?}'s width multiple requirement ({multiple})" + )] + WidthNotMultipleOf { + width: u32, + multiple: u32, + format: wgt::TextureFormat, + }, + #[error("Height {height} is not a multiple of {format:?}'s height multiple requirement ({multiple})")] + HeightNotMultipleOf { + height: u32, + multiple: u32, + format: wgt::TextureFormat, + }, #[error("Multisampled texture depth or array layers must be 1, got {0}")] MultisampledDepthOrArrayLayer(u32), } @@ -978,12 +992,11 @@ pub struct TextureViewDescriptor<'a> { pub dimension: Option, /// Range within the texture that is accessible via this view. pub range: wgt::ImageSubresourceRange, - /// The plane of the texture view. - pub plane: Option, } #[derive(Debug)] pub(crate) struct HalTextureViewDescriptor { + pub texture_format: wgt::TextureFormat, pub format: wgt::TextureFormat, pub dimension: wgt::TextureViewDimension, pub range: wgt::ImageSubresourceRange, @@ -991,7 +1004,7 @@ pub(crate) struct HalTextureViewDescriptor { impl HalTextureViewDescriptor { pub fn aspects(&self) -> hal::FormatAspects { - hal::FormatAspects::new(self.format, self.range.aspect) + hal::FormatAspects::new(self.texture_format, self.range.aspect) } } @@ -1090,16 +1103,6 @@ pub enum CreateTextureViewError { texture: wgt::TextureFormat, view: wgt::TextureFormat, }, - #[error("Invalid texture view plane `{plane:?}` with view format `{view_format:?}`")] - InvalidTextureViewPlane { - plane: Option, - view_format: wgt::TextureFormat, - }, - #[error("Invalid texture view plane `{plane:?}` on non-planar texture `{texture_format:?}`")] - InvalidTextureViewPlaneOnNonplanarTexture { - plane: Option, - texture_format: wgt::TextureFormat, - }, } #[derive(Clone, Debug, Error)] diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index ea1e7648e..18f283d8e 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -422,7 +422,6 @@ impl Example { dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::RESOURCE, range: wgt::ImageSubresourceRange::default(), - plane: None, }; let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() }; @@ -661,7 +660,6 @@ impl Example { dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::COLOR_TARGET, range: wgt::ImageSubresourceRange::default(), - plane: None, }; let surface_tex_view = unsafe { self.device diff --git a/wgpu-hal/examples/raw-gles.rs b/wgpu-hal/examples/raw-gles.rs index 71e08443e..81ab4171e 100644 --- a/wgpu-hal/examples/raw-gles.rs +++ b/wgpu-hal/examples/raw-gles.rs @@ -142,7 +142,6 @@ fn fill_screen(exposed: &hal::ExposedAdapter, width: u32, height dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::COLOR_TARGET, range: wgt::ImageSubresourceRange::default(), - plane: None, }, ) .unwrap() diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 7202b35be..6454cb899 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -555,7 +555,6 @@ impl Example { dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::STORAGE_READ_WRITE | hal::TextureUses::COPY_SRC, range: wgt::ImageSubresourceRange::default(), - plane: None, }; let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() }; @@ -888,7 +887,6 @@ impl Example { dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::COPY_DST, range: wgt::ImageSubresourceRange::default(), - plane: None, }; let surface_tex_view = unsafe { self.device diff --git a/wgpu-hal/src/auxil/dxgi/conv.rs b/wgpu-hal/src/auxil/dxgi/conv.rs index eb74b5adf..6af4b77bb 100644 --- a/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/wgpu-hal/src/auxil/dxgi/conv.rs @@ -140,9 +140,11 @@ pub fn map_texture_format_for_srv_uav( crate::FormatAspects::STENCIL, ) => dxgiformat::DXGI_FORMAT_X24_TYPELESS_G8_UINT, - (format, crate::FormatAspects::COLOR) => map_texture_format(format), + (_, crate::FormatAspects::DEPTH) + | (_, crate::FormatAspects::STENCIL) + | (_, crate::FormatAspects::DEPTH_STENCIL) => return None, - _ => return None, + _ => map_texture_format(format), }) } diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 81f0fbccc..c5d0d16b2 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -415,6 +415,15 @@ impl crate::CommandEncoder for super::CommandEncoder { wgt::TextureAspect::All => 0..2, wgt::TextureAspect::DepthOnly => 0..1, wgt::TextureAspect::StencilOnly => 1..2, + _ => unreachable!(), + } + } else if let Some(planes) = barrier.texture.format.planes() { + match barrier.range.aspect { + wgt::TextureAspect::All => 0..planes, + wgt::TextureAspect::Plane0 => 0..1, + wgt::TextureAspect::Plane1 => 1..2, + wgt::TextureAspect::Plane2 => 2..3, + _ => unreachable!(), } } else { match barrier.texture.format { diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 9f6133592..daf14bf71 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -467,11 +467,7 @@ impl crate::Device for super::Device { aspects: view_desc.aspects, target_base: ( texture.resource.clone(), - texture.calc_subresource( - desc.range.base_mip_level, - desc.range.base_array_layer, - desc.plane.unwrap_or(0), - ), + texture.calc_subresource(desc.range.base_mip_level, desc.range.base_array_layer, 0), ), handle_srv: if desc.usage.intersects(crate::TextureUses::RESOURCE) { let raw_desc = unsafe { view_desc.to_srv() }; diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 4ae224f5f..2d42d5faa 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -456,6 +456,7 @@ impl Texture { pub struct TextureView { raw_format: d3d12::Format, aspects: crate::FormatAspects, + /// only used by resolve target_base: (d3d12::Resource, u32), handle_srv: Option, handle_uav: Option, diff --git a/wgpu-hal/src/dx12/view.rs b/wgpu-hal/src/dx12/view.rs index 9a597e464..6cbad7bd1 100644 --- a/wgpu-hal/src/dx12/view.rs +++ b/wgpu-hal/src/dx12/view.rs @@ -14,12 +14,11 @@ pub(super) struct ViewDescriptor { array_layer_count: u32, mip_level_base: u32, mip_level_count: u32, - plane: u32, } impl crate::TextureViewDescriptor<'_> { pub(super) fn to_internal(&self, texture: &super::Texture) -> ViewDescriptor { - let aspects = crate::FormatAspects::new(self.format, self.range.aspect); + let aspects = crate::FormatAspects::new(texture.format, self.range.aspect); ViewDescriptor { dimension: self.dimension, @@ -31,11 +30,18 @@ impl crate::TextureViewDescriptor<'_> { mip_level_count: self.range.mip_level_count.unwrap_or(!0), array_layer_base: self.range.base_array_layer, array_layer_count: self.range.array_layer_count.unwrap_or(!0), - plane: self.plane.unwrap_or(0), } } } +fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 { + match aspects { + crate::FormatAspects::PLANE_1 => 1, + crate::FormatAspects::PLANE_2 => 2, + _ => 0, + } +} + impl ViewDescriptor { pub(crate) unsafe fn to_srv(&self) -> Option { let mut desc = d3d12_ty::D3D12_SHADER_RESOURCE_VIEW_DESC { @@ -81,7 +87,7 @@ impl ViewDescriptor { *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_SRV { MostDetailedMip: self.mip_level_base, MipLevels: self.mip_level_count, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), ResourceMinLODClamp: 0.0, } } @@ -105,7 +111,7 @@ impl ViewDescriptor { MipLevels: self.mip_level_count, FirstArraySlice: self.array_layer_base, ArraySize: self.array_layer_count, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), ResourceMinLODClamp: 0.0, } } @@ -181,7 +187,7 @@ impl ViewDescriptor { unsafe { *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_UAV { MipSlice: self.mip_level_base, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), } } } @@ -192,7 +198,7 @@ impl ViewDescriptor { MipSlice: self.mip_level_base, FirstArraySlice: self.array_layer_base, ArraySize: self.array_layer_count, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), } } } @@ -252,7 +258,7 @@ impl ViewDescriptor { unsafe { *desc.u.Texture2D_mut() = d3d12_ty::D3D12_TEX2D_RTV { MipSlice: self.mip_level_base, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), } } } @@ -274,7 +280,7 @@ impl ViewDescriptor { MipSlice: self.mip_level_base, FirstArraySlice: self.array_layer_base, ArraySize: self.array_layer_count, - PlaneSlice: self.plane, + PlaneSlice: aspects_to_plane(self.aspects), } } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index d312566e5..39037e895 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -725,6 +725,11 @@ bitflags!( const COLOR = 1 << 0; const DEPTH = 1 << 1; const STENCIL = 1 << 2; + const PLANE_0 = 1 << 3; + const PLANE_1 = 1 << 4; + const PLANE_2 = 1 << 5; + + const DEPTH_STENCIL = Self::DEPTH.bits() | Self::STENCIL.bits(); } ); @@ -734,6 +739,9 @@ impl FormatAspects { wgt::TextureAspect::All => Self::all(), wgt::TextureAspect::DepthOnly => Self::DEPTH, wgt::TextureAspect::StencilOnly => Self::STENCIL, + wgt::TextureAspect::Plane0 => Self::PLANE_0, + wgt::TextureAspect::Plane1 => Self::PLANE_1, + wgt::TextureAspect::Plane2 => Self::PLANE_2, }; Self::from(format) & aspect_mask } @@ -748,6 +756,9 @@ impl FormatAspects { Self::COLOR => wgt::TextureAspect::All, Self::DEPTH => wgt::TextureAspect::DepthOnly, Self::STENCIL => wgt::TextureAspect::StencilOnly, + Self::PLANE_0 => wgt::TextureAspect::Plane0, + Self::PLANE_1 => wgt::TextureAspect::Plane1, + Self::PLANE_2 => wgt::TextureAspect::Plane2, _ => unreachable!(), } } @@ -761,8 +772,9 @@ impl From for FormatAspects { | wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth24Plus => Self::DEPTH, wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24PlusStencil8 => { - Self::DEPTH | Self::STENCIL + Self::DEPTH_STENCIL } + wgt::TextureFormat::NV12 => Self::PLANE_0 | Self::PLANE_1, _ => Self::COLOR, } } @@ -1013,7 +1025,6 @@ pub struct TextureViewDescriptor<'a> { pub dimension: wgt::TextureViewDimension, pub usage: TextureUses, pub range: wgt::ImageSubresourceRange, - pub plane: Option, } #[derive(Clone, Debug)] diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 6a387dd57..d7fd06c8f 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -396,7 +396,7 @@ impl crate::Device for super::Device { conv::map_texture_view_dimension(desc.dimension) }; - let aspects = crate::FormatAspects::new(desc.format, desc.range.aspect); + let aspects = crate::FormatAspects::new(texture.format, desc.range.aspect); let raw_format = self .shared diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index a9eaf8b60..b4e3cd0ba 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -30,6 +30,7 @@ pub struct PhysicalDeviceFeatures { image_robustness: Option, robustness2: Option, multiview: Option, + sampler_ycbcr_conversion: Option, astc_hdr: Option, shader_float16: Option<( vk::PhysicalDeviceShaderFloat16Int8Features, @@ -273,6 +274,17 @@ impl PhysicalDeviceFeatures { } else { None }, + sampler_ycbcr_conversion: if device_api_version >= vk::API_VERSION_1_1 + || enabled_extensions.contains(&vk::KhrSamplerYcbcrConversionFn::name()) + { + Some( + vk::PhysicalDeviceSamplerYcbcrConversionFeatures::builder() + // .sampler_ycbcr_conversion(requested_features.contains(wgt::Features::TEXTURE_FORMAT_NV12)) + .build(), + ) + } else { + None + }, astc_hdr: if enabled_extensions.contains(&vk::ExtTextureCompressionAstcHdrFn::name()) { Some( vk::PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT::builder() @@ -344,7 +356,6 @@ impl PhysicalDeviceFeatures { fn to_wgpu( &self, - adapter_info: &wgt::AdapterInfo, instance: &ash::Instance, phd: vk::PhysicalDevice, caps: &PhysicalDeviceCapabilities, @@ -595,11 +606,11 @@ impl PhysicalDeviceFeatures { F::FLOAT32_FILTERABLE, is_float32_filterable_supported(instance, phd), ); - features.set( - F::TEXTURE_FORMAT_NV12, - (caps.device_api_version >= vk::API_VERSION_1_1 - || caps.supports_extension(vk::KhrSamplerYcbcrConversionFn::name())) - && supports_format( + + if let Some(ref _sampler_ycbcr_conversion) = self.sampler_ycbcr_conversion { + features.set( + F::TEXTURE_FORMAT_NV12, + supports_format( instance, phd, vk::Format::G8_B8R8_2PLANE_420_UNORM, @@ -607,9 +618,12 @@ impl PhysicalDeviceFeatures { vk::FormatFeatureFlags::SAMPLED_IMAGE | vk::FormatFeatureFlags::TRANSFER_SRC | vk::FormatFeatureFlags::TRANSFER_DST, - ) - && !adapter_info.driver.contains("MoltenVK"), - ); + ) && !caps + .driver + .map(|driver| driver.driver_id == vk::DriverId::MOLTENVK) + .unwrap_or_default(), + ); + } (features, dl_flags) } @@ -693,6 +707,11 @@ impl PhysicalDeviceCapabilities { if requested_features.contains(wgt::Features::MULTIVIEW) { extensions.push(vk::KhrMultiviewFn::name()); } + + // Require `VK_KHR_sampler_ycbcr_conversion` if the associated feature was requested + if requested_features.contains(wgt::Features::TEXTURE_FORMAT_NV12) { + extensions.push(vk::KhrSamplerYcbcrConversionFn::name()); + } } if self.device_api_version < vk::API_VERSION_1_2 { @@ -944,6 +963,16 @@ impl super::InstanceShared { builder = builder.push_next(next); } + // `VK_KHR_sampler_ycbcr_conversion` is promoted to 1.1 + if capabilities.device_api_version >= vk::API_VERSION_1_1 + || capabilities.supports_extension(vk::KhrSamplerYcbcrConversionFn::name()) + { + let next = features + .sampler_ycbcr_conversion + .insert(vk::PhysicalDeviceSamplerYcbcrConversionFeatures::default()); + builder = builder.push_next(next); + } + if capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name()) { let next = features .descriptor_indexing @@ -1074,7 +1103,7 @@ impl super::Instance { }; let (available_features, downlevel_flags) = - phd_features.to_wgpu(&info, &self.shared.raw, phd, &phd_capabilities); + phd_features.to_wgpu(&self.shared.raw, phd, &phd_capabilities); let mut workarounds = super::Workarounds::empty(); { // TODO: only enable for particular devices @@ -1671,14 +1700,14 @@ impl crate::Adapter for super::Adapter { .framebuffer_stencil_sample_counts .min(limits.sampled_image_stencil_sample_counts) } else { - match format.sample_type(None, None) { - Some(wgt::TextureSampleType::Float { .. }) => limits + match format.sample_type(None, None).unwrap() { + wgt::TextureSampleType::Float { .. } => limits .framebuffer_color_sample_counts .min(limits.sampled_image_color_sample_counts), - Some(wgt::TextureSampleType::Sint) | Some(wgt::TextureSampleType::Uint) => { + wgt::TextureSampleType::Sint | wgt::TextureSampleType::Uint => { limits.sampled_image_integer_sample_counts } - _ => vk::SampleCountFlags::TYPE_1, + _ => unreachable!(), } }; diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 826da9141..15fe5de3c 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -222,7 +222,7 @@ pub fn derive_image_layout( format: wgt::TextureFormat, ) -> vk::ImageLayout { // Note: depth textures are always sampled with RODS layout - let is_color = crate::FormatAspects::from(format).contains(crate::FormatAspects::COLOR); + let is_color = !format.is_depth_stencil_format(); match usage { crate::TextureUses::UNINITIALIZED => vk::ImageLayout::UNDEFINED, crate::TextureUses::COPY_SRC => vk::ImageLayout::TRANSFER_SRC_OPTIMAL, @@ -402,18 +402,10 @@ pub fn map_vertex_format(vertex_format: wgt::VertexFormat) -> vk::Format { } } -pub fn map_aspects(aspects: crate::FormatAspects, plane: Option) -> vk::ImageAspectFlags { +pub fn map_aspects(aspects: crate::FormatAspects) -> vk::ImageAspectFlags { let mut flags = vk::ImageAspectFlags::empty(); - match plane { - Some(0) => flags |= vk::ImageAspectFlags::PLANE_0, - Some(1) => flags |= vk::ImageAspectFlags::PLANE_1, - Some(2) => flags |= vk::ImageAspectFlags::PLANE_2, - Some(plane) => panic!("Unexpected plane {}", plane), - None => { - if aspects.contains(crate::FormatAspects::COLOR) { - flags |= vk::ImageAspectFlags::COLOR; - } - } + if aspects.contains(crate::FormatAspects::COLOR) { + flags |= vk::ImageAspectFlags::COLOR; } if aspects.contains(crate::FormatAspects::DEPTH) { flags |= vk::ImageAspectFlags::DEPTH; @@ -421,6 +413,15 @@ pub fn map_aspects(aspects: crate::FormatAspects, plane: Option) -> vk::Ima if aspects.contains(crate::FormatAspects::STENCIL) { flags |= vk::ImageAspectFlags::STENCIL; } + if aspects.contains(crate::FormatAspects::PLANE_0) { + flags |= vk::ImageAspectFlags::PLANE_0; + } + if aspects.contains(crate::FormatAspects::PLANE_1) { + flags |= vk::ImageAspectFlags::PLANE_1; + } + if aspects.contains(crate::FormatAspects::PLANE_2) { + flags |= vk::ImageAspectFlags::PLANE_2; + } flags } @@ -614,10 +615,9 @@ pub fn map_copy_extent(extent: &crate::CopyExtent) -> vk::Extent3D { pub fn map_subresource_range( range: &wgt::ImageSubresourceRange, format: wgt::TextureFormat, - plane: Option, ) -> vk::ImageSubresourceRange { vk::ImageSubresourceRange { - aspect_mask: map_aspects(crate::FormatAspects::new(format, range.aspect), plane), + aspect_mask: map_aspects(crate::FormatAspects::new(format, range.aspect)), base_mip_level: range.base_mip_level, level_count: range.mip_level_count.unwrap_or(vk::REMAINING_MIP_LEVELS), base_array_layer: range.base_array_layer, @@ -634,7 +634,7 @@ pub(super) fn map_subresource_range_combined_aspect( format: wgt::TextureFormat, private_caps: &super::PrivateCapabilities, ) -> vk::ImageSubresourceRange { - let mut range = map_subresource_range(range, format, None); + let mut range = map_subresource_range(range, format); if !private_caps.texture_s8 && format == wgt::TextureFormat::Stencil8 { range.aspect_mask |= vk::ImageAspectFlags::DEPTH; } @@ -650,7 +650,7 @@ pub fn map_subresource_layers( z: base.origin.z as i32, }; let subresource = vk::ImageSubresourceLayers { - aspect_mask: map_aspects(base.aspect, None), + aspect_mask: map_aspects(base.aspect), mip_level: base.mip_level, base_array_layer: base.array_layer, layer_count: 1, diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 0caf1aa1c..a37017a9e 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -667,6 +667,9 @@ impl super::Device { vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE; view_formats.push(desc.format) } + if desc.format.is_multi_planar_format() { + raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT; + } super::Texture { raw: vk_image, @@ -989,7 +992,7 @@ impl crate::Device for super::Device { wgt_view_formats = desc.view_formats.clone(); wgt_view_formats.push(desc.format); - if self.shared.private_caps.image_format_list && !desc.format.is_multi_planar_format() { + if self.shared.private_caps.image_format_list { vk_view_formats = desc .view_formats .iter() @@ -998,6 +1001,9 @@ impl crate::Device for super::Device { vk_view_formats.push(original_format) } } + if desc.format.is_multi_planar_format() { + raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT; + } let mut vk_info = vk::ImageCreateInfo::builder() .flags(raw_flags) @@ -1071,7 +1077,7 @@ impl crate::Device for super::Device { texture: &super::Texture, desc: &crate::TextureViewDescriptor, ) -> Result { - let subresource_range = conv::map_subresource_range(&desc.range, desc.format, desc.plane); + let subresource_range = conv::map_subresource_range(&desc.range, texture.format); let mut vk_info = vk::ImageViewCreateInfo::builder() .flags(vk::ImageViewCreateFlags::empty()) .image(texture.raw) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index dd9f90674..86a266666 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2411,9 +2411,9 @@ pub enum TextureFormat { /// - 0: Single 8 bit channel luminance. /// - 1: Dual 8 bit channel chrominance at half width and half height. /// - /// Valid view formats for luminance are [`TextureFormat::R8Unorm`] and [`TextureFormat::R8Uint`]. + /// Valid view formats for luminance are [`TextureFormat::R8Unorm`]. /// - /// Valid view formats for chrominance are [`TextureFormat::Rg8Unorm`] and [`TextureFormat::Rg8Uint`]. + /// Valid view formats for chrominance are [`TextureFormat::Rg8Unorm`]. /// /// Width and height must be even. /// @@ -2835,6 +2835,18 @@ impl Serialize for TextureFormat { } } +impl TextureAspect { + /// Returns the texture aspect for a given plane. + pub fn from_plane(plane: u32) -> Option { + Some(match plane { + 0 => Self::Plane0, + 1 => Self::Plane1, + 2 => Self::Plane2, + _ => return None, + }) + } +} + impl TextureFormat { /// Returns the aspect-specific format of the original format /// @@ -2852,7 +2864,10 @@ impl TextureFormat { ) => Some(Self::Stencil8), (Self::Depth24PlusStencil8, TextureAspect::DepthOnly) => Some(Self::Depth24Plus), (Self::Depth32FloatStencil8, TextureAspect::DepthOnly) => Some(Self::Depth32Float), - (format, TextureAspect::All) => Some(format), + (Self::NV12, TextureAspect::Plane0) => Some(Self::R8Unorm), + (Self::NV12, TextureAspect::Plane1) => Some(Self::Rg8Unorm), + // views to multi-planar formats must specify the plane + (format, TextureAspect::All) if !format.is_multi_planar_format() => Some(format), _ => None, } } @@ -2894,7 +2909,15 @@ impl TextureFormat { /// Returns `true` if the format is a multi-planar format pub fn is_multi_planar_format(&self) -> bool { - matches!(*self, Self::NV12) + self.planes().is_some() + } + + /// Returns the number of planes a multi-planar format has. + pub fn planes(&self) -> Option { + match *self { + Self::NV12 => Some(2), + _ => None, + } } /// Returns `true` if the format has a color aspect @@ -2922,6 +2945,14 @@ impl TextureFormat { } } + /// Returns the size multiple requirement for a texture using this format. + pub fn size_multiple_requirement(&self) -> (u32, u32) { + match *self { + Self::NV12 => (2, 2), + _ => self.block_dimensions(), + } + } + /// Returns the dimension of a [block](https://gpuweb.github.io/gpuweb/#texel-block) of texels. /// /// Uncompressed formats have a block dimension of `(1, 1)`. @@ -2975,9 +3006,8 @@ impl TextureFormat { | Self::Depth24Plus | Self::Depth24PlusStencil8 | Self::Depth32Float - | Self::Depth32FloatStencil8 => (1, 1), - - Self::NV12 => (2, 2), + | Self::Depth32FloatStencil8 + | Self::NV12 => (1, 1), Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb @@ -3253,16 +3283,17 @@ impl TextureFormat { } } - /// Returns the sample type compatible with this format and aspect + /// Returns the sample type compatible with this format and aspect. /// - /// Returns `None` only if the format is combined depth-stencil - /// and `TextureAspect::All` or no `aspect` was provided + /// Returns `None` only if this is a combined depth-stencil format or a multi-planar format + /// and `TextureAspect::All` or no `aspect` was provided. pub fn sample_type( &self, aspect: Option, device_features: Option, ) -> Option { let float = TextureSampleType::Float { filterable: true }; + let unfilterable_float = TextureSampleType::Float { filterable: false }; let float32_sample_type = TextureSampleType::Float { filterable: device_features .unwrap_or(Features::empty()) @@ -3314,12 +3345,17 @@ impl TextureFormat { Self::Stencil8 => Some(uint), Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => Some(depth), Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect { - None | Some(TextureAspect::All) => None, Some(TextureAspect::DepthOnly) => Some(depth), Some(TextureAspect::StencilOnly) => Some(uint), + _ => None, }, - Self::NV12 => None, + Self::NV12 => match aspect { + Some(TextureAspect::Plane0) | Some(TextureAspect::Plane1) => { + Some(unfilterable_float) + } + _ => None, + }, Self::R16Unorm | Self::R16Snorm @@ -3368,7 +3404,8 @@ impl TextureFormat { /// since uncompressed formats have a block size of 1x1. /// /// Returns `None` if any of the following are true: - /// - the format is combined depth-stencil and no `aspect` was provided + /// - the format is a combined depth-stencil and no `aspect` was provided + /// - the format is a multi-planar format and no `aspect` was provided /// - the format is `Depth24Plus` /// - the format is `Depth24PlusStencil8` and `aspect` is depth. #[deprecated(since = "0.19.0", note = "Use `block_copy_size` instead.")] @@ -3384,7 +3421,8 @@ impl TextureFormat { /// since uncompressed formats have a block size of 1x1. /// /// Returns `None` if any of the following are true: - /// - the format is combined depth-stencil and no `aspect` was provided + /// - the format is a combined depth-stencil and no `aspect` was provided + /// - the format is a multi-planar format and no `aspect` was provided /// - the format is `Depth24Plus` /// - the format is `Depth24PlusStencil8` and `aspect` is depth. pub fn block_copy_size(&self, aspect: Option) -> Option { @@ -3427,17 +3465,21 @@ impl TextureFormat { Self::Depth32Float => Some(4), Self::Depth24Plus => None, Self::Depth24PlusStencil8 => match aspect { - None | Some(TextureAspect::All) => None, Some(TextureAspect::DepthOnly) => None, Some(TextureAspect::StencilOnly) => Some(1), + _ => None, }, Self::Depth32FloatStencil8 => match aspect { - None | Some(TextureAspect::All) => None, Some(TextureAspect::DepthOnly) => Some(4), Some(TextureAspect::StencilOnly) => Some(1), + _ => None, }, - Self::NV12 => None, + Self::NV12 => match aspect { + Some(TextureAspect::Plane0) => Some(1), + Some(TextureAspect::Plane1) => Some(2), + _ => None, + }, Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb | Self::Bc4RUnorm | Self::Bc4RSnorm => { Some(8) @@ -3475,7 +3517,7 @@ impl TextureFormat { /// Returns the number of components this format has taking into account the `aspect`. /// - /// The `aspect` is only relevant for combined depth-stencil formats. + /// The `aspect` is only relevant for combined depth-stencil formats and multi-planar formats. pub fn components_with_aspect(&self, aspect: TextureAspect) -> u8 { match *self { Self::R8Unorm @@ -3526,11 +3568,15 @@ impl TextureFormat { Self::Stencil8 | Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => 1, Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect { - TextureAspect::All => 2, TextureAspect::DepthOnly | TextureAspect::StencilOnly => 1, + _ => 2, }, - Self::NV12 => 3, + Self::NV12 => match aspect { + TextureAspect::Plane0 => 1, + TextureAspect::Plane1 => 2, + _ => 3, + }, Self::Bc4RUnorm | Self::Bc4RSnorm => 1, Self::Bc5RgUnorm | Self::Bc5RgSnorm => 2, @@ -5633,6 +5679,12 @@ pub enum TextureAspect { StencilOnly, /// Depth. DepthOnly, + /// Plane 0. + Plane0, + /// Plane 1. + Plane1, + /// Plane 2. + Plane2, } /// How edges should be handled in texture addressing. diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index b1ed365a8..cf1fd7291 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1610,7 +1610,6 @@ impl crate::Context for Context { base_array_layer: desc.base_array_layer, array_layer_count: desc.array_layer_count, }, - plane: desc.plane, }; let global = &self.0; let (id, error) = wgc::gfx_select!( diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 543a58357..4b6e527ab 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -606,6 +606,9 @@ fn map_texture_aspect(aspect: wgt::TextureAspect) -> web_sys::GpuTextureAspect { wgt::TextureAspect::All => web_sys::GpuTextureAspect::All, wgt::TextureAspect::StencilOnly => web_sys::GpuTextureAspect::StencilOnly, wgt::TextureAspect::DepthOnly => web_sys::GpuTextureAspect::DepthOnly, + wgt::TextureAspect::Plane0 | wgt::TextureAspect::Plane1 | wgt::TextureAspect::Plane2 => { + panic!("multi-plane textures are not supported") + } } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 939964ce9..f5668881b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1301,8 +1301,6 @@ pub struct TextureViewDescriptor<'a> { /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count. /// If `None`, considered to include the rest of the array layers, but at least 1 in total. pub array_layer_count: Option, - /// The index (plane slice number) of the plane to use in the texture. - pub plane: Option, } static_assertions::assert_impl_all!(TextureViewDescriptor<'_>: Send, Sync);