diff --git a/Cargo.lock b/Cargo.lock index eac7830087..458d611ff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,8 +995,7 @@ dependencies = [ [[package]] name = "metal" version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" +source = "git+https://github.com/gfx-rs/metal-rs?rev=140c8f4#140c8f4e39001ae154f153ffc767da6c0c9d7f06" dependencies = [ "bitflags", "block", diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 03b333fa99..c89c38d9db 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -94,6 +94,8 @@ impl RenderBundleEncoder { parent_id: id::DeviceId, base: Option>, ) -> Result { + //TODO: validate that attachment formats are renderable, + // have expected aspects, support multisampling. Ok(Self { base: base.unwrap_or_else(|| BasePass::new(&desc.label)), parent_id, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 5940461f87..3046a7a23b 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -409,6 +409,8 @@ pub enum RenderPassErrorInner { InvalidColorAttachmentFormat(wgt::TextureFormat), #[error("attachment format {0:?} is not a depth-stencil format")] InvalidDepthStencilAttachmentFormat(wgt::TextureFormat), + #[error("attachment format {0:?} can not be resolved")] + UnsupportedResolveTargetFormat(wgt::TextureFormat), #[error("necessary attachments are missing")] MissingAttachments, #[error("attachments have differing sizes: {previous:?} is followed by {mismatch:?}")] @@ -418,10 +420,15 @@ pub enum RenderPassErrorInner { }, #[error("attachment's sample count {0} is invalid")] InvalidSampleCount(u32), - #[error("attachment with resolve target must be multi-sampled")] - InvalidResolveSourceSampleCount, - #[error("resolve target must have a sample count of 1")] - InvalidResolveTargetSampleCount, + #[error("resolve source must be multi-sampled (has {src} samples) while the resolve destination must not be multisampled (has {dst} samples)")] + InvalidResolveSampleCounts { src: u32, dst: u32 }, + #[error( + "resource source format ({src:?}) must match the resolve destination format ({dst:?})" + )] + MismatchedResolveTextureFormat { + src: wgt::TextureFormat, + dst: wgt::TextureFormat, + }, #[error("surface texture is dropped before the render pass is finished")] SurfaceTextureDropped, #[error("not enough memory left")] @@ -438,7 +445,8 @@ pub enum RenderPassErrorInner { MissingFeatures(#[from] MissingFeatures), #[error(transparent)] MissingDownlevelFlags(#[from] MissingDownlevelFlags), - #[error("indirect draw uses bytes {offset}..{end_offset} {} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!("(using count {})", v)))] + #[error("indirect draw uses bytes {offset}..{end_offset} {} which overruns indirect buffer of size {buffer_size}", + count.map_or_else(String::new, |v| format!("(using count {})", v)))] IndirectBufferOverrun { count: Option, offset: u64, @@ -823,6 +831,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .views .use_extend(&*view_guard, resolve_target, (), ()) .map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?; + check_multiview(resolve_view)?; if color_view.extent != resolve_view.extent { return Err(RenderPassErrorInner::AttachmentsDimensionMismatch { @@ -830,11 +839,26 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { mismatch: ("resolve", resolve_view.extent), }); } - if color_view.samples == 1 { - return Err(RenderPassErrorInner::InvalidResolveSourceSampleCount); + if color_view.samples == 1 || resolve_view.samples != 1 { + return Err(RenderPassErrorInner::InvalidResolveSampleCounts { + src: color_view.samples, + dst: resolve_view.samples, + }); } - if resolve_view.samples != 1 { - return Err(RenderPassErrorInner::InvalidResolveTargetSampleCount); + if color_view.desc.format != resolve_view.desc.format { + return Err(RenderPassErrorInner::MismatchedResolveTextureFormat { + src: color_view.desc.format, + dst: resolve_view.desc.format, + }); + } + if !resolve_view + .format_features + .flags + .contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE) + { + return Err(RenderPassErrorInner::UnsupportedResolveTargetFormat( + resolve_view.desc.format, + )); } cmd_buf.texture_memory_actions.register_implicit_init( diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 043443684c..057f0751f4 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1890,19 +1890,19 @@ impl Device { view_samples: view.samples, }); } - match (sample_type, format_info.sample_type, view.format_features.filterable) { - (Tst::Uint, Tst::Uint, ..) | - (Tst::Sint, Tst::Sint, ..) | - (Tst::Depth, Tst::Depth, ..) | + match (sample_type, format_info.sample_type) { + (Tst::Uint, Tst::Uint) | + (Tst::Sint, Tst::Sint) | + (Tst::Depth, Tst::Depth) | // if we expect non-filterable, accept anything float - (Tst::Float { filterable: false }, Tst::Float { .. }, ..) | + (Tst::Float { filterable: false }, Tst::Float { .. }) | // if we expect filterable, require it - (Tst::Float { filterable: true }, Tst::Float { filterable: true }, ..) | - // if we expect filterable, also accept Float that is defined as unfilterable if filterable feature is explicitly enabled - // (only hit if wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES is enabled) - (Tst::Float { filterable: true }, Tst::Float { .. }, true) | + (Tst::Float { filterable: true }, Tst::Float { filterable: true }) | // if we expect float, also accept depth (Tst::Float { .. }, Tst::Depth, ..) => {} + // if we expect filterable, also accept Float that is defined as unfilterable if filterable feature is explicitly enabled + // (only hit if wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES is enabled) + (Tst::Float { filterable: true }, Tst::Float { .. }) if view.format_features.flags.contains(wgt::TextureFormatFeatureFlags::FILTERABLE) => {} _ => { return Err(Error::InvalidTextureSampleType { binding, @@ -2268,6 +2268,8 @@ impl Device { hub: &Hub, token: &mut Token, ) -> Result, pipeline::CreateRenderPipelineError> { + use wgt::TextureFormatFeatureFlags as Tfff; + //TODO: only lock mutable if the layout is derived let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(token); let (mut bgl_guard, mut token) = hub.bind_group_layouts.write(&mut token); @@ -2413,12 +2415,16 @@ impl Device { { break Some(pipeline::ColorStateError::FormatNotRenderable(cs.format)); } - if cs.blend.is_some() && !format_features.filterable { + if cs.blend.is_some() && !format_features.flags.contains(Tfff::FILTERABLE) { break Some(pipeline::ColorStateError::FormatNotBlendable(cs.format)); } if !hal::FormatAspects::from(cs.format).contains(hal::FormatAspects::COLOR) { break Some(pipeline::ColorStateError::FormatNotColor(cs.format)); } + if desc.multisample.count > 1 && !format_features.flags.contains(Tfff::MULTISAMPLE) + { + break Some(pipeline::ColorStateError::FormatNotMultisampled(cs.format)); + } break None; }; @@ -2429,8 +2435,8 @@ impl Device { if let Some(ds) = depth_stencil_state { let error = loop { - if !self - .describe_format_features(adapter, ds.format)? + let format_features = self.describe_format_features(adapter, ds.format)?; + if !format_features .allowed_usages .contains(wgt::TextureUsages::RENDER_ATTACHMENT) { @@ -2438,6 +2444,7 @@ impl Device { ds.format, )); } + let aspect = hal::FormatAspects::from(ds.format); if ds.is_depth_enabled() && !aspect.contains(hal::FormatAspects::DEPTH) { break Some(pipeline::DepthStencilStateError::FormatNotDepth(ds.format)); @@ -2447,6 +2454,13 @@ impl Device { ds.format, )); } + if desc.multisample.count > 1 && !format_features.flags.contains(Tfff::MULTISAMPLE) + { + break Some(pipeline::DepthStencilStateError::FormatNotMultisampled( + ds.format, + )); + } + break None; }; if let Some(e) = error { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 4c6ddc7ee0..08773aa72c 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -270,14 +270,25 @@ impl Adapter { // We are currently taking the filtering and blending together, // but we may reconsider this in the future if there are formats // in the wild for which these two capabilities do not match. - let filterable = caps.contains(Tfc::SAMPLED_LINEAR) - && (!caps.contains(Tfc::COLOR_ATTACHMENT) - || caps.contains(Tfc::COLOR_ATTACHMENT_BLEND)); + flags.set( + wgt::TextureFormatFeatureFlags::FILTERABLE, + caps.contains(Tfc::SAMPLED_LINEAR) + && (!caps.contains(Tfc::COLOR_ATTACHMENT) + || caps.contains(Tfc::COLOR_ATTACHMENT_BLEND)), + ); + + flags.set( + wgt::TextureFormatFeatureFlags::MULTISAMPLE, + caps.contains(Tfc::MULTISAMPLE), + ); + flags.set( + wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE, + caps.contains(Tfc::MULTISAMPLE_RESOLVE), + ); wgt::TextureFormatFeatures { allowed_usages, flags, - filterable, } } diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index ea7be6fcac..34a57efcd0 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -270,6 +270,8 @@ pub enum ColorStateError { FormatNotBlendable(wgt::TextureFormat), #[error("format {0:?} does not have a color aspect")] FormatNotColor(wgt::TextureFormat), + #[error("format {0:?} can't be multisampled")] + FormatNotMultisampled(wgt::TextureFormat), #[error("output format {pipeline} is incompatible with the shader {shader}")] IncompatibleFormat { pipeline: validation::NumericType, @@ -287,6 +289,8 @@ pub enum DepthStencilStateError { FormatNotDepth(wgt::TextureFormat), #[error("format {0:?} does not have a stencil aspect, but stencil test/write is enabled")] FormatNotStencil(wgt::TextureFormat), + #[error("format {0:?} can't be multisampled")] + FormatNotMultisampled(wgt::TextureFormat), } #[derive(Clone, Debug, Error)] diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index e76807a64b..f9a9a09bd0 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -170,8 +170,8 @@ impl Global { hal_usage: conv::map_texture_usage(config.usage, config.format.into()), format_features: wgt::TextureFormatFeatures { allowed_usages: wgt::TextureUsages::RENDER_ATTACHMENT, - flags: wgt::TextureFormatFeatureFlags::empty(), - filterable: false, + flags: wgt::TextureFormatFeatureFlags::MULTISAMPLE + | wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE, }, initialization_status: TextureInitTracker::new(1, 1), full_range: TextureSelector { diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index b83be4abbb..0111dc342e 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -71,7 +71,7 @@ winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] } native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true } [target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies] -mtl = { package = "metal", version = "0.23.1" } +mtl = { package = "metal", git = "https://github.com/gfx-rs/metal-rs", rev = "140c8f4" } objc = "0.2.5" core-graphics-types = "0.1" diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index b405d55da9..8f3ebbf152 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -332,13 +332,16 @@ impl crate::Adapter for super::Adapter { ); let mut caps = Tfc::COPY_SRC | Tfc::COPY_DST; - let can_image = 0 - != data.Support1 - & (d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE1D - | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE2D - | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE3D - | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE); - caps.set(Tfc::SAMPLED, can_image); + let is_texture = data.Support1 + & (d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE1D + | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE2D + | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURE3D + | d3d12::D3D12_FORMAT_SUPPORT1_TEXTURECUBE) + != 0; + caps.set( + Tfc::SAMPLED, + is_texture && data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_LOAD != 0, + ); caps.set( Tfc::SAMPLED_LINEAR, data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE != 0, @@ -364,6 +367,19 @@ impl crate::Adapter for super::Adapter { data.Support2 & d3d12::D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD != 0, ); + let no_msaa_load = caps.contains(Tfc::SAMPLED) + && data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD == 0; + let no_msaa_target = data.Support1 + & (d3d12::D3D12_FORMAT_SUPPORT1_RENDER_TARGET + | d3d12::D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) + != 0 + && data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET == 0; + caps.set(Tfc::MULTISAMPLE, !no_msaa_load && !no_msaa_target); + caps.set( + Tfc::MULTISAMPLE_RESOLVE, + data.Support1 & d3d12::D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE != 0, + ); + caps } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index b8beef5eea..e4bb5b60c9 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -576,9 +576,11 @@ impl crate::Adapter for super::Adapter { ) -> crate::TextureFormatCapabilities { use crate::TextureFormatCapabilities as Tfc; use wgt::TextureFormat as Tf; + // The storage types are sprinkled based on section // "TEXTURE IMAGE LOADS AND STORES" of GLES-3.2 spec. - let unfiltered_color = Tfc::SAMPLED | Tfc::COLOR_ATTACHMENT; + let unfiltered_color = + Tfc::SAMPLED | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE; let filtered_color = unfiltered_color | Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT_BLEND; match format { Tf::R8Unorm | Tf::R8Snorm => filtered_color, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 6e735779a6..5dee453eae 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -373,7 +373,7 @@ impl super::Queue { gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32); gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32); let mut unbind_unpack_buffer = false; - if format_info.block_dimensions == (1, 1) { + if !format_info.is_compressed() { let buffer_data; let unpack_data = match src.raw { Some(buffer) => { @@ -540,7 +540,7 @@ impl super::Queue { ref copy, } => { let format_info = src_format.describe(); - if format_info.block_dimensions != (1, 1) { + if format_info.is_compressed() { log::error!("Not implemented yet: compressed texture copy to buffer"); return; } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 4b292a3b83..feb7bf7773 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -562,10 +562,15 @@ bitflags!( /// Format can be used as depth-stencil and input attachment. const DEPTH_STENCIL_ATTACHMENT = 1 << 8; + /// Format can be multisampled. + const MULTISAMPLE = 1 << 9; + /// Format can be used for render pass resolve targets. + const MULTISAMPLE_RESOLVE = 1 << 10; + /// Format can be copied from. - const COPY_SRC = 1 << 9; + const COPY_SRC = 1 << 11; /// Format can be copied to. - const COPY_DST = 1 << 10; + const COPY_DST = 1 << 12; } ); diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 287430a7fe..cf0e0f718d 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -55,6 +55,26 @@ impl crate::Adapter for super::Adapter { (Tfc::STORAGE_READ_WRITE, Tfc::STORAGE_READ_WRITE) } }; + let msaa_desktop_if = if pc.msaa_desktop { + Tfc::MULTISAMPLE + } else { + Tfc::empty() + }; + let msaa_apple7x_if = if pc.msaa_desktop | pc.msaa_apple7 { + Tfc::MULTISAMPLE + } else { + Tfc::empty() + }; + let msaa_resolve_desktop_if = if pc.msaa_desktop { + Tfc::MULTISAMPLE_RESOLVE + } else { + Tfc::empty() + }; + let msaa_resolve_apple3x_if = if pc.msaa_desktop | pc.msaa_apple3 { + Tfc::MULTISAMPLE_RESOLVE + } else { + Tfc::empty() + }; let extra = match format { Tf::R8Unorm => { @@ -63,59 +83,77 @@ impl crate::Adapter for super::Adapter { | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::R8Snorm => { Tfc::SAMPLED_LINEAR | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::R8Uint | Tf::R8Sint | Tf::R16Uint | Tf::R16Sint => { - read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT + read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE } Tf::R16Float => { read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::R16Unorm | Tf::R16Snorm => { Tfc::SAMPLED_LINEAR | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | msaa_resolve_desktop_if } Tf::Rg8Unorm | Tf::Rg8Snorm => { Tfc::SAMPLED_LINEAR | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } - Tf::Rg8Uint | Tf::Rg8Sint => Tfc::COLOR_ATTACHMENT, + Tf::Rg8Uint | Tf::Rg8Sint => Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE, Tf::R32Uint | Tf::R32Sint => { - if pc.format_r32_all { - read_write_tier1_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT + let storage = if pc.format_r32_all { + read_write_tier1_if | Tfc::STORAGE } else { - Tfc::COLOR_ATTACHMENT - } + Tfc::empty() + }; + Tfc::COLOR_ATTACHMENT | storage | msaa_desktop_if } Tf::R32Float => { - let mut flags = Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND; - if pc.format_r32float_all { - flags |= read_write_tier1_if | Tfc::STORAGE | Tfc::SAMPLED_LINEAR; + let flags = Tfc::COLOR_ATTACHMENT + | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | msaa_resolve_desktop_if; + let extra = if pc.format_r32float_all { + read_write_tier1_if | Tfc::STORAGE | Tfc::SAMPLED_LINEAR } else if pc.format_r32float_no_filter { - flags |= Tfc::SAMPLED_LINEAR; - } - flags + Tfc::SAMPLED_LINEAR + } else { + Tfc::empty() + }; + flags | extra } Tf::Rg16Uint | Tf::Rg16Sint => { - read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT + read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE } Tf::Rg16Unorm | Tf::Rg16Snorm => { Tfc::SAMPLED_LINEAR | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | msaa_resolve_desktop_if } Tf::Rg16Float => { read_write_tier2_if @@ -123,6 +161,8 @@ impl crate::Adapter for super::Adapter { | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::Rgba8Unorm => { read_write_tier2_if @@ -130,10 +170,15 @@ impl crate::Adapter for super::Adapter { | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::Rgba8UnormSrgb | Tf::Bgra8UnormSrgb => { - let mut flags = - Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND; + let mut flags = Tfc::SAMPLED_LINEAR + | Tfc::COLOR_ATTACHMENT + | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE; flags.set(Tfc::STORAGE, pc.format_rgba8_srgb_all); flags } @@ -142,25 +187,34 @@ impl crate::Adapter for super::Adapter { | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::Rgba8Uint | Tf::Rgba8Sint => { - read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT + read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE } Tf::Rgb10a2Unorm => { - let mut flags = - Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND; + let mut flags = Tfc::SAMPLED_LINEAR + | Tfc::COLOR_ATTACHMENT + | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE; flags.set(Tfc::STORAGE, pc.format_rgb10a2_unorm_all); flags } Tf::Rg11b10Float => { - let mut flags = - Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND; + let mut flags = Tfc::SAMPLED_LINEAR + | Tfc::COLOR_ATTACHMENT + | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE; flags.set(Tfc::STORAGE, pc.format_rg11b10_all); flags } - Tf::Rg32Uint | Tf::Rg32Sint => Tfc::COLOR_ATTACHMENT | Tfc::STORAGE, + Tf::Rg32Uint | Tf::Rg32Sint => Tfc::COLOR_ATTACHMENT | Tfc::STORAGE | msaa_apple7x_if, Tf::Rg32Float => { - let mut flags = Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND; + let mut flags = + Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND | msaa_apple7x_if; if pc.format_rg32float_all { flags |= Tfc::STORAGE | Tfc::SAMPLED_LINEAR; } else if pc.format_rg32float_color_blend { @@ -169,13 +223,15 @@ impl crate::Adapter for super::Adapter { flags } Tf::Rgba16Uint | Tf::Rgba16Sint => { - read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT + read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE } Tf::Rgba16Unorm | Tf::Rgba16Snorm => { Tfc::SAMPLED_LINEAR | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | msaa_resolve_desktop_if } Tf::Rgba16Float => { read_write_tier2_if @@ -183,38 +239,52 @@ impl crate::Adapter for super::Adapter { | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND + | Tfc::MULTISAMPLE + | Tfc::MULTISAMPLE_RESOLVE } Tf::Rgba32Uint | Tf::Rgba32Sint => { - if pc.format_rgba32int_color_write { - read_write_tier2_if | Tfc::COLOR_ATTACHMENT | Tfc::STORAGE + let storage = if pc.format_rgba32int_color_write { + read_write_tier2_if | Tfc::STORAGE } else { - Tfc::COLOR_ATTACHMENT - } + Tfc::empty() + }; + storage | Tfc::COLOR_ATTACHMENT | msaa_desktop_if } Tf::Rgba32Float => { - if pc.format_rgba32float_all { + let extra = if pc.format_rgba32float_all { read_write_tier2_if | Tfc::SAMPLED_LINEAR | Tfc::STORAGE - | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND } else if pc.format_rgba32float_color_write { - read_write_tier2_if | Tfc::COLOR_ATTACHMENT | Tfc::STORAGE + read_write_tier2_if | Tfc::STORAGE } else { - Tfc::COLOR_ATTACHMENT - } + Tfc::empty() + }; + extra | Tfc::COLOR_ATTACHMENT | msaa_apple7x_if | msaa_resolve_desktop_if } Tf::Depth32Float => { - if pc.format_depth32float_filter { - Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::SAMPLED_LINEAR + let linear = if pc.format_depth32float_filter { + Tfc::SAMPLED_LINEAR } else { - Tfc::DEPTH_STENCIL_ATTACHMENT - } + Tfc::empty() + }; + linear | Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::MULTISAMPLE | msaa_resolve_apple3x_if } Tf::Depth24Plus | Tf::Depth24PlusStencil8 => { - Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::SAMPLED_LINEAR + Tfc::DEPTH_STENCIL_ATTACHMENT + | Tfc::SAMPLED_LINEAR + | Tfc::MULTISAMPLE + | msaa_resolve_apple3x_if + } + Tf::Rgb9e5Ufloat => { + let msaa = if msaa_desktop_if.is_empty() { + Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE + } else { + Tfc::empty() + }; + Tfc::SAMPLED_LINEAR | msaa } - Tf::Rgb9e5Ufloat => Tfc::SAMPLED_LINEAR, Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb | Tf::Bc2RgbaUnorm @@ -613,6 +683,9 @@ impl super::PrivateCapabilities { } else { mtl::MTLReadWriteTextureTier::TierNone }, + msaa_desktop: os_is_mac, + msaa_apple3: family_check && device.supports_family(MTLGPUFamily::Apple3), + msaa_apple7: family_check && device.supports_family(MTLGPUFamily::Apple7), resource_heaps: Self::supports_any(device, RESOURCE_HEAP_SUPPORT), argument_buffers: Self::supports_any(device, ARGUMENT_BUFFER_SUPPORT), shared_textures: !os_is_mac, diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 2ea58c2635..fab99d19b8 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -144,6 +144,9 @@ struct PrivateCapabilities { msl_version: mtl::MTLLanguageVersion, fragment_rw_storage: bool, read_write_texture_tier: mtl::MTLReadWriteTextureTier, + msaa_desktop: bool, + msaa_apple3: bool, + msaa_apple7: bool, resource_heaps: bool, argument_buffers: bool, shared_textures: bool, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 993d55538b..e084d09afa 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1332,6 +1332,7 @@ impl crate::Adapter for super::Adapter { format: wgt::TextureFormat, ) -> crate::TextureFormatCapabilities { use crate::TextureFormatCapabilities as Tfc; + let vk_format = self.private_caps.map_texture_format(format); let properties = self .phd_capabilities @@ -1385,6 +1386,11 @@ impl crate::Adapter for super::Adapter { vk::FormatFeatureFlags::TRANSFER_DST | vk::FormatFeatureFlags::BLIT_DST, ), ); + // Vulkan is very permissive about MSAA + flags.set( + Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE, + !format.describe().is_compressed(), + ); flags } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 36f62e65bc..e2a15ca440 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1410,12 +1410,20 @@ bitflags::bitflags! { /// Feature flags for a texture format. #[repr(transparent)] pub struct TextureFormatFeatureFlags: u32 { + /// If not present, the texture can't be sampled with a filtering sampler. + /// This may overwrite TextureSampleType::Float.filterable + const FILTERABLE = 1 << 0; + /// Allows [`TextureDescriptor::sample_count`] greater than `1`. + const MULTISAMPLE = 1 << 1; + /// Allows a texture of this format to back a view passed as `resolve_target` + /// to a render pass for an automatic driver-implemented resolve. + const MULTISAMPLE_RESOLVE = 1 << 2; /// When used as a STORAGE texture, then a texture with this format can be bound with /// [`StorageTextureAccess::ReadOnly`] or [`StorageTextureAccess::ReadWrite`]. - const STORAGE_READ_WRITE = 1 << 0; + const STORAGE_READ_WRITE = 1 << 3; /// When used as a STORAGE texture, then a texture with this format can be written to with atomics. // TODO: No access flag exposed as of writing - const STORAGE_ATOMICS = 1 << 1; + const STORAGE_ATOMICS = 1 << 4; } } @@ -1431,9 +1439,6 @@ pub struct TextureFormatFeatures { pub allowed_usages: TextureUsages, /// Additional property flags for the format. pub flags: TextureFormatFeatureFlags, - /// If `filterable` is false, the texture can't be sampled with a filtering sampler. - /// This may overwrite TextureSampleType::Float.filterable - pub filterable: bool, } /// Information about a texture format. @@ -1455,6 +1460,13 @@ pub struct TextureFormatInfo { pub guaranteed_format_features: TextureFormatFeatures, } +impl TextureFormatInfo { + /// Return `true` for compressed formats. + pub fn is_compressed(&self) -> bool { + self.block_dimensions != (1, 1) + } +} + /// Underlying texture data format. /// /// If there is a conversion in the format (such as srgb -> linear), The conversion listed is for @@ -1984,9 +1996,18 @@ impl TextureFormat { let float = TextureSampleType::Float { filterable: true }; let depth = TextureSampleType::Depth; - // Color spaces - let linear = false; - let srgb = true; + enum ColorSpace { + Linear, + Corrected, + } + let linear = ColorSpace::Linear; + let corrected = ColorSpace::Corrected; + + // Multisampling + let noaa = TextureFormatFeatureFlags::empty(); + let msaa = TextureFormatFeatureFlags::MULTISAMPLE; + let msaa_resolve = + TextureFormatFeatureFlags::MULTISAMPLE | TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE; // Flags let basic = @@ -1999,145 +2020,238 @@ impl TextureFormat { let ( required_features, sample_type, - srgb, + color_space, + msaa_flags, block_dimensions, block_size, allowed_usages, components, ) = match self { // Normal 8 bit textures - Self::R8Unorm => (native, float, linear, (1, 1), 1, attachment, 1), - Self::R8Snorm => (native, float, linear, (1, 1), 1, basic, 1), - Self::R8Uint => (native, uint, linear, (1, 1), 1, attachment, 1), - Self::R8Sint => (native, sint, linear, (1, 1), 1, attachment, 1), + Self::R8Unorm => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 1, + attachment, + 1, + ), + Self::R8Snorm => (native, float, linear, msaa, (1, 1), 1, basic, 1), + Self::R8Uint => (native, uint, linear, msaa, (1, 1), 1, attachment, 1), + Self::R8Sint => (native, sint, linear, msaa, (1, 1), 1, attachment, 1), // Normal 16 bit textures - Self::R16Uint => (native, uint, linear, (1, 1), 2, attachment, 1), - Self::R16Sint => (native, sint, linear, (1, 1), 2, attachment, 1), - Self::R16Float => (native, float, linear, (1, 1), 2, attachment, 1), - Self::Rg8Unorm => (native, float, linear, (1, 1), 2, attachment, 2), - Self::Rg8Snorm => (native, float, linear, (1, 1), 2, attachment, 2), - Self::Rg8Uint => (native, uint, linear, (1, 1), 2, attachment, 2), - Self::Rg8Sint => (native, sint, linear, (1, 1), 2, basic, 2), + Self::R16Uint => (native, uint, linear, msaa, (1, 1), 2, attachment, 1), + Self::R16Sint => (native, sint, linear, msaa, (1, 1), 2, attachment, 1), + Self::R16Float => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 2, + attachment, + 1, + ), + Self::Rg8Unorm => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 2, + attachment, + 2, + ), + Self::Rg8Snorm => (native, float, linear, msaa, (1, 1), 2, attachment, 2), + Self::Rg8Uint => (native, uint, linear, msaa, (1, 1), 2, attachment, 2), + Self::Rg8Sint => (native, sint, linear, msaa, (1, 1), 2, basic, 2), // Normal 32 bit textures - Self::R32Uint => (native, uint, linear, (1, 1), 4, all_flags, 1), - Self::R32Sint => (native, sint, linear, (1, 1), 4, all_flags, 1), - Self::R32Float => (native, nearest, linear, (1, 1), 4, all_flags, 1), - Self::Rg16Uint => (native, uint, linear, (1, 1), 4, attachment, 2), - Self::Rg16Sint => (native, sint, linear, (1, 1), 4, attachment, 2), - Self::Rg16Float => (native, float, linear, (1, 1), 4, attachment, 2), - Self::Rgba8Unorm => (native, float, linear, (1, 1), 4, all_flags, 4), - Self::Rgba8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment, 4), - Self::Rgba8Snorm => (native, float, linear, (1, 1), 4, storage, 4), - Self::Rgba8Uint => (native, uint, linear, (1, 1), 4, all_flags, 4), - Self::Rgba8Sint => (native, sint, linear, (1, 1), 4, all_flags, 4), - Self::Bgra8Unorm => (native, float, linear, (1, 1), 4, attachment, 4), - Self::Bgra8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment, 4), + Self::R32Uint => (native, uint, linear, noaa, (1, 1), 4, all_flags, 1), + Self::R32Sint => (native, sint, linear, noaa, (1, 1), 4, all_flags, 1), + Self::R32Float => (native, nearest, linear, msaa, (1, 1), 4, all_flags, 1), + Self::Rg16Uint => (native, uint, linear, msaa, (1, 1), 4, attachment, 2), + Self::Rg16Sint => (native, sint, linear, msaa, (1, 1), 4, attachment, 2), + Self::Rg16Float => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 4, + attachment, + 2, + ), + Self::Rgba8Unorm => (native, float, linear, msaa_resolve, (1, 1), 4, all_flags, 4), + Self::Rgba8UnormSrgb => ( + native, + float, + corrected, + msaa_resolve, + (1, 1), + 4, + attachment, + 4, + ), + Self::Rgba8Snorm => (native, float, linear, msaa, (1, 1), 4, storage, 4), + Self::Rgba8Uint => (native, uint, linear, msaa, (1, 1), 4, all_flags, 4), + Self::Rgba8Sint => (native, sint, linear, msaa, (1, 1), 4, all_flags, 4), + Self::Bgra8Unorm => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 4, + attachment, + 4, + ), + Self::Bgra8UnormSrgb => ( + native, + float, + corrected, + msaa_resolve, + (1, 1), + 4, + attachment, + 4, + ), // Packed 32 bit textures - Self::Rgb10a2Unorm => (native, float, linear, (1, 1), 4, attachment, 4), - Self::Rg11b10Float => (native, float, linear, (1, 1), 4, basic, 3), + Self::Rgb10a2Unorm => ( + native, + float, + linear, + msaa_resolve, + (1, 1), + 4, + attachment, + 4, + ), + Self::Rg11b10Float => (native, float, linear, msaa, (1, 1), 4, basic, 3), // Packed 32 bit textures - Self::Rg32Uint => (native, uint, linear, (1, 1), 8, all_flags, 2), - Self::Rg32Sint => (native, sint, linear, (1, 1), 8, all_flags, 2), - Self::Rg32Float => (native, nearest, linear, (1, 1), 8, all_flags, 2), - Self::Rgba16Uint => (native, uint, linear, (1, 1), 8, all_flags, 4), - Self::Rgba16Sint => (native, sint, linear, (1, 1), 8, all_flags, 4), - Self::Rgba16Float => (native, float, linear, (1, 1), 8, all_flags, 4), + Self::Rg32Uint => (native, uint, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rg32Sint => (native, sint, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rg32Float => (native, nearest, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rgba16Uint => (native, uint, linear, msaa, (1, 1), 8, all_flags, 4), + Self::Rgba16Sint => (native, sint, linear, msaa, (1, 1), 8, all_flags, 4), + Self::Rgba16Float => (native, float, linear, msaa_resolve, (1, 1), 8, all_flags, 4), // Packed 32 bit textures - Self::Rgba32Uint => (native, uint, linear, (1, 1), 16, all_flags, 4), - Self::Rgba32Sint => (native, sint, linear, (1, 1), 16, all_flags, 4), - Self::Rgba32Float => (native, nearest, linear, (1, 1), 16, all_flags, 4), + Self::Rgba32Uint => (native, uint, linear, noaa, (1, 1), 16, all_flags, 4), + Self::Rgba32Sint => (native, sint, linear, noaa, (1, 1), 16, all_flags, 4), + Self::Rgba32Float => (native, nearest, linear, noaa, (1, 1), 16, all_flags, 4), // Depth-stencil textures - Self::Depth32Float => (native, depth, linear, (1, 1), 4, attachment, 1), - Self::Depth24Plus => (native, depth, linear, (1, 1), 4, attachment, 1), - Self::Depth24PlusStencil8 => (native, depth, linear, (1, 1), 4, attachment, 2), + Self::Depth32Float => (native, depth, linear, msaa, (1, 1), 4, attachment, 1), + Self::Depth24Plus => (native, depth, linear, msaa, (1, 1), 4, attachment, 1), + Self::Depth24PlusStencil8 => (native, depth, linear, msaa, (1, 1), 4, attachment, 2), // Packed uncompressed - Self::Rgb9e5Ufloat => (native, float, linear, (1, 1), 4, basic, 3), + Self::Rgb9e5Ufloat => (native, float, linear, noaa, (1, 1), 4, basic, 3), // BCn compressed textures - Self::Bc1RgbaUnorm => (bc, float, linear, (4, 4), 8, basic, 4), - Self::Bc1RgbaUnormSrgb => (bc, float, srgb, (4, 4), 8, basic, 4), - Self::Bc2RgbaUnorm => (bc, float, linear, (4, 4), 16, basic, 4), - Self::Bc2RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic, 4), - Self::Bc3RgbaUnorm => (bc, float, linear, (4, 4), 16, basic, 4), - Self::Bc3RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic, 4), - Self::Bc4RUnorm => (bc, float, linear, (4, 4), 8, basic, 1), - Self::Bc4RSnorm => (bc, float, linear, (4, 4), 8, basic, 1), - Self::Bc5RgUnorm => (bc, float, linear, (4, 4), 16, basic, 2), - Self::Bc5RgSnorm => (bc, float, linear, (4, 4), 16, basic, 2), - Self::Bc6hRgbUfloat => (bc, float, linear, (4, 4), 16, basic, 3), - Self::Bc6hRgbSfloat => (bc, float, linear, (4, 4), 16, basic, 3), - Self::Bc7RgbaUnorm => (bc, float, linear, (4, 4), 16, basic, 4), - Self::Bc7RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic, 4), + Self::Bc1RgbaUnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 4), + Self::Bc1RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 8, basic, 4), + Self::Bc2RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc2RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Bc3RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc3RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Bc4RUnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 1), + Self::Bc4RSnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 1), + Self::Bc5RgUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 2), + Self::Bc5RgSnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 2), + Self::Bc6hRgbUfloat => (bc, float, linear, noaa, (4, 4), 16, basic, 3), + Self::Bc6hRgbSfloat => (bc, float, linear, noaa, (4, 4), 16, basic, 3), + Self::Bc7RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc7RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), // ETC compressed textures - Self::Etc2Rgb8Unorm => (etc2, float, linear, (4, 4), 8, basic, 3), - Self::Etc2Rgb8UnormSrgb => (etc2, float, srgb, (4, 4), 8, basic, 3), - Self::Etc2Rgb8A1Unorm => (etc2, float, linear, (4, 4), 8, basic, 4), - Self::Etc2Rgb8A1UnormSrgb => (etc2, float, srgb, (4, 4), 8, basic, 4), - Self::Etc2Rgba8Unorm => (etc2, float, linear, (4, 4), 16, basic, 4), - Self::Etc2Rgba8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic, 4), - Self::EacR11Unorm => (etc2, float, linear, (4, 4), 8, basic, 1), - Self::EacR11Snorm => (etc2, float, linear, (4, 4), 8, basic, 1), - Self::EacRg11Unorm => (etc2, float, linear, (4, 4), 16, basic, 2), - Self::EacRg11Snorm => (etc2, float, linear, (4, 4), 16, basic, 2), + Self::Etc2Rgb8Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 3), + Self::Etc2Rgb8UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 8, basic, 3), + Self::Etc2Rgb8A1Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 4), + Self::Etc2Rgb8A1UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 8, basic, 4), + Self::Etc2Rgba8Unorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Etc2Rgba8UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::EacR11Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 1), + Self::EacR11Snorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 1), + Self::EacRg11Unorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 2), + Self::EacRg11Snorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 2), // ASTC compressed textures - Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic, 4), - Self::Astc4x4RgbaUnormSrgb => (astc_ldr, float, srgb, (4, 4), 16, basic, 4), - Self::Astc5x4RgbaUnorm => (astc_ldr, float, linear, (5, 4), 16, basic, 4), - Self::Astc5x4RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 4), 16, basic, 4), - Self::Astc5x5RgbaUnorm => (astc_ldr, float, linear, (5, 5), 16, basic, 4), - Self::Astc5x5RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 5), 16, basic, 4), - Self::Astc6x5RgbaUnorm => (astc_ldr, float, linear, (6, 5), 16, basic, 4), - Self::Astc6x5RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 5), 16, basic, 4), - Self::Astc6x6RgbaUnorm => (astc_ldr, float, linear, (6, 6), 16, basic, 4), - Self::Astc6x6RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 6), 16, basic, 4), - Self::Astc8x5RgbaUnorm => (astc_ldr, float, linear, (8, 5), 16, basic, 4), - Self::Astc8x5RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 5), 16, basic, 4), - Self::Astc8x6RgbaUnorm => (astc_ldr, float, linear, (8, 6), 16, basic, 4), - Self::Astc8x6RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 6), 16, basic, 4), - Self::Astc10x5RgbaUnorm => (astc_ldr, float, linear, (10, 5), 16, basic, 4), - Self::Astc10x5RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 5), 16, basic, 4), - Self::Astc10x6RgbaUnorm => (astc_ldr, float, linear, (10, 6), 16, basic, 4), - Self::Astc10x6RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 6), 16, basic, 4), - Self::Astc8x8RgbaUnorm => (astc_ldr, float, linear, (8, 8), 16, basic, 4), - Self::Astc8x8RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 8), 16, basic, 4), - Self::Astc10x8RgbaUnorm => (astc_ldr, float, linear, (10, 8), 16, basic, 4), - Self::Astc10x8RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 8), 16, basic, 4), - Self::Astc10x10RgbaUnorm => (astc_ldr, float, linear, (10, 10), 16, basic, 4), - Self::Astc10x10RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 10), 16, basic, 4), - Self::Astc12x10RgbaUnorm => (astc_ldr, float, linear, (12, 10), 16, basic, 4), - Self::Astc12x10RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 10), 16, basic, 4), - Self::Astc12x12RgbaUnorm => (astc_ldr, float, linear, (12, 12), 16, basic, 4), - Self::Astc12x12RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 12), 16, basic, 4), + Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Astc4x4RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Astc5x4RgbaUnorm => (astc_ldr, float, linear, noaa, (5, 4), 16, basic, 4), + Self::Astc5x4RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (5, 4), 16, basic, 4), + Self::Astc5x5RgbaUnorm => (astc_ldr, float, linear, noaa, (5, 5), 16, basic, 4), + Self::Astc5x5RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (5, 5), 16, basic, 4), + Self::Astc6x5RgbaUnorm => (astc_ldr, float, linear, noaa, (6, 5), 16, basic, 4), + Self::Astc6x5RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (6, 5), 16, basic, 4), + Self::Astc6x6RgbaUnorm => (astc_ldr, float, linear, noaa, (6, 6), 16, basic, 4), + Self::Astc6x6RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (6, 6), 16, basic, 4), + Self::Astc8x5RgbaUnorm => (astc_ldr, float, linear, noaa, (8, 5), 16, basic, 4), + Self::Astc8x5RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (8, 5), 16, basic, 4), + Self::Astc8x6RgbaUnorm => (astc_ldr, float, linear, noaa, (8, 6), 16, basic, 4), + Self::Astc8x6RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (8, 6), 16, basic, 4), + Self::Astc10x5RgbaUnorm => (astc_ldr, float, linear, noaa, (10, 5), 16, basic, 4), + Self::Astc10x5RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (10, 5), 16, basic, 4) + } + Self::Astc10x6RgbaUnorm => (astc_ldr, float, linear, noaa, (10, 6), 16, basic, 4), + Self::Astc10x6RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (10, 6), 16, basic, 4) + } + Self::Astc8x8RgbaUnorm => (astc_ldr, float, linear, noaa, (8, 8), 16, basic, 4), + Self::Astc8x8RgbaUnormSrgb => (astc_ldr, float, corrected, noaa, (8, 8), 16, basic, 4), + Self::Astc10x8RgbaUnorm => (astc_ldr, float, linear, noaa, (10, 8), 16, basic, 4), + Self::Astc10x8RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (10, 8), 16, basic, 4) + } + Self::Astc10x10RgbaUnorm => (astc_ldr, float, linear, noaa, (10, 10), 16, basic, 4), + Self::Astc10x10RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (10, 10), 16, basic, 4) + } + Self::Astc12x10RgbaUnorm => (astc_ldr, float, linear, noaa, (12, 10), 16, basic, 4), + Self::Astc12x10RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (12, 10), 16, basic, 4) + } + Self::Astc12x12RgbaUnorm => (astc_ldr, float, linear, noaa, (12, 12), 16, basic, 4), + Self::Astc12x12RgbaUnormSrgb => { + (astc_ldr, float, corrected, noaa, (12, 12), 16, basic, 4) + } // Optional normalized 16-bit-per-channel formats - Self::R16Unorm => (norm16bit, float, linear, (1, 1), 2, storage, 1), - Self::R16Snorm => (norm16bit, float, linear, (1, 1), 2, storage, 1), - Self::Rg16Unorm => (norm16bit, float, linear, (1, 1), 4, storage, 2), - Self::Rg16Snorm => (norm16bit, float, linear, (1, 1), 4, storage, 2), - Self::Rgba16Unorm => (norm16bit, float, linear, (1, 1), 8, storage, 4), - Self::Rgba16Snorm => (norm16bit, float, linear, (1, 1), 8, storage, 4), + Self::R16Unorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), + Self::R16Snorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), + Self::Rg16Unorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), + Self::Rg16Snorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), + Self::Rgba16Unorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), + Self::Rgba16Snorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), }; + let mut flags = msaa_flags; + flags.set( + TextureFormatFeatureFlags::FILTERABLE, + sample_type == TextureSampleType::Float { filterable: true }, + ); + TextureFormatInfo { required_features, sample_type, block_dimensions, block_size, components, - srgb, + srgb: match color_space { + ColorSpace::Linear => false, + ColorSpace::Corrected => true, + }, guaranteed_format_features: TextureFormatFeatures { allowed_usages, - flags: TextureFormatFeatureFlags::empty(), - filterable: sample_type == TextureSampleType::Float { filterable: true }, + flags, }, } }