diff --git a/tests/src/lib.rs b/tests/src/lib.rs index b3f65351e4a..22afd7ecf77 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -37,7 +37,7 @@ pub use wgpu_macros::gpu_test; pub fn fail( device: &wgpu::Device, callback: impl FnOnce() -> T, - expected_msg_substring: Option<&'static str>, + expected_msg_substring: Option<&str>, ) -> T { device.push_error_scope(wgpu::ErrorFilter::Validation); let result = callback(); diff --git a/tests/tests/wgpu-gpu/main.rs b/tests/tests/wgpu-gpu/main.rs index 98793419e15..d461845e92b 100644 --- a/tests/tests/wgpu-gpu/main.rs +++ b/tests/tests/wgpu-gpu/main.rs @@ -36,12 +36,12 @@ mod instance; mod life_cycle; mod mem_leaks; mod mesh_shader; -mod nv12_texture; mod occlusion_query; mod oob_indexing; mod oom; mod pipeline; mod pipeline_cache; +mod planar_texture; mod poll; mod push_constants; mod query_set; @@ -96,12 +96,12 @@ fn all_tests() -> Vec { life_cycle::all_tests(&mut tests); mem_leaks::all_tests(&mut tests); mesh_shader::all_tests(&mut tests); - nv12_texture::all_tests(&mut tests); occlusion_query::all_tests(&mut tests); oob_indexing::all_tests(&mut tests); oom::all_tests(&mut tests); pipeline_cache::all_tests(&mut tests); pipeline::all_tests(&mut tests); + planar_texture::all_tests(&mut tests); poll::all_tests(&mut tests); push_constants::all_tests(&mut tests); query_set::all_tests(&mut tests); diff --git a/tests/tests/wgpu-gpu/nv12_texture/mod.rs b/tests/tests/wgpu-gpu/nv12_texture/mod.rs deleted file mode 100644 index ced957ca382..00000000000 --- a/tests/tests/wgpu-gpu/nv12_texture/mod.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Tests for nv12 texture creation and sampling. - -use wgpu_test::{fail, gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters}; - -pub fn all_tests(tests: &mut Vec) { - tests.extend([ - NV12_TEXTURE_CREATION_SAMPLING, - NV12_TEXTURE_VIEW_PLANE_ON_NON_PLANAR_FORMAT, - NV12_TEXTURE_VIEW_PLANE_OUT_OF_BOUNDS, - NV12_TEXTURE_BAD_FORMAT_VIEW_PLANE, - NV12_TEXTURE_BAD_SIZE, - ]); -} - -#[gpu_test] -static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters( - TestParameters::default() - .features(wgpu::Features::TEXTURE_FORMAT_NV12) - .enable_noop(), - ) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 256, - height: 256, - depth_or_array_layers: 1, - }; - let target_format = wgpu::TextureFormat::Bgra8UnormSrgb; - - let shader = ctx - .device - .create_shader_module(wgpu::include_wgsl!("nv12_texture.wgsl")); - let pipeline = ctx - .device - .create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("nv12 pipeline"), - layout: None, - vertex: wgpu::VertexState { - module: &shader, - entry_point: Some("vs_main"), - compilation_options: Default::default(), - buffers: &[], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: Some("fs_main"), - compilation_options: Default::default(), - targets: &[Some(target_format.into())], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleStrip, - strip_index_format: Some(wgpu::IndexFormat::Uint32), - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview: None, - cache: None, - }); - - let tex = 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: &[], - }); - let y_view = tex.create_view(&wgpu::TextureViewDescriptor { - format: Some(wgpu::TextureFormat::R8Unorm), - aspect: wgpu::TextureAspect::Plane0, - ..Default::default() - }); - let uv_view = tex.create_view(&wgpu::TextureViewDescriptor { - format: Some(wgpu::TextureFormat::Rg8Unorm), - aspect: wgpu::TextureAspect::Plane1, - ..Default::default() - }); - let sampler = ctx.device.create_sampler(&wgpu::SamplerDescriptor { - min_filter: wgpu::FilterMode::Linear, - mag_filter: wgpu::FilterMode::Linear, - ..Default::default() - }); - let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &pipeline.get_bind_group_layout(0), - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Sampler(&sampler), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::TextureView(&y_view), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::TextureView(&uv_view), - }, - ], - }); - - let target_tex = ctx.device.create_texture(&wgpu::TextureDescriptor { - label: None, - size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: target_format, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - view_formats: &[], - }); - let target_view = target_tex.create_view(&wgpu::TextureViewDescriptor::default()); - - let mut encoder = ctx - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - ops: wgpu::Operations::default(), - resolve_target: None, - view: &target_view, - depth_slice: None, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }); - rpass.set_pipeline(&pipeline); - rpass.set_bind_group(0, &bind_group, &[]); - rpass.draw(0..4, 0..1); - drop(rpass); - ctx.queue.submit(Some(encoder.finish())); - }); - -#[gpu_test] -static NV12_TEXTURE_VIEW_PLANE_ON_NON_PLANAR_FORMAT: GpuTestConfiguration = - GpuTestConfiguration::new() - .parameters( - TestParameters::default() - .features(wgpu::Features::TEXTURE_FORMAT_NV12) - .enable_noop(), - ) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 256, - height: 256, - depth_or_array_layers: 1, - }; - let tex = ctx.device.create_texture(&wgpu::TextureDescriptor { - label: None, - dimension: wgpu::TextureDimension::D2, - size, - format: wgpu::TextureFormat::R8Unorm, - usage: wgpu::TextureUsages::TEXTURE_BINDING, - mip_level_count: 1, - sample_count: 1, - view_formats: &[], - }); - fail( - &ctx.device, - || { - let _ = tex.create_view(&wgpu::TextureViewDescriptor { - aspect: wgpu::TextureAspect::Plane0, - ..Default::default() - }); - }, - Some("aspect plane0 is not in the source texture format r8unorm"), - ); - }); - -#[gpu_test] -static NV12_TEXTURE_VIEW_PLANE_OUT_OF_BOUNDS: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters( - TestParameters::default() - .features(wgpu::Features::TEXTURE_FORMAT_NV12) - .enable_noop(), - ) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 256, - height: 256, - depth_or_array_layers: 1, - }; - let tex = 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: &[], - }); - fail( - &ctx.device, - || { - let _ = tex.create_view(&wgpu::TextureViewDescriptor { - format: Some(wgpu::TextureFormat::R8Unorm), - aspect: wgpu::TextureAspect::Plane2, - ..Default::default() - }); - }, - Some("aspect plane2 is not in the source texture format nv12"), - ); - }); - -#[gpu_test] -static NV12_TEXTURE_BAD_FORMAT_VIEW_PLANE: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters( - TestParameters::default() - .features(wgpu::Features::TEXTURE_FORMAT_NV12) - .enable_noop(), - ) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 256, - height: 256, - depth_or_array_layers: 1, - }; - let tex = 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: &[], - }); - fail( - &ctx.device, - || { - let _ = tex.create_view(&wgpu::TextureViewDescriptor { - format: Some(wgpu::TextureFormat::Rg8Unorm), - aspect: wgpu::TextureAspect::Plane0, - ..Default::default() - }); - }, - Some("unable to view texture nv12 as rg8unorm"), - ); - }); - -#[gpu_test] -static NV12_TEXTURE_BAD_SIZE: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters( - TestParameters::default() - .features(wgpu::Features::TEXTURE_FORMAT_NV12) - .enable_noop(), - ) - .run_sync(|ctx| { - let size = wgpu::Extent3d { - width: 255, - height: 255, - 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: &[], - }); - }, - Some("width 255 is not a multiple of nv12's width multiple requirement"), - ); - }); diff --git a/tests/tests/wgpu-gpu/planar_texture/mod.rs b/tests/tests/wgpu-gpu/planar_texture/mod.rs new file mode 100644 index 00000000000..961d4b43f64 --- /dev/null +++ b/tests/tests/wgpu-gpu/planar_texture/mod.rs @@ -0,0 +1,189 @@ +//! Tests for nv12 texture creation and sampling. + +use wgpu_test::{ + gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters, TestingContext, +}; + +pub fn all_tests(tests: &mut Vec) { + tests.extend([ + NV12_TEXTURE_CREATION_SAMPLING, + P010_TEXTURE_CREATION_SAMPLING, + ]); +} + +// Helper function to test planar texture creation and sampling. +fn test_planar_texture_creation_sampling( + ctx: &TestingContext, + y_view: &wgpu::TextureView, + uv_view: &wgpu::TextureView, +) { + let target_format = wgpu::TextureFormat::Bgra8UnormSrgb; + + let shader = ctx + .device + .create_shader_module(wgpu::include_wgsl!("planar_texture.wgsl")); + let pipeline = ctx + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("planar texture pipeline"), + layout: None, + vertex: wgpu::VertexState { + module: &shader, + entry_point: Some("vs_main"), + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Some("fs_main"), + compilation_options: Default::default(), + targets: &[Some(target_format.into())], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleStrip, + strip_index_format: Some(wgpu::IndexFormat::Uint32), + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + let sampler = ctx.device.create_sampler(&wgpu::SamplerDescriptor { + min_filter: wgpu::FilterMode::Linear, + mag_filter: wgpu::FilterMode::Linear, + ..Default::default() + }); + let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &pipeline.get_bind_group_layout(0), + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(y_view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(uv_view), + }, + ], + }); + + let target_tex = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: y_view.texture().size(), + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: target_format, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[], + }); + let target_view = target_tex.create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + ops: wgpu::Operations::default(), + resolve_target: None, + view: &target_view, + depth_slice: None, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + rpass.set_pipeline(&pipeline); + rpass.set_bind_group(0, &bind_group, &[]); + rpass.draw(0..4, 0..1); + drop(rpass); + ctx.queue.submit(Some(encoder.finish())); +} + +/// Ensures that creation and sampling of an NV12 format texture works as +/// expected. +#[gpu_test] +static NV12_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features(wgpu::Features::TEXTURE_FORMAT_NV12) + .enable_noop(), + ) + .run_sync(|ctx| { + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + let tex = 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: &[], + }); + let y_view = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(wgpu::TextureFormat::R8Unorm), + aspect: wgpu::TextureAspect::Plane0, + ..Default::default() + }); + let uv_view = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(wgpu::TextureFormat::Rg8Unorm), + aspect: wgpu::TextureAspect::Plane1, + ..Default::default() + }); + + test_planar_texture_creation_sampling(&ctx, &y_view, &uv_view); + }); + +/// Ensures that creation and sampling of a P010 format texture works as +/// expected. +#[gpu_test] +static P010_TEXTURE_CREATION_SAMPLING: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features( + wgpu::Features::TEXTURE_FORMAT_P010 | wgpu::Features::TEXTURE_FORMAT_16BIT_NORM, + ) + .enable_noop(), + ) + .run_sync(|ctx| { + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + let tex = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format: wgpu::TextureFormat::P010, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + let y_view = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(wgpu::TextureFormat::R16Unorm), + aspect: wgpu::TextureAspect::Plane0, + ..Default::default() + }); + let uv_view = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(wgpu::TextureFormat::Rg16Unorm), + aspect: wgpu::TextureAspect::Plane1, + ..Default::default() + }); + + test_planar_texture_creation_sampling(&ctx, &y_view, &uv_view); + }); diff --git a/tests/tests/wgpu-gpu/nv12_texture/nv12_texture.wgsl b/tests/tests/wgpu-gpu/planar_texture/planar_texture.wgsl similarity index 100% rename from tests/tests/wgpu-gpu/nv12_texture/nv12_texture.wgsl rename to tests/tests/wgpu-gpu/planar_texture/planar_texture.wgsl diff --git a/tests/tests/wgpu-validation/api/texture.rs b/tests/tests/wgpu-validation/api/texture.rs index 2b079cc3a78..4b1e93ebb16 100644 --- a/tests/tests/wgpu-validation/api/texture.rs +++ b/tests/tests/wgpu-validation/api/texture.rs @@ -1,5 +1,7 @@ //! Tests of [`wgpu::Texture`] and related. +use wgpu_test::{fail, valid}; + /// Ensures that submitting a command buffer referencing an already destroyed texture /// results in an error. #[test] @@ -54,3 +56,245 @@ fn destroyed_texture() { queue.submit([encoder.finish()]); } + +/// Ensures that creating a texture view from a specific plane of a planar +/// texture works as expected. +#[test] +fn planar_texture_view_plane() { + let required_features = wgpu::Features::TEXTURE_FORMAT_NV12 + | wgpu::Features::TEXTURE_FORMAT_P010 + | wgpu::Features::TEXTURE_FORMAT_16BIT_NORM; + let device_desc = wgpu::DeviceDescriptor { + required_features, + ..Default::default() + }; + let (device, _queue) = wgpu::Device::noop(&device_desc); + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + + for (tex_format, view_format, view_aspect) in [ + ( + wgpu::TextureFormat::NV12, + wgpu::TextureFormat::R8Unorm, + wgpu::TextureAspect::Plane0, + ), + ( + wgpu::TextureFormat::NV12, + wgpu::TextureFormat::Rg8Unorm, + wgpu::TextureAspect::Plane1, + ), + ( + wgpu::TextureFormat::P010, + wgpu::TextureFormat::R16Unorm, + wgpu::TextureAspect::Plane0, + ), + ( + wgpu::TextureFormat::P010, + wgpu::TextureFormat::Rg16Unorm, + wgpu::TextureAspect::Plane1, + ), + ] { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format: tex_format, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + valid(&device, || { + let _ = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(view_format), + aspect: view_aspect, + ..Default::default() + }); + }); + } +} + +/// Ensures that attempting to create a texture view from a specific plane of a +/// non-planar texture fails validation. +#[test] +fn non_planar_texture_view_plane() { + let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default()); + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format: wgpu::TextureFormat::R8Unorm, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + fail( + &device, + || { + let _ = tex.create_view(&wgpu::TextureViewDescriptor { + aspect: wgpu::TextureAspect::Plane0, + ..Default::default() + }); + }, + Some("Aspect Plane0 is not in the source texture format R8Unorm"), + ); +} + +/// Ensures that attempting to create a texture view from an invalid plane of a +/// planar texture fails validation. +#[test] +fn planar_texture_view_plane_out_of_bounds() { + let required_features = wgpu::Features::TEXTURE_FORMAT_NV12 + | wgpu::Features::TEXTURE_FORMAT_P010 + | wgpu::Features::TEXTURE_FORMAT_16BIT_NORM; + let device_desc = wgpu::DeviceDescriptor { + required_features, + ..Default::default() + }; + let (device, _queue) = wgpu::Device::noop(&device_desc); + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + + for (tex_format, view_format, view_aspect) in [ + ( + wgpu::TextureFormat::NV12, + wgpu::TextureFormat::R8Unorm, + wgpu::TextureAspect::Plane2, + ), + ( + wgpu::TextureFormat::P010, + wgpu::TextureFormat::R16Unorm, + wgpu::TextureAspect::Plane2, + ), + ] { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format: tex_format, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + fail( + &device, + || { + let _ = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(view_format), + aspect: view_aspect, + ..Default::default() + }); + }, + Some(&format!( + "Aspect {view_aspect:?} is not in the source texture format {tex_format:?}" + )), + ); + } +} + +/// Ensures that attempting to create a texture view from a specific plane of a +/// planar texture with an invalid format fails validation. +#[test] +fn planar_texture_view_plane_bad_format() { + let required_features = wgpu::Features::TEXTURE_FORMAT_NV12 + | wgpu::Features::TEXTURE_FORMAT_P010 + | wgpu::Features::TEXTURE_FORMAT_16BIT_NORM; + let device_desc = wgpu::DeviceDescriptor { + required_features, + ..Default::default() + }; + let (device, _queue) = wgpu::Device::noop(&device_desc); + let size = wgpu::Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }; + for (tex_format, view_format, view_aspect) in [ + ( + wgpu::TextureFormat::NV12, + wgpu::TextureFormat::Rg8Unorm, + wgpu::TextureAspect::Plane0, + ), + ( + wgpu::TextureFormat::P010, + wgpu::TextureFormat::Rg16Unorm, + wgpu::TextureAspect::Plane0, + ), + ] { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format: tex_format, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + fail( + &device, + || { + let _ = tex.create_view(&wgpu::TextureViewDescriptor { + format: Some(view_format), + aspect: view_aspect, + ..Default::default() + }); + }, + Some(&format!( + "unable to view texture {tex_format:?} as {view_format:?}" + )), + ); + } +} + +/// Ensures that attempting to create a planar texture with an invalid size +/// fails validation. +#[test] +fn planar_texture_bad_size() { + let required_features = + wgpu::Features::TEXTURE_FORMAT_NV12 | wgpu::Features::TEXTURE_FORMAT_P010; + let device_desc = wgpu::DeviceDescriptor { + required_features, + ..Default::default() + }; + let (device, _queue) = wgpu::Device::noop(&device_desc); + let size = wgpu::Extent3d { + width: 255, + height: 255, + depth_or_array_layers: 1, + }; + for format in [wgpu::TextureFormat::NV12, wgpu::TextureFormat::P010] { + fail( + &device, + || { + let _ = device.create_texture(&wgpu::TextureDescriptor { + label: None, + dimension: wgpu::TextureDimension::D2, + size, + format, + usage: wgpu::TextureUsages::TEXTURE_BINDING, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }); + }, + Some(&format!( + "width {} is not a multiple of {format:?}'s width multiple requirement", + size.width + )), + ); + } +} diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 593382aa931..840e9068125 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -373,8 +373,10 @@ fn clear_texture_via_buffer_copies( ) { assert!(!texture_desc.format.is_depth_stencil_format()); - if texture_desc.format == wgt::TextureFormat::NV12 { - // TODO: Currently COPY_DST for NV12 textures is unsupported. + if texture_desc.format == wgt::TextureFormat::NV12 + || texture_desc.format == wgt::TextureFormat::P010 + { + // TODO: Currently COPY_DST for NV12 and P010 textures is unsupported. return; } diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 2127604064d..2c2f4b36c44 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -817,6 +817,7 @@ impl NumericType { panic!("Unexpected depth format") } Tf::NV12 => panic!("Unexpected nv12 format"), + Tf::P010 => panic!("Unexpected p010 format"), Tf::Rgb9e5Ufloat => (NumericDimension::Vector(Vs::Tri), Scalar::F32), Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb diff --git a/wgpu-hal/src/auxil/dxgi/conv.rs b/wgpu-hal/src/auxil/dxgi/conv.rs index a53934258dc..6e27081aac4 100644 --- a/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/wgpu-hal/src/auxil/dxgi/conv.rs @@ -68,6 +68,7 @@ pub fn map_texture_format_failable( Tf::Depth32Float => DXGI_FORMAT_D32_FLOAT, Tf::Depth32FloatStencil8 => DXGI_FORMAT_D32_FLOAT_S8X24_UINT, Tf::NV12 => DXGI_FORMAT_NV12, + Tf::P010 => DXGI_FORMAT_P010, Tf::Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM, Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_UNORM_SRGB, Tf::Bc2RgbaUnorm => DXGI_FORMAT_BC2_UNORM, diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index b8b908279e0..fd045ea03d9 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -414,6 +414,35 @@ impl super::Adapter { bgra8unorm_storage_supported, ); + let p010_format_supported = { + let mut p010_info = Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT { + Format: Dxgi::Common::DXGI_FORMAT_P010, + ..Default::default() + }; + let hr = unsafe { + device.CheckFeatureSupport( + Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT, + <*mut _>::cast(&mut p010_info), + size_of_val(&p010_info) as u32, + ) + }; + if hr.is_ok() { + let supports_texture2d = p010_info + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_TEXTURE2D); + let supports_shader_load = p010_info + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD); + let supports_shader_sample = p010_info + .Support1 + .contains(Direct3D12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE); + supports_texture2d && supports_shader_load && supports_shader_sample + } else { + false + } + }; + features.set(wgt::Features::TEXTURE_FORMAT_P010, p010_format_supported); + let mut features1 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS1::default(); let hr = unsafe { device.CheckFeatureSupport( diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 865f35013c7..87e8caff667 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -1165,6 +1165,7 @@ impl crate::Adapter for super::Adapter { | Tf::Depth24Plus | Tf::Depth24PlusStencil8 => depth, Tf::NV12 => empty, + Tf::P010 => empty, Tf::Rgb9e5Ufloat => filterable, Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 7348f2f19ee..b9dd545d562 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -89,6 +89,7 @@ impl super::AdapterShared { glow::UNSIGNED_INT_24_8, ), Tf::NV12 => unreachable!(), + Tf::P010 => unreachable!(), Tf::Rgb9e5Ufloat => (glow::RGB9_E5, glow::RGB, glow::UNSIGNED_INT_5_9_9_9_REV), Tf::Bc1RgbaUnorm => (glow::COMPRESSED_RGBA_S3TC_DXT1_EXT, glow::RGBA, 0), Tf::Bc1RgbaUnormSrgb => (glow::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, glow::RGBA, 0), diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 331af72baf7..e60b07e9a6a 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1734,7 +1734,7 @@ impl From for FormatAspects { wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24PlusStencil8 => { Self::DEPTH_STENCIL } - wgt::TextureFormat::NV12 => Self::PLANE_0 | Self::PLANE_1, + wgt::TextureFormat::NV12 | wgt::TextureFormat::P010 => Self::PLANE_0 | Self::PLANE_1, _ => Self::COLOR, } } diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 7ab14ca76d2..d02e38980ac 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -290,6 +290,7 @@ impl crate::Adapter for super::Adapter { flags } Tf::NV12 => return Tfc::empty(), + Tf::P010 => return Tfc::empty(), Tf::Rgb9e5Ufloat => { if pc.msaa_apple3 { all_caps @@ -1175,6 +1176,7 @@ impl super::PrivateCapabilities { } } Tf::NV12 => unreachable!(), + Tf::P010 => unreachable!(), Tf::Rgb9e5Ufloat => MTL::RGB9E5Float, Tf::Bc1RgbaUnorm => MTL::BC1_RGBA, Tf::Bc1RgbaUnormSrgb => MTL::BC1_RGBA_sRGB, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 19c1ffe4ca7..bb4e2a9d4ae 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -850,6 +850,24 @@ impl PhysicalDeviceFeatures { ); } + if let Some(ref _sampler_ycbcr_conversion) = self.sampler_ycbcr_conversion { + features.set( + F::TEXTURE_FORMAT_P010, + supports_format( + instance, + phd, + vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + vk::ImageTiling::OPTIMAL, + vk::FormatFeatureFlags::SAMPLED_IMAGE + | vk::FormatFeatureFlags::TRANSFER_SRC + | vk::FormatFeatureFlags::TRANSFER_DST, + ) && !caps + .driver + .map(|driver| driver.driver_id == vk::DriverId::MOLTENVK) + .unwrap_or_default(), + ); + } + features.set( F::VULKAN_GOOGLE_DISPLAY_TIMING, caps.supports_extension(google::display_timing::NAME), diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 5d067c0ef0f..e6bcb20ca75 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -78,6 +78,7 @@ impl super::PrivateCapabilities { } Tf::Depth16Unorm => F::D16_UNORM, Tf::NV12 => F::G8_B8R8_2PLANE_420_UNORM, + Tf::P010 => F::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, Tf::Rgb9e5Ufloat => F::E5B9G9R9_UFLOAT_PACK32, Tf::Bc1RgbaUnorm => F::BC1_RGBA_UNORM_BLOCK, Tf::Bc1RgbaUnormSrgb => F::BC1_RGBA_SRGB_BLOCK, diff --git a/wgpu-info/src/texture.rs b/wgpu-info/src/texture.rs index 64325f0e5bc..5c9c385fab3 100644 --- a/wgpu-info/src/texture.rs +++ b/wgpu-info/src/texture.rs @@ -1,6 +1,6 @@ // Lets keep these on one line #[rustfmt::skip] -pub const TEXTURE_FORMAT_LIST: [wgpu::TextureFormat; 117] = [ +pub const TEXTURE_FORMAT_LIST: [wgpu::TextureFormat; 118] = [ wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::R8Uint, @@ -52,6 +52,7 @@ pub const TEXTURE_FORMAT_LIST: [wgpu::TextureFormat; 117] = [ wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Depth32FloatStencil8, wgpu::TextureFormat::NV12, + wgpu::TextureFormat::P010, wgpu::TextureFormat::Bc1RgbaUnorm, wgpu::TextureFormat::Bc1RgbaUnormSrgb, wgpu::TextureFormat::Bc2RgbaUnorm, diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index 908d5bda203..af3a920cd61 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -984,6 +984,16 @@ bitflags_array! { /// /// [`TextureFormat::NV12`]: super::TextureFormat::NV12 const TEXTURE_FORMAT_NV12 = 1 << 29; + /// Allows for creation of textures of format [`TextureFormat::P010`] + /// + /// Supported platforms: + /// - DX12 + /// - Vulkan + /// + /// This is a native only feature. + /// + /// [`TextureFormat::P010`]: super::TextureFormat::P010 + const TEXTURE_FORMAT_P010 = 1 << 30; /// Allows for the creation and usage of `ExternalTexture`s, and bind /// group layouts containing external texture `BindingType`s. @@ -998,7 +1008,7 @@ bitflags_array! { /// /// Supported platforms: /// - DX12 - const EXTERNAL_TEXTURE = 1 << 30; + const EXTERNAL_TEXTURE = 1 << 31; // Shader: @@ -1012,7 +1022,7 @@ bitflags_array! { /// - Vulkan /// /// This is a native-only feature. - const EXPERIMENTAL_RAY_QUERY = 1 << 31; + const EXPERIMENTAL_RAY_QUERY = 1 << 32; /// Enables 64-bit floating point types in SPIR-V shaders. /// /// Note: even when supported by GPU hardware, 64-bit floating point operations are @@ -1022,14 +1032,14 @@ bitflags_array! { /// - Vulkan /// /// This is a native only feature. - const SHADER_F64 = 1 << 32; + const SHADER_F64 = 1 << 33; /// Allows shaders to use i16. Not currently supported in `naga`, only available through `spirv-passthrough`. /// /// Supported platforms: /// - Vulkan /// /// This is a native only feature. - const SHADER_I16 = 1 << 33; + const SHADER_I16 = 1 << 34; /// Enables `builtin(primitive_index)` in fragment shaders. /// /// Note: enables geometry processing for pipelines using the builtin. @@ -1043,7 +1053,7 @@ bitflags_array! { /// - OpenGL (some) /// /// This is a native only feature. - const SHADER_PRIMITIVE_INDEX = 1 << 34; + const SHADER_PRIMITIVE_INDEX = 1 << 35; /// Allows shaders to use the `early_depth_test` attribute. /// /// The attribute is applied to the fragment shader entry point. It can be used in two @@ -1071,7 +1081,7 @@ bitflags_array! { /// This is a native only feature. /// /// [`EarlyDepthTest`]: https://docs.rs/naga/latest/naga/ir/enum.EarlyDepthTest.html - const SHADER_EARLY_DEPTH_TEST = 1 << 35; + const SHADER_EARLY_DEPTH_TEST = 1 << 36; /// Allows shaders to use i64 and u64. /// /// Supported platforms: @@ -1080,7 +1090,7 @@ bitflags_array! { /// - Metal (with MSL 2.3+) /// /// This is a native only feature. - const SHADER_INT64 = 1 << 36; + const SHADER_INT64 = 1 << 37; /// Allows compute and fragment shaders to use the subgroup operation built-ins /// /// Supported Platforms: @@ -1089,14 +1099,14 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const SUBGROUP = 1 << 37; + const SUBGROUP = 1 << 38; /// Allows vertex shaders to use the subgroup operation built-ins /// /// Supported Platforms: /// - Vulkan /// /// This is a native only feature. - const SUBGROUP_VERTEX = 1 << 38; + const SUBGROUP_VERTEX = 1 << 39; /// Allows shaders to use the subgroup barrier /// /// Supported Platforms: @@ -1104,7 +1114,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const SUBGROUP_BARRIER = 1 << 39; + const SUBGROUP_BARRIER = 1 << 40; /// Allows the use of pipeline cache objects /// /// Supported platforms: @@ -1113,7 +1123,7 @@ bitflags_array! { /// Unimplemented Platforms: /// - DX12 /// - Metal - const PIPELINE_CACHE = 1 << 40; + const PIPELINE_CACHE = 1 << 41; /// Allows shaders to use i64 and u64 atomic min and max. /// /// Supported platforms: @@ -1122,7 +1132,7 @@ bitflags_array! { /// - Metal (with MSL 2.4+) /// /// This is a native only feature. - const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 41; + const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 42; /// Allows shaders to use all i64 and u64 atomic operations. /// /// Supported platforms: @@ -1130,7 +1140,7 @@ bitflags_array! { /// - DX12 (with SM 6.6+) /// /// This is a native only feature. - const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 42; + const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 43; /// Allows using the [VK_GOOGLE_display_timing] Vulkan extension. /// /// This is used for frame pacing to reduce latency, and is generally only available on Android. @@ -1146,7 +1156,7 @@ bitflags_array! { /// /// [VK_GOOGLE_display_timing]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html /// [`Surface::as_hal()`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html#method.as_hal - const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 43; + const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 44; /// Allows using the [VK_KHR_external_memory_win32] Vulkan extension. /// @@ -1156,7 +1166,7 @@ bitflags_array! { /// This is a native only feature. /// /// [VK_KHR_external_memory_win32]: https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_external_memory_win32.html - const VULKAN_EXTERNAL_MEMORY_WIN32 = 1 << 44; + const VULKAN_EXTERNAL_MEMORY_WIN32 = 1 << 45; /// Enables R64Uint image atomic min and max. /// @@ -1166,7 +1176,7 @@ bitflags_array! { /// - Metal (with MSL 3.1+) /// /// This is a native only feature. - const TEXTURE_INT64_ATOMIC = 1 << 45; + const TEXTURE_INT64_ATOMIC = 1 << 46; /// Allows uniform buffers to be bound as binding arrays. /// @@ -1183,7 +1193,7 @@ bitflags_array! { /// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s `shaderUniformBufferArrayNonUniformIndexing` feature) /// /// This is a native only feature. - const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 46; + const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 47; /// Enables mesh shaders and task shaders in mesh shader pipelines. /// @@ -1195,7 +1205,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const EXPERIMENTAL_MESH_SHADER = 1 << 47; + const EXPERIMENTAL_MESH_SHADER = 1 << 48; /// ***THIS IS EXPERIMENTAL:*** Features enabled by this may have /// major bugs in them and are expected to be subject to breaking changes, suggestions @@ -1210,7 +1220,7 @@ bitflags_array! { /// This is a native only feature /// /// [`AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN`]: super::AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN - const EXPERIMENTAL_RAY_HIT_VERTEX_RETURN = 1 << 48; + const EXPERIMENTAL_RAY_HIT_VERTEX_RETURN = 1 << 49; /// Enables multiview in mesh shader pipelines /// @@ -1222,7 +1232,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 49; + const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 50; /// Allows usage of additional vertex formats in [BlasTriangleGeometrySizeDescriptor::vertex_format] /// @@ -1231,7 +1241,7 @@ bitflags_array! { /// - DX12 /// /// [BlasTriangleGeometrySizeDescriptor::vertex_format]: super::BlasTriangleGeometrySizeDescriptor - const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 50; + const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 51; /// Enables creating shader modules from DirectX HLSL or DXIL shaders (unsafe) /// @@ -1241,7 +1251,7 @@ bitflags_array! { /// - DX12 /// /// This is a native only feature. - const HLSL_DXIL_SHADER_PASSTHROUGH = 1 << 51; + const HLSL_DXIL_SHADER_PASSTHROUGH = 1 << 52; } /// Features that are not guaranteed to be supported. diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 2e21cb904af..fb71e420262 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2230,6 +2230,23 @@ pub enum TextureFormat { /// [`Features::TEXTURE_FORMAT_NV12`] must be enabled to use this texture format. NV12, + /// YUV 4:2:0 chroma subsampled format. + /// + /// Contains two planes: + /// - 0: Single 16 bit channel luminance, of which only the high 10 bits + /// are used. + /// - 1: Dual 16 bit channel chrominance at half width and half height, of + /// which only the high 10 bits are used. + /// + /// Valid view formats for luminance are [`TextureFormat::R16Unorm`]. + /// + /// Valid view formats for chrominance are [`TextureFormat::Rg16Unorm`]. + /// + /// Width and height must be even. + /// + /// [`Features::TEXTURE_FORMAT_P010`] must be enabled to use this texture format. + P010, + // Compressed textures usable with `TEXTURE_COMPRESSION_BC` feature. `TEXTURE_COMPRESSION_SLICED_3D` is required to use with 3D textures. /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). 4 color + alpha pallet. 5 bit R + 6 bit G + 5 bit B + 1 bit alpha. /// [0, 63] ([0, 1] for alpha) converted to/from float [0, 1] in shader. @@ -2475,6 +2492,7 @@ impl<'de> Deserialize<'de> for TextureFormat { "depth24plus" => TextureFormat::Depth24Plus, "depth24plus-stencil8" => TextureFormat::Depth24PlusStencil8, "nv12" => TextureFormat::NV12, + "p010" => TextureFormat::P010, "rgb9e5ufloat" => TextureFormat::Rgb9e5Ufloat, "bc1-rgba-unorm" => TextureFormat::Bc1RgbaUnorm, "bc1-rgba-unorm-srgb" => TextureFormat::Bc1RgbaUnormSrgb, @@ -2604,6 +2622,7 @@ impl Serialize for TextureFormat { TextureFormat::Depth24Plus => "depth24plus", TextureFormat::Depth24PlusStencil8 => "depth24plus-stencil8", TextureFormat::NV12 => "nv12", + TextureFormat::P010 => "p010", TextureFormat::Rgb9e5Ufloat => "rgb9e5ufloat", TextureFormat::Bc1RgbaUnorm => "bc1-rgba-unorm", TextureFormat::Bc1RgbaUnormSrgb => "bc1-rgba-unorm-srgb", @@ -2696,6 +2715,8 @@ impl TextureFormat { (Self::Depth32FloatStencil8, TextureAspect::DepthOnly) => Some(Self::Depth32Float), (Self::NV12, TextureAspect::Plane0) => Some(Self::R8Unorm), (Self::NV12, TextureAspect::Plane1) => Some(Self::Rg8Unorm), + (Self::P010, TextureAspect::Plane0) => Some(Self::R16Unorm), + (Self::P010, TextureAspect::Plane1) => Some(Self::Rg16Unorm), // views to multi-planar formats must specify the plane (format, TextureAspect::All) if !format.is_multi_planar_format() => Some(format), _ => None, @@ -2751,6 +2772,7 @@ impl TextureFormat { pub fn planes(&self) -> Option { match *self { Self::NV12 => Some(2), + Self::P010 => Some(2), _ => None, } } @@ -2788,6 +2810,7 @@ impl TextureFormat { pub fn size_multiple_requirement(&self) -> (u32, u32) { match *self { Self::NV12 => (2, 2), + Self::P010 => (2, 2), _ => self.block_dimensions(), } } @@ -2848,7 +2871,8 @@ impl TextureFormat { | Self::Depth24PlusStencil8 | Self::Depth32Float | Self::Depth32FloatStencil8 - | Self::NV12 => (1, 1), + | Self::NV12 + | Self::P010 => (1, 1), Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb @@ -2966,6 +2990,7 @@ impl TextureFormat { Self::Depth32FloatStencil8 => Features::DEPTH32FLOAT_STENCIL8, Self::NV12 => Features::TEXTURE_FORMAT_NV12, + Self::P010 => Features::TEXTURE_FORMAT_P010, Self::R16Unorm | Self::R16Snorm @@ -3099,8 +3124,10 @@ impl TextureFormat { Self::Depth32Float => ( msaa, attachment), Self::Depth32FloatStencil8 => ( msaa, attachment), - // We only support sampling nv12 textures until we implement transfer plane data. + // We only support sampling nv12 and p010 textures until we + // implement transfer plane data. Self::NV12 => ( none, binding), + Self::P010 => ( none, binding), Self::R16Unorm => ( msaa | s_ro_wo, storage), Self::R16Snorm => ( msaa | s_ro_wo, storage), @@ -3230,7 +3257,7 @@ impl TextureFormat { _ => None, }, - Self::NV12 => match aspect { + Self::NV12 | Self::P010 => match aspect { Some(TextureAspect::Plane0) | Some(TextureAspect::Plane1) => { Some(unfilterable_float) } @@ -3363,6 +3390,12 @@ impl TextureFormat { _ => None, }, + Self::P010 => match aspect { + Some(TextureAspect::Plane0) => Some(2), + Some(TextureAspect::Plane1) => Some(4), + _ => None, + }, + Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb | Self::Bc4RUnorm | Self::Bc4RSnorm => { Some(8) } @@ -3448,6 +3481,7 @@ impl TextureFormat { | Self::Depth32Float | Self::Depth32FloatStencil8 | Self::NV12 + | Self::P010 | Self::Rgb9e5Ufloat | Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb @@ -3531,6 +3565,7 @@ impl TextureFormat { | Self::Depth32Float | Self::Depth32FloatStencil8 | Self::NV12 + | Self::P010 | Self::Rgb9e5Ufloat | Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb @@ -3625,7 +3660,7 @@ impl TextureFormat { _ => 2, }, - Self::NV12 => match aspect { + Self::NV12 | Self::P010 => match aspect { TextureAspect::Plane0 => 1, TextureAspect::Plane1 => 2, _ => 3, @@ -3735,6 +3770,8 @@ impl TextureFormat { Self::Stencil8 => 1, // Two chroma bytes per block, one luma byte per block Self::NV12 => 3, + // Two chroma u16s and one luma u16 per block + Self::P010 => 6, f => { log::warn!("Memory footprint for format {f:?} is not implemented"); 0