Initial attempt to implement Render Graph
This commit is contained in:
parent
173cfe2acf
commit
3732fc5e3d
33 changed files with 8851 additions and 938 deletions
318
modules/khors-app/src/app.rs
Normal file
318
modules/khors-app/src/app.rs
Normal file
|
@ -0,0 +1,318 @@
|
|||
#![warn(dead_code)]
|
||||
use khors_core::{
|
||||
events::Events,
|
||||
module::{Module, ModulesStack},
|
||||
};
|
||||
use khors_graphics::{
|
||||
debug_gui::DebugGuiStack,
|
||||
render_module::{RenderModule as ThreadLocalModule, RenderModulesStack},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use flax::{component, Schedule, World};
|
||||
use vulkano::device::DeviceFeatures;
|
||||
use vulkano_util::{
|
||||
context::{VulkanoConfig, VulkanoContext},
|
||||
window::VulkanoWindows,
|
||||
};
|
||||
use winit::{
|
||||
event::{Event, WindowEvent},
|
||||
window::WindowId,
|
||||
};
|
||||
|
||||
component! {
|
||||
window_id: WindowId,
|
||||
|
||||
resources,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct App {
|
||||
name: String,
|
||||
modules: ModulesStack,
|
||||
thread_local_modules: RenderModulesStack,
|
||||
world: World,
|
||||
schedule: Schedule,
|
||||
events: Events,
|
||||
rx: flume::Receiver<AppEvent>,
|
||||
running: bool,
|
||||
event_cleanup_time: std::time::Duration,
|
||||
vk_context: VulkanoContext,
|
||||
vk_windows: VulkanoWindows,
|
||||
debug_gui_stack: DebugGuiStack,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
let mut events = Events::new();
|
||||
let (tx, rx) = flume::unbounded();
|
||||
events.subscribe_custom(tx);
|
||||
|
||||
let schedule = Schedule::builder().build();
|
||||
|
||||
let vk_config = VulkanoConfig {
|
||||
device_features: DeviceFeatures {
|
||||
dynamic_rendering: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let vk_context = VulkanoContext::new(vk_config);
|
||||
let vk_windows = VulkanoWindows::default();
|
||||
|
||||
Self {
|
||||
name: "Khors".into(),
|
||||
modules: ModulesStack::new(),
|
||||
thread_local_modules: RenderModulesStack::new(),
|
||||
world: World::new(),
|
||||
schedule,
|
||||
events,
|
||||
rx,
|
||||
running: false,
|
||||
event_cleanup_time: std::time::Duration::from_secs(60),
|
||||
vk_context,
|
||||
vk_windows,
|
||||
debug_gui_stack: DebugGuiStack::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<()> {
|
||||
self.running = true;
|
||||
|
||||
self.schedule.execute_par(&mut self.world).unwrap();
|
||||
|
||||
let vk_context = &mut self.vk_context;
|
||||
let vk_windows = &mut self.vk_windows;
|
||||
let world = &mut self.world;
|
||||
let events = &mut self.events;
|
||||
let frame_time = std::time::Duration::from_millis(16);
|
||||
let gui_stack = &mut self.debug_gui_stack;
|
||||
|
||||
for module in self.modules.iter_mut() {
|
||||
module.on_update(world, events, frame_time)?;
|
||||
}
|
||||
|
||||
for module in self.thread_local_modules.iter_mut() {
|
||||
module.on_update(gui_stack, vk_context, vk_windows, world, events, frame_time)?;
|
||||
}
|
||||
|
||||
self.handle_events();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_window<T>(&mut self, event_loop: &winit::event_loop::EventLoopWindowTarget<T>)
|
||||
where
|
||||
T: Clone + Send + Sync,
|
||||
{
|
||||
let vk_window_id = self.vk_windows.create_window(
|
||||
event_loop,
|
||||
&self.vk_context,
|
||||
&vulkano_util::window::WindowDescriptor {
|
||||
title: self.name.clone(),
|
||||
present_mode: vulkano::swapchain::PresentMode::Mailbox,
|
||||
..Default::default()
|
||||
},
|
||||
|_| {},
|
||||
);
|
||||
|
||||
let renderer = self.vk_windows.get_renderer(vk_window_id).unwrap();
|
||||
|
||||
self.world
|
||||
.set(resources(), window_id(), vk_window_id)
|
||||
.unwrap();
|
||||
|
||||
self.debug_gui_stack
|
||||
.add_gui(vk_window_id, event_loop, renderer, true, false);
|
||||
}
|
||||
|
||||
pub fn process_event_loop<T>(
|
||||
&mut self,
|
||||
event: winit::event::Event<T>,
|
||||
_elwt: &winit::event_loop::EventLoopWindowTarget<T>,
|
||||
) -> Result<bool>
|
||||
where
|
||||
T: Clone + Send + Sync,
|
||||
{
|
||||
match &event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
return Ok(true);
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Focused(_),
|
||||
..
|
||||
} => self.events().send(event.clone()),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(..) | WindowEvent::ScaleFactorChanged { .. },
|
||||
window_id,
|
||||
} => self
|
||||
.vk_windows
|
||||
.get_renderer_mut(*window_id)
|
||||
.unwrap()
|
||||
.resize(),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
window_id,
|
||||
} => 'redraw: {
|
||||
// Tasks for redrawing:
|
||||
// 1. Update state based on events
|
||||
// 2. Compute & Render
|
||||
// 3. Reset input state
|
||||
// 4. Update time & title
|
||||
|
||||
// The rendering part goes here:
|
||||
match self
|
||||
.vk_windows
|
||||
.get_renderer(*window_id)
|
||||
.unwrap()
|
||||
.window_size()
|
||||
{
|
||||
[w, h] => {
|
||||
// Skip this frame when minimized.
|
||||
if w == 0.0 || h == 0.0 {
|
||||
break 'redraw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.run()?;
|
||||
}
|
||||
Event::WindowEvent { window_id, event } => {
|
||||
let window = self.vk_windows.get_window(*window_id).unwrap();
|
||||
let gui = self.debug_gui_stack.get_mut(*window_id).unwrap();
|
||||
gui.update(window, event);
|
||||
}
|
||||
Event::AboutToWait => {
|
||||
self.vk_windows.iter().for_each(|(window_id, _)| {
|
||||
self.vk_windows
|
||||
.get_window(*window_id)
|
||||
.unwrap()
|
||||
.request_redraw()
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn handle_events(&mut self) {
|
||||
for event in self.rx.try_iter() {
|
||||
match event {
|
||||
AppEvent::Exit => self.running = false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_schedule(&mut self, schedule: Schedule) {
|
||||
self.schedule = schedule;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn world(&self) -> &World {
|
||||
&self.world
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn world_mut(&mut self) -> &mut World {
|
||||
&mut self.world
|
||||
}
|
||||
|
||||
pub fn events(&self) -> &Events {
|
||||
&self.events
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn events_mut(&mut self) -> &mut Events {
|
||||
&mut self.events
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the layer stack. The provided
|
||||
/// closure to construct the layer takes in the world and events.
|
||||
pub fn push_render_module<F, T>(&mut self, func: F)
|
||||
where
|
||||
F: FnOnce(
|
||||
&mut VulkanoContext,
|
||||
&mut VulkanoWindows,
|
||||
&mut Schedule,
|
||||
&mut World,
|
||||
&mut Events,
|
||||
) -> T,
|
||||
T: 'static + ThreadLocalModule,
|
||||
{
|
||||
let module = func(
|
||||
&mut self.vk_context,
|
||||
&mut self.vk_windows,
|
||||
&mut self.schedule,
|
||||
&mut self.world,
|
||||
&mut self.events,
|
||||
);
|
||||
self.thread_local_modules.push(module);
|
||||
}
|
||||
|
||||
/// Pushes a layer from the provided init closure to to the top of the layer stack. The provided
|
||||
/// closure to construct the layer takes in the world and events.
|
||||
pub fn push_module<F, T>(&mut self, func: F)
|
||||
where
|
||||
F: FnOnce(&mut Schedule, &mut World, &mut Events) -> T,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.schedule, &mut self.world, &mut self.events);
|
||||
self.modules.push(module);
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events, and may return an error which
|
||||
/// is propagated to the callee.
|
||||
#[allow(dead_code)]
|
||||
pub fn try_push_module<F, T, E>(&mut self, func: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> Result<T, E>,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events)?;
|
||||
self.modules.push(module);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events.
|
||||
#[allow(dead_code)]
|
||||
pub fn insert_module<F, T>(&mut self, index: usize, func: F)
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> T,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events);
|
||||
self.modules.insert(index, module);
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events, and may return an error which
|
||||
/// is propagated to the callee.
|
||||
#[allow(dead_code)]
|
||||
pub fn try_insert_module<F, T, E>(&mut self, index: usize, func: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> Result<T, E>,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events)?;
|
||||
self.modules.insert(index, module);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum AppEvent {
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
|
@ -1,318 +1 @@
|
|||
#![warn(dead_code)]
|
||||
use khors_core::{
|
||||
events::Events,
|
||||
module::{Module, ModulesStack},
|
||||
};
|
||||
use khors_graphics::{
|
||||
debug_gui::DebugGuiStack,
|
||||
render_module::{RenderModule as ThreadLocalModule, RenderModulesStack},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use flax::{component, Schedule, World};
|
||||
use vulkano::device::DeviceFeatures;
|
||||
use vulkano_util::{
|
||||
context::{VulkanoConfig, VulkanoContext},
|
||||
window::VulkanoWindows,
|
||||
};
|
||||
use winit::{
|
||||
event::{Event, WindowEvent},
|
||||
window::WindowId,
|
||||
};
|
||||
|
||||
component! {
|
||||
window_id: WindowId,
|
||||
|
||||
resources,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct App {
|
||||
name: String,
|
||||
modules: ModulesStack,
|
||||
thread_local_modules: RenderModulesStack,
|
||||
world: World,
|
||||
schedule: Schedule,
|
||||
events: Events,
|
||||
rx: flume::Receiver<AppEvent>,
|
||||
running: bool,
|
||||
event_cleanup_time: std::time::Duration,
|
||||
vk_context: VulkanoContext,
|
||||
vk_windows: VulkanoWindows,
|
||||
debug_gui_stack: DebugGuiStack,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
let mut events = Events::new();
|
||||
let (tx, rx) = flume::unbounded();
|
||||
events.subscribe_custom(tx);
|
||||
|
||||
let schedule = Schedule::builder().build();
|
||||
|
||||
let vk_config = VulkanoConfig {
|
||||
device_features: DeviceFeatures {
|
||||
dynamic_rendering: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let vk_context = VulkanoContext::new(vk_config);
|
||||
let vk_windows = VulkanoWindows::default();
|
||||
|
||||
Self {
|
||||
name: "Khors".into(),
|
||||
modules: ModulesStack::new(),
|
||||
thread_local_modules: RenderModulesStack::new(),
|
||||
world: World::new(),
|
||||
schedule,
|
||||
events,
|
||||
rx,
|
||||
running: false,
|
||||
event_cleanup_time: std::time::Duration::from_secs(60),
|
||||
vk_context,
|
||||
vk_windows,
|
||||
debug_gui_stack: DebugGuiStack::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<()> {
|
||||
self.running = true;
|
||||
|
||||
self.schedule.execute_par(&mut self.world).unwrap();
|
||||
|
||||
let vk_context = &mut self.vk_context;
|
||||
let vk_windows = &mut self.vk_windows;
|
||||
let world = &mut self.world;
|
||||
let events = &mut self.events;
|
||||
let frame_time = std::time::Duration::from_millis(16);
|
||||
let gui_stack = &mut self.debug_gui_stack;
|
||||
|
||||
for module in self.modules.iter_mut() {
|
||||
module.on_update(world, events, frame_time)?;
|
||||
}
|
||||
|
||||
for module in self.thread_local_modules.iter_mut() {
|
||||
module.on_update(gui_stack, vk_context, vk_windows, world, events, frame_time)?;
|
||||
}
|
||||
|
||||
self.handle_events();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_window<T>(&mut self, event_loop: &winit::event_loop::EventLoopWindowTarget<T>)
|
||||
where
|
||||
T: Clone + Send + Sync,
|
||||
{
|
||||
let vk_window_id = self.vk_windows.create_window(
|
||||
event_loop,
|
||||
&self.vk_context,
|
||||
&vulkano_util::window::WindowDescriptor {
|
||||
title: self.name.clone(),
|
||||
present_mode: vulkano::swapchain::PresentMode::Mailbox,
|
||||
..Default::default()
|
||||
},
|
||||
|_| {},
|
||||
);
|
||||
|
||||
let renderer = self.vk_windows.get_renderer(vk_window_id).unwrap();
|
||||
|
||||
self.world
|
||||
.set(resources(), window_id(), vk_window_id)
|
||||
.unwrap();
|
||||
|
||||
self.debug_gui_stack
|
||||
.add_gui(vk_window_id, event_loop, renderer, true, false);
|
||||
}
|
||||
|
||||
pub fn process_event_loop<T>(
|
||||
&mut self,
|
||||
event: winit::event::Event<T>,
|
||||
_elwt: &winit::event_loop::EventLoopWindowTarget<T>,
|
||||
) -> Result<bool>
|
||||
where
|
||||
T: Clone + Send + Sync,
|
||||
{
|
||||
match &event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
return Ok(true);
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Focused(_),
|
||||
..
|
||||
} => self.events().send(event.clone()),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(..) | WindowEvent::ScaleFactorChanged { .. },
|
||||
window_id,
|
||||
} => self
|
||||
.vk_windows
|
||||
.get_renderer_mut(*window_id)
|
||||
.unwrap()
|
||||
.resize(),
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::RedrawRequested,
|
||||
window_id,
|
||||
} => 'redraw: {
|
||||
// Tasks for redrawing:
|
||||
// 1. Update state based on events
|
||||
// 2. Compute & Render
|
||||
// 3. Reset input state
|
||||
// 4. Update time & title
|
||||
|
||||
// The rendering part goes here:
|
||||
match self
|
||||
.vk_windows
|
||||
.get_renderer(*window_id)
|
||||
.unwrap()
|
||||
.window_size()
|
||||
{
|
||||
[w, h] => {
|
||||
// Skip this frame when minimized.
|
||||
if w == 0.0 || h == 0.0 {
|
||||
break 'redraw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.run()?;
|
||||
}
|
||||
Event::WindowEvent { window_id, event } => {
|
||||
let window = self.vk_windows.get_window(*window_id).unwrap();
|
||||
let gui = self.debug_gui_stack.get_mut(*window_id).unwrap();
|
||||
gui.update(window, event);
|
||||
}
|
||||
Event::AboutToWait => {
|
||||
self.vk_windows.iter().for_each(|(window_id, _)| {
|
||||
self.vk_windows
|
||||
.get_window(*window_id)
|
||||
.unwrap()
|
||||
.request_redraw()
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn handle_events(&mut self) {
|
||||
for event in self.rx.try_iter() {
|
||||
match event {
|
||||
AppEvent::Exit => self.running = false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_schedule(&mut self, schedule: Schedule) {
|
||||
self.schedule = schedule;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn world(&self) -> &World {
|
||||
&self.world
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn world_mut(&mut self) -> &mut World {
|
||||
&mut self.world
|
||||
}
|
||||
|
||||
pub fn events(&self) -> &Events {
|
||||
&self.events
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn events_mut(&mut self) -> &mut Events {
|
||||
&mut self.events
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the layer stack. The provided
|
||||
/// closure to construct the layer takes in the world and events.
|
||||
pub fn push_render_module<F, T>(&mut self, func: F)
|
||||
where
|
||||
F: FnOnce(
|
||||
&mut VulkanoContext,
|
||||
&mut VulkanoWindows,
|
||||
&mut Schedule,
|
||||
&mut World,
|
||||
&mut Events,
|
||||
) -> T,
|
||||
T: 'static + ThreadLocalModule,
|
||||
{
|
||||
let module = func(
|
||||
&mut self.vk_context,
|
||||
&mut self.vk_windows,
|
||||
&mut self.schedule,
|
||||
&mut self.world,
|
||||
&mut self.events,
|
||||
);
|
||||
self.thread_local_modules.push(module);
|
||||
}
|
||||
|
||||
/// Pushes a layer from the provided init closure to to the top of the layer stack. The provided
|
||||
/// closure to construct the layer takes in the world and events.
|
||||
pub fn push_module<F, T>(&mut self, func: F)
|
||||
where
|
||||
F: FnOnce(&mut Schedule, &mut World, &mut Events) -> T,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.schedule, &mut self.world, &mut self.events);
|
||||
self.modules.push(module);
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events, and may return an error which
|
||||
/// is propagated to the callee.
|
||||
#[allow(dead_code)]
|
||||
pub fn try_push_module<F, T, E>(&mut self, func: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> Result<T, E>,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events)?;
|
||||
self.modules.push(module);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events.
|
||||
#[allow(dead_code)]
|
||||
pub fn insert_module<F, T>(&mut self, index: usize, func: F)
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> T,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events);
|
||||
self.modules.insert(index, module);
|
||||
}
|
||||
|
||||
/// Pushes a module from the provided init closure to to the top of the module stack. The provided
|
||||
/// closure to construct the module takes in the world and events, and may return an error which
|
||||
/// is propagated to the callee.
|
||||
#[allow(dead_code)]
|
||||
pub fn try_insert_module<F, T, E>(&mut self, index: usize, func: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce(&mut World, &mut Events) -> Result<T, E>,
|
||||
T: 'static + Module,
|
||||
{
|
||||
let module = func(&mut self.world, &mut self.events)?;
|
||||
self.modules.insert(index, module);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum AppEvent {
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
pub mod app;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue