diff --git a/CHANGELOG.md b/CHANGELOG.md index d6939c18cce..cc1862b74e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,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 diff --git a/tests/tests/wgpu-gpu/ray_tracing/as_build.rs b/tests/tests/wgpu-gpu/ray_tracing/as_build.rs index f7e72daf9dd..9d2de9bd561 100644 --- a/tests/tests/wgpu-gpu/ray_tracing/as_build.rs +++ b/tests/tests/wgpu-gpu/ray_tracing/as_build.rs @@ -1,4 +1,4 @@ -use std::iter; +use std::{iter, mem}; use crate::ray_tracing::AsBuildContext; use wgpu::util::{BufferInitDescriptor, DeviceExt}; @@ -604,3 +604,204 @@ 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(extra_format_build); + +fn extra_format_build(ctx: TestingContext) { + let vertices = ctx.device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: &[0; mem::size_of::<[[i16; 3]; 3]>()], + usage: BufferUsages::BLAS_INPUT, + }); + + let blas_size = BlasTriangleGeometrySizeDescriptor { + // The fourth component is ignored, and it allows us to have a smaller stride. + vertex_format: VertexFormat::Snorm16x4, + 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"), + }); + command_encoder.build_acceleration_structures( + &[BlasBuildEntry { + blas: &blas, + geometry: BlasGeometries::TriangleGeometries(vec![BlasTriangleGeometry { + size: &blas_size, + vertex_buffer: &vertices, + first_vertex: 0, + vertex_stride: mem::size_of::<[i16; 3]>() as BufferAddress, + index_buffer: None, + first_index: None, + transform_buffer: None, + transform_buffer_offset: None, + }]), + }], + &[], + ); + ctx.queue.submit([command_encoder.finish()]); +} + +#[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")), + ) + .run_sync(misaligned_build); + +fn misaligned_build(ctx: TestingContext) { + let vertices = ctx.device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: &[0; mem::size_of::<[[i16; 3]; 3]>()], + usage: BufferUsages::BLAS_INPUT, + }); + + let blas_size = BlasTriangleGeometrySizeDescriptor { + // The fourth component is ignored, and it allows us to have a smaller stride. + vertex_format: VertexFormat::Float32x3, + 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( + &ctx.device, + || { + command_encoder.build_acceleration_structures( + &[BlasBuildEntry { + blas: &blas, + geometry: BlasGeometries::TriangleGeometries(vec![BlasTriangleGeometry { + size: &blas_size, + vertex_buffer: &vertices, + first_vertex: 0, + // Not aligned to four bytes like it should be + vertex_stride: 13, + index_buffer: None, + first_index: None, + transform_buffer: None, + transform_buffer_offset: None, + }]), + }], + &[], + ) + }, + None, + ); +} + +#[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")), + ) + .run_sync(too_small_stride_build); + +fn too_small_stride_build(ctx: TestingContext) { + let vertices = ctx.device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: &[0; mem::size_of::<[[i16; 3]; 3]>()], + usage: BufferUsages::BLAS_INPUT, + }); + + let blas_size = BlasTriangleGeometrySizeDescriptor { + // The fourth component is ignored, and it allows us to have a smaller stride. + vertex_format: VertexFormat::Float32x3, + 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( + &ctx.device, + || { + command_encoder.build_acceleration_structures( + &[BlasBuildEntry { + blas: &blas, + geometry: BlasGeometries::TriangleGeometries(vec![BlasTriangleGeometry { + size: &blas_size, + vertex_buffer: &vertices, + first_vertex: 0, + // Aligned to four bytes but too small + vertex_stride: 8, + index_buffer: None, + first_index: None, + transform_buffer: None, + transform_buffer_offset: None, + }]), + }], + &[], + ) + }, + None, + ); +} diff --git a/wgpu-core/src/command/ray_tracing.rs b/wgpu-core/src/command/ray_tracing.rs index a5386934edf..33d413cdede 100644 --- a/wgpu-core/src/command/ray_tracing.rs +++ b/wgpu-core/src/command/ray_tracing.rs @@ -898,6 +898,35 @@ fn iter_blas<'a>( )); } + if size_desc + .vertex_format + .acceleration_structure_vertex_readable_size() + > mesh.vertex_stride + { + return Err(BuildAccelerationStructureError::VertexStrideTooSmall( + blas.error_ident(), + size_desc + .vertex_format + .acceleration_structure_vertex_readable_size(), + 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( diff --git a/wgpu-core/src/ray_tracing.rs b/wgpu-core/src/ray_tracing.rs index 602b42fe47d..335ec9568d9 100644 --- a/wgpu-core/src/ray_tracing.rs +++ b/wgpu-core/src/ray_tracing.rs @@ -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), diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index eff1fffd28f..492787ff906 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -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, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index e9ae1e597a2..75e84959d10 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -788,7 +788,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), diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index e99e77f8095..ccf8d7209c7 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -1196,6 +1196,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. @@ -1463,6 +1472,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 } } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 7f53a2a1c41..6477dc79a34 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -4974,6 +4974,29 @@ impl VertexFormat { Self::Float64x4 => 32, } } + + /// Returns the readable size of the vertex format in and acceleration structure build (this is + /// slightly different from [`Self::size`]) + #[must_use] + pub const fn acceleration_structure_vertex_readable_size(&self) -> u64 { + match self { + Self::Float16x2 | Self::Snorm16x2 => 4, + Self::Float32x3 => 12, + Self::Float32x2 => 8, + 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! { @@ -7434,7 +7457,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, diff --git a/wgpu/src/api/blas.rs b/wgpu/src/api/blas.rs index 82c976b98df..c712f15ffa4 100644 --- a/wgpu/src/api/blas.rs +++ b/wgpu/src/api/blas.rs @@ -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::acceleration_structure_vertex_readable_size`] + /// 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>,