186 lines
6.0 KiB
Rust
186 lines
6.0 KiB
Rust
//! Render pass data structures and interfaces.
|
|
|
|
use crate::phase::Phase;
|
|
use std::sync::Arc;
|
|
|
|
pub mod debug;
|
|
pub mod mesh;
|
|
|
|
/// Viewport data shared by all passes, once the [ViewportPhase] group is
|
|
/// entered.
|
|
pub struct ViewportData;
|
|
|
|
/// Data passed to each render pass's recording phases.
|
|
pub struct PhaseData<'a, T> {
|
|
pub phase: Phase,
|
|
pub frame_data: T,
|
|
pub viewport_data: &'a ViewportData,
|
|
pub bind_viewport: &'a wgpu::BindGroup,
|
|
}
|
|
|
|
pub type IndexedPhaseData<'a> = PhaseData<'a, usize>;
|
|
|
|
/// 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: Send + Sync {
|
|
/// A structure that contains a pass's per-frame data.
|
|
type FrameData: Send + Sync;
|
|
|
|
/// Gets a short name for this pass.
|
|
fn get_name(&self) -> &str {
|
|
std::any::type_name::<Self>()
|
|
}
|
|
|
|
/// Sets up a new instance of [Self::FrameData].
|
|
///
|
|
/// Called when a render pass is added to [crate::Renderer].
|
|
fn create_frame_data(&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.
|
|
///
|
|
/// The render pass is also given access to the [queue][wgpu::Queue] this
|
|
/// frame will be submitted on, and can be used to transfer image or buffer
|
|
/// data to the GPU.
|
|
fn begin_frame(&self, data: &mut Self::FrameData, phases: &mut Vec<Phase>, queue: &wgpu::Queue);
|
|
|
|
fn record_commands(
|
|
&self,
|
|
_data: PhaseData<&Self::FrameData>,
|
|
_cmds: &mut wgpu::CommandEncoder,
|
|
) {
|
|
}
|
|
|
|
fn record_compute<'a>(
|
|
&'a self,
|
|
_data: PhaseData<&'a Self::FrameData>,
|
|
_cmds: &mut wgpu::ComputePass<'a>,
|
|
) {
|
|
}
|
|
|
|
fn record_render(&self, _data: PhaseData<&Self::FrameData>) -> Option<wgpu::RenderBundle> {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// 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: Send + Sync {
|
|
fn begin_frame(&mut self, data_index: usize, phases: &mut Vec<Phase>, queue: &wgpu::Queue);
|
|
|
|
fn record_commands(&self, data: IndexedPhaseData, cmds: &mut wgpu::CommandEncoder);
|
|
|
|
fn record_compute<'a>(&'a self, data: IndexedPhaseData<'a>, cmds: &mut wgpu::ComputePass<'a>);
|
|
|
|
fn record_render(&self, data: IndexedPhaseData) -> Option<wgpu::RenderBundle>;
|
|
}
|
|
|
|
/// A container for a reference-counted render pass instance and its frame data.
|
|
pub struct RenderPassBox<T: RenderPass> {
|
|
render_pass: Arc<T>,
|
|
frame_data: Vec<T::FrameData>,
|
|
}
|
|
|
|
impl<T: 'static + RenderPass> RenderPassBox<T> {
|
|
/// 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<T>, frame_num: usize) -> Self {
|
|
let frame_data = {
|
|
(0..frame_num)
|
|
.map(|_| render_pass.create_frame_data())
|
|
.collect()
|
|
};
|
|
|
|
Self {
|
|
render_pass,
|
|
frame_data,
|
|
}
|
|
}
|
|
|
|
/// Same as [Self::new], but creates a boxed [RenderPassBoxTrait] in a
|
|
/// generic-friendly interface.
|
|
pub fn new_boxed(render_pass: Arc<T>, frame_num: usize) -> Box<dyn RenderPassBoxTrait> {
|
|
Box::new(Self::new(render_pass, frame_num))
|
|
}
|
|
}
|
|
|
|
impl<T: RenderPass> RenderPassBox<T> {
|
|
fn get_frame_data<'a>(
|
|
&'a self,
|
|
index: IndexedPhaseData<'a>,
|
|
) -> PhaseData<'a, &'a T::FrameData> {
|
|
let PhaseData {
|
|
phase,
|
|
frame_data,
|
|
viewport_data,
|
|
bind_viewport,
|
|
} = index;
|
|
|
|
let frame_data = self.frame_data.get(frame_data).unwrap();
|
|
|
|
PhaseData {
|
|
phase,
|
|
frame_data,
|
|
viewport_data,
|
|
bind_viewport,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: RenderPass> std::ops::Deref for RenderPassBox<T> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
self.render_pass.as_ref()
|
|
}
|
|
}
|
|
|
|
impl<T: RenderPass> RenderPassBoxTrait for RenderPassBox<T> {
|
|
fn begin_frame(&mut self, data_index: usize, phases: &mut Vec<Phase>, queue: &wgpu::Queue) {
|
|
let rp = &self.render_pass;
|
|
let name = rp.get_name();
|
|
puffin::profile_scope!("RenderPass::begin_frame(...)", name);
|
|
let frame_data = &mut self.frame_data[data_index];
|
|
rp.begin_frame(frame_data, phases, queue)
|
|
}
|
|
|
|
fn record_commands(&self, data: IndexedPhaseData, cmds: &mut wgpu::CommandEncoder) {
|
|
let rp = &self.render_pass;
|
|
let name = rp.get_name();
|
|
let scope = format!("{} (phase: {:?})", name, data.phase);
|
|
puffin::profile_scope!("RenderPass::record_commands(...)", scope);
|
|
let frame_data = self.get_frame_data(data);
|
|
rp.record_commands(frame_data, cmds)
|
|
}
|
|
|
|
fn record_compute<'a>(&'a self, data: IndexedPhaseData<'a>, cmds: &mut wgpu::ComputePass<'a>) {
|
|
let rp = &self.render_pass;
|
|
let name = rp.get_name();
|
|
let scope = format!("{} (phase: {:?})", name, data.phase);
|
|
puffin::profile_scope!("RenderPass::record_compute(...)", scope);
|
|
let frame_data = self.get_frame_data(data);
|
|
rp.record_compute(frame_data, cmds)
|
|
}
|
|
|
|
fn record_render(&self, data: IndexedPhaseData) -> Option<wgpu::RenderBundle> {
|
|
let rp = &self.render_pass;
|
|
let name = rp.get_name();
|
|
let scope = format!("{} (phase: {:?})", name, data.phase);
|
|
puffin::profile_scope!("RenderPass::record_render(...)", scope);
|
|
let frame_data = self.get_frame_data(data);
|
|
rp.record_render(frame_data)
|
|
}
|
|
}
|