diff --git a/CHANGELOG.md b/CHANGELOG.md index f6daf284bc2..6ec69d3fb4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/tests/tests/wgpu-gpu/ray_tracing/as_build.rs b/tests/tests/wgpu-gpu/ray_tracing/as_build.rs index f7e72daf9dd..2dc0e45f141 100644 --- a/tests/tests/wgpu-gpu/ray_tracing/as_build.rs +++ b/tests/tests/wgpu-gpu/ray_tracing/as_build.rs @@ -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()]); + } +} diff --git a/wgpu-core/src/command/ray_tracing.rs b/wgpu-core/src/command/ray_tracing.rs index a5386934edf..3f6950e141c 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 + .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( 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 924ea94a852..333ba22522a 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 3976ef2e5ac..595c30a02e1 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -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), diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index 6cbf2e5f29b..1ac4116c66b 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -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 } } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index a70f224eb61..2cb16e3935d 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -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, diff --git a/wgpu/src/api/blas.rs b/wgpu/src/api/blas.rs index 82c976b98df..fad3d00367a 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::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>,