Initial commit
This commit is contained in:
commit
dbad5cebd3
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "cyborg"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
strum = { version = "0.24", features = ["derive"] }
|
|
@ -0,0 +1,208 @@
|
||||||
|
//! Cyborg is a high-performance, modern, experimental rendering engine written
|
||||||
|
//! in Rust.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, strum::EnumIter)]
|
||||||
|
pub enum PrePhase {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, strum::EnumIter)]
|
||||||
|
pub enum ViewportPhase {}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct PhaseList {
|
||||||
|
pub pre: Vec<PrePhase>,
|
||||||
|
pub viewport: Vec<ViewportPhase>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhaseList {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.pre.clear();
|
||||||
|
self.viewport.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct PhaseMultiMap<T> {
|
||||||
|
pub pre: HashMap<PrePhase, Vec<T>>,
|
||||||
|
pub viewport: HashMap<ViewportPhase, Vec<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy + PartialEq> PhaseMultiMap<T> {
|
||||||
|
pub fn insert_multi(&mut self, keys: &PhaseList, val: T) {
|
||||||
|
for pre in keys.pre.iter() {
|
||||||
|
Self::insert(&mut self.pre, pre, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
for viewport in keys.viewport.iter() {
|
||||||
|
Self::insert(&mut self.viewport, viewport, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_pre<'a>(&'a self, phase: &'a PrePhase) -> std::slice::Iter<'a, T> {
|
||||||
|
Self::iter(&self.pre, phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_viewport<'a>(&'a self, phase: &'a ViewportPhase) -> std::slice::Iter<'a, T> {
|
||||||
|
Self::iter(&self.viewport, phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert<K>(map: &mut HashMap<K, Vec<T>>, key: &K, val: T)
|
||||||
|
where
|
||||||
|
K: std::hash::Hash + Eq + Copy,
|
||||||
|
{
|
||||||
|
if let Some(existing) = map.get_mut(key) {
|
||||||
|
if !existing.contains(&val) {
|
||||||
|
existing.push(val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.insert(*key, vec![val]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter<'a, K>(map: &'a HashMap<K, Vec<T>>, key: &'a K) -> std::slice::Iter<'a, T>
|
||||||
|
where
|
||||||
|
K: std::hash::Hash + Eq + Copy,
|
||||||
|
{
|
||||||
|
if let Some(vals) = map.get(key) {
|
||||||
|
vals.iter()
|
||||||
|
} else {
|
||||||
|
[].iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Box<dyn RenderPassBoxTrait>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn render(&mut self) {
|
||||||
|
let frame_index = 0;
|
||||||
|
|
||||||
|
let mut phase_passes = PhaseMultiMap::<usize>::default();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
for phase in PrePhase::iter() {
|
||||||
|
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() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T: RenderPass> {
|
||||||
|
render_pass: Arc<RwLock<T>>,
|
||||||
|
frame_data: Vec<T::FrameData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RenderPass> RenderPassBox<T> {
|
||||||
|
pub fn new(render_pass: Arc<RwLock<T>>, 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<T: RenderPass> RenderPassBoxTrait for RenderPassBox<T> {
|
||||||
|
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.
|
||||||
|
///
|
||||||
|
/// Also known as a:
|
||||||
|
/// - RenderBundleEncoder in WebGPU
|
||||||
|
/// - secondary command buffer in Vulkan
|
||||||
|
pub struct RenderBundleEncoder;
|
||||||
|
}
|
Loading…
Reference in New Issue