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:
Steins7 2020-09-01 14:19:44 +02:00
parent 7dc22f026e
commit 8992c06d16
16 changed files with 989 additions and 723 deletions

38
Cargo.lock generated
View File

@ -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",
]

View File

@ -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
View 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>

View File

@ -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
))

View File

@ -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);
// }
//}

View File

@ -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
View 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
}
}

View File

@ -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
View 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
View 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,
{
}

View File

@ -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
View 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!();
}
}

View 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
View 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,
}

View File

@ -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
View 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 }
}