Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ By @cwfitzgerald in [#8579](https://github.com/gfx-rs/wgpu/pull/8579).
- Added support for transient textures on Vulkan and Metal. By @opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247)
- Implement shader triangle barycentric coordinate builtins. By @atlv24 in [#8320](https://github.com/gfx-rs/wgpu/pull/8320).
- Added support for binding arrays of storage textures on Metal. By @msvbg in [#8464](https://github.com/gfx-rs/wgpu/pull/8464)
- 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).

### Changes

Expand Down
56 changes: 44 additions & 12 deletions tests/tests/wgpu-gpu/multiview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
vec.push(DRAW_MULTIVIEW_SINGLE);
vec.push(DRAW_MULTIVIEW);
vec.push(DRAW_MULTIVIEW_NONCONTIGUOUS);
vec.push(DRAW_MULTIVIEW_MULTISAMPLE);
}

#[gpu_test]
Expand All @@ -21,7 +22,7 @@ static DRAW_MULTIVIEW_SINGLE: GpuTestConfiguration = GpuTestConfiguration::new()
..Limits::defaults()
}),
)
.run_async(|ctx| run_test(ctx, 0b1));
.run_async(|ctx| run_test(ctx, 0b1, 1));

#[gpu_test]
static DRAW_MULTIVIEW: GpuTestConfiguration = GpuTestConfiguration::new()
Expand All @@ -33,7 +34,7 @@ static DRAW_MULTIVIEW: GpuTestConfiguration = GpuTestConfiguration::new()
..Limits::defaults()
}),
)
.run_async(|ctx| run_test(ctx, 0b11));
.run_async(|ctx| run_test(ctx, 0b11, 1));

#[gpu_test]
static DRAW_MULTIVIEW_NONCONTIGUOUS: GpuTestConfiguration = GpuTestConfiguration::new()
Expand All @@ -45,9 +46,21 @@ static DRAW_MULTIVIEW_NONCONTIGUOUS: GpuTestConfiguration = GpuTestConfiguration
..Limits::defaults()
}),
)
.run_async(|ctx| run_test(ctx, 0b1001));
.run_async(|ctx| run_test(ctx, 0b1001, 1));

async fn run_test(ctx: TestingContext, layer_mask: u32) {
#[gpu_test]
static DRAW_MULTIVIEW_MULTISAMPLE: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.features(Features::MULTIVIEW | Features::MULTISAMPLE_ARRAY)
.limits(Limits {
max_multiview_view_count: 2,
..Limits::defaults()
}),
)
.run_async(|ctx| run_test(ctx, 0b11, 4));

async fn run_test(ctx: TestingContext, layer_mask: u32, sample_count: u32) {
let num_layers = 32 - layer_mask.leading_zeros();

let shader_src = include_str!("shader.wgsl");
Expand Down Expand Up @@ -79,29 +92,34 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
})],
}),
multiview_mask: NonZero::new(layer_mask),
multisample: Default::default(),
multisample: wgpu::MultisampleState {
count: sample_count,
..Default::default()
},
layout: None,
depth_stencil: None,
cache: None,
};

const TEXTURE_SIZE: u32 = 256;
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {

let texture_desc = wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width: TEXTURE_SIZE,
height: TEXTURE_SIZE,
depth_or_array_layers: 32 - layer_mask.leading_zeros(),
},
mip_level_count: 1,
sample_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Unorm,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
let entire_texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
};
let texture = ctx.device.create_texture(&texture_desc);
let texture_view_desc = wgpu::TextureViewDescriptor {
label: None,
format: Some(wgpu::TextureFormat::R8Unorm),
dimension: Some(wgpu::TextureViewDimension::D2Array),
Expand All @@ -111,7 +129,21 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
mip_level_count: None,
base_array_layer: 0,
array_layer_count: Some(num_layers),
});
};
let entire_texture_view = texture.create_view(&texture_view_desc);

let (resolve_texture, resolve_texture_view) = if sample_count != 1 {
let mut texture_desc = texture_desc.clone();
texture_desc.sample_count = 1;

let resolve_texture = ctx.device.create_texture(&texture_desc);
let resolve_texture_view = resolve_texture.create_view(&texture_view_desc);

(Some(resolve_texture), Some(resolve_texture_view))
} else {
(None, None)
};

let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: TEXTURE_SIZE as u64 * TEXTURE_SIZE as u64 * num_layers as u64,
Expand All @@ -130,7 +162,7 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &entire_texture_view,
depth_slice: None,
resolve_target: None,
resolve_target: resolve_texture_view.as_ref(),
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
store: wgpu::StoreOp::Store,
Expand All @@ -146,7 +178,7 @@ async fn run_test(ctx: TestingContext, layer_mask: u32) {
}
encoder.copy_texture_to_buffer(
wgpu::TexelCopyTextureInfo {
texture: &texture,
texture: resolve_texture.as_ref().unwrap_or(&texture),
mip_level: 0,
origin: wgpu::Origin3d { x: 0, y: 0, z: 0 },
aspect: wgpu::TextureAspect::All,
Expand Down
20 changes: 14 additions & 6 deletions wgpu-core/src/device/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,9 @@ impl Device {
});
}

