From 8992c06d16e1a78a16a612d69a97b9343cfa40c2 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 1 Sep 2020 14:19:44 +0200 Subject: [PATCH 01/22] Started major rework of the code + added defined code structure + started implementing generic outputs + added support for multiples windows + switched to frame-based architecture --- Cargo.lock | 38 ++- Cargo.toml | 6 +- doc/architecture | 1 + src/bin/main.rs => main.rs | 13 +- src/lib.rs | 233 +++++++++-------- src/renderer.rs | 129 +++++++--- src/renderer/gpu.rs | 193 ++++++++++++++ src/renderer/init.rs | 415 ------------------------------ src/renderer/output.rs | 43 ++++ src/renderer/pipeline.rs | 20 ++ src/renderer/render.rs | 113 -------- src/renderer/swap_system.rs | 187 ++++++++++++++ src/renderer/swap_system/frame.rs | 207 +++++++++++++++ src/utils.rs | 11 + src/winit_state.rs | 49 ---- src/winit_window.rs | 54 ++++ 16 files changed, 989 insertions(+), 723 deletions(-) create mode 100644 doc/architecture rename src/bin/main.rs => main.rs (72%) create mode 100644 src/renderer/gpu.rs delete mode 100644 src/renderer/init.rs create mode 100644 src/renderer/output.rs create mode 100644 src/renderer/pipeline.rs delete mode 100644 src/renderer/render.rs create mode 100644 src/renderer/swap_system.rs create mode 100644 src/renderer/swap_system/frame.rs create mode 100644 src/utils.rs delete mode 100644 src/winit_state.rs create mode 100644 src/winit_window.rs diff --git a/Cargo.lock b/Cargo.lock index 87b4b99..3b72c66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/Cargo.toml b/Cargo.toml index 31ed5e5..e490da6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/doc/architecture b/doc/architecture new file mode 100644 index 0000000..e5a3284 --- /dev/null +++ b/doc/architecture @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/src/bin/main.rs b/main.rs similarity index 72% rename from src/bin/main.rs rename to main.rs index ebf4501..bda4db0 100644 --- a/src/bin/main.rs +++ b/main.rs @@ -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 )) diff --git a/src/lib.rs b/src/lib.rs index 4086d54..81951ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,20 +5,25 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; -use std::{ - sync::mpsc, - thread, - collections::HashMap, - cell::RefCell, -}; +//use std::{ +// sync::mpsc, +// thread, +// collections::HashMap, +// cell::RefCell, +//}; -mod winit_state; -use winit_state::WinitState; +use gfx_backend_vulkan as vk_back; -use winit::{ - event::{Event, WindowEvent}, - event_loop::ControlFlow, -}; +pub mod utils; +use crate::utils::Rect; + +mod winit_window; +use winit_window::WinitWindow; + +//use winit::{ +// event::{Event, WindowEvent}, +// event_loop::ControlFlow, +//}; mod renderer; use renderer::Renderer; @@ -51,101 +56,117 @@ pub enum Input { /// The main function of the library pub fn run() -> Result<(), &'static str> { - let winit_state = WinitState::default(); - let mut renderer = Renderer::new(&winit_state.window)?; + + let mut windows = vec![ + WinitWindow::new("IV", Rect {w: 1280, h: 720})?, + WinitWindow::new("IV 2", Rect {w: 720, h: 480})?, + ]; + + let mut renderer: Renderer = 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]; - - 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(); - }, - } + + let color = [0.5, 0.0, 0.0, 0.1]; + + loop { + for mut window in &mut windows { + let _ = renderer.draw_clear_frame(&mut window, color); } - }))); - - 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); +// } +//} diff --git a/src/renderer.rs b/src/renderer.rs index a734acb..73e3b68 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,42 +1,103 @@ -use std::mem::ManuallyDrop; +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; -use gfx_hal::{ - queue::QueueGroup, - Backend, - pso::Rect, +use std::{ + mem::ManuallyDrop, }; -use gfx_backend_vulkan as vk_back; +mod gpu; +use gpu::Gpu; -pub mod init; -pub mod render; +mod swap_system; +use swap_system::SwapSystem; +pub mod output; +use output::Output; + +//mod pipeline; +//use pipeline::Pipeline; + +//--Renderer implementation------------------------------------------------------------------------- #[derive(Debug)] -pub struct Renderer { - //items need to communicate with the GPU - instance: ManuallyDrop<::Instance>, - surface: ManuallyDrop<::Surface>, - adapter: ManuallyDrop>, - device: vk_back::Device, - queue_group: ManuallyDrop>, - render_pass: ManuallyDrop<::RenderPass>, - swapchain: ManuallyDrop<::Swapchain>, - extent: gfx_hal::window::Extent2D, - format: gfx_hal::format::Format, - render_area: Rect, - - //items needed to render the images - sems_image_available: Vec<::Semaphore>, - sems_render_finished: Vec<::Semaphore>, - fences: Vec<::Fence>, - image_views: Vec<::ImageView>, - framebuffers: Vec<::Framebuffer>, - - command_pool: ManuallyDrop<::CommandPool>, - command_buffers: Vec<::CommandBuffer>, - - //items needed to keep track of the images - image_count: usize, - current_image: usize, +pub struct Renderer { + instance: ManuallyDrop, + gpu: ManuallyDrop>, + //pipelines: Vec>, + swap_systems: Vec>, } +impl Drop for Renderer +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 Renderer +where + B: gfx_hal::Backend, +{ + pub fn new<'a, H, T: 'a, I>(outputs: I) -> Result, &'static str> + where + H: raw_window_handle::HasRawWindowHandle, + T: Output, + I: IntoIterator, + + { + 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::, &str>>()? + }; + + debug!("Renderer created !"); + Ok( Renderer { + instance: ManuallyDrop::new(instance), + gpu: ManuallyDrop::new(gpu), + swap_systems, + }) + } + + pub fn draw_clear_frame(&mut self, output: &mut O, _color: [f32; 4]) + -> Result<(), &'static str> + where + T: raw_window_handle::HasRawWindowHandle, + O: Output + { + let swap_index = output.get_id(); + let frame = self.swap_systems[swap_index].acquire_frame(); + + frame.sync_gpu(&self.gpu); + + Ok(()) + } +} + diff --git a/src/renderer/gpu.rs b/src/renderer/gpu.rs new file mode 100644 index 0000000..eefb2ed --- /dev/null +++ b/src/renderer/gpu.rs @@ -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 { + adapter: ManuallyDrop>, + device: ManuallyDrop, + queue_group: ManuallyDrop>, + command_pool: ManuallyDrop, +} + +impl Drop for Gpu +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 Gpu +where + B: gfx_hal::Backend, +{ + pub fn new<'a, H, T: 'a, I>(instance: &B::Instance, outputs: I) + -> Result<(Gpu, Vec), &'static str> + where + H: raw_window_handle::HasRawWindowHandle, + T: Output, + I: IntoIterator, + { + 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::, &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 { + &self.adapter + } + + pub fn device(&self) -> &B::Device { + &self.device + } + + pub fn command_pool_mut(&mut self) -> &mut B::CommandPool { + &mut self.command_pool + } +} + diff --git a/src/renderer/init.rs b/src/renderer/init.rs deleted file mode 100644 index 9e5e85c..0000000 --- a/src/renderer/init.rs +++ /dev/null @@ -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 { - 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<::Semaphore> = vec![]; - let mut sems_render_finished : Vec<::Semaphore> = vec![]; - let mut fences :Vec<::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::, &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::, &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, - } - ) - } -} - diff --git a/src/renderer/output.rs b/src/renderer/output.rs new file mode 100644 index 0000000..49de5f2 --- /dev/null +++ b/src/renderer/output.rs @@ -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 +where + T: HasRawWindowHandle, +{ + fn get_id(&self) -> usize; + fn set_id(&mut self, id: usize); + + fn size(&mut self) -> &mut Rect; + + fn window(&self) -> &T; +} + +//impl<'a, T, O> Output for &'a O +//where +// T: HasRawWindowHandle, +// O: Output { +// fn id(&mut self) -> &mut i32 { Output::id(*self) } +// +// fn size(&mut self) -> &mut Rect { Output::size(*self) } +// +// fn window(&self) -> &T { Output::window(*self) } +//} + +impl<'a, T, O> Output for &'a mut O +where + T: HasRawWindowHandle, + O: Output { + 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 { Output::size(*self) } + + fn window(&self) -> &T { Output::window(*self) } +} + diff --git a/src/renderer/pipeline.rs b/src/renderer/pipeline.rs new file mode 100644 index 0000000..45217a1 --- /dev/null +++ b/src/renderer/pipeline.rs @@ -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 { + render_pass: ManuallyDrop, +} + +impl Pipeline +where + B: gfx_hal::Backend, +{ + +} + diff --git a/src/renderer/render.rs b/src/renderer/render.rs deleted file mode 100644 index 86b244c..0000000 --- a/src/renderer/render.rs +++ /dev/null @@ -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(()) - } -} - diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs new file mode 100644 index 0000000..1fb820f --- /dev/null +++ b/src/renderer/swap_system.rs @@ -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 { + surface: ManuallyDrop, + render_area: GfxRect, + format: Format, + extent: Extent2D, + swapchain: ManuallyDrop, + spare_semaphore: ManuallyDrop, + render_pass: ManuallyDrop, + frames: Vec>, +} + +impl SwapSystem +where + B: gfx_hal::Backend, +{ + pub fn drop(&mut self, gpu: &mut Gpu, 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, mut surface: B::Surface) + -> Result, &'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::, &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 { + unimplemented!(); + } +} + diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs new file mode 100644 index 0000000..a2d99d4 --- /dev/null +++ b/src/renderer/swap_system/frame.rs @@ -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 { + wait_semaphores: Vec, + signal_semaphores: Vec, + fences: Vec, + image_view: ManuallyDrop, + framebuffer: ManuallyDrop, + command_buffer: ManuallyDrop, +} + +impl Frame +where + B: gfx_hal::Backend, +{ + pub fn drop(&mut self, gpu: &mut Gpu) { + 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, + image: &B::Image, + format: &Format, + render_pass: &B::RenderPass, + extent: &Extent2D) + -> Result, &'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) -> 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, &'static str> +// where +// T: 'a + Borrow, +// Ic: IntoIterator, +// S: 'a + Borrow, +// Iw: IntoIterator, +// Is: IntoIterator, +// { +// 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]), +// }) +// } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..b51888b --- /dev/null +++ b/src/utils.rs @@ -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 { + pub w: I, + pub h: I, +} + diff --git a/src/winit_state.rs b/src/winit_state.rs deleted file mode 100644 index b8faa77..0000000 --- a/src/winit_state.rs +++ /dev/null @@ -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) -> Result { - - 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() - } -} - diff --git a/src/winit_window.rs b/src/winit_window.rs new file mode 100644 index 0000000..c08320a --- /dev/null +++ b/src/winit_window.rs @@ -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, + id: usize, + + pub event_loop: EventLoop<()>, + window: Window, +} + +impl WinitWindow { + pub fn new(title: &str, size: Rect) -> Result { + + 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 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 { &mut self.size } + + fn window(&self) -> &Window { &self.window } +} + From 6579566ccd1a92a065ea5a62f1a12916e773f4bc Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 6 Sep 2020 00:23:11 +0200 Subject: [PATCH 02/22] Finished reformatting renderer + switched to modular architecture + added generic outputs --- Cargo.lock | 4 +- Cargo.toml | 2 +- doc/architecture | 2 +- src/lib.rs | 13 ++- src/renderer.rs | 34 +++++- src/renderer/gpu.rs | 6 +- src/renderer/swap_system.rs | 165 +++++++++++++++++++++++++----- src/renderer/swap_system/frame.rs | 118 +++++++++++---------- 8 files changed, 253 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b72c66..ee21473 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "gfx-hal" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc96180204064c9493e0fe4a9efeb721e0ac59fe8e1906d0c659142a93114fb1" +checksum = "a18534b23d4c262916231511309bc1f307c74cda8dcb68b93a10ca213a22814b" dependencies = [ "bitflags", "raw-window-handle", diff --git a/Cargo.toml b/Cargo.toml index e490da6..f0bbe15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" log = "0.4.8" chrono = "0.4.11" fern = { version = "0.6.0", features = ["colored"] } -gfx-hal = "0.5.0" +gfx-hal = "0.5.3" winit = "0.22.0" raw-window-handle = "0.3.3" num-traits = "0.2.12" diff --git a/doc/architecture b/doc/architecture index e5a3284..68d9f08 100644 --- a/doc/architecture +++ b/doc/architecture @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 81951ff..0c2d6fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,11 +65,18 @@ pub fn run() -> Result<(), &'static str> { let mut renderer: Renderer = Renderer::new(&mut windows)?; //let local_state = LocalState::default(); - let color = [0.5, 0.0, 0.0, 0.1]; + let color = [0.5, 0.0, 0.0, 1.0]; + for window in &mut windows { + let _ = renderer.draw_clear_frame(window, color); + } + loop { - for mut window in &mut windows { - let _ = renderer.draw_clear_frame(&mut window, color); + for window in &mut windows { + match renderer.draw_frame(window) { + Err(err) => println!("{}", err), + _ => (), + } } } } diff --git a/src/renderer.rs b/src/renderer.rs index 73e3b68..86b2f48 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -86,18 +86,42 @@ where }) } - pub fn draw_clear_frame(&mut self, output: &mut O, _color: [f32; 4]) + pub fn draw_frame(&mut self, output: &mut O) -> Result<(), &'static str> where T: raw_window_handle::HasRawWindowHandle, O: Output { - let swap_index = output.get_id(); - let frame = self.swap_systems[swap_index].acquire_frame(); + use gfx_hal::window::AcquireError; + + let swap_index = output.get_id(); + let (frame, image_id) = match self.swap_systems[swap_index].acquire_frame() { + Ok((frame, image_id)) => (frame, image_id), + Err(err) => match err { + AcquireError::NotReady => { + return Err("Frame acquisition failed because all Frames are in use"); + }, + _ => Err("Could not acquire Frame from SwapSystem")?, + }}; + + let _ = frame.sync_gpu(&self.gpu)?; + + let queue = &mut self.gpu.queue_mut(); + frame.submit(queue); + + let _ = self.swap_systems[swap_index].present_frame(frame, image_id, queue)?; - frame.sync_gpu(&self.gpu); - Ok(()) } + + pub fn draw_clear_frame(&mut self, output: &mut O, color: [f32; 4]) + -> Result<(), &'static str> + where + T: raw_window_handle::HasRawWindowHandle, + O: Output + { + self.swap_systems[output.get_id()].configure_render_pass(color)?; + self.draw_frame(output) + } } diff --git a/src/renderer/gpu.rs b/src/renderer/gpu.rs index eefb2ed..ef4ee26 100644 --- a/src/renderer/gpu.rs +++ b/src/renderer/gpu.rs @@ -162,7 +162,7 @@ where trace!("Creating CommandPool..."); device .create_command_pool(queue_group.family, - CommandPoolCreateFlags::RESET_INDIVIDUAL) + CommandPoolCreateFlags::empty()) .map_err(|_| "Could not create CommandPool")? }; @@ -189,5 +189,9 @@ where pub fn command_pool_mut(&mut self) -> &mut B::CommandPool { &mut self.command_pool } + + pub fn queue_mut(&mut self) -> &mut B::CommandQueue { + &mut self.queue_group.queues[0] + } } diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index 1fb820f..81056c9 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -4,10 +4,11 @@ use log::{debug, error, info, trace, warn}; use std::{ mem::ManuallyDrop, ptr::read, + collections::HashMap, }; use gfx_hal::{ - window::Extent2D, + window::{Extent2D, AcquireError}, pso::Rect as GfxRect, format::Format, }; @@ -21,13 +22,14 @@ use super::gpu::Gpu; #[derive(Debug)] pub struct SwapSystem { surface: ManuallyDrop, - render_area: GfxRect, format: Format, extent: Extent2D, + render_area: GfxRect, //TODO may not be needed (duplicate of extent) swapchain: ManuallyDrop, spare_semaphore: ManuallyDrop, render_pass: ManuallyDrop, - frames: Vec>, + frames: HashMap>, + frame_nb: usize, } impl SwapSystem @@ -41,7 +43,7 @@ where }; debug!("Dropping SwapSystem..."); - for mut frame in self.frames.drain(..) { + for (_, mut frame) in self.frames.drain() { frame.drop(gpu); } unsafe { @@ -51,7 +53,7 @@ where 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 + //render_area extent and format can be dropped automatically instance.destroy_surface( ManuallyDrop::into_inner(read(&mut self.surface))); } @@ -63,14 +65,9 @@ where { 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; @@ -92,19 +89,81 @@ where .iter() .find(|f| f.base_format().1 == ChannelType::Srgb) .cloned() - .ok_or("Could no find suitabe format")? + .ok_or("Could no find suitable format")? }}; - trace!("Getting surface capabilities extend..."); + trace!("Getting surface's render area size..."); let extent = capabilities.current_extent .unwrap_or(*capabilities.extents.end()) .clone(); + let render_area = GfxRect{x: 0, y: 0, w: extent.width as i16, h: extent.height as i16}; 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); + let (swapchain_config, frame_nb) = { + + 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 values specified!")? + }; + + let composite_alpha_mode = { + use gfx_hal::window::CompositeAlphaMode; + + [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT, + CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED] + .iter() + .cloned() + .find(|ca| capabilities.composite_alpha_modes.contains(*ca)) + .ok_or("No CompositeAlpha values specified!")? + }; + + let image_count = { + use std::cmp::{min, max}; + use gfx_hal::window::PresentMode; + + let count = match present_mode { + PresentMode::MAILBOX => 3, + _ => 2, //TODO to be checked + }; + max(capabilities.image_count.start().clone(), + min(capabilities.image_count.end().clone(), count)) + }; + + warn!("Hard-coding number of layers per image !"); + let image_layers = 1; + + let image_usage = { + use gfx_hal::image::Usage; + + if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) { + Usage::COLOR_ATTACHMENT + } else { + Err("The Surface isn't capable of supporting color!")? + }}; + + ( + SwapchainConfig { + present_mode, + composite_alpha_mode, + format: format.clone(), + extent: extent.clone(), + image_count: image_count.clone(), + image_layers, + image_usage, + }, + image_count as usize + ) + }; + // //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 { @@ -115,6 +174,8 @@ where .map_err(|_| "Failed to create swapchain and backbuffer")? }; + + trace!("Creating spare Semaphore..."); let spare_semaphore = { use gfx_hal::device::Device; @@ -157,31 +218,83 @@ where } }; - //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::, &str>>()? + let mut frames = HashMap::with_capacity(frame_nb); + for i in 0..frame_nb { + let frame = Frame::new(gpu, &backbuffer[i], &format, &render_pass, &extent) + .map_err(|_| "Could not create frame")?; + frames.insert(i, frame); }; + let frame_nb = frames.len(); + trace!("Created SwapSystem !"); Ok( SwapSystem { surface: ManuallyDrop::new(surface), - render_area, format, extent, + render_area, swapchain: ManuallyDrop::new(swapchain), spare_semaphore: ManuallyDrop::new(spare_semaphore), render_pass: ManuallyDrop::new(render_pass), frames, + frame_nb, }) } - pub fn acquire_frame(&mut self) -> Frame { - unimplemented!(); + pub fn configure_render_pass(&mut self, color: [f32; 4]) -> Result<(), &'static str> { + + if self.frames.len() != self.frame_nb { + return Err("Tried to configure RenderPass with frames acquired"); + } + + debug!("Configuring Color RenderPass..."); + for (_, frame) in &mut self.frames { + frame.record_command_buffer(&self.render_pass, self.render_area.clone(), color); + } + + Ok(()) + } + + pub fn acquire_frame(&mut self) -> Result<(Frame, u32), AcquireError> { + use gfx_hal::window::Swapchain; + + trace!("Acquiring Frame..."); + let image_id = unsafe { + match self.swapchain.acquire_image(core::u64::MAX, Some(&self.spare_semaphore), None) { + Ok((image_id, suboptimal)) => { + match suboptimal { + Some(_) => return Err(AcquireError::OutOfDate), + None => image_id, + }}, + Err(err) => return Err(err), + }}; + + //TODO give back image to swaphain + //debug!("image id : {}", image_id); + let mut frame = match self.frames.remove(&(image_id as usize)) { + Some(frame) => frame, + None => return Err(AcquireError::NotReady), + }; + frame.swap_semaphore(&mut self.spare_semaphore); + + Ok((frame, image_id)) + } + + pub fn present_frame(&mut self, frame: Frame, image_id: u32, queue: &mut B::CommandQueue) + -> Result<(), &'static str> { + use gfx_hal::window::Swapchain; + + trace!("Presenting Frame..."); + let _result = unsafe { + self.swapchain + .present(queue, image_id, Some(frame.get_present_semaphore())) + .map_err(|_| "Failed to present into the swapchain")?; + }; + + self.frames.insert(image_id as usize, frame); + + Ok(()) } } diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index a2d99d4..723c96f 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -5,7 +5,6 @@ use std::{ mem::ManuallyDrop, ptr::read, iter, - borrow::Borrow, }; use gfx_hal::{ @@ -40,7 +39,6 @@ where 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( @@ -109,7 +107,7 @@ where layers : 0..1, }, ) - .map_err(|_| "Could not create ImageViews")? + .map_err(|_| "Could not create ImageView")? }; trace!("Creating Framebuffer..."); @@ -147,61 +145,77 @@ where pub fn sync_gpu(&self, gpu: &Gpu) -> Result<(), &'static str>{ use gfx_hal::device::Device; + trace!("Waiting for Frame..."); unsafe { - gpu.device() + let _ = gpu.device() .wait_for_fence(&self.fences[0], !0) - .map_err(|_| "Failed to wait for Fence"); - gpu.device() + .map_err(|_| "Failed to wait for Fence")?; + let _ = gpu.device() .reset_fence(&self.fences[0]) - .map_err(|_| "Failed to reset fence"); + .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, &'static str> -// where -// T: 'a + Borrow, -// Ic: IntoIterator, -// S: 'a + Borrow, -// Iw: IntoIterator, -// Is: IntoIterator, -// { -// 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]), -// }) -// } + pub fn record_command_buffer(&mut self, + render_pass: &B::RenderPass, + render_area: GfxRect, + color: [f32; 4]) { + + trace!("Recording CommandBuffer..."); + + unsafe { + use gfx_hal::command::{ + CommandBufferFlags, + SubpassContents, + ClearValue, + ClearColor, + CommandBuffer, + }; + + self.command_buffer.begin_primary(CommandBufferFlags::EMPTY); + + 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(); + } + } + + pub fn submit(&self, queue: &mut B::CommandQueue) { + use gfx_hal::pso::PipelineStage; + + trace!("Submiting to queue..."); + let submission = 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]), + }; + + unsafe { + use gfx_hal::queue::CommandQueue; + + queue.submit(submission, Some(&self.fences[0])); + } + } + + pub fn swap_semaphore(&mut self, semaphore: &mut B::Semaphore) { + + std::mem::swap(&mut self.wait_semaphores[0], semaphore); + } + + pub fn get_present_semaphore(&self) -> &B::Semaphore { + + &self.signal_semaphores[0] + } } + From 5f9cc86689d569e32532c729e36616001c06c1ca Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 6 Sep 2020 20:10:58 +0200 Subject: [PATCH 03/22] Upgraded to gfx_hal 0.6.0 + added swapchain recreation mechanism + sorted minor issues ! some framebuffer error present ! may crash during swapchain recreation --- Cargo.lock | 242 ++++++++++++++----------- Cargo.toml | 16 +- doc/architecture | 2 +- src/lib.rs | 14 +- src/renderer.rs | 121 +++++++++---- src/renderer/gpu.rs | 2 +- src/renderer/swap_system.rs | 291 ++++++++++++++++-------------- src/renderer/swap_system/frame.rs | 154 +++------------- 8 files changed, 420 insertions(+), 422 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee21473..bb14223 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,9 +37,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "ash" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69daec0742947f33a85931fa3cb0ce5f07929159dcbd1f0cbb5b2912e2978509" +checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38" dependencies = [ "libloading", ] @@ -52,14 +52,14 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" [[package]] name = "cfg-if" @@ -104,9 +104,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.11" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits", @@ -124,13 +124,13 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f7b6f3f7f4f0b3ec5c5039aaa9e8c3cef97a7a480a400fd62944841314f293d" +checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8" dependencies = [ "bitflags", "block", - "core-foundation", + "core-foundation 0.7.0", "core-graphics", "foreign-types", "libc", @@ -145,7 +145,7 @@ checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ "atty", "lazy_static", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -154,7 +154,17 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5ed8e7e76c45974e15e41bfa8d5b0483cd90191639e01d8f5f1e606299d3fb" +dependencies = [ + "core-foundation-sys 0.8.0", "libc", ] @@ -165,13 +175,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] -name = "core-graphics" -version = "0.19.0" +name = "core-foundation-sys" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" +checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92f5d519093a4178296707dbaa3880eae85a5ef5386675f361a1cf25376e93c" +dependencies = [ + "bitflags", + "core-foundation 0.9.0", "foreign-types", "libc", ] @@ -183,7 +211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" dependencies = [ "cfg-if", - "core-foundation-sys", + "core-foundation-sys 0.7.0", "core-graphics", "libc", "objc", @@ -195,7 +223,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ - "proc-macro2 1.0.18", + "proc-macro2 1.0.20", "quote 1.0.7", "syn", ] @@ -208,18 +236,18 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dlib" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" +checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" dependencies = [ "libloading", ] [[package]] name = "downcast-rs" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "fern" @@ -264,29 +292,30 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "gfx-backend-vulkan" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd1dee09bd8d8f1ba52c5ba22d1f70c7ffa990c5eb245eb3ef2d0206f631673" +checksum = "a84bda4200a82e1912d575801e2bb76ae19c6256359afbc0adfbbaec02fcadc6" dependencies = [ "arrayvec", "ash", "byteorder", - "core-graphics", + "core-graphics-types", "gfx-hal", + "inplace_it", "lazy_static", "log", "objc", "raw-window-handle", "smallvec", - "winapi 0.3.8", + "winapi 0.3.9", "x11", ] [[package]] name = "gfx-hal" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18534b23d4c262916231511309bc1f307c74cda8dcb68b93a10ca213a22814b" +checksum = "18d0754f5b7a43915fd7466883b2d1bb0800d7cc4609178d0b27bf143b9e5123" dependencies = [ "bitflags", "raw-window-handle", @@ -294,18 +323,24 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] [[package]] -name = "instant" -version = "0.1.2" +name = "inplace_it" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c346c299e3fe8ef94dc10c2c0253d858a69aac1245157a3bf4125915d528caf" +checksum = "dd01a2a73f2f399df96b22dc88ea687ef4d76226284e7531ae3c7ee1dc5cb534" + +[[package]] +name = "instant" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" [[package]] name = "iovec" @@ -354,24 +389,24 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.68" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" [[package]] name = "libloading" -version = "0.5.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +checksum = "2443d8f0478b16759158b2f66d525991a05491138bc05814ef52a250148ef4f9" dependencies = [ - "cc", - "winapi 0.3.8", + "cfg-if", + "winapi 0.3.9", ] [[package]] @@ -385,18 +420,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ "scopeguard", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -423,14 +458,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "mio" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ "cfg-if", "fuchsia-zircon", @@ -502,13 +537,13 @@ checksum = "2b2820aca934aba5ed91c79acc72b6a44048ceacc5d36c035ed4e051f12d887d" [[package]] name = "net2" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ "cfg-if", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -526,9 +561,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ "autocfg", "num-traits", @@ -560,7 +595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.18", + "proc-macro2 1.0.20", "quote 1.0.7", "syn", ] @@ -576,18 +611,18 @@ dependencies = [ [[package]] name = "ordered-float" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579" dependencies = [ "num-traits", ] [[package]] name = "parking_lot" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" dependencies = [ "lock_api", "parking_lot_core", @@ -595,16 +630,16 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ "cfg-if", "cloudabi", "libc", "redox_syscall", "smallvec", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -615,15 +650,15 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pkg-config" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "proc-macro-crate" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ "toml", ] @@ -639,11 +674,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" dependencies = [ - "unicode-xid 0.2.0", + "unicode-xid 0.2.1", ] [[package]] @@ -661,7 +696,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.18", + "proc-macro2 1.0.20", ] [[package]] @@ -675,9 +710,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "rusttype" @@ -685,17 +720,16 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" dependencies = [ - "rusttype 0.8.2", + "rusttype 0.8.3", ] [[package]] name = "rusttype" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14a911032fb5791ccbeec9f28fdcb9bf0983b81f227bafdfd227c658d0731c8a" +checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0" dependencies = [ "approx", - "arrayvec", "ordered-float", "stb_truetype", ] @@ -717,9 +751,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.112" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" [[package]] name = "slab" @@ -729,9 +763,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.2.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "smithay-client-toolkit" @@ -760,24 +794,24 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350" dependencies = [ - "proc-macro2 1.0.18", + "proc-macro2 1.0.20", "quote 1.0.7", - "unicode-xid 0.2.0", + "unicode-xid 0.2.1", ] [[package]] name = "time" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "redox_syscall", - "winapi 0.3.8", + "wasi", + "winapi 0.3.9", ] [[package]] @@ -797,9 +831,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "void" @@ -814,10 +848,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" dependencies = [ "same-file", - "winapi 0.3.8", + "winapi 0.3.9", "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wayland-client" version = "0.23.6" @@ -886,9 +926,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -908,11 +948,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -929,7 +969,7 @@ checksum = "1e4ccbf7ddb6627828eace16cacde80fc6bf4dbb3469f88487262a02cf8e7862" dependencies = [ "bitflags", "cocoa", - "core-foundation", + "core-foundation 0.7.0", "core-graphics", "core-video-sys", "dispatch", @@ -948,7 +988,7 @@ dependencies = [ "raw-window-handle", "smithay-client-toolkit", "wayland-client", - "winapi 0.3.8", + "winapi 0.3.9", "x11-dl", ] @@ -992,6 +1032,6 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" [[package]] name = "xml-rs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb76e5c421bbbeb8924c60c030331b345555024d56261dae8f3e786ed817c23" +checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" diff --git a/Cargo.toml b/Cargo.toml index f0bbe15..cd009fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,16 +7,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -log = "0.4.8" -chrono = "0.4.11" -fern = { version = "0.6.0", features = ["colored"] } -gfx-hal = "0.5.3" -winit = "0.22.0" -raw-window-handle = "0.3.3" -num-traits = "0.2.12" +log = "^0.4.8" +chrono = "^0.4.11" +fern = { version = "^0.6.0", features = ["colored"] } +gfx-hal = "^0.6.0" +winit = "^0.22.0" +raw-window-handle = "^0.3.3" +num-traits = "^0.2.12" [dependencies.gfx-backend-vulkan] -version = "0.5" +version = "^0.6.1" features = ["x11"] [lib] diff --git a/doc/architecture b/doc/architecture index 68d9f08..242354c 100644 --- a/doc/architecture +++ b/doc/architecture @@ -1 +1 @@ -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 \ No newline at end of file +7Vxtc5u4Fv41num9M/EYMI75mNhx27vpNm0623S/eBSQbbWAWJDjuL9+9cqrICSG7uYOnYxrDkcv6Bw9enSO8MhaBI9vYxDtPmAP+iNz4j2OrOXINM25adP/mOQoJI49E4JtjDwhMjLBLfoJpXAipXvkwaSgSDD2CYqKQheHIXRJQQbiGB+KahvsF1uNwBZWBLcu8KvSr8gjOyk1Zk524x1E251sem6eixsBUMrySZId8PAhJ7KuRtYixpiIb8HjAvps8NS4iHKrmrtpx2IYkjYF/vfbb+HFH9++L9fuHfxhEm+z257JWh6Av5cP/Dbay/6SoxqE5IACH4T06nKDQ3Ir7xj0GvhoG9LvLu0FjKngAcYE0fG7kDcIjqjU3SHfuwZHvGd9TQhwf6iryx2O0U9aLfBlnfR2TKQrmLOCxi0rScUTKo1hQnVu1AAYJdEH8FhQvAYJkQIX+z6IEnSfPkYA4i0KLzEhOJBK1fFVg0WfED7mRHK830IcQBIfqYq8e2ZOpfGl99szeX3IfGk6l7Jdzo3SgkD67zatPDMx/SKt/AyLmxWLn7FmPBAx+1Efsi7o54W6prPVMthwMC0PPiAXpkpLeVnQ+WsP93C9jfE+ShU/MdlbLrIvjfH4vyN7WSrm4iAAobeO6OROyy2E8IbLSj5JTUC4r8T4B1xgH1PnW4ZYOCny/ZJI+akPN6TWS5MIuCjcXnOd5TSTfJaWYSJMy258PpN3yPNgyDwME0CAcCf2RBFGIeGWsy/pH7XlYjK2+VMv2BBk1/SPqcdkgUP6LABxZ4PUVw+Q+avGDRsn8tO+KV3RnLXzxNm0J0e0Ko5YsbGPuO2EjRX8Gi8ycEBN5cPMol+YwZdnRsXqVtXqlsbCPriH/g1OEEGY1R8L3ZLl/ynjOi1hZt6Tbaca29KHnYTwQD/f0LkPAjbh3tNhASHDkMVoYY4uJumdj3sS0dUhhYv/pKDwGSZ7n1BFn43gG75e0V5ObvfxBriUK+TLLN7Qj9lWjHUKOKIzXoyjQm8C2qA5oRVmjfHiWbFSDTF0YwgIXCcHEK2TY0JgoK9RdpGq3XKtXAsFYX1bEqGzugv9TKVV4JYPy7H6qdIVRBeF8+C8ps/0VDXisQvoXapRrBKFqnKjL12hsVq+pgyrQtfAMW8HHMbUPB065uTj9/sV/vbpC/7d9sB71/nzzzOjSlBWMQiqph5I6ctI6bTESefT6mKR8tQCJzU64KR6m+u4AIOJA0BkncCAbi0xHbAUEm6ViEnoZLJWRUYpSifU2IA1/uIaNjB0c4VWMHSbCyikvN9vNjk6LTHrUkoLzBcFdAu5fkB8aRTqHyPOKuQSxxYId0cx4D3TrF3ONmyWlNotVrTKa6haBgAlTZ5ptp5e9bxaO5ucDni1vss68jUQ647Ma5gt0bIDaq3vst2SW5e4Zypf4TgApCT8DEMPxjcgSUo3rh4JHUKzln/LtfkFPFuVrDK8ZzBw6sg/OPvmALlGAiGb2iqj6ULdFsBY2zBrbR/WtKdrrnbHUuqBIrvFThQGdMDoridxlebqJ3FvLHdWmcXZPnCgun3FX3Vct7/4q97y5xXLMxaYiOhFxk/VdYErbgR2CzIqcbygADlcCwUO3Z5ZJakxB/s1HVmgAMoldVoRWxOkVrZGFHvFkGsd3gu1PTP2gFlPYNastS8/M17bH6+cD7yyP/PqeGVfIVt9l50TeaVErDrak1/eFopePYswlmvQRpFPIZMuDjdou4/hOod99b2oJXgNcedyUNf9a49oexvBTxseOWtMctlSTRFdZKlPtqgpR3m1A8YDq62fbYD5rnGgbQRW0d7OkSA9sJCZFXpbqFgnHZUd3uIQ+FeZlI71nk4ZT450pnONOW4z2P4OCTlKWgn2BDNiSQJFOuEjIne5799YVdQa4mqpuCS/OKqLkD7vXf5ClJrO5kqQFeRXhZI3MEZ0yBhtbmacCd7HLmxB6ihx3sJGh5CRTjagje4QQx8Q9FA8haIztSx6w3w7Y76GXSK+5yVaIHoqS2UOcxHH4JhTk1Omtp0ywXaMScn/RI2ZN6bPeIKDVk+tpDQ0qYOknKs9uWdKuQffudQiyFLRiku6KdryGaDwjYLzhv9rjxVq2lWwIj3cJDsyyp8f0m17JmPHnEqPPNGPzqbWWAUUpYnPnLHjFOvBm00CyagMPF2YupoNokMvQuYuHXDC0XuwOLW4MsqxUNGp9ret8blZrNgYT8xfZv/qbvkGRZDvM4YoSU9REkO3GTEnOhIy6StMYlZ3mwzjQ8FuWfZtoJ7N4HLe2g/qIwxao5t9RRhM3RZ0iDB0ZF675ZzuK8BgTTTWzQUYsi1nhvDtAgNKv7jPH+ChY/+pbky1/tPbySCrmtgWIWl2nGHgAt1wAWdW5AKtT6wbs76ogFXNePNzM2nUT076LAw4TP2mqZ/Oo85zD0qvexeopksHZtCZeW2znXl7YwbVTZ4+9fAVhewVqtw7JJr4ddPJcbVatOMVSr9t/sCLwaE2AJ81XtvnlyQU0nZdH4L4lNbFLT5RTuoIiREIt/5Jvfgi63hJRwbw7xYdWhOA3mIB1rxi1VeWkLBHzekIzh8v2OuqmSdy2QqxoZIlPKXh+iBJkCuEUsVoIoBPJjAUx8onMJpeH+wuf3GSZ0z1mYCt5h3W1xIUVs7eRVB4NlVLu4rdy/TTiVFhu1ipUaJ9/YWD1d6ymA4wXnMSoEt7n9u2UzLNafZWS8Cvsq/lDEj/DyB9Y0773wL11XeE+LnJ7M3L15v6VW7fBQbMZ6bVKQakWaJZqdpSGqBH1Ne80ZLbAw5GH89tlZI90crnBRuf/zILv/ojR/8/uK/CPP8W3NdHfyOZ83m9oK98vhvQd4roPO0EDUqbh1926meqCfe+fsDv0uCO4ZRW+W52duqXO4pu1KnFV9d3jju7+3r2c3cVTn7/mTgfDM3vUIl3UkqmHtJ6ebM+I62XRuxURkfzIpShewNu1kHQX2txzU5evPIvOsRivsgyKyFm1bf0/hDuJS3m1SmpPq1fWNOe/GL4Waj+jKsJ5WuN29ecr1I5lfQZcL4bnJ+3wHlL+3MUHSRvtDbX5XaH+dw4PU4Ba61x+5rPujdCL3mhcuZXJbh1P+ilW+bZ/HlOHfINZp4cFvXpM9QHfoIgq7m22rSyIGLD8A4kn8FBnD94B0LmY8MrcP04tWIWTzm1/fzDRvQy+71dsXXJfrXYuvob \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0c2d6fc..3dbb978 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ pub fn run() -> Result<(), &'static str> { let mut windows = vec![ WinitWindow::new("IV", Rect {w: 1280, h: 720})?, - WinitWindow::new("IV 2", Rect {w: 720, h: 480})?, + // WinitWindow::new("IV 2", Rect {w: 720, h: 480})?, ]; let mut renderer: Renderer = Renderer::new(&mut windows)?; @@ -67,18 +67,14 @@ pub fn run() -> Result<(), &'static str> { let color = [0.5, 0.0, 0.0, 1.0]; - for window in &mut windows { - let _ = renderer.draw_clear_frame(window, color); - } - loop { for window in &mut windows { - match renderer.draw_frame(window) { + match renderer.draw_clear_frame(window, color) { Err(err) => println!("{}", err), _ => (), - } - } - } + }}} + +// Ok(()) } // let (input_tx, input_rx) = mpsc::channel(); diff --git a/src/renderer.rs b/src/renderer.rs index 86b2f48..dff28a5 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,6 +3,7 @@ use log::{debug, error, info, trace, warn}; use std::{ mem::ManuallyDrop, + iter, }; mod gpu; @@ -31,7 +32,10 @@ where B: gfx_hal::Backend, { fn drop(&mut self) { - use gfx_hal::device::Device; + use gfx_hal::{ + Instance, + device::Device, + }; debug!("Waiting for device to idle..."); let _ = self.gpu @@ -39,13 +43,14 @@ where .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 { + for mut swap_system in self.swap_systems.drain(..) { + self.instance.destroy_surface(swap_system.drop(&mut self.gpu)); + } ManuallyDrop::drop(&mut self.gpu); ManuallyDrop::drop(&mut self.instance); } @@ -86,42 +91,88 @@ where }) } - pub fn draw_frame(&mut self, output: &mut O) - -> Result<(), &'static str> - where - T: raw_window_handle::HasRawWindowHandle, - O: Output - { - use gfx_hal::window::AcquireError; - - let swap_index = output.get_id(); - let (frame, image_id) = match self.swap_systems[swap_index].acquire_frame() { - Ok((frame, image_id)) => (frame, image_id), - Err(err) => match err { - AcquireError::NotReady => { - return Err("Frame acquisition failed because all Frames are in use"); - }, - _ => Err("Could not acquire Frame from SwapSystem")?, - }}; - - let _ = frame.sync_gpu(&self.gpu)?; - - let queue = &mut self.gpu.queue_mut(); - frame.submit(queue); - - let _ = self.swap_systems[swap_index].present_frame(frame, image_id, queue)?; - - Ok(()) - } - pub fn draw_clear_frame(&mut self, output: &mut O, color: [f32; 4]) -> Result<(), &'static str> where T: raw_window_handle::HasRawWindowHandle, O: Output { - self.swap_systems[output.get_id()].configure_render_pass(color)?; - self.draw_frame(output) + use gfx_hal::{ + window::AcquireError, + device::Device, + queue::Submission, + }; + + let swap_system = &mut self.swap_systems[output.get_id()]; + + let mut frame = match swap_system.acquire_frame(&self.gpu) { + Ok(frame) => frame, + Err(err) => match err { + AcquireError::NotReady => { + return Err("Frame acquisition failed because all Frames are in use"); + }, + AcquireError::OutOfDate => { + swap_system.recreate(&mut self.gpu)?; + debug!("SwapSystem : {:#?}", swap_system); + return Ok(()); + }, + _ => Err("Could not acquire Frame from SwapSystem")?, + }}; + + trace!("Waiting for Frame..."); + unsafe { + let _ = self.gpu.device() + .wait_for_fence(&frame.fences[0], !0) + .map_err(|_| "Failed to wait for Fence")?; + let _ = self.gpu.device() + .reset_fence(&frame.fences[0]) + .map_err(|_| "Failed to reset fence")?; + } + + trace!("Recording CommandBuffer..."); + unsafe { + use gfx_hal::command::{ + CommandBufferFlags, + SubpassContents, + ClearValue, + ClearColor, + CommandBuffer, + }; + + frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + + let clear_value = ClearValue {color: ClearColor{float32: color}}; + + frame.command_buffer.begin_render_pass( + &swap_system.render_pass, + &frame.framebuffer.as_ref().unwrap(), + swap_system.render_area, + iter::once(clear_value), + SubpassContents::Inline, + ); + frame.command_buffer.end_render_pass(); + frame.command_buffer.finish(); + } + + trace!("Submiting to queue..."); + let submission = Submission { + command_buffers: iter::once(&*frame.command_buffer), + wait_semaphores: None, + signal_semaphores: iter::once(&frame.signal_semaphores[0]), + }; + + unsafe { + use gfx_hal::queue::CommandQueue; + + self.gpu.queue_mut().submit(submission, Some(&frame.fences[0])); + } + + let result = swap_system.present_frame(frame, &mut self.gpu); + if result.is_err() { + swap_system.recreate(&mut self.gpu).unwrap(); + } + + Ok(()) } } diff --git a/src/renderer/gpu.rs b/src/renderer/gpu.rs index ef4ee26..e88b197 100644 --- a/src/renderer/gpu.rs +++ b/src/renderer/gpu.rs @@ -162,7 +162,7 @@ where trace!("Creating CommandPool..."); device .create_command_pool(queue_group.family, - CommandPoolCreateFlags::empty()) + CommandPoolCreateFlags::RESET_INDIVIDUAL) .map_err(|_| "Could not create CommandPool")? }; diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index 81056c9..8a251d2 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -4,11 +4,11 @@ use log::{debug, error, info, trace, warn}; use std::{ mem::ManuallyDrop, ptr::read, - collections::HashMap, + collections::VecDeque, }; use gfx_hal::{ - window::{Extent2D, AcquireError}, + window::{Extent2D, AcquireError, PresentationSurface, SurfaceCapabilities, SwapchainConfig}, pso::Rect as GfxRect, format::Format, }; @@ -24,11 +24,9 @@ pub struct SwapSystem { surface: ManuallyDrop, format: Format, extent: Extent2D, - render_area: GfxRect, //TODO may not be needed (duplicate of extent) - swapchain: ManuallyDrop, - spare_semaphore: ManuallyDrop, - render_pass: ManuallyDrop, - frames: HashMap>, + pub render_area: GfxRect, //TODO may not be needed (duplicate of extent) + pub render_pass: ManuallyDrop, + frames: VecDeque>, frame_nb: usize, } @@ -36,36 +34,26 @@ impl SwapSystem where B: gfx_hal::Backend, { - pub fn drop(&mut self, gpu: &mut Gpu, instance: &B::Instance) { - use gfx_hal::{ - device::Device, - Instance, - }; + pub fn drop(&mut self, gpu: &mut Gpu) -> B::Surface { + use gfx_hal::device::Device; debug!("Dropping SwapSystem..."); - for (_, mut frame) in self.frames.drain() { + 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 extent and format can be dropped automatically - instance.destroy_surface( - ManuallyDrop::into_inner(read(&mut self.surface))); + self.surface.unconfigure_swapchain(gpu.device()); + trace!("SwapSystem dropped !"); + ManuallyDrop::take(&mut self.surface) } - trace!("SwapSystem dropped !"); } - pub fn new(gpu: &mut Gpu, mut surface: B::Surface) + pub fn new(gpu: &mut Gpu, mut surface: B::Surface) -> Result, &'static str> { - use gfx_hal::{ - window::SwapchainConfig, - }; debug!("Creating SwapSystem..."); trace!("Obtaining surface capabilities..."); @@ -99,92 +87,17 @@ where let render_area = GfxRect{x: 0, y: 0, w: extent.width as i16, h: extent.height as i16}; trace!("Generating Swapchain configuration..."); - let (swapchain_config, frame_nb) = { - - 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 values specified!")? - }; - - let composite_alpha_mode = { - use gfx_hal::window::CompositeAlphaMode; - - [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT, - CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED] - .iter() - .cloned() - .find(|ca| capabilities.composite_alpha_modes.contains(*ca)) - .ok_or("No CompositeAlpha values specified!")? - }; - - let image_count = { - use std::cmp::{min, max}; - use gfx_hal::window::PresentMode; - - let count = match present_mode { - PresentMode::MAILBOX => 3, - _ => 2, //TODO to be checked - }; - max(capabilities.image_count.start().clone(), - min(capabilities.image_count.end().clone(), count)) - }; - - warn!("Hard-coding number of layers per image !"); - let image_layers = 1; - - let image_usage = { - use gfx_hal::image::Usage; - - if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) { - Usage::COLOR_ATTACHMENT - } else { - Err("The Surface isn't capable of supporting color!")? - }}; - - ( - SwapchainConfig { - present_mode, - composite_alpha_mode, - format: format.clone(), - extent: extent.clone(), - image_count: image_count.clone(), - image_layers, - image_usage, - }, - image_count as usize - ) - }; - // //TODO improve swapchain configuration - // let swapchain_config = SwapchainConfig::from_caps(&capabilities, format, extent); - // let swapchain_config = swapchain_config.with_image_count(3); + let (swapchain_config, frame_nb) = + generate_swapchain_config(capabilities, &format, &extent)?; 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) + trace!("Configuring Swapchain..."); + let _ = unsafe { + surface + .configure_swapchain(gpu.device(), swapchain_config) .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::{ @@ -219,11 +132,11 @@ where }; warn!("Generating hard-coded number of frames !"); - let mut frames = HashMap::with_capacity(frame_nb); - for i in 0..frame_nb { - let frame = Frame::new(gpu, &backbuffer[i], &format, &render_pass, &extent) + let mut frames = VecDeque::with_capacity(frame_nb); + for _ in 0..frame_nb { + let frame = Frame::new(gpu) .map_err(|_| "Could not create frame")?; - frames.insert(i, frame); + frames.push_back(frame); }; let frame_nb = frames.len(); @@ -234,67 +147,167 @@ where format, extent, render_area, - swapchain: ManuallyDrop::new(swapchain), - spare_semaphore: ManuallyDrop::new(spare_semaphore), render_pass: ManuallyDrop::new(render_pass), frames, frame_nb, }) } - pub fn configure_render_pass(&mut self, color: [f32; 4]) -> Result<(), &'static str> { - - if self.frames.len() != self.frame_nb { - return Err("Tried to configure RenderPass with frames acquired"); - } + pub fn recreate(&mut self, gpu: &mut Gpu) -> Result<(), &'static str> { - debug!("Configuring Color RenderPass..."); - for (_, frame) in &mut self.frames { - frame.record_command_buffer(&self.render_pass, self.render_area.clone(), color); - } + trace!("Obtaining surface capabilities..."); + let capabilities = { + use gfx_hal::window::Surface; + + self.surface.capabilities(&gpu.adapter().physical_device) + }; + debug!("Surface capabitlities : {:#?}", capabilities); + + trace!("Getting surface's render area size..."); + self.extent = capabilities.current_extent + .unwrap_or(*capabilities.extents.end()) + .clone(); + self.render_area = + GfxRect{x: 0, y: 0, w: self.extent.width as i16, h: self.extent.height as i16}; + + trace!("Generating Swapchain configuration..."); + let (swapchain_config, _frame_nb) = //TODO check frame nb change + generate_swapchain_config(capabilities, &self.format, &self.extent)?; + debug!("Swapchain configuration : {:#?}", swapchain_config); + + trace!("Configuring Swapchain..."); + let _ = unsafe { + self.surface + .configure_swapchain(gpu.device(), swapchain_config) + .map_err(|_| "Failed to create swapchain and backbuffer")? + }; Ok(()) } - pub fn acquire_frame(&mut self) -> Result<(Frame, u32), AcquireError> { - use gfx_hal::window::Swapchain; + pub fn acquire_frame(&mut self, gpu: &Gpu) -> Result, AcquireError> { trace!("Acquiring Frame..."); - let image_id = unsafe { - match self.swapchain.acquire_image(core::u64::MAX, Some(&self.spare_semaphore), None) { - Ok((image_id, suboptimal)) => { + let image = unsafe { + match self.surface.acquire_image(core::u64::MAX) { + Ok((image, suboptimal)) => { match suboptimal { Some(_) => return Err(AcquireError::OutOfDate), - None => image_id, + None => image, }}, Err(err) => return Err(err), }}; + let mut frame = self.frames.pop_back().unwrap(); - //TODO give back image to swaphain - //debug!("image id : {}", image_id); - let mut frame = match self.frames.remove(&(image_id as usize)) { - Some(frame) => frame, - None => return Err(AcquireError::NotReady), + trace!("Creating Framebuffer..."); + let framebuffer = unsafe { + use gfx_hal::device::Device; + use std::borrow::Borrow; + + gpu.device() + .create_framebuffer(&self.render_pass, + vec![image.borrow()], + self.extent.clone().to_extent()) + .unwrap() //TODO improve that }; - frame.swap_semaphore(&mut self.spare_semaphore); + + frame.link_swapchain_image(image, framebuffer); - Ok((frame, image_id)) + Ok(frame) } - pub fn present_frame(&mut self, frame: Frame, image_id: u32, queue: &mut B::CommandQueue) + pub fn present_frame(&mut self, mut frame: Frame, gpu: &mut Gpu) -> Result<(), &'static str> { - use gfx_hal::window::Swapchain; + use gfx_hal::{ + queue::CommandQueue, + device::Device, + }; + + let (image, framebuffer) = frame + .unlink_swapchain_image() + .unwrap(); //TODO improve that trace!("Presenting Frame..."); - let _result = unsafe { - self.swapchain - .present(queue, image_id, Some(frame.get_present_semaphore())) + let _ = unsafe { + gpu.queue_mut() + .present(&mut self.surface, image, Some(&frame.signal_semaphores[0])) .map_err(|_| "Failed to present into the swapchain")?; }; - self.frames.insert(image_id as usize, frame); + self.frames.push_front(frame); + + trace!("Destroying Framebuffer..."); + unsafe { + gpu.device().destroy_framebuffer(framebuffer); + } Ok(()) } } +fn generate_swapchain_config(capabilities: SurfaceCapabilities, + format: &Format, + extent: &Extent2D) + -> Result<(SwapchainConfig, usize), &'static str> { + + trace!("Generating Swapchain configuration..."); + 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 values specified!")? + }; + + let composite_alpha_mode = { + use gfx_hal::window::CompositeAlphaMode; + + [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT, + CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED] + .iter() + .cloned() + .find(|ca| capabilities.composite_alpha_modes.contains(*ca)) + .ok_or("No CompositeAlpha values specified!")? + }; + + let image_count = { + use std::cmp::{min, max}; + use gfx_hal::window::PresentMode; + + let count = match present_mode { + PresentMode::MAILBOX => 3, + _ => 2, //TODO to be checked + }; + max(capabilities.image_count.start().clone(), + min(capabilities.image_count.end().clone(), count)) + }; + + warn!("Hard-coding number of layers per image !"); + let image_layers = 1; + + let image_usage = { + use gfx_hal::image::Usage; + + if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) { + Usage::COLOR_ATTACHMENT + } else { + Err("The Surface isn't capable of supporting color!")? + }}; + + Ok (( + SwapchainConfig { + present_mode, + composite_alpha_mode, + format: format.clone(), + extent: extent.clone(), + image_count: image_count.clone(), + image_layers, + image_usage, + }, + image_count as usize + )) +} + diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index 723c96f..24ad72d 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -7,24 +7,19 @@ use std::{ iter, }; -use gfx_hal::{ - window::Extent2D, - format::Format, - queue::Submission, - pso::Rect as GfxRect, -}; +use gfx_hal::window::{PresentationSurface}; use super::super::gpu::Gpu; //--Frame implementation---------------------------------------------------------------------------- #[derive(Debug)] pub struct Frame { - wait_semaphores: Vec, - signal_semaphores: Vec, - fences: Vec, - image_view: ManuallyDrop, - framebuffer: ManuallyDrop, - command_buffer: ManuallyDrop, + pub wait_semaphores: Vec, + pub signal_semaphores: Vec, + pub fences: Vec, + pub command_buffer: ManuallyDrop, + image_view: Option<>::SwapchainImage>, + pub framebuffer: Option, } impl Frame @@ -39,12 +34,11 @@ where trace!("Dropping Frame..."); unsafe { + if self.image_view.is_some() { + warn!("Dropping non-presented frame !"); + } 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); } @@ -58,12 +52,7 @@ where } } - pub fn new(gpu: &mut Gpu, - image: &B::Image, - format: &Format, - render_pass: &B::RenderPass, - extent: &Extent2D) - -> Result, &'static str> + pub fn new(gpu: &mut Gpu) -> Result, &'static str> { debug!("Creating Frame..."); @@ -86,41 +75,7 @@ where (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 ImageView")? - }; - 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::{ @@ -136,86 +91,29 @@ where wait_semaphores, signal_semaphores, fences, - image_view: ManuallyDrop::new(image_view), - framebuffer: ManuallyDrop::new(framebuffer), command_buffer: ManuallyDrop::new(command_buffer), + image_view: None, + framebuffer: None, }) } - pub fn sync_gpu(&self, gpu: &Gpu) -> Result<(), &'static str>{ - use gfx_hal::device::Device; - - trace!("Waiting for Frame..."); - unsafe { - let _ = gpu.device() - .wait_for_fence(&self.fences[0], !0) - .map_err(|_| "Failed to wait for Fence")?; - let _ = gpu.device() - .reset_fence(&self.fences[0]) - .map_err(|_| "Failed to reset fence")?; - } + pub fn link_swapchain_image(&mut self, + image: >::SwapchainImage, + framebuffer: B::Framebuffer) { - Ok(()) + self.image_view = Some(image); + self.framebuffer = Some(framebuffer); } - pub fn record_command_buffer(&mut self, - render_pass: &B::RenderPass, - render_area: GfxRect, - color: [f32; 4]) { + pub fn unlink_swapchain_image(&mut self) + -> Result<(>::SwapchainImage, + B::Framebuffer), &'static str> { - trace!("Recording CommandBuffer..."); - - unsafe { - use gfx_hal::command::{ - CommandBufferFlags, - SubpassContents, - ClearValue, - ClearColor, - CommandBuffer, - }; - - self.command_buffer.begin_primary(CommandBufferFlags::EMPTY); - - 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(); - } - } - - pub fn submit(&self, queue: &mut B::CommandQueue) { - use gfx_hal::pso::PipelineStage; - - trace!("Submiting to queue..."); - let submission = 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]), - }; - - unsafe { - use gfx_hal::queue::CommandQueue; - - queue.submit(submission, Some(&self.fences[0])); - } - } - - pub fn swap_semaphore(&mut self, semaphore: &mut B::Semaphore) { - - std::mem::swap(&mut self.wait_semaphores[0], semaphore); - } - - pub fn get_present_semaphore(&self) -> &B::Semaphore { - - &self.signal_semaphores[0] + match (self.image_view.take(), self.framebuffer.take()) { + (Some(image_view), Some(framebuffer)) => Some((image_view, framebuffer)), + _ => None, + } + .ok_or("Can not unlink non-linked Frame !") } } From 7f37ee7a24b2824fcd812dd4a218164d4f035abd Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 7 Nov 2020 11:23:24 +0100 Subject: [PATCH 04/22] Implemented Controller * reworked input system + added Subengines system + added Subengines pipeline system !(old) some framebuffer error present !(old) may crash during swapchain recreation ! crashes randomly while running --- doc/architecture | 2 +- src/controller.rs | 166 ++++++++++++++++++++++++++ src/input.rs | 42 ------- src/io.rs | 98 +++++++++++++++ src/lib.rs | 116 +++++++++++++----- src/renderer.rs | 29 ++--- src/renderer/gpu.rs | 23 ++-- src/renderer/output.rs | 43 ------- src/subengine.rs | 22 ++++ src/subengine/subengine_controller.rs | 140 ++++++++++++++++++++++ src/subengine/subengine_pipeline.rs | 72 +++++++++++ src/subengine/test_subengine.rs | 36 ++++++ src/winit_window.rs | 88 ++++++++++++-- 13 files changed, 724 insertions(+), 153 deletions(-) create mode 100644 src/controller.rs delete mode 100644 src/input.rs create mode 100644 src/io.rs delete mode 100644 src/renderer/output.rs create mode 100644 src/subengine.rs create mode 100644 src/subengine/subengine_controller.rs create mode 100644 src/subengine/subengine_pipeline.rs create mode 100644 src/subengine/test_subengine.rs diff --git a/doc/architecture b/doc/architecture index 242354c..4990374 100644 --- a/doc/architecture +++ b/doc/architecture @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/src/controller.rs b/src/controller.rs new file mode 100644 index 0000000..a335776 --- /dev/null +++ b/src/controller.rs @@ -0,0 +1,166 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use crate::{ + io::{Input, Output}, + subengine::SubenginePipeline, +}; + +//--Controller Implementation----------------------------------------------------------------------- +pub struct Controller<'a, I, W, O> +where + I: Input, + W: raw_window_handle::HasRawWindowHandle, + O: Output, +{ + pipelines: Vec>, + color: [f32; 4], +} + +impl Controller<'_, I, W, O> +where + I: Input, + W: raw_window_handle::HasRawWindowHandle, + O: Output, +{ + + pub fn new<'a, Ip>(pipelines: Ip) -> Controller<'a, I, W, O> + where + I: 'a + Input, + W: raw_window_handle::HasRawWindowHandle, + O: 'a + Output, + Ip: IntoIterator>, + { + let pipelines_vec = pipelines + .into_iter() + .map(|pipeline| pipeline) + .collect(); + + Controller { + pipelines: pipelines_vec, + color: [0.0, 1.0, 0.0, 0.0], + } + } + + pub fn run(&mut self) { + use std::time::Duration; + + use crate::{ + subengine::subengine_controller::SubengineCommand, + io::Key, + }; + + let mut input_keys: Vec = Vec::new(); + + for pipeline in &mut self.pipelines { + for input in &pipeline.inputs { + match input.borrow().read(1) { + Ok(key) => input_keys.push(key), + Err(_err) => (), + } + } + for input_key in &input_keys { + match input_key { + Key::MouseMove{x,y} => self.color = [ + (x/1280.0) as f32, + (y/720.0) as f32, + ((x/1280.0 + y/720.0)/2.0) as f32, + 1.0], + _ => (), + }; + } + for subengines in &pipeline.subengines { + for subengine in subengines { + subengine.exec(SubengineCommand::Run); + } + for subengine in subengines { + subengine.wait_for_exec(Duration::from_millis(1)).unwrap(); + } + } + for (renderer, output) in &mut pipeline.renderers { + match renderer.draw_clear_frame(output, self.color) { + Err(err) => warn!("{}", err), + _ => (), + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::iter; + + use crate::{ + winit_window::WinitWindow, + renderer::Renderer, + utils::Rect, + subengine::{SubengineController, TestSubengine}, + }; + + use gfx_backend_vulkan as vk_back; + + #[test] + fn test_new() { + use std::cell::RefCell; + + //creating windows + let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap()); + let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap()); + + //creating renderers + let renderer1 = Renderer::::new(&mut iter::once(&window1)).unwrap(); + let renderer2 = Renderer::::new(&mut iter::once(&window2)).unwrap(); + + //creating subengines + let (test_subengine1, _test_rx1) = TestSubengine::new("run1"); + let test_controller1 = SubengineController::new(test_subengine1); + let (test_subengine2, _test_rx2) = TestSubengine::new("run2"); + let test_controller2 = SubengineController::new(test_subengine2); + + //preparing data + let inputs = vec![&window1, &window2]; + let subengines = vec![vec![test_controller1, test_controller2]]; + let renderers = vec![(renderer1, &window1), (renderer2, &window2)]; + + //creating pipeline + let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers); + + //creating controller + let controller = Controller::new(vec![subengine_pipeline]); + } + + #[test] + fn test_run() { + use std::cell::RefCell; + + //creating windows + let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap()); + let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap()); + + //creating renderers + let renderer1 = Renderer::::new(&mut iter::once(&window1)).unwrap(); + let renderer2 = Renderer::::new(&mut iter::once(&window2)).unwrap(); + + //creating subengines + let (test_subengine1, _test_rx1) = TestSubengine::new("run1"); + let test_controller1 = SubengineController::new(test_subengine1); + let (test_subengine2, _test_rx2) = TestSubengine::new("run2"); + let test_controller2 = SubengineController::new(test_subengine2); + + //preparing data + let inputs = vec![&window1, &window2]; + let subengines = vec![vec![test_controller1, test_controller2]]; + let renderers = vec![(renderer1, &window1), (renderer2, &window2)]; + + //creating pipeline + let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers); + + //running controller + let mut controller = Controller::new(vec![subengine_pipeline]); + controller.run(); + } +} + diff --git a/src/input.rs b/src/input.rs deleted file mode 100644 index bdf7450..0000000 --- a/src/input.rs +++ /dev/null @@ -1,42 +0,0 @@ -#[allow(unused_imports)] -use log::{debug, error, info, trace, warn}; - -use winit::{ - event::{Event, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, -}; - -#[derive(Debug)] -pub struct Input { - pub close_request: bool, - pub new_frame_size: Option<(f64, f64)>, - pub new_mouse_pos: Option<(f64, f64)>, -} - -impl Input { - - pub fn poll_events_loop(event_loop: &mut EventLoop<()>) -> Self { - let mut input = Input::default(); - event_loop.run(|event, _, control_flow| { - *control_flow = ControlFlow::Wait; - - match event { - Event::WindowEvent{window_id: _, event} => match event { - WindowEvent::CloseRequested => (), - _ => (), - } - _ => (), - } - }); - input - } - - pub fn default() -> Self { - Input { - close_request: false, - new_frame_size: None, - new_mouse_pos: None, - } - } -} - diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..9dd067a --- /dev/null +++ b/src/io.rs @@ -0,0 +1,98 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use raw_window_handle::HasRawWindowHandle; + +use crate::utils::Rect; + +//--Output trait------------------------------------------------------------------------------------ +/// A trait for the ability of a type to be used as an output by the engine. +/// +/// The `Output` trait defines functions to be used by different components of the engine. This +/// allows to display with any window manager as long as the trait is defined for it. +/// +/// Types that implement the `Output` trait should manage the underlying window and settings. +/// +/// Implementation : the ID and size stored by the type implementing this trait don't need to be +/// initialized to anything specific as the engine will take care of it. +pub trait Output +where + W: HasRawWindowHandle, +{ + /// Return the ID stored internally. Used to select the right swapchain by the render engine. + /// For internal use only. + fn get_id(&self) -> usize; + + /// Store the given ID internally. For internal use only. + fn set_id(&mut self, id: usize); + + //TODO clean that + /// Give mutable acces to the size of the output. The size is a simple rectangle containing the + /// width and height of the `Output`. + fn size(&mut self) -> &mut Rect; + + /// Give reference acces to the underlying window. This is used by the engine during setup to + /// create the revelant ressources. + fn window(&self) -> &W; +} + +//impl<'a, W, O> Output for &'a mut O +//where +// W: HasRawWindowHandle, +// O: Output, +//{ +// 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 { Output::size(*self) } +// +// fn window(&self) -> &W { Output::window(*self) } +//} + +//impl<'a, W, O> Output for Box +//where +// W: HasRawWindowHandle, +// O: Output, +//{ +// 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 { Output::size(self) } +// +// fn window(&self) -> &W { Output::window(self) } +//} + +//--Input trait------------------------------------------------------------------------------------ +/// A trait for the ability of a type to be used as an input by the engine +/// +/// The `Input` trait defines functions used by different components of the engine. The allow to +/// read inputs from any window manzger as long as the is defined for it. +/// +/// Types that implement the `Input` trait should manage the EventLoop. This can be done in any way +/// (polling, interrupt, synchronous, asynchronous, ...) depending on how the input should be +/// handled. +pub trait Input { + /// Return the next input available or a ReadError if an error occured of the timeout duration + /// was reached. How inputs are handled depends on the implementation. + //TODO change timeout + fn read(&self, timeout_ms: u32) -> Result; +} + +//impl<'a, I> Input for &'a mut I +//where +// I: Input, +//{ +// fn read(&self, timeout_ms: u32) -> Result { Input::read(*self, timeout_ms) } +//} + +//--Key enum---------------------------------------------------------------------------------------- +pub enum Key { + Close, + MouseMove { x: f64, y: f64 }, +} + +//--ReadError enum---------------------------------------------------------------------------------- +pub enum ReadError { + Timeout, +} + diff --git a/src/lib.rs b/src/lib.rs index 3dbb978..d97c6b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,31 +5,32 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; -//use std::{ -// sync::mpsc, -// thread, -// collections::HashMap, -// cell::RefCell, -//}; - use gfx_backend_vulkan as vk_back; +pub mod io; + +pub mod subengine; +use subengine::SubenginePipeline; + +pub mod controller; +use controller::Controller; + pub mod utils; -use crate::utils::Rect; +//use utils::Rect; mod winit_window; -use winit_window::WinitWindow; - -//use winit::{ -// event::{Event, WindowEvent}, -// event_loop::ControlFlow, -//}; +//use winit_window::WinitWindow; mod renderer; -use renderer::Renderer; +//use renderer::Renderer; -//mod local_state; -//use local_state::LocalState; +//mod controller; +//use controller::Controller; + +//use crate::engine::{ +// EngineController, +// TestEngine, +//}; pub enum Command { NoCommand, @@ -56,24 +57,73 @@ pub enum Input { /// The main function of the library pub fn run() -> Result<(), &'static str> { - - let mut windows = vec![ - WinitWindow::new("IV", Rect {w: 1280, h: 720})?, - // WinitWindow::new("IV 2", Rect {w: 720, h: 480})?, - ]; + use std::{ + iter, + cell::RefCell, + }; - let mut renderer: Renderer = Renderer::new(&mut windows)?; + use crate::{ + winit_window::WinitWindow, + renderer::Renderer, + utils::Rect, + subengine::{SubengineController, TestSubengine}, + }; + + //creating windows + let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap()); + //let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap()); + + //creating renderers + let renderer1 = Renderer::::new(&mut iter::once(&window1)).unwrap(); + //let renderer2 = Renderer::::new(&mut iter::once(&window2)).unwrap(); + + //creating subengines + let (test_subengine1, _test_rx1) = TestSubengine::new("run1"); + let test_controller1 = SubengineController::new(test_subengine1); + //let (test_subengine2, _test_rx2) = TestSubengine::new("run2"); + //let test_controller2 = SubengineController::new(test_subengine2); + + //preparing data + let inputs = vec![&window1]; + let subengines = vec![vec![test_controller1/*, test_controller2*/]]; + let renderers = vec![(renderer1, &window1)/*, (renderer2, &window2)*/]; + + //creating pipeline + let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers); + + //running controller + let mut controller = Controller::new(vec![subengine_pipeline]); + loop { + controller.run(); + } + + //let engine_pipelines = vec![ + // EnginePipeline { + // Inputs: vec![0,1], + // Engines: vec![&color_engine], + // Renderers: vec![(1,0)], + // }, + // EnginePipeline { + // Inputs: vec![3], + // Engines: vec![&color_engine], + // Renderers: vec![(1,1),(1,2),(1,3)], + //}]; + + //let controller = Controller::new(renderers, &windows, &windows, engine_pipelines); + //controller.run(); + + Ok(()) //let local_state = LocalState::default(); - let color = [0.5, 0.0, 0.0, 1.0]; - - loop { - for window in &mut windows { - match renderer.draw_clear_frame(window, color) { - Err(err) => println!("{}", err), - _ => (), - }}} - +// let color = [0.5, 0.0, 0.0, 1.0]; +// +// loop { +// for window in &mut windows { +// match renderer.draw_clear_frame(window, color) { +// Err(err) => println!("{}", err), +// _ => (), +// }}} +// // Ok(()) } @@ -92,7 +142,7 @@ pub fn run() -> Result<(), &'static str> { // // let mut color = [0.0, 0.0, 0.0, 0.0]; // -// loop { +// loop // // //TODO manage errors // for window in windows { diff --git a/src/renderer.rs b/src/renderer.rs index dff28a5..2fc712e 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -4,6 +4,11 @@ use log::{debug, error, info, trace, warn}; use std::{ mem::ManuallyDrop, iter, + cell::RefCell, +}; + +use crate::{ + io::Output, }; mod gpu; @@ -12,18 +17,11 @@ use gpu::Gpu; 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 { instance: ManuallyDrop, gpu: ManuallyDrop>, - //pipelines: Vec>, swap_systems: Vec>, } @@ -62,12 +60,11 @@ impl Renderer where B: gfx_hal::Backend, { - pub fn new<'a, H, T: 'a, I>(outputs: I) -> Result, &'static str> + pub fn new<'a, W: 'a, O: 'a, I>(outputs: &mut I) -> Result, &'static str> where - H: raw_window_handle::HasRawWindowHandle, - T: Output, - I: IntoIterator, - + W: raw_window_handle::HasRawWindowHandle, + O: Output, + I: Iterator>, { use gfx_hal::Instance; @@ -91,11 +88,11 @@ where }) } - pub fn draw_clear_frame(&mut self, output: &mut O, color: [f32; 4]) + pub fn draw_clear_frame(&mut self, output: &RefCell, color: [f32; 4]) -> Result<(), &'static str> where - T: raw_window_handle::HasRawWindowHandle, - O: Output + W: raw_window_handle::HasRawWindowHandle, + O: Output, { use gfx_hal::{ window::AcquireError, @@ -103,7 +100,7 @@ where queue::Submission, }; - let swap_system = &mut self.swap_systems[output.get_id()]; + let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()]; let mut frame = match swap_system.acquire_frame(&self.gpu) { Ok(frame) => frame, diff --git a/src/renderer/gpu.rs b/src/renderer/gpu.rs index e88b197..31fcc7f 100644 --- a/src/renderer/gpu.rs +++ b/src/renderer/gpu.rs @@ -4,6 +4,7 @@ use log::{debug, error, info, trace, warn}; use std::{ mem::ManuallyDrop, ptr::read, + cell::RefCell, }; use gfx_hal::{ @@ -13,9 +14,14 @@ use gfx_hal::{ use gfx_hal::adapter::Gpu as GfxGpu; -use super::output::Output; +use crate::io::Output; //--Gpu implementation------------------------------------------------------------------------------ +/// A struct managing all things related to a specific GPU +/// +/// The `GPU` struct manages the structs from the gfx_hal[gfx_hal] related to the physical device. +/// It implements constructor and destructors as well as acces functions. This is done to make the +/// usage of the HAL easier and make the higher level code less dependant on changes in it. #[derive(Debug)] pub struct Gpu { adapter: ManuallyDrop>, @@ -47,12 +53,13 @@ impl Gpu where B: gfx_hal::Backend, { - pub fn new<'a, H, T: 'a, I>(instance: &B::Instance, outputs: I) + /// Create a new `GPU` based on an `instance` of the gfx_hal[gfx_hal]. + pub fn new<'a, W, O: 'a, I>(instance: &B::Instance, outputs: &mut I) -> Result<(Gpu, Vec), &'static str> where - H: raw_window_handle::HasRawWindowHandle, - T: Output, - I: IntoIterator, + W: raw_window_handle::HasRawWindowHandle, + O: Output, + I: Iterator>, { use gfx_hal::{ queue::family::QueueFamily, @@ -65,13 +72,13 @@ where let mut id = 0; outputs - .into_iter() + .by_ref() .map(|output| unsafe { - output.set_id(id); + output.borrow_mut().set_id(id); id += 1; instance - .create_surface(output.window()) + .create_surface(output.borrow().window()) .map_err(|_| "Could not create surface") }) .collect::, &str>>()? diff --git a/src/renderer/output.rs b/src/renderer/output.rs deleted file mode 100644 index 49de5f2..0000000 --- a/src/renderer/output.rs +++ /dev/null @@ -1,43 +0,0 @@ -#[allow(unused_imports)] -use log::{debug, error, info, trace, warn}; - -use raw_window_handle::HasRawWindowHandle; - -use crate::utils::Rect; - -//--Output trait------------------------------------------------------------------------------------ -pub trait Output -where - T: HasRawWindowHandle, -{ - fn get_id(&self) -> usize; - fn set_id(&mut self, id: usize); - - fn size(&mut self) -> &mut Rect; - - fn window(&self) -> &T; -} - -//impl<'a, T, O> Output for &'a O -//where -// T: HasRawWindowHandle, -// O: Output { -// fn id(&mut self) -> &mut i32 { Output::id(*self) } -// -// fn size(&mut self) -> &mut Rect { Output::size(*self) } -// -// fn window(&self) -> &T { Output::window(*self) } -//} - -impl<'a, T, O> Output for &'a mut O -where - T: HasRawWindowHandle, - O: Output { - 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 { Output::size(*self) } - - fn window(&self) -> &T { Output::window(*self) } -} - diff --git a/src/subengine.rs b/src/subengine.rs new file mode 100644 index 0000000..12fc610 --- /dev/null +++ b/src/subengine.rs @@ -0,0 +1,22 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +pub mod subengine_controller; +pub use self::subengine_controller::SubengineController; + +pub mod subengine_pipeline; +pub use self::subengine_pipeline::SubenginePipeline; + +pub mod test_subengine; +pub use self::test_subengine::TestSubengine; + + +//--SubEngine trait------------------------------------------------------------------------------------ +/// A trait that should be implemented by all subengines running it the game engine. +/// +/// Allow the [`Controller`] to run custom subengines. +pub trait Subengine { + /// Main function of the subengine. Called byt the [`Controller`] for each frame. + fn run(&self); +} + diff --git a/src/subengine/subengine_controller.rs b/src/subengine/subengine_controller.rs new file mode 100644 index 0000000..94cef97 --- /dev/null +++ b/src/subengine/subengine_controller.rs @@ -0,0 +1,140 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use std::{ + sync::mpsc::{Sender, Receiver}, + thread::JoinHandle, + mem::ManuallyDrop, + ptr::read, + time::Duration, +}; + +use crate::subengine::Subengine; + +//--SubengineController Implementation-------------------------------------------------------------- +/// Handle to manage an [`Subengine`]. +/// +/// The `SubengineController` runs the [`Engine`] in a separated thread with some control code to +/// allow control from the main thread. SubengineControllers are used by the [`Controller`] to +/// interact with Subengines. +#[derive(Debug)] +pub struct SubengineController { + tx: Sender, + rx: Receiver, + handle: ManuallyDrop>, +} + +impl Drop for SubengineController { + fn drop(&mut self) { + self.exec(SubengineCommand::Stop); + unsafe { let _ = ManuallyDrop::into_inner(read(&mut self.handle)).join(); } + debug!("SubengineController dropped !"); + } +} + +impl SubengineController { + /// Creates a new `SubengineController` from a given [`Engine`]. Since the latter will be moved + /// to a separated thread, it must implement the [`Send`] trait. + pub fn new(engine: E) -> SubengineController + where + E: Subengine + std::marker::Send, + { + use std::{ + thread, + sync::mpsc::channel, + }; + + debug!("Creating SubengineController..."); + let (tx, e_rx) = channel(); + let (e_tx, rx) = channel(); + + let handle = thread::spawn(move || { + trace!("Subengine thread started !"); + loop { + //TODO manage errors + match e_rx.recv().unwrap() { + SubengineCommand::Run => engine.run(), + SubengineCommand::Stop => return, + }; + e_tx.send(SubengineResponse::Done).unwrap(); + } + }); + + SubengineController { + tx, + rx, + handle: ManuallyDrop::new(handle), + } + } + + /// Sends a command to the [`Subengine`]. This is function is not blocking and WILL NOT check if + /// the command was received. + pub fn exec(&self, cmd: SubengineCommand) { + self.tx.send(cmd).unwrap(); + } + + /// Blocking function, waits for the [`Subengine`] to finish executing the last command given. + pub fn wait_for_exec(&self, timeout: Duration) -> Result<(),SubengineWaitError> { + match self.rx.recv_timeout(timeout) { + Err(_) => Err(SubengineWaitError::NoResponse), + Ok(val) => match val { + SubengineResponse::Done => Ok(()), + //_ => Err(SubengineWaitError::BadResponse), + }} + } +} + +//--SubengineCommand enum--------------------------------------------------------------------------- +/// Commands that can be sent to an [`Subengine`] via an `EngineController`. +#[derive(Debug)] +pub enum SubengineCommand { + Run, + Stop, +} + +//--SubengineWaitError enum------------------------------------------------------------------------- +/// Errors that can be returned by the wait_for_exec function. +#[derive(Debug)] +pub enum SubengineWaitError { + NoResponse, + BadResponse, +} + +//--SubengineResponse enum-------------------------------------------------------------------------- +#[derive(Debug)] +enum SubengineResponse { + Done, +} + +//--Tests------------------------------------------------------------------------------------------- +#[cfg(test)] +mod tests { + use super::*; + use crate::subengine::TestSubengine; + + #[test] + fn test_new_drop() { + let (test_subengine, _test_rx) = TestSubengine::new("run"); + let subengine_controller = SubengineController::new(test_subengine); + } + + #[test] + fn test_exec() { + let (test_subengine, test_rx) = TestSubengine::new("run"); + let subengine_controller = SubengineController::new(test_subengine); + + subengine_controller.exec(SubengineCommand::Run); + let response = test_rx.recv_timeout(Duration::from_millis(10)).unwrap(); + assert_eq!(response, "run"); + } + + #[test] + fn test_wait_for_exec() { + let (test_subengine, _test_rx) = TestSubengine::new("run"); + let subengine_controller = SubengineController::new(test_subengine); + + subengine_controller.exec(SubengineCommand::Run); + subengine_controller.wait_for_exec(Duration::from_millis(10)).unwrap(); + } + +} diff --git a/src/subengine/subengine_pipeline.rs b/src/subengine/subengine_pipeline.rs new file mode 100644 index 0000000..dc5ad08 --- /dev/null +++ b/src/subengine/subengine_pipeline.rs @@ -0,0 +1,72 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use std::{ + cell::RefCell, + marker::PhantomData, +}; + +use gfx_backend_vulkan as vk_back; + +use crate::{ + io::{Input, Output}, + subengine::SubengineController, + renderer::Renderer, +}; + +//--SubenginePipeline Implementation---------------------------------------------------------------- +#[derive(Debug)] +pub struct SubenginePipeline<'a, I, W, O> +where + I: Input, + W: raw_window_handle::HasRawWindowHandle, + O: Output, +{ + pub inputs: Vec<&'a RefCell>, + pub subengines: Vec>, + pub renderers: Vec<(Renderer, &'a RefCell)>, + pub phantom: PhantomData, //needed because of compiler limitations +} + +impl<'a, I, W, O> SubenginePipeline<'a, I, W, O> +where + I: Input, + W: raw_window_handle::HasRawWindowHandle, + O: Output, +{ + + pub fn new(inputs: Ii, subengines: Is, renderers: Ir) + -> SubenginePipeline<'a, I, W, O> + where + Ii: IntoIterator>, + Iss: IntoIterator, + Is: IntoIterator, + Ir: IntoIterator, &'a RefCell)>, + { + let inputs_vec = inputs + .into_iter() + .map(|input| input) + .collect(); + + let subengines_vecs = subengines + .into_iter() + .map(|subengines_vec| subengines_vec + .into_iter() + .map(|subengine| subengine) + .collect()) + .collect(); + + let renderers_vec = renderers + .into_iter() + .map(|renderer| renderer) + .collect(); + + SubenginePipeline{ + inputs: inputs_vec, + subengines: subengines_vecs, + renderers: renderers_vec, + phantom: PhantomData, + } + } +} + diff --git a/src/subengine/test_subengine.rs b/src/subengine/test_subengine.rs new file mode 100644 index 0000000..ac32da6 --- /dev/null +++ b/src/subengine/test_subengine.rs @@ -0,0 +1,36 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use std::sync::mpsc::{Sender, Receiver, channel}; + +use super::*; + +//--TestSubengine Implementation-------------------------------------------------------------------- +/// [`Subengine`] implementation used for tests. +/// +/// Simply sends back the given [`str`] depending on the command. +#[derive(Debug)] +pub struct TestSubengine { + tx: Sender<&'static str>, + run: &'static str, +} + +impl TestSubengine { + /// Creates a `TestSubengine` with specific [`str`]s to use. + pub fn new(run: &'static str) + -> (TestSubengine, Receiver<&'static str>) { + + let (tx, rx) = channel(); + ( + TestSubengine { tx, run }, + rx + ) + } +} + +impl Subengine for TestSubengine { + fn run(&self) { + self.tx.send(self.run).unwrap(); + } +} + diff --git a/src/winit_window.rs b/src/winit_window.rs index c08320a..ac8b605 100644 --- a/src/winit_window.rs +++ b/src/winit_window.rs @@ -1,6 +1,11 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; +use std::{ + thread, + sync::mpsc, +}; + use winit::{ dpi::PhysicalSize, event_loop::{EventLoop}, @@ -8,8 +13,10 @@ use winit::{ }; //TODO fix that -use super::renderer::output::Output; -use crate::utils::Rect; +use crate::{ + io::{Output, Input, Key, ReadError}, + utils::Rect, +}; #[derive(Debug)] pub struct WinitWindow { @@ -17,27 +24,77 @@ pub struct WinitWindow { size: Rect, id: usize, - pub event_loop: EventLoop<()>, + handle: thread::JoinHandle<()>, + receiver: mpsc::Receiver, window: Window, } impl WinitWindow { pub fn new(title: &str, size: Rect) -> Result { + use winit::platform::unix::EventLoopExtUnix; + debug!("Creating window"); 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")?; + + //Since we can't move the EventLoop from one thread to another, we need to create it in the + //right thread and then move the Window back to the main thread instead + let cloned_name = name.clone(); + let (tx, rx) = mpsc::channel(); + let (tmp_tx, tmp_rx) = mpsc::sync_channel(1); + let handle = thread::spawn(move || { + + trace!("Creating Window in EventLoop thread"); + //winit doesn't like use creating the EventLoop in another thread either so we have to + //drop crossplatform compatibility :/ + let event_loop = EventLoop::new_any_thread(); + let window = WindowBuilder::new() + .with_inner_size(PhysicalSize {width: size.w, height: size.h}) + .with_title(cloned_name) + .build(&event_loop).unwrap(); + + trace!("Sending Window back to main thread"); + tmp_tx.send(window).unwrap(); + + //TODO clean event type + event_loop.run(move |event: winit::event::Event<'_, ()>, _, control_flow| { + use winit::{ + event_loop::ControlFlow, + event::Event, + event, + }; + + *control_flow = ControlFlow::Wait; + + //TODO manage errors + match event { + Event::WindowEvent{window_id: _, event} => match event { + event::WindowEvent::CloseRequested => { + tx.send(Key::Close).unwrap(); + warn!("Stop input thread"); + *control_flow = ControlFlow::Exit; + }, + event::WindowEvent::CursorMoved{position, ..} => { + tx.send(Key::MouseMove{ + x: position.x, + y: position.y, + }).unwrap(); + }, + _ => (), + } + _ => (), + }}) + }); + + let window = tmp_rx.recv().unwrap(); + trace!("Received Window in main thread"); Ok(Self { name, size, id, - event_loop, + handle: handle, + receiver: rx, window, }) } @@ -52,3 +109,14 @@ impl Output for WinitWindow { fn window(&self) -> &Window { &self.window } } +impl Input for WinitWindow { + fn read(&self, timeout_ms: u32) -> Result { + use std::time::Duration; + + match self.receiver.recv_timeout(Duration::from_millis(timeout_ms.into())) { + Ok(key) => Ok(key), + Err(_) => Err(ReadError::Timeout), + } + } +} + From e3fdbb142c531354eedec589e56f0fe305297f9b Mon Sep 17 00:00:00 2001 From: Steins7 Date: Mon, 18 Jan 2021 10:16:58 +0100 Subject: [PATCH 05/22] Got the Controller working * reworked iput system again + added test functions --- src/controller.rs | 16 +- src/io.rs | 56 +++--- src/{winit_window.rs => io/:} | 89 ++++++++-- src/io/winit_window.rs | 234 ++++++++++++++++++++++++++ src/lib.rs | 7 +- src/renderer/swap_system.rs | 16 +- src/renderer/swap_system/frame.rs | 24 ++- src/subengine/subengine_controller.rs | 10 +- 8 files changed, 363 insertions(+), 89 deletions(-) rename src/{winit_window.rs => io/:} (53%) create mode 100644 src/io/winit_window.rs diff --git a/src/controller.rs b/src/controller.rs index a335776..a86b41f 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -38,7 +38,7 @@ where Controller { pipelines: pipelines_vec, - color: [0.0, 1.0, 0.0, 0.0], + color: [0.0, 1.0, 1.0, 0.0], } } @@ -54,7 +54,7 @@ where for pipeline in &mut self.pipelines { for input in &pipeline.inputs { - match input.borrow().read(1) { + match input.borrow().read(Duration::from_millis(1)) { Ok(key) => input_keys.push(key), Err(_err) => (), } @@ -87,14 +87,14 @@ where } } -#[cfg(test)] +//#[cfg(test)] mod tests { use super::*; use std::iter; use crate::{ - winit_window::WinitWindow, + io::WinitWindow, renderer::Renderer, utils::Rect, subengine::{SubengineController, TestSubengine}, @@ -102,7 +102,7 @@ mod tests { use gfx_backend_vulkan as vk_back; - #[test] + //#[test] fn test_new() { use std::cell::RefCell; @@ -129,7 +129,7 @@ mod tests { let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers); //creating controller - let controller = Controller::new(vec![subengine_pipeline]); + let _controller = Controller::new(vec![subengine_pipeline]); } #[test] @@ -160,7 +160,9 @@ mod tests { //running controller let mut controller = Controller::new(vec![subengine_pipeline]); - controller.run(); + for _i in 0..10 { + controller.run(); + } } } diff --git a/src/io.rs b/src/io.rs index 9dd067a..5423d86 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,10 +1,16 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; +use std::time::Duration; + use raw_window_handle::HasRawWindowHandle; use crate::utils::Rect; +pub mod winit_window; +pub use self::winit_window::WinitWindow; + + //--Output trait------------------------------------------------------------------------------------ /// A trait for the ability of a type to be used as an output by the engine. /// @@ -36,33 +42,7 @@ where fn window(&self) -> &W; } -//impl<'a, W, O> Output for &'a mut O -//where -// W: HasRawWindowHandle, -// O: Output, -//{ -// 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 { Output::size(*self) } -// -// fn window(&self) -> &W { Output::window(*self) } -//} - -//impl<'a, W, O> Output for Box -//where -// W: HasRawWindowHandle, -// O: Output, -//{ -// 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 { Output::size(self) } -// -// fn window(&self) -> &W { Output::window(self) } -//} - -//--Input trait------------------------------------------------------------------------------------ +//--Input trait------------------------------------------------------------------------------------- /// A trait for the ability of a type to be used as an input by the engine /// /// The `Input` trait defines functions used by different components of the engine. The allow to @@ -75,23 +55,29 @@ pub trait Input { /// Return the next input available or a ReadError if an error occured of the timeout duration /// was reached. How inputs are handled depends on the implementation. //TODO change timeout - fn read(&self, timeout_ms: u32) -> Result; + fn read(&self, timeout: Duration) -> Result; + + fn write(&self, signal: Signal); } -//impl<'a, I> Input for &'a mut I -//where -// I: Input, -//{ -// fn read(&self, timeout_ms: u32) -> Result { Input::read(*self, timeout_ms) } -//} - //--Key enum---------------------------------------------------------------------------------------- +#[derive(Debug)] pub enum Key { Close, + Closed, + Test, MouseMove { x: f64, y: f64 }, } +//--Signal enum------------------------------------------------------------------------------------- +#[derive(Debug)] +pub enum Signal { + Exit, + Test, +} + //--ReadError enum---------------------------------------------------------------------------------- +#[derive(Debug)] pub enum ReadError { Timeout, } diff --git a/src/winit_window.rs b/src/io/: similarity index 53% rename from src/winit_window.rs rename to src/io/: index ac8b605..d0d72d7 100644 --- a/src/winit_window.rs +++ b/src/io/: @@ -4,17 +4,18 @@ use log::{debug, error, info, trace, warn}; use std::{ thread, sync::mpsc, + time::Duration, }; use winit::{ dpi::PhysicalSize, - event_loop::{EventLoop}, + event_loop::{EventLoop, EventLoopProxy}, window::{WindowBuilder, Window}, }; //TODO fix that use crate::{ - io::{Output, Input, Key, ReadError}, + io::{Output, Input, Key, Signal, ReadError}, utils::Rect, }; @@ -24,9 +25,24 @@ pub struct WinitWindow { size: Rect, id: usize, - handle: thread::JoinHandle<()>, receiver: mpsc::Receiver, window: Window, + event_loop_proxy: EventLoopProxy, +} + +impl Drop for WinitWindow { + fn drop(&mut self) { + use winit::event::Event; + + // kill event_loop + if self.event_loop_proxy.send_event(Signal::Exit).is_err() { + warn!("EventLoop thread is dead before Exit signal"); + } + //while match self.read(Duration::from_millis(1)) { + // Ok(Key::Closed) => false, + // _ => true, + //} {} + } } impl WinitWindow { @@ -42,22 +58,24 @@ impl WinitWindow { let cloned_name = name.clone(); let (tx, rx) = mpsc::channel(); let (tmp_tx, tmp_rx) = mpsc::sync_channel(1); - let handle = thread::spawn(move || { + let builder = thread::Builder::new().name(title); + //the EventLoop hijacks the thread so there is no need to join it later... + thread::spawn(move || { trace!("Creating Window in EventLoop thread"); - //winit doesn't like use creating the EventLoop in another thread either so we have to + //winit doesn't like us creating the EventLoop in another thread either so we have to //drop crossplatform compatibility :/ let event_loop = EventLoop::new_any_thread(); let window = WindowBuilder::new() .with_inner_size(PhysicalSize {width: size.w, height: size.h}) .with_title(cloned_name) .build(&event_loop).unwrap(); + let event_loop_proxy = event_loop.create_proxy(); trace!("Sending Window back to main thread"); - tmp_tx.send(window).unwrap(); + tmp_tx.send((window, event_loop_proxy)).unwrap(); - //TODO clean event type - event_loop.run(move |event: winit::event::Event<'_, ()>, _, control_flow| { + event_loop.run(move |event: winit::event::Event<'_, Signal>, _, control_flow| { use winit::{ event_loop::ControlFlow, event::Event, @@ -66,13 +84,15 @@ impl WinitWindow { *control_flow = ControlFlow::Wait; - //TODO manage errors match event { + Event::LoopDestroyed => { + tx.send(Key::Closed).unwrap(); + debug!("Closed EventLoop"); + }, Event::WindowEvent{window_id: _, event} => match event { event::WindowEvent::CloseRequested => { + debug!("Close requested"); tx.send(Key::Close).unwrap(); - warn!("Stop input thread"); - *control_flow = ControlFlow::Exit; }, event::WindowEvent::CursorMoved{position, ..} => { tx.send(Key::MouseMove{ @@ -81,21 +101,30 @@ impl WinitWindow { }).unwrap(); }, _ => (), - } + }, + Event::UserEvent(signal) => match signal { + Signal::Exit => { + debug!("Stopping input thread..."); + *control_flow = ControlFlow::Exit; + }, + Signal::Test => { + tx.send(Key::Test).unwrap(); + }, + }, _ => (), }}) }); - let window = tmp_rx.recv().unwrap(); + let (window, event_loop_proxy) = tmp_rx.recv().unwrap(); trace!("Received Window in main thread"); Ok(Self { name, size, id, - handle: handle, receiver: rx, window, + event_loop_proxy, }) } } @@ -110,13 +139,39 @@ impl Output for WinitWindow { } impl Input for WinitWindow { - fn read(&self, timeout_ms: u32) -> Result { - use std::time::Duration; + fn read(&self, timeout: Duration) -> Result { - match self.receiver.recv_timeout(Duration::from_millis(timeout_ms.into())) { + match self.receiver.recv_timeout(timeout) { Ok(key) => Ok(key), Err(_) => Err(ReadError::Timeout), } } + + fn write(&self, signal: Signal) { + + self.event_loop_proxy.send_event(signal) + .map_err(|_| "Could not send Signal to EventLoop").unwrap(); + } } +#[cfg(test)] +mod tests { + use super::*; + + use crate::utils::Rect; + + #[test] + fn test_new_drop() { + let _window1 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); + let _window2 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); + panic!("test"); + } + + #[test] + fn test_read_write() { + let window = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); + window.write(Signal::Test); + let input = window.read(Duration::from_millis(1)).unwrap(); + assert!(matches!(input, Key::Test)); + } +} diff --git a/src/io/winit_window.rs b/src/io/winit_window.rs new file mode 100644 index 0000000..f45b121 --- /dev/null +++ b/src/io/winit_window.rs @@ -0,0 +1,234 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use std::{ + thread, + sync::mpsc, + time::Duration, +}; + +use winit::{ + dpi::PhysicalSize, + event_loop::{EventLoop, EventLoopProxy}, + window::{WindowBuilder, Window}, +}; + +//TODO fix that +use crate::{ + io::{Output, Input, Key, Signal, ReadError}, + utils::Rect, +}; + +#[derive(Debug)] +pub struct WinitWindow { + pub name: String, + size: Rect, + id: usize, + + receiver: mpsc::Receiver, + window: Window, + event_loop_proxy: EventLoopProxy, +} +// +//impl Drop for WinitWindow { +// fn drop(&mut self) { +// use winit::event::Event; +// +// // kill event_loop +// if self.event_loop_proxy.send_event(Signal::Exit).is_err() { +// warn!("EventLoop thread is dead before Exit signal"); +// } +// while match self.read(Duration::from_millis(1)) { +// Ok(Key::Closed) => false, +// Err(err) => match err { +// ReadError::Timeout => false, +// _ => true, +// }, +// _ => true, +// } {} +// debug!("Dropped !"); +// } +//} + +impl WinitWindow { + fn drop(&mut self) { + use winit::event::Event; + + // kill event_loop + debug!("Sending kill signal..."); + if self.event_loop_proxy.send_event(Signal::Exit).is_err() { + warn!("EventLoop thread is dead before Exit signal"); + } + debug!("Kill signal sent"); + while match self.read(Duration::from_millis(1)) { + Ok(Key::Closed) => false, + Err(err) => match err { + ReadError::Timeout => false, + _ => true, + }, + _ => true, + } {} + debug!("Dropped !"); + } + + pub fn new(title: &str, size: Rect) -> Result { + use winit::platform::unix::EventLoopExtUnix; + + debug!("Creating window"); + let name = title.to_string(); + let id = 0; + + //Since we can't move the EventLoop from one thread to another, we need to create it in the + //right thread and then move the Window back to the main thread instead + let cloned_name = name.clone(); + let (tx, rx) = mpsc::channel(); + let (tmp_tx, tmp_rx) = mpsc::sync_channel(1); + let builder = thread::Builder::new().name(title.into()); + //the EventLoop hijacks the thread so there is no need to join it later... + builder.spawn(move || { + + trace!("Creating Window in EventLoop thread"); + //winit doesn't like us creating the EventLoop in another thread either so we have to + //drop crossplatform compatibility :/ + let event_loop = EventLoop::new_any_thread(); + let window = WindowBuilder::new() + .with_inner_size(PhysicalSize {width: size.w, height: size.h}) + .with_title(cloned_name) + .build(&event_loop).unwrap(); + let event_loop_proxy = event_loop.create_proxy(); + + trace!("Sending Window back to main thread"); + tmp_tx.send((window, event_loop_proxy)).unwrap(); + + event_loop.run(move |event: winit::event::Event<'_, Signal>, _, control_flow| { + use winit::{ + event_loop::ControlFlow, + event::Event, + event, + }; + + *control_flow = ControlFlow::Wait; + + match event { + Event::LoopDestroyed => { + tx.send(Key::Closed).unwrap(); + debug!("Closed EventLoop"); + return; + }, + Event::WindowEvent{window_id: _, event} => match event { + event::WindowEvent::CloseRequested => { + debug!("Close requested"); + tx.send(Key::Close).unwrap(); + }, + event::WindowEvent::CursorMoved{position, ..} => { + tx.send(Key::MouseMove{ + x: position.x, + y: position.y, + }).unwrap(); + }, + _ => (), + }, + Event::UserEvent(signal) => match signal { + Signal::Exit => { + debug!("Stopping input thread..."); + *control_flow = ControlFlow::Exit; + }, + Signal::Test => { + tx.send(Key::Test).unwrap(); + }, + }, + _ => (), + }}) + }); + + let (window, event_loop_proxy) = tmp_rx.recv().unwrap(); + trace!("Received Window in main thread"); + + Ok(Self { + name, + size, + id, + receiver: rx, + window, + event_loop_proxy, + }) + } +} + +impl Output 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 { &mut self.size } + + fn window(&self) -> &Window { &self.window } +} + +impl Input for WinitWindow { + fn read(&self, timeout: Duration) -> Result { + + match self.receiver.recv_timeout(timeout) { + Ok(key) => Ok(key), + Err(_) => Err(ReadError::Timeout), + } + } + + fn write(&self, signal: Signal) { + + self.event_loop_proxy.send_event(signal) + .map_err(|_| "Could not send Signal to EventLoop").unwrap(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::utils::Rect; + + 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(move |out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + chrono::Local::now().format("[%H:%M:%S]"), + colors.color(record.level()), + record.target(), + message + )) + }) + .level(log::LevelFilter::Trace) + .chain(std::io::stdout()) + .chain(fern::log_file("output.log")?) + .apply()?; + Ok(()) + } + + //#[test] + fn test_new_drop() { + let _ = setup_logger(); + let mut window1 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); + let mut window2 = WinitWindow::new("IV 2", Rect {w: 1280, h: 720}).unwrap(); + + window1.drop(); + window2.drop(); + + panic!("test"); + } + + //#[test] + fn test_read_write() { + let window = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); + window.write(Signal::Test); + let input = window.read(Duration::from_millis(1)).unwrap(); + assert!(matches!(input, Key::Test)); + } +} diff --git a/src/lib.rs b/src/lib.rs index d97c6b0..52380b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,6 @@ use controller::Controller; pub mod utils; //use utils::Rect; -mod winit_window; -//use winit_window::WinitWindow; - mod renderer; //use renderer::Renderer; @@ -63,7 +60,7 @@ pub fn run() -> Result<(), &'static str> { }; use crate::{ - winit_window::WinitWindow, + io::WinitWindow, renderer::Renderer, utils::Rect, subengine::{SubengineController, TestSubengine}, @@ -112,7 +109,7 @@ pub fn run() -> Result<(), &'static str> { //let controller = Controller::new(renderers, &windows, &windows, engine_pipelines); //controller.run(); - Ok(()) + //Ok(()) //let local_state = LocalState::default(); // let color = [0.5, 0.0, 0.0, 1.0]; diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index 8a251d2..b2ae707 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -197,6 +197,8 @@ where }}, Err(err) => return Err(err), }}; + //println!("Frame nb : {}", self.frames.len()); + //frames number diminish sometimes at resize... let mut frame = self.frames.pop_back().unwrap(); trace!("Creating Framebuffer..."); @@ -211,19 +213,16 @@ where .unwrap() //TODO improve that }; - frame.link_swapchain_image(image, framebuffer); + frame.link_swapchain_image(gpu, image, framebuffer); Ok(frame) } pub fn present_frame(&mut self, mut frame: Frame, gpu: &mut Gpu) -> Result<(), &'static str> { - use gfx_hal::{ - queue::CommandQueue, - device::Device, - }; + use gfx_hal::queue::CommandQueue; - let (image, framebuffer) = frame + let image = frame .unlink_swapchain_image() .unwrap(); //TODO improve that @@ -236,11 +235,6 @@ where self.frames.push_front(frame); - trace!("Destroying Framebuffer..."); - unsafe { - gpu.device().destroy_framebuffer(framebuffer); - } - Ok(()) } } diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index 24ad72d..e582dcb 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -98,22 +98,28 @@ where } pub fn link_swapchain_image(&mut self, + gpu: &Gpu, image: >::SwapchainImage, framebuffer: B::Framebuffer) { - + use gfx_hal::device::Device; + + match self.framebuffer.replace(framebuffer) { + Some(old_framebuffer) => { + trace!("Destroying Framebuffer..."); + unsafe { gpu.device().destroy_framebuffer(old_framebuffer) }; + }, + None => (), + } + self.image_view = Some(image); - self.framebuffer = Some(framebuffer); } pub fn unlink_swapchain_image(&mut self) - -> Result<(>::SwapchainImage, - B::Framebuffer), &'static str> { + -> Result<>::SwapchainImage, &'static str> { - match (self.image_view.take(), self.framebuffer.take()) { - (Some(image_view), Some(framebuffer)) => Some((image_view, framebuffer)), - _ => None, - } - .ok_or("Can not unlink non-linked Frame !") + self.image_view + .take() + .ok_or("Can not unlink non-linked Frame !") } } diff --git a/src/subengine/subengine_controller.rs b/src/subengine/subengine_controller.rs index 94cef97..a2d4469 100644 --- a/src/subengine/subengine_controller.rs +++ b/src/subengine/subengine_controller.rs @@ -107,18 +107,18 @@ enum SubengineResponse { } //--Tests------------------------------------------------------------------------------------------- -#[cfg(test)] +//#[cfg(test)] mod tests { use super::*; use crate::subengine::TestSubengine; - #[test] + //#[test] fn test_new_drop() { let (test_subengine, _test_rx) = TestSubengine::new("run"); - let subengine_controller = SubengineController::new(test_subengine); + let _subengine_controller = SubengineController::new(test_subengine); } - #[test] + //#[test] fn test_exec() { let (test_subengine, test_rx) = TestSubengine::new("run"); let subengine_controller = SubengineController::new(test_subengine); @@ -128,7 +128,7 @@ mod tests { assert_eq!(response, "run"); } - #[test] + //#[test] fn test_wait_for_exec() { let (test_subengine, _test_rx) = TestSubengine::new("run"); let subengine_controller = SubengineController::new(test_subengine); From 64624dca20ee1638b68555be95ab337afb0ab8dd Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 19 Jan 2021 11:30:52 +0100 Subject: [PATCH 06/22] Temporarily fixed tests * reenabled SubengineController tests * fixed WinitWindow drop function - disabled all tests involving winit --- src/controller.rs | 9 +++-- src/io/winit_window.rs | 57 +++++++++++---------------- src/subengine/subengine_controller.rs | 8 ++-- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index a86b41f..481594b 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -66,6 +66,7 @@ where (y/720.0) as f32, ((x/1280.0 + y/720.0)/2.0) as f32, 1.0], + Key::Close => return, _ => (), }; } @@ -86,8 +87,10 @@ where } } } - -//#[cfg(test)] +//These tests are disabled because of some stange issue with cargo not waiting for the drop +//functions to execute before executing the next test or something like that... +#[cfg(test)] +#[allow(dead_code)] mod tests { use super::*; @@ -132,7 +135,7 @@ mod tests { let _controller = Controller::new(vec![subengine_pipeline]); } - #[test] + //#[test] fn test_run() { use std::cell::RefCell; diff --git a/src/io/winit_window.rs b/src/io/winit_window.rs index f45b121..b94c356 100644 --- a/src/io/winit_window.rs +++ b/src/io/winit_window.rs @@ -29,48 +29,29 @@ pub struct WinitWindow { window: Window, event_loop_proxy: EventLoopProxy, } -// -//impl Drop for WinitWindow { -// fn drop(&mut self) { -// use winit::event::Event; -// -// // kill event_loop -// if self.event_loop_proxy.send_event(Signal::Exit).is_err() { -// warn!("EventLoop thread is dead before Exit signal"); -// } -// while match self.read(Duration::from_millis(1)) { -// Ok(Key::Closed) => false, -// Err(err) => match err { -// ReadError::Timeout => false, -// _ => true, -// }, -// _ => true, -// } {} -// debug!("Dropped !"); -// } -//} -impl WinitWindow { +impl Drop for WinitWindow { fn drop(&mut self) { - use winit::event::Event; // kill event_loop debug!("Sending kill signal..."); if self.event_loop_proxy.send_event(Signal::Exit).is_err() { warn!("EventLoop thread is dead before Exit signal"); } - debug!("Kill signal sent"); + trace!("Kill signal sent"); while match self.read(Duration::from_millis(1)) { Ok(Key::Closed) => false, Err(err) => match err { ReadError::Timeout => false, - _ => true, + //_ => true, }, _ => true, } {} - debug!("Dropped !"); + trace!("Dropped !"); } +} +impl WinitWindow { pub fn new(title: &str, size: Rect) -> Result { use winit::platform::unix::EventLoopExtUnix; @@ -85,7 +66,8 @@ impl WinitWindow { let (tmp_tx, tmp_rx) = mpsc::sync_channel(1); let builder = thread::Builder::new().name(title.into()); //the EventLoop hijacks the thread so there is no need to join it later... - builder.spawn(move || { + //TODO manage errors here + let _ = builder.spawn(move || { trace!("Creating Window in EventLoop thread"); //winit doesn't like us creating the EventLoop in another thread either so we have to @@ -111,14 +93,14 @@ impl WinitWindow { match event { Event::LoopDestroyed => { - tx.send(Key::Closed).unwrap(); + let _ = tx.send(Key::Closed).unwrap(); debug!("Closed EventLoop"); return; }, Event::WindowEvent{window_id: _, event} => match event { event::WindowEvent::CloseRequested => { debug!("Close requested"); - tx.send(Key::Close).unwrap(); + let _ = tx.send(Key::Close).unwrap(); }, event::WindowEvent::CursorMoved{position, ..} => { tx.send(Key::MouseMove{ @@ -180,7 +162,10 @@ impl Input for WinitWindow { } } +//These tests are disabled for now because they cause some sort of bug with cargo where it doesn't +//take into account other failed tests, even inn single threaded tests. No idea what's going on... #[cfg(test)] +#[allow(dead_code)] mod tests { use super::*; @@ -214,14 +199,16 @@ mod tests { //#[test] fn test_new_drop() { - let _ = setup_logger(); - let mut window1 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap(); - let mut window2 = WinitWindow::new("IV 2", Rect {w: 1280, h: 720}).unwrap(); + use std::mem::ManuallyDrop; - window1.drop(); - window2.drop(); - - panic!("test"); + let _ = setup_logger(); + let mut window1 = ManuallyDrop::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap()); + let mut window2 = ManuallyDrop::new(WinitWindow::new("IV 2", Rect {w: 1280, h: 720}).unwrap()); + + unsafe { + ManuallyDrop::drop(&mut window1); + ManuallyDrop::drop(&mut window2); + } } //#[test] diff --git a/src/subengine/subengine_controller.rs b/src/subengine/subengine_controller.rs index a2d4469..d84e87f 100644 --- a/src/subengine/subengine_controller.rs +++ b/src/subengine/subengine_controller.rs @@ -107,18 +107,18 @@ enum SubengineResponse { } //--Tests------------------------------------------------------------------------------------------- -//#[cfg(test)] +#[cfg(test)] mod tests { use super::*; use crate::subengine::TestSubengine; - //#[test] + #[test] fn test_new_drop() { let (test_subengine, _test_rx) = TestSubengine::new("run"); let _subengine_controller = SubengineController::new(test_subengine); } - //#[test] + #[test] fn test_exec() { let (test_subengine, test_rx) = TestSubengine::new("run"); let subengine_controller = SubengineController::new(test_subengine); @@ -128,7 +128,7 @@ mod tests { assert_eq!(response, "run"); } - //#[test] + #[test] fn test_wait_for_exec() { let (test_subengine, _test_rx) = TestSubengine::new("run"); let subengine_controller = SubengineController::new(test_subengine); From dd1d214a4adcf95c4192d86ad65f91e275685317 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 30 Jan 2021 12:05:48 +0100 Subject: [PATCH 07/22] Started implementing triangle pipeline + Pipeline new() and drop() + Attachement new(() and drop() + draw_triangle_frame ! crashes at pipeline creation --- Cargo.lock | 30 +++ Cargo.toml | 1 + doc/architecture | 2 +- src/controller.rs | 33 ++- src/renderer.rs | 120 ++++++++++- src/renderer/pipeline.rs | 295 ++++++++++++++++++++++++++- src/renderer/pipeline/attachement.rs | 135 ++++++++++++ src/renderer/swap_system.rs | 4 +- src/subengine/subengine_pipeline.rs | 2 +- src/utils.rs | 13 ++ 10 files changed, 611 insertions(+), 24 deletions(-) create mode 100644 src/renderer/pipeline/attachement.rs diff --git a/Cargo.lock b/Cargo.lock index bb14223..2764364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -122,6 +122,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cmake" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +dependencies = [ + "cc", +] + [[package]] name = "cocoa" version = "0.20.2" @@ -362,6 +371,7 @@ dependencies = [ "log", "num-traits", "raw-window-handle", + "shaderc", "winit", ] @@ -755,6 +765,26 @@ version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +[[package]] +name = "shaderc" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f0cb8d1f8667fc9c50d5054be830a117af5f9a15f87c66b72bbca0c2fca484" +dependencies = [ + "libc", + "shaderc-sys", +] + +[[package]] +name = "shaderc-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89175f80244b82f882033a81bd188f87307c4c39b2fe8d0f194314f270bdea9" +dependencies = [ + "cmake", + "libc", +] + [[package]] name = "slab" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index cd009fc..b0f5b39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ gfx-hal = "^0.6.0" winit = "^0.22.0" raw-window-handle = "^0.3.3" num-traits = "^0.2.12" +shaderc = "^0.7" [dependencies.gfx-backend-vulkan] version = "^0.6.1" diff --git a/doc/architecture b/doc/architecture index 4990374..e6d4f7c 100644 --- a/doc/architecture +++ b/doc/architecture @@ -1 +1 @@ -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 \ No newline at end of file +7Vhdb9owFP01kbYHpiSGQB8LtHQaXVuoVLGXyU1MYuHYmWMK9NfvOnYI4aOl1dBekJCIj69vcu85PjE4qJcuBxJnya2ICHN8N1o6qO/4vt9qt+FLIyuDdDxkgFjSyEBeBYzpK7Gga9E5jUheC1RCMEWzOhgKzkmoahiWUizqYVPB6nfNcEx2gHGI2S76RCOVWNQLLqqJG0LjxN6649uCU1wG20ryBEdisQGhKwf1pBDKXKXLHmG6eWVf8mzwM7id/Pn1kA7xJG+7L+OHhkl2/ZEl6xIk4erTqbu/r69Xs7tBn08uHh+ay8twNrFL3BfM5rZfI02CqVetyibmC5oyzGHUnQquxnbGgzFmNOZwHcKzEQnAC5GKQv8v7YQSGaBhQlk0xCsx1xXkCoezctRNhKSvkBYzmxOmpbJS8oNaxFivBNgFVJIcYu7Ltnhb0C1e1gKHOFcWCAVjOMvp87qMFMuY8q5QSqQ26MiuW3Z02WS5oTnLwoCIlCi5ghA720ClouyW8pt2vNgQaGCxZEObQcfuC7sn4nXuine4sNR/QAbejgwcv1s90KVejwALHB95pjfdjWdbz2/JBhqiCjqlmJGeYAL00efC6IgytgWVUmJkqg4KKc9wSHk8LGL6zQoZ2T5pSMDaKSs2a0KjiHAtAqGwwoZxXUImKFdFI1td+EC7e+63ltOCB+/B2KvG8NHhUvUEh1owLfRAQE4LoiW1Rylvbrb3lVIKIzhOF6h5Il34e3SxxTGjBXeG49JhvU8RnAJVjFSMPmrC+w1vh3W0yzrawzDDz4Tdi5wqKnR+aWK3mP9f5AZHbvpT7Xm0w+3dXGXzs/mf1vw7nffNH+3VgX8iIbQOmD+NvoDj41QzmGpduEYgX43hb83tez/oxn8khzl7BEzrwuSLzQ7cyrugHE5iVeaDadfJ0ky34QbnI7x4KlbfYK7NZn2L86vrLXdDR+v88Ktrr6pbwYlU3dlR9Xd+dreTu1v7ouZuqHWku5XYvz/aHjrbSoI3DM6KA+7hzpH/Fb4alTeAMeVztramH2RlIkeQ4gp+o8qzjRxnI52jBfVBG/nECRiG1W/3Ym7jHxB09Rc=7V1rc5u4Gv41nuk5M/GYq83HxGmy3e2eZpvO9vLFo4Bs0wBiQcTJ/vojIQkQCEJiSDddOp00vOiGnlePHr0SdGasw/vLBMT735EHg5m+8O5nxvlM13XD1Mk/1PLALPZyxQy7xPeYSSsN1/7fkBsX3Jr5HkylhBihAPuxbHRRFEEXSzaQJOggJ9uiQK41BjvYMFy7IGhaP/se3nOrZjvljV+gv9vzqlf6kt0IgUjMnyTdAw8dKibj7cxYJwhh9lt4v4YB7TzRLyzfRcvdomEJjHCfDL/+9lt0+ufX7+cb9wu81bG33e9OeCl3IMj4A1/GGW8vfhCdkB78MAARuTrboghf8zsauQaBv4vI7y5pBUyI4Q4m2Cf9d8pvYBQTq7v3A+89eEAZbWuKgXsrrs72KPH/JsWCgJdJbieYu4JuSymuaU5iXhBrAlOS5kp0gFYz/Q7upYTvQYq5wUVBAOLUvykeIwTJzo/OEMYo5Ima/Ss6izwhvK+YeH9fQhRCnDyQJPzuiW5y8Ln3Wza/PpS+ZK64bV9xoyIj4P67KwovISa/cJSfgLjeQPyEVuOBmOJHfMg4JT9PxbU90w2NdgdN5cE734VFonN+KaX5K4MZ3OwSlMVFwj+o7TI3WWfafP7fmXVey+aiMASRt4nJ4C7yrZnxKrfVfJJAgHNfSdAtXKMAEec7jxBzUj8IaibhpwHc4lYvTWPg+tHufZ7m3CwtHzky1IRI3m2Qj+S973kwoh6GMMCAuRN9ohj5Ec6Rs87IX4LlejG38qde0y4or8lfmjzBaxSRZwF+7myQ+OoBUn9VuGHnQH7cN7kr0u7v44m2OZIjGg1HbGAc+Dl2DGNBv9qzAA4JVAEsEf1EAT8/0RqoG03UDQXCAbiBwRVKfewjWn7C0taQ/1HgOj1pZjUStqYCW/KwiwgeyM83ZOyDkA64d6RbQEQ5ZD1b67PTRXHnQ4ZjMjsUdPGfghQ+wjQLMEkY0B58k89XpJWL6yzZApdohWqe9Rvyw96xvi4IhzXGS1AstSYkFeoLUmBZWZ69zFYrIYFuAgGGm/QA4k36kGIYqkvkTSTJrvNUlRokY3tdnKHLsqV2FtYmcfOHzbn6sdwNRmeZq+S8Ic/0WDHssSX2rpXIZgmpqErvc1foLDafU6ZZYWjiWPUjDk3o+mOoY4U/fL+5QF//+IT+Z3ngnet8+3aiNQXKRQLCJtSTKH2eKDVrmnRlNieLQqdKmlQbQJOqMVdpAUoTB+DjTQpDsrREpMMKSrgWJmohg8m4kBUly50SsAGt/NklbGHkVjJdwMjtziCY8ibbbitymnPWGbdKytcPyRJyc+fnUyNL/iHOVQWf4ugE4e4JB7yjKVunsy0dJbV65YIuqilEKROB4i7P1HsPr3ZdrRxNzgC6Wt1klfiahPVA8Gp6T7YcQFqrm2z11NY17VnYL1ASAlwzfoSRB5MrkKa1G2/vMelCvVV/87n5GTpb5GwqvCcocOLIt7n6zgly4zOG7KqrzqZrcZsRY2vFtLYsaqlPVV3riqXWAiF25UZIHTpx9NCDuClz1YN4NJVrN0ZxuQ6cpO5Y8VeV1h0v/qpGftlAnqrAlEUvSn0qriWtuGXczcQo53EpAczpmiXIqdvTmyI1ycl+Q3oWCIJycVuqmM4JPFU5R8itosy1iW5YsoyCPXHWI5xl9/blJ8Zrx9OVq0lXjgevSleOFbJVN9k5UldyxmqTPdXpbS3k1ZMEY70EZRT5GDHpomjr77IEbirc196KVoHXEXeuB3XdvzKf1Ldl+rTjkcvKuJatlRSTSZb4ZI+SKpJX2WF5YLX3s000PzQP9I3ACtk7OBMUBxZKWKG3g0J1kl7Zox2KQPC2tJK+zsiQ8XhPl2neo5y3KW1/hxg/cFkJMoyosMShEJ3w3sdfKr9/pUURNNjVudCS+cWDuIjI836pXrBcpr0ShjJjfiXlvIKJT7qMyuZuxZmiLHFhD1FHhPMOdjoEj3TSDu10hwQGAPt38ikUFdQ86xX17VL5alZN+C5rsoC1lOcqHeY0ScBDJRkfMq311AW2oy1q/sdKLL2xeMYjHLR5aqWQoWkbJVVc7dE1U6E98pVLK4OcC1lxRhZFu3wECH4j5LzN//TnCjHsGlxRHG7iDZlVzw+plj2LuaOb3COP9KMT05iLgCKH+MSZO45cDtpuU4hndeIZAurmbhDpehYyd0mH45y9J8QJ4gKUB6mgY/G3jPlSlwvW5gv9xfBvrpav/Bjm64wpSjJSlERTLUaKRJIIsccKk+jN1Wa+WUaGRcKEaX7g1HfTVn+YtKh6KB0TclB6gTFWyEFXrUmnkMNA8CrOoirhHSviYCwU6FYiDuUatBzi/SIFZfqBAgITtwzufM1lrtL5nLFWuYK0Kt7HAtz0cMSkLIZRFo4tK4ve59/HExZGc/+cCQsRQ+TMUAYVp6HfNfSLcTT4ToZIN7wLNDdfJ1kxGLyW3g/e0WRFc8mo3sj47Ef0hazKGykKtdB1Dl3MFv1EiUjfV3x4CTi0hvPLylvb/JztiaJeN4AgOaZ2disfKEc1BCc+iHbBUa34xMt4TkMm8h+WHXoLgMVoAmDVQPWVbW9Ys+7NjVw/ntKXX0tPzG0XPu0qnsMTKdwApKnvMiNPonUJwEe3Q4TGqm6HdL2MONxuyFGeYar3FXaKN2JfS4hZOPsQIWbbFFO72Angm1lHxpgtuVCtJvvGCy6Ld1jkzQXtNW8pDIn30rKcGjTH4S2mgJfC13Ampv8BTN+5Q/5PofrmG0f5KczyPc7Xu5Es3H4IDljZujEoBxR7Tnat2Noewoisr3g/prIGnECfryyxwXskyksJ4+WLIfzqDzD9PLwvwjz/FN5XR39jvmH0eklf+PwwpO/I7GwOwga1xcOLnSEyFeHe10/4QwLuaE5tlh9mZSe+AyK70aCIx1++mTfm50vndn91ffvt5s/YWp8sf3b+V3Lq85hcEHSVyZWdar4QbysrV58GYr7PX7Zvcjftn/d0wI03np84BmWI2n23KwpTD8IMI8h1e27bTuXPqlaL/lKDV3HmxzpbtLD1Twnx0rFrGA8jx635Sqb5+gc9xgO1udw+xRi4exhCfgB9Om/R5mcNVm91nfqnXZQHOQ3Vi86DnLdonzYazH2j+hJKCEPEa/z37rk94gDto+sp5y2UPjDEMU5l81RfrKhh/C85bjE8uIr9VCW4A5y2ULZOdZSm863RchNemgH6naGQshx3tvOQ+Fh1qqBRhUe8YXod8gd5d/OUqNK7hzglqmyeUEjV73RkN/k3ESbRMpJoMVRvn4x2RkQNu/okQEqL35OhNg30Jw90rSUI1fGuiQrz0USK4ruTk0oZDF7VuyYjHQpVN6+5AJ0G83hoK17uUA7m0aZtswHqFAGeHRsB1l5q605du3rrLmVyTLF19ypjg1pLmL2yOW/XgnizIWKDta2aF4z3Kj6F17E995OCurSGQVGTXWMAEMll+X/UsOTl//RjvP0/7Vpdb9owFP01PK5K7CSEx5bSrlKrVWXT2qfJJCbxFmzmmEL26+cQmyQEUWhhMWhP2MfXjn3v8fEXHdifLG45msYPLMRJB1jhogOvOwDYjuXLnxzJCsS3YQFEnITKqASG5A9WoKXQGQlxWjMUjCWCTOtgwCjFgahhiHM2r5uNWVL/6hRFuAEMA5Q00e8kFLFCba9XFnzGJIrVp33QLQomSBurkaQxCtm8AsFBB/Y5Y6JITRZ9nOTO0355eswWX4d3zn1If6NvPybofjT/VDR2s0+V1RA4puKwTevBvqJkphw2oBGhMmLAS+THrkZcpqI8dUxk6V+R6aBxNqMhzjtuyeJ5TAQeTlGQl84lTSUWi0kic/aq9pveUV58xVzgRYUbylu3mE2w4Jk00aW+CrxiPuip/LzkkesoLK5QyLYUiBR3o1XbZXxkQoVoHybARrgavsOh5L/KMi5iFjGKkkGJXtW9W9rcMzZVPv2JhcjUZEYzweoeTwXi4jKfnBIIEpSmJNDwDUm02Vgm+yxhfNkxOPYDHBR2nP3ClZKR7zpu3pcQpfGyY/vHNWUzHuBtVFfig3iEt7anDHM/bqUJxwkS5LWuMwcPOei1EWG8IOK5kn7Jm7pwVe56oVpeZjKdoXK8z6Vhnn3RbeSZstoyp+u9k01j7G1mU9jtjSxT2AR8s9jU0I8nLJnCMTdTg91eXYOdblODbbBBg72jSXDThV9mYjoT6Wl40LNb96B/eopW1bOKvB1U0UIX+6GzSdF8MIKed3gRg7uKmFkaZrXJH+sCuFUKHX9JpIziNfZY72LPMdfDXalkO2ZxqanmrW+ozyreOnKmxNtpVzu6/7XjA1yCRnGpeRbvMxkJliQf3U0XYdDXVeCIu0No3P4atiLAZ7E7POp5V9/d/vsD77Kq9BfKKgZTRmhx5FItP+ZA5djj1okN3bXb0Tfs9a1vSeWiByWxV0P5wGqk52v19lUQQbChh8l1uYCgdbmwG546MbkAZ6kXep9/KnoB99SLdXtgucfXC+3Uil48xpmkg6FyYRsnF/bJy8VbamGWDHR3VAGzdvbNR9E7au4N7/osM2APD099lnXPclEGO5+0DXu1ah61LwNBGDV0Rq6/ubS/7umA1h7+0oIwD4iiyNQHwO6aK+0Nf8KwvcO4UmbLf/MUe7byP1Fw8Bc=7VpZb+I6FP41SJ0rgRLC1keWFtphOqjM2hdkEgMekpjrmIH019/jxCabYdpp0NyRqFCJT04c29/ns+GK1ff2Q4Y2qw/UwW6lbjj7ijWo1Oum2bbgS0jCWNJqN2PBkhFHKiWCKXnGUmhI6ZY4OMgockpdTjZZoU19H9s8I0OM0V1WbUHd7Fs3aIkLgqmN3KL0K3H4Ss2rdZ3cGGGyXMlXd+rt+IaHlLKcSbBCDt2lRNZNxeozSnl85e372BWLp9ZlHpjbxr+rJuUj3B11n+6NT1417uz2NY8cpsCwz3+76+939+v14tZ58G/D+8lkbMy+qkeMn8jdyvXqU58z6rqYyVnzUC1lsCOei3xo9RagNZV3TGgjlyx9uLZhhPCk1fuJGSeAQlfe4HQDUntFXGeMQroV8wg4steq1VtRRp6hW+TKPuE245JQ9VZGYyqeBLEBUoYD0JmoxTFzog9on1Eco4BLgQ3TRJuAzA/T8BBbEr9HOaeeVHrh2kuMxLTxPsU8icUQUw9zFoKKvNuQSy+3lanau4SkDUPKVil+mkqI5MZYHrpOwIcLif8ruGAWuFCN8Eccw3fF6sL/adzKEQOmzCPAGF3jPnUpMGDg05gpxHVzIkUWFy/4UaoEG2QTfzmOdAaNRPIo10KIKDy7cKNNuSKOg30BM4UxohhTAeCGEp9Ha9XswQdWr2/UmpUmDLwPbTNpw0eoMw57AOaCSIQ4BsLssCCNhgsnN9WvuSDBB3a/CHulVzr09QL0BYxdEmEXY6wsqflbAHsAlYsTRD8JwAdVs4C6VUTd0iDsojl2JzQgnFDRP4t1c8j/KXCb9ZeB2zkTtpYGW5is4ePd1SP2HcwwC8ReqBt3/mbL5fXHLU8aNz6YRTwhGyxoELw72IO0twByWmZsMkX/bOtfJYri8mI1SiVW64Ueo1GCw5ixEX1kvc/j0bL6PNxX7SGaa4KHmCeXwOGcgcMhHlXOo1PkwUEnzYN240w8uHgPHdont8xbQgMtuCV4D+2Aj3kPYd3j3Z618Tkn4DC6uQIp8sQu9mC/KmdycQ1nZI3VeBlrynAN7z/O3fHsy27+aC/7H5+sRe/7tRpxClLsQFoum7AiK7qkPnJvEims8xaiEUeucqIzptEOFxv8B+Y8lJYdbTkVtp17yu7jPeHfUtffRVeARNwaKHMeNULZiHxFV9QZEjpFslsiZhw/ADFO+C3dSPUsmknXUUv1/ToPENAts/GJAEFVT8DVYNnfj4eqNbyZf/jaqt9zfzmZdVijKi2GWPCTXGHYRZz8zNZJdEyQj04E71MJbC6DtVo5MsUDlU/l+HQYxosoNuyuXXNmDO7ogzfww3bYmdc10YdIV3FkXIJjFiXFll9GHgdHE/n/owZgoHxID0KLZURiZZ7AFi6iPy0ZTm2cwlY/FMjkOCrpGpQuTDBqrU67no0U4tYbca+arZp6KlSierYXulgE+K2ofw7fW/P1+/vVj9HNlA/urEb3QYO6MLm12j+R/b2A3jZaWdCrJaHeqUGgmfrLMqBzBvwbHadDEBpOF8zfTO39027Kj+YcKjctcOCSe5SYezSvczbfLOYelqULT0uIT7V8KBYt48CTxKWMKMD8gm0IQd044JKhaFTqgNZSSrNha7CdK0eS70HX2VSppzrUd8wOBZd8v0mUrIoycelF9764NqNe8i552yWM5ie4UkbypWV3s4TMWjviS2Z9PnA1ZRO96SoBW0KfA/Dl3afnUXcz666/cP73pEj/3/TnlEcoOf2BFBGFKQXJ4aPxUtPIekqzfZ1mzC/1rZaVY1g8gt8OpnQU1P/it1Fl/r8hnj61tcqIpztmvZkBpqwkKgt3tX2OAFq3NhqX8lclUOcHXMWqJSdQZq1hGsczqOszEEBbHmoWCBBnUJeDH38mh9Ke/DA1gYhplVCtPVUxzPmBf7dYNKNjH6FvT6O0ROUiny5JR4EfJ7fbmw6D6OhQxmEQ7YjbRQ9xSTpKAld3GEQHbglJh3bAHQ226jBI/ne5olvIFTPwHttJ2SKvfvJ3wR0ifLagbHa6j7gEwomHwVXMvNTBk0ccbF1+KJ7Ajf7Vu6Nll+M/Qx4b78Wolcp73VkVHe/br3dx0EzO4MZBUnKS2br5Dw== \ No newline at end of file diff --git a/src/controller.rs b/src/controller.rs index 481594b..2e230e9 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -14,7 +14,7 @@ where O: Output, { pipelines: Vec>, - color: [f32; 4], + mouse_pos: [f32; 2], } impl Controller<'_, I, W, O> @@ -38,7 +38,7 @@ where Controller { pipelines: pipelines_vec, - color: [0.0, 1.0, 1.0, 0.0], + mouse_pos: [0.5, 0.5], } } @@ -48,6 +48,7 @@ where use crate::{ subengine::subengine_controller::SubengineCommand, io::Key, + utils::Triangle, }; let mut input_keys: Vec = Vec::new(); @@ -61,11 +62,10 @@ where } for input_key in &input_keys { match input_key { - Key::MouseMove{x,y} => self.color = [ - (x/1280.0) as f32, - (y/720.0) as f32, - ((x/1280.0 + y/720.0)/2.0) as f32, - 1.0], + Key::MouseMove{x,y} => self.mouse_pos = [ + (x/1280.0 * 2.0 - 1.0) as f32, + (y/720.0 * 2.0 - 1.0) as f32, + ], Key::Close => return, _ => (), }; @@ -78,13 +78,24 @@ where subengine.wait_for_exec(Duration::from_millis(1)).unwrap(); } } + + let triangle = Triangle { + points: [self.mouse_pos, [-0.5, 0.5], [-0.5, -0.5]], + }; + + debug!("Triangle : {:#?}", triangle); + for (renderer, output) in &mut pipeline.renderers { - match renderer.draw_clear_frame(output, self.color) { + // match renderer.draw_clear_frame(output, self.color) { + // Err(err) => warn!("{}", err), + // _ => (), + // } + match renderer.draw_triangle_frame(output, triangle) { Err(err) => warn!("{}", err), _ => (), - } - } - } + }; + }; + }; } } //These tests are disabled because of some stange issue with cargo not waiting for the drop diff --git a/src/renderer.rs b/src/renderer.rs index 2fc712e..74fd363 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -9,13 +9,18 @@ use std::{ use crate::{ io::Output, + utils::Triangle, + }; mod gpu; -use gpu::Gpu; +use self::gpu::Gpu; mod swap_system; -use swap_system::SwapSystem; +use self::swap_system::SwapSystem; + +mod pipeline; +use self::pipeline::Pipeline; //--Renderer implementation------------------------------------------------------------------------- #[derive(Debug)] @@ -23,6 +28,7 @@ pub struct Renderer { instance: ManuallyDrop, gpu: ManuallyDrop>, swap_systems: Vec>, + pipelines: Vec>, } impl Drop for Renderer @@ -35,16 +41,17 @@ where device::Device, }; + debug!("Dropping Pipelines..."); + for pipeline in self.pipelines.drain(..) { + pipeline.drop(&mut self.gpu); + } + debug!("Waiting for device to idle..."); let _ = self.gpu .device() .wait_idle(); info!("Dropping Renderer..."); - -// for mut pipeline in self.pipelines.drain(..) { -// } -// unsafe { for mut swap_system in self.swap_systems.drain(..) { self.instance.destroy_surface(swap_system.drop(&mut self.gpu)); @@ -79,12 +86,15 @@ where .map(|surface| SwapSystem::new(&mut gpu, surface)) .collect::, &str>>()? }; + let pipelines = vec!(Pipeline::new(&mut gpu, &swap_systems[0]) //TODO improve that + .map_err(|err| err)?); debug!("Renderer created !"); Ok( Renderer { instance: ManuallyDrop::new(instance), gpu: ManuallyDrop::new(gpu), swap_systems, + pipelines, }) } @@ -171,5 +181,103 @@ where Ok(()) } + + pub fn draw_triangle_frame(&mut self, output: &RefCell, triangle: Triangle) + -> Result<(), &'static str> + where + W: raw_window_handle::HasRawWindowHandle, + O: Output, + { + use gfx_hal::{ + window::AcquireError, + device::Device, + queue::Submission, + }; + + let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()]; + + let mut frame = match swap_system.acquire_frame(&self.gpu) { + Ok(frame) => frame, + Err(err) => match err { + AcquireError::NotReady => { + return Err("Frame acquisition failed because all Frames are in use"); + }, + AcquireError::OutOfDate => { + swap_system.recreate(&mut self.gpu)?; + debug!("SwapSystem : {:#?}", swap_system); + return Ok(()); + }, + _ => Err("Could not acquire Frame from SwapSystem")?, + }}; + + trace!("Waiting for Frame..."); + unsafe { + let _ = self.gpu.device() + .wait_for_fence(&frame.fences[0], !0) + .map_err(|_| "Failed to wait for Fence")?; + let _ = self.gpu.device() + .reset_fence(&frame.fences[0]) + .map_err(|_| "Failed to reset fence")?; + } + + trace!("Uploading triangle data..."); + let points = triangle.points_flat(); + self.pipelines[0].write_vertex_buffer(&self.gpu, 0, (&points).to_vec())?; //TODO meh + + trace!("Recording CommandBuffer..."); + unsafe { + use gfx_hal::command::{ + CommandBufferFlags, + SubpassContents, + ClearValue, + ClearColor, + CommandBuffer, + }; + + frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); + + const TRIANGLE_CLEAR: ClearValue = + ClearValue {color : ClearColor{float32 : [0.1, 0.2, 0.3, 1.0]}}; + + frame.command_buffer.begin_render_pass( + &swap_system.render_pass, + &frame.framebuffer.as_ref().unwrap(), + swap_system.render_area, + iter::once(TRIANGLE_CLEAR), + SubpassContents::Inline, + ); + frame.command_buffer.bind_graphics_pipeline(self.pipelines[0].raw_pipeline()); + + // storing const data via the CommandBuffer + //let buffer_ref: &B::Buffer = &self.buffer; + //let buffers: Vec<[_; 1]> = vec![(buffer_ref, 0)].into(); + frame.command_buffer.bind_vertex_buffers(0, self.pipelines[0].raw_vertex_buffers()); + + frame.command_buffer.draw(0..3, 0..1); + frame.command_buffer.end_render_pass(); + frame.command_buffer.finish(); + } + + trace!("Submiting to queue..."); + let submission = Submission { + command_buffers: iter::once(&*frame.command_buffer), + wait_semaphores: None, + signal_semaphores: iter::once(&frame.signal_semaphores[0]), + }; + + unsafe { + use gfx_hal::queue::CommandQueue; + + self.gpu.queue_mut().submit(submission, Some(&frame.fences[0])); + } + + let result = swap_system.present_frame(frame, &mut self.gpu); + if result.is_err() { + swap_system.recreate(&mut self.gpu).unwrap(); + } + + Ok(()) + + } } diff --git a/src/renderer/pipeline.rs b/src/renderer/pipeline.rs index 45217a1..2940a2c 100644 --- a/src/renderer/pipeline.rs +++ b/src/renderer/pipeline.rs @@ -1,20 +1,309 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; -use std::{ - mem::ManuallyDrop, +use std::mem::{ManuallyDrop, size_of}; + +use gfx_hal::{ + buffer::SubRange, }; +use super::{ + gpu::Gpu, + swap_system::SwapSystem, +}; + +mod attachement; +use self::attachement::Attachement; + +const VERTEX_SOURCE: &str = +"#version 440 core + +layout (location = 0) in vec2 position; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() +{ + gl_Position = vec4(position, 0.0, 1.0); +}"; + +const FRAGMENT_SOURCE: &str = +"#version 440 core + +layout (location = 0) out vec4 frag_color; + +void main() +{ + frag_color = vec4(0.5, 0.5, 0.5, 0.5); +}"; + //--Pipeline implementation------------------------------------------------------------------------- #[derive(Debug)] pub struct Pipeline { - render_pass: ManuallyDrop, + set_layout: Vec, + layout: ManuallyDrop, + gfx_pipeline: ManuallyDrop, + vertex_buffers: Vec>, } impl Pipeline where B: gfx_hal::Backend, { + pub fn drop(mut self, gpu: &mut Gpu) { + use std::ptr::read; + + use gfx_hal::device::Device; + + debug!("Dropping Pipeline..."); + for buffer in self.vertex_buffers.drain(..) { + buffer.drop(gpu); + } + unsafe { + gpu.device() + .destroy_graphics_pipeline( + ManuallyDrop::into_inner(read(&mut self.gfx_pipeline))); + gpu.device() + .destroy_pipeline_layout( + ManuallyDrop::into_inner(read(&mut self.layout))); + for layout in self.set_layout.drain(..) { + gpu.device().destroy_descriptor_set_layout(layout); + }} + } + + pub fn new(gpu: &mut Gpu, swap_system: &SwapSystem) -> Result, &'static str> { + use gfx_hal::{ + device::Device, + pso::{EntryPoint, Specialization, VertexBufferDesc, VertexInputRate, AttributeDesc, + Element, InputAssemblerDesc, Primitive, PrimitiveAssemblerDesc, Rasterizer, + PolygonMode, Face, FrontFace, State, DepthStencilDesc, BakedStates, Viewport, + DescriptorSetLayoutBinding, ShaderStageFlags + }, + format::Format, + }; + + use std::borrow::Cow; + + debug!("Compiling shaders..."); + let mut compiler = shaderc::Compiler::new().ok_or("shaderc not found")?; + let vertex_compile_artifact = compiler + .compile_into_spirv(VERTEX_SOURCE, shaderc::ShaderKind::Vertex, "vertex.vert", + "main", + None) + .map_err(|err| {error!("{}", err); + "Could not compile vertex shader"})?; + let fragment_compile_artifact = compiler + .compile_into_spirv(FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, "fragement.frag", + "main", + None) + .map_err(|err| {error!("{}", err); + "Could not compile fragment shader"})?; + + trace!("Creating ShaderModules..."); + let vertex_shader_module = unsafe { + gpu.device() + .create_shader_module(vertex_compile_artifact.as_binary()) + .map_err(|err| {error!("{}", err); + "Could not create vertex shader module"})? + }; + let fragment_shader_module = unsafe { + gpu.device() + .create_shader_module(fragment_compile_artifact.as_binary()) + .map_err(|err| {error!("{}", err); + "Could not create fragment shader module"})? + }; + + trace!("Creating shader set..."); + let (vs_entry, fs_entry) = ( + EntryPoint { + entry: "main", + module: &vertex_shader_module, + specialization: Specialization { + constants: Cow::Borrowed{0: &[]}, + data: Cow::Borrowed{0: &[]}, + }, + }, + EntryPoint { + entry: "main", + module: &fragment_shader_module, + specialization: Specialization { + constants: Cow::Borrowed{0: &[]}, + data: Cow::Borrowed{0: &[]}, + }, + }, + ); + + trace!("Creating PrimitiveAssembler..."); + let buffers: Vec = + vec![VertexBufferDesc { + binding: 0, + stride: (size_of::()*2) as u32, + rate: VertexInputRate::Vertex, + }]; + let attributes: Vec = + vec![AttributeDesc { + location: 0, + binding: 0, + element: Element { + format: Format::Rgb32Sfloat, + offset: 0, + }, + }]; + let input_assembler = InputAssemblerDesc { + primitive: Primitive::TriangleList, //TODO switch to strips + with_adjacency: false, + restart_index: None, + }; + + let primitive_assembler = PrimitiveAssemblerDesc::Vertex { + buffers: &buffers, + attributes: &attributes, + input_assembler, + vertex: vs_entry, + tessellation: None, + geometry: None, + }; + + trace!("Creating Rasterizer..."); + let rasterizer = Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::NONE, //TODO adjut that + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: false, + line_width: State::Static{0: 1.0}, //TODO may need to be changed + }; + + trace!("Configuring color blending..."); + let blender = { + use gfx_hal::pso::{BlendState, BlendOp, Factor, BlendDesc, LogicOp, ColorBlendDesc, + ColorMask}; + + let blend_state = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }}; + BlendDesc { + logic_op: Some(LogicOp::Copy), + targets: vec![ + ColorBlendDesc { + mask: ColorMask::ALL, + blend: Some(blend_state), + }]} + }; + + trace!("Configuring depth options..."); + let depth_stencil = DepthStencilDesc { + depth: None, + depth_bounds: false, + stencil: None, + }; + + trace!("Configuring baked-in pipeline states..."); + let baked_states = BakedStates { + viewport: Some(Viewport { + rect: swap_system.render_area.clone(), + depth: (0.0..1.0), + }), + scissor: Some(swap_system.render_area.clone()), + blend_color: None, + depth_bounds: None, + }; + + trace!("Creating PipelineLayout..."); + let set_layout = { + let bindings = Vec::::new(); + let immutable_samplers = Vec::::new(); + unsafe { + vec![gpu.device() + .create_descriptor_set_layout(bindings, immutable_samplers) + .map_err(|_| "Could not create DescriptorSetLayout")? + ]}}; + let layout = { + let push_constants = Vec::<(ShaderStageFlags, std::ops::Range)>::new(); + unsafe { + gpu.device() + .create_pipeline_layout(&set_layout, push_constants) + .map_err(|_| "Could not create PipelineLayout")? + }}; + + debug!("Creating GraphicsPipeline..."); + let gfx_pipeline = { + use gfx_hal::{ + pso::{GraphicsPipelineDesc, PipelineCreationFlags, BasePipeline}, + pass::Subpass, + }; + + //manual deref for ManuallyDrop to not cause troubles + let render_pass_ref: &B::RenderPass = &swap_system.render_pass; + + let pipeline_desc = GraphicsPipelineDesc { + primitive_assembler, + rasterizer, + fragment: Some(fs_entry), + blender, + depth_stencil, + multisampling: None, + baked_states, + layout: &layout, + subpass: Subpass { + index: 0, + main_pass: render_pass_ref, + }, + flags: PipelineCreationFlags::empty(), + parent: BasePipeline::None, + }; + + unsafe { + gpu.device() + .create_graphics_pipeline(&pipeline_desc, None) + .map_err(|_| "Could not create GraphicsPipeline")? + }}; + + trace!("Destroying no-longer-needed shader modules..."); + unsafe { + gpu.device() + .destroy_shader_module(vertex_shader_module); + gpu.device() + .destroy_shader_module(fragment_shader_module); + }; + + let vertex_buffers = vec![Attachement::new(gpu)?]; + + Ok( Pipeline { + set_layout, + layout: ManuallyDrop::new(layout), + gfx_pipeline: ManuallyDrop::new(gfx_pipeline), + vertex_buffers, + }) + } + + pub fn raw_pipeline(&self) -> &B::GraphicsPipeline { + &self.gfx_pipeline + } + + pub fn raw_vertex_buffers(&self) -> Vec<(&B::Buffer, SubRange)> { + + self.vertex_buffers + .iter() + //TODO move SubRange to Attachement ? + .map(|buffer| (buffer.get_buffer(), SubRange {offset: 0, size: None})) + .collect() + } + + pub fn write_vertex_buffer(&mut self, gpu: &Gpu, index: usize, data: Vec) + -> Result<(), &'static str> + { + self.vertex_buffers[index].write_buffer(gpu, data) + } } diff --git a/src/renderer/pipeline/attachement.rs b/src/renderer/pipeline/attachement.rs new file mode 100644 index 0000000..6786990 --- /dev/null +++ b/src/renderer/pipeline/attachement.rs @@ -0,0 +1,135 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use std::mem::ManuallyDrop; + +use crate::renderer::gpu::Gpu; + +//--Attachement implementation---------------------------------------------------------------------- +#[derive(Debug)] +pub struct Attachement { + buffer: ManuallyDrop, + memory: ManuallyDrop, + size: u64, +} + +impl Attachement +where + B: gfx_hal::Backend, +{ + pub fn drop(mut self, gpu: &mut Gpu) { + use std::ptr::read; + + use gfx_hal::device::Device; + + debug!("Dropping Attachement..."); + unsafe { + gpu.device() + .free_memory(ManuallyDrop::into_inner(read(&mut self.memory))); + gpu.device() + .destroy_buffer(ManuallyDrop::into_inner(read(&mut self.buffer))); + } + } + + pub fn new(gpu: &mut Gpu) -> Result, &'static str> { + use std::mem::size_of; + + use gfx_hal::{ + device::Device, + adapter::PhysicalDevice, + buffer::Usage, + }; + + debug!("Creating attachement..."); + let mut buffer = unsafe { + gpu.device() + .create_buffer((size_of::()*2*3) as u64, Usage::VERTEX) + .map_err(|_| "Could not create buffer")? + }; + + trace!("Creating underlying attachement memory..."); + let (memory, size) = { + use gfx_hal::{ + memory::Properties, + MemoryTypeId, + }; + + let requirements = unsafe { + gpu.device().get_buffer_requirements(&buffer) + }; + let memory_type = gpu.adapter() + .physical_device + .memory_properties() + .memory_types + .iter() + .enumerate() + .find(|&(id, memory_type)| { + requirements.type_mask & (1 << id) != 0 && + memory_type.properties.contains(Properties::CPU_VISIBLE)}) + .map(|(id, _)| MemoryTypeId(id)) + .ok_or("Could not find a suitable memory type to allocate attachement memory")?; + + ( + unsafe { + gpu.device() + .allocate_memory(memory_type, requirements.size) + .map_err(|_| "Could not allocate buffer memory...")? + }, + requirements.size, + )}; + + trace!("Binding memory to buffer..."); + unsafe { + gpu.device() + .bind_buffer_memory(&memory, 0, &mut buffer) + .map_err(|__| "Could not bind memory to buffer")?; + } + + + Ok( Attachement { + buffer: ManuallyDrop::new(buffer), + memory: ManuallyDrop::new(memory), + size, + }) + } + + pub fn get_buffer(&self) -> &B::Buffer { + //manual deref for ManuallyDrop to not cause troubles + &self.buffer + } + + pub fn write_buffer(&self, gpu: &Gpu, data: Vec) -> Result<(), &'static str> + { + use gfx_hal::{ + device::Device, + memory::Segment, + }; + + trace!("writing data to buffer..."); + unsafe { + let mapped_memory = gpu.device() + .map_memory(&self.memory, Segment::ALL) + .map_err(|_| "Could not map buffer memory")?; + + //debug!("before : {}", std::ptr::read(mapped_memory as *mut f32)); + + std::ptr::copy_nonoverlapping(data.as_ptr() as *const u8, + mapped_memory, self.size as usize); + + //debug!("after : {}", std::ptr::read(mapped_memory as *mut f32)); + + //manual deref for ManuallyDrop to not cause troubles + let memory_ref: &B::Memory = &self.memory; + + gpu.device() + .flush_mapped_memory_ranges(std::iter::once((memory_ref, Segment::ALL))) + .map_err(|_| "Could not flush mapped buffer memory")?; + + gpu.device().unmap_memory(&self.memory); + } + + Ok(()) + } + +} + diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index b2ae707..c5973c6 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -25,7 +25,7 @@ pub struct SwapSystem { format: Format, extent: Extent2D, pub render_area: GfxRect, //TODO may not be needed (duplicate of extent) - pub render_pass: ManuallyDrop, + pub render_pass: ManuallyDrop, //TODO move to Pipeline ? frames: VecDeque>, frame_nb: usize, } @@ -51,7 +51,7 @@ where } } - pub fn new(gpu: &mut Gpu, mut surface: B::Surface) + pub fn new(gpu: &mut Gpu, mut surface: B::Surface) -> Result, &'static str> { diff --git a/src/subengine/subengine_pipeline.rs b/src/subengine/subengine_pipeline.rs index dc5ad08..45c26e8 100644 --- a/src/subengine/subengine_pipeline.rs +++ b/src/subengine/subengine_pipeline.rs @@ -25,7 +25,7 @@ where pub inputs: Vec<&'a RefCell>, pub subengines: Vec>, pub renderers: Vec<(Renderer, &'a RefCell)>, - pub phantom: PhantomData, //needed because of compiler limitations + phantom: PhantomData, //needed because of compiler limitations } impl<'a, I, W, O> SubenginePipeline<'a, I, W, O> diff --git a/src/utils.rs b/src/utils.rs index b51888b..ac9a067 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,3 +9,16 @@ pub struct Rect { pub h: I, } +#[derive(Debug, Copy, Clone)] +pub struct Triangle { + pub points: [[f32; 2]; 3], +} + +impl Triangle { + + pub fn points_flat(&self) -> [f32; 6] { + let [[a, b], [c, d], [e, f]] = self.points; + [a, b, c, d, e, f] + } +} + From 6b1a18e7959ccb19eab7d7550790d09891e6c074 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 30 Jan 2021 20:55:18 +0100 Subject: [PATCH 08/22] Got mouse-dependant color on triangle + added color attachement * tweaked shaders * tweaked controller --- src/controller.rs | 25 ++++++++++++++----- src/renderer.rs | 9 +++++-- src/renderer/pipeline.rs | 36 ++++++++++++++++++++++------ src/renderer/pipeline/attachement.rs | 15 ++++++------ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index 2e230e9..595fe23 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -15,6 +15,7 @@ where { pipelines: Vec>, mouse_pos: [f32; 2], + color: [f32; 3], } impl Controller<'_, I, W, O> @@ -39,6 +40,7 @@ where Controller { pipelines: pipelines_vec, mouse_pos: [0.5, 0.5], + color: [1.0, 1.0, 1.0], } } @@ -62,10 +64,17 @@ where } for input_key in &input_keys { match input_key { - Key::MouseMove{x,y} => self.mouse_pos = [ - (x/1280.0 * 2.0 - 1.0) as f32, - (y/720.0 * 2.0 - 1.0) as f32, - ], + Key::MouseMove{x,y} => { + self.mouse_pos = [ + (x/1280.0 * 2.0 - 1.0) as f32, + (y/720.0 * 2.0 - 1.0) as f32, + ]; + self.color = [ + (x/1280.0) as f32, + (y/720.0) as f32, + (((x + y)/2.0)/((1280.0 + 720.0)/2.0)) as f32, + ]; + }, Key::Close => return, _ => (), }; @@ -83,14 +92,18 @@ where points: [self.mouse_pos, [-0.5, 0.5], [-0.5, -0.5]], }; - debug!("Triangle : {:#?}", triangle); + let colors = [ + [self.color[0], self.color[1], self.color[2]], + [self.color[2], self.color[0], self.color[1]], + [self.color[1], self.color[2], self.color[0]], + ]; for (renderer, output) in &mut pipeline.renderers { // match renderer.draw_clear_frame(output, self.color) { // Err(err) => warn!("{}", err), // _ => (), // } - match renderer.draw_triangle_frame(output, triangle) { + match renderer.draw_triangle_frame(output, triangle, colors) { Err(err) => warn!("{}", err), _ => (), }; diff --git a/src/renderer.rs b/src/renderer.rs index 74fd363..32a9b4b 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -182,7 +182,10 @@ where Ok(()) } - pub fn draw_triangle_frame(&mut self, output: &RefCell, triangle: Triangle) + pub fn draw_triangle_frame(&mut self, + output: &RefCell, + triangle: Triangle, + colors: [[f32; 3]; 3]) -> Result<(), &'static str> where W: raw_window_handle::HasRawWindowHandle, @@ -223,6 +226,8 @@ where trace!("Uploading triangle data..."); let points = triangle.points_flat(); self.pipelines[0].write_vertex_buffer(&self.gpu, 0, (&points).to_vec())?; //TODO meh + let colors_flat = colors.iter().flatten().copied().collect(); + self.pipelines[0].write_vertex_buffer(&self.gpu, 1, colors_flat)?; trace!("Recording CommandBuffer..."); unsafe { @@ -237,7 +242,7 @@ where frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); const TRIANGLE_CLEAR: ClearValue = - ClearValue {color : ClearColor{float32 : [0.1, 0.2, 0.3, 1.0]}}; + ClearValue {color : ClearColor{float32 : [0.5, 0.5, 0.5, 1.0]}}; frame.command_buffer.begin_render_pass( &swap_system.render_pass, diff --git a/src/renderer/pipeline.rs b/src/renderer/pipeline.rs index 2940a2c..03844c7 100644 --- a/src/renderer/pipeline.rs +++ b/src/renderer/pipeline.rs @@ -16,27 +16,31 @@ mod attachement; use self::attachement::Attachement; const VERTEX_SOURCE: &str = -"#version 440 core +"#version 450 core layout (location = 0) in vec2 position; +layout (location = 1) in vec3 color; -out gl_PerVertex { +layout (location = 0) out gl_PerVertex { vec4 gl_Position; }; +layout (location = 1) out vec3 frag_color; void main() { gl_Position = vec4(position, 0.0, 1.0); + frag_color = color; }"; const FRAGMENT_SOURCE: &str = -"#version 440 core +"#version 450 core layout (location = 0) out vec4 frag_color; +layout (location = 1) in vec3 color; void main() { - frag_color = vec4(0.5, 0.5, 0.5, 0.5); + frag_color = vec4(color, 1); }"; //--Pipeline implementation------------------------------------------------------------------------- @@ -137,19 +141,34 @@ where trace!("Creating PrimitiveAssembler..."); let buffers: Vec = - vec![VertexBufferDesc { + vec![ + VertexBufferDesc { binding: 0, stride: (size_of::()*2) as u32, rate: VertexInputRate::Vertex, + }, + VertexBufferDesc { + binding: 1, + stride: (size_of::()*3) as u32, + rate: VertexInputRate::Vertex, }]; let attributes: Vec = - vec![AttributeDesc { + vec![ + AttributeDesc { location: 0, binding: 0, element: Element { format: Format::Rgb32Sfloat, offset: 0, }, + }, + AttributeDesc { + location: 1, + binding: 1, + element: Element { + format: Format::Rgb32Sfloat, + offset: 0, + }, }]; let input_assembler = InputAssemblerDesc { primitive: Primitive::TriangleList, //TODO switch to strips @@ -276,7 +295,10 @@ where .destroy_shader_module(fragment_shader_module); }; - let vertex_buffers = vec![Attachement::new(gpu)?]; + let vertex_buffers = vec![ + Attachement::new(gpu, (size_of::()*2*3) as u64)?, + Attachement::new(gpu, (size_of::()*3*3) as u64)?, + ]; Ok( Pipeline { set_layout, diff --git a/src/renderer/pipeline/attachement.rs b/src/renderer/pipeline/attachement.rs index 6786990..9af3950 100644 --- a/src/renderer/pipeline/attachement.rs +++ b/src/renderer/pipeline/attachement.rs @@ -31,9 +31,7 @@ where } } - pub fn new(gpu: &mut Gpu) -> Result, &'static str> { - use std::mem::size_of; - + pub fn new(gpu: &mut Gpu, size: u64) -> Result, &'static str> { use gfx_hal::{ device::Device, adapter::PhysicalDevice, @@ -43,7 +41,7 @@ where debug!("Creating attachement..."); let mut buffer = unsafe { gpu.device() - .create_buffer((size_of::()*2*3) as u64, Usage::VERTEX) + .create_buffer(size, Usage::VERTEX) .map_err(|_| "Could not create buffer")? }; @@ -75,7 +73,7 @@ where .allocate_memory(memory_type, requirements.size) .map_err(|_| "Could not allocate buffer memory...")? }, - requirements.size, + size, )}; trace!("Binding memory to buffer..."); @@ -111,12 +109,15 @@ where .map_memory(&self.memory, Segment::ALL) .map_err(|_| "Could not map buffer memory")?; - //debug!("before : {}", std::ptr::read(mapped_memory as *mut f32)); + //debug!("data : {:?}", data); + //debug!("before : {:?}", std::slice::from_raw_parts(mapped_memory as *mut f32, + // (self.size/4) as usize)); std::ptr::copy_nonoverlapping(data.as_ptr() as *const u8, mapped_memory, self.size as usize); - //debug!("after : {}", std::ptr::read(mapped_memory as *mut f32)); + //debug!("after : {:?}", std::slice::from_raw_parts(mapped_memory as *mut f32, + // (self.size/4) as usize)); //manual deref for ManuallyDrop to not cause troubles let memory_ref: &B::Memory = &self.memory; From 189708f0268312d134bbe05088621eab399b7f04 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 31 Jan 2021 10:56:49 +0100 Subject: [PATCH 09/22] Moved shader to separate files + base.vert and base.frag * adjusted pipeline.rs --- src/renderer/pipeline.rs | 33 ++++----------------------------- src/renderer/shaders/base.frag | 10 ++++++++++ src/renderer/shaders/base.vert | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 src/renderer/shaders/base.frag create mode 100644 src/renderer/shaders/base.vert diff --git a/src/renderer/pipeline.rs b/src/renderer/pipeline.rs index 03844c7..3e82281 100644 --- a/src/renderer/pipeline.rs +++ b/src/renderer/pipeline.rs @@ -15,33 +15,8 @@ use super::{ mod attachement; use self::attachement::Attachement; -const VERTEX_SOURCE: &str = -"#version 450 core - -layout (location = 0) in vec2 position; -layout (location = 1) in vec3 color; - -layout (location = 0) out gl_PerVertex { - vec4 gl_Position; -}; -layout (location = 1) out vec3 frag_color; - -void main() -{ - gl_Position = vec4(position, 0.0, 1.0); - frag_color = color; -}"; - -const FRAGMENT_SOURCE: &str = -"#version 450 core - -layout (location = 0) out vec4 frag_color; -layout (location = 1) in vec3 color; - -void main() -{ - frag_color = vec4(color, 1); -}"; +static VERT_SRC: &'static str = include_str!("shaders/base.vert"); +static FRAG_SRC: &'static str = include_str!("shaders/base.frag"); //--Pipeline implementation------------------------------------------------------------------------- #[derive(Debug)] @@ -93,13 +68,13 @@ where debug!("Compiling shaders..."); let mut compiler = shaderc::Compiler::new().ok_or("shaderc not found")?; let vertex_compile_artifact = compiler - .compile_into_spirv(VERTEX_SOURCE, shaderc::ShaderKind::Vertex, "vertex.vert", + .compile_into_spirv(VERT_SRC, shaderc::ShaderKind::Vertex, "vertex.vert", "main", None) .map_err(|err| {error!("{}", err); "Could not compile vertex shader"})?; let fragment_compile_artifact = compiler - .compile_into_spirv(FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, "fragement.frag", + .compile_into_spirv(FRAG_SRC, shaderc::ShaderKind::Fragment, "fragement.frag", "main", None) .map_err(|err| {error!("{}", err); diff --git a/src/renderer/shaders/base.frag b/src/renderer/shaders/base.frag new file mode 100644 index 0000000..00c4439 --- /dev/null +++ b/src/renderer/shaders/base.frag @@ -0,0 +1,10 @@ +#version 450 + +layout (location = 0) out vec4 frag_color; +layout (location = 1) in vec3 color; + +void main() +{ + frag_color = vec4(color, 1); +} + diff --git a/src/renderer/shaders/base.vert b/src/renderer/shaders/base.vert new file mode 100644 index 0000000..05ff862 --- /dev/null +++ b/src/renderer/shaders/base.vert @@ -0,0 +1,16 @@ +#version 450 + +layout (location = 0) in vec2 position; +layout (location = 1) in vec3 color; + +layout (location = 0) out gl_PerVertex { + vec4 gl_Position; +}; +layout (location = 1) out vec3 frag_color; + +void main() +{ + gl_Position = vec4(position, 0.0, 1.0); + frag_color = color; +} + From 6aa5e8e3c08a05b165ce9ecac321c455cc462514 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 2 Feb 2021 11:23:20 +0100 Subject: [PATCH 10/22] Fixed framebuffer error * tweaked swap_system acquire_frame() function * moved fence waiting in acquire_frame() * cleaned minor details --- doc/architecture | 2 +- main.rs | 2 +- src/io/winit_window.rs | 7 ++++--- src/lib.rs | 5 +++-- src/renderer.rs | 11 ----------- src/renderer/swap_system.rs | 23 +++++++++++++++++++---- src/renderer/swap_system/frame.rs | 4 ++-- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/doc/architecture b/doc/architecture index e6d4f7c..bce308f 100644 --- a/doc/architecture +++ b/doc/architecture @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/main.rs b/main.rs index bda4db0..2bfb471 100644 --- a/main.rs +++ b/main.rs @@ -25,7 +25,7 @@ fn setup_logger() -> Result<(), fern::InitError> { message )) }) - .level(log::LevelFilter::Debug) + .level(log::LevelFilter::Trace) .chain(std::io::stdout()) .chain(fern::log_file("output.log")?) .apply()?; diff --git a/src/io/winit_window.rs b/src/io/winit_window.rs index b94c356..c64bc19 100644 --- a/src/io/winit_window.rs +++ b/src/io/winit_window.rs @@ -13,7 +13,6 @@ use winit::{ window::{WindowBuilder, Window}, }; -//TODO fix that use crate::{ io::{Output, Input, Key, Signal, ReadError}, utils::Rect, @@ -202,8 +201,10 @@ mod tests { use std::mem::ManuallyDrop; let _ = setup_logger(); - let mut window1 = ManuallyDrop::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap()); - let mut window2 = ManuallyDrop::new(WinitWindow::new("IV 2", Rect {w: 1280, h: 720}).unwrap()); + let mut window1 = ManuallyDrop::new(WinitWindow::new("IV", + Rect {w: 1280, h: 720}).unwrap()); + let mut window2 = ManuallyDrop::new(WinitWindow::new("IV 2", + Rect {w: 1280, h: 720}).unwrap()); unsafe { ManuallyDrop::drop(&mut window1); diff --git a/src/lib.rs b/src/lib.rs index 52380b7..7930672 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,7 +90,8 @@ pub fn run() -> Result<(), &'static str> { //running controller let mut controller = Controller::new(vec![subengine_pipeline]); - loop { + //loop { + for _i in 0..10 { controller.run(); } @@ -121,7 +122,7 @@ pub fn run() -> Result<(), &'static str> { // _ => (), // }}} // -// Ok(()) + Ok(()) } // let (input_tx, input_rx) = mpsc::channel(); diff --git a/src/renderer.rs b/src/renderer.rs index 32a9b4b..f729449 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -193,7 +193,6 @@ where { use gfx_hal::{ window::AcquireError, - device::Device, queue::Submission, }; @@ -213,16 +212,6 @@ where _ => Err("Could not acquire Frame from SwapSystem")?, }}; - trace!("Waiting for Frame..."); - unsafe { - let _ = self.gpu.device() - .wait_for_fence(&frame.fences[0], !0) - .map_err(|_| "Failed to wait for Fence")?; - let _ = self.gpu.device() - .reset_fence(&frame.fences[0]) - .map_err(|_| "Failed to reset fence")?; - } - trace!("Uploading triangle data..."); let points = triangle.points_flat(); self.pipelines[0].write_vertex_buffer(&self.gpu, 0, (&points).to_vec())?; //TODO meh diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index c5973c6..483c4c4 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -131,7 +131,7 @@ where } }; - warn!("Generating hard-coded number of frames !"); + warn!("Generating hard-coded number of frames ({}) !", frame_nb); let mut frames = VecDeque::with_capacity(frame_nb); for _ in 0..frame_nb { let frame = Frame::new(gpu) @@ -187,6 +187,22 @@ where pub fn acquire_frame(&mut self, gpu: &Gpu) -> Result, AcquireError> { + //println!("Frame nb : {}", self.frames.len()); + //TODO frames number diminish sometimes at resize... + let mut frame = self.frames.pop_back().unwrap(); + + trace!("Waiting for Frame..."); + unsafe { + use gfx_hal::device::Device; + + let _ = gpu.device() + .wait_for_fence(&frame.fences[0], !0) + .map_err(|_| "Failed to wait for Fence"); //TODO error + let _ = gpu.device() + .reset_fence(&frame.fences[0]) + .map_err(|_| "Failed to reset Fence"); //TODO error + } + trace!("Acquiring Frame..."); let image = unsafe { match self.surface.acquire_image(core::u64::MAX) { @@ -197,15 +213,14 @@ where }}, Err(err) => return Err(err), }}; - //println!("Frame nb : {}", self.frames.len()); - //frames number diminish sometimes at resize... - let mut frame = self.frames.pop_back().unwrap(); trace!("Creating Framebuffer..."); let framebuffer = unsafe { use gfx_hal::device::Device; use std::borrow::Borrow; + //frame.command_buffer.reset(true); //TODO may be needed at some point... + gpu.device() .create_framebuffer(&self.render_pass, vec![image.borrow()], diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index e582dcb..4fdbbd7 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -71,7 +71,7 @@ where let fences = vec!( gpu.device() .create_fence(true) - .map_err(|_| "Could not create Semaphore")?); + .map_err(|_| "Could not create Fence")?); (wait_semaphores, signal_semaphores, fences) }; @@ -90,7 +90,7 @@ where Ok( Frame { wait_semaphores, signal_semaphores, - fences, + fences, command_buffer: ManuallyDrop::new(command_buffer), image_view: None, framebuffer: None, From a36c332ddd180f7a41bc3d35740ff298b923c57c Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 3 Feb 2021 08:51:52 +0100 Subject: [PATCH 11/22] Partially fixed Framebuffer issues * tweaked functions order in draw_triangle_frame() --- src/lib.rs | 4 ++-- src/renderer/swap_system.rs | 30 ++++++++++++++++++++++++++---- src/renderer/swap_system/frame.rs | 23 ++++++++++++++++------- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7930672..33b0421 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub fn run() -> Result<(), &'static str> { //running controller let mut controller = Controller::new(vec![subengine_pipeline]); - //loop { - for _i in 0..10 { + loop { + //for _i in 0..40 { controller.run(); } diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index 483c4c4..cffe1a0 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -189,7 +189,11 @@ where //println!("Frame nb : {}", self.frames.len()); //TODO frames number diminish sometimes at resize... + static mut id: i32 = 0; let mut frame = self.frames.pop_back().unwrap(); + unsafe { + id = (id+1)%3; + } trace!("Waiting for Frame..."); unsafe { @@ -203,7 +207,16 @@ where .map_err(|_| "Failed to reset Fence"); //TODO error } - trace!("Acquiring Frame..."); + trace!("Reseting CommandBuffer..."); + unsafe { + use gfx_hal::command::CommandBuffer; + + frame.command_buffer.reset(false); //TODO may be needed at some point... + }; + + unsafe { + trace!("Acquiring Frame {}...", id); + } let image = unsafe { match self.surface.acquire_image(core::u64::MAX) { Ok((image, suboptimal)) => { @@ -215,12 +228,10 @@ where }}; trace!("Creating Framebuffer..."); - let framebuffer = unsafe { + let mut framebuffer = unsafe { use gfx_hal::device::Device; use std::borrow::Borrow; - //frame.command_buffer.reset(true); //TODO may be needed at some point... - gpu.device() .create_framebuffer(&self.render_pass, vec![image.borrow()], @@ -228,6 +239,16 @@ where .unwrap() //TODO improve that }; + unsafe { + use gfx_hal::{ + device::Device, + command::CommandBuffer, + }; + + gpu.device() + .set_framebuffer_name(&mut framebuffer, format!("frambuffer {}", id).as_str()); + } + frame.link_swapchain_image(gpu, image, framebuffer); Ok(frame) @@ -248,6 +269,7 @@ where .map_err(|_| "Failed to present into the swapchain")?; }; + frame.destroy_framebuffer(gpu); self.frames.push_front(frame); Ok(()) diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index 4fdbbd7..1d0b2af 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -103,13 +103,14 @@ where framebuffer: B::Framebuffer) { use gfx_hal::device::Device; - match self.framebuffer.replace(framebuffer) { - Some(old_framebuffer) => { - trace!("Destroying Framebuffer..."); - unsafe { gpu.device().destroy_framebuffer(old_framebuffer) }; - }, - None => (), - } + self.framebuffer = Some(framebuffer); + //match self.framebuffer.replace(framebuffer) { + // Some(old_framebuffer) => { + // trace!("Destroying Framebuffer..."); + // unsafe { gpu.device().destroy_framebuffer(old_framebuffer) }; + // }, + // None => (), + //} self.image_view = Some(image); } @@ -121,5 +122,13 @@ where .take() .ok_or("Can not unlink non-linked Frame !") } + + pub fn destroy_framebuffer(&mut self, gpu: &Gpu) { + unsafe { + use gfx_hal::device::Device; + + gpu.device().destroy_framebuffer(self.framebuffer.take().unwrap()); + } + } } From 545f5b326ee12d46e6cfbfa1a99cc83de06d7caf Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 3 Feb 2021 09:10:53 +0100 Subject: [PATCH 12/22] Fixed close button + added controller main loop * cleaned code from previous commit --- src/controller.rs | 101 ++++++++++++++++-------------- src/lib.rs | 5 +- src/renderer/swap_system.rs | 30 +++++---- src/renderer/swap_system/frame.rs | 3 +- 4 files changed, 69 insertions(+), 70 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index 595fe23..e84331b 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -55,60 +55,65 @@ where let mut input_keys: Vec = Vec::new(); - for pipeline in &mut self.pipelines { - for input in &pipeline.inputs { - match input.borrow().read(Duration::from_millis(1)) { - Ok(key) => input_keys.push(key), - Err(_err) => (), + loop { + for pipeline in &mut self.pipelines { + for input in &pipeline.inputs { + match input.borrow().read(Duration::from_millis(1)) { + Ok(key) => input_keys.push(key), + Err(_err) => (), + } } - } - for input_key in &input_keys { - match input_key { - Key::MouseMove{x,y} => { - self.mouse_pos = [ - (x/1280.0 * 2.0 - 1.0) as f32, - (y/720.0 * 2.0 - 1.0) as f32, - ]; - self.color = [ - (x/1280.0) as f32, - (y/720.0) as f32, - (((x + y)/2.0)/((1280.0 + 720.0)/2.0)) as f32, - ]; - }, - Key::Close => return, - _ => (), + for input_key in &input_keys { + match input_key { + Key::MouseMove{x,y} => { + self.mouse_pos = [ + (x/1280.0 * 2.0 - 1.0) as f32, + (y/720.0 * 2.0 - 1.0) as f32, + ]; + self.color = [ + (x/1280.0) as f32, + (y/720.0) as f32, + (((x + y)/2.0)/((1280.0 + 720.0)/2.0)) as f32, + ]; + }, + Key::Close => { + info!("Shutting down IV !"); + return; + } + _ => (), + }; + } + for subengines in &pipeline.subengines { + for subengine in subengines { + subengine.exec(SubengineCommand::Run); + } + for subengine in subengines { + subengine.wait_for_exec(Duration::from_millis(1)).unwrap(); + } + } + + let triangle = Triangle { + points: [self.mouse_pos, [-0.5, 0.5], [-0.5, -0.5]], }; - } - for subengines in &pipeline.subengines { - for subengine in subengines { - subengine.exec(SubengineCommand::Run); - } - for subengine in subengines { - subengine.wait_for_exec(Duration::from_millis(1)).unwrap(); - } - } - - let triangle = Triangle { - points: [self.mouse_pos, [-0.5, 0.5], [-0.5, -0.5]], - }; - let colors = [ - [self.color[0], self.color[1], self.color[2]], - [self.color[2], self.color[0], self.color[1]], - [self.color[1], self.color[2], self.color[0]], - ]; + let colors = [ + [self.color[0], self.color[1], self.color[2]], + [self.color[2], self.color[0], self.color[1]], + [self.color[1], self.color[2], self.color[0]], + ]; - for (renderer, output) in &mut pipeline.renderers { - // match renderer.draw_clear_frame(output, self.color) { - // Err(err) => warn!("{}", err), - // _ => (), - // } - match renderer.draw_triangle_frame(output, triangle, colors) { - Err(err) => warn!("{}", err), - _ => (), + for (renderer, output) in &mut pipeline.renderers { + // match renderer.draw_clear_frame(output, self.color) { + // Err(err) => warn!("{}", err), + // _ => (), + // } + match renderer.draw_triangle_frame(output, triangle, colors) { + Err(err) => warn!("{}", err), + _ => (), + }; }; }; - }; + } } } //These tests are disabled because of some stange issue with cargo not waiting for the drop diff --git a/src/lib.rs b/src/lib.rs index 33b0421..7b560c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,10 +90,7 @@ pub fn run() -> Result<(), &'static str> { //running controller let mut controller = Controller::new(vec![subengine_pipeline]); - loop { - //for _i in 0..40 { - controller.run(); - } + controller.run(); //let engine_pipelines = vec![ // EnginePipeline { diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index cffe1a0..4ba1b0f 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -189,11 +189,11 @@ where //println!("Frame nb : {}", self.frames.len()); //TODO frames number diminish sometimes at resize... - static mut id: i32 = 0; + //static mut id: i32 = 0; let mut frame = self.frames.pop_back().unwrap(); - unsafe { - id = (id+1)%3; - } + //unsafe { + // id = (id+1)%3; + //} trace!("Waiting for Frame..."); unsafe { @@ -214,9 +214,10 @@ where frame.command_buffer.reset(false); //TODO may be needed at some point... }; - unsafe { - trace!("Acquiring Frame {}...", id); - } + //unsafe { + // trace!("Acquiring Frame {}...", id); + //} + trace!("Acquiring Frame..."); let image = unsafe { match self.surface.acquire_image(core::u64::MAX) { Ok((image, suboptimal)) => { @@ -228,7 +229,7 @@ where }}; trace!("Creating Framebuffer..."); - let mut framebuffer = unsafe { + let framebuffer = unsafe { use gfx_hal::device::Device; use std::borrow::Borrow; @@ -239,15 +240,12 @@ where .unwrap() //TODO improve that }; - unsafe { - use gfx_hal::{ - device::Device, - command::CommandBuffer, - }; + //unsafe { + // use gfx_hal::{device::Device}; - gpu.device() - .set_framebuffer_name(&mut framebuffer, format!("frambuffer {}", id).as_str()); - } + // gpu.device() + // .set_framebuffer_name(&mut framebuffer, format!("frambuffer {}", id).as_str()); + //} frame.link_swapchain_image(gpu, image, framebuffer); diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index 1d0b2af..3312a4d 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -98,10 +98,9 @@ where } pub fn link_swapchain_image(&mut self, - gpu: &Gpu, + _gpu: &Gpu, //TODO clear that when framebuffer issue is fixed image: >::SwapchainImage, framebuffer: B::Framebuffer) { - use gfx_hal::device::Device; self.framebuffer = Some(framebuffer); //match self.framebuffer.replace(framebuffer) { From 012393e04b3bc0a8288c84a3f3202c2d9add365e Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 3 Feb 2021 09:38:12 +0100 Subject: [PATCH 13/22] Fixed shutdown ressource cleaning * changed drop order in Renderer * cleaned dropping logs * cleaned unnecessary code --- main.rs | 8 +- src/controller.rs | 1 + src/io/winit_window.rs | 2 +- src/lib.rs | 123 ------------------------------ src/renderer.rs | 13 ++-- src/renderer/swap_system.rs | 2 +- src/renderer/swap_system/frame.rs | 1 - 7 files changed, 11 insertions(+), 139 deletions(-) diff --git a/main.rs b/main.rs index 2bfb471..2f78ccf 100644 --- a/main.rs +++ b/main.rs @@ -32,17 +32,11 @@ fn setup_logger() -> Result<(), fern::InitError> { Ok(()) } - -//pub fn draw_frame(hal : &mut HalState, local : &LocalState) -> Result<(), &'static str> { -// -// hal.draw_clear_frame(local.color()); -//} - pub fn main() -> Result<(), &'static str> { setup_logger().unwrap(); run()?; - //print!("test"); + Ok(()) } diff --git a/src/controller.rs b/src/controller.rs index e84331b..bb422f3 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -78,6 +78,7 @@ where }, Key::Close => { info!("Shutting down IV !"); + return; } _ => (), diff --git a/src/io/winit_window.rs b/src/io/winit_window.rs index c64bc19..3b3623d 100644 --- a/src/io/winit_window.rs +++ b/src/io/winit_window.rs @@ -46,7 +46,7 @@ impl Drop for WinitWindow { }, _ => true, } {} - trace!("Dropped !"); + trace!("Dropped window !"); } } diff --git a/src/lib.rs b/src/lib.rs index 7b560c2..1393313 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,129 +92,6 @@ pub fn run() -> Result<(), &'static str> { let mut controller = Controller::new(vec![subengine_pipeline]); controller.run(); - //let engine_pipelines = vec![ - // EnginePipeline { - // Inputs: vec![0,1], - // Engines: vec![&color_engine], - // Renderers: vec![(1,0)], - // }, - // EnginePipeline { - // Inputs: vec![3], - // Engines: vec![&color_engine], - // Renderers: vec![(1,1),(1,2),(1,3)], - //}]; - - //let controller = Controller::new(renderers, &windows, &windows, engine_pipelines); - //controller.run(); - - //Ok(()) - //let local_state = LocalState::default(); - -// let color = [0.5, 0.0, 0.0, 1.0]; -// -// loop { -// for window in &mut windows { -// match renderer.draw_clear_frame(window, color) { -// Err(err) => println!("{}", err), -// _ => (), -// }}} -// Ok(()) } -// 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); -// } -//} diff --git a/src/renderer.rs b/src/renderer.rs index f729449..174a033 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -41,25 +41,26 @@ where device::Device, }; - debug!("Dropping Pipelines..."); - for pipeline in self.pipelines.drain(..) { - pipeline.drop(&mut self.gpu); - } - debug!("Waiting for device to idle..."); let _ = self.gpu .device() .wait_idle(); + debug!("Dropping Pipelines..."); + for pipeline in self.pipelines.drain(..) { + pipeline.drop(&mut self.gpu); + } + info!("Dropping Renderer..."); unsafe { + debug!("Dropping SwapSystems..."); for mut swap_system in self.swap_systems.drain(..) { self.instance.destroy_surface(swap_system.drop(&mut self.gpu)); } ManuallyDrop::drop(&mut self.gpu); ManuallyDrop::drop(&mut self.instance); } - trace!("Renderer dropped !"); + debug!("Renderer dropped !"); } } diff --git a/src/renderer/swap_system.rs b/src/renderer/swap_system.rs index 4ba1b0f..5d9abb7 100644 --- a/src/renderer/swap_system.rs +++ b/src/renderer/swap_system.rs @@ -37,7 +37,7 @@ where pub fn drop(&mut self, gpu: &mut Gpu) -> B::Surface { use gfx_hal::device::Device; - debug!("Dropping SwapSystem..."); + trace!("Dropping frames..."); for mut frame in self.frames.drain(..) { frame.drop(gpu); } diff --git a/src/renderer/swap_system/frame.rs b/src/renderer/swap_system/frame.rs index 3312a4d..5d4e0dd 100644 --- a/src/renderer/swap_system/frame.rs +++ b/src/renderer/swap_system/frame.rs @@ -32,7 +32,6 @@ where pool::CommandPool, }; - trace!("Dropping Frame..."); unsafe { if self.image_view.is_some() { warn!("Dropping non-presented frame !"); From 2e7b5ac33a0cbc73c0aa910b7b858d3f7c3ec423 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 3 Feb 2021 10:06:00 +0100 Subject: [PATCH 14/22] Increased response timeout * increased response timeout in Controller --- src/controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller.rs b/src/controller.rs index bb422f3..e747600 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -89,7 +89,7 @@ where subengine.exec(SubengineCommand::Run); } for subengine in subengines { - subengine.wait_for_exec(Duration::from_millis(1)).unwrap(); + subengine.wait_for_exec(Duration::from_millis(10)).unwrap(); } } From 35eed08d5feebd25e87668bc1fa69a1d4e0a9a0e Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 3 Feb 2021 11:52:22 +0100 Subject: [PATCH 15/22] Improved input lag * switched to sync_channel in WinitWindow + added framerate math (commented) * improved gpu selection algorithm --- main.rs | 2 +- src/controller.rs | 18 +++++++++++++++++- src/io/winit_window.rs | 13 ++++++++----- src/renderer/gpu.rs | 12 +++++++++++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/main.rs b/main.rs index 2f78ccf..707e91b 100644 --- a/main.rs +++ b/main.rs @@ -25,7 +25,7 @@ fn setup_logger() -> Result<(), fern::InitError> { message )) }) - .level(log::LevelFilter::Trace) + .level(log::LevelFilter::Debug) .chain(std::io::stdout()) .chain(fern::log_file("output.log")?) .apply()?; diff --git a/src/controller.rs b/src/controller.rs index e747600..df6b70d 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -45,7 +45,7 @@ where } pub fn run(&mut self) { - use std::time::Duration; + use std::time::Duration; //, SystemTime}; use crate::{ subengine::subengine_controller::SubengineCommand, @@ -56,6 +56,8 @@ where let mut input_keys: Vec = Vec::new(); loop { +// let frame_start = SystemTime::now(); + for pipeline in &mut self.pipelines { for input in &pipeline.inputs { match input.borrow().read(Duration::from_millis(1)) { @@ -114,6 +116,20 @@ where }; }; }; + +// let frame_time = SystemTime::now() +// .duration_since(frame_start) +// .unwrap(); +// +// let sleep_time = Duration::from_secs_f32(1.0/60.0) +// .checked_sub(frame_time) +// .unwrap_or_else(|| { +// info!("Engine overloaded !"); +// Duration::from_secs(0) +// }); +// std::thread::sleep(sleep_time); +// +// info!("FPS : {}", 1.0/frame_time.as_secs_f32());// + sleep_time.as_secs_f32())); } } } diff --git a/src/io/winit_window.rs b/src/io/winit_window.rs index 3b3623d..809734d 100644 --- a/src/io/winit_window.rs +++ b/src/io/winit_window.rs @@ -61,7 +61,7 @@ impl WinitWindow { //Since we can't move the EventLoop from one thread to another, we need to create it in the //right thread and then move the Window back to the main thread instead let cloned_name = name.clone(); - let (tx, rx) = mpsc::channel(); + let (tx, rx) = mpsc::sync_channel(1); let (tmp_tx, tmp_rx) = mpsc::sync_channel(1); let builder = thread::Builder::new().name(title.into()); //the EventLoop hijacks the thread so there is no need to join it later... @@ -92,23 +92,25 @@ impl WinitWindow { match event { Event::LoopDestroyed => { - let _ = tx.send(Key::Closed).unwrap(); + tx.send(Key::Closed).unwrap(); debug!("Closed EventLoop"); return; }, + Event::WindowEvent{window_id: _, event} => match event { event::WindowEvent::CloseRequested => { debug!("Close requested"); - let _ = tx.send(Key::Close).unwrap(); + tx.send(Key::Close).unwrap(); }, event::WindowEvent::CursorMoved{position, ..} => { - tx.send(Key::MouseMove{ + let _ = tx.try_send(Key::MouseMove{ x: position.x, y: position.y, - }).unwrap(); + }); }, _ => (), }, + Event::UserEvent(signal) => match signal { Signal::Exit => { debug!("Stopping input thread..."); @@ -118,6 +120,7 @@ impl WinitWindow { tx.send(Key::Test).unwrap(); }, }, + _ => (), }}) }); diff --git a/src/renderer/gpu.rs b/src/renderer/gpu.rs index 31fcc7f..5284502 100644 --- a/src/renderer/gpu.rs +++ b/src/renderer/gpu.rs @@ -88,6 +88,7 @@ where use gfx_hal::{ Instance, window::Surface, + adapter::DeviceType, }; // dry run to print all adapters for debug purposes @@ -103,7 +104,7 @@ where let adapter = instance .enumerate_adapters() .into_iter() - .find(|a| { + .filter(|a| { a.queue_families .iter() .any(|qf| @@ -113,7 +114,16 @@ where .all(|surface| surface.supports_queue_family(&qf) ))}) + .max_by_key(|adapter| { + match adapter.info.device_type { + DeviceType::DiscreteGpu => 4, + DeviceType::IntegratedGpu => 3, + DeviceType::VirtualGpu => 2, + DeviceType::Other => 1, + DeviceType::Cpu => 0, + }}) .ok_or("Could not find a graphical adapter")?; + info!("Selected adapter : {}", adapter.info.name); adapter From 15dfb5193cf93be7c7ba496678dff46f0a444d37 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 09:31:11 +0100 Subject: [PATCH 16/22] Testing Gitlab config with example CI file --- .gitlab-ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..efa1945 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,22 @@ +build-job: + stage: build + script: + - echo "Hello, $GITLAB_USER_LOGIN!" + +test-job1: + stage: test + script: + - echo "This job tests something" + +test-job2: + stage: test + script: + - echo "This job tests something, but takes more time than test-job1." + - echo "After the echo commands complete, it runs the sleep command for 20 seconds" + - echo "which simulates a test that runs 20 seconds longer than test-job1" + - sleep 20 + +deploy-prod: + stage: deploy + script: + - echo "This job deploys something from the $CI_COMMIT_BRANCH branch." From db54e2d2ef1a42e7ab4b5f937150b22013c14b4a Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 09:35:07 +0100 Subject: [PATCH 17/22] Testing CI solution for Rust --- .gitlab-ci.yml | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index efa1945..0ac3322 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,22 +1,6 @@ -build-job: - stage: build - script: - - echo "Hello, $GITLAB_USER_LOGIN!" - -test-job1: +stable:cargo: + image: rustdocker/rust:stable stage: test script: - - echo "This job tests something" - -test-job2: - stage: test - script: - - echo "This job tests something, but takes more time than test-job1." - - echo "After the echo commands complete, it runs the sleep command for 20 seconds" - - echo "which simulates a test that runs 20 seconds longer than test-job1" - - sleep 20 - -deploy-prod: - stage: deploy - script: - - echo "This job deploys something from the $CI_COMMIT_BRANCH branch." + - cargo test --verbose --jobs 1 + From fa2857c2ba5a6751c1d6e1f034e94eebd1d4b219 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 14:45:18 +0100 Subject: [PATCH 18/22] Added rustup commands --- .gitlab-ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0ac3322..83debee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,15 @@ -stable:cargo: - image: rustdocker/rust:stable +stages: + - build + - test + +stable:cargo:build: + stage: build + script: + - rustup toolchain install stable + - rustup default stable + - cargo build + +stable:cargo:test: stage: test script: - cargo test --verbose --jobs 1 From 82dc53d044f267dea89ab8dafad66524ccdce5cc Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 15:16:45 +0100 Subject: [PATCH 19/22] Added nightly coverage --- .gitlab-ci.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 83debee..45db404 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,6 +11,21 @@ stable:cargo:build: stable:cargo:test: stage: test + dependencies: [stable:cargo:build] script: - - cargo test --verbose --jobs 1 - + - cargo test --jobs 1 + +nightly:cargo:build: + stage: build + script: + - rustup toolchain install nightly + - rustup default nightly + - cargo build + allow_failure: true + +nightly:cargo:test: + stage: test + dependencies: [nightly:cargo:build] + script: + - cargo test --jobs 1 + allow_failure: true From ae4bf9efa0c4bee9c9fed78beff5282ee571596f Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 15:35:25 +0100 Subject: [PATCH 20/22] Improved job dependencies --- .gitlab-ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 45db404..69b6b5d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,8 +11,12 @@ stable:cargo:build: stable:cargo:test: stage: test - dependencies: [stable:cargo:build] + dependencies: + - stable:cargo:build + needs: + - stable:cargo:build script: + - rustup default stable - cargo test --jobs 1 nightly:cargo:build: @@ -25,7 +29,11 @@ nightly:cargo:build: nightly:cargo:test: stage: test - dependencies: [nightly:cargo:build] + dependencies: + - nightly:cargo:build + needs: + - nightly:cargo:build script: + - rustup default nightly - cargo test --jobs 1 allow_failure: true From becba709a9362c4027342ec7feb5fdc2ee79b305 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 15:42:21 +0100 Subject: [PATCH 21/22] Added doc generation to pipeline --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 69b6b5d..ee74388 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ stages: - build - test + - doc stable:cargo:build: stage: build @@ -37,3 +38,9 @@ nightly:cargo:test: - rustup default nightly - cargo test --jobs 1 allow_failure: true + +stable:cargo:doc: + stage: doc + needs: [] + script: + - cargo doc From fee8adb5d7ba44ad6e40e69af5df7452fa2cecc0 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Fri, 5 Feb 2021 15:55:24 +0100 Subject: [PATCH 22/22] Added rustc & cargo version display --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ee74388..49879e5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,7 @@ stable:cargo:build: script: - rustup toolchain install stable - rustup default stable + - rustc --version && cargo --version - cargo build stable:cargo:test: @@ -18,6 +19,7 @@ stable:cargo:test: - stable:cargo:build script: - rustup default stable + - rustc --version && cargo --version - cargo test --jobs 1 nightly:cargo:build: @@ -25,6 +27,7 @@ nightly:cargo:build: script: - rustup toolchain install nightly - rustup default nightly + - rustc --version && cargo --version - cargo build allow_failure: true @@ -36,6 +39,7 @@ nightly:cargo:test: - nightly:cargo:build script: - rustup default nightly + - rustc --version && cargo --version - cargo test --jobs 1 allow_failure: true