Added support for MSAA(x2,x8) beyond WEBGPU restrictions for native a… (#3140)

Closes https://github.com/gfx-rs/wgpu/issues/2910
This commit is contained in:
Ali 2022-11-09 22:19:05 +02:00 committed by GitHub
parent 04d12baa81
commit 3c82a4cd5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 214 additions and 73 deletions

View File

@ -50,6 +50,7 @@ Bottom level categories:
- New downlevel feature `UNRESTRICTED_INDEX_BUFFER` to indicate support for using `INDEX` together with other non-copy/map usages (unsupported on WebGL). By @Wumpf in [#3157](https://github.com/gfx-rs/wgpu/pull/3157)
#### WebGPU
- Implement `queue_validate_write_buffer` by @jinleili in [#3098](https://github.com/gfx-rs/wgpu/pull/3098)
#### GLES
@ -64,12 +65,17 @@ Bottom level categories:
- Add the `"wgsl"` feature, to enable WGSL shaders in `wgpu-core` and `wgpu`. Enabled by default in `wgpu`. By @daxpedda in [#2890](https://github.com/gfx-rs/wgpu/pull/2890).
- Implement `Clone` for `ShaderSource` and `ShaderModuleDescriptor` in `wgpu`. By @daxpedda in [#3086](https://github.com/gfx-rs/wgpu/pull/3086).
- Add `get_default_config` for `Surface` to simplify user creation of `SurfaceConfiguration`. By @jinleili in [#3034](https://github.com/gfx-rs/wgpu/pull/3034)
- Native adapters can now use MSAA x2 and x8 if it's supported , previously only x1 and x4 were supported . By @39ali in [3140](https://github.com/gfx-rs/wgpu/pull/3140)
#### GLES
- Surfaces support now `TextureFormat::Rgba8Unorm` and (non-web only) `TextureFormat::Bgra8Unorm`. By @Wumpf in [#3070](https://github.com/gfx-rs/wgpu/pull/3070)
- Support alpha to coverage. By @Wumpf in [#3156](https://github.com/gfx-rs/wgpu/pull/3156)
#### WebGPU
- Add `MULTISAMPLE_X2`, `MULTISAMPLE_X4` and `MULTISAMPLE_X8` to `TextureFormatFeatureFlags`. By @39ali in [3140](https://github.com/gfx-rs/wgpu/pull/3140)
### Bug Fixes
#### General
@ -81,6 +87,7 @@ Bottom level categories:
- Fix an integer overflow in `queue_write_texture` by @nical in (#3146)[https://github.com/gfx-rs/wgpu/pull/3146]
#### WebGPU
- Use `log` instead of `println` in hello example by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858)
#### GLES
@ -95,6 +102,7 @@ Bottom level categories:
By @jimblandy in [#3171](https://github.com/gfx-rs/wgpu/pull/3171)
### Examples
- Log adapter info in hello example on wasm target by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858)
### Testing/Internal
@ -204,6 +212,7 @@ both `raw_window_handle::HasRawWindowHandle` and `raw_window_handle::HasRawDispl
- Report Apple M2 gpu as integrated. By @i509VCB [#3036](https://github.com/gfx-rs/wgpu/pull/3036)
#### WebGPU
- When called in a web worker, `Context::init()` now uses `web_sys::WorkerGlobalContext` to create a `wgpu::Instance` instead of trying to access the unavailable `web_sys::Window` by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858)
### Changes
@ -359,6 +368,7 @@ Added items to the public API
- Update present_mode docs as most of them don't automatically fall back to Fifo anymore. by @Elabajaba in [#2855](https://github.com/gfx-rs/wgpu/pull/2855)
#### Hal
- Document safety requirements for `Adapter::from_external` in gles hal by @i509VCB in [#2863](https://github.com/gfx-rs/wgpu/pull/2863)
- Make `AdapterContext` a publicly accessible type in the gles hal by @i509VCB in [#2870](https://github.com/gfx-rs/wgpu/pull/2870)

View File

@ -732,9 +732,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
expected: sample_count,
});
}
if sample_count != 1 && sample_count != 4 {
return Err(RenderPassErrorInner::InvalidSampleCount(sample_count));
}
attachment_type_name = type_name;
Ok(())
};

View File

@ -811,12 +811,23 @@ impl<A: HalApi> Device<A> {
return Err(CreateTextureError::MultisampledNotRenderAttachment);
}
if !format_features
.flags
.contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE)
{
if !format_features.flags.intersects(
wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4
| wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2
| wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
) {
return Err(CreateTextureError::InvalidMultisampledFormat(desc.format));
}
if !format_features
.flags
.sample_count_supported(desc.sample_count)
{
return Err(CreateTextureError::InvalidSampleCount(
desc.sample_count,
desc.format,
));
};
}
let mips = desc.mip_level_count;
@ -2665,7 +2676,9 @@ impl<A: HalApi> Device<A> {
break Some(pipeline::ColorStateError::FormatNotColor(cs.format));
}
if desc.multisample.count > 1
&& !format_features.flags.contains(Tfff::MULTISAMPLE)
&& !format_features
.flags
.sample_count_supported(desc.multisample.count)
{
break Some(pipeline::ColorStateError::FormatNotMultisampled(cs.format));
}
@ -2699,7 +2712,10 @@ impl<A: HalApi> Device<A> {
ds.format,
));
}
if desc.multisample.count > 1 && !format_features.flags.contains(Tfff::MULTISAMPLE)
if desc.multisample.count > 1
&& !format_features
.flags
.sample_count_supported(desc.multisample.count)
{
break Some(pipeline::DepthStencilStateError::FormatNotMultisampled(
ds.format,

View File

@ -268,9 +268,18 @@ impl<A: HalApi> Adapter<A> {
);
flags.set(
wgt::TextureFormatFeatureFlags::MULTISAMPLE,
caps.contains(Tfc::MULTISAMPLE),
wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
caps.contains(Tfc::MULTISAMPLE_X2),
);
flags.set(
wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
caps.contains(Tfc::MULTISAMPLE_X4),
);
flags.set(
wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
caps.contains(Tfc::MULTISAMPLE_X8),
);
flags.set(
wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
caps.contains(Tfc::MULTISAMPLE_RESOLVE),

View File

@ -184,7 +184,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal_usage: conv::map_texture_usage(config.usage, config.format.into()),
format_features: wgt::TextureFormatFeatures {
allowed_usages: wgt::TextureUsages::RENDER_ATTACHMENT,
flags: wgt::TextureFormatFeatureFlags::MULTISAMPLE
flags: wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4
| wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
},
initialization_status: TextureInitTracker::new(1, 1),

View File

@ -517,6 +517,8 @@ pub enum CreateTextureError {
MultisampledNotRenderAttachment,
#[error("Texture format {0:?} can't be used due to missing features.")]
MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
#[error("Sample count {0} is not supported by format {1:?} on this device. It may be supported by your adapter through the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature.")]
InvalidSampleCount(u32, wgt::TextureFormat),
}
impl<A: hal::Api> Resource for Texture<A> {

View File

@ -446,12 +446,37 @@ impl crate::Adapter<super::Api> for super::Adapter {
| 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,
);
let mut ms_levels = d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
Format: raw_format,
SampleCount: 0,
Flags: d3d12::D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE,
NumQualityLevels: 0,
};
let mut set_sample_count = |sc: u32, tfc: Tfc| {
ms_levels.SampleCount = sc;
if self.device.CheckFeatureSupport(
d3d12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
<*mut _>::cast(&mut ms_levels),
mem::size_of::<d3d12::D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS>() as _,
) == winerror::S_OK
&& ms_levels.NumQualityLevels != 0
{
caps.set(tfc, !no_msaa_load && !no_msaa_target);
}
};
set_sample_count(2, Tfc::MULTISAMPLE_X2);
set_sample_count(4, Tfc::MULTISAMPLE_X4);
set_sample_count(8, Tfc::MULTISAMPLE_X8);
caps
}

View File

@ -89,6 +89,7 @@ impl crate::Adapter<Api> for Context {
) -> crate::TextureFormatCapabilities {
crate::TextureFormatCapabilities::empty()
}
unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
None
}

View File

@ -197,7 +197,6 @@ impl super::Adapter {
(vendor, renderer)
};
let version = gl.get_parameter_string(glow::VERSION);
log::info!("Vendor: {}", vendor);
log::info!("Renderer: {}", renderer);
log::info!("Version: {}", version);
@ -664,6 +663,21 @@ impl crate::Adapter<super::Api> for super::Adapter {
use crate::TextureFormatCapabilities as Tfc;
use wgt::TextureFormat as Tf;
let sample_count = {
let max_samples = self
.shared
.context
.lock()
.get_parameter_i32(glow::MAX_SAMPLES);
if max_samples >= 8 {
Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4 | Tfc::MULTISAMPLE_X8
} else if max_samples >= 4 {
Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4
} else {
Tfc::MULTISAMPLE_X2
}
};
// Base types are pulled from the table in the OpenGLES 3.0 spec in section 3.8.
//
// The storage types are based on table 8.26, in section
@ -671,10 +685,10 @@ impl crate::Adapter<super::Api> for super::Adapter {
let empty = Tfc::empty();
let base = Tfc::COPY_SRC | Tfc::COPY_DST;
let unfilterable = base | Tfc::SAMPLED;
let depth = base | Tfc::SAMPLED | Tfc::MULTISAMPLE | Tfc::DEPTH_STENCIL_ATTACHMENT;
let depth = base | Tfc::SAMPLED | sample_count | Tfc::DEPTH_STENCIL_ATTACHMENT;
let filterable = unfilterable | Tfc::SAMPLED_LINEAR;
let renderable =
unfilterable | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE;
unfilterable | Tfc::COLOR_ATTACHMENT | sample_count | Tfc::MULTISAMPLE_RESOLVE;
let filterable_renderable = filterable | renderable | Tfc::COLOR_ATTACHMENT_BLEND;
let storage = base | Tfc::STORAGE | Tfc::STORAGE_READ_WRITE;

View File

@ -582,15 +582,20 @@ 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 multisampled by x2.
const MULTISAMPLE_X2 = 1 << 9;
/// Format can be multisampled by x4.
const MULTISAMPLE_X4 = 1 << 10;
/// Format can be multisampled by x8.
const MULTISAMPLE_X8 = 1 << 11;
/// Format can be used for render pass resolve targets.
const MULTISAMPLE_RESOLVE = 1 << 10;
const MULTISAMPLE_RESOLVE = 1 << 12;
/// Format can be copied from.
const COPY_SRC = 1 << 11;
const COPY_SRC = 1 << 13;
/// Format can be copied to.
const COPY_DST = 1 << 12;
const COPY_DST = 1 << 14;
}
);

View File

@ -56,16 +56,8 @@ impl crate::Adapter<super::Api> 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_count = pc.sample_count_mask;
let msaa_resolve_desktop_if = if pc.msaa_desktop {
Tfc::MULTISAMPLE_RESOLVE
} else {
@ -90,7 +82,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tfc::STORAGE
| Tfc::COLOR_ATTACHMENT
| Tfc::COLOR_ATTACHMENT_BLEND
| Tfc::MULTISAMPLE
| msaa_count
| Tfc::MULTISAMPLE_RESOLVE;
let extra = match format {
@ -110,7 +102,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tf::Rgba8Sint
| Tf::Rgba16Uint
| Tf::Rgba16Sint => {
read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE
read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_count
}
Tf::R16Unorm
| Tf::R16Snorm
@ -122,26 +114,23 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tfc::STORAGE
| Tfc::COLOR_ATTACHMENT
| Tfc::COLOR_ATTACHMENT_BLEND
| Tfc::MULTISAMPLE
| msaa_count
| msaa_resolve_desktop_if
}
Tf::Rg8Unorm | Tf::Rg16Float | Tf::Bgra8Unorm => all_caps,
Tf::Rg8Uint | Tf::Rg8Sint => Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE,
Tf::Rg8Uint | Tf::Rg8Sint => Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_count,
Tf::R32Uint | Tf::R32Sint => {
read_write_tier1_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_desktop_if
read_write_tier1_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_count
}
Tf::R32Float => {
let flags = if pc.format_r32float_all {
all_caps
} else {
Tfc::STORAGE
| Tfc::COLOR_ATTACHMENT
| Tfc::COLOR_ATTACHMENT_BLEND
| Tfc::MULTISAMPLE
Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND | msaa_count
};
read_write_tier1_if | flags
}
Tf::Rg16Uint | Tf::Rg16Sint => Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE,
Tf::Rg16Uint | Tf::Rg16Sint => Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_count,
Tf::Rgba8UnormSrgb | Tf::Bgra8UnormSrgb => {
let mut flags = all_caps;
flags.set(Tfc::STORAGE, pc.format_rgba8_srgb_all);
@ -157,26 +146,23 @@ impl crate::Adapter<super::Api> for super::Adapter {
flags.set(Tfc::STORAGE, pc.format_rg11b10_all);
flags
}
Tf::Rg32Uint | Tf::Rg32Sint => Tfc::COLOR_ATTACHMENT | Tfc::STORAGE | msaa_apple7x_if,
Tf::Rg32Uint | Tf::Rg32Sint => Tfc::COLOR_ATTACHMENT | Tfc::STORAGE | msaa_count,
Tf::Rg32Float => {
if pc.format_rg32float_all {
all_caps
} else {
Tfc::STORAGE
| Tfc::COLOR_ATTACHMENT
| Tfc::COLOR_ATTACHMENT_BLEND
| msaa_apple7x_if
Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | Tfc::COLOR_ATTACHMENT_BLEND | msaa_count
}
}
Tf::Rgba32Uint | Tf::Rgba32Sint => {
read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_desktop_if
read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT | msaa_count
}
Tf::Rgba32Float => {
let mut flags = read_write_tier2_if | Tfc::STORAGE | Tfc::COLOR_ATTACHMENT;
if pc.format_rgba32float_all {
flags |= all_caps
} else if pc.msaa_apple7 {
flags |= Tfc::MULTISAMPLE
flags |= msaa_count
};
flags
}
@ -189,7 +175,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
}*/
Tf::Depth16Unorm => {
let mut flags =
Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::MULTISAMPLE | msaa_resolve_apple3x_if;
Tfc::DEPTH_STENCIL_ATTACHMENT | msaa_count | msaa_resolve_apple3x_if;
if pc.format_depth16unorm {
flags |= Tfc::SAMPLED_LINEAR
}
@ -197,14 +183,14 @@ impl crate::Adapter<super::Api> for super::Adapter {
}
Tf::Depth32Float | Tf::Depth32FloatStencil8 => {
let mut flags =
Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::MULTISAMPLE | msaa_resolve_apple3x_if;
Tfc::DEPTH_STENCIL_ATTACHMENT | msaa_count | msaa_resolve_apple3x_if;
if pc.format_depth32float_filter {
flags |= Tfc::SAMPLED_LINEAR
}
flags
}
Tf::Depth24Plus | Tf::Depth24PlusStencil8 => {
let mut flags = Tfc::DEPTH_STENCIL_ATTACHMENT | Tfc::MULTISAMPLE;
let mut flags = Tfc::DEPTH_STENCIL_ATTACHMENT | msaa_count;
if pc.format_depth24_stencil8 {
flags |= Tfc::SAMPLED_LINEAR | Tfc::MULTISAMPLE_RESOLVE
} else {
@ -224,7 +210,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
Tfc::SAMPLED_LINEAR
| Tfc::COLOR_ATTACHMENT
| Tfc::COLOR_ATTACHMENT_BLEND
| Tfc::MULTISAMPLE
| msaa_count
| Tfc::MULTISAMPLE_RESOLVE
}
}
@ -489,12 +475,12 @@ impl super::PrivateCapabilities {
version.is_mac = os_is_mac;
let family_check = version.at_least((10, 15), (13, 0));
let mut sample_count_mask: u8 = 1 | 4; // 1 and 4 samples are supported on all devices
let mut sample_count_mask = crate::TextureFormatCapabilities::MULTISAMPLE_X4; // 1 and 4 samples are supported on all devices
if device.supports_texture_sample_count(2) {
sample_count_mask |= 2;
sample_count_mask |= crate::TextureFormatCapabilities::MULTISAMPLE_X2;
}
if device.supports_texture_sample_count(8) {
sample_count_mask |= 8;
sample_count_mask |= crate::TextureFormatCapabilities::MULTISAMPLE_X8;
}
let rw_texture_tier = if version.at_least((10, 13), (11, 0)) {

View File

@ -219,7 +219,7 @@ struct PrivateCapabilities {
max_varying_components: u32,
max_threads_per_group: u32,
max_total_threadgroup_memory: u32,
sample_count_mask: u8,
sample_count_mask: crate::TextureFormatCapabilities,
supports_debug_markers: bool,
supports_binary_archives: bool,
supports_capture_manager: bool,

View File

@ -1417,10 +1417,42 @@ impl crate::Adapter<super::Api> for super::Adapter {
),
);
// Vulkan is very permissive about MSAA
flags.set(Tfc::MULTISAMPLE_RESOLVE, !format.describe().is_compressed());
// get the supported sample counts
let format_aspect = crate::FormatAspects::from(format);
let limits = self.phd_capabilities.properties.limits;
let sample_flags = if format_aspect.contains(crate::FormatAspects::DEPTH) {
limits
.framebuffer_depth_sample_counts
.min(limits.sampled_image_depth_sample_counts)
} else if format_aspect.contains(crate::FormatAspects::STENCIL) {
limits
.framebuffer_stencil_sample_counts
.min(limits.sampled_image_stencil_sample_counts)
} else {
limits
.framebuffer_color_sample_counts
.min(limits.sampled_image_color_sample_counts)
.min(limits.sampled_image_integer_sample_counts)
.min(limits.storage_image_sample_counts)
};
flags.set(
Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE,
!format.describe().is_compressed(),
Tfc::MULTISAMPLE_X2,
sample_flags.contains(vk::SampleCountFlags::TYPE_2),
);
flags.set(
Tfc::MULTISAMPLE_X4,
sample_flags.contains(vk::SampleCountFlags::TYPE_4),
);
flags.set(
Tfc::MULTISAMPLE_X8,
sample_flags.contains(vk::SampleCountFlags::TYPE_8),
);
flags
}

View File

@ -230,7 +230,7 @@ mod inner {
}
}
println!("\tTexture Format Features: ┌──────────┬──────────┬──────────Allowed┬Usages───────────┬───────────────────┐ ┌────────────┬─────────────┬──────────────Feature┬Flags───────────────┬─────────────────");
println!("\tTexture Format Features: ┌──────────┬──────────┬──────────Allowed┬Usages───────────┬───────────────────┐ ┌────────────┬────────────────┬──────────────Feature┬Flags──────┬─────────────────────┬────────────────────┬─");
for format in TEXTURE_FORMAT_LIST {
let features = adapter.get_texture_format_features(format);
let format_name = match format {
@ -271,9 +271,10 @@ mod inner {
}
}
}
println!("");
}
println!("\t └──────────┴──────────┴─────────────────┴─────────────────┴───────────────────┘ └────────────┴─────────────┴─────────────────────┴─────────────────────────────────────┘");
println!("\t └──────────┴──────────┴─────────────────┴─────────────────┴───────────────────┘ └────────────┴────────────────────────────────┴─────────────────────────────────────┘");
}
pub fn main() {

View File

@ -1629,19 +1629,40 @@ bitflags::bitflags! {
/// 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 [`TextureDescriptor::sample_count`] to be `2`.
const MULTISAMPLE_X2 = 1 << 1;
/// Allows [`TextureDescriptor::sample_count`] to be `4`.
const MULTISAMPLE_X4 = 1 << 2 ;
/// Allows [`TextureDescriptor::sample_count`] to be `8`.
const MULTISAMPLE_X8 = 1 << 3 ;
/// 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;
const MULTISAMPLE_RESOLVE = 1 << 4;
/// 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 << 3;
const STORAGE_READ_WRITE = 1 << 5;
/// 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 << 4;
const STORAGE_ATOMICS = 1 << 6;
/// If not present, the texture can't be blended into the render target.
const BLENDABLE = 1 << 5;
const BLENDABLE = 1 << 7;
}
}
impl TextureFormatFeatureFlags {
/// Sample count supported by a given texture format.
///
/// returns `true` if `count` is a supported sample count.
pub fn sample_count_supported(&self, count: u32) -> bool {
use TextureFormatFeatureFlags as tfsc;
match count {
1 => true,
2 => self.contains(tfsc::MULTISAMPLE_X2),
4 => self.contains(tfsc::MULTISAMPLE_X4),
8 => self.contains(tfsc::MULTISAMPLE_X8),
_ => false,
}
}
}
@ -2308,9 +2329,9 @@ impl TextureFormat {
// Multisampling
let noaa = TextureFormatFeatureFlags::empty();
let msaa = TextureFormatFeatureFlags::MULTISAMPLE;
let msaa_resolve =
TextureFormatFeatureFlags::MULTISAMPLE | TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE;
let msaa = TextureFormatFeatureFlags::MULTISAMPLE_X4;
let msaa_resolve = TextureFormatFeatureFlags::MULTISAMPLE_X4
| TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE;
// Flags
let basic =

View File

@ -32,6 +32,7 @@ struct Example {
sample_count: u32,
rebuild_bundle: bool,
config: wgpu::SurfaceConfiguration,
max_sample_count: u32,
}
impl Example {
@ -117,6 +118,10 @@ impl Example {
}
impl framework::Example for Example {
fn optional_features() -> wgt::Features {
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
}
fn init(
config: &wgpu::SurfaceConfiguration,
_adapter: &wgpu::Adapter,
@ -124,7 +129,22 @@ impl framework::Example for Example {
_queue: &wgpu::Queue,
) -> Self {
log::info!("Press left/right arrow keys to change sample_count.");
let sample_count = 4;
let sample_flags = _adapter.get_texture_format_features(config.format).flags;
let max_sample_count = {
if sample_flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X8) {
8
} else if sample_flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X4) {
4
} else if sample_flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X2) {
2
} else {
1
}
};
let sample_count = max_sample_count;
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
@ -181,6 +201,7 @@ impl framework::Example for Example {
vertex_buffer,
vertex_count,
sample_count,
max_sample_count,
rebuild_bundle: false,
config: config.clone(),
}
@ -195,14 +216,14 @@ impl framework::Example for Example {
// TODO: Switch back to full scans of possible options when we expose
// supported sample counts to the user.
Some(winit::event::VirtualKeyCode::Left) => {
if self.sample_count == 4 {
if self.sample_count == self.max_sample_count {
self.sample_count = 1;
self.rebuild_bundle = true;
}
}
Some(winit::event::VirtualKeyCode::Right) => {
if self.sample_count == 1 {
self.sample_count = 4;
self.sample_count = self.max_sample_count;
self.rebuild_bundle = true;
}
}
@ -295,7 +316,8 @@ fn msaa_line() {
image_path: "/examples/msaa-line/screenshot.png",
width: 1024,
height: 768,
optional_features: wgpu::Features::default(),
optional_features: wgpu::Features::default()
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
base_test_parameters: framework::test_common::TestParameters::default(),
tolerance: 64,
max_outliers: 1 << 16, // MSAA is comically different between vendors, 32k is a decent limit