Add extra acceleration structure vertex formats. (#7580)

This commit is contained in:
Vecvec
2025-06-12 10:17:14 +12:00
committed by GitHub
parent 41616d9ddf
commit efbac5dfba
9 changed files with 193 additions and 5 deletions

View File

@@ -51,6 +51,7 @@ Bottom level categories:
- Add support for astc-sliced-3d feature. By @mehmetoguzderin in [#7577](https://github.com/gfx-rs/wgpu/issues/7577)
- Add support for rendering to slices of 3D texture views and single layered 2D-Array texture views (this requires `VK_KHR_maintenance1` which should be widely available on newer drivers). By @teoxoy in [#7596](https://github.com/gfx-rs/wgpu/pull/7596)
- Add extra acceleration structure vertex formats. By @Vecvec in [#7580](https://github.com/gfx-rs/wgpu/pull/7580).
#### Naga

View File

@@ -4,7 +4,7 @@ use crate::ray_tracing::AsBuildContext;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::*;
use wgpu_test::{
fail, gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext,
fail, fail_if, gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext,
};
#[gpu_test]
@@ -604,3 +604,106 @@ fn only_tlas_vertex_return(ctx: TestingContext) {
None,
);
}
#[gpu_test]
static EXTRA_FORMAT_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.test_features_limits()
.features(
wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
| wgpu::Features::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS,
)
// https://github.com/gfx-rs/wgpu/issues/6727
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
)
.run_sync(|ctx| test_as_build_format_stride(ctx, VertexFormat::Snorm16x4, 6, false));
#[gpu_test]
static MISALIGNED_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.test_features_limits()
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
// https://github.com/gfx-rs/wgpu/issues/6727
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
)
// Larger than the minimum size, but not aligned as required
.run_sync(|ctx| test_as_build_format_stride(ctx, VertexFormat::Float32x3, 13, true));
#[gpu_test]
static TOO_SMALL_STRIDE_BUILD: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.test_features_limits()
.features(wgpu::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE)
// https://github.com/gfx-rs/wgpu/issues/6727
.skip(FailureCase::backend_adapter(wgpu::Backends::VULKAN, "AMD")),
)
// Aligned as required, but smaller than minimum size
.run_sync(|ctx| test_as_build_format_stride(ctx, VertexFormat::Float32x3, 8, true));
fn test_as_build_format_stride(
ctx: TestingContext,
format: VertexFormat,
stride: BufferAddress,
invalid_combination: bool,
) {
let vertices = ctx.device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: &vec![0; (format.min_acceleration_structure_vertex_stride() * 3) as usize],
usage: BufferUsages::BLAS_INPUT,
});
let blas_size = BlasTriangleGeometrySizeDescriptor {
// The fourth component is ignored, and it allows us to have a smaller stride.
vertex_format: format,
vertex_count: 3,
index_format: None,
index_count: None,
flags: wgpu::AccelerationStructureGeometryFlags::empty(),
};
let blas = ctx.device.create_blas(
&CreateBlasDescriptor {
label: Some("BLAS"),
flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
update_mode: AccelerationStructureUpdateMode::Build,
},
BlasGeometrySizeDescriptors::Triangles {
descriptors: vec![blas_size.clone()],
},
);
let mut command_encoder = ctx
.device
.create_command_encoder(&CommandEncoderDescriptor {
label: Some("BLAS_1"),
});
fail_if(
&ctx.device,
invalid_combination,
|| {
command_encoder.build_acceleration_structures(
&[BlasBuildEntry {
blas: &blas,
geometry: BlasGeometries::TriangleGeometries(vec![BlasTriangleGeometry {
size: &blas_size,
vertex_buffer: &vertices,
first_vertex: 0,
vertex_stride: stride,
index_buffer: None,
first_index: None,
transform_buffer: None,
transform_buffer_offset: None,
}]),
}],
&[],
)
},
None,
);
if !invalid_combination {
ctx.queue.submit([command_encoder.finish()]);
}
}

View File

