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",
|
"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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -126,6 +137,17 @@ dependencies = [
|
|||||||
"objc",
|
"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]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -205,6 +227,7 @@ version = "0.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
|
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"colored",
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -269,6 +292,15 @@ dependencies = [
|
|||||||
"raw-window-handle",
|
"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]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -293,6 +325,8 @@ dependencies = [
|
|||||||
"gfx-backend-vulkan",
|
"gfx-backend-vulkan",
|
||||||
"gfx-hal",
|
"gfx-hal",
|
||||||
"log",
|
"log",
|
||||||
|
"num-traits",
|
||||||
|
"raw-window-handle",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -502,9 +536,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.11"
|
version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -9,9 +9,11 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
chrono = "0.4.11"
|
chrono = "0.4.11"
|
||||||
fern = "0.6.0"
|
fern = { version = "0.6.0", features = ["colored"] }
|
||||||
gfx-hal = "0.5.0"
|
gfx-hal = "0.5.0"
|
||||||
winit = "0.22.0"
|
winit = "0.22.0"
|
||||||
|
raw-window-handle = "0.3.3"
|
||||||
|
num-traits = "0.2.12"
|
||||||
|
|
||||||
[dependencies.gfx-backend-vulkan]
|
[dependencies.gfx-backend-vulkan]
|
||||||
version = "0.5"
|
version = "0.5"
|
||||||
@ -23,5 +25,5 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "iv"
|
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)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
|
||||||
use chrono;
|
use chrono;
|
||||||
|
|
||||||
use ::iv::run;
|
use ::iv::run;
|
||||||
|
|
||||||
fn setup_logger() -> Result<(), fern::InitError> {
|
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()
|
fern::Dispatch::new()
|
||||||
.format(|out, message, record| {
|
.format(move |out, message, record| {
|
||||||
out.finish(format_args!(
|
out.finish(format_args!(
|
||||||
"{}[{}][{}] {}",
|
"{}[{}][{}] {}",
|
||||||
chrono::Local::now().format("[%H:%M:%S]"),
|
chrono::Local::now().format("[%H:%M:%S]"),
|
||||||
record.level(),
|
colors.color(record.level()),
|
||||||
record.target(),
|
record.target(),
|
||||||
message
|
message
|
||||||
))
|
))
|
||||||
233
src/lib.rs
233
src/lib.rs
@ -5,20 +5,25 @@
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
use std::{
|
//use std::{
|
||||||
sync::mpsc,
|
// sync::mpsc,
|
||||||
thread,
|
// thread,
|
||||||
collections::HashMap,
|
// collections::HashMap,
|
||||||
cell::RefCell,
|
// cell::RefCell,
|
||||||
};
|
//};
|
||||||
|
|
||||||
mod winit_state;
|
use gfx_backend_vulkan as vk_back;
|
||||||
use winit_state::WinitState;
|
|
||||||
|
|
||||||
use winit::{
|
pub mod utils;
|
||||||
event::{Event, WindowEvent},
|
use crate::utils::Rect;
|
||||||
event_loop::ControlFlow,
|
|
||||||
};
|
mod winit_window;
|
||||||
|
use winit_window::WinitWindow;
|
||||||
|
|
||||||
|
//use winit::{
|
||||||
|
// event::{Event, WindowEvent},
|
||||||
|
// event_loop::ControlFlow,
|
||||||
|
//};
|
||||||
|
|
||||||
mod renderer;
|
mod renderer;
|
||||||
use renderer::Renderer;
|
use renderer::Renderer;
|
||||||
@ -51,101 +56,117 @@ pub enum Input {
|
|||||||
|
|
||||||
/// The main function of the library
|
/// The main function of the library
|
||||||
pub fn run() -> Result<(), &'static str> {
|
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 local_state = LocalState::default();
|
||||||
|
|
||||||
let (input_tx, input_rx) = mpsc::channel();
|
let color = [0.5, 0.0, 0.0, 0.1];
|
||||||
let mut window_senders = HashMap::with_capacity(1);
|
|
||||||
window_senders.insert(1, input_tx);
|
loop {
|
||||||
|
for mut window in &mut windows {
|
||||||
let control_thread = RefCell::new(Some(thread::spawn(move || {
|
let _ = renderer.draw_clear_frame(&mut window, color);
|
||||||
#[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
|
|
||||||
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];
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 {
|
// let (input_tx, input_rx) = mpsc::channel();
|
||||||
#[test]
|
// let mut window_senders = HashMap::with_capacity(1);
|
||||||
fn it_works() {
|
// window_senders.insert(1, input_tx);
|
||||||
assert_eq!(2 + 2, 4);
|
//
|
||||||
}
|
// 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::{
|
use std::{
|
||||||
queue::QueueGroup,
|
mem::ManuallyDrop,
|
||||||
Backend,
|
|
||||||
pso::Rect,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use gfx_backend_vulkan as vk_back;
|
mod gpu;
|
||||||
|
use gpu::Gpu;
|
||||||
|
|
||||||
pub mod init;
|
mod swap_system;
|
||||||
pub mod render;
|
use swap_system::SwapSystem;
|
||||||
|
|
||||||
|
pub mod output;
|
||||||
|
use output::Output;
|
||||||
|
|
||||||
|
//mod pipeline;
|
||||||
|
//use pipeline::Pipeline;
|
||||||
|
|
||||||
|
//--Renderer implementation-------------------------------------------------------------------------
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Renderer {
|
pub struct Renderer<B: gfx_hal::Backend> {
|
||||||
//items need to communicate with the GPU
|
instance: ManuallyDrop<B::Instance>,
|
||||||
instance: ManuallyDrop<<vk_back::Backend as Backend>::Instance>,
|
gpu: ManuallyDrop<Gpu<B>>,
|
||||||
surface: ManuallyDrop<<vk_back::Backend as Backend>::Surface>,
|
//pipelines: Vec<Pipeline<B>>,
|
||||||
adapter: ManuallyDrop<gfx_hal::adapter::Adapter<vk_back::Backend>>,
|
swap_systems: Vec<SwapSystem<B>>,
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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