diff --git a/crates/engine_render/src/lib.rs b/crates/engine_render/src/lib.rs index f42013e..ccbc39d 100644 --- a/crates/engine_render/src/lib.rs +++ b/crates/engine_render/src/lib.rs @@ -6,7 +6,7 @@ use bevy_ecs::{ }; use engine_vulkan::{ VulkanCommandBufferAllocator, VulkanDescriptorSetAllocator, VulkanDevice, VulkanGraphicsQueue, - VulkanMemoryAllocator, + VulkanInstance, VulkanMemoryAllocator, }; use engine_window::raw_handle::WindowWrapper; use window::WindowRenderPlugin; @@ -31,7 +31,7 @@ impl Render { let mut schedule = Schedule::new(Self); - schedule.configure_sets((Prepare, Queue, Render, Present).chain()); + schedule.configure_sets((ManageViews, Prepare, Queue, Render, Present).chain()); schedule } @@ -49,6 +49,7 @@ impl Plugin for RenderPlugin { let world = app.world(); world.get_resource::().is_some() + && world.get_resource::().is_some() && world.get_resource::().is_some() && world.get_resource::().is_some() && world.get_resource::().is_some() @@ -71,10 +72,6 @@ impl Plugin for RenderPlugin { app.add_plugins(WindowRenderPlugin); } - - fn cleanup(&self, app: &mut App) { - app.remove_sub_app(RenderApp); - } } fn extract_app_resources(world: &mut World, render_world: &mut World) { @@ -82,6 +79,10 @@ fn extract_app_resources(world: &mut World, render_world: &mut World) { .get_resource::() .expect("Failed to get WindowWrapper. Check is WindowPlugin is added before RenderPlugin."); + let vulkan_instance = world.get_resource::().expect( + "Failed to get Vulkan instance. Check is VulkanPlugin is added before RenderPlugin.", + ); + let vulkan_device = world .get_resource::() .expect("Failed to get Vulkan device. Check is VulkanPlugin is added before RenderPlugin."); @@ -102,6 +103,7 @@ fn extract_app_resources(world: &mut World, render_world: &mut World) { .get_resource::() .expect("Failed to get Vulkan descriptor set allocator. Check is VulkanPlugin is added before RenderPlugin."); + render_world.insert_resource(vulkan_instance.clone()); render_world.insert_resource(vulkan_device.clone()); render_world.insert_resource(vulkan_graphics_queue.clone()); render_world.insert_resource(vulkan_memory_allocator.clone()); diff --git a/crates/engine_render/src/window/mod.rs b/crates/engine_render/src/window/mod.rs index bcb3ea6..9af4184 100644 --- a/crates/engine_render/src/window/mod.rs +++ b/crates/engine_render/src/window/mod.rs @@ -1,13 +1,21 @@ use std::sync::Arc; use bevy_app::{App, Plugin}; -use bevy_ecs::resource::Resource; +use bevy_ecs::{ + resource::Resource, + schedule::IntoScheduleConfigs, + system::{Res, ResMut}, +}; +use engine_vulkan::{VulkanDevice, VulkanInstance}; +use engine_window::raw_handle::WindowWrapper; use vulkano::{ - image::view::ImageView, pipeline::graphics::viewport::Viewport, swapchain::Swapchain, - sync::GpuFuture, + image::{Image, ImageUsage, view::ImageView}, + pipeline::graphics::viewport::Viewport, + swapchain::{Surface, Swapchain, SwapchainCreateInfo}, + sync::{self, GpuFuture}, }; -use crate::RenderApp; +use super::{Render, RenderApp, RenderSystems}; pub struct WindowSurfaceData { pub swapchain: Arc, @@ -31,5 +39,186 @@ impl Plugin for WindowRenderPlugin { .expect("Failed to get RenderApp. Check is RenderPlugin is added."); render_app.init_resource::(); + + render_app.add_systems( + Render, + create_window_surface + .in_set(RenderSystems::ManageViews) + .run_if(need_create_window_surface) + .before(need_update_window_surface), + ); + + render_app.add_systems( + Render, + update_window_surface + .in_set(RenderSystems::ManageViews) + .run_if(need_update_window_surface), + ); } } + +fn need_create_window_surface(window_surface: Res) -> bool { + window_surface.surface.is_none() +} + +fn create_window_surface( + mut window_surface: ResMut, + window_handle: Res, + vulkan_instance: Res, + vulkan_device: Res, +) { + let window_size = window_handle.0.inner_size(); + + let surface = Surface::from_window(vulkan_instance.0.clone(), window_handle.0.clone()) + .expect("Failed to create surface"); + log::debug!("Surface created"); + + let (swapchain, images) = { + let surface_capabilities = vulkan_device + .0 + .physical_device() + .surface_capabilities(&surface, Default::default()) + .unwrap(); + + let (image_format, _) = vulkan_device + .0 + .physical_device() + .surface_formats(&surface, Default::default()) + .unwrap()[0]; + + Swapchain::new( + vulkan_device.0.clone(), + surface, + SwapchainCreateInfo { + // 2 because with some graphics driver, it crash on fullscreen because fullscreen need to min image to works. + min_image_count: surface_capabilities.min_image_count.max(2), + image_format, + image_extent: window_size.into(), + image_usage: ImageUsage::COLOR_ATTACHMENT, + composite_alpha: surface_capabilities + .supported_composite_alpha + .into_iter() + .next() + .unwrap(), + + ..Default::default() + }, + ) + .unwrap() + }; + log_swapchain_info(&swapchain, false); + + let attachment_image_views = window_size_dependent_setup(&images); + + let viewport = Viewport { + offset: [0.0, 0.0], + extent: window_size.into(), + depth_range: 0.0..=1.0, + }; + log_viewport_info(&viewport, false); + + let recreate_swapchain = false; + let previous_frame_end = Some(sync::now(vulkan_device.0.clone()).boxed_send_sync()); + + window_surface.surface = Some(WindowSurfaceData { + swapchain, + attachment_image_views, + viewport, + recreate_swapchain, + previous_frame_end, + }); +} + +fn window_size_dependent_setup(images: &[Arc]) -> Vec> { + images + .iter() + .map(|image| ImageView::new_default(image.clone()).unwrap()) + .collect::>() +} + +fn need_update_window_surface(window_surface: Res) -> bool { + match &window_surface.surface { + Some(surface) => surface.recreate_swapchain, + None => false, + } +} + +fn update_window_surface( + mut window_surface: ResMut, + window_handle: Res, +) { + if window_surface.surface.is_none() { + return; + } + + let window_surface = window_surface.surface.as_mut().unwrap(); + + if !window_surface.recreate_swapchain { + return; + } + + let window_size = window_handle.0.inner_size(); + let (new_swapchain, new_images) = window_surface + .swapchain + .recreate(SwapchainCreateInfo { + image_extent: window_size.into(), + ..window_surface.swapchain.create_info() + }) + .expect("Failed to recreate swapchain"); + + window_surface.swapchain = new_swapchain; + window_surface.attachment_image_views = window_size_dependent_setup(&new_images); + window_surface.viewport.extent = window_size.into(); + window_surface.recreate_swapchain = false; + + log_swapchain_info(&window_surface.swapchain, true); + log_viewport_info(&window_surface.viewport, true); +} + +fn log_swapchain_info(swapchain: &Swapchain, recreate_swapchain: bool) { + if recreate_swapchain { + log::debug!("Swapchain recreated"); + } else { + log::debug!("Swapchain created"); + } + log::debug!( + "\tMin image count: {}", + swapchain.create_info().min_image_count + ); + log::debug!("\tImage format: {:?}", swapchain.create_info().image_format); + log::debug!("\tImage extent: {:?}", swapchain.create_info().image_extent); + log::debug!("\tImage usage: {:?}", swapchain.create_info().image_usage); + log::debug!( + "\tComposite alpha: {:?}", + swapchain.create_info().composite_alpha + ); + log::debug!("\tPresent mode: {:?}", swapchain.create_info().present_mode); + log::debug!( + "\tImage sharing: {:?}", + swapchain.create_info().image_sharing + ); + log::debug!( + "\tPre transform: {:?}", + swapchain.create_info().pre_transform + ); + log::debug!( + "\tComposite alpha: {:?}", + swapchain.create_info().composite_alpha + ); + log::debug!("\tPresent mode: {:?}", swapchain.create_info().present_mode); + log::debug!( + "\tFull screen exclusive: {:?}", + swapchain.create_info().full_screen_exclusive + ); +} + +fn log_viewport_info(viewport: &Viewport, recreate_viewport: bool) { + if recreate_viewport { + log::debug!("Viewport recreated"); + } else { + log::debug!("Viewport created"); + } + log::debug!("\tOffset: {:?}", viewport.offset); + log::debug!("\tExtent: {:?}", viewport.extent); + log::debug!("\tDepth range: {:?}", viewport.depth_range); +} diff --git a/crates/engine_vulkan/src/lib.rs b/crates/engine_vulkan/src/lib.rs index 65e9349..4f5129b 100644 --- a/crates/engine_vulkan/src/lib.rs +++ b/crates/engine_vulkan/src/lib.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use bevy_ecs::resource::Resource; -use engine_window::raw_handle::WindowWrapper; use utils::{device::create_and_insert_device, instance::create_and_insert_instance}; use vulkano::{ command_buffer::allocator::StandardCommandBufferAllocator, @@ -10,12 +9,10 @@ use vulkano::{ instance::Instance, memory::allocator::StandardMemoryAllocator, }; -use window_render_context::WindowRenderContext; use bevy_app::{App, Plugin}; mod utils; -mod window_render_context; #[derive(Resource, Clone)] pub struct VulkanInstance(pub Arc); diff --git a/crates/engine_vulkan/src/window_render_context.rs b/crates/engine_vulkan/src/window_render_context.rs deleted file mode 100644 index 95b3d90..0000000 --- a/crates/engine_vulkan/src/window_render_context.rs +++ /dev/null @@ -1,125 +0,0 @@ -use bevy_app::App; -use bevy_ecs::resource::Resource; -use engine_window::raw_handle::WindowWrapper; -use std::sync::Arc; -use vulkano::image::view::ImageView; -use vulkano::image::{Image, ImageUsage}; -use vulkano::pipeline::graphics::viewport::Viewport; -use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; -use vulkano::sync::{self, GpuFuture}; -use vulkano::{Validated, VulkanError}; -use winit::window::Window; - -use crate::{VulkanDevice, VulkanInstance}; - -#[derive(Resource)] -pub struct WindowRenderContext { - pub window: Arc, - pub swapchain: Arc, - pub attachment_image_views: Vec>, - pub viewport: Viewport, - pub recreate_swapchain: bool, - pub previous_frame_end: Option>, -} - -impl From<&App> for WindowRenderContext { - fn from(app: &App) -> Self { - let world = app.world(); - let window_handle = world - .get_resource::() - .expect("Failed to find window handle"); - let vulkan_instance = world - .get_resource::() - .expect("Failed to find vulkan instance"); - let vulkan_device = world - .get_resource::() - .expect("Failed to find vulkan device"); - - let window_size = window_handle.0.inner_size(); - - let surface = Surface::from_window(vulkan_instance.0.clone(), window_handle.0.clone()) - .expect("Failed to create surface"); - - let (swapchain, images) = { - let surface_capabilities = vulkan_device - .0 - .physical_device() - .surface_capabilities(&surface, Default::default()) - .unwrap(); - - let (image_format, _) = vulkan_device - .0 - .physical_device() - .surface_formats(&surface, Default::default()) - .unwrap()[0]; - - Swapchain::new( - vulkan_device.0.clone(), - surface, - SwapchainCreateInfo { - // 2 because with some graphics driver, it crash on fullscreen because fullscreen need to min image to works. - min_image_count: surface_capabilities.min_image_count.max(2), - image_format, - image_extent: window_size.into(), - image_usage: ImageUsage::COLOR_ATTACHMENT, - composite_alpha: surface_capabilities - .supported_composite_alpha - .into_iter() - .next() - .unwrap(), - - ..Default::default() - }, - ) - .unwrap() - }; - - let attachment_image_views = window_size_dependent_setup(&images); - - let viewport = Viewport { - offset: [0.0, 0.0], - extent: window_size.into(), - depth_range: 0.0..=1.0, - }; - - let recreate_swapchain = false; - let previous_frame_end = Some(sync::now(vulkan_device.0.clone()).boxed_send_sync()); - - Self { - window: window_handle.0.clone(), - swapchain, - attachment_image_views, - viewport, - recreate_swapchain, - previous_frame_end, - } - } -} - -impl WindowRenderContext { - pub fn update_swapchain(&mut self) -> Result<(), Validated> { - if !self.recreate_swapchain { - return Ok(()); - } - - let window_size = self.window.inner_size(); - let (new_swapchain, new_images) = self.swapchain.recreate(SwapchainCreateInfo { - image_extent: window_size.into(), - ..self.swapchain.create_info() - })?; - - self.swapchain = new_swapchain; - self.attachment_image_views = window_size_dependent_setup(&new_images); - self.viewport.extent = window_size.into(); - self.recreate_swapchain = false; - - Ok(()) - } -} - -fn window_size_dependent_setup(images: &[Arc]) -> Vec> { - images - .iter() - .map(|image| ImageView::new_default(image.clone()).unwrap()) - .collect::>() -} diff --git a/src/game/mod.rs b/src/game/mod.rs index 9c5b547..e04b2a7 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -33,13 +33,4 @@ pub fn init(app: &mut App) { VulkanPlugin { vulkan_config }, RenderPlugin, )); - - // app.get_sub_app_mut(RenderApp) - // .expect("Failed to get RenderApp. Check is RenderPlugin is added.") - // .add_systems(Render, test_system.in_set(RenderSystems::Prepare)); } - -// fn test_system(vulkan_device: Res, vulkan_graphics_queue: Res) { -// log::trace!("vulkan_device: {:?}", vulkan_device.0); -// log::trace!("vulkan_graphics_queue: {:?}", vulkan_graphics_queue.0); -// }