From cd16e71654ef7acf0979c113198a660a3d519f26 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 3 Sep 2022 15:28:00 +0200 Subject: [PATCH 01/11] Initial commit --- wgpu-hal/examples/halmark/main.rs | 8 ++++ wgpu-hal/src/empty.rs | 4 ++ wgpu-hal/src/gles/device.rs | 6 +++ wgpu-hal/src/gles/mod.rs | 1 + wgpu-hal/src/lib.rs | 18 ++++++++ wgpu-hal/src/vulkan/adapter.rs | 21 +++++++++ wgpu-hal/src/vulkan/device.rs | 71 +++++++++++++++++++++++++++++++ wgpu-hal/src/vulkan/mod.rs | 9 ++++ 8 files changed, 138 insertions(+) diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 383efcdc53..1fa19bfd07 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -345,6 +345,14 @@ impl Example { }; let sampler = unsafe { device.create_sampler(&sampler_desc).unwrap() }; + let accel = unsafe { + device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { + label: Some("my as"), + size: 1024, + format: hal::AccelerationStructureFormat::BottomLevel, + }) + }; + let globals = Globals { // cgmath::ortho() projection mvp: [ diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 0c546469b2..59eae2dedf 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -28,6 +28,7 @@ impl crate::Api for Api { type Sampler = Resource; type QuerySet = Resource; type Fence = Resource; + type AccelerationStructure = Resource; type BindGroupLayout = Resource; type BindGroup = Resource; @@ -118,6 +119,9 @@ impl crate::Device for Context { unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { Ok(Resource) } + unsafe fn create_acceleration_structure(&self, desc: &crate::AccelerationStructureDescriptor) -> DeviceResult { + Ok(Resource) + } unsafe fn destroy_buffer(&self, buffer: Resource) {} unsafe fn map_buffer( &self, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 04ecdffe02..b8fd7d3842 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -455,6 +455,12 @@ impl crate::Device for super::Device { data, }) } + unsafe fn create_acceleration_structure( + &self, + _desc: &crate::AccelerationStructureDescriptor, + ) -> Result<(), crate::DeviceError> { + unimplemented!() + } unsafe fn destroy_buffer(&self, buffer: super::Buffer) { if let Some(raw) = buffer.raw { let gl = &self.shared.context.lock(); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 717502f2c6..a688f230e7 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -112,6 +112,7 @@ impl crate::Api for Api { type Sampler = Sampler; type QuerySet = QuerySet; type Fence = Fence; + type AccelerationStructure = (); type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 02d3c13af1..88d0a848fc 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -172,6 +172,8 @@ pub trait Api: Clone + Sized { type ShaderModule: fmt::Debug + Send + Sync; type RenderPipeline: Send + Sync; type ComputePipeline: Send + Sync; + + type AccelerationStructure: fmt::Debug + Send + Sync + 'static; } pub trait Instance: Sized + Send + Sync { @@ -236,6 +238,9 @@ pub trait Device: Send + Sync { /// /// The initial usage is `BufferUses::empty()`. unsafe fn create_buffer(&self, desc: &BufferDescriptor) -> Result; + + unsafe fn create_acceleration_structure(&self, desc: &AccelerationStructureDescriptor) -> Result; + unsafe fn destroy_buffer(&self, buffer: A::Buffer); //TODO: clarify if zero-sized mapping is allowed unsafe fn map_buffer( @@ -810,6 +815,19 @@ pub struct BufferDescriptor<'a> { pub memory_flags: MemoryFlags, } +#[derive(Clone, Debug)] +pub struct AccelerationStructureDescriptor<'a> { + pub label: Label<'a>, + pub size: wgt::BufferAddress, + pub format: AccelerationStructureFormat, +} + +#[derive(Clone, Debug)] +pub enum AccelerationStructureFormat { + TopLevel, + BottomLevel, +} + #[derive(Clone, Debug)] pub struct TextureDescriptor<'a> { pub label: Label<'a>, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 0a3afb690e..94ca7e0d13 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -27,6 +27,7 @@ pub struct PhysicalDeviceFeatures { vk::PhysicalDeviceShaderFloat16Int8Features, vk::PhysicalDevice16BitStorageFeatures, )>, + acceleration_structure: Option, } // This is safe because the structs have `p_next: *mut c_void`, which we null out/never read. @@ -65,6 +66,9 @@ impl PhysicalDeviceFeatures { info = info.push_next(f16_i8_feature); info = info.push_next(_16bit_feature); } + if let Some(ref mut feature) = self.acceleration_structure { + info = info.push_next(feature); + } info } @@ -295,6 +299,12 @@ impl PhysicalDeviceFeatures { } else { None }, + acceleration_structure: if true { + Some(vk::PhysicalDeviceAccelerationStructureFeaturesKHR::builder() + .acceleration_structure(true).build()) + } else { + None + } } } @@ -579,6 +589,11 @@ impl PhysicalDeviceCapabilities { extensions.push(vk::KhrDrawIndirectCountFn::name()); } + if true { + extensions.push(vk::KhrDeferredHostOperationsFn::name()); + extensions.push(vk::KhrAccelerationStructureFn::name()); + } + if requested_features.contains(wgt::Features::CONSERVATIVE_RASTERIZATION) { extensions.push(vk::ExtConservativeRasterizationFn::name()); } @@ -1098,6 +1113,11 @@ impl super::Adapter { } else { None }; + let acceleration_structure_fn = if enabled_extensions.contains(&khr::AccelerationStructure::name()) { + Some(khr::AccelerationStructure::new(&self.instance.raw, &raw_device)) + } else { + None + }; let naga_options = { use naga::back::spv; @@ -1190,6 +1210,7 @@ impl super::Adapter { extension_fns: super::DeviceExtensionFunctions { draw_indirect_count: indirect_count_fn, timeline_semaphore: timeline_semaphore_fn, + acceleration_structure: acceleration_structure_fn, }, vendor_id: self.phd_capabilities.properties.vendor_id, timestamp_period: self.phd_capabilities.properties.limits.timestamp_period, diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index b9d74e36e3..5f9a326608 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -808,6 +808,77 @@ impl crate::Device for super::Device { block: Mutex::new(block), }) } + + unsafe fn create_acceleration_structure(&self, desc: &crate::AccelerationStructureDescriptor) -> Result { + let functor = match self.shared.extension_fns.acceleration_structure { + Some(ref functor) => { + functor + } + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + let vk_buffer_info = vk::BufferCreateInfo::builder() + .size(desc.size) + .usage( + vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + ) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let raw_buffer = self.shared.raw.create_buffer(&vk_buffer_info, None)?; + let req = self.shared.raw.get_buffer_memory_requirements(raw_buffer); + + dbg!(&req); + + let block = self.mem_allocator.lock().alloc( + &*self.shared, + gpu_alloc::Request { + size: req.size, + align_mask: req.alignment - 1, + usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, + memory_types: req.memory_type_bits & self.valid_ash_memory_types, + }, + )?; + + self.shared + .raw + .bind_buffer_memory(raw_buffer, *block.memory(), block.offset())?; + + if let Some(label) = desc.label { + self.shared + .set_object_name(vk::ObjectType::BUFFER, raw_buffer, label); + } + + let ty = match desc.format { + crate::AccelerationStructureFormat::TopLevel => vk::AccelerationStructureTypeKHR::TOP_LEVEL, + crate::AccelerationStructureFormat::BottomLevel => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL, + }; + + let vk_info = vk::AccelerationStructureCreateInfoKHR::builder() + .buffer(raw_buffer) + .offset(256) + .size(desc.size / 2) + .ty(ty).build(); + + dbg!(&vk_info); + + let raw_acceleration_structure = functor.create_acceleration_structure( + &vk_info, + None, + )?; + + if let Some(label) = desc.label { + self.shared + .set_object_name(vk::ObjectType::ACCELERATION_STRUCTURE_KHR, raw_acceleration_structure, label); + } + + Ok(super::AccelerationStructure { + raw: raw_acceleration_structure, + buffer: raw_buffer, + block: Mutex::new(block), + }) + } + unsafe fn destroy_buffer(&self, buffer: super::Buffer) { self.shared.raw.destroy_buffer(buffer.raw, None); self.mem_allocator diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index d3416a50ed..443d7f1422 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -65,6 +65,7 @@ impl crate::Api for Api { type Sampler = Sampler; type QuerySet = QuerySet; type Fence = Fence; + type AccelerationStructure = AccelerationStructure; type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; @@ -147,6 +148,7 @@ enum ExtensionFn { struct DeviceExtensionFunctions { draw_indirect_count: Option, timeline_semaphore: Option>, + acceleration_structure: Option, } /// Set of internal capabilities, which don't show up in the exposed @@ -344,6 +346,13 @@ pub struct Buffer { block: Mutex>, } +#[derive(Debug)] +pub struct AccelerationStructure { + raw: vk::AccelerationStructureKHR, + buffer: vk::Buffer, + block: Mutex>, +} + #[derive(Debug)] pub struct Texture { raw: vk::Image, From ae4dcfed87df8e0b5fd21ffea0645c925c3201de Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sun, 11 Sep 2022 20:53:15 +0200 Subject: [PATCH 02/11] Woo! building an AS works --- wgpu-hal/examples/halmark/main.rs | 131 +++++++++++++++++++++++++-- wgpu-hal/src/empty.rs | 28 +++++- wgpu-hal/src/lib.rs | 61 ++++++++++++- wgpu-hal/src/vulkan/adapter.rs | 89 ++++++++++++++++--- wgpu-hal/src/vulkan/command.rs | 51 +++++++++++ wgpu-hal/src/vulkan/conv.rs | 30 +++++++ wgpu-hal/src/vulkan/device.rs | 143 ++++++++++++++++++++++++------ wgpu-hal/src/vulkan/mod.rs | 1 + 8 files changed, 486 insertions(+), 48 deletions(-) diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 1fa19bfd07..ef92b30f7f 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -252,7 +252,9 @@ impl Example { let staging_buffer_desc = hal::BufferDescriptor { label: Some("stage"), size: texture_data.len() as wgt::BufferAddress, - usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::COPY_SRC, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::COPY_SRC + | hal::BufferUses::BUFFER_DEVICE_ADDRESS, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }; let staging_buffer = unsafe { device.create_buffer(&staging_buffer_desc).unwrap() }; @@ -269,6 +271,110 @@ impl Example { assert!(mapping.is_coherent); } + let triangle: [f32; 9] = [0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; + + let triangle_size = std::mem::size_of::<[f32; 9]>(); + + dbg!(&triangle_size); + + let indices: [u32; 3] = [0, 1, 2]; + + let indices_size = std::mem::size_of::<[u32; 3]>(); + + let triangle_buffer = unsafe { + device + .create_buffer(&hal::BufferDescriptor { + label: Some("t buf"), + size: triangle_size as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap() + }; + + let i_buf = unsafe { + device + .create_buffer(&hal::BufferDescriptor { + label: Some("i buf"), + size: indices_size as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap() + }; + + unsafe { + let mapping = device + .map_buffer(&triangle_buffer, 0..triangle_size as u64) + .unwrap(); + ptr::copy_nonoverlapping( + triangle.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + triangle_size, + ); + device.unmap_buffer(&staging_buffer).unwrap(); + assert!(mapping.is_coherent); + } + + unsafe { + let mapping = device.map_buffer(&i_buf, 0..indices_size as u64).unwrap(); + ptr::copy_nonoverlapping( + indices.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + indices_size, + ); + device.unmap_buffer(&staging_buffer).unwrap(); + assert!(mapping.is_coherent); + } + + let geometry = hal::AccelerationStructureGeometry::Triangles { + vertex_buffer: &triangle_buffer, + vertex_format: wgt::VertexFormat::Float32x3, + max_vertex: 3, + vertex_stride: 3 * 4, + indices: Some(hal::AccelerationStructureGeometryIndices { + buffer: &i_buf, + format: wgt::IndexFormat::Uint32, + }), + }; + + let sizes = unsafe { + device.get_acceleration_structure_build_size( + &geometry, + hal::AccelerationStructureFormat::BottomLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 1, + ) + }; + + dbg!(&sizes); + + let blas = unsafe { + device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { + label: Some("my as"), + size: sizes.acceleration_structure_size, + format: hal::AccelerationStructureFormat::BottomLevel, + }) + } + .unwrap(); + + let scratch_buffer = unsafe { + device + .create_buffer(&hal::BufferDescriptor { + label: Some("scratch buffer"), + size: sizes.build_scratch_size, + usage: hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::STORAGE_READ_WRITE, + memory_flags: hal::MemoryFlags::empty(), + }) + .unwrap() + }; + let texture_desc = hal::TextureDescriptor { label: None, size: wgt::Extent3d { @@ -291,6 +397,21 @@ impl Example { }; let mut cmd_encoder = unsafe { device.create_command_encoder(&cmd_encoder_desc).unwrap() }; unsafe { cmd_encoder.begin_encoding(Some("init")).unwrap() }; + + unsafe { + // todo: extract out bytes from transmission renderer example and try those. + cmd_encoder.build_acceleration_structures( + &geometry, + hal::AccelerationStructureFormat::BottomLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 1, + 0, + &blas, + &scratch_buffer, + ); + } + { let buffer_barrier = hal::BufferBarrier { buffer: &staging_buffer, @@ -345,14 +466,6 @@ impl Example { }; let sampler = unsafe { device.create_sampler(&sampler_desc).unwrap() }; - let accel = unsafe { - device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { - label: Some("my as"), - size: 1024, - format: hal::AccelerationStructureFormat::BottomLevel, - }) - }; - let globals = Globals { // cgmath::ortho() projection mvp: [ diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 59eae2dedf..8119af97c3 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -119,9 +119,22 @@ impl crate::Device for Context { unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { Ok(Resource) } - unsafe fn create_acceleration_structure(&self, desc: &crate::AccelerationStructureDescriptor) -> DeviceResult { + unsafe fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + ) -> DeviceResult { Ok(Resource) } + unsafe fn get_acceleration_structure_build_size( + &self, + geometry: &crate::AccelerationStructureGeometry, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + ) -> crate::AccelerationStructureBuildSizes { + Default::default() + } unsafe fn destroy_buffer(&self, buffer: Resource) {} unsafe fn map_buffer( &self, @@ -395,4 +408,17 @@ impl crate::CommandEncoder for Encoder { unsafe fn dispatch(&mut self, count: [u32; 3]) {} unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {} + + unsafe fn build_acceleration_structures( + &mut self, + geometry: &crate::AccelerationStructureGeometry, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + primitive_offset: u32, + destination_acceleration_structure: &Resource, + scratch_buffer: &Resource, + ) { + } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 88d0a848fc..e475c5748a 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -239,7 +239,19 @@ pub trait Device: Send + Sync { /// The initial usage is `BufferUses::empty()`. unsafe fn create_buffer(&self, desc: &BufferDescriptor) -> Result; - unsafe fn create_acceleration_structure(&self, desc: &AccelerationStructureDescriptor) -> Result; + unsafe fn create_acceleration_structure( + &self, + desc: &AccelerationStructureDescriptor, + ) -> Result; + + unsafe fn get_acceleration_structure_build_size( + &self, + geometry: &AccelerationStructureGeometry, + format: AccelerationStructureFormat, + mode: AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + ) -> AccelerationStructureBuildSizes; unsafe fn destroy_buffer(&self, buffer: A::Buffer); //TODO: clarify if zero-sized mapping is allowed @@ -528,6 +540,18 @@ pub trait CommandEncoder: Send + Sync { unsafe fn dispatch(&mut self, count: [u32; 3]); unsafe fn dispatch_indirect(&mut self, buffer: &A::Buffer, offset: wgt::BufferAddress); + + unsafe fn build_acceleration_structures( + &mut self, + geometry: &crate::AccelerationStructureGeometry, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + primitive_offset: u32, + destination_acceleration_structure: &A::AccelerationStructure, + scratch_buffer: &A::Buffer, + ); } bitflags!( @@ -664,6 +688,8 @@ bitflags::bitflags! { const STORAGE_READ_WRITE = 1 << 8; /// The indirect or count buffer in a indirect draw or dispatch. const INDIRECT = 1 << 9; + const BUFFER_DEVICE_ADDRESS = 1 << 10; + const ACCELERATION_STRUCTURE_BUILD_INPUT = 1 << 11; /// The combination of states that a buffer may be in _at the same time_. const INCLUSIVE = Self::MAP_READ.bits | Self::COPY_SRC.bits | Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits | @@ -822,12 +848,25 @@ pub struct AccelerationStructureDescriptor<'a> { pub format: AccelerationStructureFormat, } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum AccelerationStructureFormat { TopLevel, BottomLevel, } +#[derive(Clone, Debug)] +pub enum AccelerationStructureBuildMode { + Build, + Update, +} + +#[derive(Clone, Debug, Default)] +pub struct AccelerationStructureBuildSizes { + pub acceleration_structure_size: wgt::BufferAddress, + pub update_scratch_size: wgt::BufferAddress, + pub build_scratch_size: wgt::BufferAddress, +} + #[derive(Clone, Debug)] pub struct TextureDescriptor<'a> { pub label: Label<'a>, @@ -1115,6 +1154,24 @@ pub struct BufferCopy { pub size: wgt::BufferSize, } +pub enum AccelerationStructureGeometry<'a, A: Api> { + Triangles { + vertex_buffer: &'a A::Buffer, + vertex_format: wgt::VertexFormat, + max_vertex: u32, + vertex_stride: wgt::BufferAddress, + indices: Option>, + }, + Instances { + buffer: &'a A::Buffer, + }, +} + +pub struct AccelerationStructureGeometryIndices<'a, A: Api> { + pub format: wgt::IndexFormat, + pub buffer: &'a A::Buffer, +} + #[derive(Clone, Debug)] pub struct TextureCopyBase { pub mip_level: u32, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 94ca7e0d13..c5f75864a9 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -28,6 +28,8 @@ pub struct PhysicalDeviceFeatures { vk::PhysicalDevice16BitStorageFeatures, )>, acceleration_structure: Option, + buffer_device_address: Option, + ray_query: Option, } // This is safe because the structs have `p_next: *mut c_void`, which we null out/never read. @@ -69,6 +71,12 @@ impl PhysicalDeviceFeatures { if let Some(ref mut feature) = self.acceleration_structure { info = info.push_next(feature); } + if let Some(ref mut feature) = self.buffer_device_address { + info = info.push_next(feature); + } + if let Some(ref mut feature) = self.ray_query { + info = info.push_next(feature); + } info } @@ -299,12 +307,37 @@ impl PhysicalDeviceFeatures { } else { None }, - acceleration_structure: if true { - Some(vk::PhysicalDeviceAccelerationStructureFeaturesKHR::builder() - .acceleration_structure(true).build()) + acceleration_structure: if enabled_extensions + .contains(&vk::KhrAccelerationStructureFn::name()) + { + Some( + vk::PhysicalDeviceAccelerationStructureFeaturesKHR::builder() + .acceleration_structure(true) + .build(), + ) } else { None - } + }, + buffer_device_address: if enabled_extensions + .contains(&vk::KhrBufferDeviceAddressFn::name()) + { + Some( + vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR::builder() + .buffer_device_address(true) + .build(), + ) + } else { + None + }, + ray_query: if enabled_extensions.contains(&vk::KhrRayQueryFn::name()) { + Some( + vk::PhysicalDeviceRayQueryFeaturesKHR::builder() + .ray_query(true) + .build(), + ) + } else { + None + }, } } @@ -516,11 +549,12 @@ impl PhysicalDeviceFeatures { } /// Information gathered about a physical device capabilities. -#[derive(Default)] +#[derive(Default, Debug)] pub struct PhysicalDeviceCapabilities { supported_extensions: Vec, properties: vk::PhysicalDeviceProperties, descriptor_indexing: Option, + acceleration_structure: Option, } // This is safe because the structs have `p_next: *mut c_void`, which we null out/never read. @@ -592,6 +626,8 @@ impl PhysicalDeviceCapabilities { if true { extensions.push(vk::KhrDeferredHostOperationsFn::name()); extensions.push(vk::KhrAccelerationStructureFn::name()); + extensions.push(vk::KhrBufferDeviceAddressFn::name()); + extensions.push(vk::KhrRayQueryFn::name()); } if requested_features.contains(wgt::Features::CONSERVATIVE_RASTERIZATION) { @@ -752,6 +788,9 @@ impl super::InstanceShared { let supports_descriptor_indexing = capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name()); + let supports_acceleration_structure = + capabilities.supports_extension(vk::KhrAccelerationStructureFn::name()); + let mut builder = vk::PhysicalDeviceProperties2::builder(); if supports_descriptor_indexing { @@ -761,6 +800,13 @@ impl super::InstanceShared { builder = builder.push_next(next); } + if supports_acceleration_structure { + let next = capabilities + .acceleration_structure + .insert(vk::PhysicalDeviceAccelerationStructurePropertiesKHR::default()); + builder = builder.push_next(next); + } + let mut properties2 = builder.build(); unsafe { get_device_properties.get_physical_device_properties2(phd, &mut properties2); @@ -846,6 +892,12 @@ impl super::InstanceShared { builder = builder.push_next(&mut next.0); builder = builder.push_next(&mut next.1); } + if capabilities.supports_extension(vk::KhrAccelerationStructureFn::name()) { + let next = features + .acceleration_structure + .insert(vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default()); + builder = builder.push_next(next); + } let mut features2 = builder.build(); unsafe { @@ -1113,11 +1165,24 @@ impl super::Adapter { } else { None }; - let acceleration_structure_fn = if enabled_extensions.contains(&khr::AccelerationStructure::name()) { - Some(khr::AccelerationStructure::new(&self.instance.raw, &raw_device)) - } else { - None - }; + let acceleration_structure_fn = + if enabled_extensions.contains(&khr::AccelerationStructure::name()) { + Some(khr::AccelerationStructure::new( + &self.instance.raw, + &raw_device, + )) + } else { + None + }; + let buffer_device_address_fn = + if enabled_extensions.contains(&khr::BufferDeviceAddress::name()) { + Some(khr::BufferDeviceAddress::new( + &self.instance.raw, + &raw_device, + )) + } else { + None + }; let naga_options = { use naga::back::spv; @@ -1211,6 +1276,7 @@ impl super::Adapter { draw_indirect_count: indirect_count_fn, timeline_semaphore: timeline_semaphore_fn, acceleration_structure: acceleration_structure_fn, + buffer_device_address: buffer_device_address_fn, }, vendor_id: self.phd_capabilities.properties.vendor_id, timestamp_period: self.phd_capabilities.properties.limits.timestamp_period, @@ -1259,7 +1325,8 @@ impl super::Adapter { size: memory_heap.size, }) .collect(), - buffer_device_address: false, + buffer_device_address: enabled_extensions + .contains(&khr::BufferDeviceAddress::name()), }; gpu_alloc::GpuAllocator::new(config, properties) }; diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index e225ca8356..641145dc94 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -341,6 +341,57 @@ impl crate::CommandEncoder for super::CommandEncoder { ); } + unsafe fn build_acceleration_structures( + &mut self, + geometry: &crate::AccelerationStructureGeometry, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + primitive_offset: u32, + destination_acceleration_structure: &super::AccelerationStructure, + scratch_buffer: &super::Buffer, + ) { + let extension = match self.device.extension_fns.acceleration_structure { + Some(ref extension) => extension, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + let bda_extension = match self.device.extension_fns.buffer_device_address { + Some(ref extension) => extension, + None => panic!("Feature `BDA` not enabled"), + }; + + let geometry = + super::device::map_acceleration_structure_geometry(geometry, &bda_extension).build(); + + let geometries = &[geometry]; + + let range = vk::AccelerationStructureBuildRangeInfoKHR::builder() + .primitive_count(primitive_count) + .primitive_offset(primitive_offset) + .build(); + + let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + .ty(conv::map_acceleration_structure_format(format)) + .mode(conv::map_acceleration_structure_build_mode(mode)) + .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) + .geometries(geometries) + .dst_acceleration_structure(destination_acceleration_structure.raw) + .scratch_data(vk::DeviceOrHostAddressKHR { + device_address: bda_extension.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(scratch_buffer.raw), + ), + }) + .build(); + + let range = &[range][..]; + let range = &[range][..]; + let geometry_info = &[geometry_info]; + + extension.cmd_build_acceleration_structures(self.active, geometry_info, range); + } + // render unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) { diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index dc5b915970..95ff907f83 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -491,6 +491,12 @@ pub fn map_buffer_usage(usage: crate::BufferUses) -> vk::BufferUsageFlags { if usage.contains(crate::BufferUses::INDIRECT) { flags |= vk::BufferUsageFlags::INDIRECT_BUFFER; } + if usage.contains(crate::BufferUses::BUFFER_DEVICE_ADDRESS) { + flags |= vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS; + } + if usage.contains(crate::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT) { + flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR; + } flags } @@ -823,3 +829,27 @@ pub fn map_pipeline_statistics( } flags } + +pub fn map_acceleration_structure_format( + format: crate::AccelerationStructureFormat, +) -> vk::AccelerationStructureTypeKHR { + match format { + crate::AccelerationStructureFormat::TopLevel => vk::AccelerationStructureTypeKHR::TOP_LEVEL, + crate::AccelerationStructureFormat::BottomLevel => { + vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL + } + } +} + +pub fn map_acceleration_structure_build_mode( + format: crate::AccelerationStructureBuildMode, +) -> vk::BuildAccelerationStructureModeKHR { + match format { + crate::AccelerationStructureBuildMode::Build => { + vk::BuildAccelerationStructureModeKHR::BUILD + } + crate::AccelerationStructureBuildMode::Update => { + vk::BuildAccelerationStructureModeKHR::UPDATE + } + } +} diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 5f9a326608..79a12e689b 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -809,11 +809,53 @@ impl crate::Device for super::Device { }) } - unsafe fn create_acceleration_structure(&self, desc: &crate::AccelerationStructureDescriptor) -> Result { - let functor = match self.shared.extension_fns.acceleration_structure { - Some(ref functor) => { - functor - } + unsafe fn get_acceleration_structure_build_size( + &self, + geometry: &crate::AccelerationStructureGeometry, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: (), + primitive_count: u32, + ) -> crate::AccelerationStructureBuildSizes { + let extension = match self.shared.extension_fns.acceleration_structure { + Some(ref extension) => extension, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + let bda_extension = match self.shared.extension_fns.buffer_device_address { + Some(ref extension) => extension, + None => panic!("Feature `BDA` not enabled"), + }; + + let geometry = map_acceleration_structure_geometry(geometry, &bda_extension); + + let geometries = &[*geometry]; + + let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + .ty(conv::map_acceleration_structure_format(format)) + .mode(conv::map_acceleration_structure_build_mode(mode)) + .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) + .geometries(geometries); + + let raw = extension.get_acceleration_structure_build_sizes( + vk::AccelerationStructureBuildTypeKHR::DEVICE, + &geometry_info, + &[primitive_count], + ); + + crate::AccelerationStructureBuildSizes { + acceleration_structure_size: raw.acceleration_structure_size, + update_scratch_size: raw.update_scratch_size, + build_scratch_size: raw.build_scratch_size, + } + } + + unsafe fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + ) -> Result { + let extension = match self.shared.extension_fns.acceleration_structure { + Some(ref extension) => extension, None => panic!("Feature `RAY_TRACING` not enabled"), }; @@ -821,14 +863,12 @@ impl crate::Device for super::Device { .size(desc.size) .usage( vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR - | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS, ) .sharing_mode(vk::SharingMode::EXCLUSIVE); let raw_buffer = self.shared.raw.create_buffer(&vk_buffer_info, None)?; let req = self.shared.raw.get_buffer_memory_requirements(raw_buffer); - - dbg!(&req); let block = self.mem_allocator.lock().alloc( &*self.shared, @@ -849,27 +889,20 @@ impl crate::Device for super::Device { .set_object_name(vk::ObjectType::BUFFER, raw_buffer, label); } - let ty = match desc.format { - crate::AccelerationStructureFormat::TopLevel => vk::AccelerationStructureTypeKHR::TOP_LEVEL, - crate::AccelerationStructureFormat::BottomLevel => vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL, - }; - let vk_info = vk::AccelerationStructureCreateInfoKHR::builder() - .buffer(raw_buffer) - .offset(256) - .size(desc.size / 2) - .ty(ty).build(); - - dbg!(&vk_info); + .buffer(raw_buffer) + .offset(0) + .size(desc.size) + .ty(conv::map_acceleration_structure_format(desc.format)); - let raw_acceleration_structure = functor.create_acceleration_structure( - &vk_info, - None, - )?; + let raw_acceleration_structure = extension.create_acceleration_structure(&vk_info, None)?; if let Some(label) = desc.label { - self.shared - .set_object_name(vk::ObjectType::ACCELERATION_STRUCTURE_KHR, raw_acceleration_structure, label); + self.shared.set_object_name( + vk::ObjectType::ACCELERATION_STRUCTURE_KHR, + raw_acceleration_structure, + label, + ); } Ok(super::AccelerationStructure { @@ -2006,3 +2039,63 @@ impl From for crate::DeviceError { Self::OutOfMemory } } + +pub unsafe fn map_acceleration_structure_geometry<'a>( + geometry: &crate::AccelerationStructureGeometry, + buffer_device_address: &ash::extensions::khr::BufferDeviceAddress, +) -> vk::AccelerationStructureGeometryKHRBuilder<'a> { + match geometry { + crate::AccelerationStructureGeometry::Instances { buffer } => { + let instances = vk::AccelerationStructureGeometryInstancesDataKHR::builder().data( + vk::DeviceOrHostAddressConstKHR { + device_address: buffer_device_address.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(buffer.raw), + ), + }, + ); + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::INSTANCES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + instances: *instances, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + &crate::AccelerationStructureGeometry::Triangles { + vertex_buffer, + vertex_format, + max_vertex, + vertex_stride, + ref indices, + } => { + let mut triangles_data = vk::AccelerationStructureGeometryTrianglesDataKHR::builder() + .vertex_data(vk::DeviceOrHostAddressConstKHR { + device_address: buffer_device_address.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(vertex_buffer.raw), + ), + }) + .vertex_format(conv::map_vertex_format(vertex_format)) + .vertex_stride(vertex_stride) + .max_vertex(max_vertex); + + if let Some(indices) = indices { + triangles_data = triangles_data + .index_type(conv::map_index_format(indices.format)) + .index_data(vk::DeviceOrHostAddressConstKHR { + device_address: buffer_device_address.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(indices.buffer.raw), + ), + }) + } + + let triangles_data = triangles_data.build(); + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::TRIANGLES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + triangles: triangles_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + } +} diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 443d7f1422..5732fbfb60 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -149,6 +149,7 @@ struct DeviceExtensionFunctions { draw_indirect_count: Option, timeline_semaphore: Option>, acceleration_structure: Option, + buffer_device_address: Option, } /// Set of internal capabilities, which don't show up in the exposed From 98cf75b594f378ef6b186c27f955e60469234a73 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sun, 11 Sep 2022 23:29:49 +0200 Subject: [PATCH 03/11] Fix alignment for amdpro driver --- wgpu-hal/examples/halmark/main.rs | 179 +++++++++++++++++++++++++++++- wgpu-hal/src/empty.rs | 7 ++ wgpu-hal/src/lib.rs | 10 +- wgpu-hal/src/vulkan/conv.rs | 13 ++- wgpu-hal/src/vulkan/device.rs | 47 +++++++- 5 files changed, 245 insertions(+), 11 deletions(-) diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index ef92b30f7f..eeb3838533 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -78,6 +78,8 @@ struct Example { context_index: usize, extent: [u32; 2], start: Instant, + buffers: Vec, + acceleration_structures: Vec, } impl Example { @@ -288,7 +290,7 @@ impl Example { size: triangle_size as u64, usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT, + | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }) .unwrap() @@ -301,7 +303,7 @@ impl Example { size: indices_size as u64, usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT, + | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }) .unwrap() @@ -316,7 +318,7 @@ impl Example { mapping.ptr.as_ptr(), triangle_size, ); - device.unmap_buffer(&staging_buffer).unwrap(); + device.unmap_buffer(&triangle_buffer).unwrap(); assert!(mapping.is_coherent); } @@ -327,7 +329,7 @@ impl Example { mapping.ptr.as_ptr(), indices_size, ); - device.unmap_buffer(&staging_buffer).unwrap(); + device.unmap_buffer(&i_buf).unwrap(); assert!(mapping.is_coherent); } @@ -375,6 +377,146 @@ impl Example { .unwrap() }; + #[derive(Clone, Copy)] + struct Vec4 { + x: f32, + y: f32, + z: f32, + w: f32, + } + + struct Mat4 { + rows: [Vec4; 4], + } + + impl Mat4 { + const fn from_translation(x: f32, y: f32, z: f32) -> Self { + Mat4 { + rows: [ + Vec4 { + x: 1.0, + y: 0.0, + z: 0.0, + w: 0.0, + }, + Vec4 { + x: 0.0, + y: 1.0, + z: 0.0, + w: 0.0, + }, + Vec4 { + x: 0.0, + y: 0.0, + z: 1.0, + w: 0.0, + }, + Vec4 { x, y, z, w: 1.0 }, + ], + } + } + } + + fn transpose_matrix_for_acceleration_structure_instance(matrix: Mat4) -> [f32; 12] { + let row_0 = matrix.rows[0]; + let row_1 = matrix.rows[1]; + let row_2 = matrix.rows[2]; + [ + row_0.x, row_0.y, row_0.z, row_0.w, row_1.x, row_1.y, row_1.z, row_1.w, row_2.x, + row_2.y, row_2.z, row_2.w, + ] + } + + fn pack_24_8(low_24: u32, high_8: u8) -> u32 { + (low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24) + } + + #[derive(Debug)] + #[repr(C)] + struct Instance { + transform: [f32; 12], + instance_custom_index_and_mask: u32, + instance_shader_binding_table_record_offset_and_flags: u32, + acceleration_structure_reference: u64, + } + + let instances = unsafe { + [ + Instance { + transform: transpose_matrix_for_acceleration_structure_instance( + Mat4::from_translation(0.0, 0.0, 0.0), + ), + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: device + .get_acceleration_structure_device_address(&blas), + }, + Instance { + transform: transpose_matrix_for_acceleration_structure_instance( + Mat4::from_translation(1.0, 1.0, 1.0), + ), + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: device + .get_acceleration_structure_device_address(&blas), + }, + ] + }; + + let instances_buffer_size = instances.len() * std::mem::size_of::(); + + dbg!(&instances_buffer_size); + + let instances_buffer = unsafe { + device + .create_buffer(&hal::BufferDescriptor { + label: Some("instances_buffer"), + size: instances_buffer_size as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap() + }; + + unsafe { + let mapping = device + .map_buffer(&instances_buffer, 0..instances_buffer_size as u64) + .unwrap(); + ptr::copy_nonoverlapping( + instances.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + instances_buffer_size, + ); + device.unmap_buffer(&instances_buffer).unwrap(); + assert!(mapping.is_coherent); + } + + let instance_geometry: hal::AccelerationStructureGeometry = + hal::AccelerationStructureGeometry::Instances { + buffer: &instances_buffer, + }; + + let instance_sizes = unsafe { + device.get_acceleration_structure_build_size( + &instance_geometry, + hal::AccelerationStructureFormat::TopLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 2, + ) + }; + + let tlas = unsafe { + device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { + label: Some("my tlas"), + size: instance_sizes.acceleration_structure_size, + format: hal::AccelerationStructureFormat::TopLevel, + }) + } + .unwrap(); + let texture_desc = hal::TextureDescriptor { label: None, size: wgt::Extent3d { @@ -410,6 +552,24 @@ impl Example { &blas, &scratch_buffer, ); + + let as_barrier = hal::BufferBarrier { + buffer: &staging_buffer, + usage: hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT + ..hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + }; + cmd_encoder.transition_buffers(iter::once(as_barrier)); + + cmd_encoder.build_acceleration_structures( + &instance_geometry, + hal::AccelerationStructureFormat::TopLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 2, + 0, + &tlas, + &scratch_buffer, + ); } { @@ -623,6 +783,8 @@ impl Example { context_index: 0, extent: [window_size.0, window_size.1], start: Instant::now(), + buffers: vec![triangle_buffer, i_buf, scratch_buffer, instances_buffer], + acceleration_structures: vec![blas, tlas], }) } @@ -651,6 +813,15 @@ impl Example { self.device.destroy_buffer(self.global_buffer); self.device.destroy_texture_view(self.texture_view); self.device.destroy_texture(self.texture); + + for buffer in self.buffers.drain(..) { + self.device.destroy_buffer(buffer); + } + + for a_s in self.acceleration_structures.drain(..) { + self.device.destroy_acceleration_structure(a_s); + } + self.device.destroy_sampler(self.sampler); self.device.destroy_shader_module(self.shader); self.device.destroy_render_pipeline(self.pipeline); diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 8119af97c3..904f4d119b 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -135,6 +135,13 @@ impl crate::Device for Context { ) -> crate::AccelerationStructureBuildSizes { Default::default() } + unsafe fn get_acceleration_structure_device_address( + &self, + _acceleration_structure: &Resource, + ) -> wgt::BufferAddress { + Default::default() + } + unsafe fn destroy_acceleration_structure(&self, buffer: Resource) {} unsafe fn destroy_buffer(&self, buffer: Resource) {} unsafe fn map_buffer( &self, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index e475c5748a..212a31d848 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -253,6 +253,13 @@ pub trait Device: Send + Sync { primitive_count: u32, ) -> AccelerationStructureBuildSizes; + unsafe fn get_acceleration_structure_device_address( + &self, + acceleration_structure: &A::AccelerationStructure, + ) -> wgt::BufferAddress; + + unsafe fn destroy_acceleration_structure(&self, buffer: A::AccelerationStructure); + unsafe fn destroy_buffer(&self, buffer: A::Buffer); //TODO: clarify if zero-sized mapping is allowed unsafe fn map_buffer( @@ -689,7 +696,8 @@ bitflags::bitflags! { /// The indirect or count buffer in a indirect draw or dispatch. const INDIRECT = 1 << 9; const BUFFER_DEVICE_ADDRESS = 1 << 10; - const ACCELERATION_STRUCTURE_BUILD_INPUT = 1 << 11; + const BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 11; + const TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 12; /// The combination of states that a buffer may be in _at the same time_. const INCLUSIVE = Self::MAP_READ.bits | Self::COPY_SRC.bits | Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits | diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 95ff907f83..f8d6e68f1f 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -494,7 +494,10 @@ pub fn map_buffer_usage(usage: crate::BufferUses) -> vk::BufferUsageFlags { if usage.contains(crate::BufferUses::BUFFER_DEVICE_ADDRESS) { flags |= vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS; } - if usage.contains(crate::BufferUses::ACCELERATION_STRUCTURE_BUILD_INPUT) { + if usage.intersects( + crate::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT + | crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + ) { flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR; } flags @@ -549,6 +552,14 @@ pub fn map_buffer_usage_to_barrier( stages |= vk::PipelineStageFlags::DRAW_INDIRECT; access |= vk::AccessFlags::INDIRECT_COMMAND_READ; } + if usage.intersects( + crate::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT + | crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + ) { + stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR; + access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR + | vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR; + } (stages, access) } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 79a12e689b..a0cfe725d9 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -788,7 +788,14 @@ impl crate::Device for super::Device { &*self.shared, gpu_alloc::Request { size: req.size, - align_mask: req.alignment - 1, + align_mask: if desc + .usage + .contains(crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT) + { + 16 + } else { + req.alignment + } - 1, usage: alloc_usage, memory_types: req.memory_type_bits & self.valid_ash_memory_types, }, @@ -850,6 +857,21 @@ impl crate::Device for super::Device { } } + unsafe fn get_acceleration_structure_device_address( + &self, + acceleration_structure: &super::AccelerationStructure, + ) -> wgt::BufferAddress { + let extension = match self.shared.extension_fns.acceleration_structure { + Some(ref extension) => extension, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + extension.get_acceleration_structure_device_address( + &vk::AccelerationStructureDeviceAddressInfoKHR::builder() + .acceleration_structure(acceleration_structure.raw), + ) + } + unsafe fn create_acceleration_structure( &self, desc: &crate::AccelerationStructureDescriptor, @@ -861,10 +883,7 @@ impl crate::Device for super::Device { let vk_buffer_info = vk::BufferCreateInfo::builder() .size(desc.size) - .usage( - vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR - | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS, - ) + .usage(vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR) .sharing_mode(vk::SharingMode::EXCLUSIVE); let raw_buffer = self.shared.raw.create_buffer(&vk_buffer_info, None)?; @@ -919,6 +938,24 @@ impl crate::Device for super::Device { .dealloc(&*self.shared, buffer.block.into_inner()); } + unsafe fn destroy_acceleration_structure( + &self, + acceleration_structure: super::AccelerationStructure, + ) { + let extension = match self.shared.extension_fns.acceleration_structure { + Some(ref extension) => extension, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + extension.destroy_acceleration_structure(acceleration_structure.raw, None); + self.shared + .raw + .destroy_buffer(acceleration_structure.buffer, None); + self.mem_allocator + .lock() + .dealloc(&*self.shared, acceleration_structure.block.into_inner()); + } + unsafe fn map_buffer( &self, buffer: &super::Buffer, From 6655d2380495302a460e20692b6f91c80c1ffdb0 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 12 Sep 2022 23:26:26 +0200 Subject: [PATCH 04/11] Ray tracing works in shaders! --- Cargo.lock | 9 +- wgpu-hal/Cargo.toml | 1 + wgpu-hal/examples/halmark/main.rs | 296 +------ wgpu-hal/examples/ray-traced-triangle/main.rs | 829 ++++++++++++++++++ .../examples/ray-traced-triangle/shader.comp | 44 + .../ray-traced-triangle/shader.comp.spv | Bin 0 -> 3520 bytes wgpu-hal/src/empty.rs | 4 +- wgpu-hal/src/lib.rs | 20 +- wgpu-hal/src/vulkan/command.rs | 61 +- wgpu-hal/src/vulkan/conv.rs | 1 + wgpu-hal/src/vulkan/device.rs | 141 +-- wgpu-types/src/lib.rs | 2 + 12 files changed, 1035 insertions(+), 373 deletions(-) create mode 100644 wgpu-hal/examples/ray-traced-triangle/main.rs create mode 100644 wgpu-hal/examples/ray-traced-triangle/shader.comp create mode 100644 wgpu-hal/examples/ray-traced-triangle/shader.comp.spv diff --git a/Cargo.lock b/Cargo.lock index 7b48ee4aad..7fea60ce6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -814,6 +814,12 @@ version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f" +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + [[package]] name = "glow" version = "0.11.2" @@ -2352,7 +2358,7 @@ dependencies = [ "ddsfile", "env_logger", "futures-intrusive", - "glam", + "glam 0.20.5", "js-sys", "log", "naga", @@ -2414,6 +2420,7 @@ dependencies = [ "env_logger", "foreign-types 0.3.2", "fxhash", + "glam 0.21.3", "glow", "glutin", "gpu-alloc", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index b89f400537..9fcc70e8b6 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -109,6 +109,7 @@ features = ["wgsl-in"] [dev-dependencies] env_logger = "0.9" winit = "0.27.1" # for "halmark" example +glam = "0.21.3" # for ray-traced-triangle example [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] glutin = "0.28.0" # for "gles" example diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index eeb3838533..bd8196d8dc 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -78,8 +78,6 @@ struct Example { context_index: usize, extent: [u32; 2], start: Instant, - buffers: Vec, - acceleration_structures: Vec, } impl Example { @@ -254,9 +252,7 @@ impl Example { let staging_buffer_desc = hal::BufferDescriptor { label: Some("stage"), size: texture_data.len() as wgt::BufferAddress, - usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::COPY_SRC - | hal::BufferUses::BUFFER_DEVICE_ADDRESS, + usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::COPY_SRC, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }; let staging_buffer = unsafe { device.create_buffer(&staging_buffer_desc).unwrap() }; @@ -273,250 +269,6 @@ impl Example { assert!(mapping.is_coherent); } - let triangle: [f32; 9] = [0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; - - let triangle_size = std::mem::size_of::<[f32; 9]>(); - - dbg!(&triangle_size); - - let indices: [u32; 3] = [0, 1, 2]; - - let indices_size = std::mem::size_of::<[u32; 3]>(); - - let triangle_buffer = unsafe { - device - .create_buffer(&hal::BufferDescriptor { - label: Some("t buf"), - size: triangle_size as u64, - usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, - memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, - }) - .unwrap() - }; - - let i_buf = unsafe { - device - .create_buffer(&hal::BufferDescriptor { - label: Some("i buf"), - size: indices_size as u64, - usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, - memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, - }) - .unwrap() - }; - - unsafe { - let mapping = device - .map_buffer(&triangle_buffer, 0..triangle_size as u64) - .unwrap(); - ptr::copy_nonoverlapping( - triangle.as_ptr() as *const u8, - mapping.ptr.as_ptr(), - triangle_size, - ); - device.unmap_buffer(&triangle_buffer).unwrap(); - assert!(mapping.is_coherent); - } - - unsafe { - let mapping = device.map_buffer(&i_buf, 0..indices_size as u64).unwrap(); - ptr::copy_nonoverlapping( - indices.as_ptr() as *const u8, - mapping.ptr.as_ptr(), - indices_size, - ); - device.unmap_buffer(&i_buf).unwrap(); - assert!(mapping.is_coherent); - } - - let geometry = hal::AccelerationStructureGeometry::Triangles { - vertex_buffer: &triangle_buffer, - vertex_format: wgt::VertexFormat::Float32x3, - max_vertex: 3, - vertex_stride: 3 * 4, - indices: Some(hal::AccelerationStructureGeometryIndices { - buffer: &i_buf, - format: wgt::IndexFormat::Uint32, - }), - }; - - let sizes = unsafe { - device.get_acceleration_structure_build_size( - &geometry, - hal::AccelerationStructureFormat::BottomLevel, - hal::AccelerationStructureBuildMode::Build, - (), - 1, - ) - }; - - dbg!(&sizes); - - let blas = unsafe { - device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { - label: Some("my as"), - size: sizes.acceleration_structure_size, - format: hal::AccelerationStructureFormat::BottomLevel, - }) - } - .unwrap(); - - let scratch_buffer = unsafe { - device - .create_buffer(&hal::BufferDescriptor { - label: Some("scratch buffer"), - size: sizes.build_scratch_size, - usage: hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::STORAGE_READ_WRITE, - memory_flags: hal::MemoryFlags::empty(), - }) - .unwrap() - }; - - #[derive(Clone, Copy)] - struct Vec4 { - x: f32, - y: f32, - z: f32, - w: f32, - } - - struct Mat4 { - rows: [Vec4; 4], - } - - impl Mat4 { - const fn from_translation(x: f32, y: f32, z: f32) -> Self { - Mat4 { - rows: [ - Vec4 { - x: 1.0, - y: 0.0, - z: 0.0, - w: 0.0, - }, - Vec4 { - x: 0.0, - y: 1.0, - z: 0.0, - w: 0.0, - }, - Vec4 { - x: 0.0, - y: 0.0, - z: 1.0, - w: 0.0, - }, - Vec4 { x, y, z, w: 1.0 }, - ], - } - } - } - - fn transpose_matrix_for_acceleration_structure_instance(matrix: Mat4) -> [f32; 12] { - let row_0 = matrix.rows[0]; - let row_1 = matrix.rows[1]; - let row_2 = matrix.rows[2]; - [ - row_0.x, row_0.y, row_0.z, row_0.w, row_1.x, row_1.y, row_1.z, row_1.w, row_2.x, - row_2.y, row_2.z, row_2.w, - ] - } - - fn pack_24_8(low_24: u32, high_8: u8) -> u32 { - (low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24) - } - - #[derive(Debug)] - #[repr(C)] - struct Instance { - transform: [f32; 12], - instance_custom_index_and_mask: u32, - instance_shader_binding_table_record_offset_and_flags: u32, - acceleration_structure_reference: u64, - } - - let instances = unsafe { - [ - Instance { - transform: transpose_matrix_for_acceleration_structure_instance( - Mat4::from_translation(0.0, 0.0, 0.0), - ), - instance_custom_index_and_mask: pack_24_8(0, 0xff), - instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), - acceleration_structure_reference: device - .get_acceleration_structure_device_address(&blas), - }, - Instance { - transform: transpose_matrix_for_acceleration_structure_instance( - Mat4::from_translation(1.0, 1.0, 1.0), - ), - instance_custom_index_and_mask: pack_24_8(0, 0xff), - instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), - acceleration_structure_reference: device - .get_acceleration_structure_device_address(&blas), - }, - ] - }; - - let instances_buffer_size = instances.len() * std::mem::size_of::(); - - dbg!(&instances_buffer_size); - - let instances_buffer = unsafe { - device - .create_buffer(&hal::BufferDescriptor { - label: Some("instances_buffer"), - size: instances_buffer_size as u64, - usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, - memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, - }) - .unwrap() - }; - - unsafe { - let mapping = device - .map_buffer(&instances_buffer, 0..instances_buffer_size as u64) - .unwrap(); - ptr::copy_nonoverlapping( - instances.as_ptr() as *const u8, - mapping.ptr.as_ptr(), - instances_buffer_size, - ); - device.unmap_buffer(&instances_buffer).unwrap(); - assert!(mapping.is_coherent); - } - - let instance_geometry: hal::AccelerationStructureGeometry = - hal::AccelerationStructureGeometry::Instances { - buffer: &instances_buffer, - }; - - let instance_sizes = unsafe { - device.get_acceleration_structure_build_size( - &instance_geometry, - hal::AccelerationStructureFormat::TopLevel, - hal::AccelerationStructureBuildMode::Build, - (), - 2, - ) - }; - - let tlas = unsafe { - device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { - label: Some("my tlas"), - size: instance_sizes.acceleration_structure_size, - format: hal::AccelerationStructureFormat::TopLevel, - }) - } - .unwrap(); - let texture_desc = hal::TextureDescriptor { label: None, size: wgt::Extent3d { @@ -539,39 +291,6 @@ impl Example { }; let mut cmd_encoder = unsafe { device.create_command_encoder(&cmd_encoder_desc).unwrap() }; unsafe { cmd_encoder.begin_encoding(Some("init")).unwrap() }; - - unsafe { - // todo: extract out bytes from transmission renderer example and try those. - cmd_encoder.build_acceleration_structures( - &geometry, - hal::AccelerationStructureFormat::BottomLevel, - hal::AccelerationStructureBuildMode::Build, - (), - 1, - 0, - &blas, - &scratch_buffer, - ); - - let as_barrier = hal::BufferBarrier { - buffer: &staging_buffer, - usage: hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT - ..hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, - }; - cmd_encoder.transition_buffers(iter::once(as_barrier)); - - cmd_encoder.build_acceleration_structures( - &instance_geometry, - hal::AccelerationStructureFormat::TopLevel, - hal::AccelerationStructureBuildMode::Build, - (), - 2, - 0, - &tlas, - &scratch_buffer, - ); - } - { let buffer_barrier = hal::BufferBarrier { buffer: &staging_buffer, @@ -696,6 +415,7 @@ impl Example { buffers: &[global_buffer_binding], samplers: &[&sampler], textures: &[texture_binding], + acceleration_structures: &[], entries: &[ hal::BindGroupEntry { binding: 0, @@ -729,6 +449,7 @@ impl Example { buffers: &[local_buffer_binding], samplers: &[], textures: &[], + acceleration_structures: &[], entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, @@ -783,8 +504,6 @@ impl Example { context_index: 0, extent: [window_size.0, window_size.1], start: Instant::now(), - buffers: vec![triangle_buffer, i_buf, scratch_buffer, instances_buffer], - acceleration_structures: vec![blas, tlas], }) } @@ -813,15 +532,6 @@ impl Example { self.device.destroy_buffer(self.global_buffer); self.device.destroy_texture_view(self.texture_view); self.device.destroy_texture(self.texture); - - for buffer in self.buffers.drain(..) { - self.device.destroy_buffer(buffer); - } - - for a_s in self.acceleration_structures.drain(..) { - self.device.destroy_acceleration_structure(a_s); - } - self.device.destroy_sampler(self.sampler); self.device.destroy_shader_module(self.shader); self.device.destroy_render_pipeline(self.pipeline); diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs new file mode 100644 index 0000000000..93f62eac04 --- /dev/null +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -0,0 +1,829 @@ +extern crate wgpu_hal as hal; + +use hal::{ + Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, Surface as _, +}; + +use glam::{Mat4, Vec3}; +use std::{ + borrow::{Borrow, Cow}, + iter, mem, + mem::{align_of, size_of}, + ptr::{self, copy_nonoverlapping}, + time::Instant, +}; + +const COMMAND_BUFFER_PER_CONTEXT: usize = 100; +const DESIRED_FRAMES: u32 = 3; + +struct ExecutionContext { + encoder: A::CommandEncoder, + fence: A::Fence, + fence_value: hal::FenceValue, + used_views: Vec, + used_cmd_bufs: Vec, + frames_recorded: usize, +} + +impl ExecutionContext { + unsafe fn wait_and_clear(&mut self, device: &A::Device) { + device.wait(&self.fence, self.fence_value, !0).unwrap(); + self.encoder.reset_all(self.used_cmd_bufs.drain(..)); + for view in self.used_views.drain(..) { + device.destroy_texture_view(view); + } + self.frames_recorded = 0; + } +} + +#[allow(dead_code)] +struct Example { + instance: A::Instance, + adapter: A::Adapter, + surface: A::Surface, + surface_format: wgt::TextureFormat, + device: A::Device, + queue: A::Queue, + + contexts: Vec>, + context_index: usize, + extent: [u32; 2], + start: Instant, + pipeline: A::ComputePipeline, + bind_group: A::BindGroup, + //local_group: A::BindGroup, + //global_group_layout: A::BindGroupLayout, + //local_group_layout: A::BindGroupLayout, + pipeline_layout: A::PipelineLayout, + /*shader: A::ShaderModule, + pipeline: A::RenderPipeline, + bunnies: Vec, + local_buffer: A::Buffer, + local_alignment: u32, + global_buffer: A::Buffer, + sampler: A::Sampler, + */ + texture: A::Texture, + /*texture_view: A::TextureView, + contexts: Vec>, + context_index: usize, + extent: [u32; 2], + start: Instant, + buffers: Vec, + acceleration_structures: Vec,*/ +} + +impl Example { + fn init(window: &winit::window::Window) -> Result { + let instance_desc = hal::InstanceDescriptor { + name: "example", + flags: if cfg!(debug_assertions) { + hal::InstanceFlags::all() + } else { + hal::InstanceFlags::empty() + }, + }; + let instance = unsafe { A::Instance::init(&instance_desc)? }; + let mut surface = unsafe { instance.create_surface(window).unwrap() }; + + let (adapter, _capabilities) = unsafe { + let mut adapters = instance.enumerate_adapters(); + if adapters.is_empty() { + return Err(hal::InstanceError); + } + let exposed = adapters.swap_remove(0); + (exposed.adapter, exposed.capabilities) + }; + let surface_caps = + unsafe { adapter.surface_capabilities(&surface) }.ok_or(hal::InstanceError)?; + log::info!("Surface caps: {:#?}", surface_caps); + + let hal::OpenDevice { device, mut queue } = unsafe { + adapter + .open(wgt::Features::empty(), &wgt::Limits::default()) + .unwrap() + }; + + let window_size: (u32, u32) = window.inner_size().into(); + let surface_config = hal::SurfaceConfiguration { + swap_chain_size: DESIRED_FRAMES + .max(*surface_caps.swap_chain_sizes.start()) + .min(*surface_caps.swap_chain_sizes.end()), + present_mode: wgt::PresentMode::Fifo, + composite_alpha_mode: hal::CompositeAlphaMode::Opaque, + format: wgt::TextureFormat::Rgba8Unorm, + extent: wgt::Extent3d { + width: window_size.0, + height: window_size.1, + depth_or_array_layers: 1, + }, + usage: hal::TextureUses::COLOR_TARGET | hal::TextureUses::COPY_DST, + }; + unsafe { + surface.configure(&device, &surface_config).unwrap(); + }; + + #[allow(dead_code)] + struct Uniforms { + view_inverse: glam::Mat4, + proj_inverse: glam::Mat4, + } + + let bgl_desc = hal::BindGroupLayoutDescriptor { + label: None, + flags: hal::BindGroupLayoutFlags::empty(), + entries: &[ + wgt::BindGroupLayoutEntry { + binding: 0, + visibility: wgt::ShaderStages::COMPUTE, + ty: wgt::BindingType::Buffer { + ty: wgt::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: wgt::BufferSize::new(mem::size_of::() as _), + }, + count: None, + }, + wgt::BindGroupLayoutEntry { + binding: 1, + visibility: wgt::ShaderStages::COMPUTE, + ty: wgt::BindingType::StorageTexture { + access: wgt::StorageTextureAccess::WriteOnly, + format: wgt::TextureFormat::Rgba8Unorm, + view_dimension: wgt::TextureViewDimension::D2, + }, + count: None, + }, + wgt::BindGroupLayoutEntry { + binding: 2, + visibility: wgt::ShaderStages::COMPUTE, + ty: wgt::BindingType::AccelerationStructure, + count: None, + }, + ], + }; + + let bgl = unsafe { device.create_bind_group_layout(&bgl_desc).unwrap() }; + + pub fn make_spirv_raw(data: &[u8]) -> Cow<[u32]> { + const MAGIC_NUMBER: u32 = 0x0723_0203; + assert_eq!( + data.len() % size_of::(), + 0, + "data size is not a multiple of 4" + ); + + //If the data happens to be aligned, directly use the byte array, + // otherwise copy the byte array in an owned vector and use that instead. + let words = if data.as_ptr().align_offset(align_of::()) == 0 { + let (pre, words, post) = unsafe { data.align_to::() }; + debug_assert!(pre.is_empty()); + debug_assert!(post.is_empty()); + Cow::from(words) + } else { + let mut words = vec![0u32; data.len() / size_of::()]; + unsafe { + copy_nonoverlapping(data.as_ptr(), words.as_mut_ptr() as *mut u8, data.len()); + } + Cow::from(words) + }; + + assert_eq!( + words[0], MAGIC_NUMBER, + "wrong magic word {:x}. Make sure you are using a binary SPIRV file.", + words[0] + ); + + words + } + + let shader = unsafe { + device + .create_shader_module( + &hal::ShaderModuleDescriptor { + label: None, + runtime_checks: false, + }, + hal::ShaderInput::SpirV(&make_spirv_raw(include_bytes!("shader.comp.spv"))), + ) + .unwrap() + }; + + let pipeline_layout_desc = hal::PipelineLayoutDescriptor { + label: None, + flags: hal::PipelineLayoutFlags::empty(), + bind_group_layouts: &[&bgl], + push_constant_ranges: &[], + }; + let pipeline_layout = unsafe { + device + .create_pipeline_layout(&pipeline_layout_desc) + .unwrap() + }; + + let pipeline = unsafe { + device.create_compute_pipeline(&hal::ComputePipelineDescriptor { + label: Some("pipeline"), + layout: &pipeline_layout, + stage: hal::ProgrammableStage { + module: &shader, + entry_point: "main", + }, + }) + } + .unwrap(); + + let vertices: [f32; 9] = [1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0, -1.0, 0.0]; + + let vertices_size_in_bytes = vertices.len() * 4; + + let indices: [u32; 3] = [0, 1, 2]; + + let indices_size_in_bytes = indices.len() * 4; + + let transform_matrix = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]; + + let vertices_buffer = unsafe { + let vertices_buffer = device + .create_buffer(&hal::BufferDescriptor { + label: Some("vertices buffer"), + size: vertices_size_in_bytes as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap(); + + let mapping = device + .map_buffer(&vertices_buffer, 0..vertices_size_in_bytes as u64) + .unwrap(); + ptr::copy_nonoverlapping( + vertices.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + vertices_size_in_bytes, + ); + device.unmap_buffer(&vertices_buffer).unwrap(); + assert!(mapping.is_coherent); + + vertices_buffer + }; + + let indices_buffer = unsafe { + let indices_buffer = device + .create_buffer(&hal::BufferDescriptor { + label: Some("indices buffer"), + size: indices_size_in_bytes as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap(); + + let mapping = device + .map_buffer(&indices_buffer, 0..indices_size_in_bytes as u64) + .unwrap(); + ptr::copy_nonoverlapping( + indices.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + indices_size_in_bytes, + ); + device.unmap_buffer(&indices_buffer).unwrap(); + assert!(mapping.is_coherent); + + indices_buffer + }; + + let blas_sizes = unsafe { + device.get_acceleration_structure_build_sizes( + &hal::AccelerationStructureGeometryInfo::Triangles { + vertex_format: wgt::VertexFormat::Float32x3, + max_vertex: 3, + index_format: Some(wgt::IndexFormat::Uint32), + }, + hal::AccelerationStructureFormat::BottomLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 1, + ) + }; + + let tlas_sizes = unsafe { + device.get_acceleration_structure_build_sizes( + &hal::AccelerationStructureGeometryInfo::Instances, + hal::AccelerationStructureFormat::TopLevel, + hal::AccelerationStructureBuildMode::Build, + (), + 1, + ) + }; + + let blas = unsafe { + device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { + label: Some("blas"), + size: blas_sizes.acceleration_structure_size, + format: hal::AccelerationStructureFormat::BottomLevel, + }) + } + .unwrap(); + + let tlas = unsafe { + device.create_acceleration_structure(&hal::AccelerationStructureDescriptor { + label: Some("tlas"), + size: tlas_sizes.acceleration_structure_size, + format: hal::AccelerationStructureFormat::TopLevel, + }) + } + .unwrap(); + + let uniforms = { + let view = Mat4::look_at_rh(Vec3::new(0.0, 0.0, 2.5), Vec3::ZERO, Vec3::Y); + let proj = Mat4::perspective_rh(59.0_f32.to_radians(), 1.0, 0.001, 1000.0); + + Uniforms { + view_inverse: view.inverse(), + proj_inverse: proj.inverse(), + } + }; + + let uniforms_size = std::mem::size_of::(); + + let uniform_buffer = unsafe { + let uniform_buffer = device + .create_buffer(&hal::BufferDescriptor { + label: Some("uniform buffer"), + size: uniforms_size as u64, + usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::UNIFORM, + memory_flags: hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap(); + + let mapping = device + .map_buffer(&uniform_buffer, 0..uniforms_size as u64) + .unwrap(); + ptr::copy_nonoverlapping( + &uniforms as *const Uniforms as *const u8, + mapping.ptr.as_ptr(), + uniforms_size, + ); + device.unmap_buffer(&uniform_buffer).unwrap(); + assert!(mapping.is_coherent); + uniform_buffer + }; + + let texture_desc = hal::TextureDescriptor { + label: None, + size: wgt::Extent3d { + width: 512, + height: 512, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgt::TextureDimension::D2, + format: wgt::TextureFormat::Rgba8Unorm, + usage: hal::TextureUses::STORAGE_READ_WRITE | hal::TextureUses::COPY_SRC, + memory_flags: hal::MemoryFlags::empty(), + }; + let texture = unsafe { device.create_texture(&texture_desc).unwrap() }; + + let view_desc = hal::TextureViewDescriptor { + label: None, + format: texture_desc.format, + dimension: wgt::TextureViewDimension::D2, + usage: hal::TextureUses::STORAGE_READ_WRITE | hal::TextureUses::COPY_SRC, + range: wgt::ImageSubresourceRange::default(), + }; + let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() }; + + let bind_group = { + let buffer_binding = hal::BufferBinding { + buffer: &uniform_buffer, + offset: 0, + size: None, + }; + let texture_binding = hal::TextureBinding { + view: &texture_view, + usage: hal::TextureUses::STORAGE_READ_WRITE, + }; + let group_desc = hal::BindGroupDescriptor { + label: Some("bind group"), + layout: &bgl, + buffers: &[buffer_binding], + samplers: &[], + textures: &[texture_binding], + acceleration_structures: &[&tlas], + entries: &[ + hal::BindGroupEntry { + binding: 0, + resource_index: 0, + count: 1, + }, + hal::BindGroupEntry { + binding: 1, + resource_index: 0, + count: 1, + }, + hal::BindGroupEntry { + binding: 2, + resource_index: 0, + count: 1, + }, + ], + }; + unsafe { device.create_bind_group(&group_desc).unwrap() } + }; + + let scratch_buffer = unsafe { + device + .create_buffer(&hal::BufferDescriptor { + label: Some("scratch buffer"), + size: blas_sizes + .build_scratch_size + .max(tlas_sizes.build_scratch_size), + usage: hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::STORAGE_READ_WRITE, + memory_flags: hal::MemoryFlags::empty(), + }) + .unwrap() + }; + + fn pack_24_8(low_24: u32, high_8: u8) -> u32 { + (low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24) + } + + #[derive(Debug)] + #[repr(C)] + struct Instance { + transform: [f32; 12], + instance_custom_index_and_mask: u32, + instance_shader_binding_table_record_offset_and_flags: u32, + acceleration_structure_reference: u64, + } + + fn transpose_matrix_for_acceleration_structure_instance(matrix: Mat4) -> [f32; 12] { + let row_0 = matrix.row(0); + let row_1 = matrix.row(1); + let row_2 = matrix.row(2); + [ + row_0.x, row_0.y, row_0.z, row_0.w, row_1.x, row_1.y, row_1.z, row_1.w, row_2.x, + row_2.y, row_2.z, row_2.w, + ] + } + + let instances = [ + Instance { + transform: transform_matrix, + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: unsafe { + device.get_acceleration_structure_device_address(&blas) + }, + }, + Instance { + transform: transpose_matrix_for_acceleration_structure_instance( + Mat4::from_rotation_y(1.0), + ), + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: unsafe { + device.get_acceleration_structure_device_address(&blas) + }, + }, + Instance { + transform: transpose_matrix_for_acceleration_structure_instance( + Mat4::from_rotation_y(-1.0), + ), + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: unsafe { + device.get_acceleration_structure_device_address(&blas) + }, + }, + ]; + + let instances_buffer_size = instances.len() * std::mem::size_of::(); + + let instances_buffer = unsafe { + let instances_buffer = device + .create_buffer(&hal::BufferDescriptor { + label: Some("instances_buffer"), + size: instances_buffer_size as u64, + usage: hal::BufferUses::MAP_WRITE + | hal::BufferUses::BUFFER_DEVICE_ADDRESS + | hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, + }) + .unwrap(); + + let mapping = device + .map_buffer(&instances_buffer, 0..instances_buffer_size as u64) + .unwrap(); + ptr::copy_nonoverlapping( + instances.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + instances_buffer_size, + ); + device.unmap_buffer(&instances_buffer).unwrap(); + assert!(mapping.is_coherent); + + instances_buffer + }; + + let cmd_encoder_desc = hal::CommandEncoderDescriptor { + label: None, + queue: &queue, + }; + let mut cmd_encoder = unsafe { device.create_command_encoder(&cmd_encoder_desc).unwrap() }; + + unsafe { cmd_encoder.begin_encoding(Some("init")).unwrap() }; + + unsafe { + cmd_encoder.build_acceleration_structures( + &hal::AccelerationStructureGeometry::Triangles { + vertex_buffer: &vertices_buffer, + vertex_format: wgt::VertexFormat::Float32x3, + max_vertex: vertices.len() as u32, + vertex_stride: 3 * 4, + indices: Some(hal::AccelerationStructureGeometryIndices { + buffer: &indices_buffer, + format: wgt::IndexFormat::Uint32, + }), + }, + hal::AccelerationStructureFormat::BottomLevel, + hal::AccelerationStructureBuildMode::Build, + (), + indices.len() as u32 / 3, + 0, + &blas, + &scratch_buffer, + ); + + let as_barrier = hal::BufferBarrier { + buffer: &scratch_buffer, + usage: hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT + ..hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + }; + cmd_encoder.transition_buffers(iter::once(as_barrier)); + + cmd_encoder.build_acceleration_structures( + &hal::AccelerationStructureGeometry::Instances { + buffer: &instances_buffer, + }, + hal::AccelerationStructureFormat::TopLevel, + hal::AccelerationStructureBuildMode::Build, + (), + instances.len() as u32, + 0, + &tlas, + &scratch_buffer, + ); + + let texture_barrier = hal::TextureBarrier { + texture: &texture, + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::UNINITIALIZED..hal::TextureUses::STORAGE_READ_WRITE, + }; + + cmd_encoder.transition_textures(iter::once(texture_barrier)); + } + + let init_fence_value = 1; + let fence = unsafe { + let mut fence = device.create_fence().unwrap(); + let init_cmd = cmd_encoder.end_encoding().unwrap(); + queue + .submit(&[&init_cmd], Some((&mut fence, init_fence_value))) + .unwrap(); + device.wait(&fence, init_fence_value, !0).unwrap(); + cmd_encoder.reset_all(iter::once(init_cmd)); + fence + }; + + Ok(Self { + instance, + adapter, + surface, + surface_format: surface_config.format, + device, + queue, + pipeline, + contexts: vec![ExecutionContext { + encoder: cmd_encoder, + fence, + fence_value: init_fence_value + 1, + used_views: Vec::new(), + used_cmd_bufs: Vec::new(), + frames_recorded: 0, + }], + context_index: 0, + extent: [window_size.0, window_size.1], + start: Instant::now(), + pipeline_layout, + bind_group, + texture, + }) + } + + fn update(&mut self, _event: winit::event::WindowEvent) {} + + fn render(&mut self) { + let ctx = &mut self.contexts[self.context_index]; + + let surface_tex = unsafe { self.surface.acquire_texture(None).unwrap().unwrap().texture }; + + let target_barrier0 = hal::TextureBarrier { + texture: surface_tex.borrow(), + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::UNINITIALIZED..hal::TextureUses::COPY_DST, + }; + unsafe { + ctx.encoder.begin_encoding(Some("frame")).unwrap(); + ctx.encoder.transition_textures(iter::once(target_barrier0)); + } + + let surface_view_desc = hal::TextureViewDescriptor { + label: None, + format: self.surface_format, + dimension: wgt::TextureViewDimension::D2, + usage: hal::TextureUses::COPY_DST, + range: wgt::ImageSubresourceRange::default(), + }; + let surface_tex_view = unsafe { + self.device + .create_texture_view(surface_tex.borrow(), &surface_view_desc) + .unwrap() + }; + unsafe { + ctx.encoder + .begin_compute_pass(&hal::ComputePassDescriptor { label: None }); + ctx.encoder.set_compute_pipeline(&self.pipeline); + ctx.encoder + .set_bind_group(&self.pipeline_layout, 0, &self.bind_group, &[]); + ctx.encoder.dispatch([512 / 8, 512 / 8, 1]); + } + + ctx.frames_recorded += 1; + let do_fence = ctx.frames_recorded > COMMAND_BUFFER_PER_CONTEXT; + + let target_barrier1 = hal::TextureBarrier { + texture: surface_tex.borrow(), + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::COPY_DST..hal::TextureUses::PRESENT, + }; + let target_barrier2 = hal::TextureBarrier { + texture: &self.texture, + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::STORAGE_READ_WRITE..hal::TextureUses::COPY_SRC, + }; + let target_barrier3 = hal::TextureBarrier { + texture: &self.texture, + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::COPY_SRC..hal::TextureUses::STORAGE_READ_WRITE, + }; + unsafe { + ctx.encoder.end_compute_pass(); + ctx.encoder.transition_textures(iter::once(target_barrier2)); + ctx.encoder.copy_texture_to_texture( + &self.texture, + hal::TextureUses::COPY_SRC, + &surface_tex.borrow(), + std::iter::once(hal::TextureCopy { + src_base: hal::TextureCopyBase { + mip_level: 0, + array_layer: 0, + origin: wgt::Origin3d::ZERO, + aspect: hal::FormatAspects::COLOR, + }, + dst_base: hal::TextureCopyBase { + mip_level: 0, + array_layer: 0, + origin: wgt::Origin3d::ZERO, + aspect: hal::FormatAspects::COLOR, + }, + size: hal::CopyExtent { + width: 512, + height: 512, + depth: 1, + }, + }), + ); + ctx.encoder.transition_textures(iter::once(target_barrier1)); + ctx.encoder.transition_textures(iter::once(target_barrier3)); + } + + unsafe { + let cmd_buf = ctx.encoder.end_encoding().unwrap(); + let fence_param = if do_fence { + Some((&mut ctx.fence, ctx.fence_value)) + } else { + None + }; + self.queue.submit(&[&cmd_buf], fence_param).unwrap(); + self.queue.present(&mut self.surface, surface_tex).unwrap(); + ctx.used_cmd_bufs.push(cmd_buf); + ctx.used_views.push(surface_tex_view); + }; + + if do_fence { + log::info!("Context switch from {}", self.context_index); + let old_fence_value = ctx.fence_value; + if self.contexts.len() == 1 { + let hal_desc = hal::CommandEncoderDescriptor { + label: None, + queue: &self.queue, + }; + self.contexts.push(unsafe { + ExecutionContext { + encoder: self.device.create_command_encoder(&hal_desc).unwrap(), + fence: self.device.create_fence().unwrap(), + fence_value: 0, + used_views: Vec::new(), + used_cmd_bufs: Vec::new(), + frames_recorded: 0, + } + }); + } + self.context_index = (self.context_index + 1) % self.contexts.len(); + let next = &mut self.contexts[self.context_index]; + unsafe { + next.wait_and_clear(&self.device); + } + next.fence_value = old_fence_value + 1; + } + } +} + +#[cfg(all(feature = "metal"))] +type Api = hal::api::Metal; +#[cfg(all(feature = "vulkan", not(feature = "metal")))] +type Api = hal::api::Vulkan; +#[cfg(all(feature = "gles", not(feature = "metal"), not(feature = "vulkan")))] +type Api = hal::api::Gles; +#[cfg(all( + feature = "dx12", + not(feature = "metal"), + not(feature = "vulkan"), + not(feature = "gles") +))] +type Api = hal::api::Dx12; +#[cfg(not(any( + feature = "metal", + feature = "vulkan", + feature = "gles", + feature = "dx12" +)))] +type Api = hal::api::Empty; + +fn main() { + env_logger::init(); + + let event_loop = winit::event_loop::EventLoop::new(); + let window = winit::window::WindowBuilder::new() + .with_title("hal-bunnymark") + .with_inner_size(winit::dpi::PhysicalSize { + width: 512, + height: 512, + }) + .build(&event_loop) + .unwrap(); + + let example_result = Example::::init(&window); + let mut example = Some(example_result.expect("Selected backend is not supported")); + + event_loop.run(move |event, _, control_flow| { + let _ = &window; // force ownership by the closure + *control_flow = winit::event_loop::ControlFlow::Poll; + match event { + winit::event::Event::RedrawEventsCleared => { + window.request_redraw(); + } + winit::event::Event::WindowEvent { event, .. } => match event { + winit::event::WindowEvent::KeyboardInput { + input: + winit::event::KeyboardInput { + virtual_keycode: Some(winit::event::VirtualKeyCode::Escape), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } + | winit::event::WindowEvent::CloseRequested => { + *control_flow = winit::event_loop::ControlFlow::Exit; + } + _ => { + example.as_mut().unwrap().update(event); + } + }, + winit::event::Event::RedrawRequested(_) => { + let ex = example.as_mut().unwrap(); + + ex.render(); + } + winit::event::Event::LoopDestroyed => { + //example.take().unwrap().exit(); + } + _ => {} + } + }); +} diff --git a/wgpu-hal/examples/ray-traced-triangle/shader.comp b/wgpu-hal/examples/ray-traced-triangle/shader.comp new file mode 100644 index 0000000000..d31f29115f --- /dev/null +++ b/wgpu-hal/examples/ray-traced-triangle/shader.comp @@ -0,0 +1,44 @@ +#version 460 +#extension GL_EXT_ray_query : enable + +layout(set = 0, binding = 0) uniform Uniforms +{ + mat4 viewInverse; + mat4 projInverse; +} cam; +layout(set = 0, binding = 1, rgba8) uniform image2D image; +layout(set = 0, binding = 2) uniform accelerationStructureEXT tlas; + +layout(local_size_x = 8, local_size_y = 8) in; + +void main() +{ + uvec2 launch_id = gl_GlobalInvocationID.xy; + uvec2 launch_size = gl_NumWorkGroups.xy * 8; + + const vec2 pixelCenter = vec2(launch_id) + vec2(0.5); + const vec2 inUV = pixelCenter/vec2(launch_size); + vec2 d = inUV * 2.0 - 1.0; + + vec4 origin = cam.viewInverse * vec4(0,0,0,1); + vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1) ; + vec4 direction = cam.viewInverse*vec4(normalize(target.xyz), 0) ; + + float tmin = 0.001; + float tmax = 10000.0; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, gl_RayFlagsOpaqueEXT, 0xff, origin.xyz, tmin, direction.xyz, tmax); + + rayQueryProceedEXT(rayQuery); + + vec3 out_colour = vec3(0.0, 0.0, 0.0); + + if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT ) { + vec2 barycentrics = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true); + + out_colour = vec3(barycentrics.x, barycentrics.y, 1.0 - barycentrics.x - barycentrics.y); + } + + imageStore(image, ivec2(launch_id), vec4(out_colour, 1.0)); +} \ No newline at end of file diff --git a/wgpu-hal/examples/ray-traced-triangle/shader.comp.spv b/wgpu-hal/examples/ray-traced-triangle/shader.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..345085c948d1fab7ad065d6d92437f40c1c57440 GIT binary patch literal 3520 zcmZ9O`F0dV6o)&>B#}ihYym|KizpHiWfcU%IsqaCLc$_443i-lm`sOG0tvDNL5=@- zj<4af_zFIU%Q+tXzV0p1UGiqyz7DsPIKS$ZbckJG?(+bO?Hbv@N9(6|T=mjuQ zt~KPBf_GAMq&!nFdj{*Z@z;v{9izY;#evevE0JY9<$r%$B*_GtO5oT=KwDmk6$+Q>OKGjTai?iQ1HW^#%! zeC^RXz%ldnb^#DgVwriC$wg=m9Lr&;ljMVQ}rr-L`Cx0-v?YUgA?V0v={N}C%)?GuDHOL-d z?e3I&HMeJ!&70*K>p3!x^wN3b-v@HS`o?SpjJ{xhoSO4ToMSt>F$LiIdy&o|zZQE( zuIt}`?Rm)w<98zMjlBEQ_8jHx=NHHx&;p!adlzt+zZ+?6Hcz(ReL5Mvti*Nf2XXfd;&mi@AcA+Poppru+(7>itfC8kqvnkvUAOD&rK++9!v2-p zShewYz&c*rM@aYL-kOKK4QKl}cNpt>wEadL_Tw4S^D)PH7b6#d_fy!rz1*`<6Ep4I zUod|6*7P3x_PhRIFK@EF!+w9kukD-NY;S3@y^p@z!LRK*+iVw`Y|nh?4cj+1#E+qm zH`&e~=k_7i@1EZVezWJvGH+SV$vf=vVRr65^@TitJN>pp-U@U%;V^HIPFZsm2z`B# zbF1OZ(Pw@8CTD$f-UZG%iQSESFXx_-ue~AXd;`q4&vNGL?*Ve5-bQri2=z9h%Pr*f ze7k#qy!AXMxlr#zbh%&h_>a)#wgUI*oZEokt9YJspP(D7&$^zs+)@0#2YY~T$S&Yq zz72bU{IA6LCVZK5`;pf0j>v@?U!hyW_aW3cgf4H4_oNRv_hDd+-_KFdm&z>WIJz;% zK!`bkE;?Ag-p&Dij=-Hq5AlH;%sFd@JzhXJ-+2A|K-l9&bk}T*dn_X5 z)cqEHQ`Lu&Bfx!KLw*ac=eGMS0nah)^JdP;JHkH0Ih5h7ANq6)-MK@41zk=!-pn6` zb4_zyi_-Vo^&A5?z)fI%YZ&*qtB}68x6!Wx_cM;Hfu~*m2Np$lfj;ltZ}hy1tOI%L z{z*;)>G+2p=$im?zM<+1-Pw0Di5_Y>SBxze?(RKwx#qi@V9SS?sXWHHL(its~LuEg$k8qMIu}nBUFs&|RnN&>#9J|2I7dy->Pl zf2*E?C%N5;oCk}*BmB>h--CHzyx+%j;Ms)x{37QNFS#Fb&N~s}e$2U6WVrV~p_^~K Te)~{i9@pf&`v2u-?Fat@FKh for Context { ) -> DeviceResult { Ok(Resource) } - unsafe fn get_acceleration_structure_build_size( + unsafe fn get_acceleration_structure_build_sizes( &self, - geometry: &crate::AccelerationStructureGeometry, + geometry_info: &crate::AccelerationStructureGeometryInfo, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, flags: (), diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 212a31d848..44d7860e10 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -244,9 +244,9 @@ pub trait Device: Send + Sync { desc: &AccelerationStructureDescriptor, ) -> Result; - unsafe fn get_acceleration_structure_build_size( + unsafe fn get_acceleration_structure_build_sizes( &self, - geometry: &AccelerationStructureGeometry, + geometry_info: &AccelerationStructureGeometryInfo, format: AccelerationStructureFormat, mode: AccelerationStructureBuildMode, flags: (), @@ -550,9 +550,9 @@ pub trait CommandEncoder: Send + Sync { unsafe fn build_acceleration_structures( &mut self, - geometry: &crate::AccelerationStructureGeometry, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, + geometry: &AccelerationStructureGeometry, + format: AccelerationStructureFormat, + mode: AccelerationStructureBuildMode, flags: (), primitive_count: u32, primitive_offset: u32, @@ -993,6 +993,7 @@ pub struct BindGroupDescriptor<'a, A: Api> { pub samplers: &'a [&'a A::Sampler], pub textures: &'a [TextureBinding<'a, A>], pub entries: &'a [BindGroupEntry], + pub acceleration_structures: &'a [&'a A::AccelerationStructure], } #[derive(Clone, Debug)] @@ -1162,6 +1163,15 @@ pub struct BufferCopy { pub size: wgt::BufferSize, } +pub enum AccelerationStructureGeometryInfo { + Triangles { + vertex_format: wgt::VertexFormat, + max_vertex: u32, + index_format: Option, + }, + Instances, +} + pub enum AccelerationStructureGeometry<'a, A: Api> { Triangles { vertex_buffer: &'a A::Buffer, diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index 641145dc94..e3073b0643 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -362,17 +362,70 @@ impl crate::CommandEncoder for super::CommandEncoder { None => panic!("Feature `BDA` not enabled"), }; - let geometry = - super::device::map_acceleration_structure_geometry(geometry, &bda_extension).build(); + let geometry = match geometry { + crate::AccelerationStructureGeometry::Instances { buffer } => { + let instances = vk::AccelerationStructureGeometryInstancesDataKHR::builder().data( + vk::DeviceOrHostAddressConstKHR { + device_address: bda_extension.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(buffer.raw), + ), + }, + ); + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::INSTANCES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + instances: *instances, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + &crate::AccelerationStructureGeometry::Triangles { + vertex_buffer, + vertex_format, + max_vertex, + vertex_stride, + ref indices, + } => { + let mut triangles_data = + vk::AccelerationStructureGeometryTrianglesDataKHR::builder() + .vertex_data(vk::DeviceOrHostAddressConstKHR { + device_address: bda_extension.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(vertex_buffer.raw), + ), + }) + .vertex_format(conv::map_vertex_format(vertex_format)) + .vertex_stride(vertex_stride) + .max_vertex(max_vertex); + + if let Some(indices) = indices { + triangles_data = triangles_data + .index_type(conv::map_index_format(indices.format)) + .index_data(vk::DeviceOrHostAddressConstKHR { + device_address: bda_extension.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(indices.buffer.raw), + ), + }) + } + + let triangles_data = triangles_data.build(); + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::TRIANGLES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + triangles: triangles_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + }; - let geometries = &[geometry]; + let geometries = &[*geometry]; let range = vk::AccelerationStructureBuildRangeInfoKHR::builder() .primitive_count(primitive_count) .primitive_offset(primitive_offset) .build(); - let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() .ty(conv::map_acceleration_structure_format(format)) .mode(conv::map_acceleration_structure_build_mode(mode)) .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index f8d6e68f1f..e169b4ad29 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -713,6 +713,7 @@ pub fn map_binding_type(ty: wgt::BindingType) -> vk::DescriptorType { wgt::BindingType::Sampler { .. } => vk::DescriptorType::SAMPLER, wgt::BindingType::Texture { .. } => vk::DescriptorType::SAMPLED_IMAGE, wgt::BindingType::StorageTexture { .. } => vk::DescriptorType::STORAGE_IMAGE, + wgt::BindingType::AccelerationStructure => vk::DescriptorType::ACCELERATION_STRUCTURE_KHR, } } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index a0cfe725d9..47c20726fc 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -816,9 +816,9 @@ impl crate::Device for super::Device { }) } - unsafe fn get_acceleration_structure_build_size( + unsafe fn get_acceleration_structure_build_sizes( &self, - geometry: &crate::AccelerationStructureGeometry, + geometry_info: &crate::AccelerationStructureGeometryInfo, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, flags: (), @@ -829,12 +829,40 @@ impl crate::Device for super::Device { None => panic!("Feature `RAY_TRACING` not enabled"), }; - let bda_extension = match self.shared.extension_fns.buffer_device_address { - Some(ref extension) => extension, - None => panic!("Feature `BDA` not enabled"), - }; + let geometry = match geometry_info { + crate::AccelerationStructureGeometryInfo::Instances => { + let instances_data = vk::AccelerationStructureGeometryInstancesDataKHR::builder(); - let geometry = map_acceleration_structure_geometry(geometry, &bda_extension); + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::INSTANCES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + instances: *instances_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + &crate::AccelerationStructureGeometryInfo::Triangles { + vertex_format, + max_vertex, + index_format, + } => { + let mut triangles_data = + vk::AccelerationStructureGeometryTrianglesDataKHR::builder() + .vertex_format(conv::map_vertex_format(vertex_format)) + .max_vertex(max_vertex); + + if let Some(index_format) = index_format { + triangles_data = + triangles_data.index_type(conv::map_index_format(index_format)); + } + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::TRIANGLES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + triangles: *triangles_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + }; let geometries = &[*geometry]; @@ -1277,6 +1305,9 @@ impl crate::Device for super::Device { wgt::BindingType::StorageTexture { .. } => { desc_count.storage_image += count; } + wgt::BindingType::AccelerationStructure => { + desc_count.acceleration_structure += count; + } } } @@ -1475,6 +1506,10 @@ impl crate::Device for super::Device { let mut buffer_infos = Vec::with_capacity(desc.buffers.len()); let mut sampler_infos = Vec::with_capacity(desc.samplers.len()); let mut image_infos = Vec::with_capacity(desc.textures.len()); + let mut acceleration_structure_infos = + Vec::with_capacity(desc.acceleration_structures.len()); + let mut raw_acceleration_structures = + Vec::with_capacity(desc.acceleration_structures.len()); for entry in desc.entries { let (ty, size) = desc.layout.types[entry.binding as usize]; if size == 0 { @@ -1484,6 +1519,9 @@ impl crate::Device for super::Device { .dst_set(*set.raw()) .dst_binding(entry.binding) .descriptor_type(ty); + + let mut extra_descriptor_count = 0; + write = match ty { vk::DescriptorType::SAMPLER => { let index = sampler_infos.len(); @@ -1532,9 +1570,36 @@ impl crate::Device for super::Device { )); write.buffer_info(&buffer_infos[index..]) } + vk::DescriptorType::ACCELERATION_STRUCTURE_KHR => { + let index = acceleration_structure_infos.len(); + let start = entry.resource_index; + let end = start + entry.count; + + let raw_start = raw_acceleration_structures.len(); + + raw_acceleration_structures.extend( + desc.acceleration_structures[start as usize..end as usize] + .iter() + .map(|acceleration_structure| acceleration_structure.raw), + ); + + acceleration_structure_infos.push( + // todo: this dereference to build the struct is a hack to get around lifetime issues. + *vk::WriteDescriptorSetAccelerationStructureKHR::builder() + .acceleration_structures(&raw_acceleration_structures[raw_start..]), + ); + + extra_descriptor_count += 1; + + write.push_next(&mut acceleration_structure_infos[index]) + } _ => unreachable!(), }; - writes.push(write.build()); + + let mut write = write.build(); + write.descriptor_count += extra_descriptor_count; + + writes.push(write); } self.shared.raw.update_descriptor_sets(&writes, &[]); @@ -2076,63 +2141,3 @@ impl From for crate::DeviceError { Self::OutOfMemory } } - -pub unsafe fn map_acceleration_structure_geometry<'a>( - geometry: &crate::AccelerationStructureGeometry, - buffer_device_address: &ash::extensions::khr::BufferDeviceAddress, -) -> vk::AccelerationStructureGeometryKHRBuilder<'a> { - match geometry { - crate::AccelerationStructureGeometry::Instances { buffer } => { - let instances = vk::AccelerationStructureGeometryInstancesDataKHR::builder().data( - vk::DeviceOrHostAddressConstKHR { - device_address: buffer_device_address.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(buffer.raw), - ), - }, - ); - - vk::AccelerationStructureGeometryKHR::builder() - .geometry_type(vk::GeometryTypeKHR::INSTANCES) - .geometry(vk::AccelerationStructureGeometryDataKHR { - instances: *instances, - }) - .flags(vk::GeometryFlagsKHR::empty()) - } - &crate::AccelerationStructureGeometry::Triangles { - vertex_buffer, - vertex_format, - max_vertex, - vertex_stride, - ref indices, - } => { - let mut triangles_data = vk::AccelerationStructureGeometryTrianglesDataKHR::builder() - .vertex_data(vk::DeviceOrHostAddressConstKHR { - device_address: buffer_device_address.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(vertex_buffer.raw), - ), - }) - .vertex_format(conv::map_vertex_format(vertex_format)) - .vertex_stride(vertex_stride) - .max_vertex(max_vertex); - - if let Some(indices) = indices { - triangles_data = triangles_data - .index_type(conv::map_index_format(indices.format)) - .index_data(vk::DeviceOrHostAddressConstKHR { - device_address: buffer_device_address.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(indices.buffer.raw), - ), - }) - } - - let triangles_data = triangles_data.build(); - - vk::AccelerationStructureGeometryKHR::builder() - .geometry_type(vk::GeometryTypeKHR::TRIANGLES) - .geometry(vk::AccelerationStructureGeometryDataKHR { - triangles: triangles_data, - }) - .flags(vk::GeometryFlagsKHR::empty()) - } - } -} diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8718d79794..ab6e9a944d 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -4040,6 +4040,8 @@ pub enum BindingType { /// Dimension of the texture view that is going to be sampled. view_dimension: TextureViewDimension, }, + + AccelerationStructure, } impl BindingType { From 2cc43852d4ed64a3412c55a7c5260a14381176da Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Sep 2022 11:59:05 +0200 Subject: [PATCH 05/11] Major clean up, allow for acceleration structure updates --- wgpu-hal/examples/ray-traced-triangle/main.rs | 219 +++++++++++++----- wgpu-hal/src/empty.rs | 4 +- wgpu-hal/src/lib.rs | 19 +- wgpu-hal/src/vulkan/adapter.rs | 39 ++-- wgpu-hal/src/vulkan/command.rs | 62 +++-- wgpu-hal/src/vulkan/conv.rs | 34 ++- wgpu-hal/src/vulkan/device.rs | 64 ++--- wgpu-hal/src/vulkan/mod.rs | 8 +- wgpu-types/src/lib.rs | 15 ++ 9 files changed, 321 insertions(+), 143 deletions(-) diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 93f62eac04..a4ae25e41c 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -16,6 +16,29 @@ use std::{ const COMMAND_BUFFER_PER_CONTEXT: usize = 100; const DESIRED_FRAMES: u32 = 3; +fn pack_24_8(low_24: u32, high_8: u8) -> u32 { + (low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24) +} + +#[derive(Debug)] +#[repr(C)] +struct Instance { + transform: [f32; 12], + instance_custom_index_and_mask: u32, + instance_shader_binding_table_record_offset_and_flags: u32, + acceleration_structure_reference: u64, +} + +fn transpose_matrix_for_acceleration_structure_instance(matrix: Mat4) -> [f32; 12] { + let row_0 = matrix.row(0); + let row_1 = matrix.row(1); + let row_2 = matrix.row(2); + [ + row_0.x, row_0.y, row_0.z, row_0.w, row_1.x, row_1.y, row_1.z, row_1.w, row_2.x, row_2.y, + row_2.z, row_2.w, + ] +} + struct ExecutionContext { encoder: A::CommandEncoder, fence: A::Fence, @@ -51,26 +74,20 @@ struct Example { start: Instant, pipeline: A::ComputePipeline, bind_group: A::BindGroup, - //local_group: A::BindGroup, - //global_group_layout: A::BindGroupLayout, - //local_group_layout: A::BindGroupLayout, + bgl: A::BindGroupLayout, + shader_module: A::ShaderModule, + texture_view: A::TextureView, + uniform_buffer: A::Buffer, pipeline_layout: A::PipelineLayout, - /*shader: A::ShaderModule, - pipeline: A::RenderPipeline, - bunnies: Vec, - local_buffer: A::Buffer, - local_alignment: u32, - global_buffer: A::Buffer, - sampler: A::Sampler, - */ + vertices_buffer: A::Buffer, + indices_buffer: A::Buffer, texture: A::Texture, - /*texture_view: A::TextureView, - contexts: Vec>, - context_index: usize, - extent: [u32; 2], - start: Instant, - buffers: Vec, - acceleration_structures: Vec,*/ + instances: [Instance; 1], + instances_buffer: A::Buffer, + blas: A::AccelerationStructure, + tlas: A::AccelerationStructure, + scratch_buffer: A::Buffer, + time: f32, } impl Example { @@ -86,23 +103,21 @@ impl Example { let instance = unsafe { A::Instance::init(&instance_desc)? }; let mut surface = unsafe { instance.create_surface(window).unwrap() }; - let (adapter, _capabilities) = unsafe { + let (adapter, features) = unsafe { let mut adapters = instance.enumerate_adapters(); if adapters.is_empty() { return Err(hal::InstanceError); } let exposed = adapters.swap_remove(0); - (exposed.adapter, exposed.capabilities) + dbg!(exposed.features); + (exposed.adapter, exposed.features) }; let surface_caps = unsafe { adapter.surface_capabilities(&surface) }.ok_or(hal::InstanceError)?; log::info!("Surface caps: {:#?}", surface_caps); - let hal::OpenDevice { device, mut queue } = unsafe { - adapter - .open(wgt::Features::empty(), &wgt::Limits::default()) - .unwrap() - }; + let hal::OpenDevice { device, mut queue } = + unsafe { adapter.open(features, &wgt::Limits::default()).unwrap() }; let window_size: (u32, u32) = window.inner_size().into(); let surface_config = hal::SurfaceConfiguration { @@ -196,7 +211,7 @@ impl Example { words } - let shader = unsafe { + let shader_module = unsafe { device .create_shader_module( &hal::ShaderModuleDescriptor { @@ -225,7 +240,7 @@ impl Example { label: Some("pipeline"), layout: &pipeline_layout, stage: hal::ProgrammableStage { - module: &shader, + module: &shader_module, entry_point: "main", }, }) @@ -248,7 +263,6 @@ impl Example { label: Some("vertices buffer"), size: vertices_size_in_bytes as u64, usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }) @@ -274,7 +288,6 @@ impl Example { label: Some("indices buffer"), size: indices_size_in_bytes as u64, usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS | hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }) @@ -303,17 +316,20 @@ impl Example { }, hal::AccelerationStructureFormat::BottomLevel, hal::AccelerationStructureBuildMode::Build, - (), + hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, 1, ) }; + let tlas_flags = hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE + | hal::AccelerationStructureBuildFlags::ALLOW_UPDATE; + let tlas_sizes = unsafe { device.get_acceleration_structure_build_sizes( &hal::AccelerationStructureGeometryInfo::Instances, hal::AccelerationStructureFormat::TopLevel, hal::AccelerationStructureBuildMode::Build, - (), + tlas_flags, 1, ) }; @@ -441,36 +457,12 @@ impl Example { size: blas_sizes .build_scratch_size .max(tlas_sizes.build_scratch_size), - usage: hal::BufferUses::BUFFER_DEVICE_ADDRESS - | hal::BufferUses::STORAGE_READ_WRITE, + usage: hal::BufferUses::ACCELERATION_STRUCTURE_SCRATCH, memory_flags: hal::MemoryFlags::empty(), }) .unwrap() }; - fn pack_24_8(low_24: u32, high_8: u8) -> u32 { - (low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24) - } - - #[derive(Debug)] - #[repr(C)] - struct Instance { - transform: [f32; 12], - instance_custom_index_and_mask: u32, - instance_shader_binding_table_record_offset_and_flags: u32, - acceleration_structure_reference: u64, - } - - fn transpose_matrix_for_acceleration_structure_instance(matrix: Mat4) -> [f32; 12] { - let row_0 = matrix.row(0); - let row_1 = matrix.row(1); - let row_2 = matrix.row(2); - [ - row_0.x, row_0.y, row_0.z, row_0.w, row_1.x, row_1.y, row_1.z, row_1.w, row_2.x, - row_2.y, row_2.z, row_2.w, - ] - } - let instances = [ Instance { transform: transform_matrix, @@ -480,7 +472,7 @@ impl Example { device.get_acceleration_structure_device_address(&blas) }, }, - Instance { + /*Instance { transform: transpose_matrix_for_acceleration_structure_instance( Mat4::from_rotation_y(1.0), ), @@ -499,7 +491,7 @@ impl Example { acceleration_structure_reference: unsafe { device.get_acceleration_structure_device_address(&blas) }, - }, + },*/ ]; let instances_buffer_size = instances.len() * std::mem::size_of::(); @@ -510,7 +502,6 @@ impl Example { label: Some("instances_buffer"), size: instances_buffer_size as u64, usage: hal::BufferUses::MAP_WRITE - | hal::BufferUses::BUFFER_DEVICE_ADDRESS | hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, memory_flags: hal::MemoryFlags::TRANSIENT | hal::MemoryFlags::PREFER_COHERENT, }) @@ -552,7 +543,7 @@ impl Example { }, hal::AccelerationStructureFormat::BottomLevel, hal::AccelerationStructureBuildMode::Build, - (), + hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, indices.len() as u32 / 3, 0, &blas, @@ -572,7 +563,7 @@ impl Example { }, hal::AccelerationStructureFormat::TopLevel, hal::AccelerationStructureBuildMode::Build, - (), + tlas_flags, instances.len() as u32, 0, &tlas, @@ -622,6 +613,18 @@ impl Example { pipeline_layout, bind_group, texture, + instances, + instances_buffer, + blas, + tlas, + scratch_buffer, + time: 0.0, + indices_buffer, + vertices_buffer, + uniform_buffer, + texture_view, + bgl, + shader_module, }) } @@ -637,8 +640,63 @@ impl Example { range: wgt::ImageSubresourceRange::default(), usage: hal::TextureUses::UNINITIALIZED..hal::TextureUses::COPY_DST, }; + + let instances_buffer_size = self.instances.len() * std::mem::size_of::(); + + let tlas_flags = hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE + | hal::AccelerationStructureBuildFlags::ALLOW_UPDATE; + + self.time += 1.0 / 60.0; + + self.instances[0] = Instance { + transform: transpose_matrix_for_acceleration_structure_instance(Mat4::from_rotation_y( + self.time, + )), + instance_custom_index_and_mask: pack_24_8(0, 0xff), + instance_shader_binding_table_record_offset_and_flags: pack_24_8(0, 0), + acceleration_structure_reference: unsafe { + self.device + .get_acceleration_structure_device_address(&self.blas) + }, + }; + + unsafe { + let mapping = self + .device + .map_buffer(&self.instances_buffer, 0..instances_buffer_size as u64) + .unwrap(); + ptr::copy_nonoverlapping( + self.instances.as_ptr() as *const u8, + mapping.ptr.as_ptr(), + instances_buffer_size, + ); + self.device.unmap_buffer(&self.instances_buffer).unwrap(); + assert!(mapping.is_coherent); + } + unsafe { ctx.encoder.begin_encoding(Some("frame")).unwrap(); + + ctx.encoder.build_acceleration_structures( + &hal::AccelerationStructureGeometry::Instances { + buffer: &self.instances_buffer, + }, + hal::AccelerationStructureFormat::TopLevel, + hal::AccelerationStructureBuildMode::Build, + tlas_flags, + self.instances.len() as u32, + 0, + &self.tlas, + &self.scratch_buffer, + ); + + let as_barrier = hal::BufferBarrier { + buffer: &self.scratch_buffer, + usage: hal::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT + ..hal::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + }; + ctx.encoder.transition_buffers(iter::once(as_barrier)); + ctx.encoder.transition_textures(iter::once(target_barrier0)); } @@ -752,6 +810,43 @@ impl Example { next.fence_value = old_fence_value + 1; } } + + fn exit(mut self) { + unsafe { + { + let ctx = &mut self.contexts[self.context_index]; + self.queue + .submit(&[], Some((&mut ctx.fence, ctx.fence_value))) + .unwrap(); + } + + for mut ctx in self.contexts { + ctx.wait_and_clear(&self.device); + self.device.destroy_command_encoder(ctx.encoder); + self.device.destroy_fence(ctx.fence); + } + + self.device.destroy_bind_group(self.bind_group); + self.device.destroy_buffer(self.scratch_buffer); + self.device.destroy_buffer(self.instances_buffer); + self.device.destroy_buffer(self.indices_buffer); + self.device.destroy_buffer(self.vertices_buffer); + self.device.destroy_buffer(self.uniform_buffer); + self.device.destroy_acceleration_structure(self.tlas); + self.device.destroy_acceleration_structure(self.blas); + self.device.destroy_texture_view(self.texture_view); + self.device.destroy_texture(self.texture); + self.device.destroy_compute_pipeline(self.pipeline); + self.device.destroy_pipeline_layout(self.pipeline_layout); + self.device.destroy_bind_group_layout(self.bgl); + self.device.destroy_shader_module(self.shader_module); + + self.surface.unconfigure(&self.device); + self.device.exit(self.queue); + self.instance.destroy_surface(self.surface); + drop(self.adapter); + } + } } #[cfg(all(feature = "metal"))] @@ -821,7 +916,7 @@ fn main() { ex.render(); } winit::event::Event::LoopDestroyed => { - //example.take().unwrap().exit(); + example.take().unwrap().exit(); } _ => {} } diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 5d5fa43d22..6448157a18 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -130,7 +130,7 @@ impl crate::Device for Context { geometry_info: &crate::AccelerationStructureGeometryInfo, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, ) -> crate::AccelerationStructureBuildSizes { Default::default() @@ -421,7 +421,7 @@ impl crate::CommandEncoder for Encoder { geometry: &crate::AccelerationStructureGeometry, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, primitive_offset: u32, destination_acceleration_structure: &Resource, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 44d7860e10..a0c4597254 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -249,7 +249,7 @@ pub trait Device: Send + Sync { geometry_info: &AccelerationStructureGeometryInfo, format: AccelerationStructureFormat, mode: AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, ) -> AccelerationStructureBuildSizes; @@ -553,7 +553,7 @@ pub trait CommandEncoder: Send + Sync { geometry: &AccelerationStructureGeometry, format: AccelerationStructureFormat, mode: AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, primitive_offset: u32, destination_acceleration_structure: &A::AccelerationStructure, @@ -695,7 +695,7 @@ bitflags::bitflags! { const STORAGE_READ_WRITE = 1 << 8; /// The indirect or count buffer in a indirect draw or dispatch. const INDIRECT = 1 << 9; - const BUFFER_DEVICE_ADDRESS = 1 << 10; + const ACCELERATION_STRUCTURE_SCRATCH = 1 << 10; const BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 11; const TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 12; /// The combination of states that a buffer may be in _at the same time_. @@ -856,13 +856,13 @@ pub struct AccelerationStructureDescriptor<'a> { pub format: AccelerationStructureFormat, } -#[derive(Clone, Copy, Debug)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum AccelerationStructureFormat { TopLevel, BottomLevel, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum AccelerationStructureBuildMode { Build, Update, @@ -1190,6 +1190,15 @@ pub struct AccelerationStructureGeometryIndices<'a, A: Api> { pub buffer: &'a A::Buffer, } +bitflags!( + pub struct AccelerationStructureBuildFlags: u32 { + const PREFER_FAST_TRACE = 1 << 0; + const PREFER_FAST_BUILD = 1 << 1; + const ALLOW_UPDATE = 1 << 2; + const LOW_MEMORY = 1 << 3; + } +); + #[derive(Clone, Debug)] pub struct TextureCopyBase { pub mip_level: u32, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index c5f75864a9..025eb4cb4b 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -535,6 +535,14 @@ impl PhysicalDeviceFeatures { ), ); + features.set( + F::RAY_TRACING, + caps.supports_extension(vk::KhrDeferredHostOperationsFn::name()) + && caps.supports_extension(vk::KhrAccelerationStructureFn::name()) + && caps.supports_extension(vk::KhrBufferDeviceAddressFn::name()) + && caps.supports_extension(vk::KhrRayQueryFn::name()), + ); + (features, dl_flags) } @@ -623,7 +631,7 @@ impl PhysicalDeviceCapabilities { extensions.push(vk::KhrDrawIndirectCountFn::name()); } - if true { + if requested_features.contains(wgt::Features::RAY_TRACING) { extensions.push(vk::KhrDeferredHostOperationsFn::name()); extensions.push(vk::KhrAccelerationStructureFn::name()); extensions.push(vk::KhrBufferDeviceAddressFn::name()); @@ -1165,24 +1173,22 @@ impl super::Adapter { } else { None }; - let acceleration_structure_fn = - if enabled_extensions.contains(&khr::AccelerationStructure::name()) { - Some(khr::AccelerationStructure::new( + let ray_tracing_fns = if enabled_extensions.contains(&khr::AccelerationStructure::name()) + && enabled_extensions.contains(&khr::BufferDeviceAddress::name()) + { + Some(super::RayTracingDeviceExtensionFunctions { + acceleration_structure: khr::AccelerationStructure::new( &self.instance.raw, &raw_device, - )) - } else { - None - }; - let buffer_device_address_fn = - if enabled_extensions.contains(&khr::BufferDeviceAddress::name()) { - Some(khr::BufferDeviceAddress::new( + ), + buffer_device_address: khr::BufferDeviceAddress::new( &self.instance.raw, &raw_device, - )) - } else { - None - }; + ), + }) + } else { + None + }; let naga_options = { use naga::back::spv; @@ -1275,8 +1281,7 @@ impl super::Adapter { extension_fns: super::DeviceExtensionFunctions { draw_indirect_count: indirect_count_fn, timeline_semaphore: timeline_semaphore_fn, - acceleration_structure: acceleration_structure_fn, - buffer_device_address: buffer_device_address_fn, + ray_tracing: ray_tracing_fns, }, vendor_id: self.phd_capabilities.properties.vendor_id, timestamp_period: self.phd_capabilities.properties.limits.timestamp_period, diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index e3073b0643..a5b35f765e 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -346,29 +346,26 @@ impl crate::CommandEncoder for super::CommandEncoder { geometry: &crate::AccelerationStructureGeometry, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, primitive_offset: u32, destination_acceleration_structure: &super::AccelerationStructure, scratch_buffer: &super::Buffer, ) { - let extension = match self.device.extension_fns.acceleration_structure { - Some(ref extension) => extension, + let ray_tracing_functions = match self.device.extension_fns.ray_tracing { + Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; - let bda_extension = match self.device.extension_fns.buffer_device_address { - Some(ref extension) => extension, - None => panic!("Feature `BDA` not enabled"), - }; - let geometry = match geometry { crate::AccelerationStructureGeometry::Instances { buffer } => { let instances = vk::AccelerationStructureGeometryInstancesDataKHR::builder().data( vk::DeviceOrHostAddressConstKHR { - device_address: bda_extension.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(buffer.raw), - ), + device_address: ray_tracing_functions + .buffer_device_address + .get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(buffer.raw), + ), }, ); @@ -389,9 +386,12 @@ impl crate::CommandEncoder for super::CommandEncoder { let mut triangles_data = vk::AccelerationStructureGeometryTrianglesDataKHR::builder() .vertex_data(vk::DeviceOrHostAddressConstKHR { - device_address: bda_extension.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(vertex_buffer.raw), - ), + device_address: ray_tracing_functions + .buffer_device_address + .get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(vertex_buffer.raw), + ), }) .vertex_format(conv::map_vertex_format(vertex_format)) .vertex_stride(vertex_stride) @@ -401,9 +401,12 @@ impl crate::CommandEncoder for super::CommandEncoder { triangles_data = triangles_data .index_type(conv::map_index_format(indices.format)) .index_data(vk::DeviceOrHostAddressConstKHR { - device_address: bda_extension.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(indices.buffer.raw), - ), + device_address: ray_tracing_functions + .buffer_device_address + .get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(indices.buffer.raw), + ), }) } @@ -425,24 +428,33 @@ impl crate::CommandEncoder for super::CommandEncoder { .primitive_offset(primitive_offset) .build(); - let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() .ty(conv::map_acceleration_structure_format(format)) .mode(conv::map_acceleration_structure_build_mode(mode)) - .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) + .flags(conv::map_acceleration_structure_flags(flags)) .geometries(geometries) .dst_acceleration_structure(destination_acceleration_structure.raw) .scratch_data(vk::DeviceOrHostAddressKHR { - device_address: bda_extension.get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(scratch_buffer.raw), - ), - }) - .build(); + device_address: ray_tracing_functions + .buffer_device_address + .get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(scratch_buffer.raw), + ), + }); + + if mode == crate::AccelerationStructureBuildMode::Update { + geometry_info.src_acceleration_structure = destination_acceleration_structure.raw; + } + + let geometry_info = geometry_info.build(); let range = &[range][..]; let range = &[range][..]; let geometry_info = &[geometry_info]; - extension.cmd_build_acceleration_structures(self.active, geometry_info, range); + ray_tracing_functions + .acceleration_structure + .cmd_build_acceleration_structures(self.active, geometry_info, range); } // render diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index e169b4ad29..7677a2ab56 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -491,14 +491,15 @@ pub fn map_buffer_usage(usage: crate::BufferUses) -> vk::BufferUsageFlags { if usage.contains(crate::BufferUses::INDIRECT) { flags |= vk::BufferUsageFlags::INDIRECT_BUFFER; } - if usage.contains(crate::BufferUses::BUFFER_DEVICE_ADDRESS) { - flags |= vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS; + if usage.contains(crate::BufferUses::ACCELERATION_STRUCTURE_SCRATCH) { + flags |= vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS; } if usage.intersects( crate::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT | crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, ) { - flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR; + flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS; } flags } @@ -554,7 +555,8 @@ pub fn map_buffer_usage_to_barrier( } if usage.intersects( crate::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT - | crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT, + | crate::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT + | crate::BufferUses::ACCELERATION_STRUCTURE_SCRATCH, ) { stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR; access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR @@ -865,3 +867,27 @@ pub fn map_acceleration_structure_build_mode( } } } + +pub fn map_acceleration_structure_flags( + flags: crate::AccelerationStructureBuildFlags, +) -> vk::BuildAccelerationStructureFlagsKHR { + let mut vk_flags = vk::BuildAccelerationStructureFlagsKHR::empty(); + + if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_TRACE) { + vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE; + } + + if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_BUILD) { + vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_BUILD; + } + + if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_UPDATE) { + vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_UPDATE; + } + + if flags.contains(crate::AccelerationStructureBuildFlags::LOW_MEMORY) { + vk_flags |= vk::BuildAccelerationStructureFlagsKHR::LOW_MEMORY; + } + + vk_flags +} diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 47c20726fc..42b2257c24 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -821,11 +821,11 @@ impl crate::Device for super::Device { geometry_info: &crate::AccelerationStructureGeometryInfo, format: crate::AccelerationStructureFormat, mode: crate::AccelerationStructureBuildMode, - flags: (), + flags: crate::AccelerationStructureBuildFlags, primitive_count: u32, ) -> crate::AccelerationStructureBuildSizes { - let extension = match self.shared.extension_fns.acceleration_structure { - Some(ref extension) => extension, + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; @@ -869,14 +869,16 @@ impl crate::Device for super::Device { let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() .ty(conv::map_acceleration_structure_format(format)) .mode(conv::map_acceleration_structure_build_mode(mode)) - .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) + .flags(conv::map_acceleration_structure_flags(flags)) .geometries(geometries); - let raw = extension.get_acceleration_structure_build_sizes( - vk::AccelerationStructureBuildTypeKHR::DEVICE, - &geometry_info, - &[primitive_count], - ); + let raw = ray_tracing_functions + .acceleration_structure + .get_acceleration_structure_build_sizes( + vk::AccelerationStructureBuildTypeKHR::DEVICE, + &geometry_info, + &[primitive_count], + ); crate::AccelerationStructureBuildSizes { acceleration_structure_size: raw.acceleration_structure_size, @@ -889,23 +891,25 @@ impl crate::Device for super::Device { &self, acceleration_structure: &super::AccelerationStructure, ) -> wgt::BufferAddress { - let extension = match self.shared.extension_fns.acceleration_structure { - Some(ref extension) => extension, + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; - extension.get_acceleration_structure_device_address( - &vk::AccelerationStructureDeviceAddressInfoKHR::builder() - .acceleration_structure(acceleration_structure.raw), - ) + ray_tracing_functions + .acceleration_structure + .get_acceleration_structure_device_address( + &vk::AccelerationStructureDeviceAddressInfoKHR::builder() + .acceleration_structure(acceleration_structure.raw), + ) } unsafe fn create_acceleration_structure( &self, desc: &crate::AccelerationStructureDescriptor, ) -> Result { - let extension = match self.shared.extension_fns.acceleration_structure { - Some(ref extension) => extension, + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; @@ -942,7 +946,9 @@ impl crate::Device for super::Device { .size(desc.size) .ty(conv::map_acceleration_structure_format(desc.format)); - let raw_acceleration_structure = extension.create_acceleration_structure(&vk_info, None)?; + let raw_acceleration_structure = ray_tracing_functions + .acceleration_structure + .create_acceleration_structure(&vk_info, None)?; if let Some(label) = desc.label { self.shared.set_object_name( @@ -970,12 +976,14 @@ impl crate::Device for super::Device { &self, acceleration_structure: super::AccelerationStructure, ) { - let extension = match self.shared.extension_fns.acceleration_structure { - Some(ref extension) => extension, + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; - extension.destroy_acceleration_structure(acceleration_structure.raw, None); + ray_tracing_functions + .acceleration_structure + .destroy_acceleration_structure(acceleration_structure.raw, None); self.shared .raw .destroy_buffer(acceleration_structure.buffer, None); @@ -1583,11 +1591,15 @@ impl crate::Device for super::Device { .map(|acceleration_structure| acceleration_structure.raw), ); - acceleration_structure_infos.push( - // todo: this dereference to build the struct is a hack to get around lifetime issues. - *vk::WriteDescriptorSetAccelerationStructureKHR::builder() - .acceleration_structures(&raw_acceleration_structures[raw_start..]), - ); + let acceleration_structure_info = + vk::WriteDescriptorSetAccelerationStructureKHR::builder() + .acceleration_structures(&raw_acceleration_structures[raw_start..]); + + // todo: Dereference the struct to get around lifetime issues. Safe as long as we never resize + // `raw_acceleration_structures`. + let acceleration_structure_info: vk::WriteDescriptorSetAccelerationStructureKHR = *acceleration_structure_info; + + acceleration_structure_infos.push(acceleration_structure_info); extra_descriptor_count += 1; diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 5732fbfb60..c552a6179b 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -148,8 +148,12 @@ enum ExtensionFn { struct DeviceExtensionFunctions { draw_indirect_count: Option, timeline_semaphore: Option>, - acceleration_structure: Option, - buffer_device_address: Option, + ray_tracing: Option, +} + +struct RayTracingDeviceExtensionFunctions { + acceleration_structure: khr::AccelerationStructure, + buffer_device_address: khr::BufferDeviceAddress, } /// Set of internal capabilities, which don't show up in the exposed diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ab6e9a944d..b33702e6ec 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -638,6 +638,14 @@ bitflags::bitflags! { /// - DX12 /// - Metal (Intel and AMD GPUs) const WRITE_TIMESTAMP_INSIDE_PASSES = 1 << 41; + + /// Allows for the creation of ray-tracing acceleration structures and ray queries within shaders. + /// + /// Supported platforms: + /// - Vulkan + /// + /// This is a native-only feature. + const RAY_TRACING = 1 << 42; } } @@ -4041,6 +4049,13 @@ pub enum BindingType { view_dimension: TextureViewDimension, }, + /// A ray-tracing acceleration structure binding. + /// + /// Example GLSL syntax: + /// ```cpp,ignore + /// layout(binding = 0) + /// uniform accelerationStructureEXT as; + /// ``` AccelerationStructure, } From cd7c80755b259ea201166bf7915b247192071c5a Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Sep 2022 12:09:55 +0200 Subject: [PATCH 06/11] Fix trait implementaiton on gles --- wgpu-hal/src/empty.rs | 46 ++++++++++++++++++------------------ wgpu-hal/src/gles/command.rs | 14 +++++++++++ wgpu-hal/src/gles/device.rs | 31 +++++++++++++++++++----- wgpu-hal/src/lib.rs | 4 ++-- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 6448157a18..54e791b680 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -119,29 +119,6 @@ impl crate::Device for Context { unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { Ok(Resource) } - unsafe fn create_acceleration_structure( - &self, - desc: &crate::AccelerationStructureDescriptor, - ) -> DeviceResult { - Ok(Resource) - } - unsafe fn get_acceleration_structure_build_sizes( - &self, - geometry_info: &crate::AccelerationStructureGeometryInfo, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, - primitive_count: u32, - ) -> crate::AccelerationStructureBuildSizes { - Default::default() - } - unsafe fn get_acceleration_structure_device_address( - &self, - _acceleration_structure: &Resource, - ) -> wgt::BufferAddress { - Default::default() - } - unsafe fn destroy_acceleration_structure(&self, buffer: Resource) {} unsafe fn destroy_buffer(&self, buffer: Resource) {} unsafe fn map_buffer( &self, @@ -253,6 +230,29 @@ impl crate::Device for Context { false } unsafe fn stop_capture(&self) {} + unsafe fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn get_acceleration_structure_build_sizes( + &self, + geometry_info: &crate::AccelerationStructureGeometryInfo, + format: crate::AccelerationStructureFormat, + mode: crate::AccelerationStructureBuildMode, + flags: crate::AccelerationStructureBuildFlags, + primitive_count: u32, + ) -> crate::AccelerationStructureBuildSizes { + Default::default() + } + unsafe fn get_acceleration_structure_device_address( + &self, + _acceleration_structure: &Resource, + ) -> wgt::BufferAddress { + Default::default() + } + unsafe fn destroy_acceleration_structure(&self, _acceleration_structure: Resource) {} } impl crate::CommandEncoder for Encoder { diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index beaf600e6e..a7ab8bef04 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1000,4 +1000,18 @@ impl crate::CommandEncoder for super::CommandEncoder { indirect_offset: offset, }); } + + unsafe fn build_acceleration_structures( + &mut self, + _geometry: &crate::AccelerationStructureGeometry, + _format: crate::AccelerationStructureFormat, + _mode: crate::AccelerationStructureBuildMode, + _flags: crate::AccelerationStructureBuildFlags, + _primitive_count: u32, + _primitive_offset: u32, + _destination_acceleration_structure: &(), + _scratch_buffer: &super::Buffer, + ) { + unimplemented!() + } } diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index b8fd7d3842..c765d95cca 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -455,12 +455,6 @@ impl crate::Device for super::Device { data, }) } - unsafe fn create_acceleration_structure( - &self, - _desc: &crate::AccelerationStructureDescriptor, - ) -> Result<(), crate::DeviceError> { - unimplemented!() - } unsafe fn destroy_buffer(&self, buffer: super::Buffer) { if let Some(raw) = buffer.raw { let gl = &self.shared.context.lock(); @@ -867,6 +861,7 @@ impl crate::Device for super::Device { ty: wgt::BufferBindingType::Storage { .. }, .. } => &mut num_storage_buffers, + wgt::BindingType::AccelerationStructure => unimplemented!(), }; binding_to_slot[entry.binding as usize] = *counter; @@ -947,6 +942,7 @@ impl crate::Device for super::Device { format: format_desc.internal, }) } + wgt::BindingType::AccelerationStructure => unimplemented!(), }; contents.push(binding); } @@ -1167,6 +1163,29 @@ impl crate::Device for super::Device { self.render_doc .end_frame_capture(ptr::null_mut(), ptr::null_mut()) } + unsafe fn create_acceleration_structure( + &self, + _desc: &crate::AccelerationStructureDescriptor, + ) -> Result<(), crate::DeviceError> { + unimplemented!() + } + unsafe fn get_acceleration_structure_build_sizes( + &self, + _geometry_info: &crate::AccelerationStructureGeometryInfo, + _format: crate::AccelerationStructureFormat, + _mode: crate::AccelerationStructureBuildMode, + _flags: crate::AccelerationStructureBuildFlags, + _primitive_count: u32, + ) -> crate::AccelerationStructureBuildSizes { + unimplemented!() + } + unsafe fn get_acceleration_structure_device_address( + &self, + _acceleration_structure: &(), + ) -> wgt::BufferAddress { + unimplemented!() + } + unsafe fn destroy_acceleration_structure(&self, _acceleration_structure: ()) {} } // SAFE: WASM doesn't have threads diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index a0c4597254..ea953cefb2 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -249,7 +249,7 @@ pub trait Device: Send + Sync { geometry_info: &AccelerationStructureGeometryInfo, format: AccelerationStructureFormat, mode: AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, + flags: AccelerationStructureBuildFlags, primitive_count: u32, ) -> AccelerationStructureBuildSizes; @@ -553,7 +553,7 @@ pub trait CommandEncoder: Send + Sync { geometry: &AccelerationStructureGeometry, format: AccelerationStructureFormat, mode: AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, + flags: AccelerationStructureBuildFlags, primitive_count: u32, primitive_offset: u32, destination_acceleration_structure: &A::AccelerationStructure, From 4ef32a4dce94151fbe6a2aab27b46e82f123aac3 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Sep 2022 19:47:39 +0200 Subject: [PATCH 07/11] Put larger function call param lists into descriptors for easier dummy implementation, run cargo clippy, fix wgpu/wgpu build --- wgpu-core/src/binding_model.rs | 1 + wgpu-core/src/device/mod.rs | 2 + wgpu-hal/examples/ray-traced-triangle/main.rs | 95 ++++++----- wgpu-hal/src/empty.rs | 15 +- wgpu-hal/src/gles/command.rs | 9 +- wgpu-hal/src/gles/device.rs | 6 +- wgpu-hal/src/lib.rs | 159 +++++++++--------- wgpu-hal/src/vulkan/command.rs | 33 ++-- wgpu-hal/src/vulkan/device.rs | 18 +- 9 files changed, 161 insertions(+), 177 deletions(-) diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 71f95a723d..7ef9acac2a 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -328,6 +328,7 @@ impl BindingTypeMaxCountValidator { wgt::BindingType::StorageTexture { .. } => { self.storage_textures.add(binding.visibility, count); } + wgt::BindingType::AccelerationStructure => todo!(), } } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index a5c5cbe51c..68d8b8fa59 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1504,6 +1504,7 @@ impl Device { }, ) } + Bt::AccelerationStructure => todo!(), }; // Validate the count parameter @@ -1977,6 +1978,7 @@ impl Device { buffers: &hal_buffers, samplers: &hal_samplers, textures: &hal_textures, + acceleration_structures: &[], }; let raw = unsafe { self.raw diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index a4ae25e41c..fa749de870 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -309,15 +309,17 @@ impl Example { let blas_sizes = unsafe { device.get_acceleration_structure_build_sizes( - &hal::AccelerationStructureGeometryInfo::Triangles { - vertex_format: wgt::VertexFormat::Float32x3, - max_vertex: 3, - index_format: Some(wgt::IndexFormat::Uint32), + &hal::GetAccelerationStructureBuildSizesDescriptor { + geometry_info: hal::AccelerationStructureGeometryInfo::Triangles { + vertex_format: wgt::VertexFormat::Float32x3, + max_vertex: 3, + index_format: Some(wgt::IndexFormat::Uint32), + }, + format: hal::AccelerationStructureFormat::BottomLevel, + mode: hal::AccelerationStructureBuildMode::Build, + flags: hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, + primitive_count: 1, }, - hal::AccelerationStructureFormat::BottomLevel, - hal::AccelerationStructureBuildMode::Build, - hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, - 1, ) }; @@ -326,11 +328,13 @@ impl Example { let tlas_sizes = unsafe { device.get_acceleration_structure_build_sizes( - &hal::AccelerationStructureGeometryInfo::Instances, - hal::AccelerationStructureFormat::TopLevel, - hal::AccelerationStructureBuildMode::Build, - tlas_flags, - 1, + &hal::GetAccelerationStructureBuildSizesDescriptor { + geometry_info: hal::AccelerationStructureGeometryInfo::Instances, + format: hal::AccelerationStructureFormat::TopLevel, + mode: hal::AccelerationStructureBuildMode::Build, + flags: tlas_flags, + primitive_count: 1, + }, ) }; @@ -530,8 +534,8 @@ impl Example { unsafe { cmd_encoder.begin_encoding(Some("init")).unwrap() }; unsafe { - cmd_encoder.build_acceleration_structures( - &hal::AccelerationStructureGeometry::Triangles { + cmd_encoder.build_acceleration_structures(&hal::BuildAccelerationStructureDescriptor { + geometry: &hal::AccelerationStructureGeometry::Triangles { vertex_buffer: &vertices_buffer, vertex_format: wgt::VertexFormat::Float32x3, max_vertex: vertices.len() as u32, @@ -541,14 +545,14 @@ impl Example { format: wgt::IndexFormat::Uint32, }), }, - hal::AccelerationStructureFormat::BottomLevel, - hal::AccelerationStructureBuildMode::Build, - hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, - indices.len() as u32 / 3, - 0, - &blas, - &scratch_buffer, - ); + format: hal::AccelerationStructureFormat::BottomLevel, + mode: hal::AccelerationStructureBuildMode::Build, + flags: hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE, + primitive_count: indices.len() as u32 / 3, + primitive_offset: 0, + destination_acceleration_structure: &blas, + scratch_buffer: &scratch_buffer, + }); let as_barrier = hal::BufferBarrier { buffer: &scratch_buffer, @@ -557,18 +561,18 @@ impl Example { }; cmd_encoder.transition_buffers(iter::once(as_barrier)); - cmd_encoder.build_acceleration_structures( - &hal::AccelerationStructureGeometry::Instances { + cmd_encoder.build_acceleration_structures(&hal::BuildAccelerationStructureDescriptor { + geometry: &hal::AccelerationStructureGeometry::Instances { buffer: &instances_buffer, }, - hal::AccelerationStructureFormat::TopLevel, - hal::AccelerationStructureBuildMode::Build, - tlas_flags, - instances.len() as u32, - 0, - &tlas, - &scratch_buffer, - ); + format: hal::AccelerationStructureFormat::TopLevel, + mode: hal::AccelerationStructureBuildMode::Build, + flags: tlas_flags, + primitive_count: instances.len() as u32, + primitive_offset: 0, + destination_acceleration_structure: &tlas, + scratch_buffer: &scratch_buffer, + }); let texture_barrier = hal::TextureBarrier { texture: &texture, @@ -677,18 +681,19 @@ impl Example { unsafe { ctx.encoder.begin_encoding(Some("frame")).unwrap(); - ctx.encoder.build_acceleration_structures( - &hal::AccelerationStructureGeometry::Instances { - buffer: &self.instances_buffer, - }, - hal::AccelerationStructureFormat::TopLevel, - hal::AccelerationStructureBuildMode::Build, - tlas_flags, - self.instances.len() as u32, - 0, - &self.tlas, - &self.scratch_buffer, - ); + ctx.encoder + .build_acceleration_structures(&hal::BuildAccelerationStructureDescriptor { + geometry: &hal::AccelerationStructureGeometry::Instances { + buffer: &self.instances_buffer, + }, + format: hal::AccelerationStructureFormat::TopLevel, + mode: hal::AccelerationStructureBuildMode::Update, + flags: tlas_flags, + primitive_count: self.instances.len() as u32, + primitive_offset: 0, + destination_acceleration_structure: &self.tlas, + scratch_buffer: &self.scratch_buffer, + }); let as_barrier = hal::BufferBarrier { buffer: &self.scratch_buffer, diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 54e791b680..aff9640a79 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -238,11 +238,7 @@ impl crate::Device for Context { } unsafe fn get_acceleration_structure_build_sizes( &self, - geometry_info: &crate::AccelerationStructureGeometryInfo, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, - primitive_count: u32, + _desc: &crate::GetAccelerationStructureBuildSizesDescriptor, ) -> crate::AccelerationStructureBuildSizes { Default::default() } @@ -418,14 +414,7 @@ impl crate::CommandEncoder for Encoder { unsafe fn build_acceleration_structures( &mut self, - geometry: &crate::AccelerationStructureGeometry, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, - primitive_count: u32, - primitive_offset: u32, - destination_acceleration_structure: &Resource, - scratch_buffer: &Resource, + _desc: &crate::BuildAccelerationStructureDescriptor, ) { } } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index a7ab8bef04..e61e70357b 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1003,14 +1003,7 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn build_acceleration_structures( &mut self, - _geometry: &crate::AccelerationStructureGeometry, - _format: crate::AccelerationStructureFormat, - _mode: crate::AccelerationStructureBuildMode, - _flags: crate::AccelerationStructureBuildFlags, - _primitive_count: u32, - _primitive_offset: u32, - _destination_acceleration_structure: &(), - _scratch_buffer: &super::Buffer, + _desc: &crate::BuildAccelerationStructureDescriptor, ) { unimplemented!() } diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index c765d95cca..1858825463 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1171,11 +1171,7 @@ impl crate::Device for super::Device { } unsafe fn get_acceleration_structure_build_sizes( &self, - _geometry_info: &crate::AccelerationStructureGeometryInfo, - _format: crate::AccelerationStructureFormat, - _mode: crate::AccelerationStructureBuildMode, - _flags: crate::AccelerationStructureBuildFlags, - _primitive_count: u32, + _desc: &crate::GetAccelerationStructureBuildSizesDescriptor, ) -> crate::AccelerationStructureBuildSizes { unimplemented!() } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index ea953cefb2..019c6b4b9f 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -246,11 +246,7 @@ pub trait Device: Send + Sync { unsafe fn get_acceleration_structure_build_sizes( &self, - geometry_info: &AccelerationStructureGeometryInfo, - format: AccelerationStructureFormat, - mode: AccelerationStructureBuildMode, - flags: AccelerationStructureBuildFlags, - primitive_count: u32, + desc: &GetAccelerationStructureBuildSizesDescriptor, ) -> AccelerationStructureBuildSizes; unsafe fn get_acceleration_structure_device_address( @@ -550,14 +546,7 @@ pub trait CommandEncoder: Send + Sync { unsafe fn build_acceleration_structures( &mut self, - geometry: &AccelerationStructureGeometry, - format: AccelerationStructureFormat, - mode: AccelerationStructureBuildMode, - flags: AccelerationStructureBuildFlags, - primitive_count: u32, - primitive_offset: u32, - destination_acceleration_structure: &A::AccelerationStructure, - scratch_buffer: &A::Buffer, + desc: &BuildAccelerationStructureDescriptor, ); } @@ -849,32 +838,6 @@ pub struct BufferDescriptor<'a> { pub memory_flags: MemoryFlags, } -#[derive(Clone, Debug)] -pub struct AccelerationStructureDescriptor<'a> { - pub label: Label<'a>, - pub size: wgt::BufferAddress, - pub format: AccelerationStructureFormat, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum AccelerationStructureFormat { - TopLevel, - BottomLevel, -} - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum AccelerationStructureBuildMode { - Build, - Update, -} - -#[derive(Clone, Debug, Default)] -pub struct AccelerationStructureBuildSizes { - pub acceleration_structure_size: wgt::BufferAddress, - pub update_scratch_size: wgt::BufferAddress, - pub build_scratch_size: wgt::BufferAddress, -} - #[derive(Clone, Debug)] pub struct TextureDescriptor<'a> { pub label: Label<'a>, @@ -1163,42 +1126,6 @@ pub struct BufferCopy { pub size: wgt::BufferSize, } -pub enum AccelerationStructureGeometryInfo { - Triangles { - vertex_format: wgt::VertexFormat, - max_vertex: u32, - index_format: Option, - }, - Instances, -} - -pub enum AccelerationStructureGeometry<'a, A: Api> { - Triangles { - vertex_buffer: &'a A::Buffer, - vertex_format: wgt::VertexFormat, - max_vertex: u32, - vertex_stride: wgt::BufferAddress, - indices: Option>, - }, - Instances { - buffer: &'a A::Buffer, - }, -} - -pub struct AccelerationStructureGeometryIndices<'a, A: Api> { - pub format: wgt::IndexFormat, - pub buffer: &'a A::Buffer, -} - -bitflags!( - pub struct AccelerationStructureBuildFlags: u32 { - const PREFER_FAST_TRACE = 1 << 0; - const PREFER_FAST_BUILD = 1 << 1; - const ALLOW_UPDATE = 1 << 2; - const LOW_MEMORY = 1 << 3; - } -); - #[derive(Clone, Debug)] pub struct TextureCopyBase { pub mip_level: u32, @@ -1329,3 +1256,85 @@ fn test_default_limits() { let limits = wgt::Limits::default(); assert!(limits.max_bind_groups <= MAX_BIND_GROUPS as u32); } + +#[derive(Clone, Debug)] +pub struct AccelerationStructureDescriptor<'a> { + pub label: Label<'a>, + pub size: wgt::BufferAddress, + pub format: AccelerationStructureFormat, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum AccelerationStructureFormat { + TopLevel, + BottomLevel, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum AccelerationStructureBuildMode { + Build, + Update, +} + +#[derive(Clone, Debug, Default)] +pub struct AccelerationStructureBuildSizes { + pub acceleration_structure_size: wgt::BufferAddress, + pub update_scratch_size: wgt::BufferAddress, + pub build_scratch_size: wgt::BufferAddress, +} + +pub struct GetAccelerationStructureBuildSizesDescriptor { + pub geometry_info: AccelerationStructureGeometryInfo, + pub format: AccelerationStructureFormat, + pub mode: AccelerationStructureBuildMode, + pub flags: AccelerationStructureBuildFlags, + pub primitive_count: u32, +} + +#[derive(Clone, Copy)] +pub enum AccelerationStructureGeometryInfo { + Triangles { + vertex_format: wgt::VertexFormat, + max_vertex: u32, + index_format: Option, + }, + Instances, +} + +pub struct BuildAccelerationStructureDescriptor<'a, A: Api> { + pub geometry: &'a AccelerationStructureGeometry<'a, A>, + pub format: AccelerationStructureFormat, + pub mode: AccelerationStructureBuildMode, + pub flags: AccelerationStructureBuildFlags, + pub primitive_count: u32, + pub primitive_offset: u32, + pub destination_acceleration_structure: &'a A::AccelerationStructure, + pub scratch_buffer: &'a A::Buffer, +} + +pub enum AccelerationStructureGeometry<'a, A: Api> { + Triangles { + vertex_buffer: &'a A::Buffer, + vertex_format: wgt::VertexFormat, + max_vertex: u32, + vertex_stride: wgt::BufferAddress, + indices: Option>, + }, + Instances { + buffer: &'a A::Buffer, + }, +} + +pub struct AccelerationStructureGeometryIndices<'a, A: Api> { + pub format: wgt::IndexFormat, + pub buffer: &'a A::Buffer, +} + +bitflags!( + pub struct AccelerationStructureBuildFlags: u32 { + const PREFER_FAST_TRACE = 1 << 0; + const PREFER_FAST_BUILD = 1 << 1; + const ALLOW_UPDATE = 1 << 2; + const LOW_MEMORY = 1 << 3; + } +); diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index a5b35f765e..02768f3c74 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -343,21 +343,14 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn build_acceleration_structures( &mut self, - geometry: &crate::AccelerationStructureGeometry, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, - primitive_count: u32, - primitive_offset: u32, - destination_acceleration_structure: &super::AccelerationStructure, - scratch_buffer: &super::Buffer, + desc: &crate::BuildAccelerationStructureDescriptor, ) { let ray_tracing_functions = match self.device.extension_fns.ray_tracing { Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; - let geometry = match geometry { + let geometry = match *desc.geometry { crate::AccelerationStructureGeometry::Instances { buffer } => { let instances = vk::AccelerationStructureGeometryInstancesDataKHR::builder().data( vk::DeviceOrHostAddressConstKHR { @@ -376,7 +369,7 @@ impl crate::CommandEncoder for super::CommandEncoder { }) .flags(vk::GeometryFlagsKHR::empty()) } - &crate::AccelerationStructureGeometry::Triangles { + crate::AccelerationStructureGeometry::Triangles { vertex_buffer, vertex_format, max_vertex, @@ -397,7 +390,7 @@ impl crate::CommandEncoder for super::CommandEncoder { .vertex_stride(vertex_stride) .max_vertex(max_vertex); - if let Some(indices) = indices { + if let Some(ref indices) = *indices { triangles_data = triangles_data .index_type(conv::map_index_format(indices.format)) .index_data(vk::DeviceOrHostAddressConstKHR { @@ -424,26 +417,26 @@ impl crate::CommandEncoder for super::CommandEncoder { let geometries = &[*geometry]; let range = vk::AccelerationStructureBuildRangeInfoKHR::builder() - .primitive_count(primitive_count) - .primitive_offset(primitive_offset) + .primitive_count(desc.primitive_count) + .primitive_offset(desc.primitive_offset) .build(); let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() - .ty(conv::map_acceleration_structure_format(format)) - .mode(conv::map_acceleration_structure_build_mode(mode)) - .flags(conv::map_acceleration_structure_flags(flags)) + .ty(conv::map_acceleration_structure_format(desc.format)) + .mode(conv::map_acceleration_structure_build_mode(desc.mode)) + .flags(conv::map_acceleration_structure_flags(desc.flags)) .geometries(geometries) - .dst_acceleration_structure(destination_acceleration_structure.raw) + .dst_acceleration_structure(desc.destination_acceleration_structure.raw) .scratch_data(vk::DeviceOrHostAddressKHR { device_address: ray_tracing_functions .buffer_device_address .get_buffer_device_address( - &vk::BufferDeviceAddressInfo::builder().buffer(scratch_buffer.raw), + &vk::BufferDeviceAddressInfo::builder().buffer(desc.scratch_buffer.raw), ), }); - if mode == crate::AccelerationStructureBuildMode::Update { - geometry_info.src_acceleration_structure = destination_acceleration_structure.raw; + if desc.mode == crate::AccelerationStructureBuildMode::Update { + geometry_info.src_acceleration_structure = desc.destination_acceleration_structure.raw; } let geometry_info = geometry_info.build(); diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 42b2257c24..83c9e6ac58 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -818,18 +818,14 @@ impl crate::Device for super::Device { unsafe fn get_acceleration_structure_build_sizes( &self, - geometry_info: &crate::AccelerationStructureGeometryInfo, - format: crate::AccelerationStructureFormat, - mode: crate::AccelerationStructureBuildMode, - flags: crate::AccelerationStructureBuildFlags, - primitive_count: u32, + desc: &crate::GetAccelerationStructureBuildSizesDescriptor, ) -> crate::AccelerationStructureBuildSizes { let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { Some(ref functions) => functions, None => panic!("Feature `RAY_TRACING` not enabled"), }; - let geometry = match geometry_info { + let geometry = match desc.geometry_info { crate::AccelerationStructureGeometryInfo::Instances => { let instances_data = vk::AccelerationStructureGeometryInstancesDataKHR::builder(); @@ -840,7 +836,7 @@ impl crate::Device for super::Device { }) .flags(vk::GeometryFlagsKHR::empty()) } - &crate::AccelerationStructureGeometryInfo::Triangles { + crate::AccelerationStructureGeometryInfo::Triangles { vertex_format, max_vertex, index_format, @@ -867,9 +863,9 @@ impl crate::Device for super::Device { let geometries = &[*geometry]; let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() - .ty(conv::map_acceleration_structure_format(format)) - .mode(conv::map_acceleration_structure_build_mode(mode)) - .flags(conv::map_acceleration_structure_flags(flags)) + .ty(conv::map_acceleration_structure_format(desc.format)) + .mode(conv::map_acceleration_structure_build_mode(desc.mode)) + .flags(conv::map_acceleration_structure_flags(desc.flags)) .geometries(geometries); let raw = ray_tracing_functions @@ -877,7 +873,7 @@ impl crate::Device for super::Device { .get_acceleration_structure_build_sizes( vk::AccelerationStructureBuildTypeKHR::DEVICE, &geometry_info, - &[primitive_count], + &[desc.primitive_count], ); crate::AccelerationStructureBuildSizes { From 8318b5f77a538d6db692b2e1f760ad154b6f37bf Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Sep 2022 19:55:53 +0200 Subject: [PATCH 08/11] Fix wasm build --- wgpu/src/backend/web.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index f816125148..6b1a8cfd37 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1443,7 +1443,8 @@ impl crate::Context for Context { storage_texture.access(mapped_access); storage_texture.view_dimension(map_texture_view_dimension(view_dimension)); mapped_entry.storage_texture(&storage_texture); - } + }, + wgt::BindingType::AccelerationStructure => todo!(), } mapped_entry From fecb5382e7e50e451f1b4e10459992d436d4324f Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Sep 2022 20:48:43 +0200 Subject: [PATCH 09/11] Shuffle some code around, add a dummy implementation for DX12 with some links to implementation resources. --- wgpu-hal/src/dx11/command.rs | 7 + wgpu-hal/src/dx11/device.rs | 25 +++ wgpu-hal/src/dx11/mod.rs | 4 + wgpu-hal/src/dx12/command.rs | 9 + wgpu-hal/src/dx12/conv.rs | 1 + wgpu-hal/src/dx12/device.rs | 36 ++++ wgpu-hal/src/dx12/mod.rs | 5 + wgpu-hal/src/lib.rs | 35 ++-- wgpu-hal/src/vulkan/device.rs | 331 +++++++++++++++++----------------- wgpu/src/backend/web.rs | 2 +- 10 files changed, 270 insertions(+), 185 deletions(-) diff --git a/wgpu-hal/src/dx11/command.rs b/wgpu-hal/src/dx11/command.rs index 1c73f3c325..3ec95d0c33 100644 --- a/wgpu-hal/src/dx11/command.rs +++ b/wgpu-hal/src/dx11/command.rs @@ -265,4 +265,11 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { todo!() } + + unsafe fn build_acceleration_structures( + &mut self, + desc: &crate::BuildAccelerationStructureDescriptor, + ) { + todo!() + } } diff --git a/wgpu-hal/src/dx11/device.rs b/wgpu-hal/src/dx11/device.rs index 7b095ba1df..ee73329412 100644 --- a/wgpu-hal/src/dx11/device.rs +++ b/wgpu-hal/src/dx11/device.rs @@ -200,6 +200,31 @@ impl crate::Device for super::Device { unsafe fn stop_capture(&self) { todo!() } + + unsafe fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + ) -> Result { + todo!() + } + unsafe fn get_acceleration_structure_build_sizes( + &self, + desc: &crate::GetAccelerationStructureBuildSizesDescriptor, + ) -> crate::AccelerationStructureBuildSizes { + todo!() + } + unsafe fn get_acceleration_structure_device_address( + &self, + acceleration_structure: &super::AccelerationStructure, + ) -> wgt::BufferAddress { + todo!() + } + unsafe fn destroy_acceleration_structure( + &self, + acceleration_structure: super::AccelerationStructure, + ) { + todo!() + } } impl crate::Queue for super::Queue { diff --git a/wgpu-hal/src/dx11/mod.rs b/wgpu-hal/src/dx11/mod.rs index a77bb95919..e67feb3fad 100644 --- a/wgpu-hal/src/dx11/mod.rs +++ b/wgpu-hal/src/dx11/mod.rs @@ -36,6 +36,8 @@ impl crate::Api for Api { type ShaderModule = ShaderModule; type RenderPipeline = RenderPipeline; type ComputePipeline = ComputePipeline; + + type AccelerationStructure = AccelerationStructure; } pub struct Instance { @@ -106,6 +108,8 @@ pub struct BindGroup {} pub struct PipelineLayout {} #[derive(Debug)] pub struct ShaderModule {} +#[derive(Debug)] +pub struct AccelerationStructure {} pub struct RenderPipeline {} pub struct ComputePipeline {} diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index ca2f036430..4f843146f8 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -1019,4 +1019,13 @@ impl crate::CommandEncoder for super::CommandEncoder { 0, ); } + + unsafe fn build_acceleration_structures( + &mut self, + _desc: &crate::BuildAccelerationStructureDescriptor, + ) { + // Implement using `BuildRaytracingAccelerationStructure`: + // https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html#buildraytracingaccelerationstructure + todo!() + } } diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index 4114fba002..bbe14cefff 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -107,6 +107,7 @@ pub fn map_binding_type(ty: &wgt::BindingType) -> native::DescriptorRangeType { .. } | Bt::StorageTexture { .. } => native::DescriptorRangeType::UAV, + Bt::AccelerationStructure => todo!(), } } diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index de81b4e1bd..106f815711 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -706,6 +706,7 @@ impl crate::Device for super::Device { num_texture_views += count } wgt::BindingType::Sampler { .. } => num_samplers += count, + wgt::BindingType::AccelerationStructure => todo!(), } } @@ -1189,6 +1190,7 @@ impl crate::Device for super::Device { cpu_samplers.as_mut().unwrap().stage.push(data.handle.raw); } } + wgt::BindingType::AccelerationStructure => todo!(), } } @@ -1567,4 +1569,38 @@ impl crate::Device for super::Device { self.render_doc .end_frame_capture(self.raw.as_mut_ptr() as *mut _, ptr::null_mut()) } + + unsafe fn get_acceleration_structure_build_sizes( + &self, + _desc: &crate::GetAccelerationStructureBuildSizesDescriptor, + ) -> crate::AccelerationStructureBuildSizes { + // Implement using `GetRaytracingAccelerationStructurePrebuildInfo`: + // https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html#getraytracingaccelerationstructureprebuildinfo + todo!() + } + + unsafe fn get_acceleration_structure_device_address( + &self, + _acceleration_structure: &super::AccelerationStructure, + ) -> wgt::BufferAddress { + // Implement using `GetGPUVirtualAddress`: + // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12resource-getgpuvirtualaddress + todo!() + } + + unsafe fn create_acceleration_structure( + &self, + _desc: &crate::AccelerationStructureDescriptor, + ) -> Result { + // Create a D3D12 resource as per-usual. + todo!() + } + + unsafe fn destroy_acceleration_structure( + &self, + _acceleration_structure: super::AccelerationStructure, + ) { + // Destroy a D3D12 resource as per-usual. + todo!() + } } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 61d2ad9576..195fd429fe 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -79,6 +79,8 @@ impl crate::Api for Api { type ShaderModule = ShaderModule; type RenderPipeline = RenderPipeline; type ComputePipeline = ComputePipeline; + + type AccelerationStructure = AccelerationStructure; } // Limited by D3D12's root signature size of 64. Each element takes 1 or 2 entries. @@ -524,6 +526,9 @@ pub struct ComputePipeline { unsafe impl Send for ComputePipeline {} unsafe impl Sync for ComputePipeline {} +#[derive(Debug)] +pub struct AccelerationStructure {} + impl SwapChain { unsafe fn release_resources(self) -> native::WeakPtr { for resource in self.resources { diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 019c6b4b9f..c91560cca9 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -238,24 +238,6 @@ pub trait Device: Send + Sync { /// /// The initial usage is `BufferUses::empty()`. unsafe fn create_buffer(&self, desc: &BufferDescriptor) -> Result; - - unsafe fn create_acceleration_structure( - &self, - desc: &AccelerationStructureDescriptor, - ) -> Result; - - unsafe fn get_acceleration_structure_build_sizes( - &self, - desc: &GetAccelerationStructureBuildSizesDescriptor, - ) -> AccelerationStructureBuildSizes; - - unsafe fn get_acceleration_structure_device_address( - &self, - acceleration_structure: &A::AccelerationStructure, - ) -> wgt::BufferAddress; - - unsafe fn destroy_acceleration_structure(&self, buffer: A::AccelerationStructure); - unsafe fn destroy_buffer(&self, buffer: A::Buffer); //TODO: clarify if zero-sized mapping is allowed unsafe fn map_buffer( @@ -343,6 +325,23 @@ pub trait Device: Send + Sync { unsafe fn start_capture(&self) -> bool; unsafe fn stop_capture(&self); + + unsafe fn create_acceleration_structure( + &self, + desc: &AccelerationStructureDescriptor, + ) -> Result; + unsafe fn get_acceleration_structure_build_sizes( + &self, + desc: &GetAccelerationStructureBuildSizesDescriptor, + ) -> AccelerationStructureBuildSizes; + unsafe fn get_acceleration_structure_device_address( + &self, + acceleration_structure: &A::AccelerationStructure, + ) -> wgt::BufferAddress; + unsafe fn destroy_acceleration_structure( + &self, + acceleration_structure: A::AccelerationStructure, + ); } pub trait Queue: Send + Sync { diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 83c9e6ac58..afff881b18 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -815,152 +815,6 @@ impl crate::Device for super::Device { block: Mutex::new(block), }) } - - unsafe fn get_acceleration_structure_build_sizes( - &self, - desc: &crate::GetAccelerationStructureBuildSizesDescriptor, - ) -> crate::AccelerationStructureBuildSizes { - let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { - Some(ref functions) => functions, - None => panic!("Feature `RAY_TRACING` not enabled"), - }; - - let geometry = match desc.geometry_info { - crate::AccelerationStructureGeometryInfo::Instances => { - let instances_data = vk::AccelerationStructureGeometryInstancesDataKHR::builder(); - - vk::AccelerationStructureGeometryKHR::builder() - .geometry_type(vk::GeometryTypeKHR::INSTANCES) - .geometry(vk::AccelerationStructureGeometryDataKHR { - instances: *instances_data, - }) - .flags(vk::GeometryFlagsKHR::empty()) - } - crate::AccelerationStructureGeometryInfo::Triangles { - vertex_format, - max_vertex, - index_format, - } => { - let mut triangles_data = - vk::AccelerationStructureGeometryTrianglesDataKHR::builder() - .vertex_format(conv::map_vertex_format(vertex_format)) - .max_vertex(max_vertex); - - if let Some(index_format) = index_format { - triangles_data = - triangles_data.index_type(conv::map_index_format(index_format)); - } - - vk::AccelerationStructureGeometryKHR::builder() - .geometry_type(vk::GeometryTypeKHR::TRIANGLES) - .geometry(vk::AccelerationStructureGeometryDataKHR { - triangles: *triangles_data, - }) - .flags(vk::GeometryFlagsKHR::empty()) - } - }; - - let geometries = &[*geometry]; - - let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() - .ty(conv::map_acceleration_structure_format(desc.format)) - .mode(conv::map_acceleration_structure_build_mode(desc.mode)) - .flags(conv::map_acceleration_structure_flags(desc.flags)) - .geometries(geometries); - - let raw = ray_tracing_functions - .acceleration_structure - .get_acceleration_structure_build_sizes( - vk::AccelerationStructureBuildTypeKHR::DEVICE, - &geometry_info, - &[desc.primitive_count], - ); - - crate::AccelerationStructureBuildSizes { - acceleration_structure_size: raw.acceleration_structure_size, - update_scratch_size: raw.update_scratch_size, - build_scratch_size: raw.build_scratch_size, - } - } - - unsafe fn get_acceleration_structure_device_address( - &self, - acceleration_structure: &super::AccelerationStructure, - ) -> wgt::BufferAddress { - let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { - Some(ref functions) => functions, - None => panic!("Feature `RAY_TRACING` not enabled"), - }; - - ray_tracing_functions - .acceleration_structure - .get_acceleration_structure_device_address( - &vk::AccelerationStructureDeviceAddressInfoKHR::builder() - .acceleration_structure(acceleration_structure.raw), - ) - } - - unsafe fn create_acceleration_structure( - &self, - desc: &crate::AccelerationStructureDescriptor, - ) -> Result { - let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { - Some(ref functions) => functions, - None => panic!("Feature `RAY_TRACING` not enabled"), - }; - - let vk_buffer_info = vk::BufferCreateInfo::builder() - .size(desc.size) - .usage(vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - - let raw_buffer = self.shared.raw.create_buffer(&vk_buffer_info, None)?; - let req = self.shared.raw.get_buffer_memory_requirements(raw_buffer); - - let block = self.mem_allocator.lock().alloc( - &*self.shared, - gpu_alloc::Request { - size: req.size, - align_mask: req.alignment - 1, - usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, - memory_types: req.memory_type_bits & self.valid_ash_memory_types, - }, - )?; - - self.shared - .raw - .bind_buffer_memory(raw_buffer, *block.memory(), block.offset())?; - - if let Some(label) = desc.label { - self.shared - .set_object_name(vk::ObjectType::BUFFER, raw_buffer, label); - } - - let vk_info = vk::AccelerationStructureCreateInfoKHR::builder() - .buffer(raw_buffer) - .offset(0) - .size(desc.size) - .ty(conv::map_acceleration_structure_format(desc.format)); - - let raw_acceleration_structure = ray_tracing_functions - .acceleration_structure - .create_acceleration_structure(&vk_info, None)?; - - if let Some(label) = desc.label { - self.shared.set_object_name( - vk::ObjectType::ACCELERATION_STRUCTURE_KHR, - raw_acceleration_structure, - label, - ); - } - - Ok(super::AccelerationStructure { - raw: raw_acceleration_structure, - buffer: raw_buffer, - block: Mutex::new(block), - }) - } - unsafe fn destroy_buffer(&self, buffer: super::Buffer) { self.shared.raw.destroy_buffer(buffer.raw, None); self.mem_allocator @@ -968,26 +822,6 @@ impl crate::Device for super::Device { .dealloc(&*self.shared, buffer.block.into_inner()); } - unsafe fn destroy_acceleration_structure( - &self, - acceleration_structure: super::AccelerationStructure, - ) { - let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { - Some(ref functions) => functions, - None => panic!("Feature `RAY_TRACING` not enabled"), - }; - - ray_tracing_functions - .acceleration_structure - .destroy_acceleration_structure(acceleration_structure.raw, None); - self.shared - .raw - .destroy_buffer(acceleration_structure.buffer, None); - self.mem_allocator - .lock() - .dealloc(&*self.shared, acceleration_structure.block.into_inner()); - } - unsafe fn map_buffer( &self, buffer: &super::Buffer, @@ -2117,6 +1951,171 @@ impl crate::Device for super::Device { .end_frame_capture(raw_vk_instance_dispatch_table, ptr::null_mut()) } } + + unsafe fn get_acceleration_structure_build_sizes( + &self, + desc: &crate::GetAccelerationStructureBuildSizesDescriptor, + ) -> crate::AccelerationStructureBuildSizes { + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + let geometry = match desc.geometry_info { + crate::AccelerationStructureGeometryInfo::Instances => { + let instances_data = vk::AccelerationStructureGeometryInstancesDataKHR::builder(); + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::INSTANCES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + instances: *instances_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + crate::AccelerationStructureGeometryInfo::Triangles { + vertex_format, + max_vertex, + index_format, + } => { + let mut triangles_data = + vk::AccelerationStructureGeometryTrianglesDataKHR::builder() + .vertex_format(conv::map_vertex_format(vertex_format)) + .max_vertex(max_vertex); + + if let Some(index_format) = index_format { + triangles_data = + triangles_data.index_type(conv::map_index_format(index_format)); + } + + vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::TRIANGLES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + triangles: *triangles_data, + }) + .flags(vk::GeometryFlagsKHR::empty()) + } + }; + + let geometries = &[*geometry]; + + let geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + .ty(conv::map_acceleration_structure_format(desc.format)) + .mode(conv::map_acceleration_structure_build_mode(desc.mode)) + .flags(conv::map_acceleration_structure_flags(desc.flags)) + .geometries(geometries); + + let raw = ray_tracing_functions + .acceleration_structure + .get_acceleration_structure_build_sizes( + vk::AccelerationStructureBuildTypeKHR::DEVICE, + &geometry_info, + &[desc.primitive_count], + ); + + crate::AccelerationStructureBuildSizes { + acceleration_structure_size: raw.acceleration_structure_size, + update_scratch_size: raw.update_scratch_size, + build_scratch_size: raw.build_scratch_size, + } + } + + unsafe fn get_acceleration_structure_device_address( + &self, + acceleration_structure: &super::AccelerationStructure, + ) -> wgt::BufferAddress { + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + ray_tracing_functions + .acceleration_structure + .get_acceleration_structure_device_address( + &vk::AccelerationStructureDeviceAddressInfoKHR::builder() + .acceleration_structure(acceleration_structure.raw), + ) + } + + unsafe fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + ) -> Result { + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + let vk_buffer_info = vk::BufferCreateInfo::builder() + .size(desc.size) + .usage(vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let raw_buffer = self.shared.raw.create_buffer(&vk_buffer_info, None)?; + let req = self.shared.raw.get_buffer_memory_requirements(raw_buffer); + + let block = self.mem_allocator.lock().alloc( + &*self.shared, + gpu_alloc::Request { + size: req.size, + align_mask: req.alignment - 1, + usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, + memory_types: req.memory_type_bits & self.valid_ash_memory_types, + }, + )?; + + self.shared + .raw + .bind_buffer_memory(raw_buffer, *block.memory(), block.offset())?; + + if let Some(label) = desc.label { + self.shared + .set_object_name(vk::ObjectType::BUFFER, raw_buffer, label); + } + + let vk_info = vk::AccelerationStructureCreateInfoKHR::builder() + .buffer(raw_buffer) + .offset(0) + .size(desc.size) + .ty(conv::map_acceleration_structure_format(desc.format)); + + let raw_acceleration_structure = ray_tracing_functions + .acceleration_structure + .create_acceleration_structure(&vk_info, None)?; + + if let Some(label) = desc.label { + self.shared.set_object_name( + vk::ObjectType::ACCELERATION_STRUCTURE_KHR, + raw_acceleration_structure, + label, + ); + } + + Ok(super::AccelerationStructure { + raw: raw_acceleration_structure, + buffer: raw_buffer, + block: Mutex::new(block), + }) + } + + unsafe fn destroy_acceleration_structure( + &self, + acceleration_structure: super::AccelerationStructure, + ) { + let ray_tracing_functions = match self.shared.extension_fns.ray_tracing { + Some(ref functions) => functions, + None => panic!("Feature `RAY_TRACING` not enabled"), + }; + + ray_tracing_functions + .acceleration_structure + .destroy_acceleration_structure(acceleration_structure.raw, None); + self.shared + .raw + .destroy_buffer(acceleration_structure.buffer, None); + self.mem_allocator + .lock() + .dealloc(&*self.shared, acceleration_structure.block.into_inner()); + } } impl From for crate::DeviceError { diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 6b1a8cfd37..5cb9057208 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1443,7 +1443,7 @@ impl crate::Context for Context { storage_texture.access(mapped_access); storage_texture.view_dimension(map_texture_view_dimension(view_dimension)); mapped_entry.storage_texture(&storage_texture); - }, + } wgt::BindingType::AccelerationStructure => todo!(), } From 7905dc582f90ece798f069fe481cfa581411cf93 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 16 Sep 2022 22:28:09 +0200 Subject: [PATCH 10/11] Add dummy implementation for metal --- wgpu-hal/src/metal/command.rs | 7 +++++++ wgpu-hal/src/metal/device.rs | 28 ++++++++++++++++++++++++++++ wgpu-hal/src/metal/mod.rs | 5 +++++ 3 files changed, 40 insertions(+) diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index 49337ee7ea..6048aca0f4 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -962,4 +962,11 @@ impl crate::CommandEncoder for super::CommandEncoder { let encoder = self.state.compute.as_ref().unwrap(); encoder.dispatch_thread_groups_indirect(&buffer.raw, offset, self.state.raw_wg_size); } + + unsafe fn build_acceleration_structures( + &mut self, + _desc: &crate::BuildAccelerationStructureDescriptor, + ) { + unimplemented!() + } } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 81b9461f87..7064068acb 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -1123,4 +1123,32 @@ impl crate::Device for super::Device { } shared_capture_manager.stop_capture(); } + + unsafe fn get_acceleration_structure_build_sizes( + &self, + _desc: &crate::GetAccelerationStructureBuildSizesDescriptor, + ) -> crate::AccelerationStructureBuildSizes { + unimplemented!() + } + + unsafe fn get_acceleration_structure_device_address( + &self, + _acceleration_structure: &super::AccelerationStructure, + ) -> wgt::BufferAddress { + unimplemented!() + } + + unsafe fn create_acceleration_structure( + &self, + _desc: &crate::AccelerationStructureDescriptor, + ) -> Result { + unimplemented!() + } + + unsafe fn destroy_acceleration_structure( + &self, + _acceleration_structure: super::AccelerationStructure, + ) { + unimplemented!() + } } diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index dee9467e74..42466fc3c8 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -59,6 +59,8 @@ impl crate::Api for Api { type ShaderModule = ShaderModule; type RenderPipeline = RenderPipeline; type ComputePipeline = ComputePipeline; + + type AccelerationStructure = AccelerationStructure; } pub struct Instance { @@ -733,3 +735,6 @@ pub struct CommandBuffer { unsafe impl Send for CommandBuffer {} unsafe impl Sync for CommandBuffer {} + +#[derive(Debug)] +pub struct AccelerationStructure; From 6f2b07a00c3e462da85a6c15fe88adcc45b30ae4 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sun, 18 Sep 2022 15:08:19 +0200 Subject: [PATCH 11/11] Fix example, hopefully have fixed metal code --- wgpu-hal/examples/ray-traced-triangle/main.rs | 7 ++++++- wgpu-hal/src/metal/device.rs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index fa749de870..49fb58686b 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -3,6 +3,7 @@ extern crate wgpu_hal as hal; use hal::{ Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, Surface as _, }; +use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use glam::{Mat4, Vec3}; use std::{ @@ -101,7 +102,11 @@ impl Example { }, }; let instance = unsafe { A::Instance::init(&instance_desc)? }; - let mut surface = unsafe { instance.create_surface(window).unwrap() }; + let mut surface = unsafe { + instance + .create_surface(window.raw_display_handle(), window.raw_window_handle()) + .unwrap() + }; let (adapter, features) = unsafe { let mut adapters = instance.enumerate_adapters(); diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 81b9461f87..da7ecd4830 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -595,6 +595,7 @@ impl crate::Device for super::Device { wgt::StorageTextureAccess::ReadWrite => true, }; } + wgt::BindingType::AccelerationStructure => unimplemented!(), } let br = naga::ResourceBinding { @@ -755,6 +756,7 @@ impl crate::Device for super::Device { ); counter.textures += size; } + wgt::BindingType::AccelerationStructure => unimplemented!(), } } }