diff --git a/src/application.rs b/src/application.rs index 22f0c8e0..95925bcc 100644 --- a/src/application.rs +++ b/src/application.rs @@ -195,7 +195,7 @@ impl Application for GraphicsApplication { window_system::WindowEvents::Button { pressed, button } => { input_system.record_input_source_action(&self.mouse_device_handle, input_manager::InputSourceAction::Name("Mouse.LeftButton"), input_manager::Value::Bool(pressed)); }, - window_system::WindowEvents::MouseMove { x, y } => { + window_system::WindowEvents::MouseMove { x, y, time } => { let vec = Vector2::new((x as f32 / 1920f32 - 0.5f32) * 2f32, (y as f32 / 1080f32 - 0.5f32) * 2f32); input_system.record_input_source_action(&self.mouse_device_handle, input_manager::InputSourceAction::Name("Mouse.Position"), input_manager::Value::Vector2(vec)); }, diff --git a/src/input_manager.rs b/src/input_manager.rs index ae569ce5..1920120e 100644 --- a/src/input_manager.rs +++ b/src/input_manager.rs @@ -539,6 +539,17 @@ impl InputManager { time, }; + { + let mut i = 0; + while i < self.records.len() { + if self.records[i].input_source_handle == input_source_handle { + self.records.remove(i); + } else { + i += 1; + } + } + } + self.records.push(record); if let Value::Bool(boo) = value { @@ -561,18 +572,19 @@ impl InputManager { if records.len() == 0 { return; } - for record in records { - let actions_for_input_source = self.actions.iter().enumerate().filter(|(i, a)| { a.input_event_descriptions.iter().any(|ied| ied.input_source_handle == record.input_source_handle) }); + for (i, action) in self.actions.iter().enumerate() { + let action_records = records.iter().filter(|r| action.input_event_descriptions.iter().any(|ied| ied.input_source_handle == r.input_source_handle)); + + let most_recent_record = action_records.max_by_key(|r| r.time); - for (i, action) in actions_for_input_source { - match action.type_ { - Types::Vector2 => { - let v = if let Value::Vector2(v) = record.value.clone() { v } else { panic!("Not a vector2!") }; + if let Some(record) = most_recent_record { + let value = self.resolve_action_value_from_record(action, record); + + match value { + Value::Vector2(v) => { orchestrator.set_owned_property(orchestrator::InternalId(i as u32), Action::::value, v); } - Types::Vector3 => { - let value = self.get_action_state(ActionHandle(i as u32), &DeviceHandle(0)); - let v = if let Value::Vector3(v) = value.value { v } else { panic!("Not a vector3!") }; + Value::Vector3(v) => { orchestrator.set_owned_property(orchestrator::InternalId(i as u32), Action::::value, v); } _ => {} @@ -694,9 +706,12 @@ impl InputManager { if let Function::Sphere = function { let r = record_value; - let x = r.x; - let y = r.y; - let z = (1f32 - (x * x + y * y)).sqrt(); + let x_pi = r.x * PI; + let y_pi = r.y * PI * 0.5f32; + + let x = x_pi.sin() * y_pi.cos(); + let y = y_pi.sin(); + let z = x_pi.cos() * y_pi.cos(); let transformation = if let Value::Vector3(transformation) = mapping.mapping { transformation } else { panic!("Not implemented!"); }; diff --git a/src/lib.rs b/src/lib.rs index 87c26ebc..012733ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![feature(non_lifetime_binders)] #![feature(downcast_unchecked)] #![feature(const_mut_refs)] +#![feature(extract_if)] #![warn(missing_docs)] #![warn(missing_doc_code_examples)] diff --git a/src/math.rs b/src/math.rs index a4663b49..05f6fcad 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,6 +1,6 @@ pub fn look_at(direction: crate::Vector3) -> maths_rs::Mat4f { - let x_axis = maths_rs::normalize(maths_rs::cross(crate::Vector3::new(0f32, 1f32, 0f32), direction)); - let y_axis = maths_rs::normalize(maths_rs::cross(direction, x_axis)); + let x_axis = maths_rs::normalize(maths_rs::cross(crate::Vector3::new(0f32, 1f32, 0f32), maths_rs::normalize(direction))); + let y_axis = maths_rs::normalize(maths_rs::cross(maths_rs::normalize(direction), x_axis)); maths_rs::Mat4f::from(( maths_rs::Vec4f::from((x_axis, 0f32)), diff --git a/src/orchestrator.rs b/src/orchestrator.rs index 5ab64c90..d9ac67cc 100644 --- a/src/orchestrator.rs +++ b/src/orchestrator.rs @@ -218,7 +218,10 @@ impl Orchestrator { if ties.contains_key(&(property_function_pointer as usize)) { let ties = ties.get_mut(&(property_function_pointer as usize)).unwrap(); - ties.push(Tie { update_function, destination_system_handle: receiver_component_handle.internal_id }); + + if !ties.iter().any(|tie| tie.destination_system_handle == receiver_component_handle.internal_id) { + ties.push(Tie { update_function, destination_system_handle: receiver_component_handle.internal_id }); + } } else { let mut ties_new = Vec::new(); ties_new.push(Tie { update_function, destination_system_handle: receiver_component_handle.internal_id }); diff --git a/src/render_backend.rs b/src/render_backend.rs index 4c2c8927..a07e7cb2 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -186,6 +186,17 @@ pub struct TextureCopy { pub extent: crate::Extent, } +#[derive(Clone, Copy)] +/// Stores the information of a buffer copy. +pub struct BufferCopy { + /// The source buffer. + pub source: Buffer, + /// The destination buffer. + pub destination: Buffer, + /// The size of the copy. + pub size: usize, +} + #[derive(Clone, Copy)] /// Stores the information of a memory backed resource. pub struct MemoryBackedResourceCreationResult { @@ -210,11 +221,28 @@ bitflags! { } } +#[derive(Clone, Copy)] +pub struct TextureState { + /// The layout of the resource. + pub layout: Layouts, + /// The format of the resource. + pub format: TextureFormats, +} + #[derive(Clone, Copy)] /// Stores the information of a barrier. pub enum Barrier { /// A texture barrier. - Texture(Texture), + Texture { + source: Option, + destination: TextureState, + /// The texture of the barrier. + texture: Texture, + }, + /// A buffer barrier. + Buffer(Buffer), + /// A memory barrier. + Memory(), } bitflags! { @@ -231,6 +259,18 @@ bitflags! { const COMPUTE = 0b00000100; /// The transfer stage. const TRANSFER = 0b00001000; + /// The acceleration structure stage. + const ACCELERATION_STRUCTURE = 0b00010000; + /// The presentation stage. + const PRESENTATION = 0b00100000; + /// The host stage. + const HOST = 0b01000000; + /// The all graphics stage. + const ALL_GRAPHICS = 0b10000000; + /// The all stage. + const ALL = 0b11111111; + /// The shader read stage. + const SHADER_READ = 0b00000001; } } @@ -241,10 +281,6 @@ pub struct TransitionState { pub stage: Stages, /// The type of access that will be done on the resource by the process the operation that requires this transition. pub access: AccessPolicies, - /// The layout of the resource. - pub layout: Layouts, - /// The format of the resource. - pub format: TextureFormats, } /// Stores the information of a barrier descriptor. @@ -726,13 +762,15 @@ pub trait RenderBackend { /// * `copies` - The copies to perform. fn copy_textures(&self, command_buffer: &CommandBuffer, copies: &[TextureCopy]); + fn copy_buffers(&self, command_buffer: &CommandBuffer, copies: &[BufferCopy]); + /// Executes a command buffer. /// /// # Arguments /// * `command_buffer` - The command buffer to execute. /// * `wait_for` - The synchronizer to wait for. /// * `signal` - The synchronizer to signal. - fn execute(&self, command_buffer: &CommandBuffer, wait_for: Option<&crate::render_backend::Synchronizer>, signal: Option<&crate::render_backend::Synchronizer>, execution_completion: &crate::render_backend::Synchronizer); + fn execute(&self, command_buffer: &CommandBuffer, wait_for: &[Synchronizer], signal: &[Synchronizer], execution_completion: &crate::render_backend::Synchronizer); /// Acquires an image from a swapchain. /// diff --git a/src/render_domain.rs b/src/render_domain.rs index 49f52556..fde2612d 100644 --- a/src/render_domain.rs +++ b/src/render_domain.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use maths_rs::{prelude::{MatProjection, MatRotate3D}, Mat4f}; +use maths_rs::{prelude::{MatProjection, MatRotate3D, MatTranslate}, Mat4f}; -use crate::{resource_manager, render_system::{RenderSystem, self}, render_backend, Extent, orchestrator::{Entity, System, self, OrchestratorReference, OwnedComponent}, Vector3, camera::{self, Camera}, math}; +use crate::{resource_manager, render_system::{RenderSystem, self, FrameHandle}, render_backend, Extent, orchestrator::{Entity, System, self, OrchestratorReference, OwnedComponent}, Vector3, camera::{self, Camera}, math}; /// This the visibility buffer implementation of the world render domain. pub struct VisibilityWorldRenderDomain { @@ -17,10 +17,16 @@ pub struct VisibilityWorldRenderDomain { frames: Vec, render_finished_synchronizer: render_system::SynchronizerHandle, image_ready: render_system::SynchronizerHandle, - command_buffer: render_system::CommandBufferHandle, + render_command_buffer: render_system::CommandBufferHandle, camera_data_buffer_handle: render_system::BufferHandle, current_frame: usize, + descriptor_set_layout: render_system::DescriptorSetLayoutHandle, + descriptor_set: render_system::DescriptorSetHandle, + + transfer_synchronizer: render_system::SynchronizerHandle, + transfer_command_buffer: render_system::CommandBufferHandle, + meshes_data_buffer: render_system::BufferHandle, shaders_by_name: std::collections::HashMap, @@ -61,6 +67,16 @@ impl VisibilityWorldRenderDomain { mat4 model; }; + layout(set = 0, binding = 0) uniform CameraBuffer { + mat4 view; + mat4 projection; + mat4 view_projection; + } camera; + + layout(set = 0, binding = 1) uniform MeshBuffer { + mat4 model; + } meshes; + layout(push_constant) uniform push_constants { Camera camera; Mesh meshes; @@ -69,12 +85,15 @@ impl VisibilityWorldRenderDomain { layout(location = 0) in vec3 in_position; layout(location = 1) in vec3 in_normal; - layout(location = 0) flat out int out_instance_index; + layout(location=0) out vec3 out_position; + layout(location=1) flat out int out_instance_index; //layout(max_vertices=128, max_primitives=64) out; void main() { - gl_Position = pc.camera.view_projection * pc.meshes[gl_InstanceIndex].model * vec4(in_position, 1.0); + vec4 position = pc.camera.projection * pc.camera.view * pc.meshes[gl_InstanceIndex].model * vec4(in_position, 1.0); + gl_Position = position; out_instance_index = gl_InstanceIndex; + out_position = pc.meshes[gl_InstanceIndex].model[3].xyz; } "; @@ -84,9 +103,10 @@ impl VisibilityWorldRenderDomain { layout(row_major) uniform; layout(row_major) buffer; - layout(location = 0) flat in int in_instance_index; + layout(location=0) in vec3 in_position; + layout(location=1) flat in int in_instance_index; - layout(location = 0) out vec4 out_color; + layout(location=0) out vec4 out_color; vec4 get_debug_color(int i) { vec4 colors[16] = vec4[16]( @@ -117,19 +137,40 @@ impl VisibilityWorldRenderDomain { "; let vertex_layout = [ - crate::render_system::VertexElement{ name: "POSITION".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, - crate::render_system::VertexElement{ name: "NORMAL".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, + render_system::VertexElement{ name: "POSITION".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, + render_system::VertexElement{ name: "NORMAL".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, ]; - let vertex_shader = render_system.add_shader(crate::render_system::ShaderSourceType::GLSL, vertex_shader_code.as_bytes()); - let fragment_shader = render_system.add_shader(crate::render_system::ShaderSourceType::GLSL, fragment_shader_code.as_bytes()); + let vertex_shader = render_system.add_shader(render_system::ShaderSourceType::GLSL, vertex_shader_code.as_bytes()); + let fragment_shader = render_system.add_shader(render_system::ShaderSourceType::GLSL, fragment_shader_code.as_bytes()); let mut shaders_by_name = std::collections::HashMap::new(); - let pipeline_layout_handle = render_system.create_pipeline_layout(&[]); + let bindings = [ + render_system::DescriptorSetLayoutBinding { + binding: 0, + descriptor_type: render_backend::DescriptorType::UniformBuffer, + descriptor_count: 1, + stage_flags: render_backend::Stages::VERTEX, + immutable_samplers: None, + }, + render_system::DescriptorSetLayoutBinding { + binding: 1, + descriptor_type: render_backend::DescriptorType::UniformBuffer, + descriptor_count: 1, + stage_flags: render_backend::Stages::VERTEX, + immutable_samplers: None, + }, + ]; + + let descriptor_set_layout = render_system.create_descriptor_set_layout(&bindings); + + let descriptor_set = render_system.create_descriptor_set(&descriptor_set_layout, &bindings); + + let pipeline_layout_handle = render_system.create_pipeline_layout(&[descriptor_set_layout]); - let vertices_buffer_handle = render_system.create_buffer(1024 * 1024 * 16, render_backend::Uses::Vertex, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead); - let indices_buffer_handle = render_system.create_buffer(1024 * 1024 * 16, render_backend::Uses::Index, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead); + let vertices_buffer_handle = render_system.create_buffer(1024 * 1024 * 16, render_backend::Uses::Vertex, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::STATIC); + let indices_buffer_handle = render_system.create_buffer(1024 * 1024 * 16, render_backend::Uses::Index, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::STATIC); let render_target = render_system.create_texture(Extent::new(1920, 1080, 1), render_backend::TextureFormats::RGBAu8, render_backend::Uses::RenderTarget, render_system::DeviceAccesses::GpuRead); let depth_target = render_system.create_texture(Extent::new(1920, 1080, 1), render_backend::TextureFormats::Depth32, render_backend::Uses::DepthStencil, render_system::DeviceAccesses::GpuRead); @@ -137,14 +178,14 @@ impl VisibilityWorldRenderDomain { let attachments = [ render_system::AttachmentInfo { texture: render_target, - format: crate::render_backend::TextureFormats::RGBAu8, + format: render_backend::TextureFormats::RGBAu8, clear: Some(crate::RGBA { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }), load: false, store: true, }, render_system::AttachmentInfo { texture: depth_target, - format: crate::render_backend::TextureFormats::Depth32, + format: render_backend::TextureFormats::Depth32, clear: Some(crate::RGBA { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }), load: false, store: true, @@ -159,11 +200,29 @@ impl VisibilityWorldRenderDomain { let render_finished_synchronizer = render_system.create_synchronizer(true); let image_ready = render_system.create_synchronizer(false); - let command_buffer = render_system.create_command_buffer(); + let transfer_synchronizer = render_system.create_synchronizer(true); - let camera_data_buffer_handle = render_system.create_buffer(16 * 4 * 4, render_backend::Uses::Uniform, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead); + let render_command_buffer = render_system.create_command_buffer(); + let transfer_command_buffer = render_system.create_command_buffer(); - let meshes_data_buffer = render_system.create_buffer(16 * 4 * 4 * 16, render_backend::Uses::Uniform, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead); + let camera_data_buffer_handle = render_system.create_buffer(16 * 4 * 4, render_backend::Uses::Uniform, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::DYNAMIC); + + let meshes_data_buffer = render_system.create_buffer(16 * 4 * 4 * 16, render_backend::Uses::Uniform, render_system::DeviceAccesses::CpuWrite | render_system::DeviceAccesses::GpuRead, render_system::UseCases::DYNAMIC); + + render_system.write(&[ + render_system::DescriptorWrite { + descriptor_set, + binding: 0, + array_element: 0, + descriptor: render_system::Descriptor::Buffer(camera_data_buffer_handle), + }, + render_system::DescriptorWrite { + descriptor_set, + binding: 1, + array_element: 0, + descriptor: render_system::Descriptor::Buffer(meshes_data_buffer), + }, + ]); orchestrator.subscribe_to_class(Self::listen_to_camera); orchestrator.subscribe_to_class(Self::listen_to_mesh); @@ -175,6 +234,9 @@ impl VisibilityWorldRenderDomain { vertices_buffer: vertices_buffer_handle, indices_buffer: indices_buffer_handle, + descriptor_set_layout, + descriptor_set, + render_target, depth_target, @@ -182,11 +244,16 @@ impl VisibilityWorldRenderDomain { instance_count: 0, current_frame: 0, frames, + render_finished_synchronizer, image_ready, - command_buffer, + render_command_buffer, + camera_data_buffer_handle, + transfer_synchronizer, + transfer_command_buffer, + meshes_data_buffer, shaders_by_name, @@ -207,8 +274,8 @@ impl VisibilityWorldRenderDomain { let new_shader = render_system.add_shader(crate::render_system::ShaderSourceType::GLSL, shader_source); let vertex_layout = [ - crate::render_system::VertexElement{ name: "POSITION".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, - crate::render_system::VertexElement{ name: "NORMAL".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, + render_system::VertexElement{ name: "POSITION".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, + render_system::VertexElement{ name: "NORMAL".to_string(), format: crate::render_system::DataTypes::Float3, shuffled: false }, ]; let attachments = self.get_attachments(); @@ -232,7 +299,9 @@ impl VisibilityWorldRenderDomain { let mut render_system = render_system.get_mut(); let render_system: &mut render_system::RenderSystem = render_system.downcast_mut().unwrap(); - let meshes_data_slice = render_system.get_mut_buffer_slice(None, self.meshes_data_buffer); + let closed_frame_index = self.current_frame % 2; + + let meshes_data_slice = render_system.get_mut_buffer_slice(Some(FrameHandle(closed_frame_index as u32)), self.meshes_data_buffer); let meshes_data = [ value, @@ -275,7 +344,9 @@ impl VisibilityWorldRenderDomain { self.index_count += resource_info.index_count; } - let meshes_data_slice = render_system.get_mut_buffer_slice(None, self.meshes_data_buffer); + let closed_frame_index = self.current_frame % 2; + + let meshes_data_slice = render_system.get_mut_buffer_slice(Some(FrameHandle(closed_frame_index as u32)), self.meshes_data_buffer); let meshes_data = [ mesh.transform, @@ -301,21 +372,24 @@ impl VisibilityWorldRenderDomain { let frame_handle_option = Some(self.frames[self.current_frame % 2]); + { + let mut command_buffer_recording = render_system.create_command_buffer_recording(frame_handle_option, self.transfer_command_buffer); + + command_buffer_recording.synchronize_buffers(); + + render_system.execute(frame_handle_option, command_buffer_recording, &[], &[self.transfer_synchronizer], self.transfer_synchronizer); + } + render_system.wait(frame_handle_option, self.render_finished_synchronizer); render_system.start_frame_capture(); - let camera_data_buffer = render_system.get_mut_buffer_slice(None, self.camera_data_buffer_handle); + let camera_data_buffer = render_system.get_mut_buffer_slice(frame_handle_option, self.camera_data_buffer_handle); let camera_position = orchestrator.get_property(camera_handle, camera::Camera::position); let camera_orientation = orchestrator.get_property(camera_handle, camera::Camera::orientation); - let mut view_matrix = maths_rs::Mat4f::identity(); - view_matrix.set_column(3, maths_rs::Vec4f::new(-camera_position.x, -camera_position.y, -camera_position.z, 1f32)); - - let rotation_matrix = math::look_at(Vector3::new(camera_orientation.x, camera_orientation.y, camera_orientation.z)); - - view_matrix = rotation_matrix * view_matrix; + let view_matrix = maths_rs::Mat4f::from_translation(-camera_position) * math::look_at(camera_orientation); let projection_matrix = math::projection_matrix(35f32, 16f32 / 9f32, 0.1f32, 100f32); @@ -335,7 +409,7 @@ impl VisibilityWorldRenderDomain { let image_index = render_system.acquire_swapchain_image(frame_handle_option, self.image_ready); - let mut command_buffer_recording = render_system.create_command_buffer_recording(frame_handle_option, self.command_buffer); + let mut command_buffer_recording = render_system.create_command_buffer_recording(frame_handle_option, self.render_command_buffer); let attachments = self.get_attachments(); @@ -369,14 +443,16 @@ impl VisibilityWorldRenderDomain { command_buffer_recording.bind_index_buffer(&index_buffer_index_descriptor); - let camera_data_buffer_address = render_system.get_buffer_address(None, self.camera_data_buffer_handle); - let meshes_data_buffer_address = render_system.get_buffer_address(None, self.meshes_data_buffer); + let camera_data_buffer_address = render_system.get_buffer_address(frame_handle_option, self.camera_data_buffer_handle); + let meshes_data_buffer_address = render_system.get_buffer_address(frame_handle_option, self.meshes_data_buffer); let data = [ camera_data_buffer_address, meshes_data_buffer_address, ]; + command_buffer_recording.bind_descriptor_set(self.pipeline_layout_handle, 0, &self.descriptor_set); + command_buffer_recording.write_to_push_constant(&self.pipeline_layout_handle, 0, unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(&data)) }); command_buffer_recording.draw_indexed(self.index_count, self.instance_count, 0, 0, 0); @@ -387,14 +463,14 @@ impl VisibilityWorldRenderDomain { command_buffer_recording.copy_textures(&[(self.render_target, swapchain_texture_handle,)]); - command_buffer_recording.end(); - - render_system.execute(frame_handle_option, command_buffer_recording, Some(self.image_ready), Some(self.render_finished_synchronizer), self.render_finished_synchronizer); + render_system.execute(frame_handle_option, command_buffer_recording, &[self.transfer_synchronizer, self.image_ready], &[self.render_finished_synchronizer], self.render_finished_synchronizer); render_system.end_frame_capture(); render_system.present(frame_handle_option, image_index, self.render_finished_synchronizer); + render_system.wait(frame_handle_option, self.transfer_synchronizer); // Wait for buffers to be copied over to the GPU, or else we might overwrite them on the CPU before they are copied over + self.current_frame += 1; } diff --git a/src/render_system.rs b/src/render_system.rs index 5726a3c1..e9a04c7b 100644 --- a/src/render_system.rs +++ b/src/render_system.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::hash::Hasher; -use crate::render_backend::RenderBackend; +use crate::render_backend::{RenderBackend, Uses}; use crate::{window_system, orchestrator::System, Extent}; use crate::{render_backend, insert_return_length, render_debugger, orchestrator}; @@ -98,11 +98,12 @@ pub struct VertexElement { pub struct BufferHandle(u32); struct Buffer { + common_handle: usize, frame_handle: Option, - next: Option, buffer: crate::render_backend::Buffer, size: usize, pointer: *mut u8, + role: String, } unsafe impl Send for Buffer {} // Needed for pointer field @@ -175,7 +176,7 @@ pub struct CommandBufferRecording<'a> { frame_handle: Option, in_render_pass: bool, /// `texture_states` is used to perform resource tracking on textures.\ It is mainly useful for barriers and transitions and copies. - texture_states: HashMap, + texture_states: HashMap, } pub struct BufferDescriptor { @@ -199,7 +200,7 @@ impl CommandBufferRecording<'_> { /// Retrieves the current state of a texture.\ /// If the texture has no known state, it will return a default state with undefined layout. This is useful for the first transition of a texture.\ /// If the texture has a known state, it will return the known state. - fn get_texture_state(&self, texture_handle: TextureHandle) -> Option { + fn get_texture_state(&self, texture_handle: TextureHandle) -> Option<(render_backend::TransitionState, render_backend::TextureState)> { if let Some(state) = self.texture_states.get(&texture_handle) { Some(*state) } else { @@ -212,7 +213,7 @@ impl CommandBufferRecording<'_> { /// If the texture has a known state, it will update it with the given state. /// It will return the given state. /// This is useful to perform a transition on a texture. - fn upsert_texture_state(&mut self, texture_handle: TextureHandle, texture_state: crate::render_backend::TransitionState) -> crate::render_backend::TransitionState { + fn upsert_texture_state(&mut self, texture_handle: TextureHandle, texture_state: (render_backend::TransitionState, render_backend::TextureState)) -> (render_backend::TransitionState, render_backend::TextureState) { self.texture_states.insert(texture_handle, texture_state); texture_state } @@ -225,15 +226,23 @@ impl CommandBufferRecording<'_> { /// Starts a render pass on the GPU. /// A render pass is a particular configuration of render targets which will be used simultaneously to render certain imagery. pub fn start_render_pass(&mut self, extent: Extent, attachments: &[AttachmentInfo]) { - let barriers = attachments.iter().map(|attachment| crate::render_backend::BarrierDescriptor { - barrier: crate::render_backend::Barrier::Texture(self.render_system.get_texture(self.frame_handle, attachment.texture).texture), - source: self.get_texture_state(attachment.texture), - destination: self.upsert_texture_state(attachment.texture, crate::render_backend::TransitionState { - layout: crate::render_backend::Layouts::RenderTarget, - format: attachment.format, - stage: crate::render_backend::Stages::FRAGMENT, - access: crate::render_backend::AccessPolicies::WRITE, - }), + let barriers = attachments.iter().map(|attachment| { + let state = self.get_texture_state(attachment.texture, ); + + render_backend::BarrierDescriptor { + barrier: render_backend::Barrier::Texture{ texture: self.render_system.get_texture(self.frame_handle, attachment.texture).texture, source: state.and_then(|s| Some(s.1)), destination: render_backend::TextureState{ layout: render_backend::Layouts::RenderTarget, format: attachment.format } }, + source: self.get_texture_state(attachment.texture).and_then(|f| Some(f.0)), + destination: self.upsert_texture_state(attachment.texture, (render_backend::TransitionState { + stage: render_backend::Stages::FRAGMENT, + access: render_backend::AccessPolicies::WRITE, + }, + render_backend::TextureState { + layout: render_backend::Layouts::RenderTarget, + format: attachment.format, + } + ) + ).0, + } }).collect::>(); self.render_system.render_backend.execute_barriers(&self.render_system.command_buffers[self.command_buffer.0 as usize].command_buffer, &barriers); @@ -336,16 +345,20 @@ impl CommandBufferRecording<'_> { /// The `stage` parameter determines the new stage of the texture. /// The `access` parameter determines the new access of the texture. /// The resource states are automatically tracked. - pub fn transition_textures(&mut self, transitions: &[(TextureHandle, bool, crate::render_backend::Layouts, crate::render_backend::Stages, crate::render_backend::AccessPolicies)]) { + pub fn transition_textures(&mut self, transitions: &[(TextureHandle, bool, render_backend::Layouts, render_backend::Stages, render_backend::AccessPolicies)]) { let mut barriers = Vec::new(); for (texture_handle, keep_old, layout, stage, access) in transitions { let texture = self.render_system.get_texture(self.frame_handle, *texture_handle); - barriers.push(crate::render_backend::BarrierDescriptor { - barrier: crate::render_backend::Barrier::Texture(texture.texture), - source: if *keep_old { self.get_texture_state(*texture_handle) } else { None }, - destination: self.upsert_texture_state(*texture_handle, crate::render_backend::TransitionState { layout: *layout, format: texture.format, stage: *stage, access: *access, }), + barriers.push(render_backend::BarrierDescriptor { + barrier: render_backend::Barrier::Texture{ + source: if *keep_old { self.get_texture_state(*texture_handle).and_then(|s| Some(s.1)) } else { None }, + destination: render_backend::TextureState { layout: *layout, format: texture.format }, + texture: texture.texture + }, + source: if *keep_old { self.get_texture_state(*texture_handle).and_then(|s| Some(s.0)) } else { None }, + destination: self.upsert_texture_state(*texture_handle, (render_backend::TransitionState { stage: *stage, access: *access, }, render_backend::TextureState{ layout: *layout, format: texture.format })).0, }); } @@ -473,7 +486,7 @@ impl CommandBufferRecording<'_> { //barrier: crate::render_backend::Barrier::Texture(self.render_system.textures[surface.textures[self.frame_handle.unwrap().0 as usize].0 as usize].texture), let transitions = [ - (surface.textures[self.frame_handle.unwrap().0 as usize], true, crate::render_backend::Layouts::Present, crate::render_backend::Stages::TRANSFER, crate::render_backend::AccessPolicies::READ), + (surface.textures[self.frame_handle.unwrap().0 as usize], true, crate::render_backend::Layouts::Present, crate::render_backend::Stages::PRESENTATION, crate::render_backend::AccessPolicies::READ), ]; self.transition_textures(&transitions); @@ -486,12 +499,45 @@ impl CommandBufferRecording<'_> { pub fn bind_descriptor_set(&self, pipeline_layout: PipelineLayoutHandle, arg: u32, descriptor_set_handle: &DescriptorSetHandle) { self.render_system.render_backend.bind_descriptor_set(&self.render_system.command_buffers[self.command_buffer.0 as usize].command_buffer, &self.render_system.pipeline_layouts[pipeline_layout.0 as usize].pipeline_layout, &self.render_system.descriptor_sets[descriptor_set_handle.0 as usize].descriptor_set, arg); } + + pub(crate) fn synchronize_buffers(&self) { + let mut copies = Vec::new(); + let mut barriers = Vec::new(); + + for buffer in &self.render_system.buffers { + if buffer.role == "GPU_READ" { + let source_buffer = self.render_system.buffers.iter().find(|b| b.role == "CPU_WRITE" && b.common_handle == buffer.common_handle).unwrap(); + + copies.push( + render_backend::BufferCopy { + source: source_buffer.buffer, + destination: buffer.buffer, + size: buffer.size, + } + ); + + barriers.push(render_backend::BarrierDescriptor { + barrier: render_backend::Barrier::Memory(), + source: Some(render_backend::TransitionState { stage: render_backend::Stages::TRANSFER, access: render_backend::AccessPolicies::WRITE, }), + destination: render_backend::TransitionState { + stage: render_backend::Stages::VERTEX, + access: render_backend::AccessPolicies::READ, + }, + }); + } + } + + let command_buffer = self.render_system.command_buffers[self.command_buffer.0 as usize].command_buffer; + + self.render_system.render_backend.copy_buffers(&command_buffer, &copies); + self.render_system.render_backend.execute_barriers(&command_buffer, &barriers); + } } pub struct AllocationHandle(u64); #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct FrameHandle(u32); +pub struct FrameHandle(pub u32); struct Frame {} @@ -515,10 +561,10 @@ pub enum Descriptor { } pub struct DescriptorWrite { - descriptor_set: DescriptorSetHandle, - binding: u32, - array_element: u32, - descriptor: Descriptor, + pub descriptor_set: DescriptorSetHandle, + pub binding: u32, + pub array_element: u32, + pub descriptor: Descriptor, } pub struct DescriptorSetLayoutBinding { @@ -529,6 +575,11 @@ pub struct DescriptorSetLayoutBinding { pub immutable_samplers: Option>, } +pub enum UseCases { + STATIC, + DYNAMIC +} + /// The [`RenderSystem`] implements easy to use rendering functionality. /// It is a wrapper around the [`render_backend::RenderBackend`]. /// It is responsible for creating and managing resources. @@ -642,15 +693,17 @@ impl RenderSystem { self.meshes.push(Mesh { vertex_buffer: Buffer { + common_handle: 0, + role: "VERTEX".to_string(), frame_handle: None, - next: None, buffer: vertex_buffer_creation_result.resource, size: vertex_buffer_creation_result.size, pointer: std::ptr::null_mut(), }, index_buffer: Buffer { + common_handle: 1, + role: "INDEX".to_string(), frame_handle: None, - next: None, buffer: index_buffer_creation_result.resource, size: index_buffer_creation_result.size, pointer: std::ptr::null_mut(), @@ -757,12 +810,16 @@ impl RenderSystem { binding: descriptor_write.binding, array_element: descriptor_write.array_element, descriptor_type: match descriptor_write.descriptor { - Descriptor::Buffer(_) => crate::render_backend::DescriptorType::UniformBuffer, - Descriptor::Texture(_) => crate::render_backend::DescriptorType::SampledImage, + Descriptor::Buffer(_) => render_backend::DescriptorType::UniformBuffer, + Descriptor::Texture(_) => render_backend::DescriptorType::SampledImage, }, descriptor_info: match descriptor_write.descriptor { - Descriptor::Buffer(buffer_handle) => crate::render_backend::DescriptorInfo::Buffer{ buffer: self.buffers[buffer_handle.0 as usize].buffer, offset: 0, range: 64 }, - Descriptor::Texture(texture_handle) => crate::render_backend::DescriptorInfo::Texture{ texture: self.textures[texture_handle.0 as usize].texture_view.unwrap(), format: render_backend::TextureFormats::RGBAu8, layout: render_backend::Layouts::Texture, }, + Descriptor::Buffer(buffer_handle) => { + let buffer = &self.buffers[buffer_handle.0 as usize]; + assert!(buffer.role == "GPU_READ"); + render_backend::DescriptorInfo::Buffer{ buffer: buffer.buffer, offset: 0, range: 128 } + } + Descriptor::Texture(texture_handle) => render_backend::DescriptorInfo::Texture{ texture: self.textures[texture_handle.0 as usize].texture_view.unwrap(), format: render_backend::TextureFormats::RGBAu8, layout: render_backend::Layouts::Texture, }, }, }).collect::>(); @@ -851,59 +908,109 @@ impl RenderSystem { /// # Returns /// /// The handle of the buffer. - pub fn create_buffer(&mut self, size: usize, resource_uses: render_backend::Uses, device_accesses: DeviceAccesses) -> BufferHandle { - let buffer_handle = BufferHandle(self.buffers.len() as u32); + pub fn create_buffer(&mut self, size: usize, resource_uses: render_backend::Uses, device_accesses: DeviceAccesses, use_case: UseCases) -> BufferHandle { + let buffer_index = self.buffers.len(); - let mut previous_buffer_handle: Option = None; + let buffer_handle = BufferHandle(buffer_index as u32); if device_accesses.contains(DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead) { - for i in 0..self.frames.len() { - let buffer_handle = BufferHandle(self.buffers.len() as u32); + match use_case { + UseCases::STATIC => { + let buffer_creation_result = self.render_backend.create_buffer(size, resource_uses); - let buffer_creation_result = self.render_backend.create_buffer(size, resource_uses); + let allocation_handle = self.create_allocation(buffer_creation_result.size, resource_uses, device_accesses); - let allocation_handle = self.create_allocation(buffer_creation_result.size, resource_uses, device_accesses); + let allocation = &self.allocations[allocation_handle.0 as usize]; - let allocation = &self.allocations[allocation_handle.0 as usize]; + self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &buffer_creation_result); + + let pointer = self.render_backend.get_allocation_pointer(&allocation.allocation); + + self.buffers.push(Buffer { + common_handle: buffer_index, + role: String::from("CPU_WRITE"), + frame_handle: None, + buffer: buffer_creation_result.resource, + size: buffer_creation_result.size, + pointer, + }); + } + UseCases::DYNAMIC => { + let buffer_creation_result = self.render_backend.create_buffer(size, resource_uses | Uses::TransferDestination); + + let allocation_handle = self.create_allocation(buffer_creation_result.size, resource_uses, DeviceAccesses::GpuRead); + + let allocation = &self.allocations[allocation_handle.0 as usize]; + + self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &buffer_creation_result); + + let pointer = self.render_backend.get_allocation_pointer(&allocation.allocation); + + self.buffers.push(Buffer { + common_handle: buffer_index, + frame_handle: None, + role: String::from("GPU_READ"), + buffer: buffer_creation_result.resource, + size: buffer_creation_result.size, + pointer, + }); - self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &buffer_creation_result); + let buffer_creation_result = self.render_backend.create_buffer(size, resource_uses | Uses::TransferSource); - let pointer = self.render_backend.get_allocation_pointer(&allocation.allocation); + let allocation_handle = self.create_allocation(buffer_creation_result.size, resource_uses, DeviceAccesses::CpuWrite); - self.buffers.push(Buffer { - frame_handle: None, - next: None, - buffer: buffer_creation_result.resource, - size: buffer_creation_result.size, - pointer, - }); + let allocation = &self.allocations[allocation_handle.0 as usize]; - if let Some(previous_buffer_handle) = previous_buffer_handle { - self.buffers[previous_buffer_handle.0 as usize].next = Some(buffer_handle); - } + self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &buffer_creation_result); + + let pointer = self.render_backend.get_allocation_pointer(&allocation.allocation); - previous_buffer_handle = Some(buffer_handle); + self.buffers.push(Buffer { + common_handle: buffer_index, + frame_handle: None, + role: String::from("CPU_WRITE"), + buffer: buffer_creation_result.resource, + size: buffer_creation_result.size, + pointer, + }); + } } + } else if device_accesses.contains(DeviceAccesses::GpuWrite) { + let buffer_creation_result = self.render_backend.create_buffer(size, resource_uses); + + let allocation_handle = self.create_allocation(buffer_creation_result.size, resource_uses, device_accesses); + + let allocation = &self.allocations[allocation_handle.0 as usize]; + + self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &buffer_creation_result); + + let pointer = self.render_backend.get_allocation_pointer(&allocation.allocation); + + self.buffers.push(Buffer { + common_handle: buffer_index, + role: String::new(), + frame_handle: None, + buffer: buffer_creation_result.resource, + size: buffer_creation_result.size, + pointer, + }); } buffer_handle } pub fn get_buffer_address(&self, frame_handle: Option, buffer_handle: BufferHandle) -> u64 { - let buffer_handle = self.get_buffer_handle(frame_handle, buffer_handle); - let buffer = &self.buffers[buffer_handle.0 as usize]; + let buffer = self.buffers.iter().find(|b| b.role == "GPU_READ" && b.common_handle == buffer_handle.0 as usize).unwrap(); self.render_backend.get_buffer_address(&buffer.buffer) } - pub fn get_buffer_pointer(&mut self, frame_handle: Option, buffer_handle: BufferHandle) -> *mut u8 { - let buffer_handle = self.get_buffer_handle(frame_handle, buffer_handle); - let buffer = &mut self.buffers[buffer_handle.0 as usize]; - buffer.pointer + pub fn cheat_get_buffer_address(&self, frame_handle: Option, buffer_handle: BufferHandle) -> u64 { + let buffer = self.buffers.iter().find(|b| b.role == "CPU_WRITE" && b.common_handle == buffer_handle.0 as usize).unwrap(); + self.render_backend.get_buffer_address(&buffer.buffer) } pub fn get_buffer_slice(&mut self, frame_handle: Option, buffer_handle: BufferHandle) -> &[u8] { - let buffer_handle = self.get_buffer_handle(frame_handle, buffer_handle); - let buffer = &mut self.buffers[buffer_handle.0 as usize]; + let buffer = self.buffers.iter().find(|b| b.role == "CPU_WRITE" && b.common_handle == buffer_handle.0 as usize).unwrap(); unsafe { std::slice::from_raw_parts(buffer.pointer, buffer.size as usize) } @@ -911,8 +1018,7 @@ impl RenderSystem { // Return a mutable slice to the buffer data. pub fn get_mut_buffer_slice(&self, frame_handle: Option, buffer_handle: BufferHandle) -> &mut [u8] { - let buffer_handle = self.get_buffer_handle(frame_handle, buffer_handle); - let buffer = &self.buffers[buffer_handle.0 as usize]; + let buffer = self.buffers.iter().find(|b| b.role == "CPU_WRITE" && b.common_handle == buffer_handle.0 as usize).unwrap(); unsafe { std::slice::from_raw_parts_mut(buffer.pointer, buffer.size as usize) } @@ -1188,7 +1294,7 @@ impl RenderSystem { /// # Panics /// /// Panics if . - pub fn acquire_swapchain_image(&mut self, frame_handle: Option, synchronizer_handle: SynchronizerHandle) -> u32 { + pub fn acquire_swapchain_image(&self, frame_handle: Option, synchronizer_handle: SynchronizerHandle) -> u32 { let synchronizer = self.get_synchronizer(frame_handle, synchronizer_handle); let (index, swapchain_state) = self.render_backend.acquire_swapchain_image(&self.surface.as_ref().unwrap().swapchain, &synchronizer.synchronizer); @@ -1204,24 +1310,18 @@ impl RenderSystem { surface.textures[frame_handle.unwrap().0 as usize] } - pub fn execute(&self, frame_handle: Option, command_buffer_recording: CommandBufferRecording, wait_for_synchronizer_handle: Option, signal_synchronizer_handle: Option, execution_synchronizer_handle: SynchronizerHandle) { + pub fn execute(&self, frame_handle: Option, mut command_buffer_recording: CommandBufferRecording, wait_for_synchronizer_handles: &[SynchronizerHandle], signal_synchronizer_handles: &[SynchronizerHandle], execution_synchronizer_handle: SynchronizerHandle) { + command_buffer_recording.end(); + let command_buffer = self.get_command_buffer(frame_handle, command_buffer_recording.command_buffer); - let wait_for_synchronizer = if let Some(wait_for_synchronizer) = wait_for_synchronizer_handle { - Some(&self.get_synchronizer(frame_handle, wait_for_synchronizer).synchronizer) - } else { - None - }; + let wait_for_synchronizers = wait_for_synchronizer_handles.iter().map(|wait_for_synchronizer_handle| self.get_synchronizer(frame_handle, *wait_for_synchronizer_handle).synchronizer).collect::>(); - let signal_synchronizer = if let Some(signal_synchronizer) = signal_synchronizer_handle { - Some(&self.get_synchronizer(frame_handle, signal_synchronizer).synchronizer) - } else { - None - }; + let signal_synchronizers = signal_synchronizer_handles.iter().map(|signal_synchronizer_handle| self.get_synchronizer(frame_handle, *signal_synchronizer_handle).synchronizer).collect::>(); let execution_synchronizer = self.get_synchronizer(frame_handle, execution_synchronizer_handle); - self.render_backend.execute(&command_buffer.command_buffer, wait_for_synchronizer, signal_synchronizer, &execution_synchronizer.synchronizer); + self.render_backend.execute(&command_buffer.command_buffer, &wait_for_synchronizers, &signal_synchronizers, &execution_synchronizer.synchronizer); } pub fn present(&self, frame_handle: Option, image_index: u32, synchronizer_handle: SynchronizerHandle) { @@ -1280,17 +1380,6 @@ impl RenderSystem { let mut resource = &self.buffers[resource_handle.0 as usize]; let mut buffer_handle = resource_handle; - loop { - if resource.frame_handle == frame_handle { break; } - - if let Some(next) = resource.next { - resource = &self.buffers[next.0 as usize]; - buffer_handle = next; - } else { - panic!("Resource not found"); - } - } - buffer_handle } @@ -1325,6 +1414,22 @@ impl RenderSystem { resource } + + fn copy_buffers(&self, command_buffer_handle: CommandBufferHandle, buffer_handles: &[BufferHandle]) { + let command_buffer = self.get_command_buffer(None, command_buffer_handle); + + let copies = buffer_handles.iter().map(|buffer_handle| { + let buffer = self.get_buffer_handle(None, *buffer_handle); + let buffer = &self.buffers[buffer.0 as usize]; + crate::render_backend::BufferCopy { + source: buffer.buffer, + destination: buffer.buffer, + size: buffer.size, + } + }).collect::>(); + + self.render_backend.copy_buffers(&command_buffer.command_buffer, &copies); + } } // TODO: handle resizing @@ -1447,7 +1552,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, None, None, signal); + renderer.execute(Some(frame_handle), command_buffer_recording, &[], &[], signal); renderer.end_frame_capture(); @@ -1606,7 +1711,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, Some(image_ready), Some(render_finished_synchronizer), render_finished_synchronizer); + renderer.execute(Some(frame_handle), command_buffer_recording, &[image_ready], &[render_finished_synchronizer], render_finished_synchronizer); renderer.present(Some(frame_handle), image_index, render_finished_synchronizer); @@ -1733,7 +1838,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, None, None, render_finished_synchronizer); + renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, &[], &[], render_finished_synchronizer); renderer.end_frame_capture(); } @@ -1830,7 +1935,7 @@ mod tests { let pipeline = renderer.create_pipeline(pipeline_layout, &[&vertex_shader, &fragment_shader], &vertex_layout, &attachments); - let buffer = renderer.create_buffer(64, crate::render_backend::Uses::Storage, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead); + let buffer = renderer.create_buffer(64, crate::render_backend::Uses::Storage, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::DYNAMIC); let command_buffer_handle = renderer.create_command_buffer(); @@ -1881,7 +1986,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, None, None, render_finished_synchronizer); + renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, &[], &[], render_finished_synchronizer); renderer.end_frame_capture(); } @@ -1952,7 +2057,7 @@ mod tests { let vertex_shader = renderer.add_shader(crate::render_system::ShaderSourceType::GLSL, vertex_shader_code.as_bytes()); let fragment_shader = renderer.add_shader(crate::render_system::ShaderSourceType::GLSL, fragment_shader_code.as_bytes()); - let buffer = renderer.create_buffer(64, render_backend::Uses::Uniform, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead); + let buffer = renderer.create_buffer(64, render_backend::Uses::Uniform, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead, UseCases::DYNAMIC); let sampled_texture = renderer.create_texture(crate::Extent { width: 2, height: 2, depth: 1 }, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::Texture, crate::render_system::DeviceAccesses::CpuWrite | crate::render_system::DeviceAccesses::GpuRead); @@ -2049,7 +2154,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, None, None, signal); + renderer.execute(Some(frame_handle), command_buffer_recording, &[], &[], signal); renderer.end_frame_capture(); diff --git a/src/vulkan_render_backend.rs b/src/vulkan_render_backend.rs index 05f79a66..d56cd5a4 100644 --- a/src/vulkan_render_backend.rs +++ b/src/vulkan_render_backend.rs @@ -1,6 +1,6 @@ //! The Vulkan render backend. -use ash::{vk, Entry}; +use ash::{vk::{self, ValidationFeatureEnableEXT}, Entry}; use crate::{render_backend::{self, TextureFormats}, render_system}; @@ -39,6 +39,7 @@ pub(crate) struct Pipeline { #[derive(Clone, Copy)] pub(crate) struct CommandBuffer { + command_pool: vk::CommandPool, command_buffer: vk::CommandBuffer, } @@ -98,7 +99,6 @@ pub(crate) struct VulkanRenderBackend { surface: ash::extensions::khr::Surface, acceleration_structure: ash::extensions::khr::AccelerationStructure, ray_tracing_pipeline: ash::extensions::khr::RayTracingPipeline, - dynamic_rendering: ash::extensions::khr::DynamicRendering, } static mut counter: u32 = 0; @@ -206,6 +206,10 @@ fn to_pipeline_stage_flags(stages: crate::render_backend::Stages) -> vk::Pipelin pipeline_stage_flags |= vk::PipelineStageFlags2::TRANSFER } + if stages.contains(crate::render_backend::Stages::PRESENTATION) { + pipeline_stage_flags |= vk::PipelineStageFlags2::BOTTOM_OF_PIPE + } + pipeline_stage_flags } @@ -216,6 +220,9 @@ fn to_access_flags(accesses: crate::render_backend::AccessPolicies, stages: crat if stages.intersects(crate::render_backend::Stages::TRANSFER) { access_flags |= vk::AccessFlags2::TRANSFER_READ } + if stages.intersects(render_backend::Stages::PRESENTATION) { + access_flags |= vk::AccessFlags2::NONE + } } if accesses.contains(crate::render_backend::AccessPolicies::WRITE) { @@ -309,26 +316,28 @@ impl VulkanRenderBackend { ash::extensions::khr::XcbSurface::NAME.as_ptr(), ]; + let enabled_validation_features = [ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION, ValidationFeatureEnableEXT::BEST_PRACTICES]; + + let mut validation_features = vk::ValidationFeaturesEXT::default() + .enabled_validation_features(&enabled_validation_features); + let instance_create_info = vk::InstanceCreateInfo::default() + .push_next(&mut validation_features/* .build() */) .application_info(&application_info) .enabled_layer_names(&layer_names) .enabled_extension_names(&extension_names) /* .build() */; - let instance = unsafe { entry.create_instance(&instance_create_info, None).expect("No instance") }; let debug_utils = ash::extensions::ext::DebugUtils::new(&entry, &instance); let debug_utils_create_info = vk::DebugUtilsMessengerCreateInfoEXT::default() .message_severity( - vk::DebugUtilsMessageSeverityFlagsEXT::WARNING - | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR, + vk::DebugUtilsMessageSeverityFlagsEXT::INFO | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR, ) .message_type( - vk::DebugUtilsMessageTypeFlagsEXT::GENERAL - | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION - | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, + vk::DebugUtilsMessageTypeFlagsEXT::GENERAL | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, ) .pfn_user_callback(Some(vulkan_debug_utils_callback)); @@ -341,6 +350,11 @@ impl VulkanRenderBackend { { let best_physical_device = crate::render_system::select_by_score(physical_devices.as_slice(), |physical_device| { let properties = unsafe { instance.get_physical_device_properties(*physical_device) }; + let features = unsafe { instance.get_physical_device_features(*physical_device) }; + + if features.sample_rate_shading == vk::FALSE { + return 0; + } let mut device_score = 0 as i64; @@ -377,13 +391,12 @@ impl VulkanRenderBackend { let device_extension_names = [ ash::extensions::khr::Swapchain::NAME.as_ptr(), - ash::extensions::khr::DynamicRendering::NAME.as_ptr(), ]; let queue_create_infos = [vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index) - .queue_priorities(&[1.0]) - /* .build() */]; + .queue_family_index(queue_family_index) + .queue_priorities(&[1.0]) + /* .build() */]; let mut buffer_device_address_features = vk::PhysicalDeviceBufferDeviceAddressFeatures::default().buffer_device_address(true); let mut dynamic_rendering_features = vk::PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true); @@ -412,7 +425,6 @@ impl VulkanRenderBackend { let acceleration_structure = ash::extensions::khr::AccelerationStructure::new(&instance, &device); let ray_tracing_pipeline = ash::extensions::khr::RayTracingPipeline::new(&instance, &device); - let dynamic_rendering = ash::extensions::khr::DynamicRendering::new(&instance, &device); let swapchain = ash::extensions::khr::Swapchain::new(&instance, &device); let surface = ash::extensions::khr::Surface::new(&entry, &instance); @@ -430,7 +442,6 @@ impl VulkanRenderBackend { surface, acceleration_structure, ray_tracing_pipeline, - dynamic_rendering, } } } @@ -567,7 +578,6 @@ impl render_backend::RenderBackend for VulkanRenderBackend { fn create_command_buffer(&self) -> crate::render_backend::CommandBuffer { let command_pool_create_info = vk::CommandPoolCreateInfo::default() - .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) .queue_family_index(self.queue_family_index) /* .build() */; @@ -583,6 +593,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { crate::render_backend::CommandBuffer { vulkan_command_buffer: CommandBuffer { + command_pool, command_buffer: command_buffer[0], }, } @@ -883,6 +894,12 @@ impl render_backend::RenderBackend for VulkanRenderBackend { | if resource_uses.contains(render_backend::Uses::Uniform) { vk::BufferUsageFlags::UNIFORM_BUFFER } else { vk::BufferUsageFlags::empty() } | + if resource_uses.contains(render_backend::Uses::Storage) { vk::BufferUsageFlags::STORAGE_BUFFER } else { vk::BufferUsageFlags::empty() } + | + if resource_uses.contains(render_backend::Uses::TransferSource) { vk::BufferUsageFlags::TRANSFER_SRC } else { vk::BufferUsageFlags::empty() } + | + if resource_uses.contains(render_backend::Uses::TransferDestination) { vk::BufferUsageFlags::TRANSFER_DST } else { vk::BufferUsageFlags::empty() } + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS /*We allways use this feature so include constantly*/ ) /* .build() */; @@ -1157,7 +1174,9 @@ impl render_backend::RenderBackend for VulkanRenderBackend { }).collect::>() } - fn begin_command_buffer_recording(&self, command_buffer: &crate::render_backend::CommandBuffer) { + fn begin_command_buffer_recording(&self, command_buffer: &render_backend::CommandBuffer) { + unsafe { self.device.reset_command_pool(command_buffer.vulkan_command_buffer.command_pool, vk::CommandPoolResetFlags::empty()); } + let command_buffer_begin_info = vk::CommandBufferBeginInfo::default() .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT) /* .build() */; @@ -1213,13 +1232,13 @@ impl render_backend::RenderBackend for VulkanRenderBackend { } ]; - unsafe { self.dynamic_rendering.cmd_begin_rendering(command_buffer.vulkan_command_buffer.command_buffer, &rendering_info); } + unsafe { self.device.cmd_begin_rendering(command_buffer.vulkan_command_buffer.command_buffer, &rendering_info); } unsafe { self.device.cmd_set_viewport(command_buffer.vulkan_command_buffer.command_buffer, 0, &viewports); } unsafe { self.device.cmd_set_scissor(command_buffer.vulkan_command_buffer.command_buffer, 0, &[render_area]); } } fn end_render_pass(&self, command_buffer: &crate::render_backend::CommandBuffer) { - unsafe { self.dynamic_rendering.cmd_end_rendering(command_buffer.vulkan_command_buffer.command_buffer); } + unsafe { self.device.cmd_end_rendering(command_buffer.vulkan_command_buffer.command_buffer); } } fn bind_shader(&self, _command_buffer: &crate::render_backend::CommandBuffer, _shader: &crate::render_backend::Shader) { @@ -1255,30 +1274,67 @@ impl render_backend::RenderBackend for VulkanRenderBackend { fn execute_barriers(&self, command_buffer: &crate::render_backend::CommandBuffer, barriers: &[crate::render_backend::BarrierDescriptor]) { let mut image_memory_barriers = Vec::new(); + let mut buffer_memory_barriers = Vec::new(); + let mut memory_barriers = Vec::new(); for barrier in barriers { match barrier.barrier { - // crate::render_backend::Barrier::BufferBarrier(buffer_barrier) => { - // let buffer_memory_barrier = vk::BufferMemoryBarrier2KHR::default() - // .src_stage_mask(to_pipeline_stage_flags(buffer_barrier.source_stage)) - // .dst_stage_mask(to_pipeline_stage_flags(buffer_barrier.destination_stage)) - // .src_access_mask(to_access_flags(buffer_barrier.source_access)) - // .dst_access_mask(to_access_flags(buffer_barrier.destination_access)) - // .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - // .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - // .buffer(unsafe { buffer_barrier.buffer.vulkan_buffer.buffer }) - // .offset(0) - // .size(vk::WHOLE_SIZE) - // /* .build() */; - - // unsafe { self.device.cmd_pipeline_barrier2(command_buffer.vulkan_command_buffer.command_buffer, &vk::DependencyInfo::default().buffer_memory_barriers(&[buffer_memory_barrier])) }; - // }, - crate::render_backend::Barrier::Texture(texture_barrier) => { - let image_memory_barrier = if let Some(source) = barrier.source { - vk::ImageMemoryBarrier2KHR::default() - .old_layout(texture_format_and_resource_use_to_image_layout(source.format, source.layout, Some(source.access))) + render_backend::Barrier::Buffer(buffer_barrier) => { + let buffer_memory_barrier = if let Some(source) = barrier.source { + vk::BufferMemoryBarrier2KHR::default() .src_stage_mask(to_pipeline_stage_flags(source.stage)) .src_access_mask(to_access_flags(source.access, source.stage)) + .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) + } else { + vk::BufferMemoryBarrier2KHR::default() + .src_stage_mask(vk::PipelineStageFlags2::empty()) + .src_access_mask(vk::AccessFlags2KHR::empty()) + .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) + } + .dst_stage_mask(to_pipeline_stage_flags(barrier.destination.stage)) + .dst_access_mask(to_access_flags(barrier.destination.access, barrier.destination.stage)) + .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) + .buffer(unsafe { buffer_barrier.vulkan_buffer.buffer }) + .offset(0) + .size(vk::WHOLE_SIZE) + /* .build() */; + + buffer_memory_barriers.push(buffer_memory_barrier); + }, + render_backend::Barrier::Memory() => { + let memory_barrier = if let Some(source) = barrier.source { + vk::MemoryBarrier2::default() + //.src_stage_mask(to_pipeline_stage_flags(source.stage)) + //.src_access_mask(to_access_flags(source.access, source.stage)) + .src_stage_mask(vk::PipelineStageFlags2::TRANSFER) + .src_access_mask(vk::AccessFlags2::TRANSFER_WRITE) + + } else { + vk::MemoryBarrier2::default() + .src_stage_mask(vk::PipelineStageFlags2::empty()) + .src_access_mask(vk::AccessFlags2KHR::empty()) + } + //.dst_stage_mask(to_pipeline_stage_flags(barrier.destination.stage)) + //.dst_access_mask(to_access_flags(barrier.destination.access, barrier.destination.stage)) + .dst_stage_mask(vk::PipelineStageFlags2::VERTEX_SHADER) + .dst_access_mask(vk::AccessFlags2::MEMORY_READ) + /* .build() */; + + memory_barriers.push(memory_barrier); + } + render_backend::Barrier::Texture{ source, destination, texture } => { + let image_memory_barrier = if let Some(barrier_source) = barrier.source { + if let Some(texture_source) = source { + vk::ImageMemoryBarrier2KHR::default() + .old_layout(texture_format_and_resource_use_to_image_layout(texture_source.format, texture_source.layout, Some(barrier_source.access))) + .src_stage_mask(to_pipeline_stage_flags(barrier_source.stage)) + .src_access_mask(to_access_flags(barrier_source.access, barrier_source.stage)) + } else { + vk::ImageMemoryBarrier2KHR::default() + .old_layout(vk::ImageLayout::UNDEFINED) + .src_stage_mask(vk::PipelineStageFlags2::empty()) + .src_access_mask(vk::AccessFlags2KHR::empty()) + } } else { vk::ImageMemoryBarrier2KHR::default() .old_layout(vk::ImageLayout::UNDEFINED) @@ -1286,13 +1342,13 @@ impl render_backend::RenderBackend for VulkanRenderBackend { .src_access_mask(vk::AccessFlags2KHR::empty()) } .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .new_layout(texture_format_and_resource_use_to_image_layout(barrier.destination.format, barrier.destination.layout, Some(barrier.destination.access))) + .new_layout(texture_format_and_resource_use_to_image_layout(destination.format, destination.layout, Some(barrier.destination.access))) .dst_stage_mask(to_pipeline_stage_flags(barrier.destination.stage)) .dst_access_mask(to_access_flags(barrier.destination.access, barrier.destination.stage)) .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .image(unsafe { texture_barrier.vulkan_texture.image }) + .image(unsafe { texture.vulkan_texture.image }) .subresource_range(vk::ImageSubresourceRange { - aspect_mask: if barrier.destination.format != render_backend::TextureFormats::Depth32 { vk::ImageAspectFlags::COLOR } else { vk::ImageAspectFlags::DEPTH }, + aspect_mask: if destination.format != render_backend::TextureFormats::Depth32 { vk::ImageAspectFlags::COLOR } else { vk::ImageAspectFlags::DEPTH }, base_mip_level: 0, level_count: vk::REMAINING_MIP_LEVELS, base_array_layer: 0, @@ -1307,12 +1363,34 @@ impl render_backend::RenderBackend for VulkanRenderBackend { let dependency_info = vk::DependencyInfo::default() .image_memory_barriers(&image_memory_barriers) + .buffer_memory_barriers(&buffer_memory_barriers) + .memory_barriers(&memory_barriers) .dependency_flags(vk::DependencyFlags::BY_REGION) /* .build() */; unsafe { self.device.cmd_pipeline_barrier2(command_buffer.vulkan_command_buffer.command_buffer, &dependency_info) }; } + fn copy_buffers(&self, command_buffer: &render_backend::CommandBuffer, copies: &[render_backend::BufferCopy]) { + for copy in copies { + let buffer_copy = vk::BufferCopy2KHR::default() + .src_offset(0) + .dst_offset(0) + .size(copy.size as u64) + /* .build() */; + + let regions = [buffer_copy]; + + let copy_buffer_info = vk::CopyBufferInfo2KHR::default() + .src_buffer(unsafe { copy.source.vulkan_buffer.buffer }) + .dst_buffer(unsafe { copy.destination.vulkan_buffer.buffer }) + .regions(®ions) + /* .build() */; + + unsafe { self.device.cmd_copy_buffer2(command_buffer.vulkan_command_buffer.command_buffer, ©_buffer_info); } + } + } + fn copy_textures(&self, command_buffer: &crate::render_backend::CommandBuffer, copies: &[crate::render_backend::TextureCopy]) { for copy in copies { if copy.source_format == copy.destination_format { @@ -1384,7 +1462,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { } } - fn execute(&self, command_buffer: &crate::render_backend::CommandBuffer, wait_for: Option<&crate::render_backend::Synchronizer>, signal: Option<&crate::render_backend::Synchronizer>, execution_completion: &crate::render_backend::Synchronizer) { + fn execute(&self, command_buffer: &crate::render_backend::CommandBuffer, wait_for: &[render_backend::Synchronizer], signal: &[render_backend::Synchronizer], execution_completion: &crate::render_backend::Synchronizer) { let command_buffers = [unsafe { command_buffer.vulkan_command_buffer.command_buffer }]; let command_buffer_infos = [ @@ -1395,26 +1473,21 @@ impl render_backend::RenderBackend for VulkanRenderBackend { /* .build() */ ]; - let wait_semaphores = if let Some(wait_for) = wait_for { - vec![ - vk::SemaphoreSubmitInfo::default() - .semaphore(unsafe { wait_for.vulkan_synchronizer.semaphore }) - .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) - /* .build() */ - ] - } else { - vec![] - }; + // TODO: Take actual stage masks - let signal_semaphores = if let Some(signal) = signal { - vec![ - vk::SemaphoreSubmitInfo::default() - .semaphore(unsafe { signal.vulkan_synchronizer.semaphore }) + let wait_semaphores = wait_for.iter().map(|wait_for| { + vk::SemaphoreSubmitInfo::default() + .semaphore(unsafe { wait_for.vulkan_synchronizer.semaphore }) + .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) /* .build() */ - ] - } else { - vec![] - }; + }).collect::>(); + + let signal_semaphores = signal.iter().map(|signal| { + vk::SemaphoreSubmitInfo::default() + .semaphore(unsafe { signal.vulkan_synchronizer.semaphore }) + .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + /* .build() */ + }).collect::>(); let submit_info = vk::SubmitInfo2::default() .command_buffer_infos(&command_buffer_infos) diff --git a/src/window_system.rs b/src/window_system.rs index 867cbb44..ccbc9240 100644 --- a/src/window_system.rs +++ b/src/window_system.rs @@ -230,6 +230,7 @@ pub enum WindowEvents { MouseMove { x: u32, y: u32, + time: u64, }, } @@ -554,7 +555,7 @@ impl Window { let x = ev.event_x(); let y = ev.event_y(); - Some(WindowEvents::MouseMove { x: x as u32, y: 1080 - (y as u32) }) + Some(WindowEvents::MouseMove { x: x as u32, y: 1080 - (y as u32), time: ev.time() as u64 }) }, _ => { None } }; diff --git a/tests/gallery_shooter.rs b/tests/gallery_shooter.rs index e88b0808..b40aa22a 100644 --- a/tests/gallery_shooter.rs +++ b/tests/gallery_shooter.rs @@ -1,7 +1,7 @@ #![feature(const_mut_refs)] use byte_engine::{application::Application, Vec3f, input_manager, Vector3, orchestrator::{Component, EntityHandle, self}, render_domain::{Mesh, MeshParameters}, Vector2, math}; -use maths_rs::prelude::{MatTranslate, MatScale}; +use maths_rs::prelude::{MatTranslate, MatScale, MatInverse}; #[ignore] #[test] @@ -24,9 +24,10 @@ fn gallery_shooter() { let scale = maths_rs::Mat4f::from_scale(Vec3f::new(0.1, 0.1, 0.1)); - let duck_1: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(-0.5, 0.5, 2.0)) * scale, }); - let duck_2: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.5, 2.0)) * scale, }); - let duck_3: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.5, 0.5, 2.0)) * scale, }); + let duck_1: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.0, 2.0)) * scale, }); + let duck_2: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(2.0, 0.0, 0.0)) * scale, }); + let duck_3: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(-2.0, 0.0, 0.0)) * scale, }); + let duck_4: EntityHandle = orchestrator.spawn_component(MeshParameters{ resource_id: "Box.gltf", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.0, -2.0)) * scale, }); app.do_loop(); @@ -76,19 +77,15 @@ impl Player { } fn set_lookaround(&mut self, orchestrator: orchestrator::OrchestratorReference, direction: Vec3f) { - let old_direction = orchestrator.get_property(&self.camera, byte_engine::camera::Camera::orientation); - let new_direction = direction; - - let direction_delta = new_direction - old_direction; - - let rotation = math::look_at(Vector3::new(-new_direction.x, -new_direction.y, new_direction.z)); - let mut transform = maths_rs::Mat4f::identity(); - transform *= rotation; - transform *= maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.0, 0.9f32)); + transform *= maths_rs::Mat4f::from_translation(direction); + transform *= math::look_at(direction).inverse(); + transform *= maths_rs::Mat4f::from_translation(Vec3f::new(0.25, -0.15, 0.0f32)); transform *= maths_rs::Mat4f::from_scale(Vec3f::new(0.05, 0.03, 0.2)); + println!("Position {:?}", Vec3f::new(transform[3], transform[7], transform[11])); + orchestrator.set_property(&self.mesh, Mesh::transform, transform); } } \ No newline at end of file