From f8359414328f5032edba36efd9cfe62f70acbb63 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 29 May 2025 00:17:21 +0200 Subject: [PATCH] app: Move render_pass into scene --- src/core/app.rs | 160 +++++++----------------- src/core/render/mod.rs | 1 - src/core/render/render_context.rs | 98 --------------- src/core/scene/context.rs | 82 ++++++++++++ src/core/{scene.rs => scene/manager.rs} | 25 +--- src/core/scene/mod.rs | 24 ++++ src/game/main_scene.rs | 127 ++++++++++++++----- 7 files changed, 250 insertions(+), 267 deletions(-) delete mode 100644 src/core/render/render_context.rs create mode 100644 src/core/scene/context.rs rename src/core/{scene.rs => scene/manager.rs} (59%) create mode 100644 src/core/scene/mod.rs diff --git a/src/core/app.rs b/src/core/app.rs index bcdb82d..5865cb1 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -1,22 +1,15 @@ use std::collections::HashMap; use std::sync::Arc; -use super::render::render_context::RenderContext; use super::render::vulkan_context::VulkanContext; +use super::scene::SceneContext; use crate::core::input::InputManager; use crate::core::scene::SceneManager; use crate::core::timer::Timer; use crate::game::main_scene::MainScene; -use egui_winit_vulkano::{Gui, GuiConfig, egui}; -use vulkano::command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, -}; -use vulkano::pipeline::graphics::viewport::Viewport; -use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; +use egui_winit_vulkano::{Gui, GuiConfig}; use vulkano::swapchain::PresentMode; -use vulkano::sync::GpuFuture; use vulkano_util::context::VulkanoContext; -use vulkano_util::renderer::VulkanoWindowRenderer; use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; @@ -27,28 +20,9 @@ pub struct App { vulkan_context: Arc, vulkano_windows: Arc, gui: HashMap, - clear_color: [f32; 3], - input_manager: InputManager, scene_manager: SceneManager, - timer: Timer, -} - -impl From<(&VulkanContext, &VulkanoWindowRenderer)> for RenderContext { - fn from((vulkan_context, renderer): (&VulkanContext, &VulkanoWindowRenderer)) -> Self { - RenderContext::new( - vulkan_context.vulkano_context().instance().clone(), - vulkan_context.vulkano_context().device().clone(), - vulkan_context.vulkano_context().graphics_queue().clone(), - vulkan_context.vulkano_context().compute_queue().clone(), - vulkan_context.vulkano_context().transfer_queue().cloned(), - vulkan_context.vulkano_context().memory_allocator().clone(), - vulkan_context.command_buffer_allocator().clone(), - vulkan_context.descriptor_set_allocator().clone(), - renderer.resolution(), - renderer.aspect_ratio(), - renderer.swapchain_format(), - ) - } + input_manager: Arc, + timer: Arc, } impl App { @@ -57,10 +31,9 @@ impl App { vulkan_context: Arc::new(VulkanContext::new(vulkano_context)), vulkano_windows: Arc::new(VulkanoWindows::default()), gui: HashMap::new(), - clear_color: [0.0, 0.0, 0.0], - input_manager, + input_manager: Arc::new(input_manager), scene_manager: SceneManager::new(), - timer: Timer::new(), + timer: Arc::new(Timer::new()), } } } @@ -109,7 +82,10 @@ impl ApplicationHandler for App { _device_id: winit::event::DeviceId, event: winit::event::DeviceEvent, ) { - self.input_manager.process_device_event(&event); + match Arc::get_mut(&mut self.input_manager) { + Some(input_manager) => input_manager.process_device_event(&event), + None => log::error!("Failed to get a mutable reference to the input manager"), + } } fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) { @@ -118,10 +94,12 @@ impl ApplicationHandler for App { .get_renderer_mut(id) .unwrap(); let gui = self.gui.get_mut(&id).unwrap(); - let render_context = RenderContext::from((self.vulkan_context.as_ref(), &*renderer)); if !gui.update(&event) { - self.input_manager.process_window_event(&event); + match Arc::get_mut(&mut self.input_manager) { + Some(input_manager) => input_manager.process_window_event(&event), + None => log::error!("Failed to get a mutable reference to the input manager"), + } } match event { @@ -136,86 +114,40 @@ impl ApplicationHandler for App { renderer.resize(); } WindowEvent::RedrawRequested => { - self.input_manager.update(); - self.timer.update(); - self.scene_manager.load_scene_if_not_loaded(&render_context); + match Arc::get_mut(&mut self.input_manager) { + Some(input_manager) => input_manager.update(), + None => log::error!("Failed to get a mutable reference to the input manager"), + } + match Arc::get_mut(&mut self.timer) { + Some(timer) => timer.update(), + None => log::error!("Failed to get a mutable reference to the timer"), + } + + let scene_context = SceneContext::from(( + &*renderer, + &self.vulkan_context, + &self.input_manager, + &self.timer, + )); + self.scene_manager.load_scene_if_not_loaded(&scene_context); + if let Some(scene) = self.scene_manager.current_scene_mut() { - scene.update(&render_context, &self.input_manager, &self.timer); + scene.update(&scene_context); + + let acquire_future = renderer.acquire(None, |_| {}).unwrap(); + let acquire_future = scene.render( + &renderer.swapchain_image_view(), + acquire_future, + &scene_context, + gui, + ); + match acquire_future { + Ok(future) => renderer.present(future, true), + Err(e) => { + log::error!("Error rendering scene: {}", e); + } + } } - - let acquire_future = renderer.acquire(None, |_| {}).unwrap(); - - let mut builder = AutoCommandBufferBuilder::primary( - self.vulkan_context.command_buffer_allocator().clone(), - self.vulkan_context - .vulkano_context() - .graphics_queue() - .queue_family_index(), - CommandBufferUsage::OneTimeSubmit, - ) - .unwrap(); - - { - let viewport = Viewport { - offset: [0.0, 0.0], - extent: renderer.resolution(), - depth_range: 0.0..=1.0, - }; - - builder - .begin_rendering(RenderingInfo { - color_attachments: vec![Some(RenderingAttachmentInfo { - load_op: AttachmentLoadOp::Clear, - store_op: AttachmentStoreOp::Store, - clear_value: Some(self.clear_color.into()), - ..RenderingAttachmentInfo::image_view( - renderer.swapchain_image_view().clone(), - ) - })], - ..Default::default() - }) - .unwrap() - .set_viewport(0, [viewport].into_iter().collect()) - .unwrap(); - } - - if let Some(scene) = self.scene_manager.current_scene() { - scene.render(&render_context, &mut builder); - } - - builder.end_rendering().unwrap(); - - let command_buffer = builder.build().unwrap(); - - let render_future = acquire_future - .then_execute( - self.vulkan_context - .vulkano_context() - .graphics_queue() - .clone(), - command_buffer, - ) - .unwrap(); - - gui.immediate_ui(|gui| { - let ctx = gui.context(); - - egui::Window::new("Informations") - .vscroll(true) - .show(&ctx, |ui| { - ui.label(format!("Resolution: {:?}", renderer.resolution())); - ui.color_edit_button_rgb(&mut self.clear_color); - - ui.label(format!("{:#?}", self.input_manager)); - - ui.label(format!("Delta time: {:?}", self.timer.delta_time())); - }); - }); - - let render_future = - gui.draw_on_image(render_future, renderer.swapchain_image_view()); - - renderer.present(render_future.boxed(), true); } _ => {} } diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs index a50c5da..07e4134 100644 --- a/src/core/render/mod.rs +++ b/src/core/render/mod.rs @@ -1,4 +1,3 @@ pub mod primitives; -pub mod render_context; pub mod texture; pub mod vulkan_context; diff --git a/src/core/render/render_context.rs b/src/core/render/render_context.rs deleted file mode 100644 index e9e34a1..0000000 --- a/src/core/render/render_context.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::sync::Arc; - -use vulkano::{ - command_buffer::allocator::StandardCommandBufferAllocator, - descriptor_set::allocator::StandardDescriptorSetAllocator, - device::{Device, Queue}, - format::Format, - instance::Instance, - memory::allocator::StandardMemoryAllocator, -}; - -pub struct RenderContext { - instance: Arc, - device: Arc, - graphics_queue: Arc, - compute_queue: Arc, - transfer_queue: Option>, - memory_allocator: Arc, - command_buffer_allocator: Arc, - descriptor_set_allocator: Arc, - window_size: [f32; 2], - aspect_ratio: f32, - swapchain_format: Format, -} - -impl RenderContext { - pub fn new( - instance: Arc, - device: Arc, - graphics_queue: Arc, - compute_queue: Arc, - transfer_queue: Option>, - memory_allocator: Arc, - command_buffer_allocator: Arc, - descriptor_set_allocator: Arc, - window_size: [f32; 2], - aspect_ratio: f32, - swapchain_format: Format, - ) -> Self { - Self { - instance, - device, - graphics_queue, - compute_queue, - transfer_queue, - memory_allocator, - command_buffer_allocator, - descriptor_set_allocator, - window_size, - aspect_ratio, - swapchain_format, - } - } - - pub fn instance(&self) -> &Arc { - &self.instance - } - - pub fn device(&self) -> &Arc { - &self.device - } - - pub fn graphics_queue(&self) -> &Arc { - &self.graphics_queue - } - - pub fn compute_queue(&self) -> &Arc { - &self.compute_queue - } - - pub fn transfer_queue(&self) -> Option<&Arc> { - self.transfer_queue.as_ref() - } - - pub fn memory_allocator(&self) -> &Arc { - &self.memory_allocator - } - - pub fn command_buffer_allocator(&self) -> &Arc { - &self.command_buffer_allocator - } - - pub fn descriptor_set_allocator(&self) -> &Arc { - &self.descriptor_set_allocator - } - - pub fn window_size(&self) -> &[f32; 2] { - &self.window_size - } - - pub fn aspect_ratio(&self) -> f32 { - self.aspect_ratio - } - - pub fn swapchain_format(&self) -> Format { - self.swapchain_format - } -} diff --git a/src/core/scene/context.rs b/src/core/scene/context.rs new file mode 100644 index 0000000..028d612 --- /dev/null +++ b/src/core/scene/context.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; + +use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, + descriptor_set::allocator::StandardDescriptorSetAllocator, + device::{Device, Queue}, + format::Format, + instance::Instance, + memory::allocator::StandardMemoryAllocator, +}; +use vulkano_util::renderer::VulkanoWindowRenderer; + +use crate::core::{input::InputManager, render::vulkan_context::VulkanContext, timer::Timer}; + +pub struct SceneContext { + pub instance: Arc, + pub device: Arc, + pub graphics_queue: Arc, + pub compute_queue: Arc, + pub transfer_queue: Option>, + pub memory_allocator: Arc, + pub command_buffer_allocator: Arc, + pub descriptor_set_allocator: Arc, + pub window_size: [f32; 2], + pub aspect_ratio: f32, + pub swapchain_format: Format, + pub input_manager: Arc, + pub timer: Arc, +} + +impl + From<( + &VulkanoWindowRenderer, + &Arc, + &Arc, + &Arc, + )> for SceneContext +{ + fn from( + (renderer, vulkan_context, input_manager, timer): ( + &VulkanoWindowRenderer, + &Arc, + &Arc, + &Arc, + ), + ) -> Self { + let (command_buffer_allocator, descriptor_set_allocator) = { + ( + vulkan_context.command_buffer_allocator().clone(), + vulkan_context.descriptor_set_allocator().clone(), + ) + }; + + let (instance, device, graphics_queue, compute_queue, transfer_queue, memory_allocator) = { + let vulkan_context = vulkan_context.vulkano_context(); + ( + vulkan_context.instance().clone(), + vulkan_context.device().clone(), + vulkan_context.graphics_queue().clone(), + vulkan_context.compute_queue().clone(), + vulkan_context.transfer_queue().cloned(), + vulkan_context.memory_allocator().clone(), + ) + }; + + Self { + instance, + device, + graphics_queue, + compute_queue, + transfer_queue, + memory_allocator, + command_buffer_allocator, + descriptor_set_allocator, + window_size: renderer.window_size(), + aspect_ratio: renderer.aspect_ratio(), + swapchain_format: renderer.swapchain_format(), + input_manager: input_manager.clone(), + timer: timer.clone(), + } + } +} diff --git a/src/core/scene.rs b/src/core/scene/manager.rs similarity index 59% rename from src/core/scene.rs rename to src/core/scene/manager.rs index 9717117..8e25a74 100644 --- a/src/core/scene.rs +++ b/src/core/scene/manager.rs @@ -1,23 +1,4 @@ -use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; - -use super::{input::InputManager, render::render_context::RenderContext, timer::Timer}; - -pub trait Scene { - fn loaded(&self) -> bool; - fn load(&mut self, render_context: &RenderContext); - fn update( - &mut self, - render_context: &RenderContext, - input_manager: &InputManager, - timer: &Timer, - ); - fn render( - &self, - render_context: &RenderContext, - builder: &mut AutoCommandBufferBuilder, - ); - fn unload(&mut self); -} +use super::{Scene, SceneContext}; pub struct SceneManager { current_scene: Option>, @@ -30,10 +11,10 @@ impl SceneManager { } } - pub fn load_scene_if_not_loaded(&mut self, render_context: &RenderContext) { + pub fn load_scene_if_not_loaded(&mut self, scene_context: &SceneContext) { if let Some(current_scene) = self.current_scene.as_mut() { if !current_scene.loaded() { - current_scene.load(render_context); + current_scene.load(scene_context); } } } diff --git a/src/core/scene/mod.rs b/src/core/scene/mod.rs new file mode 100644 index 0000000..dc97ece --- /dev/null +++ b/src/core/scene/mod.rs @@ -0,0 +1,24 @@ +use std::{error::Error, sync::Arc}; + +use egui_winit_vulkano::Gui; +use vulkano::{image::view::ImageView, sync::GpuFuture}; + +mod context; +pub use context::SceneContext; + +mod manager; +pub use manager::SceneManager; + +pub trait Scene { + fn loaded(&self) -> bool; + fn load(&mut self, scene_context: &SceneContext); + fn update(&mut self, scene_context: &SceneContext); + fn render( + &mut self, + image_view: &Arc, + acquire_future: Box, + scene_context: &SceneContext, + gui: &mut Gui, + ) -> Result, Box>; + fn unload(&mut self); +} diff --git a/src/game/main_scene.rs b/src/game/main_scene.rs index c3d08ca..3000746 100644 --- a/src/game/main_scene.rs +++ b/src/game/main_scene.rs @@ -1,13 +1,20 @@ -use crate::core::input::InputManager; +use std::{error::Error, sync::Arc}; + use crate::core::render::primitives::camera::Camera; -use crate::core::render::render_context::RenderContext; use crate::core::render::texture::Texture; use crate::core::scene::Scene; -use crate::core::timer::Timer; +use crate::core::scene::SceneContext; +use egui_winit_vulkano::{Gui, egui}; use glam::{Mat4, Vec3}; -use vulkano::command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, - PrimaryCommandBufferAbstract, +use vulkano::{ + command_buffer::{ + AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract, + RenderingAttachmentInfo, RenderingInfo, + }, + image::view::ImageView, + pipeline::graphics::viewport::Viewport, + render_pass::{AttachmentLoadOp, AttachmentStoreOp}, + sync::GpuFuture, }; use super::assets::square::Square; @@ -29,11 +36,11 @@ impl Scene for MainScene { self.state.is_some() } - fn load(&mut self, render_context: &RenderContext) { + fn load(&mut self, scene_context: &SceneContext) { let square = Square::new( - render_context.device(), - render_context.memory_allocator(), - render_context.swapchain_format(), + &scene_context.device, + &scene_context.memory_allocator, + scene_context.swapchain_format, ) .unwrap(); @@ -45,22 +52,22 @@ impl Scene for MainScene { ), Mat4::perspective_rh_gl( std::f32::consts::FRAC_PI_2, - render_context.aspect_ratio(), + scene_context.aspect_ratio, 0.01, 100.0, ), ); let mut uploads = AutoCommandBufferBuilder::primary( - render_context.command_buffer_allocator().clone(), - render_context.graphics_queue().queue_family_index(), + scene_context.command_buffer_allocator.clone(), + scene_context.graphics_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) .unwrap(); let texture = Texture::from_file( - render_context.device(), - render_context.memory_allocator(), + &scene_context.device, + &scene_context.memory_allocator, &mut uploads, "res/textures/wooden-crate.jpg", ) @@ -69,7 +76,7 @@ impl Scene for MainScene { let _ = uploads .build() .unwrap() - .execute(render_context.graphics_queue().clone()) + .execute(scene_context.graphics_queue.clone()) .unwrap(); self.state = Some(MainSceneState { @@ -80,43 +87,99 @@ impl Scene for MainScene { }); } - fn update( - &mut self, - render_context: &RenderContext, - input_manager: &InputManager, - timer: &Timer, - ) { + fn update(&mut self, scene_context: &SceneContext) { let state = self.state.as_mut().unwrap(); - state.camera.update(input_manager, timer, state.speed, 10.0); + state.camera.update( + &scene_context.input_manager, + &scene_context.timer, + state.speed, + 10.0, + ); state.camera.set_projection(Mat4::perspective_rh_gl( std::f32::consts::FRAC_PI_2, - render_context.aspect_ratio(), + scene_context.aspect_ratio, 0.01, 100.0, )); } fn render( - &self, - render_context: &RenderContext, - builder: &mut AutoCommandBufferBuilder, - ) { + &mut self, + image_view: &Arc, + acquire_future: Box, + scene_context: &SceneContext, + gui: &mut Gui, + ) -> Result, Box> { let state = self.state.as_ref().unwrap(); + + let mut builder = AutoCommandBufferBuilder::primary( + scene_context.command_buffer_allocator.clone(), + scene_context.graphics_queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + )?; + + { + let viewport = Viewport { + offset: [0.0, 0.0], + extent: scene_context.window_size, + depth_range: 0.0..=1.0, + }; + + builder + .begin_rendering(RenderingInfo { + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), + ..RenderingAttachmentInfo::image_view(image_view.clone()) + })], + ..Default::default() + })? + .set_viewport(0, [viewport].into_iter().collect())?; + } + let camera_uniform = state .camera - .create_buffer(render_context.memory_allocator()) - .unwrap(); + .create_buffer(&scene_context.memory_allocator)?; state .square .render( - builder, - render_context.descriptor_set_allocator(), + &mut builder, + &scene_context.descriptor_set_allocator, &camera_uniform, &state.texture, ) .unwrap(); + + builder.end_rendering()?; + + let command_buffer = builder.build()?; + + let render_future = + acquire_future.then_execute(scene_context.graphics_queue.clone(), command_buffer)?; + + gui.immediate_ui(|gui| { + let ctx = gui.context(); + + egui::Window::new("Informations") + .vscroll(true) + .show(&ctx, |ui| { + ui.label(format!("Resolution: {:?}", scene_context.window_size)); + + ui.label(format!("{:#?}", scene_context.input_manager)); + + ui.label(format!( + "Delta time: {:?}", + scene_context.timer.delta_time() + )); + }); + }); + + let render_future = gui.draw_on_image(render_future, image_view.clone()); + + Ok(render_future) } fn unload(&mut self) {}