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 } +} +