diff --git a/src/lib.rs b/src/lib.rs index a4d74e1..8619304 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,40 +1,14 @@ //! Cyborg is a high-performance, modern, experimental rendering engine written //! in Rust. -use std::sync::{Arc, RwLock}; use strum::IntoEnumIterator; pub mod phase; +pub mod pass; +use pass::*; use phase::*; -pub struct ViewportData; - -pub trait FrameData {} - -pub trait RenderPass { - type FrameData: FrameData; - - fn create_frame_data(&mut self) -> Self::FrameData; - - fn begin_frame(&mut self, data: &mut Self::FrameData, phases: &mut PhaseList); - - fn render_pre( - &self, - phase: PrePhase, - data: &Self::FrameData, - cmds: &mut gpu::RenderBundleEncoder, - ); - - fn render_viewport( - &self, - phase: ViewportPhase, - data: &Self::FrameData, - viewport: &ViewportData, - cmds: &mut gpu::RenderBundleEncoder, - ); -} - pub struct Renderer { pub render_passes: Vec>, } @@ -72,65 +46,6 @@ impl Renderer { } } -pub trait RenderPassBoxTrait { - fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList); - - fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder); - - fn render_viewport( - &self, - phase: ViewportPhase, - data_index: usize, - viewport: &ViewportData, - cmds: &mut gpu::RenderBundleEncoder, - ); -} - -pub struct RenderPassBox { - render_pass: Arc>, - frame_data: Vec, -} - -impl RenderPassBox { - pub fn new(render_pass: Arc>, frame_num: usize) -> Self { - let frame_data = { - let mut lock = render_pass.write().unwrap(); - (0..frame_num).map(|_| lock.create_frame_data()).collect() - }; - - Self { - render_pass, - frame_data, - } - } -} - -impl RenderPassBoxTrait for RenderPassBox { - fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList) { - let frame_data = &mut self.frame_data[data_index]; - let mut render_pass = self.render_pass.write().unwrap(); - render_pass.begin_frame(frame_data, phases) - } - - fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder) { - let frame_data = &self.frame_data[data_index]; - let render_pass = self.render_pass.read().unwrap(); - render_pass.render_pre(phase, frame_data, cmds) - } - - fn render_viewport( - &self, - phase: ViewportPhase, - data_index: usize, - viewport: &ViewportData, - cmds: &mut gpu::RenderBundleEncoder, - ) { - let frame_data = &self.frame_data[data_index]; - let render_pass = self.render_pass.read().unwrap(); - render_pass.render_viewport(phase, frame_data, viewport, cmds) - } -} - /// Mock GPU API (like Vulkan, WebGPU, or OpenGL) types for prototyping. pub mod gpu { /// Thread-safe GPU command recorder that's later executed in a command buffer. diff --git a/src/pass.rs b/src/pass.rs new file mode 100644 index 0000000..c18a80e --- /dev/null +++ b/src/pass.rs @@ -0,0 +1,122 @@ +//! Render pass data structures and interfaces. + +use crate::gpu; +use crate::phase::*; +use std::sync::{Arc, RwLock}; + +/// Viewport data shared by all passes, once the [ViewportPhase] group is +/// entered. +pub struct ViewportData; + +/// The render pass interface trait. +/// +/// Render passes are persistent structures that share GPU resources, user data, +/// and more across both phases and frames. +/// +/// Rendering functions record their GPU commands using the [gpu::RenderBundleEncoder] +/// passed to them. +pub trait RenderPass { + /// A structure that contains a pass's per-frame data. + type FrameData; + + /// Sets up a new instance of [Self::FrameData]. + /// + /// Called when a render pass is added to [crate::Renderer]. + fn create_frame_data(&mut self) -> Self::FrameData; + + /// Initializes this frame's [Self::FrameData], and queries the pass for + /// which phases to execute. + /// + /// This is the only opportunity the render pass has to mutate this frame's + /// data this frame, so all setup for future phases should be done here. + fn begin_frame(&mut self, data: &mut Self::FrameData, phases: &mut PhaseList); + + /// Renders a phase in the [PrePhase] group. + fn render_pre( + &self, + phase: PrePhase, + data: &Self::FrameData, + cmds: &mut gpu::RenderBundleEncoder, + ); + + /// Renders a phase in the [ViewportPhase] group. + /// + /// During these render phases, passes may have access to this frame's + /// [ViewportData]. + fn render_viewport( + &self, + phase: ViewportPhase, + data: &Self::FrameData, + viewport: &ViewportData, + cmds: &mut gpu::RenderBundleEncoder, + ); +} + +/// The interface trait for [RenderPassBox], allowing use of a statically-sized +/// [Box] for storage. +/// +/// 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 { + fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList); + + fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder); + + fn render_viewport( + &self, + phase: ViewportPhase, + data_index: usize, + viewport: &ViewportData, + cmds: &mut gpu::RenderBundleEncoder, + ); +} + +/// A container for a reference-counted render pass instance and its frame data. +pub struct RenderPassBox { + render_pass: Arc>, + frame_data: Vec, +} + +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 { + let frame_data = { + let mut lock = render_pass.write().unwrap(); + (0..frame_num).map(|_| lock.create_frame_data()).collect() + }; + + Self { + render_pass, + frame_data, + } + } +} + +impl RenderPassBoxTrait for RenderPassBox { + fn begin_frame(&mut self, data_index: usize, phases: &mut PhaseList) { + let frame_data = &mut self.frame_data[data_index]; + let mut render_pass = self.render_pass.write().unwrap(); + render_pass.begin_frame(frame_data, phases) + } + + fn render_pre(&self, phase: PrePhase, data_index: usize, cmds: &mut gpu::RenderBundleEncoder) { + let frame_data = &self.frame_data[data_index]; + let render_pass = self.render_pass.read().unwrap(); + render_pass.render_pre(phase, frame_data, cmds) + } + + fn render_viewport( + &self, + phase: ViewportPhase, + data_index: usize, + viewport: &ViewportData, + cmds: &mut gpu::RenderBundleEncoder, + ) { + let frame_data = &self.frame_data[data_index]; + let render_pass = self.render_pass.read().unwrap(); + render_pass.render_viewport(phase, frame_data, viewport, cmds) + } +} diff --git a/src/phase.rs b/src/phase.rs index a985194..4a7201f 100644 --- a/src/phase.rs +++ b/src/phase.rs @@ -1,4 +1,4 @@ -//! Definitions and containers for rendering phase identifiers. +//! Definitions and containers for render phase identifiers. //! //! Rendering phases are organized into different groups, which represent //! different kinds of external data becoming available as the frame progresses.