From 60cea633ca8d282c7a66e07dc998eb4e930e6bad Mon Sep 17 00:00:00 2001 From: Facundo Villa Date: Thu, 2 Nov 2023 00:30:00 -0300 Subject: [PATCH] RayTracing API WIP. --- src/lib.rs | 1 + src/render_domain.rs | 8 +- src/rendering/render_system.rs | 226 +++++++++++++++++++++----- src/rendering/vulkan_render_system.rs | 166 +++++++++++++++---- tests/gi.rs | 2 +- 5 files changed, 323 insertions(+), 80 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 978a559a..96d12263 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(const_mut_refs)] #![feature(is_sorted)] #![feature(iter_map_windows)] +#![feature(pointer_is_aligned)] // #![warn(missing_docs)] # Disable now because we are writing a lot of code // #![warn(missing_doc_code_examples)] # Disable now because we are writing a lot of code diff --git a/src/render_domain.rs b/src/render_domain.rs index a102191d..60e30882 100644 --- a/src/render_domain.rs +++ b/src/render_domain.rs @@ -962,7 +962,7 @@ void main() {{ binding: 0, descriptor_type: render_system::DescriptorType::AccelerationStructure, descriptor_count: 1, - stages: render_system::Stages::ACCELERATION_STRUCTURE, + stages: render_system::Stages::RAYGEN, immutable_samplers: None, }, ]); @@ -975,7 +975,7 @@ void main() {{ binding: 0, descriptor_type: render_system::DescriptorType::AccelerationStructure, descriptor_count: 1, - stages: render_system::Stages::ACCELERATION_STRUCTURE, + stages: render_system::Stages::RAYGEN, immutable_samplers: None, }, ]); @@ -990,8 +990,8 @@ void main() {{ ]); const _SHADOW_RAY_GEN_SHADER: &'static str = " -#version 450 -#pragma shader_stage(ray_gen) +#version 460 core +#pragma shader_stage(raygen) #extension GL_EXT_scalar_block_layout: enable #extension GL_EXT_buffer_reference: enable diff --git a/src/rendering/render_system.rs b/src/rendering/render_system.rs index fd79ea4e..af88d01d 100644 --- a/src/rendering/render_system.rs +++ b/src/rendering/render_system.rs @@ -112,6 +112,7 @@ pub struct TextureCopyHandle(pub(crate) u64); pub enum Handle { Buffer(BaseBufferHandle), // AccelerationStructure(AccelerationStructureHandle), + TopLevelAccelerationStructure(TopLevelAccelerationStructureHandle), CommandBuffer(CommandBufferHandle), Shader(ShaderHandle), Pipeline(PipelineHandle), @@ -371,6 +372,7 @@ pub trait RenderSystem: orchestrator::System { fn create_bottom_level_acceleration_structure(&mut self, description: &BottomLevelAccelerationStructure) -> BottomLevelAccelerationStructureHandle; fn write_instance(&mut self, instances_buffer_handle: BaseBufferHandle, transform: [[f32; 4]; 3], custom_index: u16, mask: u8, sbt_record_offset: usize, acceleration_structure: BottomLevelAccelerationStructureHandle); + fn write_sbt_entry(&mut self, sbt_buffer_handle: BaseBufferHandle, sbt_record_offset: usize, pipeline_handle: PipelineHandle, shader_handle: ShaderHandle); fn bind_to_window(&mut self, window_os_handles: &window_system::WindowOsHandles) -> SwapchainHandle; @@ -592,8 +594,6 @@ bitflags::bitflags! { const COMPUTE = 0b1000; /// The transfer stage. const TRANSFER = 0b10000; - /// The acceleration structure stage. - const ACCELERATION_STRUCTURE = 0b100000; /// The presentation stage. const PRESENTATION = 0b1000000; /// The host stage. @@ -602,6 +602,20 @@ bitflags::bitflags! { const SHADER_WRITE = 0b1000000000; /// The indirect commands evaluation stage. const INDIRECT = 0b10000000000; + /// The task stage. + const TASK = 0b100000000000; + /// The ray generation stage. + const RAYGEN = 0b100000000000; + /// The closest hit stage. + const CLOSEST_HIT = 0b1000000000000; + /// The any hit stage. + const ANY_HIT = 0b10000000000000; + /// The intersection stage. + const INTERSECTION = 0b100000000000000; + /// The miss stage. + const MISS = 0b1000000000000000; + /// The callable stage. + const CALLABLE = 0b10000000000000000; } } @@ -656,6 +670,8 @@ bitflags::bitflags! { const ShaderBindingTable = 1 << 11; /// Resource will be used as a acceleration structure build scratch buffer. const AccelerationStructureBuildScratch = 1 << 12; + + const AccelerationStructureBuild = 1 << 13; } } @@ -990,6 +1006,10 @@ impl RenderSystem for RenderSystemImplementation { self.pointer.write_instance(instances_buffer_handle, transform, custom_index, mask, sbt_record_offset, acceleration_structure) } + fn write_sbt_entry(&mut self, sbt_buffer_handle: BaseBufferHandle, sbt_record_offset: usize, pipeline_handle: PipelineHandle, shader_handle: ShaderHandle) { + self.pointer.write_sbt_entry(sbt_buffer_handle, sbt_record_offset, pipeline_handle, shader_handle) + } + fn create_synchronizer(&mut self, signaled: bool) -> SynchronizerHandle { self.pointer.create_synchronizer(signaled) } @@ -1901,8 +1921,13 @@ pub(super) mod tests { const FRAMES_IN_FLIGHT: usize = 2; + let mut window_system = window_system::WindowSystem::new(); + // Use and odd width to make sure there is a middle/center pixel - let _extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; + let extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; + + let window_handle = window_system.create_window("Renderer Test", extent, "test"); + let swapchain = renderer.bind_to_window(&window_system.get_os_handles_2(&window_handle)); let positions: [f32; 3 * 3] = [ 0.0, 1.0, 0.0, @@ -1921,17 +1946,17 @@ pub(super) mod tests { VertexElement{ name: "COLOR".to_string(), format: DataTypes::Float4, binding: 0 }, ]; - let vertex_positions_buffer = renderer.create_buffer(None, positions.len() * 4, Uses::Vertex, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); - let vertex_colors_buffer = renderer.create_buffer(None, positions.len() * 4, Uses::Vertex, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); - let index_buffer = renderer.create_buffer(None, positions.len() * 2, Uses::Index, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); + let vertex_positions_buffer = renderer.create_buffer(None, positions.len() * 4, Uses::Storage | Uses::AccelerationStructureBuild, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); + let vertex_colors_buffer = renderer.create_buffer(None, colors.len() * 4, Uses::Storage | Uses::AccelerationStructureBuild, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); + let index_buffer = renderer.create_buffer(None, 3 * 2, Uses::Storage | Uses::AccelerationStructureBuild, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); renderer.get_mut_buffer_slice(vertex_positions_buffer).copy_from_slice(unsafe { std::slice::from_raw_parts(positions.as_ptr() as *const u8, positions.len() * 4) }); renderer.get_mut_buffer_slice(vertex_colors_buffer).copy_from_slice(unsafe { std::slice::from_raw_parts(colors.as_ptr() as *const u8, colors.len() * 4) }); renderer.get_mut_buffer_slice(index_buffer).copy_from_slice(unsafe { std::slice::from_raw_parts([0u16, 1u16, 2u16].as_ptr() as *const u8, 3 * 2) }); let raygen_shader_code = " -#version 450 -#pragma shader_stage(ray_gen) +#version 460 core +#pragma shader_stage(raygen) #extension GL_EXT_scalar_block_layout: enable #extension GL_EXT_buffer_reference: enable @@ -1948,21 +1973,25 @@ void main() { const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.xy); vec2 d = inUV * 2.0 - 1.0; + d.y *= -1.0; uint rayFlags = gl_RayFlagsOpaqueEXT; uint cullMask = 0xff; float tmin = 0.001; - float tmax = 10000.0; + float tmax = 10.0; - traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin.xyz, tmin, direction.xyz, tmax, 0); + vec3 origin = vec3(d, -1.0); + vec3 direction = vec3(0.0, 0.0, 1.0); - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 0.0)); + traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direction, tmax, 0); + + imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 1.0)); } "; let closest_hit_shader_code = " -#version 450 -#pragma shader_stage(closest_hit) +#version 460 core +#pragma shader_stage(closest) #extension GL_EXT_scalar_block_layout: enable #extension GL_EXT_buffer_reference: enable @@ -1973,17 +2002,26 @@ void main() { layout(location = 0) rayPayloadInEXT vec3 hitValue; hitAttributeEXT vec2 attribs; -layout(binding = 3, set = 0) buffer Vertices { vec4 v[]; } vertices; -layout(binding = 4, set = 0) buffer Indices { uint16_t i[]; } indices; +layout(binding = 2, set = 0) buffer VertexPositions { vec3 positions[3]; }; +layout(binding = 3, set = 0) buffer VertexColors { vec4 colors[3]; }; +layout(binding = 4, set = 0) buffer Indices { uint16_t indices[3]; }; void main() { const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y); - ivec3 index = ivec3(indices.i[3 * gl_PrimitiveID], indices.i[3 * gl_PrimitiveID + 1], indices.i[3 * gl_PrimitiveID + 2]); + ivec3 index = ivec3(indices[3 * gl_PrimitiveID], indices[3 * gl_PrimitiveID + 1], indices[3 * gl_PrimitiveID + 2]); + + vec3[3] vertex_positions = vec3[3](positions[index.x], positions[index.y], positions[index.z]); + vec4[3] vertex_colors = vec4[3](colors[index.x], colors[index.y], colors[index.z]); + + vec3 position = vertex_positions[0] * barycentricCoords.x + vertex_positions[1] * barycentricCoords.y + vertex_positions[2] * barycentricCoords.z; + vec4 color = vertex_colors[0] * barycentricCoords.x + vertex_colors[1] * barycentricCoords.y + vertex_colors[2] * barycentricCoords.z; + + hitValue = color.xyz; } "; let miss_shader_code = " -#version 450 +#version 460 core #pragma shader_stage(miss) #extension GL_EXT_scalar_block_layout: enable @@ -1995,7 +2033,7 @@ void main() { layout(location = 0) rayPayloadInEXT vec3 hitValue; void main() { - hitValue = vec3(0.0, 0.0, 0.2); + hitValue = vec3(0.0, 0.0, 0.0); } "; @@ -2019,7 +2057,39 @@ void main() { descriptor_count: 1, descriptor_type: DescriptorType::AccelerationStructure, binding: 0, - stages: Stages::ACCELERATION_STRUCTURE, + stages: Stages::RAYGEN, + immutable_samplers: None, + }, + DescriptorSetLayoutBinding { + name: "render target", + descriptor_count: 1, + descriptor_type: DescriptorType::StorageImage, + binding: 1, + stages: Stages::RAYGEN, + immutable_samplers: None, + }, + DescriptorSetLayoutBinding { + name: "vertex positions", + descriptor_count: 1, + descriptor_type: DescriptorType::StorageBuffer, + binding: 2, + stages: Stages::CLOSEST_HIT, + immutable_samplers: None, + }, + DescriptorSetLayoutBinding { + name: "vertex colors", + descriptor_count: 1, + descriptor_type: DescriptorType::StorageBuffer, + binding: 3, + stages: Stages::CLOSEST_HIT, + immutable_samplers: None, + }, + DescriptorSetLayoutBinding { + name: "indices", + descriptor_count: 1, + descriptor_type: DescriptorType::StorageBuffer, + binding: 4, + stages: Stages::CLOSEST_HIT, immutable_samplers: None, }, ]; @@ -2028,15 +2098,16 @@ void main() { let descriptor_set = renderer.create_descriptor_set(None, &descriptor_set_layout_handle, &bindings); + let render_target = renderer.create_image(None, extent, Formats::RGBAu8, None, Uses::Storage, DeviceAccesses::CpuRead | DeviceAccesses::GpuWrite, UseCases::DYNAMIC); + renderer.write(&[ DescriptorWrite { descriptor_set: descriptor_set, binding: 0, array_element: 0, descriptor: Descriptor::AccelerationStructure{ handle: top_level_acceleration_structure } }, + DescriptorWrite { descriptor_set: descriptor_set, binding: 1, array_element: 0, descriptor: Descriptor::Image { handle: render_target, layout: Layouts::General } }, + DescriptorWrite { descriptor_set: descriptor_set, binding: 2, array_element: 0, descriptor: Descriptor::Buffer { handle: vertex_positions_buffer, size: Ranges::Size(12 * 3) } }, + DescriptorWrite { descriptor_set: descriptor_set, binding: 3, array_element: 0, descriptor: Descriptor::Buffer { handle: vertex_colors_buffer, size: Ranges::Size(16 * 3) } }, + DescriptorWrite { descriptor_set: descriptor_set, binding: 4, array_element: 0, descriptor: Descriptor::Buffer { handle: index_buffer, size: Ranges::Size(2 * 3) } }, ]); - // Use and odd width to make sure there is a middle/center pixel - let extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; - - let render_target = renderer.create_image(None, extent, Formats::RGBAu8, None, Uses::RenderTarget, DeviceAccesses::CpuRead | DeviceAccesses::GpuWrite, UseCases::DYNAMIC); - let pipeline_layout = renderer.create_pipeline_layout(&[descriptor_set_layout_handle], &[]); let pipeline = renderer.create_ray_tracing_pipeline( @@ -2044,15 +2115,17 @@ void main() { &[(&raygen_shader, ShaderTypes::Raygen, vec![]), (&closest_hit_shader, ShaderTypes::ClosestHit, vec![]), (&miss_shader, ShaderTypes::Miss, vec![])], ); - let command_buffer_handle = renderer.create_command_buffer(); + let building_command_buffer_handle = renderer.create_command_buffer(); + let rendering_command_buffer_handle = renderer.create_command_buffer(); - let render_finished_synchronizer = renderer.create_synchronizer(false); + let render_finished_synchronizer = renderer.create_synchronizer(true); + let image_ready = renderer.create_synchronizer(true); let instances_buffer = renderer.create_acceleration_structure_instance_buffer(None, 1); renderer.write_instance(instances_buffer, [[1f32, 0f32, 0f32, 0f32], [0f32, 1f32, 0f32, 0f32], [0f32, 0f32, 1f32, 0f32]], 0, 0xFF, 0, bottom_level_acceleration_structure); - let build_sync = renderer.create_synchronizer(false); + let build_sync = renderer.create_synchronizer(true); let scratch_buffer = renderer.create_buffer(None, 1024 * 1024, Uses::AccelerationStructureBuildScratch, DeviceAccesses::GpuWrite, UseCases::DYNAMIC); @@ -2060,9 +2133,55 @@ void main() { let miss_sbt_buffer = renderer.create_buffer(None, 64, Uses::ShaderBindingTable, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); let hit_sbt_buffer = renderer.create_buffer(None, 64, Uses::ShaderBindingTable, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::STATIC); - for i in 0..FRAMES_IN_FLIGHT * 10 { + renderer.write_sbt_entry(raygen_sbt_buffer, 0, pipeline, raygen_shader); + renderer.write_sbt_entry(miss_sbt_buffer, 0, pipeline, miss_shader); + renderer.write_sbt_entry(hit_sbt_buffer, 0, pipeline, closest_hit_shader); + + for i in 0..FRAMES_IN_FLIGHT * 1000 { + renderer.wait(render_finished_synchronizer); + + // { + // renderer.wait(build_sync); + + // let mut command_buffer_recording = renderer.create_command_buffer_recording(building_command_buffer_handle, Some(i as u32)); + + // command_buffer_recording.build_bottom_level_acceleration_structures(&[BottomLevelAccelerationStructureBuild { + // acceleration_structure: bottom_level_acceleration_structure, + // description: BottomLevelAccelerationStructureBuildDescriptions::Mesh { + // vertex_buffer: BufferStridedRange { buffer: vertex_positions_buffer, offset: 0, stride: 12, size: 12 * 3 }, + // vertex_count: 3, + // index_buffer: BufferStridedRange { buffer: index_buffer, offset: 0, stride: 2, size: 2 * 3 }, + // vertex_position_encoding: Encodings::IEEE754, + // index_format: DataTypes::U16, + // triangle_count: 1, + // }, + // scratch_buffer: BufferDescriptor { buffer: scratch_buffer, offset: 0, range: 1024 * 512, slot: 0 }, + // }]); + + // command_buffer_recording.build_top_level_acceleration_structure(&TopLevelAccelerationStructureBuild { + // acceleration_structure: top_level_acceleration_structure, + // description: TopLevelAccelerationStructureBuildDescriptions::Instance { + // instances_buffer, + // instance_count: 1, + // }, + // scratch_buffer: BufferDescriptor { buffer: scratch_buffer, offset: 1024 * 512, range: 1024 * 512, slot: 0 }, + // }); + + // command_buffer_recording.execute(&[], &[build_sync], build_sync); + // } + + // renderer.wait(render_finished_synchronizer); + + renderer.start_frame_capture(); + + let image_index = renderer.acquire_swapchain_image(swapchain, image_ready); + + let mut command_buffer_recording = renderer.create_command_buffer_recording(rendering_command_buffer_handle, Some(i as u32)); + { - let mut command_buffer_recording = renderer.create_command_buffer_recording(command_buffer_handle, Some(i as u32)); + // renderer.wait(build_sync); + + // let mut command_buffer_recording = renderer.create_command_buffer_recording(building_command_buffer_handle, Some(i as u32)); command_buffer_recording.build_bottom_level_acceleration_structures(&[BottomLevelAccelerationStructureBuild { acceleration_structure: bottom_level_acceleration_structure, @@ -2086,17 +2205,28 @@ void main() { scratch_buffer: BufferDescriptor { buffer: scratch_buffer, offset: 1024 * 512, range: 1024 * 512, slot: 0 }, }); - command_buffer_recording.execute(&[], &[build_sync], render_finished_synchronizer); + // command_buffer_recording.execute(&[], &[build_sync], build_sync); } - // renderer.wait(render_finished_synchronizer); - - renderer.start_frame_capture(); - - let mut command_buffer_recording = renderer.create_command_buffer_recording(command_buffer_handle, Some(i as u32)); - command_buffer_recording.bind_ray_tracing_pipeline(&pipeline); + command_buffer_recording.bind_descriptor_sets(&pipeline_layout, &[(descriptor_set, 0)]); + + command_buffer_recording.consume_resources(&[ + Consumption { + handle: Handle::Image(render_target), + stages: Stages::RAYGEN, + access: AccessPolicies::WRITE, + layout: Layouts::General, + }, + Consumption { + handle: Handle::TopLevelAccelerationStructure(top_level_acceleration_structure), + stages: Stages::RAYGEN, + access: AccessPolicies::READ, + layout: Layouts::General, + }, + ]); + command_buffer_recording.trace_rays(BindingTables { raygen: BufferStridedRange { buffer: raygen_sbt_buffer, offset: 0, stride: 64, size: 64 }, hit: BufferStridedRange { buffer: hit_sbt_buffer, offset: 0, stride: 64, size: 64 }, @@ -2104,19 +2234,33 @@ void main() { callable: None, }, 1920, 1080, 1); + command_buffer_recording.copy_to_swapchain(render_target, image_index, swapchain); + let texure_copy_handles = command_buffer_recording.sync_textures(&[render_target]); - command_buffer_recording.execute(&[build_sync], &[], render_finished_synchronizer); + command_buffer_recording.execute(&[/*build_sync,*/image_ready], &[render_finished_synchronizer], render_finished_synchronizer); + + renderer.present(image_index, &[swapchain], render_finished_synchronizer); renderer.end_frame_capture(); - renderer.wait(render_finished_synchronizer); + // renderer.wait(render_finished_synchronizer); assert!(!renderer.has_errors()); - let pixels = unsafe { std::slice::from_raw_parts(renderer.get_image_data(texure_copy_handles[0]).as_ptr() as *const RGBAu8, (extent.width * extent.height) as usize) }; - - check_triangle(pixels, extent); + // let pixels = unsafe { std::slice::from_raw_parts(renderer.get_image_data(texure_copy_handles[0]).as_ptr() as *const RGBAu8, (extent.width * extent.height) as usize) }; + + // let mut file = std::fs::File::create("test.png").unwrap(); +// + // let mut encoder = png::Encoder::new(&mut file, extent.width, extent.height); +// + // encoder.set_color(png::ColorType::Rgba); + // encoder.set_depth(png::BitDepth::Eight); +// + // let mut writer = encoder.write_header().unwrap(); + // writer.write_image_data(unsafe { std::slice::from_raw_parts(pixels.as_ptr() as *const u8, pixels.len() * 4) }).unwrap(); + + // check_triangle(pixels, extent); } } } \ No newline at end of file diff --git a/src/rendering/vulkan_render_system.rs b/src/rendering/vulkan_render_system.rs index 89c3064d..5e43e052 100644 --- a/src/rendering/vulkan_render_system.rs +++ b/src/rendering/vulkan_render_system.rs @@ -44,6 +44,7 @@ pub struct VulkanRenderSystem { descriptor_sets: Vec, meshes: Vec, acceleration_structures: Vec, + pipelines: Vec, command_buffers: Vec, synchronizers: Vec, swapchains: Vec, @@ -63,7 +64,8 @@ fn uses_to_vk_usage_flags(usage: render_system::Uses) -> vk::BufferUsageFlags { flags |= if usage.contains(render_system::Uses::AccelerationStructure) { vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR } else { vk::BufferUsageFlags::empty() }; flags |= if usage.contains(render_system::Uses::Indirect) { vk::BufferUsageFlags::INDIRECT_BUFFER } else { vk::BufferUsageFlags::empty() }; flags |= if usage.contains(render_system::Uses::ShaderBindingTable) { vk::BufferUsageFlags::SHADER_BINDING_TABLE_KHR } else { vk::BufferUsageFlags::empty() }; - flags |= if usage.contains(render_system::Uses::AccelerationStructureBuildScratch) { vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR } else { vk::BufferUsageFlags::empty() }; + flags |= if usage.contains(render_system::Uses::AccelerationStructureBuildScratch) { vk::BufferUsageFlags::STORAGE_BUFFER } else { vk::BufferUsageFlags::empty() }; + flags |= if usage.contains(render_system::Uses::AccelerationStructureBuild) { vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR } else { vk::BufferUsageFlags::empty() }; flags } @@ -427,7 +429,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { let mut acc_str_descriptor_info = vk::WriteDescriptorSetAccelerationStructureKHR::default() .acceleration_structures(&acceleration_structures); - let write_info = vk::WriteDescriptorSet::default() + let write_info = vk::WriteDescriptorSet{ descriptor_count: 1, ..vk::WriteDescriptorSet::default() } .push_next(&mut acc_str_descriptor_info) .dst_set(descriptor_set.descriptor_set) .dst_binding(descriptor_set_write.binding) @@ -513,7 +515,14 @@ impl render_system::RenderSystem for VulkanRenderSystem { self.device.create_compute_pipelines(vk::PipelineCache::null(), &create_infos, None).expect("No compute pipeline")[0] }; - render_system::PipelineHandle(pipeline_handle.as_raw()) + let handle = render_system::PipelineHandle(self.pipelines.len() as u64); + + self.pipelines.push(Pipeline { + pipeline: pipeline_handle, + shader_handles: HashMap::new(), + }); + + handle } fn create_ray_tracing_pipeline(&mut self, pipeline_layout_handle: &render_system::PipelineLayoutHandle, shaders: &[render_system::ShaderParameter]) -> render_system::PipelineHandle { @@ -532,18 +541,34 @@ impl render_system::RenderSystem for VulkanRenderSystem { match shader.1 { render_system::ShaderTypes::Raygen | render_system::ShaderTypes::Miss | render_system::ShaderTypes::Callable => { groups.push(vk::RayTracingShaderGroupCreateInfoKHR::default() - .general_shader(i as u32)); + .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL) + .general_shader(i as u32) + .closest_hit_shader(vk::SHADER_UNUSED_KHR) + .any_hit_shader(vk::SHADER_UNUSED_KHR) + .intersection_shader(vk::SHADER_UNUSED_KHR)); } render_system::ShaderTypes::ClosestHit => { groups.push(vk::RayTracingShaderGroupCreateInfoKHR::default() - .closest_hit_shader(i as u32)); + .ty(vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP) + .general_shader(vk::SHADER_UNUSED_KHR) + .closest_hit_shader(i as u32) + .any_hit_shader(vk::SHADER_UNUSED_KHR) + .intersection_shader(vk::SHADER_UNUSED_KHR)); } render_system::ShaderTypes::AnyHit => { groups.push(vk::RayTracingShaderGroupCreateInfoKHR::default() - .any_hit_shader(i as u32)); + .ty(vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP) + .general_shader(vk::SHADER_UNUSED_KHR) + .closest_hit_shader(vk::SHADER_UNUSED_KHR) + .any_hit_shader(i as u32) + .intersection_shader(vk::SHADER_UNUSED_KHR)); } render_system::ShaderTypes::Intersection => { groups.push(vk::RayTracingShaderGroupCreateInfoKHR::default() + .ty(vk::RayTracingShaderGroupTypeKHR::PROCEDURAL_HIT_GROUP) + .general_shader(vk::SHADER_UNUSED_KHR) + .closest_hit_shader(vk::SHADER_UNUSED_KHR) + .any_hit_shader(vk::SHADER_UNUSED_KHR) .intersection_shader(i as u32)); } _ => { @@ -558,13 +583,30 @@ impl render_system::RenderSystem for VulkanRenderSystem { .groups(&groups) .max_pipeline_ray_recursion_depth(1); + let mut handles: HashMap = HashMap::with_capacity(shaders.len()); + let pipeline_handle = unsafe { let pipeline = self.ray_tracing_pipeline.create_ray_tracing_pipelines(vk::DeferredOperationKHR::null(), vk::PipelineCache::null(), &[create_info], None).expect("No ray tracing pipeline")[0]; let handle_buffer = self.ray_tracing_pipeline.get_ray_tracing_shader_group_handles(pipeline, 0, groups.len() as u32, 32 * groups.len()).expect("Could not get ray tracing shader group handles"); + + for (i, shader) in shaders.iter().enumerate() { + let mut h = [0u8; 32]; + h.copy_from_slice(&handle_buffer[i * 32..(i + 1) * 32]); + + handles.insert(*shader.0, h); + } + pipeline }; - render_system::PipelineHandle(pipeline_handle.as_raw()) + let handle = render_system::PipelineHandle(self.pipelines.len() as u64); + + self.pipelines.push(Pipeline { + pipeline: pipeline_handle, + shader_handles: handles, + }); + + handle } fn create_command_buffer(&mut self) -> render_system::CommandBufferHandle { @@ -630,7 +672,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { self.buffers.push(Buffer { buffer: buffer_creation_result.resource, - size: buffer_creation_result.size, + size, device_address, pointer, }); @@ -648,7 +690,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { self.buffers.push(Buffer { buffer: buffer_creation_result.resource, - size: buffer_creation_result.size, + size, device_address, pointer, }); @@ -661,7 +703,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { self.buffers.push(Buffer { buffer: buffer_creation_result.resource, - size: buffer_creation_result.size, + size, device_address, pointer, }); @@ -680,7 +722,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { self.buffers.push(Buffer { buffer: buffer_creation_result.resource, - size: buffer_creation_result.size, + size, device_address, pointer, }); @@ -853,6 +895,10 @@ impl render_system::RenderSystem for VulkanRenderSystem { let buffer = self.create_vulkan_buffer(None, acceleration_structure_size, vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS); + let (allocation_handle, _) = self.create_allocation_internal(buffer.size, render_system::DeviceAccesses::GpuWrite); + + let (_, _) = self.bind_vulkan_buffer_memory(&buffer, allocation_handle, 0); + let create_info = vk::AccelerationStructureCreateInfoKHR::default() .buffer(buffer.resource) .size(acceleration_structure_size as u64) @@ -938,6 +984,10 @@ impl render_system::RenderSystem for VulkanRenderSystem { let buffer_descriptor = self.create_vulkan_buffer(None, acceleration_structure_size, vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS); + let (allocation_handle, _) = self.create_allocation_internal(buffer_descriptor.size, render_system::DeviceAccesses::GpuWrite); + + let (_, _) = self.bind_vulkan_buffer_memory(&buffer_descriptor, allocation_handle, 0); + let create_info = vk::AccelerationStructureCreateInfoKHR::default() .buffer(buffer_descriptor.resource) .size(acceleration_structure_size as u64) @@ -976,6 +1026,10 @@ impl render_system::RenderSystem for VulkanRenderSystem { } fn write_instance(&mut self, instances_buffer: BaseBufferHandle, transform: [[f32; 4]; 3], custom_index: u16, mask: u8, sbt_record_offset: usize, acceleration_structure: render_system::BottomLevelAccelerationStructureHandle) { + let buffer = self.acceleration_structures[acceleration_structure.0 as usize].buffer; + + let address = unsafe { self.device.get_buffer_device_address(&vk::BufferDeviceAddressInfo::default().buffer(buffer)) }; + let instance = vk::AccelerationStructureInstanceKHR{ transform: vk::TransformMatrixKHR { matrix: [transform[0][0], transform[0][1], transform[0][2], transform[0][3], transform[1][0], transform[1][1], transform[1][2], transform[1][3], transform[2][0], transform[2][1], transform[2][2], transform[2][3]], @@ -983,7 +1037,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { instance_custom_index_and_mask: vk::Packed24_8::new(custom_index as u32, mask), instance_shader_binding_table_record_offset_and_flags: vk::Packed24_8::new(sbt_record_offset as u32, 0), acceleration_structure_reference: vk::AccelerationStructureReferenceKHR { - device_handle: self.acceleration_structures[acceleration_structure.0 as usize].acceleration_structure.as_raw() as u64, + device_handle: address, }, }; @@ -994,6 +1048,16 @@ impl render_system::RenderSystem for VulkanRenderSystem { instance_buffer_slice[0] = instance; } + fn write_sbt_entry(&mut self, sbt_buffer_handle: BaseBufferHandle, sbt_record_offset: usize, pipeline_handle: render_system::PipelineHandle, shader_handle: render_system::ShaderHandle) { + let slice = self.get_mut_buffer_slice(sbt_buffer_handle); + + let pipeline = &self.pipelines[pipeline_handle.0 as usize]; + + assert!(slice.as_ptr().is_aligned_to(64)); + + slice[sbt_record_offset..sbt_record_offset + 32].copy_from_slice(pipeline.shader_handles.get(&shader_handle).unwrap()) + } + fn bind_to_window(&mut self, window_os_handles: &window_system::WindowOsHandles) -> render_system::SwapchainHandle { let surface = self.create_vulkan_surface(window_os_handles); @@ -1128,7 +1192,7 @@ impl render_system::RenderSystem for VulkanRenderSystem { use ash::{vk::{ValidationFeatureEnableEXT, Handle}, Entry}; -use super::render_system::{CommandBufferRecording, Formats, DispatchExtent, BaseBufferHandle, RenderSystem}; +use super::render_system::{CommandBufferRecording, Formats, DispatchExtent, BaseBufferHandle, RenderSystem, ShaderHandle}; #[derive(Clone)] pub(crate) struct Swapchain { @@ -1156,9 +1220,10 @@ pub(crate) struct DescriptorSet { descriptor_set_layout: render_system::DescriptorSetLayoutHandle, } -#[derive(Clone, Copy)] +#[derive(Clone)] pub(crate) struct Pipeline { pipeline: vk::Pipeline, + shader_handles: HashMap, } #[derive(Clone, Copy)] @@ -1369,6 +1434,10 @@ fn to_pipeline_stage_flags(stages: render_system::Stages) -> vk::PipelineStageFl pipeline_stage_flags |= vk::PipelineStageFlags2::DRAW_INDIRECT; } + if stages.contains(render_system::Stages::RAYGEN) { + pipeline_stage_flags |= vk::PipelineStageFlags2::RAY_TRACING_SHADER_KHR; + } + pipeline_stage_flags } @@ -1431,6 +1500,9 @@ fn to_access_flags(accesses: render_system::AccessPolicies, stages: render_syste if stages.intersects(render_system::Stages::INDIRECT) { access_flags |= vk::AccessFlags2::INDIRECT_COMMAND_READ } + if stages.intersects(render_system::Stages::RAYGEN) { + access_flags |= vk::AccessFlags2::ACCELERATION_STRUCTURE_READ_KHR + } } if accesses.contains(render_system::AccessPolicies::WRITE) { @@ -1500,6 +1572,13 @@ impl Into for render_system::Stages { shader_stage_flags |= if self.intersects(render_system::Stages::FRAGMENT) { vk::ShaderStageFlags::FRAGMENT } else { vk::ShaderStageFlags::default() }; shader_stage_flags |= if self.intersects(render_system::Stages::COMPUTE) { vk::ShaderStageFlags::COMPUTE } else { vk::ShaderStageFlags::default() }; shader_stage_flags |= if self.intersects(render_system::Stages::MESH) { vk::ShaderStageFlags::MESH_EXT } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::TASK) { vk::ShaderStageFlags::TASK_EXT } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::RAYGEN) { vk::ShaderStageFlags::RAYGEN_KHR } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::CLOSEST_HIT) { vk::ShaderStageFlags::CLOSEST_HIT_KHR } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::ANY_HIT) { vk::ShaderStageFlags::ANY_HIT_KHR } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::INTERSECTION) { vk::ShaderStageFlags::INTERSECTION_KHR } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::MISS) { vk::ShaderStageFlags::MISS_KHR } else { vk::ShaderStageFlags::default() }; + shader_stage_flags |= if self.intersects(render_system::Stages::CALLABLE) { vk::ShaderStageFlags::CALLABLE_KHR } else { vk::ShaderStageFlags::default() }; shader_stage_flags } @@ -1602,8 +1681,8 @@ impl VulkanRenderSystem { ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION, ValidationFeatureEnableEXT::BEST_PRACTICES, // ValidationFeatureEnableEXT::GPU_ASSISTED, - ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT, - ValidationFeatureEnableEXT::DEBUG_PRINTF, + // ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT, + // ValidationFeatureEnableEXT::DEBUG_PRINTF, ]; let mut validation_features = vk::ValidationFeaturesEXT::default() @@ -1823,6 +1902,7 @@ impl VulkanRenderSystem { descriptor_sets_layouts: Vec::new(), descriptor_sets: Vec::new(), acceleration_structures: Vec::new(), + pipelines: Vec::new(), meshes: Vec::new(), command_buffers: Vec::new(), synchronizers: Vec::new(), @@ -1850,7 +1930,7 @@ impl VulkanRenderSystem { render_system::ShaderHandle(shader_module.as_raw()) } - fn create_vulkan_pipeline(&self, blocks: &[render_system::PipelineConfigurationBlocks]) -> render_system::PipelineHandle { + fn create_vulkan_pipeline(&mut self, blocks: &[render_system::PipelineConfigurationBlocks]) -> render_system::PipelineHandle { /// This function calls itself recursively to build the pipeline the pipeline states. /// This is done because this way we can "dynamically" allocate on the stack the needed structs because the recursive call keep them alive. fn build_block(vulkan_render_system: &VulkanRenderSystem, pipeline_create_info: vk::GraphicsPipelineCreateInfo<'_>, mut block_iterator: std::slice::Iter<'_, render_system::PipelineConfigurationBlocks>) -> vk::Pipeline { @@ -2066,7 +2146,11 @@ impl VulkanRenderSystem { let pipeline = build_block(self, pipeline_create_info, blocks.iter()); - render_system::PipelineHandle(pipeline.as_raw()) + let handle = render_system::PipelineHandle(self.pipelines.len() as u64); + + self.pipelines.push(Pipeline { pipeline, shader_handles: HashMap::new() }); + + handle } fn create_texture_internal(&mut self, texture: Texture, previous: Option) -> render_system::ImageHandle { @@ -2719,9 +2803,7 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> let command_buffer = self.get_command_buffer(); - for (info, geos) in infos.iter().zip(geometries) { - info.geometries(&geos); - } + let infos = infos.iter().zip(geometries.iter()).map(|(info, geos)| info.geometries(geos)).collect::>(); let build_range_infos = build_range_infos.iter().map(|build_range_info| build_range_info.as_slice()).collect::>(); @@ -2746,7 +2828,7 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> &vk::BufferDeviceAddressInfo::default() .buffer(buffer.buffer) /* .build() */ - ) + ) + vertex_buffer.offset as u64 }; let index_data_address = unsafe { @@ -2755,7 +2837,7 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> &vk::BufferDeviceAddressInfo::default() .buffer(buffer.buffer) /* .build() */ - ) + ) + index_buffer.offset as u64 }; let triangles = vk::AccelerationStructureGeometryTrianglesDataKHR::default() @@ -2819,9 +2901,7 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> } else { let command_buffer = this.get_command_buffer(); - for (info, geos) in infos.iter().zip(geometries) { - info.geometries(&geos); - } + let infos = infos.iter().zip(geometries.iter()).map(|(info, geos)| info.geometries(geos)).collect::>(); let build_range_infos = build_range_infos.iter().map(|build_range_info| build_range_info.as_slice()).collect::>(); @@ -2842,20 +2922,21 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> /// Binds a pipeline to the GPU. fn bind_raster_pipeline(&mut self, pipeline_handle: &render_system::PipelineHandle) { let command_buffer = self.get_command_buffer(); - let pipeline = vk::Pipeline::from_raw(pipeline_handle.0); + let pipeline = self.render_system.pipelines[pipeline_handle.0 as usize].pipeline; unsafe { self.render_system.device.cmd_bind_pipeline(command_buffer.command_buffer, vk::PipelineBindPoint::GRAPHICS, pipeline); } + self.pipeline_bind_point = vk::PipelineBindPoint::GRAPHICS; } fn bind_compute_pipeline(&mut self, pipeline_handle: &render_system::PipelineHandle) { let command_buffer = self.get_command_buffer(); - let pipeline = vk::Pipeline::from_raw(pipeline_handle.0); + let pipeline = self.render_system.pipelines[pipeline_handle.0 as usize].pipeline; unsafe { self.render_system.device.cmd_bind_pipeline(command_buffer.command_buffer, vk::PipelineBindPoint::COMPUTE, pipeline); } self.pipeline_bind_point = vk::PipelineBindPoint::COMPUTE; } fn bind_ray_tracing_pipeline(&mut self, pipeline_handle: &render_system::PipelineHandle) { let command_buffer = self.get_command_buffer(); - let pipeline = vk::Pipeline::from_raw(pipeline_handle.0); + let pipeline = self.render_system.pipelines[pipeline_handle.0 as usize].pipeline; unsafe { self.render_system.device.cmd_bind_pipeline(command_buffer.command_buffer, vk::PipelineBindPoint::RAY_TRACING_KHR, pipeline); } self.pipeline_bind_point = vk::PipelineBindPoint::RAY_TRACING_KHR; } @@ -3019,6 +3100,23 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> memory_barriers.push(memory_barrier); }, + render_system::Handle::TopLevelAccelerationStructure(handle) => { + // let (handle, acceleration_structure) = self.get_top_level_acceleration_structure(handle); + + let memory_barrier = if let Some(source) = self.states.get(&consumption.handle) { + vk::MemoryBarrier2::default() + .src_stage_mask(source.stage) + .src_access_mask(source.access) + } else { + vk::MemoryBarrier2::default() + .src_stage_mask(vk::PipelineStageFlags2::empty()) + .src_access_mask(vk::AccessFlags2KHR::empty()) + } + .dst_stage_mask(new_stage_mask) + .dst_access_mask(new_access_mask); + + memory_barriers.push(memory_barrier); + } _ => unimplemented!(), }; @@ -3120,12 +3218,12 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> fn trace_rays(&mut self, binding_tables: render_system::BindingTables, x: u32, y: u32, z: u32) { let command_buffer = self.get_command_buffer(); - fn make_strided_range(range: render_system::BufferStridedRange) -> vk::StridedDeviceAddressRegionKHR { + let make_strided_range = |range: render_system::BufferStridedRange| -> vk::StridedDeviceAddressRegionKHR { vk::StridedDeviceAddressRegionKHR::default() - .device_address(0) + .device_address(self.render_system.get_buffer_address(range.buffer) + range.offset as u64) .stride(range.stride) .size(range.size) - } + }; let raygen_shader_binding_tables = make_strided_range(binding_tables.raygen); let miss_shader_binding_tables = make_strided_range(binding_tables.miss); @@ -3481,14 +3579,14 @@ impl render_system::CommandBufferRecording for VulkanCommandBufferRecording<'_> let wait_semaphores = wait_for_synchronizer_handles.iter().map(|wait_for| { vk::SemaphoreSubmitInfo::default() .semaphore(self.render_system.synchronizers[wait_for.0 as usize].semaphore) - .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT | vk::PipelineStageFlags2::RAY_TRACING_SHADER_KHR) /* .build() */ }).collect::>(); let signal_semaphores = signal_synchronizer_handles.iter().map(|signal| { vk::SemaphoreSubmitInfo::default() .semaphore(self.render_system.synchronizers[signal.0 as usize].semaphore) - .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT | vk::PipelineStageFlags2::ACCELERATION_STRUCTURE_BUILD_KHR) /* .build() */ }).collect::>(); diff --git a/tests/gi.rs b/tests/gi.rs index b7cbe187..7d7debf9 100644 --- a/tests/gi.rs +++ b/tests/gi.rs @@ -21,7 +21,7 @@ fn gi() { }); let _floor: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, -0.5, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(5.0, 1.0, 2.5)), }); - let _a: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Sphere", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.5, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.4, 0.4, 0.4)), }); + let _a: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Suzanne", material_id: "white_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.5, 0.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.4, 0.4, 0.4)), }); let _b: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "red_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(-0.6, 0.17, -0.1)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.34, 0.34, 0.34)), }); let _c: EntityHandle = orchestrator.spawn(Mesh{ resource_id: "Box", material_id: "green_solid", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.5, 0.13, -0.3)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.26, 0.26, 0.26)), });