diff --git a/.cargo/config.toml b/.cargo/config.toml index 3b5ff24a..6eb1bb15 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,2 @@ [build] -rustflags = ["-C", "link-arg=-fuse-ld=mold"] \ No newline at end of file +rustflags = ["-Clink-arg=-fuse-ld=mold", "-Ctarget-feature=+avx2"] \ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7484239f..d8c9d681 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -24,7 +24,5 @@ jobs: vulkan-query-version: latest vulkan-components: Vulkan-Headers, Vulkan-Loader vulkan-use-cache: true - - name: Build - run: cargo build - - name: Run tests - run: cargo test --verbose -- --test-threads 1 + - name: Build & Run tests + run: cargo test --verbose -- --test-threads 1 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6857748b..7903cb19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ dependencies = [ [[package]] name = "ash" version = "0.37.0+1.3.254" -source = "git+https://github.com/ash-rs/ash?branch=master#eb1712944e6fc860168297741532bc1c85b8f09e" +source = "git+https://github.com/ash-rs/ash?branch=master#a0f8b9cf3ef5fb4eb766e51b54e90c50df405d5a" dependencies = [ "libloading", ] @@ -144,6 +144,7 @@ dependencies = [ "intel_tex_2", "json", "libdeflater", + "maths-rs", "notify", "png", "polodb_core", @@ -664,6 +665,12 @@ dependencies = [ "twox-hash", ] +[[package]] +name = "maths-rs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86562883d365f2b08fcf6bdfe9b64a9b6758c9a955be64c14353c012d6528669" + [[package]] name = "memchr" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 7f348630..24ec2eaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] xcb = { version = "1.2.1", features=['xtest'] } -# ash = { version = "0.37.2", features=['linked'] } +# ash = { version = "0.37.3", features=['linked'] } ash = { git = "https://github.com/ash-rs/ash", branch = "master", features=['linked'] } futures = "0.3.28" shaderc = "0.8.2" @@ -22,6 +22,13 @@ notify = "6.0.0" serde_json = "1.0.96" dual_quaternion = "0.2.0" cgmath = "0.18.0" +maths-rs = "0.2.3" [profile.dev] incremental = true +lto="off" + +[profile.release] +lto="fat" +panic="abort" +codegen-units = 1 diff --git a/src/application.rs b/src/application.rs index 4c49570f..b428ff29 100644 --- a/src/application.rs +++ b/src/application.rs @@ -19,12 +19,16 @@ pub trait Application { /// Returns the name of the application. fn get_name(&self) -> String; + /// Performs a tick of the application. fn tick(&mut self); /// Deinitializes the application. fn deinitialize(&mut self); } +/// The most basic implementation of the application trait. +/// It has no functionality and is only used as a base for other implementations. +/// It just stores the name of the application. pub struct BaseApplication { name: String, } @@ -54,6 +58,8 @@ impl Application for BaseApplication { use crate::{orchestrator, window_system, render_system}; +/// An orchestrated application is an application that uses the orchestrator to manage systems. +/// It is the recommended way to create a simple application. pub struct OrchestratedApplication { application: BaseApplication, orchestrator: orchestrator::Orchestrator, @@ -96,16 +102,20 @@ impl Application for OrchestratedApplication { } impl OrchestratedApplication { + /// Flags the application for closing. pub fn close(&mut self) { self.close = true; } - pub fn get_name(&self) -> String { self.application.get_name() } - + /// Returns a reference to the orchestrator. pub fn get_orchestrator(&self) -> &orchestrator::Orchestrator { &self.orchestrator } + + /// Returns a mutable reference to the orchestrator. pub fn get_mut_orchestrator(&mut self) -> &mut orchestrator::Orchestrator { &mut self.orchestrator } } +/// A graphics application is the base for all applications that use the graphics functionality of the engine. +/// It uses the orchestrated application as a base and adds rendering and windowing functionality. pub struct GraphicsApplication { application: OrchestratedApplication, file_tracker: crate::file_tracker::FileTracker, @@ -149,9 +159,13 @@ impl Application for GraphicsApplication { } impl GraphicsApplication { + /// Flags the application for closing. pub fn close(&mut self) { self.application.close(); } + + /// Returns a reference to the orchestrator. + pub fn get_orchestrator(&self) -> &orchestrator::Orchestrator { &self.application.get_orchestrator() } } #[cfg(test)] diff --git a/src/beshader_compiler.rs b/src/beshader_compiler.rs index 5f1a9c71..9531b24a 100644 --- a/src/beshader_compiler.rs +++ b/src/beshader_compiler.rs @@ -5,12 +5,12 @@ //! # Example beShader //! //! ```glsl -//! struct Light { +//! Light: struct { //! position: vec3, //! color: vec3, //! } //! -//! fn main() -> void { +//! main: fn () -> void { //! gl_Position = vec4(0.0, 0.0, 0.0, 1.0); //! } //! ``` diff --git a/src/input_manager.rs b/src/input_manager.rs index ea896fa7..20853d2e 100644 --- a/src/input_manager.rs +++ b/src/input_manager.rs @@ -7,8 +7,8 @@ //! An input source is a source of input on a device class/type. Such as the UP key on a keyboard or the left trigger on a gamepad. //! ## Input Destination //! An input destination is a destination of input on a device. Such as the rumble motors on a gamepad. -//! ## Input Event -//! An input event is an application specific event that is triggered by a combination of input sources. +//! ## Action +//! An action is an application specific event that is triggered by a combination of input sources. //! For example move sideways is triggered by the left and right keys being pressed. //! //! # Usage @@ -160,7 +160,8 @@ pub enum Function { Linear, } -pub struct InputEventDescription { +/// An action binding description is a description of how an input source is mapped to a value for an action. +pub struct ActionBindingDescription { pub input_source: InputSourceAction, pub mapping: Value, pub function: Option @@ -214,8 +215,6 @@ enum Types { struct InputEvent { name: String, type_: Types, - min: Value, - max: Value, input_event_descriptions: Vec, /// The stack is a list of input source records that simultaneous, connected, and currently active. /// The stack is used to determine the value of the input event. @@ -255,7 +254,7 @@ pub struct InputEventState { /// The device that triggered the input event. device_handle: DeviceHandle, /// The handle to the input event. - input_event_handle: InputEventHandle, + input_event_handle: ActionHandle, /// The value of the input event. value: Value, } @@ -274,7 +273,7 @@ pub struct DeviceHandle(u32); #[derive(Copy, Clone, PartialEq, Eq, Hash)] /// Handle to an input event. -pub struct InputEventHandle(u32); +pub struct ActionHandle(u32); /// The input manager is responsible for managing input devices and input events. pub struct InputManager { @@ -282,7 +281,7 @@ pub struct InputManager { input_sources: Vec, devices: Vec, records: Vec, - input_events: Vec, + actions: Vec, } impl InputManager { @@ -293,7 +292,7 @@ impl InputManager { input_sources: Vec::new(), devices: Vec::new(), records: Vec::new(), - input_events: Vec::new(), + actions: Vec::new(), } } @@ -491,23 +490,10 @@ impl InputManager { /// - 3D: Returns a 3D point when the RGBA color is reached. /// - Quaternion: Returns a quaternion when the RGBA color is reached. /// - RGBA: Returns the RGBA color. - fn register_input_event(&mut self, name: &str, min: Value, max: Value, input_events: &[InputEventDescription]) -> InputEventHandle { - let type_ = match (min, max) { - (Value::Bool(_), Value::Bool(_)) => Types::Bool, - (Value::Unicode(_), Value::Unicode(_)) => Types::Unicode, - (Value::Float(_), Value::Float(_)) => Types::Float, - (Value::Int(_), Value::Int(_)) => Types::Int, - (Value::Rgba(_), Value::Rgba(_)) => Types::Rgba, - (Value::Vector2(_), Value::Vector2(_)) => Types::Vector2, - (Value::Vector3(_), Value::Vector3(_)) => Types::Vector3, - (Value::Quaternion(_), Value::Quaternion(_)) => Types::Quaternion, - _ => panic!("Min and max value types do not match!"), - }; - + fn create_action(&mut self, name: &str, type_: Types, input_events: &[ActionBindingDescription]) -> ActionHandle { let input_event = InputEvent { name: name.to_string(), type_, - min, max, input_event_descriptions: input_events.iter().map(|input_event| { InputSourceMapping { input_source_handle: self.to_input_source_handle(&input_event.input_source), @@ -518,7 +504,7 @@ impl InputManager { stack: Vec::new(), }; - InputEventHandle(insert_return_length(&mut self.input_events, input_event) as u32) + ActionHandle(insert_return_length(&mut self.actions, input_event) as u32) } /// Records an input source action. @@ -570,7 +556,7 @@ impl InputManager { self.records.push(record); if let Value::Bool(boo) = value { - let input_events = self.input_events.iter_mut().filter(|ie| ie.input_event_descriptions.iter().any(|ied| ied.input_source_handle == input_source_handle)); + let input_events = self.actions.iter_mut().filter(|ie| ie.input_event_descriptions.iter().any(|ied| ied.input_source_handle == input_source_handle)); if boo { for input_event in input_events { @@ -621,8 +607,8 @@ impl InputManager { } /// Gets the value of an input event. - pub fn get_input_event_value(&self, input_event_handle: InputEventHandle, device_handle: &DeviceHandle) -> InputEventState { - let input_event = &self.input_events[input_event_handle.0 as usize]; + pub fn get_action_value(&self, input_event_handle: ActionHandle, device_handle: &DeviceHandle) -> InputEventState { + let input_event = &self.actions[input_event_handle.0 as usize]; let input_sources_values = input_event.input_event_descriptions.iter().map(|input_event_description| { (self.get_input_source_record(device_handle, InputSourceAction::Handle(input_event_description.input_source_handle)), input_event_description.input_source_handle, input_event_description) @@ -632,11 +618,6 @@ impl InputManager { let value = match input_event.type_ { Types::Float => { - let (min, max) = match (input_event.min, input_event.max) { - (Value::Float(min), Value::Float(max)) => (min, max), - _ => panic!("Min and max value types do not match!"), - }; - let (input_source_value, input_source_mapping_value) = if let Some(last) = input_event.stack.last() { if let Value::Bool(value) = last.value { let event_description_for_input_source = input_event.input_event_descriptions.iter().find(|description| description.input_source_handle == last.input_source_handle).unwrap(); @@ -1098,13 +1079,13 @@ mod tests { declare_keyboard_input_device_class(&mut input_manager); - let input_event = input_manager.register_input_event("MoveLongitudinally", Value::Float(-1f32), Value::Float(1f32), &[ - InputEventDescription { + input_manager.create_action("MoveLongitudinally", Types::Float, &[ + ActionBindingDescription { input_source: InputSourceAction::Name("Keyboard.Up"), mapping: Value::Float(1.0), function: Some(Function::Linear), }, - InputEventDescription { + ActionBindingDescription { input_source: InputSourceAction::Name("Keyboard.Down"), mapping: Value::Float(-1.0), function: Some(Function::Linear), @@ -1117,13 +1098,13 @@ mod tests { let device_class_handle = declare_keyboard_input_device_class(&mut input_manager); - let input_event = input_manager.register_input_event("MoveLongitudinally", Value::Float(-1f32), Value::Float(1f32), &[ - InputEventDescription { + let input_event = input_manager.create_action("MoveLongitudinally", Types::Float, &[ + ActionBindingDescription { input_source: InputSourceAction::Name("Keyboard.Up"), mapping: Value::Float(1.0), function: Some(Function::Linear), }, - InputEventDescription { + ActionBindingDescription { input_source: InputSourceAction::Name("Keyboard.Down"), mapping: Value::Float(-1.0), function: Some(Function::Linear), @@ -1131,46 +1112,46 @@ mod tests { let device_handle = input_manager.create_device(&device_class_handle); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.device_handle, device_handle); assert_eq!(value.value, Value::Float(0f32)); // Default value must be 0. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Up"), Value::Bool(true)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(1.0)); // Must be 1.0 after recording. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Up"), Value::Bool(false)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(0.0)); // Must be 0.0 after recording. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(true)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(-1.0)); // Must be -1.0 after recording. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(false)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(0.0)); // Must be 0.0 after recording. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Up"), Value::Bool(true)); input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(true)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(-1.0)); // Must be -1.0 after recording down after up while up is still pressed. input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Up"), Value::Bool(false)); input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(false)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(0.0)); // Must be 0.0 after recording @@ -1178,7 +1159,7 @@ mod tests { input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(true)); input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Up"), Value::Bool(false)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(-1.0)); // Must be -1.0 after releasing up while down down is still pressed. @@ -1186,7 +1167,7 @@ mod tests { input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(true)); input_manager.record_input_source_action(&device_handle, InputSourceAction::Name("Keyboard.Down"), Value::Bool(false)); - let value = input_manager.get_input_event_value(input_event, &device_handle); + let value = input_manager.get_action_value(input_event, &device_handle); assert_eq!(value.value, Value::Float(1.0)); // Must be 1.0 after releasing down while up is still pressed. } diff --git a/src/lib.rs b/src/lib.rs index ad6c6a71..25d125a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,9 @@ #![feature(int_roundings)] #![feature(ptr_sub_ptr)] #![feature(iter_advance_by)] +#![feature(inherent_associated_types)] +#![feature(downcast_unchecked)] +#![feature(const_mut_refs)] #![warn(missing_docs)] #![warn(missing_doc_code_examples)] @@ -22,6 +25,10 @@ pub mod beshader_compiler; pub mod executor; //pub mod gdeflate; +use maths_rs; + +pub use maths_rs::Vec2f; + #[derive(Debug, Clone, Copy, PartialEq)] pub struct Extent { pub width: u32, diff --git a/src/orchestrator.rs b/src/orchestrator.rs index e47d2ae7..8c37df4b 100644 --- a/src/orchestrator.rs +++ b/src/orchestrator.rs @@ -37,6 +37,8 @@ // TODO: implement Drop +use std::collections::HashMap; + /// System handle is a handle to a system in an [`Orchestrator`] pub struct SystemHandle(u32); @@ -46,17 +48,39 @@ pub trait System { fn as_any(&self) -> &dyn std::any::Any; } +pub struct ComponentHandle { + internal_id: u32, + external_id: u32, + phantom: std::marker::PhantomData, +} + +pub trait Component { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle; +} + +enum UpdateFunctionTypes { + Component(std::boxed::Box), + System(std::boxed::Box), +} + +struct Tie { + update_function: UpdateFunctionTypes, + destination_system_handle: u32, +} + /// An orchestrator is a collection of systems that are updated in parallel. pub struct Orchestrator { sep: std::sync::Mutex<(crate::executor::Executor, crate::executor::Spawner)>, systems_data: SystemsData, tasks: Vec, + ties: HashMap>, } unsafe impl Send for Orchestrator {} struct SystemsData { systems: Vec>>, + systems_by_name: HashMap<&'static str, u32>, } trait SystemLock { @@ -69,12 +93,24 @@ struct Task { type OrchestratorHandle = std::sync::Arc; +pub enum Property { + System { + getter: fn(&S, &ComponentHandle) -> V, + setter: fn(&mut S, &ComponentHandle, V), + }, + Component { + getter: fn(&O) -> V, + setter: fn(&mut O, V), + }, +} + impl Orchestrator { pub fn new() -> Orchestrator { Orchestrator { sep: std::sync::Mutex::new(crate::executor::new_executor_and_spawner()), - systems_data: SystemsData { systems: Vec::new() }, + systems_data: SystemsData { systems: Vec::new(), systems_by_name: HashMap::new() }, tasks: Vec::new(), + ties: HashMap::new(), } } @@ -95,6 +131,69 @@ impl Orchestrator { system_handle } + pub fn make_object(&mut self, c: C) -> ComponentHandle { + let obj = std::sync::Arc::new(std::sync::Mutex::new(c)); + let internal_id = self.systems_data.systems.len() as u32; + self.systems_data.systems.push(obj); + let external_id = 0; + ComponentHandle:: { internal_id, external_id, phantom: std::marker::PhantomData } + } + + pub fn make_object_with_handle(&mut self, name: &'static str, c: impl Fn(ComponentHandle) -> C) -> ComponentHandle { + let internal_id = self.systems_data.systems.len() as u32; + let external_id = 0; + let handle = ComponentHandle:: { internal_id, external_id, phantom: std::marker::PhantomData }; + self.systems_data.systems.push(std::sync::Arc::new(std::sync::Mutex::new(c(ComponentHandle:: { internal_id, external_id, phantom: std::marker::PhantomData })))); + self.systems_data.systems_by_name.insert(name, internal_id); + handle + } + + pub fn make_handle(&self, component_handle: &ComponentHandle, external_id: u32) -> ComponentHandle { + ComponentHandle:: { internal_id: component_handle.internal_id, external_id, phantom: std::marker::PhantomData } + } + + pub fn tie<'a, 'b, T: 'static, U: 'b, V: 'static, S0: 'static, S1: 'static>(&mut self, receiver_component_handle: &ComponentHandle, i: fn() -> Property, sender_component_handle: &ComponentHandle, j: fn() -> Property) { + let property_function_pointer = j as *const (); // Use the property function pointer as a key to the ties hashmap. + + let property = i(); + + let update_function = match property { + Property::Component { getter, setter } => UpdateFunctionTypes::Component(std::boxed::Box::new(setter)), + Property::System { getter, setter } => UpdateFunctionTypes::System(std::boxed::Box::new(setter)), + }; + + if self.ties.contains_key(&(property_function_pointer as usize)) { + let ties = self.ties.get_mut(&(property_function_pointer as usize)).unwrap(); + ties.push(Tie { update_function, destination_system_handle: receiver_component_handle.internal_id }); + } else { + let mut ties = Vec::new(); + ties.push(Tie { update_function, destination_system_handle: receiver_component_handle.internal_id }); + self.ties.insert(property_function_pointer as usize, ties); + } + } + + pub fn notify(&self, component_handle: &ComponentHandle, function: fn() -> Property, value: V) { + let po = function as *const (); + let ties = self.ties.get(&(po as usize)).unwrap(); + + for tie in ties { + unsafe { + match tie.update_function { + UpdateFunctionTypes::Component(ref setter) => { + let mut component = self.systems_data.systems[tie.destination_system_handle as usize].lock().unwrap(); + let setter = setter.downcast_ref_unchecked::(); + (setter)(component.downcast_mut_unchecked::(), value); + }, + UpdateFunctionTypes::System(ref setter) => { + let mut component = self.systems_data.systems[tie.destination_system_handle as usize].lock().unwrap(); + let setter = setter.downcast_ref_unchecked::, V)>(); + (setter)(component.downcast_mut_unchecked::(), component_handle, value); + }, + } + } + } + } + pub fn execute_task_standalone(&self, task: impl std::future::Future + Send + 'static) { self.sep.lock().unwrap().1.spawn(task); } @@ -114,6 +213,35 @@ impl Orchestrator { self.tasks.push(Task { function: std::boxed::Box::new(task) }); } + pub fn get_and(&self, component_handle: &ComponentHandle, function: F) -> R where F: FnOnce(&C) -> R { + let component = self.systems_data.systems[component_handle.internal_id as usize].lock().unwrap(); + function(component.downcast_ref::().unwrap()) + } + + pub fn get_mut_by_name_and(&self, name: &'static str, function: F) -> R where F: FnOnce(&mut C) -> R { + let mut component = self.systems_data.systems[self.systems_data.systems_by_name[name] as usize].lock().unwrap(); + function(component.downcast_mut::().unwrap()) + } + + pub fn get_property(&self, component_handle: &ComponentHandle, function: fn() -> Property) -> V { + let property = function(); + + match property { + Property::Component { getter, setter: _ } => { + let component = self.systems_data.systems[component_handle.internal_id as usize].lock().unwrap(); + let getter = getter as *const (); + let getter = unsafe { std::mem::transmute::<*const (), fn(&C) -> V>(getter) }; + (getter)(component.downcast_ref::().unwrap()) + }, + Property::System { getter, setter: _ } => { + let component = self.systems_data.systems[component_handle.internal_id as usize].lock().unwrap(); + let getter = getter as *const (); + let getter = unsafe { std::mem::transmute::<*const (), fn(&S, &ComponentHandle) -> V>(getter) }; + (getter)(component.downcast_ref::().unwrap(), component_handle) + }, + } + } + // pub fn get_system(&self, system_handle: SystemHandle) -> Arc where T: System + Send { // self.systems_data.systems[system_handle.0 as usize].jesus() // } @@ -214,4 +342,156 @@ mod tests { orchestrator.update(); } + + #[test] + fn tie() { + let mut orchestrator = Orchestrator::new(); + + struct Sender { + value: u32, + } + + impl Sender { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle { + orchestrator.make_object(Sender { value: 0 }) + } + + fn get_value(&self) -> u32 { + self.value + } + + fn set_value(&mut self, value: u32) { + self.value = value; + } + + const fn send() -> Property<(), Sender, u32> { + Property::Component { getter: Sender::get_value, setter: Sender::set_value } + } + } + + struct Receiver { + value: u32, + } + + impl Receiver { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle { + orchestrator.make_object(Receiver { value: 0 }) + } + + fn read_value(&self) -> u32 { + self.value + } + + fn set_value(&mut self, value: u32) { + self.value = value; + } + + const fn value() -> Property<(), Receiver, u32> { + Property::Component { getter: Receiver::read_value, setter: Receiver::set_value } + } + } + + let sender_handle = Sender::new(&mut orchestrator); + + let receiver_handle = Receiver::new(&mut orchestrator); + + let value = orchestrator.get_property(&receiver_handle, Receiver::value); + + assert_eq!(value, 0); + + orchestrator.tie(&receiver_handle, Receiver::value, &sender_handle, Sender::send); + + orchestrator.notify(&sender_handle, Sender::send, 5); + + let value = orchestrator.get_and(&receiver_handle, |r| r.value); + + assert_eq!(value, 5); + } + + #[test] + fn system_owned_components() { + let mut orchestrator = Orchestrator::new(); + + struct Sender { + value: u32, + } + + impl Sender { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle { + orchestrator.make_object(Sender { value: 0 }) + } + + fn get_value(&self) -> u32 { self.value } + fn set_value(&mut self, value: u32) { self.value = value; } + + const fn send() -> Property<(), Sender, u32> { Property::Component { getter: Sender::get_value, setter: Sender::set_value } } + } + + struct Component { + // No data in component as it is managed/owned by the system. + } + + struct System { + handle: ComponentHandle, + data: Vec, + } + + impl System { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle { + orchestrator.make_object_with_handle("System", |handle| { + System { handle: handle, data: Vec::new() } + }) + } + + fn create_component(orchestrator: &mut Orchestrator, value: u32) -> ComponentHandle { + orchestrator.get_mut_by_name_and("System", |system: &mut System| { + let external_id = system.data.len() as u32; + system.data.push(value); + orchestrator.make_handle(&system.handle, external_id) + }) + } + + fn set_component_value(&mut self, component_handle: &ComponentHandle, value: u32) { + self.data[component_handle.external_id as usize] = value; + } + + fn get_component_value(&self, component_handle: &ComponentHandle) -> u32 { + self.data[component_handle.external_id as usize] + } + } + + impl super::System for System { + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + + impl Component { + fn new(orchestrator: &mut Orchestrator) -> ComponentHandle { + System::create_component(orchestrator, 0) + } + + const fn value() -> Property { + Property::System { getter: System::get_component_value, setter: System::set_component_value } + } + } + + let sender_handle = Sender::new(&mut orchestrator); + + System::new(&mut orchestrator); + + let component_handle = Component::new(&mut orchestrator); + + let value = orchestrator.get_property(&component_handle, Component::value); + + assert_eq!(value, 0); + + orchestrator.tie(&component_handle, Component::value, &sender_handle, Sender::send); + + orchestrator.notify(&sender_handle, Sender::send, 5); + + let value = orchestrator.get_property(&component_handle, Component::value); + + assert_eq!(value, 5); + } } \ No newline at end of file diff --git a/src/render_backend.rs b/src/render_backend.rs index 88d2abc5..e3c2fc90 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -64,14 +64,14 @@ pub enum TextureFormats { /// Stores the information of a buffer. pub union Buffer { /// The information of a buffer. - pub vulkan_buffer: vulkan_render_backend::Buffer, + pub(crate) vulkan_buffer: vulkan_render_backend::Buffer, } #[derive(Clone, Copy)] /// Stores the information of a descriptor set layout. pub union DescriptorSetLayout { /// The information of a descriptor set layout. - pub vulkan_descriptor_set_layout: vulkan_render_backend::DescriptorSetLayout, + pub(crate) vulkan_descriptor_set_layout: vulkan_render_backend::DescriptorSetLayout, } #[derive(Clone, Copy)] @@ -90,49 +90,49 @@ pub union TextureView { /// Stores the information of a shader. pub union Shader { /// The information of a shader. - pub vulkan_shader: vulkan_render_backend::Shader, + pub(crate) vulkan_shader: vulkan_render_backend::Shader, } #[derive(Clone, Copy)] /// Stores the information of a swapchain. pub union Swapchain { /// The information of a swapchain. - pub vulkan_swapchain: vulkan_render_backend::Swapchain, + pub(crate) vulkan_swapchain: vulkan_render_backend::Swapchain, } #[derive(Clone, Copy)] /// Stores the information of a surface. pub union Surface { /// The information of a surface. - pub vulkan_surface: vulkan_render_backend::Surface, + pub(crate) vulkan_surface: vulkan_render_backend::Surface, } #[derive(Clone, Copy)] /// Stores the information of a synchronizer. pub union Synchronizer { /// The information of a synchronizer. - pub vulkan_synchronizer: vulkan_render_backend::Synchronizer, + pub(crate) vulkan_synchronizer: vulkan_render_backend::Synchronizer, } #[derive(Clone, Copy)] /// Stores the information of a pipeline layout. pub union PipelineLayout { /// The information of a pipeline layout. - pub vulkan_pipeline_layout: vulkan_render_backend::PipelineLayout, + pub(crate) vulkan_pipeline_layout: vulkan_render_backend::PipelineLayout, } #[derive(Clone, Copy)] /// Stores the information of a pipeline. pub union Pipeline { /// The information of a pipeline. - pub vulkan_pipeline: vulkan_render_backend::Pipeline, + pub(crate) vulkan_pipeline: vulkan_render_backend::Pipeline, } #[derive(Clone, Copy)] /// Stores the information of a command buffer. pub union CommandBuffer { /// The information of a command buffer. - pub vulkan_command_buffer: vulkan_render_backend::CommandBuffer, + pub(crate) vulkan_command_buffer: vulkan_render_backend::CommandBuffer, } #[derive(Clone, Copy)] @@ -148,9 +148,9 @@ pub struct Memory<'a> { /// The allocation that the memory region is associated with. pub allocation: &'a Allocation, /// The offset of the memory region. - pub offset: u64, + pub offset: usize, /// The size of the memory region. - pub size: u64, + pub size: usize, } #[derive(Clone, Copy)] @@ -186,8 +186,12 @@ pub struct TextureCopy { #[derive(Clone, Copy)] /// Stores the information of a memory backed resource. pub struct MemoryBackedResourceCreationResult { - pub(crate) resource: T, - pub(crate) size: u64, + /// The resource. + pub resource: T, + /// The final size of the resource. + pub size: usize, + /// Tha alignment the resources needs when bound to a memory region. + pub alignment: usize, } use bitflags::bitflags; @@ -311,7 +315,7 @@ pub enum DescriptorType { /// Stores the information of a sampler. pub struct Sampler { /// The Vulkan backend implementation object for a sampler. - pub vulkan_sampler: vulkan_render_backend::Sampler, + pub(crate) vulkan_sampler: vulkan_render_backend::Sampler, } /// Stores the information of a descriptor set layout binding. @@ -332,7 +336,7 @@ pub struct DescriptorSetLayoutBinding { /// Stores the information of a descriptor set. pub union DescriptorSet { /// The Vulkan backend implementation object for a descriptor set. - pub vulkan_descriptor_set: vulkan_render_backend::DescriptorSet, + pub(crate) vulkan_descriptor_set: vulkan_render_backend::DescriptorSet, } /// Stores the information of a descriptor. @@ -454,7 +458,7 @@ pub trait RenderBackend { /// /// # Returns /// * `Allocation` - The allocated memory region. - fn allocate_memory(&self, size: u64, device_accesses: crate::render_system::DeviceAccesses) -> Allocation; + fn allocate_memory(&self, size: usize, device_accesses: crate::render_system::DeviceAccesses) -> Allocation; /// Returns a pointer to the start of the memory region. /// @@ -474,7 +478,7 @@ pub trait RenderBackend { /// /// # Returns /// * `MemoryBackedResourceCreationResult` - The created buffer. - fn create_buffer(&self, size: u64, resource_uses: Uses) -> MemoryBackedResourceCreationResult; + fn create_buffer(&self, size: usize, resource_uses: Uses) -> MemoryBackedResourceCreationResult; /// Creates a texture. /// Textures are used to store images on the GPU. @@ -696,7 +700,7 @@ pub trait RenderBackend { /// * `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: &crate::render_backend::Synchronizer); + 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); /// Acquires an image from a swapchain. /// diff --git a/src/render_system.rs b/src/render_system.rs index ebbad55a..01d9a6d6 100644 --- a/src/render_system.rs +++ b/src/render_system.rs @@ -99,7 +99,7 @@ struct Buffer { frame_handle: Option, next: Option, buffer: crate::render_backend::Buffer, - size: u64, + size: usize, pointer: *mut u8, } @@ -377,10 +377,10 @@ impl CommandBufferRecording<'_> { let texture = self.render_system.get_texture(self.frame_handle, texture_handle); - let copy_dst_texture = self.render_system.textures.iter().enumerate().find(|(_, texture)| texture.parent == Some(texture_handle) && texture.role == "CPU_READ"); + let copy_dst_texture = self.render_system.textures.iter().enumerate().find(|(_, texture)| texture.parent == Some(texture_handle) && texture.role == "CPU_READ").expect("No CPU_READ texture found. Texture must be created with the CPU read access flag."); let source_texture_handle = texture_handle; - let destination_texture_handle = TextureHandle(copy_dst_texture.unwrap().0 as u32); + let destination_texture_handle = TextureHandle(copy_dst_texture.0 as u32); let transitions = [ (source_texture_handle, true, crate::render_backend::Layouts::Transfer, crate::render_backend::Stages::TRANSFER, crate::render_backend::AccessPolicies::READ), @@ -391,7 +391,7 @@ impl CommandBufferRecording<'_> { texture_copies.push(crate::render_backend::TextureCopy { source: texture.texture, - destination: copy_dst_texture.unwrap().1.texture, + destination: copy_dst_texture.1.texture, extent: texture.extent, }); @@ -525,7 +525,7 @@ impl RenderSystem { } /// Creates a new allocation from a managed allocator for the underlying GPU allocations. - pub fn create_allocation(&mut self, size: u64, _resource_uses: render_backend::Uses, resource_device_accesses: DeviceAccesses) -> AllocationHandle { + pub fn create_allocation(&mut self, size: usize, _resource_uses: render_backend::Uses, resource_device_accesses: DeviceAccesses) -> AllocationHandle { let allocation = self.render_backend.allocate_memory(size, resource_device_accesses); let allocation_handle = AllocationHandle(self.allocations.len() as u64); @@ -546,14 +546,15 @@ impl RenderSystem { let vertex_layout_hash = hasher.finish(); - let vertex_buffer_size = vertices.len() as u64; - let vertex_buffer_offset = 0; + let vertex_buffer_size = vertices.len(); let vertex_buffer_creation_result = self.render_backend.create_buffer(vertex_buffer_size, render_backend::Uses::Vertex); - let index_buffer_size = indices.len() as u64; - let index_buffer_offset = vertices.len() as u64 + 15 & !15; + let index_buffer_size = indices.len(); let index_buffer_creation_result = self.render_backend.create_buffer(index_buffer_size, render_backend::Uses::Index); - let allocation_handle = self.create_allocation(vertex_buffer_creation_result.size + index_buffer_creation_result.size + 64, render_backend::Uses::Vertex | render_backend::Uses::Index, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead); + let vertex_buffer_offset = 0usize; + let index_buffer_offset = vertices.len().next_multiple_of(index_buffer_creation_result.alignment); + + let allocation_handle = self.create_allocation(vertex_buffer_creation_result.size.next_multiple_of(index_buffer_creation_result.alignment) + index_buffer_creation_result.size, render_backend::Uses::Vertex | render_backend::Uses::Index, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead); let allocation = &self.allocations[allocation_handle.0 as usize]; @@ -777,13 +778,13 @@ impl RenderSystem { for i in 0..self.frames.len() { let buffer_handle = BufferHandle(self.buffers.len() as u32); - let buffer_creation_result = self.render_backend.create_buffer(size as u64, 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 = &self.allocations[allocation_handle.0 as usize]; - self.render_backend.bind_buffer_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size as u64 }, &buffer_creation_result); + 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); @@ -820,58 +821,73 @@ impl RenderSystem { } } + /// Creates a texture. pub fn create_texture(&mut self, extent: crate::Extent, format: crate::render_backend::TextureFormats, resource_uses: render_backend::Uses, device_accesses: DeviceAccesses) -> TextureHandle { - let size = extent.width as u64 * extent.height as u64 * extent.depth as u64 * 4; - - dbg!(device_accesses); + let size = (extent.width * extent.height * extent.depth * 4) as usize; // CPU readeble render target if device_accesses == DeviceAccesses::CpuRead | DeviceAccesses::GpuWrite { - let texture_creation_result = self.render_backend.create_texture(extent, format, render_backend::Uses::TransferDestination, DeviceAccesses::CpuRead, crate::render_backend::AccessPolicies::READ, 1); + let texture_handle = TextureHandle(self.textures.len() as u32); + let mut previous_texture_handle: Option = None; + let mut previous_cpu_texture_handle: Option = None; - let allocation_handle = self.create_allocation(texture_creation_result.size, resource_uses, DeviceAccesses::CpuRead); + for i in 0..self.frames.len() { + let texture_creation_result = self.render_backend.create_texture(extent, format, resource_uses | render_backend::Uses::TransferSource, DeviceAccesses::GpuWrite, crate::render_backend::AccessPolicies::WRITE, 1); - let allocation = &self.allocations[allocation_handle.0 as usize]; + let allocation_handle = self.create_allocation(texture_creation_result.size, resource_uses, DeviceAccesses::GpuWrite); - self.render_backend.bind_texture_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &texture_creation_result); + let allocation = &self.allocations[allocation_handle.0 as usize]; - //let texture_view = self.render_backend.create_texture_view(&texture_creation_result.resource, format, 1); + self.render_backend.bind_texture_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &texture_creation_result); - let proxy_texture_handle = TextureHandle(self.textures.len() as u32); + let texture_view = self.render_backend.create_texture_view(&texture_creation_result.resource, format, 1); - self.textures.push(Texture { - frame_handle: Some(FrameHandle(0)), - next: None, - parent: None, - texture: texture_creation_result.resource, - texture_view: None, - allocation_handle, - extent, - role: String::from("CPU_READ"), - }); + let texture_handle = TextureHandle(self.textures.len() as u32); - let texture_creation_result = self.render_backend.create_texture(extent, format, resource_uses | render_backend::Uses::TransferSource, DeviceAccesses::GpuWrite, crate::render_backend::AccessPolicies::WRITE, 1); + self.textures.push(Texture { + frame_handle: Some(FrameHandle(i as u32)), + next: None, + parent: None, + texture: texture_creation_result.resource, + texture_view: Some(texture_view), + allocation_handle, + extent, + role: String::from("GPU_WRITE"), + }); - let allocation_handle = self.create_allocation(texture_creation_result.size, resource_uses, DeviceAccesses::GpuWrite); - - let allocation = &self.allocations[allocation_handle.0 as usize]; - - self.render_backend.bind_texture_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &texture_creation_result); - - let texture_view = self.render_backend.create_texture_view(&texture_creation_result.resource, format, 1); - - let texture_handle = self.create_texture_internal(Texture { - frame_handle: Some(FrameHandle(0)), - next: None, - parent: None, - texture: texture_creation_result.resource, - texture_view: Some(texture_view), - allocation_handle, - extent, - role: String::from("GPU_WRITE"), - }); - - self.textures[proxy_texture_handle.0 as usize].parent = Some(texture_handle); + if let Some(previous_texture_handle) = previous_texture_handle { + self.textures[previous_texture_handle.0 as usize].next = Some(texture_handle); + } + + previous_texture_handle = Some(texture_handle); + + let texture_creation_result = self.render_backend.create_texture(extent, format, render_backend::Uses::TransferDestination, DeviceAccesses::CpuRead, crate::render_backend::AccessPolicies::READ, 1); + + let allocation_handle = self.create_allocation(texture_creation_result.size, resource_uses, DeviceAccesses::CpuRead); + + let allocation = &self.allocations[allocation_handle.0 as usize]; + + self.render_backend.bind_texture_memory(crate::render_backend::Memory{ allocation: &allocation.allocation, offset: 0, size: size }, &texture_creation_result); + + let cpu_texture_handle = TextureHandle(self.textures.len() as u32); + + self.textures.push(Texture { + frame_handle: Some(FrameHandle(i as u32)), + next: None, + parent: Some(texture_handle), + texture: texture_creation_result.resource, + texture_view: None, + allocation_handle, + extent, + role: String::from("CPU_READ"), + }); + + if let Some(previous_texture_handle) = previous_cpu_texture_handle { + self.textures[previous_texture_handle.0 as usize].next = Some(cpu_texture_handle); + } + + previous_cpu_texture_handle = Some(cpu_texture_handle); + } texture_handle } else if device_accesses == DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead { @@ -1085,7 +1101,7 @@ 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: SynchronizerHandle) { + pub fn execute(&self, frame_handle: Option, command_buffer_recording: CommandBufferRecording, wait_for_synchronizer_handle: Option, signal_synchronizer_handle: Option, execution_synchronizer_handle: SynchronizerHandle) { 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 { @@ -1094,9 +1110,15 @@ impl RenderSystem { None }; - let signal_synchronizer = self.get_synchronizer(frame_handle, signal_synchronizer_handle); + let signal_synchronizer = if let Some(signal_synchronizer) = signal_synchronizer_handle { + Some(&self.get_synchronizer(frame_handle, signal_synchronizer).synchronizer) + } else { + None + }; + + let execution_synchronizer = self.get_synchronizer(frame_handle, execution_synchronizer_handle); - self.render_backend.execute(&command_buffer.command_buffer, wait_for_synchronizer, &signal_synchronizer.synchronizer); + self.render_backend.execute(&command_buffer.command_buffer, wait_for_synchronizer, signal_synchronizer, &execution_synchronizer.synchronizer); } pub fn present(&self, frame_handle: Option, image_index: u32, synchronizer_handle: SynchronizerHandle) { @@ -1280,7 +1302,7 @@ mod tests { // Use and odd width to make sure there is a middle/center pixel let extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; - let texture = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::CpuRead | crate::render_system::DeviceAccesses::GpuWrite); + let render_target = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::CpuRead | crate::render_system::DeviceAccesses::GpuWrite); let command_buffer_handle = renderer.create_command_buffer(); @@ -1290,7 +1312,7 @@ mod tests { let attachments = [ crate::render_system::AttachmentInfo { - texture: texture, + texture: render_target, format: crate::render_backend::TextureFormats::RGBAu8, clear: Some(crate::RGBA { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }), load: false, @@ -1306,18 +1328,18 @@ mod tests { command_buffer_recording.end_render_pass(); - command_buffer_recording.synchronize_texture(texture); + command_buffer_recording.synchronize_texture(render_target); command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, None, signal); + renderer.execute(Some(frame_handle), command_buffer_recording, None, None, signal); renderer.end_frame_capture(); renderer.wait(Some(frame_handle), signal); // Wait for the render to finish before accessing the texture data // assert colored triangle was drawn to texture - let pixels = renderer.get_texture_data::(texture); + let pixels = renderer.get_texture_data::(render_target); // let mut file = std::fs::File::create("test.png").unwrap(); @@ -1354,6 +1376,7 @@ mod tests { assert!(!renderer.has_errors()) } + #[ignore = "Ignore until we have a way to disable this test in CI where presentation is not supported"] #[test] fn present() { let mut renderer = RenderSystem::new(); @@ -1460,7 +1483,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, Some(image_ready), render_finished_synchronizer); + renderer.execute(Some(frame_handle), command_buffer_recording, Some(image_ready), Some(render_finished_synchronizer), render_finished_synchronizer); renderer.present(Some(frame_handle), image_index, render_finished_synchronizer); @@ -1482,15 +1505,9 @@ mod tests { let mut renderer = RenderSystem::new(); - 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 window_handle = window_system.create_window("Renderer Test", extent, "test"); - - renderer.bind_to_window(window_system.get_os_handles(window_handle)); - let frames = (0..FRAMES_IN_FLIGHT).map(|_| renderer.create_frame()).collect::>(); let floats: [f32;21] = [ @@ -1545,25 +1562,22 @@ mod tests { // Use and odd width to make sure there is a middle/center pixel let extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; - let texture = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::GpuWrite); + let render_target = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::CpuRead | crate::render_system::DeviceAccesses::GpuWrite); let command_buffer_handle = renderer.create_command_buffer(); let render_finished_synchronizer = renderer.create_synchronizer(true); - let image_ready = renderer.create_synchronizer(false); for i in 0..FRAMES_IN_FLIGHT*10 { renderer.wait(Some(frames[i % FRAMES_IN_FLIGHT]), render_finished_synchronizer); - let image_index = renderer.acquire_swapchain_image(Some(frames[i % FRAMES_IN_FLIGHT]), image_ready); - renderer.start_frame_capture(); let mut command_buffer_recording = renderer.create_command_buffer_recording(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_handle); let attachments = [ crate::render_system::AttachmentInfo { - texture: texture, + texture: render_target, format: crate::render_backend::TextureFormats::RGBAu8, clear: Some(crate::RGBA { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }), load: false, @@ -1579,20 +1593,11 @@ mod tests { command_buffer_recording.end_render_pass(); - let swapchain_texture_handle = renderer.get_swapchain_texture_handle(Some(frames[i % FRAMES_IN_FLIGHT])); - - command_buffer_recording.copy_textures(&[ - ( - texture, render_backend::Layouts::Transfer, render_backend::Stages::TRANSFER, render_backend::AccessPolicies::READ, - swapchain_texture_handle, render_backend::Layouts::Transfer, render_backend::Stages::TRANSFER, render_backend::AccessPolicies::WRITE - ) - ]); + command_buffer_recording.synchronize_texture(render_target); command_buffer_recording.end(); - renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, Some(image_ready), render_finished_synchronizer); - - renderer.present(Some(frames[i % FRAMES_IN_FLIGHT]), image_index, render_finished_synchronizer); + renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, None, None, render_finished_synchronizer); renderer.end_frame_capture(); } @@ -1611,15 +1616,9 @@ mod tests { let mut renderer = RenderSystem::new(); - 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 window_handle = window_system.create_window("Renderer Test", extent, "test"); - - renderer.bind_to_window(window_system.get_os_handles(window_handle)); - let frames = (0..FRAMES_IN_FLIGHT).map(|_| renderer.create_frame()).collect::>(); let floats: [f32;21] = [ @@ -1680,14 +1679,13 @@ mod tests { // Use and odd width to make sure there is a middle/center pixel let extent = crate::Extent { width: 1920, height: 1080, depth: 1 }; - let texture = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::GpuWrite); + let render_target = renderer.create_texture(extent, crate::render_backend::TextureFormats::RGBAu8, crate::render_backend::Uses::RenderTarget, crate::render_system::DeviceAccesses::CpuRead | crate::render_system::DeviceAccesses::GpuWrite); let buffer = renderer.create_buffer(64, crate::render_backend::Uses::Storage, DeviceAccesses::CpuWrite | DeviceAccesses::GpuRead); let command_buffer_handle = renderer.create_command_buffer(); let render_finished_synchronizer = renderer.create_synchronizer(true); - let image_ready = renderer.create_synchronizer(false); for i in 0..FRAMES_IN_FLIGHT*10 { renderer.wait(Some(frames[i % FRAMES_IN_FLIGHT]), render_finished_synchronizer); @@ -1696,15 +1694,13 @@ mod tests { //unsafe { std::ptr::copy_nonoverlapping(matrix.as_ptr(), pointer as *mut f32, 16); } - let image_index = renderer.acquire_swapchain_image(Some(frames[i % FRAMES_IN_FLIGHT]), image_ready); - renderer.start_frame_capture(); let mut command_buffer_recording = renderer.create_command_buffer_recording(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_handle); let attachments = [ crate::render_system::AttachmentInfo { - texture: texture, + texture: render_target, format: crate::render_backend::TextureFormats::RGBAu8, clear: Some(crate::RGBA { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }), load: false, @@ -1732,20 +1728,11 @@ mod tests { command_buffer_recording.end_render_pass(); - let swapchain_texture_handle = renderer.get_swapchain_texture_handle(Some(frames[i % FRAMES_IN_FLIGHT])); - - command_buffer_recording.copy_textures(&[ - ( - texture, render_backend::Layouts::Transfer, render_backend::Stages::TRANSFER, render_backend::AccessPolicies::READ, - swapchain_texture_handle, render_backend::Layouts::Transfer, render_backend::Stages::TRANSFER, render_backend::AccessPolicies::WRITE - ) - ]); + command_buffer_recording.synchronize_texture(render_target); command_buffer_recording.end(); - renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, Some(image_ready), render_finished_synchronizer); - - renderer.present(Some(frames[i % FRAMES_IN_FLIGHT]), image_index, render_finished_synchronizer); + renderer.execute(Some(frames[i % FRAMES_IN_FLIGHT]), command_buffer_recording, None, None, render_finished_synchronizer); renderer.end_frame_capture(); } @@ -1900,7 +1887,7 @@ mod tests { command_buffer_recording.end(); - renderer.execute(Some(frame_handle), command_buffer_recording, None, signal); + renderer.execute(Some(frame_handle), command_buffer_recording, None, None, signal); renderer.end_frame_capture(); diff --git a/src/resource_manager.rs b/src/resource_manager.rs index f6c444a3..0c982163 100644 --- a/src/resource_manager.rs +++ b/src/resource_manager.rs @@ -2,7 +2,7 @@ //! Handles loading assets or resources from different origins (network, local, etc.). //! It also handles caching of resources. -use std::{io::prelude::*, f32::consts::E}; +use std::{io::prelude::*}; use polodb_core::bson::{Document, bson, doc}; diff --git a/src/vulkan_render_backend.rs b/src/vulkan_render_backend.rs index 11d66724..37935bcb 100644 --- a/src/vulkan_render_backend.rs +++ b/src/vulkan_render_backend.rs @@ -5,7 +5,7 @@ use ash::{vk, Entry}; use crate::render_backend; #[derive(Clone, Copy)] -pub struct Surface { +pub(crate) struct Surface { surface: vk::SurfaceKHR, surface_capabilities: vk::SurfaceCapabilitiesKHR, surface_format: vk::SurfaceFormatKHR, @@ -13,78 +13,78 @@ pub struct Surface { } #[derive(Clone, Copy)] -pub struct Swapchain { +pub(crate) struct Swapchain { swapchain: vk::SwapchainKHR, } #[derive(Clone, Copy)] -pub struct DescriptorSetLayout { +pub(crate) struct DescriptorSetLayout { descriptor_set_layout: vk::DescriptorSetLayout, } #[derive(Clone, Copy)] -pub struct DescriptorSet { +pub(crate) struct DescriptorSet { descriptor_set: vk::DescriptorSet, } #[derive(Clone, Copy)] -pub struct PipelineLayout { +pub(crate) struct PipelineLayout { pipeline_layout: vk::PipelineLayout, } #[derive(Clone, Copy)] -pub struct Pipeline { +pub(crate) struct Pipeline { pipeline: vk::Pipeline, } #[derive(Clone, Copy)] -pub struct CommandBuffer { +pub(crate) struct CommandBuffer { command_buffer: vk::CommandBuffer, } #[derive(Clone, Copy)] -pub struct Allocation { +pub(crate) struct Allocation { memory: vk::DeviceMemory, } #[derive(Clone, Copy)] -pub struct Buffer { +pub(crate) struct Buffer { buffer: vk::Buffer, device_address: vk::DeviceAddress, } #[derive(Clone, Copy)] -pub struct Synchronizer { +pub(crate) struct Synchronizer { fence: vk::Fence, semaphore: vk::Semaphore, } #[derive(Clone, Copy)] -pub struct Sampler { +pub(crate) struct Sampler { sampler: vk::Sampler, } #[derive(Clone, Copy)] -pub struct Texture { +pub(crate) struct Texture { image: vk::Image, } #[derive(Clone, Copy)] -pub struct TextureView { +pub(crate) struct TextureView { image_view: vk::ImageView, } #[derive(Clone, Copy)] -pub struct Shader { +pub(crate) struct Shader { shader_module: vk::ShaderModule, stage: vk::ShaderStageFlags } #[derive(Clone, Copy)] -struct AccelerationStructure { +pub(crate) struct AccelerationStructure { acceleration_structure: vk::AccelerationStructureKHR, } -pub struct VulkanRenderBackend { +pub(crate) struct VulkanRenderBackend { entry: ash::Entry, instance: ash::Instance, debug_utils: ash::extensions::ext::DebugUtils, @@ -108,7 +108,12 @@ unsafe extern "system" fn vulkan_debug_utils_callback(message_severity: vk::Debu let ty = format!("{:?}", message_type).to_lowercase(); println!("[Debug][{}][{}] {:?}", severity, ty, message); - counter += 1; + match message_severity { + vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => { + counter += 1; + } + _ => {} + } vk::FALSE } @@ -717,7 +722,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { } } - fn allocate_memory(&self, size: u64, device_accesses: crate::render_system::DeviceAccesses) -> crate::render_backend::Allocation { + fn allocate_memory(&self, size: usize, device_accesses: crate::render_system::DeviceAccesses) -> crate::render_backend::Allocation { // get memory types let memory_properties = unsafe { self.instance.get_physical_device_memory_properties(self.physical_device) }; @@ -746,7 +751,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { let mut memory_allocate_flags_info = vk::MemoryAllocateFlagsInfo::default().flags(vk::MemoryAllocateFlags::DEVICE_ADDRESS); let memory_allocate_info = vk::MemoryAllocateInfo::default() - .allocation_size(size) + .allocation_size(size as u64) .memory_type_index(memory_type_index) .push_next(&mut memory_allocate_flags_info) /* .build() */; @@ -756,7 +761,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { let mut mapped_memory = std::ptr::null_mut(); if device_accesses.intersects(crate::render_system::DeviceAccesses::CpuRead | crate::render_system::DeviceAccesses::CpuWrite) { - mapped_memory = unsafe { self.device.map_memory(memory, 0, size, vk::MemoryMapFlags::empty()).expect("No mapped memory") as *mut u8 }; + mapped_memory = unsafe { self.device.map_memory(memory, 0, size as u64, vk::MemoryMapFlags::empty()).expect("No mapped memory") as *mut u8 }; } crate::render_backend::Allocation { @@ -771,9 +776,9 @@ impl render_backend::RenderBackend for VulkanRenderBackend { allocation.pointer } - fn create_buffer(&self, size: u64, resource_uses: render_backend::Uses) -> crate::render_backend::MemoryBackedResourceCreationResult { + fn create_buffer(&self, size: usize, resource_uses: render_backend::Uses) -> crate::render_backend::MemoryBackedResourceCreationResult { let buffer_create_info = vk::BufferCreateInfo::default() - .size(size) + .size(size as u64) .sharing_mode(vk::SharingMode::EXCLUSIVE) .usage( if resource_uses.contains(render_backend::Uses::Vertex) { vk::BufferUsageFlags::VERTEX_BUFFER } else { vk::BufferUsageFlags::empty() } @@ -797,7 +802,8 @@ impl render_backend::RenderBackend for VulkanRenderBackend { device_address: 0, }, }, - size: memory_requirements.size + size: memory_requirements.size as usize, + alignment: memory_requirements.alignment as usize, } } @@ -849,7 +855,8 @@ impl render_backend::RenderBackend for VulkanRenderBackend { image, }, }, - size: memory_requirements.size + size: memory_requirements.size as usize, + alignment: memory_requirements.alignment as usize, } } @@ -899,11 +906,11 @@ impl render_backend::RenderBackend for VulkanRenderBackend { } fn bind_buffer_memory(&self, memory: crate::render_backend::Memory, resource_creation_info: &crate::render_backend::MemoryBackedResourceCreationResult) { - unsafe { self.device.bind_buffer_memory(resource_creation_info.resource.vulkan_buffer.buffer, memory.allocation.vulkan_allocation.memory, memory.offset).expect("No buffer memory binding") }; + unsafe { self.device.bind_buffer_memory(resource_creation_info.resource.vulkan_buffer.buffer, memory.allocation.vulkan_allocation.memory, memory.offset as u64).expect("No buffer memory binding") }; } fn bind_texture_memory(&self, memory: crate::render_backend::Memory, resource_creation_info: &crate::render_backend::MemoryBackedResourceCreationResult) { - unsafe { self.device.bind_image_memory(resource_creation_info.resource.vulkan_texture.image, memory.allocation.vulkan_allocation.memory, memory.offset).expect("No image memory binding") }; + unsafe { self.device.bind_image_memory(resource_creation_info.resource.vulkan_texture.image, memory.allocation.vulkan_allocation.memory, memory.offset as u64).expect("No image memory binding") }; //let image_view = unsafe { self.device.create_image_view(&image_view_create_info, None).expect("No image view") }; //resource_creation_info.resource.vulkan_texture.image_view = image_view; } @@ -1239,7 +1246,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { } } - fn execute(&self, command_buffer: &crate::render_backend::CommandBuffer, wait_for: Option<&crate::render_backend::Synchronizer>, signal: &crate::render_backend::Synchronizer) { + 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) { let command_buffers = [unsafe { command_buffer.vulkan_command_buffer.command_buffer }]; let command_buffer_infos = [ @@ -1261,11 +1268,15 @@ impl render_backend::RenderBackend for VulkanRenderBackend { vec![] }; - let signal_semaphores = [ - vk::SemaphoreSubmitInfo::default() - .semaphore(unsafe { signal.vulkan_synchronizer.semaphore }) + let signal_semaphores = if let Some(signal) = signal { + vec![ + vk::SemaphoreSubmitInfo::default() + .semaphore(unsafe { signal.vulkan_synchronizer.semaphore }) /* .build() */ - ]; + ] + } else { + vec![] + }; let submit_info = vk::SubmitInfo2::default() .command_buffer_infos(&command_buffer_infos) @@ -1273,7 +1284,7 @@ impl render_backend::RenderBackend for VulkanRenderBackend { .signal_semaphore_infos(&signal_semaphores) /* .build() */; - unsafe { self.device.queue_submit2(self.queue, &[submit_info], signal.vulkan_synchronizer.fence); } + unsafe { self.device.queue_submit2(self.queue, &[submit_info], execution_completion.vulkan_synchronizer.fence); } } fn acquire_swapchain_image(&self, swapchain: &crate::render_backend::Swapchain, image_available: &crate::render_backend::Synchronizer) -> (u32, render_backend::SwapchainStates) { diff --git a/src/window_system.rs b/src/window_system.rs index e159db0b..04d16359 100644 --- a/src/window_system.rs +++ b/src/window_system.rs @@ -7,126 +7,194 @@ use xcb::{Xid, x}; use crate::{Extent, orchestrator::System}; #[derive(Debug, Clone, Copy)] -enum Keys { +/// The keys that can be pressed on a keyboard. +pub enum Keys { + /// The A key. A, + /// The B key. B, + /// The C key. C, + /// The D key. D, + /// The E key. E, + /// The F key. F, + /// The G key. G, + /// The H key. H, + /// The I key. I, + /// The J key. J, + /// The K key. K, + /// The L key. L, + /// The M key. M, + /// The N key. N, + /// The O key. O, + /// The P key. P, + /// The Q key. Q, + /// The R key. R, + /// The S key. S, + /// The T key. T, + /// The U key. U, + /// The V key. V, + /// The W key. W, + /// The X key. X, + /// The Y key. Y, + /// The Z key. Z, + /// The number 0 key. Num0, + /// The number 1 key. Num1, + /// The number 2 key. Num2, + /// The number 3 key. Num3, + /// The number 4 key. Num4, + /// The number 5 key. Num5, + /// The number 6 key. Num6, + /// The number 7 key. Num7, + /// The number 8 key. Num8, + /// The number 9 key. Num9, + /// The numpad 0 key. NumPad0, + /// The numpad 1 key. NumPad1, + /// The numpad 2 key. NumPad2, + /// The numpad 3 key. NumPad3, + /// The numpad 4 key. NumPad4, + /// The numpad 5 key. NumPad5, + /// The numpad 6 key. NumPad6, + /// The numpad 7 key. NumPad7, + /// The numpad 8 key. NumPad8, + /// The numpad 9 key. NumPad9, + /// The numpad add key. NumPadAdd, + /// The numpad subtract key. NumPadSubtract, + /// The numpad multiply key. NumPadMultiply, + /// The numpad divide key. NumPadDivide, + /// The numpad decimal key. NumPadDecimal, + /// The numpad enter key. NumPadEnter, + /// The backspace key. Backspace, + /// The tab key. Tab, + /// The enter key. Enter, + /// The shift left key. ShiftLeft, + /// The shift right key. ShiftRight, + /// The control left key. ControlLeft, + /// The control right key. ControlRight, + /// The alt left key. AltLeft, + /// The alt right key. AltRight, + /// The menu key. Menu, + /// The spacebar key. Space, + /// The insert key. Insert, + /// The delete key. Delete, + /// The home key. Home, + /// The end key. End, + /// The page up key. PageUp, + /// The page down key. PageDown, + /// The arrow up key. ArrowUp, + /// The arrow down key. ArrowDown, + /// The arrow left key. ArrowLeft, + /// The arrow right key. ArrowRight, + /// The escape key. Escape, + /// The F1 key. F1, + /// The F2 key. F2, + /// The F3 key. F3, + /// The F4 key. F4, + /// The F5 key. F5, + /// The F6 key. F6, + /// The F7 key. F7, + /// The F8 key. F8, + /// The F9 key. F9, + /// The F10 key. F10, + /// The F11 key. F11, + /// The F12 key. F12, + /// The num lock key. NumLock, + /// The scroll lock key. ScrollLock, + /// The caps lock key. CapsLock, + /// The print screen key. PrintScreen, - Pause, - Help, - SysReq, - Compose, - AltGr, - Stop, - Again, - Undo, - Cut, - Copy, - Paste, - Find, - Mute, - VolumeUp, - VolumeDown, - NumPadComma, - NumPadEquals, - NumPadParenLeft, - NumPadParenRight, - NumPadBackspace, - NumPadMemoryStore, - NumPadMemoryRecall, - NumPadMemoryClear, } #[derive(Debug, Clone, Copy)] @@ -139,15 +207,22 @@ enum MouseKeys { } #[derive(Debug, Clone, Copy)] +/// The events that can be received from a window. enum WindowEvents { + /// The window has been resized. Resize, + /// The window has been minimized. Minimize, + /// The window has been maximized. Maximize, + /// The window has been closed. Close, + /// A key has been pressed or released. Key { pressed: bool, key: Keys, }, + /// A mouse button has been pressed or released. Button { pressed: bool, button: MouseKeys, @@ -171,7 +246,7 @@ impl TryFrom for Keys { 113 => Ok(Keys::ArrowLeft), 116 => Ok(Keys::ArrowDown), 114 => Ok(Keys::ArrowRight), 111 => Ok(Keys::ArrowUp), 9 => Ok(Keys::Escape), 23 => Ok(Keys::Tab), 50 => Ok(Keys::ShiftLeft), 37 => Ok(Keys::ControlLeft), 64 => Ok(Keys::AltLeft), - 65 => Ok(Keys::Space), 108 => Ok(Keys::AltGr), 105 => Ok(Keys::ControlRight), 62 => Ok(Keys::ShiftRight), 36 => Ok(Keys::Enter), + 65 => Ok(Keys::Space), 108 => Ok(Keys::AltRight), 105 => Ok(Keys::ControlRight), 62 => Ok(Keys::ShiftRight), 36 => Ok(Keys::Enter), 22 => Ok(Keys::Backspace), _ => Err(()), @@ -493,6 +568,7 @@ impl Window { } } +/// The window system. pub struct WindowSystem { windows: Vec, } @@ -501,6 +577,7 @@ impl System for WindowSystem { fn as_any(&self) -> &dyn std::any::Any { self } } +/// The handle of a window. pub struct WindowHandle(u64); /// The operating system handles for a window.