@@ -898,6 +898,35 @@ fn iter_blas<'a>(
));
}
if size_desc
.vertex_format
.min_acceleration_structure_vertex_stride()
> mesh.vertex_stride
{
return Err(BuildAccelerationStructureError::VertexStrideTooSmall(
blas.error_ident(),
size_desc
.vertex_format
.min_acceleration_structure_vertex_stride(),
mesh.vertex_stride,
));
}
if mesh.vertex_stride
% size_desc
.vertex_format
.acceleration_structure_stride_alignment()
!= 0
{
return Err(BuildAccelerationStructureError::VertexStrideUnaligned(
blas.error_ident(),
size_desc
.vertex_format
.acceleration_structure_stride_alignment(),
mesh.vertex_stride,
));
}
match (size_desc.index_count, mesh.size.index_count) {
(Some(_), None) | (None, Some(_)) => {
return Err(

View File

@@ -102,6 +102,12 @@ pub enum BuildAccelerationStructureError {
#[error("Blas {0:?} vertex formats are different, creation format: {1:?}, provided: {2:?}")]
DifferentBlasVertexFormats(ResourceErrorIdent, VertexFormat, VertexFormat),
#[error("Blas {0:?} stride was required to be at least {1} but stride given was {2}")]
VertexStrideTooSmall(ResourceErrorIdent, u64, u64),
#[error("Blas {0:?} stride was required to be a multiple of {1} but stride given was {2}")]
VertexStrideUnaligned(ResourceErrorIdent, u64, u64),
#[error("Blas {0:?} index count was provided at creation or building, but not the other")]
BlasIndexCountProvidedMismatch(ResourceErrorIdent),

View File

@@ -474,7 +474,8 @@ impl super::Adapter {
// Once ray tracing pipelines are supported they also will go here
features.set(
wgt::Features::EXPERIMENTAL_RAY_QUERY
| wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE,
| wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
| wgt::Features::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS,
features5.RaytracingTier == Direct3D12::D3D12_RAYTRACING_TIER_1_1
&& shader_model >= naga::back::hlsl::ShaderModel::V6_5
&& has_features5,

View File

@@ -799,7 +799,8 @@ impl PhysicalDeviceFeatures {
features.set(F::DEPTH32FLOAT_STENCIL8, texture_d32_s8);
features.set(
F::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE,
F::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
| F::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS,
caps.supports_extension(khr::deferred_host_operations::NAME)
&& caps.supports_extension(khr::acceleration_structure::NAME)
&& caps.supports_extension(khr::buffer_device_address::NAME),

View File

@@ -1217,6 +1217,15 @@ bitflags_array! {
///
/// This is a native only feature.
const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 49;
/// Allows usage of additional vertex formats in [BlasTriangleGeometrySizeDescriptor::vertex_format]
///
/// Supported platforms
/// - Vulkan
/// - DX12
///
/// [BlasTriangleGeometrySizeDescriptor::vertex_format]: super::BlasTriangleGeometrySizeDescriptor
const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 50;
}
/// Features that are not guaranteed to be supported.
@@ -1484,6 +1493,13 @@ impl Features {
if self.contains(Self::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE) {
formats.push(VertexFormat::Float32x3);
}
if self.contains(Self::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS) {
formats.push(VertexFormat::Float32x2);
formats.push(VertexFormat::Float16x2);
formats.push(VertexFormat::Float16x4);
formats.push(VertexFormat::Snorm16x2);
formats.push(VertexFormat::Snorm16x4);
}
formats
}
}

View File

@@ -4974,6 +4974,36 @@ impl VertexFormat {
Self::Float64x4 => 32,
}
}
/// Returns the size read by an acceleration structure build of the vertex format. This is
/// slightly different from [`Self::size`] because the alpha component of 4-component formats
/// are not read in an acceleration structure build, allowing for a smaller stride.
#[must_use]
pub const fn min_acceleration_structure_vertex_stride(&self) -> u64 {
match self {
Self::Float16x2 | Self::Snorm16x2 => 4,
Self::Float32x3 => 12,
Self::Float32x2 => 8,
// This is the minimum value from DirectX
// > A16 component is ignored, other data can be packed there, such as setting vertex stride to 6 bytes
//
// https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html#d3d12_raytracing_geometry_triangles_desc
//
// Vulkan does not express a minimum stride.
Self::Float16x4 | Self::Snorm16x4 => 6,
_ => unreachable!(),
}
}
/// Returns the alignment required for `wgpu::BlasTriangleGeometry::vertex_stride`
#[must_use]
pub const fn acceleration_structure_stride_alignment(&self) -> u64 {
match self {
Self::Float16x4 | Self::Float16x2 | Self::Snorm16x4 | Self::Snorm16x2 => 2,
Self::Float32x2 | Self::Float32x3 => 4,
_ => unreachable!(),
}
}
}
bitflags::bitflags! {
@@ -7436,7 +7466,7 @@ impl Default for ShaderRuntimeChecks {
pub struct BlasTriangleGeometrySizeDescriptor {
/// Format of a vertex position, must be [`VertexFormat::Float32x3`]
/// with just [`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE`]
/// but later features may add more formats.
/// but [`Features::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS`] adds more.
pub vertex_format: VertexFormat,
/// Number of vertices.
pub vertex_count: u32,

View File

@@ -100,7 +100,8 @@ pub struct BlasTriangleGeometry<'a> {
pub vertex_buffer: &'a Buffer,
/// Offset into the vertex buffer as a factor of the vertex stride.
pub first_vertex: u32,
/// Vertex stride.
/// Vertex stride, must be greater than [`wgpu_types::VertexFormat::min_acceleration_structure_vertex_stride`]
/// of the format and must be a multiple of [`wgpu_types::VertexFormat::acceleration_structure_stride_alignment`].
pub vertex_stride: wgt::BufferAddress,
/// Index buffer (optional).
pub index_buffer: Option<&'a Buffer>,