if desc.size.depth_or_array_layers != 1 {
if desc.size.depth_or_array_layers != 1
&& !self.features.contains(wgt::Features::MULTISAMPLE_ARRAY)
{
Comment on lines +1439 to +1441
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good

return Err(CreateTextureError::InvalidDimension(
TextureDimensionError::MultisampledDepthOrArrayLayer(
desc.size.depth_or_array_layers,
Expand Down Expand Up @@ -1741,11 +1743,17 @@ impl Device {

// check if multisampled texture is seen as anything but 2D
if texture.desc.sample_count > 1 && resolved_dimension != TextureViewDimension::D2 {
return Err(
resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
resolved_dimension,
),
);
// Multisample is allowed on 2D arrays, only if explicitly supported
let multisample_array_exception = resolved_dimension == TextureViewDimension::D2Array
&& self.features.contains(wgt::Features::MULTISAMPLE_ARRAY);

if !multisample_array_exception {
return Err(
resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
resolved_dimension,
),
);
}
}

// check if the dimension is compatible with the texture
Expand Down
3 changes: 2 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ impl super::Adapter {
| wgt::Features::FLOAT32_FILTERABLE
| wgt::Features::TEXTURE_ATOMIC
| wgt::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS
| wgt::Features::EXTERNAL_TEXTURE;
| wgt::Features::EXTERNAL_TEXTURE
| wgt::Features::MULTISAMPLE_ARRAY;

//TODO: in order to expose this, we need to run a compute shader
// that extract the necessary statistics out of the D3D12 result.
Expand Down
35 changes: 35 additions & 0 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ pub struct PhysicalDeviceFeatures {

/// Features provided by `VK_KHR_fragment_shader_barycentric`
shader_barycentrics: Option<vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR<'static>>,

/// Features provided by `VK_KHR_portability_subset`.
///
/// Strictly speaking this tells us what features we *don't* have compared to core.
portability_subset: Option<vk::PhysicalDevicePortabilitySubsetFeaturesKHR<'static>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be added to device creation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where specifically?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for references to other *Features members in this struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, added to the list.

}

impl PhysicalDeviceFeatures {
Expand Down Expand Up @@ -206,6 +211,9 @@ impl PhysicalDeviceFeatures {
if let Some(ref mut feature) = self.shader_barycentrics {
info = info.push_next(feature);
}
if let Some(ref mut feature) = self.portability_subset {
info = info.push_next(feature);
}
info
}

Expand Down Expand Up @@ -551,6 +559,17 @@ impl PhysicalDeviceFeatures {
} else {
None
},
portability_subset: if enabled_extensions.contains(&khr::portability_subset::NAME) {
let multisample_array_needed =
requested_features.intersects(wgt::Features::MULTISAMPLE_ARRAY);

Some(
vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default()
.multisample_array_image(multisample_array_needed),
)
} else {
None
},
}
}

Expand Down Expand Up @@ -927,6 +946,15 @@ impl PhysicalDeviceFeatures {
mesh_shader.multiview_mesh_shader != 0,
);
}

// Not supported by default by `VK_KHR_portability_subset`, which we use on apple platforms.
features.set(
F::MULTISAMPLE_ARRAY,
self.portability_subset
.map(|p| p.multisample_array_image == vk::TRUE)
.unwrap_or(true),
);

(features, dl_flags)
}
}
Expand Down Expand Up @@ -1698,6 +1726,13 @@ impl super::InstanceShared {
features2 = features2.push_next(next);
}

if capabilities.supports_extension(khr::portability_subset::NAME) {
let next = features
.portability_subset
.insert(vk::PhysicalDevicePortabilitySubsetFeaturesKHR::default());
features2 = features2.push_next(next);
}

unsafe { get_device_properties.get_physical_device_features2(phd, &mut features2) };
features2.features
} else {
Expand Down
10 changes: 10 additions & 0 deletions wgpu-types/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,16 @@ bitflags_array! {
///
/// This is a native only feature.
const EXPERIMENTAL_MESH_SHADER_POINTS = 1 << 55;

/// Enables creating texture arrays that are also multisampled.
///
/// Without this feature, you cannot create a texture that has both a `sample_count` higher
/// than 1, and a `depth_or_array_layers` higher than 1.
///
/// Supported platforms:
/// - Vulkan (except VK_KHR_portability_subset if multisampleArrayImage is not available)
/// - DX12
const MULTISAMPLE_ARRAY = 1 << 56;
Comment on lines +1267 to +1275
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way we could add support to some Metal platforms in this PR? Especially with Apple Vision Pro this would probably be useful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be very useful for apple vision pro, but I don't have any apple products to test this on and the support seems to be non-trivial.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the support is non-trivial? Isn't it just checking if the OS version is high enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to @teoxoy it would require a few more changes. I have absolutely zero experience with the Metal API.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LaylBongers Alright. If you'd rather not than can you file an issue for Metal multisample array textures?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added at #8593.

}

/// Features that are not guaranteed to be supported.
Expand Down
Loading