diff --git a/Cargo.toml b/Cargo.toml index c9dff52..482f978 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +rayon = "1" strum = { version = "0.24", features = ["derive"] } diff --git a/src/lib.rs b/src/lib.rs index 8619304..81ff81f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,11 @@ //! Cyborg is a high-performance, modern, experimental rendering engine written //! in Rust. +use rayon::prelude::*; use strum::IntoEnumIterator; -pub mod phase; pub mod pass; +pub mod phase; use pass::*; use phase::*; @@ -17,32 +18,41 @@ impl Renderer { pub fn render(&mut self) { let frame_index = 0; - let mut phase_passes = PhaseMultiMap::::default(); + let phase_passes = PhaseMultiMap::::default(); + let phase_passes = std::sync::Mutex::new(phase_passes); - let mut phases_buf = PhaseList::default(); - for (pass_index, rp) in self.render_passes.iter_mut().enumerate() { - phases_buf.clear(); - rp.begin_frame(frame_index, &mut phases_buf); - phase_passes.insert_multi(&phases_buf, pass_index); - } + self.render_passes + .par_iter_mut() + .enumerate() + .for_each(|(pass_index, rp)| { + let mut phases_buf = PhaseList::default(); + phases_buf.clear(); + rp.begin_frame(frame_index, &mut phases_buf); + phase_passes + .lock() + .unwrap() + .insert_multi(&phases_buf, pass_index); + }); - for phase in PrePhase::iter() { + let phase_passes = phase_passes.into_inner().unwrap(); + + PrePhase::iter().par_bridge().for_each(|phase| { for pass_index in phase_passes.iter_pre(&phase) { let pass = &self.render_passes[*pass_index]; let mut encoder = gpu::RenderBundleEncoder; pass.render_pre(phase, frame_index, &mut encoder); } - } + }); let viewport = ViewportData; - for phase in ViewportPhase::iter() { + ViewportPhase::iter().par_bridge().for_each(|phase| { for pass_index in phase_passes.iter_viewport(&phase) { let pass = &self.render_passes[*pass_index]; let mut encoder = gpu::RenderBundleEncoder; pass.render_viewport(phase, frame_index, &viewport, &mut encoder); } - } + }); } } @@ -55,3 +65,52 @@ pub mod gpu { /// - secondary command buffer in Vulkan pub struct RenderBundleEncoder; } + +#[cfg(test)] +mod tests { + use super::*; + + struct DummyPass; + + impl RenderPass for DummyPass { + type FrameData = usize; + + fn create_frame_data(&mut self) -> usize { + 0 + } + + fn begin_frame(&mut self, data: &mut Self::FrameData, phases: &mut PhaseList) { + println!("begin_frame()"); + } + + fn render_pre( + &self, + phase: PrePhase, + data: &Self::FrameData, + cmds: &mut gpu::RenderBundleEncoder, + ) { + println!("render_pre(phase: {:?})", phase); + } + + fn render_viewport( + &self, + phase: ViewportPhase, + data: &Self::FrameData, + viewport: &ViewportData, + cmds: &mut gpu::RenderBundleEncoder, + ) { + println!("render_viewport(phase: {:?})", phase); + } + } + + #[test] + fn dummy_pass() { + use std::sync::{Arc, RwLock}; + let dummy_pass = DummyPass; + let dummy_pass = Arc::new(RwLock::new(dummy_pass)); + let dummy_pass = RenderPassBox::new(dummy_pass, 1); + let render_passes = vec![dummy_pass]; + let mut renderer = Renderer { render_passes }; + renderer.render(); + } +} diff --git a/src/pass.rs b/src/pass.rs index c18a80e..0570489 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -15,9 +15,9 @@ pub struct ViewportData; /// /// Rendering functions record their GPU commands using the [gpu::RenderBundleEncoder] /// passed to them. -pub trait RenderPass { +pub trait RenderPass: Send + Sync { /// A structure that contains a pass's per-frame data. - type FrameData; + type FrameData: Send + Sync; /// Sets up a new instance of [Self::FrameData]. /// @@ -57,7 +57,7 @@ pub trait RenderPass { /// /// Functions on this trait map one-to-one with [RenderPass], except that /// frame data is passed by index and not by reference. -pub trait RenderPassBoxTrait { +pub trait RenderPassBoxTrait: Send + Sync { fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList); fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder); @@ -77,21 +77,21 @@ pub struct RenderPassBox { frame_data: Vec, } -impl RenderPassBox { +impl RenderPassBox { /// Creates a new boxed render pass. /// /// Calls to [RenderPassBoxTrait] functions with frame indices greater /// than or equal to `frame_num` are out-of-bounds and will panic. - pub fn new(render_pass: Arc>, frame_num: usize) -> Self { + pub fn new(render_pass: Arc>, frame_num: usize) -> Box { let frame_data = { let mut lock = render_pass.write().unwrap(); (0..frame_num).map(|_| lock.create_frame_data()).collect() }; - Self { + Box::new(Self { render_pass, frame_data, - } + }) } }