Started major rework of the code
+ added defined code structure + started implementing generic outputs + added support for multiples windows + switched to frame-based architecture
This commit is contained in:
parent
7dc22f026e
commit
8992c06d16
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -44,6 +44,17 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
@ -126,6 +137,17 @@ dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.7.0"
|
||||
@ -205,6 +227,7 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"log",
|
||||
]
|
||||
|
||||
@ -269,6 +292,15 @@ dependencies = [
|
||||
"raw-window-handle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.2"
|
||||
@ -293,6 +325,8 @@ dependencies = [
|
||||
"gfx-backend-vulkan",
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"num-traits",
|
||||
"raw-window-handle",
|
||||
"winit",
|
||||
]
|
||||
|
||||
@ -502,9 +536,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
@ -9,9 +9,11 @@ edition = "2018"
|
||||
[dependencies]
|
||||
log = "0.4.8"
|
||||
chrono = "0.4.11"
|
||||
fern = "0.6.0"
|
||||
fern = { version = "0.6.0", features = ["colored"] }
|
||||
gfx-hal = "0.5.0"
|
||||
winit = "0.22.0"
|
||||
raw-window-handle = "0.3.3"
|
||||
num-traits = "0.2.12"
|
||||
|
||||
[dependencies.gfx-backend-vulkan]
|
||||
version = "0.5"
|
||||
@ -23,5 +25,5 @@ path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "iv"
|
||||
path = "src/bin/main.rs"
|
||||
path = "main.rs"
|
||||
|
||||
|
||||
1
doc/architecture
Normal file
1
doc/architecture
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2020-09-01T11:10:06.803Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.5.3 Chrome/83.0.4103.122 Electron/9.2.1 Safari/537.36" etag="TUY_ullQ74L3nj0ZrbPn" version="12.5.3" type="device"><diagram id="nEmVVCywiwsQaQufvWWo" name="Page-1">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</diagram></mxfile>
|
||||
@ -1,17 +1,26 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
|
||||
use chrono;
|
||||
|
||||
use ::iv::run;
|
||||
|
||||
fn setup_logger() -> Result<(), fern::InitError> {
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
|
||||
let colors = ColoredLevelConfig::new()
|
||||
.info(Color::Green)
|
||||
.debug(Color::Magenta)
|
||||
.warn(Color::Yellow)
|
||||
.error(Color::Red);
|
||||
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
.format(move |out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"{}[{}][{}] {}",
|
||||
chrono::Local::now().format("[%H:%M:%S]"),
|
||||
record.level(),
|
||||
colors.color(record.level()),
|
||||
record.target(),
|
||||
message
|
||||
))
|
||||
225
src/lib.rs
225
src/lib.rs
@ -5,20 +5,25 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
sync::mpsc,
|
||||
thread,
|
||||
collections::HashMap,
|
||||
cell::RefCell,
|
||||
};
|
||||
//use std::{
|
||||
// sync::mpsc,
|
||||
// thread,
|
||||
// collections::HashMap,
|
||||
// cell::RefCell,
|
||||
//};
|
||||
|
||||
mod winit_state;
|
||||
use winit_state::WinitState;
|
||||
use gfx_backend_vulkan as vk_back;
|
||||
|
||||
use winit::{
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::ControlFlow,
|
||||
};
|
||||
pub mod utils;
|
||||
use crate::utils::Rect;
|
||||
|
||||
mod winit_window;
|
||||
use winit_window::WinitWindow;
|
||||
|
||||
//use winit::{
|
||||
// event::{Event, WindowEvent},
|
||||
// event_loop::ControlFlow,
|
||||
//};
|
||||
|
||||
mod renderer;
|
||||
use renderer::Renderer;
|
||||
@ -51,101 +56,117 @@ pub enum Input {
|
||||
|
||||
/// The main function of the library
|
||||
pub fn run() -> Result<(), &'static str> {
|
||||
let winit_state = WinitState::default();
|
||||
let mut renderer = Renderer::new(&winit_state.window)?;
|
||||
|
||||
let mut windows = vec![
|
||||
WinitWindow::new("IV", Rect {w: 1280, h: 720})?,
|
||||
WinitWindow::new("IV 2", Rect {w: 720, h: 480})?,
|
||||
];
|
||||
|
||||
let mut renderer: Renderer<vk_back::Backend> = Renderer::new(&mut windows)?;
|
||||
//let local_state = LocalState::default();
|
||||
|
||||
let (input_tx, input_rx) = mpsc::channel();
|
||||
let mut window_senders = HashMap::with_capacity(1);
|
||||
window_senders.insert(1, input_tx);
|
||||
|
||||
let control_thread = RefCell::new(Some(thread::spawn(move || {
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||
let render_thread = thread::spawn(move || {
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
let mut color = [0.0, 0.0, 0.0, 0.0];
|
||||
let color = [0.5, 0.0, 0.0, 0.1];
|
||||
|
||||
loop {
|
||||
|
||||
//TODO manage errors
|
||||
let _ = renderer.draw_clear_frame(color);
|
||||
|
||||
match cmd_rx.try_recv().unwrap_or(Command::NoCommand) {
|
||||
Command::NoCommand => (),
|
||||
Command::Stop => {
|
||||
warn!("Stop render thread");
|
||||
return;
|
||||
},
|
||||
Command::Color{r, g, b, a} => {
|
||||
color = [r, g, b, a];
|
||||
},
|
||||
for mut window in &mut windows {
|
||||
let _ = renderer.draw_clear_frame(&mut window, color);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
match input_rx.recv().unwrap() {
|
||||
Input::Close => {
|
||||
cmd_tx.send(Command::Stop).unwrap();
|
||||
//TODO stop event_loop
|
||||
warn!("wait for render thread");
|
||||
render_thread.join().unwrap();
|
||||
warn!("Stop control thread");
|
||||
return;
|
||||
},
|
||||
Input::Mouse{x, y} => {
|
||||
let pos = Command::Color{
|
||||
r: (x/1280.0) as f32,
|
||||
g: (y/720.0) as f32,
|
||||
b: ((x/1280.0 + y/720.0)/2.0) as f32,
|
||||
a: 1.0,
|
||||
};
|
||||
cmd_tx.send(pos).unwrap();
|
||||
},
|
||||
}
|
||||
}
|
||||
})));
|
||||
|
||||
winit_state.event_loop.run(move |event, _, control_flow| {
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
//TODO manage errors
|
||||
let input_tx = window_senders.get(&1).unwrap();
|
||||
match event {
|
||||
Event::WindowEvent{window_id: _, event} => match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
input_tx.send(Input::Close).unwrap();
|
||||
let handle = control_thread.replace(None).unwrap();
|
||||
warn!("Wait for control thread");
|
||||
handle.join().unwrap();
|
||||
warn!("Stop input thread");
|
||||
*control_flow = ControlFlow::Exit;
|
||||
},
|
||||
WindowEvent::CursorMoved{position, ..} => {
|
||||
input_tx
|
||||
.send(Input::Mouse{
|
||||
x: position.x,
|
||||
y: position.y})
|
||||
.unwrap();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
||||
// let (input_tx, input_rx) = mpsc::channel();
|
||||
// let mut window_senders = HashMap::with_capacity(1);
|
||||
// window_senders.insert(1, input_tx);
|
||||
//
|
||||
// let control_thread = RefCell::new(Some(thread::spawn(move || {
|
||||
// #[allow(unused_imports)]
|
||||
// use log::{debug, error, info, trace, warn};
|
||||
//
|
||||
// let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||
// let render_thread = thread::spawn(move || {
|
||||
// #[allow(unused_imports)]
|
||||
// use log::{debug, error, info, trace, warn};
|
||||
//
|
||||
// let mut color = [0.0, 0.0, 0.0, 0.0];
|
||||
//
|
||||
// loop {
|
||||
//
|
||||
// //TODO manage errors
|
||||
// for window in windows {
|
||||
// let _ = renderer.draw_clear_frame(&mut window, color);
|
||||
// }
|
||||
//
|
||||
// match cmd_rx.try_recv().unwrap_or(Command::NoCommand) {
|
||||
// Command::NoCommand => (),
|
||||
// Command::Stop => {
|
||||
// warn!("Stop render thread");
|
||||
// return;
|
||||
// },
|
||||
// Command::Color{r, g, b, a} => {
|
||||
// color = [r, g, b, a];
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// loop {
|
||||
// match input_rx.recv().unwrap() {
|
||||
// Input::Close => {
|
||||
// cmd_tx.send(Command::Stop).unwrap();
|
||||
// //TODO stop event_loop
|
||||
// warn!("wait for render thread");
|
||||
// render_thread.join().unwrap();
|
||||
// warn!("Stop control thread");
|
||||
// return;
|
||||
// },
|
||||
// Input::Mouse{x, y} => {
|
||||
// let pos = Command::Color{
|
||||
// r: (x/1280.0) as f32,
|
||||
// g: (y/720.0) as f32,
|
||||
// b: ((x/1280.0 + y/720.0)/2.0) as f32,
|
||||
// a: 1.0,
|
||||
// };
|
||||
// cmd_tx.send(pos).unwrap();
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// })));
|
||||
//
|
||||
// windows[0].event_loop.run(move |event, _, control_flow| {
|
||||
// #[allow(unused_imports)]
|
||||
// use log::{debug, error, info, trace, warn};
|
||||
//
|
||||
// *control_flow = ControlFlow::Wait;
|
||||
//
|
||||
// //TODO manage errors
|
||||
// let input_tx = window_senders.get(&1).unwrap();
|
||||
// match event {
|
||||
// Event::WindowEvent{window_id: _, event} => match event {
|
||||
// WindowEvent::CloseRequested => {
|
||||
// input_tx.send(Input::Close).unwrap();
|
||||
// let handle = control_thread.replace(None).unwrap();
|
||||
// warn!("Wait for control thread");
|
||||
// handle.join().unwrap();
|
||||
// warn!("Stop input thread");
|
||||
// *control_flow = ControlFlow::Exit;
|
||||
// },
|
||||
// WindowEvent::CursorMoved{position, ..} => {
|
||||
// input_tx
|
||||
// .send(Input::Mouse{
|
||||
// x: position.x,
|
||||
// y: position.y})
|
||||
// .unwrap();
|
||||
// },
|
||||
// _ => (),
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
//
|
||||
//mod tests {
|
||||
// #[test]
|
||||
// fn it_works() {
|
||||
// assert_eq!(2 + 2, 4);
|
||||
// }
|
||||
//}
|
||||
|
||||
129
src/renderer.rs
129
src/renderer.rs
@ -1,42 +1,103 @@
|
||||
use std::mem::ManuallyDrop;
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use gfx_hal::{
|
||||
queue::QueueGroup,
|
||||
Backend,
|
||||
pso::Rect,
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
};
|
||||
|
||||
use gfx_backend_vulkan as vk_back;
|
||||
mod gpu;
|
||||
use gpu::Gpu;
|
||||
|
||||
pub mod init;
|
||||
pub mod render;
|
||||
mod swap_system;
|
||||
use swap_system::SwapSystem;
|
||||
|
||||
pub mod output;
|
||||
use output::Output;
|
||||
|
||||
//mod pipeline;
|
||||
//use pipeline::Pipeline;
|
||||
|
||||
//--Renderer implementation-------------------------------------------------------------------------
|
||||
#[derive(Debug)]
|
||||
pub struct Renderer {
|
||||
//items need to communicate with the GPU
|
||||
instance: ManuallyDrop<<vk_back::Backend as Backend>::Instance>,
|
||||
surface: ManuallyDrop<<vk_back::Backend as Backend>::Surface>,
|
||||
adapter: ManuallyDrop<gfx_hal::adapter::Adapter<vk_back::Backend>>,
|
||||
device: vk_back::Device,
|
||||
queue_group: ManuallyDrop<QueueGroup<vk_back::Backend>>,
|
||||
render_pass: ManuallyDrop<<vk_back::Backend as Backend>::RenderPass>,
|
||||
swapchain: ManuallyDrop<<vk_back::Backend as Backend>::Swapchain>,
|
||||
extent: gfx_hal::window::Extent2D,
|
||||
format: gfx_hal::format::Format,
|
||||
render_area: Rect,
|
||||
|
||||
//items needed to render the images
|
||||
sems_image_available: Vec<<vk_back::Backend as Backend>::Semaphore>,
|
||||
sems_render_finished: Vec<<vk_back::Backend as Backend>::Semaphore>,
|
||||
fences: Vec<<vk_back::Backend as Backend>::Fence>,
|
||||
image_views: Vec<<vk_back::Backend as Backend>::ImageView>,
|
||||
framebuffers: Vec<<vk_back::Backend as Backend>::Framebuffer>,
|
||||
|
||||
command_pool: ManuallyDrop<<vk_back::Backend as Backend>::CommandPool>,
|
||||
command_buffers: Vec<<vk_back::Backend as Backend>::CommandBuffer>,
|
||||
|
||||
//items needed to keep track of the images
|
||||
image_count: usize,
|
||||
current_image: usize,
|
||||
pub struct Renderer<B: gfx_hal::Backend> {
|
||||
instance: ManuallyDrop<B::Instance>,
|
||||
gpu: ManuallyDrop<Gpu<B>>,
|
||||
//pipelines: Vec<Pipeline<B>>,
|
||||
swap_systems: Vec<SwapSystem<B>>,
|
||||
}
|
||||
|
||||
impl<B> Drop for Renderer<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
debug!("Waiting for device to idle...");
|
||||
let _ = self.gpu
|
||||
.device()
|
||||
.wait_idle();
|
||||
|
||||
info!("Dropping Renderer...");
|
||||
for mut swap_system in self.swap_systems.drain(..) {
|
||||
swap_system.drop(&mut self.gpu, &self.instance);
|
||||
}
|
||||
// for mut pipeline in self.pipelines.drain(..) {
|
||||
//
|
||||
// }
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut self.gpu);
|
||||
ManuallyDrop::drop(&mut self.instance);
|
||||
}
|
||||
trace!("Renderer dropped !");
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Renderer<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
pub fn new<'a, H, T: 'a, I>(outputs: I) -> Result<Renderer<B>, &'static str>
|
||||
where
|
||||
H: raw_window_handle::HasRawWindowHandle,
|
||||
T: Output<H>,
|
||||
I: IntoIterator<Item = &'a mut T>,
|
||||
|
||||
{
|
||||
use gfx_hal::Instance;
|
||||
|
||||
info!("Creating renderer...");
|
||||
let instance = B::Instance::create("IV", 1)
|
||||
.map_err(|_| "Could not create instance")?;
|
||||
let (mut gpu, mut surfaces) = Gpu::new(&instance, outputs)
|
||||
.map_err(|err| err)?;
|
||||
let swap_systems = {
|
||||
surfaces
|
||||
.drain(..)
|
||||
.map(|surface| SwapSystem::new(&mut gpu, surface))
|
||||
.collect::<Result<Vec<_>, &str>>()?
|
||||
};
|
||||
|
||||
debug!("Renderer created !");
|
||||
Ok( Renderer {
|
||||
instance: ManuallyDrop::new(instance),
|
||||
gpu: ManuallyDrop::new(gpu),
|
||||
swap_systems,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn draw_clear_frame<T, O>(&mut self, output: &mut O, _color: [f32; 4])
|
||||
-> Result<(), &'static str>
|
||||
where
|
||||
T: raw_window_handle::HasRawWindowHandle,
|
||||
O: Output<T>
|
||||
{
|
||||
let swap_index = output.get_id();
|
||||
let frame = self.swap_systems[swap_index].acquire_frame();
|
||||
|
||||
frame.sync_gpu(&self.gpu);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
193
src/renderer/gpu.rs
Normal file
193
src/renderer/gpu.rs
Normal file
@ -0,0 +1,193 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
ptr::read,
|
||||
};
|
||||
|
||||
use gfx_hal::{
|
||||
adapter::Adapter,
|
||||
queue::QueueGroup,
|
||||
};
|
||||
|
||||
use gfx_hal::adapter::Gpu as GfxGpu;
|
||||
|
||||
use super::output::Output;
|
||||
|
||||
//--Gpu implementation------------------------------------------------------------------------------
|
||||
#[derive(Debug)]
|
||||
pub struct Gpu<B: gfx_hal::Backend> {
|
||||
adapter: ManuallyDrop<Adapter<B>>,
|
||||
device: ManuallyDrop<B::Device>,
|
||||
queue_group: ManuallyDrop<QueueGroup<B>>,
|
||||
command_pool: ManuallyDrop<B::CommandPool>,
|
||||
}
|
||||
|
||||
impl<B> Drop for Gpu<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
debug!("Dropping Gpu...");
|
||||
unsafe {
|
||||
self.device.destroy_command_pool(
|
||||
ManuallyDrop::into_inner(read(&mut self.command_pool)));
|
||||
ManuallyDrop::drop(&mut self.queue_group);
|
||||
ManuallyDrop::drop(&mut self.device);
|
||||
ManuallyDrop::drop(&mut self.adapter);
|
||||
}
|
||||
trace!("Gpu dropped !");
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Gpu<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
pub fn new<'a, H, T: 'a, I>(instance: &B::Instance, outputs: I)
|
||||
-> Result<(Gpu<B>, Vec<B::Surface>), &'static str>
|
||||
where
|
||||
H: raw_window_handle::HasRawWindowHandle,
|
||||
T: Output<H>,
|
||||
I: IntoIterator<Item = &'a mut T>,
|
||||
{
|
||||
use gfx_hal::{
|
||||
queue::family::QueueFamily,
|
||||
};
|
||||
|
||||
debug!("Creating Gpu...");
|
||||
trace!("Creating Surfaces...");
|
||||
let surfaces: Vec<_> = {
|
||||
use gfx_hal::Instance;
|
||||
|
||||
let mut id = 0;
|
||||
outputs
|
||||
.into_iter()
|
||||
.map(|output| unsafe {
|
||||
output.set_id(id);
|
||||
id += 1;
|
||||
|
||||
instance
|
||||
.create_surface(output.window())
|
||||
.map_err(|_| "Could not create surface")
|
||||
})
|
||||
.collect::<Result<Vec<_>, &str>>()?
|
||||
};
|
||||
|
||||
let adapter = {
|
||||
use gfx_hal::{
|
||||
Instance,
|
||||
window::Surface,
|
||||
};
|
||||
|
||||
// dry run to print all adapters for debug purposes
|
||||
trace!("Listing Adapters...");
|
||||
let adapters = instance
|
||||
.enumerate_adapters()
|
||||
.into_iter();
|
||||
debug!("Adapters : {:#?}", adapters);
|
||||
|
||||
// selecting an adapter suitabe for all surfaces used
|
||||
//TODO improve selection
|
||||
trace!("Selecting Adapter...");
|
||||
let adapter = instance
|
||||
.enumerate_adapters()
|
||||
.into_iter()
|
||||
.find(|a| {
|
||||
a.queue_families
|
||||
.iter()
|
||||
.any(|qf|
|
||||
QueueFamily::queue_type(qf).supports_graphics()
|
||||
&& surfaces
|
||||
.iter()
|
||||
.all(|surface|
|
||||
surface.supports_queue_family(&qf)
|
||||
))})
|
||||
.ok_or("Could not find a graphical adapter")?;
|
||||
info!("Selected adapter : {}", adapter.info.name);
|
||||
|
||||
adapter
|
||||
};
|
||||
|
||||
let (device, queue_group) = {
|
||||
// get the previously found QueueFamily index
|
||||
trace!("Getting QueueFamily index...");
|
||||
let queue_family = adapter
|
||||
.queue_families
|
||||
.iter()
|
||||
.find(|qf|
|
||||
QueueFamily::queue_type(*qf).supports_graphics())
|
||||
//&& Surface::supports_queue_family(&surface, &qf))
|
||||
.ok_or("Could not find suitable queue_family")?;
|
||||
|
||||
// get the related PhysicalDevice and QueueFamily list
|
||||
trace!("Get Device and QueueGroups...");
|
||||
let GfxGpu {device, queue_groups} = unsafe {
|
||||
use gfx_hal::{
|
||||
adapter::PhysicalDevice,
|
||||
Features,
|
||||
};
|
||||
|
||||
adapter
|
||||
.physical_device
|
||||
.open(&[(&queue_family, &[1.0; 1])], Features::empty())
|
||||
.map_err(|_| "Could not open physical device")?
|
||||
};
|
||||
|
||||
// retrieve the selected QueueFamily
|
||||
trace!("Selecting QueueGroup...");
|
||||
let queue_group = queue_groups
|
||||
.into_iter()
|
||||
.find(|qg| qg.family == queue_family.id())
|
||||
.ok_or("Could not take ownership of the queue")?;
|
||||
|
||||
// check the QueueGroup
|
||||
trace!("Checking selected QueueGroup...");
|
||||
if queue_group.queues.len() <= 0 {
|
||||
return Err("The QueueGroup does not have any CommandQueues available");
|
||||
};
|
||||
|
||||
(device, queue_group)
|
||||
};
|
||||
|
||||
let command_pool = unsafe {
|
||||
use gfx_hal::{
|
||||
pool::CommandPoolCreateFlags,
|
||||
device::Device,
|
||||
};
|
||||
|
||||
trace!("Creating CommandPool...");
|
||||
device
|
||||
.create_command_pool(queue_group.family,
|
||||
CommandPoolCreateFlags::RESET_INDIVIDUAL)
|
||||
.map_err(|_| "Could not create CommandPool")?
|
||||
};
|
||||
|
||||
debug!("Gpu created !");
|
||||
Ok((
|
||||
Gpu {
|
||||
adapter: ManuallyDrop::new(adapter),
|
||||
device: ManuallyDrop::new(device),
|
||||
queue_group: ManuallyDrop::new(queue_group),
|
||||
command_pool: ManuallyDrop::new(command_pool),
|
||||
},
|
||||
surfaces
|
||||
))
|
||||
}
|
||||
|
||||
pub fn adapter(&self) -> &Adapter<B> {
|
||||
&self.adapter
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &B::Device {
|
||||
&self.device
|
||||
}
|
||||
|
||||
pub fn command_pool_mut(&mut self) -> &mut B::CommandPool {
|
||||
&mut self.command_pool
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,415 +0,0 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
};
|
||||
|
||||
use core::ptr::read;
|
||||
|
||||
use gfx_hal::{
|
||||
Instance,
|
||||
device::Device,
|
||||
Backend,
|
||||
pool::CommandPool,
|
||||
pso::Rect,
|
||||
};
|
||||
|
||||
use gfx_backend_vulkan as vk_back;
|
||||
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::renderer::Renderer;
|
||||
|
||||
impl core::ops::Drop for Renderer {
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
fn drop(&mut self) {
|
||||
|
||||
let _ = self.device.wait_idle();
|
||||
|
||||
//destroy all underlying ressources
|
||||
debug!("Destroying Renderer ressources");
|
||||
unsafe {
|
||||
self.command_pool.free(self.command_buffers.drain(..));
|
||||
self.device.destroy_command_pool(
|
||||
ManuallyDrop::into_inner(read(&mut self.command_pool)));
|
||||
for buffer in self.framebuffers.drain(..) {
|
||||
self.device.destroy_framebuffer(buffer);
|
||||
}
|
||||
for view in self.image_views.drain(..) {
|
||||
self.device.destroy_image_view(view);
|
||||
}
|
||||
for fence in self.fences.drain(..) {
|
||||
self.device.destroy_fence(fence);
|
||||
}
|
||||
for sem in self.sems_image_available.drain(..) {
|
||||
self.device.destroy_semaphore(sem);
|
||||
}
|
||||
for sem in self.sems_render_finished.drain(..) {
|
||||
self.device.destroy_semaphore(sem);
|
||||
}
|
||||
self.device.destroy_swapchain(ManuallyDrop::into_inner(read(&mut self.swapchain)));
|
||||
self.device.destroy_render_pass(ManuallyDrop::into_inner(read(&mut self.render_pass)));
|
||||
ManuallyDrop::drop(&mut self.queue_group);
|
||||
ManuallyDrop::drop(&mut self.adapter);
|
||||
self.instance.destroy_surface(ManuallyDrop::into_inner(read(&mut self.surface)));
|
||||
ManuallyDrop::drop(&mut self.instance);
|
||||
}
|
||||
info!("Renderer ressources destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
pub fn update_swapchain(&mut self) -> Result<(), &'static str> {
|
||||
use gfx_hal::window::{
|
||||
SwapchainConfig,
|
||||
Surface,
|
||||
PresentationSurface,
|
||||
};
|
||||
|
||||
debug!("Updating swapchain");
|
||||
|
||||
//creating new swapchain config
|
||||
let capabilities = self.surface.capabilities(&self.adapter.physical_device);
|
||||
let swapchain_config = SwapchainConfig::from_caps(&capabilities, self.format, self.extent);
|
||||
info!("{:?}", swapchain_config);
|
||||
|
||||
self.device
|
||||
.wait_idle()
|
||||
.map_err(|_| "Failed to to wait for device to be idle")?;
|
||||
|
||||
unsafe {
|
||||
self.surface
|
||||
.configure_swapchain(&self.device, swapchain_config)
|
||||
.map_err(|_| "Failed to updtate swapchain")?;
|
||||
debug!("update succesfull !");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
pub fn new(window: &Window) -> Result<Renderer, &'static str> {
|
||||
use gfx_hal::adapter::Gpu;
|
||||
|
||||
// create top level
|
||||
let instance = vk_back::Instance::create("IV", 1)
|
||||
.map_err(|_| "Could not create instance")?;
|
||||
|
||||
let mut surface = unsafe {
|
||||
instance
|
||||
.create_surface(window)
|
||||
.map_err(|_| "Could not create Surface")?
|
||||
};
|
||||
|
||||
let (adapter, device, queue_group) = {
|
||||
use gfx_hal::{
|
||||
window::Surface,
|
||||
queue::family::QueueFamily,
|
||||
};
|
||||
|
||||
// find a adapter with a suitable queue family
|
||||
// TODO add weight for adapters
|
||||
let adapter =
|
||||
Instance::enumerate_adapters(&instance)
|
||||
.into_iter();
|
||||
// .find(|a| {
|
||||
// a.queue_families
|
||||
// .iter()
|
||||
// .any(|qf|
|
||||
// QueueFamily::queue_type(qf).supports_graphics()
|
||||
// && Surface::supports_queue_family(&surface, &qf)
|
||||
// )})
|
||||
// .ok_or("Could not find a graphical adapter")?;
|
||||
|
||||
debug!("Adapters : {:#?}", adapter);
|
||||
|
||||
let adapter =
|
||||
Instance::enumerate_adapters(&instance)
|
||||
.into_iter()
|
||||
.find(|a| {
|
||||
a.queue_families
|
||||
.iter()
|
||||
.any(|qf|
|
||||
QueueFamily::queue_type(qf).supports_graphics()
|
||||
&& Surface::supports_queue_family(&surface, &qf)
|
||||
)})
|
||||
.ok_or("Could not find a graphical adapter")?;
|
||||
|
||||
info!("Selected adapter : {}", adapter.info.name);
|
||||
|
||||
// get the suitable queue family index
|
||||
let queue_family = adapter
|
||||
.queue_families
|
||||
.iter()
|
||||
.find(|qf|
|
||||
QueueFamily::queue_type(*qf).supports_graphics()
|
||||
&& Surface::supports_queue_family(&surface, &qf))
|
||||
.ok_or("Could not find suitable queue_family")?;
|
||||
|
||||
// get the related physical device and queue family list
|
||||
let Gpu {device, queue_groups} = unsafe {
|
||||
use gfx_hal::{
|
||||
adapter::PhysicalDevice,
|
||||
Features,
|
||||
};
|
||||
|
||||
adapter
|
||||
.physical_device
|
||||
.open(&[(&queue_family, &[1.0; 1])], Features::empty())
|
||||
.map_err(|_| "Could not open physical device")?
|
||||
};
|
||||
|
||||
// retrieve the selected queue family
|
||||
let queue_group = queue_groups
|
||||
.into_iter()
|
||||
.find(|qg| qg.family == queue_family.id())
|
||||
.ok_or("Could not take ownership of the queue")?;
|
||||
|
||||
// check our harvest
|
||||
if queue_group.queues.len() <= 0 {
|
||||
return Err("The QueueGroup does not have any CommandQueues available");
|
||||
};
|
||||
|
||||
(adapter, device, queue_group)
|
||||
};
|
||||
|
||||
let (swapchain, extent, backbuffer, format, image_count) = {
|
||||
use gfx_hal::window::{
|
||||
SwapchainConfig,
|
||||
Surface,
|
||||
};
|
||||
|
||||
let capabilities = surface.capabilities(&adapter.physical_device);
|
||||
debug!("{:#?}", capabilities);
|
||||
|
||||
// select optimal presentation mode (vsync, triple buffuring, ...)
|
||||
let present_mode = {
|
||||
use gfx_hal::window::PresentMode;
|
||||
|
||||
[PresentMode::MAILBOX, PresentMode::FIFO,
|
||||
PresentMode::RELAXED, PresentMode::IMMEDIATE]
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|pm| capabilities.present_modes.contains(*pm))
|
||||
.ok_or("No PresentMode found")?
|
||||
};
|
||||
|
||||
// select optimal alpha composition
|
||||
// let composite_alpha_mode = {
|
||||
// use gfx_hal::window::CompositeAlphaMode;
|
||||
//
|
||||
// [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT,
|
||||
// CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED]
|
||||
// .iter()
|
||||
// .cloned()
|
||||
// .find(|cam| capabilities.composite_alpha_modes.contains(*cam))
|
||||
// .ok_or("No CompositeAlphaMode found")?
|
||||
// };
|
||||
|
||||
// select optimal format (sRGB)
|
||||
let format = {
|
||||
use gfx_hal::format::{Format, ChannelType};
|
||||
|
||||
match surface.supported_formats(&adapter.physical_device) {
|
||||
None => Format::Rgba8Srgb,
|
||||
Some(formats) => formats
|
||||
.iter()
|
||||
.find(|f| f.base_format().1 == ChannelType::Srgb)
|
||||
.cloned()
|
||||
.ok_or("Could no find suitabe format")?
|
||||
}};
|
||||
|
||||
let extent = capabilities.extents.end().clone();
|
||||
|
||||
// verify swapchain size
|
||||
let image_count = {
|
||||
use gfx_hal::window::PresentMode;
|
||||
|
||||
capabilities.image_count.end()
|
||||
.min(capabilities.image_count.start()
|
||||
.max(match present_mode {
|
||||
PresentMode::MAILBOX => &3,
|
||||
PresentMode::FIFO => &2,
|
||||
_ => &1,
|
||||
})).clone()
|
||||
};
|
||||
debug!("image count : {}", image_count);
|
||||
|
||||
// // a surface support at least one layer
|
||||
// let image_layers = 1;
|
||||
//
|
||||
// // verify surface compatibility
|
||||
// let image_usage = {
|
||||
// use gfx_hal::image::Usage;
|
||||
//
|
||||
// if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) {
|
||||
// Ok(Usage::COLOR_ATTACHMENT)
|
||||
// } else {
|
||||
// Err("This surface does not support color")
|
||||
// }
|
||||
// }?;
|
||||
|
||||
let swapchain_config = SwapchainConfig::from_caps(&capabilities, format, extent);
|
||||
debug!("{:?}", swapchain_config);
|
||||
|
||||
let (swapchain, backbuffer) = unsafe {
|
||||
device
|
||||
.create_swapchain(&mut surface, swapchain_config, None)
|
||||
.map_err(|_| "Failed to create swapchain and backbuffer")?
|
||||
};
|
||||
|
||||
(swapchain, extent, backbuffer, format, image_count as usize)
|
||||
};
|
||||
|
||||
// creating semaphores and fences
|
||||
let (sems_image_available, sems_render_finished, fences) = {
|
||||
|
||||
let mut sems_image_available : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
|
||||
let mut sems_render_finished : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
|
||||
let mut fences :Vec<<vk_back::Backend as Backend>::Fence> = vec![];
|
||||
|
||||
for _ in 0..image_count {
|
||||
sems_image_available
|
||||
.push(device
|
||||
.create_semaphore()
|
||||
.map_err(|_| "Could not create sempahore")?
|
||||
);
|
||||
sems_render_finished
|
||||
.push(device
|
||||
.create_semaphore()
|
||||
.map_err(|_| "Could not create sempahore")?
|
||||
);
|
||||
fences
|
||||
.push(device
|
||||
.create_fence(true)
|
||||
.map_err(|_| "Could not create fence")?
|
||||
);
|
||||
}
|
||||
|
||||
(sems_image_available, sems_render_finished, fences)
|
||||
};
|
||||
|
||||
// creating RenderPass
|
||||
let render_pass = {
|
||||
use gfx_hal::{
|
||||
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
|
||||
image::Layout,
|
||||
};
|
||||
|
||||
let color_attachment = Attachment {
|
||||
format : Some(format),
|
||||
samples : 1,
|
||||
ops : AttachmentOps {
|
||||
load : AttachmentLoadOp::Clear,
|
||||
store : AttachmentStoreOp::Store,
|
||||
},
|
||||
stencil_ops : AttachmentOps::DONT_CARE,
|
||||
layouts : (Layout::Undefined..Layout::Present),
|
||||
};
|
||||
|
||||
let subpass = SubpassDesc {
|
||||
colors : &[(0, Layout::ColorAttachmentOptimal)],
|
||||
depth_stencil : None,
|
||||
inputs : &[],
|
||||
resolves : &[],
|
||||
preserves : &[],
|
||||
};
|
||||
|
||||
unsafe {
|
||||
device.create_render_pass(&[color_attachment], &[subpass], &[])
|
||||
.map_err(|_| "Could not create render pass")?
|
||||
}
|
||||
};
|
||||
|
||||
// add ImageView "headers" to images in BackBuffer
|
||||
let image_views : Vec<_> = {
|
||||
use gfx_hal::{
|
||||
image::{ViewKind, SubresourceRange},
|
||||
format::{Swizzle, Aspects},
|
||||
};
|
||||
|
||||
backbuffer
|
||||
.iter()
|
||||
.map(|img| unsafe {
|
||||
device
|
||||
.create_image_view(
|
||||
&img,
|
||||
ViewKind::D2,
|
||||
format,
|
||||
Swizzle::NO,
|
||||
SubresourceRange {
|
||||
aspects : Aspects::COLOR,
|
||||
levels : 0..1,
|
||||
layers : 0..1,
|
||||
},
|
||||
)
|
||||
.map_err(|_| "Could not create ImageViews")
|
||||
})
|
||||
.collect::<Result<Vec<_>, &str>>()?
|
||||
};
|
||||
|
||||
let framebuffers: Vec<_> = {
|
||||
|
||||
image_views
|
||||
.iter()
|
||||
.map(|image_view|
|
||||
unsafe {
|
||||
device
|
||||
.create_framebuffer(&render_pass, vec![image_view], extent.to_extent())
|
||||
.map_err(|_| "Could not create FrameBuffer")
|
||||
},
|
||||
)
|
||||
.collect::<Result<Vec<_>, &str>>()?
|
||||
};
|
||||
|
||||
let mut command_pool = unsafe {
|
||||
use gfx_hal::pool::CommandPoolCreateFlags;
|
||||
|
||||
device
|
||||
.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
|
||||
.map_err(|_| "Could not create CommandPool")?
|
||||
};
|
||||
|
||||
let command_buffers: Vec<_> = unsafe {
|
||||
use gfx_hal::command::Level;
|
||||
|
||||
framebuffers
|
||||
.iter()
|
||||
.map(|_| command_pool.allocate_one(Level::Primary))
|
||||
.collect()
|
||||
};
|
||||
|
||||
info!("HAL successfully initialized");
|
||||
|
||||
Ok(
|
||||
Renderer {
|
||||
instance: ManuallyDrop::new(instance),
|
||||
surface: ManuallyDrop::new(surface),
|
||||
adapter: ManuallyDrop::new(adapter),
|
||||
device: device,
|
||||
queue_group: ManuallyDrop::new(queue_group),
|
||||
render_pass: ManuallyDrop::new(render_pass),
|
||||
swapchain: ManuallyDrop::new(swapchain),
|
||||
extent: extent,
|
||||
format: format,
|
||||
render_area: Rect{x: 0, y: 0, w: 1280, h: 720},
|
||||
sems_image_available,
|
||||
sems_render_finished,
|
||||
fences,
|
||||
image_views,
|
||||
framebuffers,
|
||||
|
||||
command_pool: ManuallyDrop::new(command_pool),
|
||||
command_buffers,
|
||||
|
||||
image_count,
|
||||
current_image: 0,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
43
src/renderer/output.rs
Normal file
43
src/renderer/output.rs
Normal file
@ -0,0 +1,43 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
|
||||
use crate::utils::Rect;
|
||||
|
||||
//--Output trait------------------------------------------------------------------------------------
|
||||
pub trait Output<T>
|
||||
where
|
||||
T: HasRawWindowHandle,
|
||||
{
|
||||
fn get_id(&self) -> usize;
|
||||
fn set_id(&mut self, id: usize);
|
||||
|
||||
fn size(&mut self) -> &mut Rect<i32>;
|
||||
|
||||
fn window(&self) -> &T;
|
||||
}
|
||||
|
||||
//impl<'a, T, O> Output<T> for &'a O
|
||||
//where
|
||||
// T: HasRawWindowHandle,
|
||||
// O: Output<T> {
|
||||
// fn id(&mut self) -> &mut i32 { Output::id(*self) }
|
||||
//
|
||||
// fn size(&mut self) -> &mut Rect<i32> { Output::size(*self) }
|
||||
//
|
||||
// fn window(&self) -> &T { Output::window(*self) }
|
||||
//}
|
||||
|
||||
impl<'a, T, O> Output<T> for &'a mut O
|
||||
where
|
||||
T: HasRawWindowHandle,
|
||||
O: Output<T> {
|
||||
fn get_id(&self) -> usize { Output::get_id(*self) }
|
||||
fn set_id(&mut self, id: usize) { Output::set_id(*self, id); }
|
||||
|
||||
fn size(&mut self) -> &mut Rect<i32> { Output::size(*self) }
|
||||
|
||||
fn window(&self) -> &T { Output::window(*self) }
|
||||
}
|
||||
|
||||
20
src/renderer/pipeline.rs
Normal file
20
src/renderer/pipeline.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
};
|
||||
|
||||
//--Pipeline implementation-------------------------------------------------------------------------
|
||||
#[derive(Debug)]
|
||||
pub struct Pipeline<B: gfx_hal::Backend> {
|
||||
render_pass: ManuallyDrop<B::RenderPass>,
|
||||
}
|
||||
|
||||
impl<B> Pipeline<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::iter;
|
||||
|
||||
use gfx_hal::{
|
||||
device::Device,
|
||||
window::Swapchain,
|
||||
command::CommandBuffer,
|
||||
};
|
||||
|
||||
use crate::renderer::Renderer;
|
||||
|
||||
impl Renderer {
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
pub fn draw_clear_frame(&mut self, color: [f32; 4]) -> Result<(), &'static str> {
|
||||
use gfx_hal::{
|
||||
command::{SubpassContents, ClearValue, ClearColor, CommandBufferFlags},
|
||||
queue::{Submission, CommandQueue},
|
||||
pso::PipelineStage,
|
||||
};
|
||||
|
||||
// get current frame fence
|
||||
let fence = &self.fences[self.current_image];
|
||||
|
||||
//wait for current fence in case we are submiting too fast
|
||||
unsafe {
|
||||
self.device
|
||||
.wait_for_fence(fence, !0)
|
||||
.map_err(|_| "Failed to wait for fence")?;
|
||||
self.device
|
||||
.reset_fence(fence)
|
||||
.map_err(|_| "Failed to reset fence")?;
|
||||
}
|
||||
|
||||
// get current frame semaphores
|
||||
let sem_image_available = &self.sems_image_available[self.current_image];
|
||||
let sem_render_finished = &self.sems_render_finished[self.current_image];
|
||||
|
||||
// acquire image id in swapchain
|
||||
let swp_image_id = unsafe {
|
||||
match self.swapchain.acquire_image(core::u64::MAX, Some(sem_image_available), None) {
|
||||
Ok((swp_image_id, suboptimal)) => match suboptimal {
|
||||
Some(_) => {
|
||||
return self.update_swapchain()
|
||||
.map_err(|_| "Could not recreate swpachain");
|
||||
},
|
||||
None => swp_image_id,
|
||||
}
|
||||
Err(_) => {
|
||||
return self.update_swapchain()
|
||||
.map_err(|_| "Could not recreate swpachain");
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// debug!("current image : {}", self.current_image);
|
||||
// debug!("swapchain index : {}", swp_image_id);
|
||||
|
||||
unsafe {
|
||||
|
||||
let command_buffer = &mut self.command_buffers[self.current_image];
|
||||
command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
|
||||
|
||||
let clear_value = ClearValue {color: ClearColor{float32: color}};
|
||||
|
||||
command_buffer.begin_render_pass(
|
||||
&self.render_pass,
|
||||
&self.framebuffers[swp_image_id as usize],
|
||||
self.render_area,
|
||||
iter::once(clear_value),
|
||||
SubpassContents::Inline,
|
||||
);
|
||||
command_buffer.end_render_pass();
|
||||
command_buffer.finish();
|
||||
}
|
||||
|
||||
let command_buffer = &self.command_buffers[self.current_image];
|
||||
|
||||
// prepare the submission
|
||||
let submission = Submission {
|
||||
command_buffers: iter::once(command_buffer),
|
||||
wait_semaphores: iter::once((sem_image_available,
|
||||
PipelineStage::COLOR_ATTACHMENT_OUTPUT)),
|
||||
signal_semaphores: iter::once(sem_render_finished),
|
||||
};
|
||||
|
||||
let mut queue = &mut self.queue_group.queues[0];
|
||||
|
||||
unsafe {
|
||||
|
||||
queue.submit(submission, Some(fence));
|
||||
|
||||
let result = self.swapchain.present(&mut queue, swp_image_id, Some(sem_render_finished))
|
||||
.map_err(|_| "Failed to present into the swapchain")?;
|
||||
|
||||
if result.is_some() {
|
||||
self.update_swapchain()
|
||||
.map_err(|_| "Could not recreate swapchain")?;
|
||||
}
|
||||
}
|
||||
|
||||
self.current_image = (self.current_image + 1) % self.image_count;
|
||||
|
||||
// if self.current_image == 0 {
|
||||
// panic!("Abort");
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
187
src/renderer/swap_system.rs
Normal file
187
src/renderer/swap_system.rs
Normal file
@ -0,0 +1,187 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
ptr::read,
|
||||
};
|
||||
|
||||
use gfx_hal::{
|
||||
window::Extent2D,
|
||||
pso::Rect as GfxRect,
|
||||
format::Format,
|
||||
};
|
||||
|
||||
mod frame;
|
||||
use frame::Frame;
|
||||
|
||||
use super::gpu::Gpu;
|
||||
|
||||
//--SwapSystem implementation-----------------------------------------------------------------------
|
||||
#[derive(Debug)]
|
||||
pub struct SwapSystem<B: gfx_hal::Backend> {
|
||||
surface: ManuallyDrop<B::Surface>,
|
||||
render_area: GfxRect,
|
||||
format: Format,
|
||||
extent: Extent2D,
|
||||
swapchain: ManuallyDrop<B::Swapchain>,
|
||||
spare_semaphore: ManuallyDrop<B::Semaphore>,
|
||||
render_pass: ManuallyDrop<B::RenderPass>,
|
||||
frames: Vec<Frame<B>>,
|
||||
}
|
||||
|
||||
impl<B> SwapSystem<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
pub fn drop(&mut self, gpu: &mut Gpu<B>, instance: &B::Instance) {
|
||||
use gfx_hal::{
|
||||
device::Device,
|
||||
Instance,
|
||||
};
|
||||
|
||||
debug!("Dropping SwapSystem...");
|
||||
for mut frame in self.frames.drain(..) {
|
||||
frame.drop(gpu);
|
||||
}
|
||||
unsafe {
|
||||
gpu.device().destroy_render_pass(
|
||||
ManuallyDrop::into_inner(read(&mut self.render_pass)));
|
||||
gpu.device().destroy_semaphore(
|
||||
ManuallyDrop::into_inner(read(&mut self.spare_semaphore)));
|
||||
gpu.device().destroy_swapchain(
|
||||
ManuallyDrop::into_inner(read(&mut self.swapchain)));
|
||||
//render area can be dropped automatically
|
||||
instance.destroy_surface(
|
||||
ManuallyDrop::into_inner(read(&mut self.surface)));
|
||||
}
|
||||
trace!("SwapSystem dropped !");
|
||||
}
|
||||
|
||||
pub fn new(gpu: &mut Gpu<B>, mut surface: B::Surface)
|
||||
-> Result<SwapSystem<B>, &'static str>
|
||||
{
|
||||
use gfx_hal::{
|
||||
window::SwapchainConfig,
|
||||
pso::Rect,
|
||||
};
|
||||
|
||||
debug!("Creating SwapSystem...");
|
||||
//TODO handle render_area properly
|
||||
warn!("Hard-coding render area size !");
|
||||
let render_area = Rect{x: 0, y: 0, w: 1280, h: 720};
|
||||
|
||||
trace!("Obtaining surface capabilities...");
|
||||
let capabilities = {
|
||||
use gfx_hal::window::Surface;
|
||||
|
||||
surface.capabilities(&gpu.adapter().physical_device)
|
||||
};
|
||||
debug!("Surface capabitlities : {:#?}", capabilities);
|
||||
|
||||
trace!("Selecting image format...");
|
||||
let format = {
|
||||
use gfx_hal::{
|
||||
format::ChannelType,
|
||||
window::Surface,
|
||||
};
|
||||
|
||||
match surface.supported_formats(&gpu.adapter().physical_device) {
|
||||
None => Format::Rgba8Srgb,
|
||||
Some(formats) => formats
|
||||
.iter()
|
||||
.find(|f| f.base_format().1 == ChannelType::Srgb)
|
||||
.cloned()
|
||||
.ok_or("Could no find suitabe format")?
|
||||
}};
|
||||
|
||||
trace!("Getting surface capabilities extend...");
|
||||
let extent = capabilities.current_extent
|
||||
.unwrap_or(*capabilities.extents.end())
|
||||
.clone();
|
||||
|
||||
trace!("Generating Swapchain configuration...");
|
||||
//TODO improve swapchain configuration
|
||||
let swapchain_config = SwapchainConfig::from_caps(&capabilities, format, extent);
|
||||
let swapchain_config = swapchain_config.with_image_count(3);
|
||||
debug!("Swapchain configuration : {:?}", swapchain_config);
|
||||
|
||||
trace!("Creating Swapchain...");
|
||||
let (swapchain, backbuffer) = unsafe {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
gpu.device()
|
||||
.create_swapchain(&mut surface, swapchain_config, None)
|
||||
.map_err(|_| "Failed to create swapchain and backbuffer")?
|
||||
};
|
||||
|
||||
trace!("Creating spare Semaphore...");
|
||||
let spare_semaphore = {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
gpu.device()
|
||||
.create_semaphore()
|
||||
.map_err(|_| "Could not create sempahore")?
|
||||
};
|
||||
|
||||
trace!("Creating RenderPass...");
|
||||
let render_pass = {
|
||||
use gfx_hal::{
|
||||
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
|
||||
image::Layout,
|
||||
device::Device,
|
||||
};
|
||||
|
||||
let color_attachment = Attachment {
|
||||
format : Some(format),
|
||||
samples : 1,
|
||||
ops : AttachmentOps {
|
||||
load : AttachmentLoadOp::Clear,
|
||||
store : AttachmentStoreOp::Store,
|
||||
},
|
||||
stencil_ops : AttachmentOps::DONT_CARE,
|
||||
layouts : (Layout::Undefined..Layout::Present),
|
||||
};
|
||||
|
||||
let subpass = SubpassDesc {
|
||||
colors : &[(0, Layout::ColorAttachmentOptimal)],
|
||||
depth_stencil : None,
|
||||
inputs : &[],
|
||||
resolves : &[],
|
||||
preserves : &[],
|
||||
};
|
||||
|
||||
unsafe {
|
||||
gpu.device().create_render_pass(&[color_attachment], &[subpass], &[])
|
||||
.map_err(|_| "Could not create render pass")?
|
||||
}
|
||||
};
|
||||
|
||||
//TODO adapt to improved swapchain configuration
|
||||
warn!("Generating hard-coded number of frames !");
|
||||
let frames = {
|
||||
backbuffer
|
||||
.iter()
|
||||
.map(|img|
|
||||
Frame::new(gpu, &img, &format, &render_pass, &extent))
|
||||
.collect::<Result<Vec<_>, &str>>()?
|
||||
};
|
||||
|
||||
trace!("Created SwapSystem !");
|
||||
Ok( SwapSystem {
|
||||
surface: ManuallyDrop::new(surface),
|
||||
render_area,
|
||||
format,
|
||||
extent,
|
||||
swapchain: ManuallyDrop::new(swapchain),
|
||||
spare_semaphore: ManuallyDrop::new(spare_semaphore),
|
||||
render_pass: ManuallyDrop::new(render_pass),
|
||||
frames,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn acquire_frame(&mut self) -> Frame<B> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
207
src/renderer/swap_system/frame.rs
Normal file
207
src/renderer/swap_system/frame.rs
Normal file
@ -0,0 +1,207 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
ptr::read,
|
||||
iter,
|
||||
borrow::Borrow,
|
||||
};
|
||||
|
||||
use gfx_hal::{
|
||||
window::Extent2D,
|
||||
format::Format,
|
||||
queue::Submission,
|
||||
pso::Rect as GfxRect,
|
||||
};
|
||||
|
||||
use super::super::gpu::Gpu;
|
||||
|
||||
//--Frame implementation----------------------------------------------------------------------------
|
||||
#[derive(Debug)]
|
||||
pub struct Frame<B: gfx_hal::Backend> {
|
||||
wait_semaphores: Vec<B::Semaphore>,
|
||||
signal_semaphores: Vec<B::Semaphore>,
|
||||
fences: Vec<B::Fence>,
|
||||
image_view: ManuallyDrop<B::ImageView>,
|
||||
framebuffer: ManuallyDrop<B::Framebuffer>,
|
||||
command_buffer: ManuallyDrop<B::CommandBuffer>,
|
||||
}
|
||||
|
||||
impl<B> Frame<B>
|
||||
where
|
||||
B: gfx_hal::Backend,
|
||||
{
|
||||
pub fn drop(&mut self, gpu: &mut Gpu<B>) {
|
||||
use gfx_hal::{
|
||||
device::Device,
|
||||
pool::CommandPool,
|
||||
};
|
||||
|
||||
trace!("Dropping Frame...");
|
||||
unsafe {
|
||||
//TODO check that
|
||||
gpu.command_pool_mut().free(
|
||||
iter::once(ManuallyDrop::into_inner(read(&mut self.command_buffer))));
|
||||
gpu.device().destroy_framebuffer(
|
||||
ManuallyDrop::into_inner(read(&mut self.framebuffer)));
|
||||
gpu.device().destroy_image_view(
|
||||
ManuallyDrop::into_inner(read(&mut self.image_view)));
|
||||
for fence in self.fences.drain(..) {
|
||||
gpu.device().destroy_fence(fence);
|
||||
}
|
||||
for semaphore in self.signal_semaphores.drain(..) {
|
||||
gpu.device().destroy_semaphore(semaphore);
|
||||
}
|
||||
for semaphore in self.wait_semaphores.drain(..) {
|
||||
gpu.device().destroy_semaphore(semaphore);
|
||||
}
|
||||
trace!("Frame Dropped !");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(gpu: &mut Gpu<B>,
|
||||
image: &B::Image,
|
||||
format: &Format,
|
||||
render_pass: &B::RenderPass,
|
||||
extent: &Extent2D)
|
||||
-> Result<Frame<B>, &'static str>
|
||||
{
|
||||
|
||||
debug!("Creating Frame...");
|
||||
trace!("Creating Semaphore and Fences...");
|
||||
let (wait_semaphores, signal_semaphores, fences) = {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
let wait_semaphores = vec!(
|
||||
gpu.device()
|
||||
.create_semaphore()
|
||||
.map_err(|_| "Could not create Semaphore")?);
|
||||
let signal_semaphores = vec!(
|
||||
gpu.device()
|
||||
.create_semaphore()
|
||||
.map_err(|_| "Could not create Semaphore")?);
|
||||
let fences = vec!(
|
||||
gpu.device()
|
||||
.create_fence(true)
|
||||
.map_err(|_| "Could not create Semaphore")?);
|
||||
|
||||
(wait_semaphores, signal_semaphores, fences)
|
||||
};
|
||||
|
||||
trace!("Creating ImageView...");
|
||||
let image_view = unsafe {
|
||||
use gfx_hal::{
|
||||
image::{ViewKind, SubresourceRange},
|
||||
format::{Swizzle, Aspects},
|
||||
device::Device,
|
||||
};
|
||||
|
||||
gpu.device()
|
||||
.create_image_view(
|
||||
image,
|
||||
ViewKind::D2,
|
||||
format.clone(),
|
||||
Swizzle::NO,
|
||||
SubresourceRange {
|
||||
aspects : Aspects::COLOR,
|
||||
levels : 0..1,
|
||||
layers : 0..1,
|
||||
},
|
||||
)
|
||||
.map_err(|_| "Could not create ImageViews")?
|
||||
};
|
||||
|
||||
trace!("Creating Framebuffer...");
|
||||
let framebuffer = unsafe {
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
gpu.device()
|
||||
.create_framebuffer(render_pass,
|
||||
vec![&image_view],
|
||||
extent.clone().to_extent())
|
||||
.map_err(|_| "Could not create FrameBuffer")?
|
||||
};
|
||||
|
||||
trace!("Allocating CommandBuffer...");
|
||||
let command_buffer = unsafe {
|
||||
use gfx_hal::{
|
||||
command::Level,
|
||||
pool::CommandPool,
|
||||
};
|
||||
|
||||
gpu.command_pool_mut().allocate_one(Level::Primary)
|
||||
};
|
||||
|
||||
trace!("Created Frame !");
|
||||
Ok( Frame {
|
||||
wait_semaphores,
|
||||
signal_semaphores,
|
||||
fences,
|
||||
image_view: ManuallyDrop::new(image_view),
|
||||
framebuffer: ManuallyDrop::new(framebuffer),
|
||||
command_buffer: ManuallyDrop::new(command_buffer),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sync_gpu(&self, gpu: &Gpu<B>) -> Result<(), &'static str>{
|
||||
use gfx_hal::device::Device;
|
||||
|
||||
unsafe {
|
||||
gpu.device()
|
||||
.wait_for_fence(&self.fences[0], !0)
|
||||
.map_err(|_| "Failed to wait for Fence");
|
||||
gpu.device()
|
||||
.reset_fence(&self.fences[0])
|
||||
.map_err(|_| "Failed to reset fence");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn construct_pipeline<'a, T, Ic, S, Iw, Is>(&self,
|
||||
// render_pass: &B::RenderPass,
|
||||
// render_area: GfxRect,
|
||||
// color: [f32; 4])
|
||||
// -> Result<Submission<Ic, Iw, Is>, &'static str>
|
||||
// where
|
||||
// T: 'a + Borrow<B::CommandBuffer>,
|
||||
// Ic: IntoIterator<Item = &'a T>,
|
||||
// S: 'a + Borrow<B::Semaphore>,
|
||||
// Iw: IntoIterator<Item = (&'a S, gfx_hal::pso::PipelineStage)>,
|
||||
// Is: IntoIterator<Item = &'a S>,
|
||||
// {
|
||||
// use gfx_hal::pso::PipelineStage;
|
||||
//
|
||||
// unsafe {
|
||||
// use gfx_hal::command::{
|
||||
// CommandBufferFlags,
|
||||
// SubpassContents,
|
||||
// ClearValue,
|
||||
// ClearColor,
|
||||
// CommandBuffer,
|
||||
// };
|
||||
//
|
||||
// self.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
|
||||
//
|
||||
// let clear_value = ClearValue {color: ClearColor{float32: color}};
|
||||
//
|
||||
// self.command_buffer.begin_render_pass(
|
||||
// render_pass,
|
||||
// &self.framebuffer,
|
||||
// render_area,
|
||||
// iter::once(clear_value),
|
||||
// SubpassContents::Inline,
|
||||
// );
|
||||
// self.command_buffer.end_render_pass();
|
||||
// self.command_buffer.finish();
|
||||
// }
|
||||
//
|
||||
// Ok( Submission {
|
||||
// command_buffers: iter::once(&self.command_buffer),
|
||||
// wait_semaphores: iter::once((&self.wait_semaphores[0],
|
||||
// PipelineStage::COLOR_ATTACHMENT_OUTPUT)),
|
||||
// signal_semaphores: iter::once(&self.signal_semaphores[0]),
|
||||
// })
|
||||
// }
|
||||
}
|
||||
11
src/utils.rs
Normal file
11
src/utils.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use num_traits::Num;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Rect<I: Num> {
|
||||
pub w: I,
|
||||
pub h: I,
|
||||
}
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event_loop::{EventLoop},
|
||||
window::{WindowBuilder, Window},
|
||||
error::OsError,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WinitState {
|
||||
pub event_loop: EventLoop<()>,
|
||||
pub window: Window,
|
||||
}
|
||||
|
||||
impl WinitState {
|
||||
|
||||
pub fn new (title: &str, size: PhysicalSize<u32>) -> Result<WinitState, OsError> {
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let window = WindowBuilder::new()
|
||||
.with_inner_size(size)
|
||||
.with_title(title)
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
Ok(Self {
|
||||
event_loop,
|
||||
window,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WinitState {
|
||||
|
||||
fn default() -> WinitState {
|
||||
|
||||
WinitState::new(
|
||||
"IV",
|
||||
PhysicalSize {
|
||||
width : 1280,
|
||||
height : 720
|
||||
}
|
||||
).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
54
src/winit_window.rs
Normal file
54
src/winit_window.rs
Normal file
@ -0,0 +1,54 @@
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event_loop::{EventLoop},
|
||||
window::{WindowBuilder, Window},
|
||||
};
|
||||
|
||||
//TODO fix that
|
||||
use super::renderer::output::Output;
|
||||
use crate::utils::Rect;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WinitWindow {
|
||||
pub name: String,
|
||||
size: Rect<i32>,
|
||||
id: usize,
|
||||
|
||||
pub event_loop: EventLoop<()>,
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl WinitWindow {
|
||||
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
|
||||
|
||||
let name = title.to_string();
|
||||
let id = 0;
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new()
|
||||
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
|
||||
.with_title(title)
|
||||
.build(&event_loop)
|
||||
.map_err(|_| "Could not create window")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
size,
|
||||
id,
|
||||
event_loop,
|
||||
window,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Output<Window> for WinitWindow {
|
||||
fn get_id(&self) -> usize { self.id }
|
||||
fn set_id(&mut self, id: usize) { self.id = id; }
|
||||
|
||||
fn size(&mut self) -> &mut Rect<i32> { &mut self.size }
|
||||
|
||||
fn window(&self) -> &Window { &self.window }
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user