Skip to content

Commit 21e6143

Browse files
authored
Add MULTISAMPLE_ARRAY feature flag. (#8571)
1 parent d85408a commit 21e6143

File tree

5 files changed

+103
-18
lines changed

5 files changed

+103
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ By @cwfitzgerald in [#8609](https://github.com/gfx-rs/wgpu/pull/8609).
162162
- Added support for transient textures on Vulkan and Metal. By @opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247)
163163
- Implement shader triangle barycentric coordinate builtins. By @atlv24 in [#8320](https://github.com/gfx-rs/wgpu/pull/8320).
164164
- Added support for binding arrays of storage textures on Metal. By @msvbg in [#8464](https://github.com/gfx-rs/wgpu/pull/8464)
165+
- Added support for multisampled texture arrays on Vulkan through adapter feature `MULTISAMPLE_ARRAY`. By @LaylBongers in [#8571](https://github.com/gfx-rs/wgpu/pull/8571).
165166

166167
### Changes
167168

tests/tests/wgpu-gpu/multiview/mod.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
99
vec.push(DRAW_MULTIVIEW_SINGLE);
1010
vec.push(DRAW_MULTIVIEW);
1111
vec.push(DRAW_MULTIVIEW_NONCONTIGUOUS);
12+
vec.push(DRAW_MULTIVIEW_MULTISAMPLE);
1213
}
1314

1415
#[gpu_test]
@@ -21,7 +22,7 @@ static DRAW_MULTIVIEW_SINGLE: GpuTestConfiguration = GpuTestConfiguration::new()
2122
..Limits::defaults()
2223
}),
2324
)
24-
.run_async(|ctx| run_test(ctx, 0b1));
25+
.run_async(|ctx| run_test(ctx, 0b1, 1));
2526

2627
#[gpu_test]
2728
static DRAW_MULTIVIEW: GpuTestConfiguration = GpuTestConfiguration::new()
@@ -33,7 +34,7 @@ static DRAW_MULTIVIEW: GpuTestConfiguration = GpuTestConfiguration::new()
3334
..Limits::defaults()
3435
}),
3536
)
36-
.run_async(|ctx| run_test(ctx, 0b11));
37+
.run_async(|ctx| run_test(ctx, 0b11, 1));
3738

3839
#[gpu_test]
3940
static DRAW_MULTIVIEW_NONCONTIGUOUS: GpuTestConfiguration = GpuTestConfiguration::new()
@@ -45,9 +46,21 @@ static DRAW_MULTIVIEW_NONCONTIGUOUS: GpuTestConfiguration = GpuTestConfiguration
4546
..Limits::defaults()
4647
}),
4748
)
48-
.run_async(|ctx| run_test(ctx, 0b1001));
49+
.run_async(|ctx| run_test(ctx, 0b1001, 1));
4950

50-
async fn run_test(ctx: TestingContext, layer_mask: u32) {
51+
#[gpu_test]
52+
static DRAW_MULTIVIEW_MULTISAMPLE: GpuTestConfiguration = GpuTestConfiguration::new()
53+
.parameters(
54+
TestParameters::default()
55+
.features(Features::MULTIVIEW | Features::MULTISAMPLE_ARRAY)
56+
.limits(Limits {
57+
max_multiview_view_count: 2,
58+
..Limits::defaults()
59+
}),
60+
)
61+
.run_async(|ctx| run_test(ctx, 0b11, 4));
62+
63+
async fn run_test(ctx: TestingContext, layer_mask: u32, sample_count: u32) {
5164
let num_layers = 32 - layer_mask.leading_zeros();
5265

5366
let shader_src = include_str!("shader.wgsl");
@@ -79,29 +92,34 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
7992
})],
8093
}),
8194
multiview_mask: NonZero::new(layer_mask),
82-
multisample: Default::default(),
95+
multisample: wgpu::MultisampleState {
96+
count: sample_count,
97+
..Default::default()
98+
},
8399
layout: None,
84100
depth_stencil: None,
85101
cache: None,
86102
};
87103

88104
const TEXTURE_SIZE: u32 = 256;
89105
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
90-
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
106+
107+
let texture_desc = wgpu::TextureDescriptor {
91108
label: None,
92109
size: wgpu::Extent3d {
93110
width: TEXTURE_SIZE,
94111
height: TEXTURE_SIZE,
95112
depth_or_array_layers: 32 - layer_mask.leading_zeros(),
96113
},
97114
mip_level_count: 1,
98-
sample_count: 1,
115+
sample_count,
99116
dimension: wgpu::TextureDimension::D2,
100117
format: wgpu::TextureFormat::R8Unorm,
101118
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
102119
view_formats: &[],
103-
});
104-
let entire_texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
120+
};
121+
let texture = ctx.device.create_texture(&texture_desc);
122+
let texture_view_desc = wgpu::TextureViewDescriptor {
105123
label: None,
106124
format: Some(wgpu::TextureFormat::R8Unorm),
107125
dimension: Some(wgpu::TextureViewDimension::D2Array),
@@ -111,7 +129,21 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
111129
mip_level_count: None,
112130
base_array_layer: 0,
113131
array_layer_count: Some(num_layers),
114-
});
132+
};
133+
let entire_texture_view = texture.create_view(&texture_view_desc);
134+
135+
let (resolve_texture, resolve_texture_view) = if sample_count != 1 {
136+
let mut texture_desc = texture_desc.clone();
137+
texture_desc.sample_count = 1;
138+
139+
let resolve_texture = ctx.device.create_texture(&texture_desc);
140+
let resolve_texture_view = resolve_texture.create_view(&texture_view_desc);
141+
142+
(Some(resolve_texture), Some(resolve_texture_view))
143+
} else {
144+
(None, None)
145+
};
146+
115147
let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
116148
label: None,
117149
size: TEXTURE_SIZE as u64 * TEXTURE_SIZE as u64 * num_layers as u64,
@@ -130,7 +162,7 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
130162
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
131163
view: &entire_texture_view,
132164
depth_slice: None,
133-
resolve_target: None,
165+
resolve_target: resolve_texture_view.as_ref(),
134166
ops: wgpu::Operations {
135167
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
136168
store: wgpu::StoreOp::Store,
@@ -146,7 +178,7 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
146178
}
147179
encoder.copy_texture_to_buffer(
148180
wgpu::TexelCopyTextureInfo {
149-
texture: &texture,
181+
texture: resolve_texture.as_ref().unwrap_or(&texture),
150182
mip_level: 0,
151183
origin: wgpu::Origin3d { x: 0, y: 0, z: 0 },
152184
aspect: wgpu::TextureAspect::All,

wgpu-core/src/device/resource.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,7 +1436,9 @@ impl Device {
14361436
});
14371437
}
14381438

1439-
if desc.size.depth_or_array_layers != 1 {
1439+
if desc.size.depth_or_array_layers != 1
1440+
&& !self.features.contains(wgt::Features::MULTISAMPLE_ARRAY)
1441+
{
14401442
return Err(CreateTextureError::InvalidDimension(
14411443
TextureDimensionError::MultisampledDepthOrArrayLayer(
14421444
desc.size.depth_or_array_layers,
@@ -1741,11 +1743,17 @@ impl Device {
17411743

17421744
// check if multisampled texture is seen as anything but 2D
17431745
if texture.desc.sample_count > 1 && resolved_dimension != TextureViewDimension::D2 {
1744-
return Err(
1745-
resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
1746-
resolved_dimension,
1747-
),
1748-
);
1746+
// Multisample is allowed on 2D arrays, only if explicitly supported
1747+
let multisample_array_exception = resolved_dimension == TextureViewDimension::D2Array
1748+
&& self.features.contains(wgt::Features::MULTISAMPLE_ARRAY);
1749+
1750+
if !multisample_array_exception {
1751+
return Err(
1752+
resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
1753+
resolved_dimension,
1754+
),
1755+
);
1756+
}
17491757
}
17501758

17511759
// check if the dimension is compatible with the texture

wgpu-hal/src/vulkan/adapter.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ pub struct PhysicalDeviceFeatures {
130130

131131
/// Features provided by `VK_KHR_fragment_shader_barycentric`
132132
shader_barycentrics: Option<vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR<'static>>,
133+
134+
/// Features provided by `VK_KHR_portability_subset`.
135+
///
136+
/// Strictly speaking this tells us what features we *don't* have compared to core.
137+
portability_subset: Option<vk::PhysicalDevicePortabilitySubsetFeaturesKHR<'static>>,
133138
}
134139

135140
impl PhysicalDeviceFeatures {
@@ -206,6 +211,9 @@ impl PhysicalDeviceFeatures {
206211
if let Some(ref mut feature) = self.shader_barycentrics {
207212
info = info.push_next(feature);
208213
}
214+
if let Some(ref mut feature) = self.portability_subset {
215+
info = info.push_next(feature);
216+
}
209217
info
210218
}
211219

@@ -551,6 +559,17 @@ impl PhysicalDeviceFeatures {
551559
} else {
552560
None
553561
},
562+
portability_subset: if enabled_extensions.contains(&khr::portability_subset::NAME) {
563+
let multisample_array_needed =
564+
requested_features.intersects(wgt::Features::MULTISAMPLE_ARRAY);
565+
566+
Some(
567+
vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default()
568+
.multisample_array_image(multisample_array_needed),
569+
)
570+
} else {
571+
None
572+
},
554573
}
555574
}
556575

@@ -927,6 +946,15 @@ impl PhysicalDeviceFeatures {
927946
mesh_shader.multiview_mesh_shader != 0,
928947
);
929948
}
949+
950+
// Not supported by default by `VK_KHR_portability_subset`, which we use on apple platforms.
951+
features.set(
952+
F::MULTISAMPLE_ARRAY,
953+
self.portability_subset
954+
.map(|p| p.multisample_array_image == vk::TRUE)
955+
.unwrap_or(true),
956+
);
957+
930958
(features, dl_flags)
931959
}
932960
}
@@ -1690,6 +1718,13 @@ impl super::InstanceShared {
16901718
features2 = features2.push_next(next);
16911719
}
16921720

1721+
if capabilities.supports_extension(khr::portability_subset::NAME) {
1722+
let next = features
1723+
.portability_subset
1724+
.insert(vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default());
1725+
features2 = features2.push_next(next);
1726+
}
1727+
16931728
unsafe { get_device_properties.get_physical_device_features2(phd, &mut features2) };
16941729
features2.features
16951730
} else {

wgpu-types/src/features.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,15 @@ bitflags_array! {
12381238
///
12391239
/// This is a native only feature.
12401240
const EXPERIMENTAL_MESH_SHADER_POINTS = 1 << 55;
1241+
1242+
/// Enables creating texture arrays that are also multisampled.
1243+
///
1244+
/// Without this feature, you cannot create a texture that has both a `sample_count` higher
1245+
/// than 1, and a `depth_or_array_layers` higher than 1.
1246+
///
1247+
/// Supported platforms:
1248+
/// - Vulkan (except VK_KHR_portability_subset if multisampleArrayImage is not available)
1249+
const MULTISAMPLE_ARRAY = 1 << 56;
12411250
}
12421251

12431252
/// Features that are not guaranteed to be supported.

0 commit comments

Comments
 (0)