mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
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:
parent
04d12baa81
commit
3c82a4cd5c
10
CHANGELOG.md
10
CHANGELOG.md
@ -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)
|
||||
|
||||
|
@ -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(())
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user