diff --git a/src/display/app.rs b/src/display/app.rs index c233f83..0d5fb1d 100644 --- a/src/display/app.rs +++ b/src/display/app.rs @@ -1,13 +1,15 @@ use crate::display::window::Window; -use crate::renderer::vulkan::VkRenderContext; +use crate::renderer::{vulkan::VkRenderContext, Renderable}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::window::WindowId; +use crate::scene::TriangleScene; pub struct App { window: Window, render_context: Option, + scene: Option>, } impl App { @@ -15,6 +17,18 @@ impl App { Self { window, render_context: None, + scene: None, + } + } + + pub fn set_scene(&mut self, mut scene: Box) { + let result = self.render_context.as_mut() + .ok_or_else(|| anyhow::anyhow!("No render context")) + .and_then(|render_context| render_context.init_scene(&mut scene)); + + match result { + Ok(_) => self.scene = Some(scene), + Err(err) => log::warn!("{err}"), } } } @@ -27,6 +41,9 @@ impl ApplicationHandler for App { .unwrap(); self.render_context = VkRenderContext::init(&self.window).ok(); + + let scene = TriangleScene::new(); + self.set_scene(Box::new(scene)); } fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { @@ -59,7 +76,7 @@ impl ApplicationHandler for App { if !event_loop.exiting() { match self.render_context.as_mut() { Some(render_context) => { - if let Err(error) = render_context.render() { + if let Err(error) = render_context.render(self.scene.as_ref()) { log::error!("Failed to render with render context : {}", error); event_loop.exit(); } diff --git a/src/main.rs b/src/main.rs index f75f835..2f48cfe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use winit::event_loop::{ControlFlow, EventLoop}; mod display; mod renderer; +mod scene; fn main() { env_logger::init(); diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 145c8fe..cca608a 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,7 +1,9 @@ +use std::sync::Arc; use ash::vk; pub mod vulkan; pub trait Renderable { - fn render(device: &vulkan::VkDevice, command_buffer: vk::CommandBuffer); + fn init(&mut self, device: &Arc, render_pass: &Arc) -> anyhow::Result<()>; + fn render(&self, device: &vulkan::VkDevice, swapchain: &vulkan::VkSwapchain, command_buffer: &vk::CommandBuffer) -> anyhow::Result<()>; } \ No newline at end of file diff --git a/src/renderer/vulkan/vk_command_pool.rs b/src/renderer/vulkan/vk_command_pool.rs index 977f871..c657e97 100644 --- a/src/renderer/vulkan/vk_command_pool.rs +++ b/src/renderer/vulkan/vk_command_pool.rs @@ -6,7 +6,7 @@ use std::sync::Arc; pub struct VkCommandPool { device: Arc, - pub(super) handle: vk::CommandPool, + pub handle: vk::CommandPool, } impl VkCommandPool { diff --git a/src/renderer/vulkan/vk_device.rs b/src/renderer/vulkan/vk_device.rs index ffcabcf..eaf73e4 100644 --- a/src/renderer/vulkan/vk_device.rs +++ b/src/renderer/vulkan/vk_device.rs @@ -5,9 +5,9 @@ use std::sync::Arc; pub struct VkDevice { instance: Arc, - pub(super) handle: ash::Device, - pub(super) swapchain_loader: ash::khr::swapchain::Device, - pub(super) queue_family_index: u32, + pub handle: ash::Device, + pub swapchain_loader: ash::khr::swapchain::Device, + pub queue_family_index: u32, // Arc not used because vk::Queue is destroyed with Device automatically // so any references of vk::Queue must be destroyed with VkDevice @@ -15,7 +15,7 @@ pub struct VkDevice { } impl VkDevice { - pub(super) fn new_graphics_device( + pub fn new_graphics_device( instance: &Arc, physical_device: &VkPhysicalDevice, queue_family_index: u32, @@ -64,11 +64,11 @@ impl VkDevice { }) } - pub(super) fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> { + pub fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> { self.queues.get(queue_index as usize) } - pub(super) fn create_command_pool( + pub fn create_command_pool( &self, info: &vk::CommandPoolCreateInfo, ) -> VkResult { @@ -77,18 +77,18 @@ impl VkDevice { unsafe { self.handle.create_command_pool(&info, None) } } - pub(super) fn allocate_command_buffers( + pub fn allocate_command_buffers( &self, info: &vk::CommandBufferAllocateInfo, ) -> VkResult> { unsafe { self.handle.allocate_command_buffers(&info) } } - pub(super) fn create_fence(&self, info: &vk::FenceCreateInfo) -> VkResult { + pub fn create_fence(&self, info: &vk::FenceCreateInfo) -> VkResult { unsafe { self.handle.create_fence(&info, None) } } - pub(super) fn create_semaphore( + pub fn create_semaphore( &self, info: &vk::SemaphoreCreateInfo, ) -> VkResult { diff --git a/src/renderer/vulkan/vk_fence.rs b/src/renderer/vulkan/vk_fence.rs index 5bbc52e..9fb71ff 100644 --- a/src/renderer/vulkan/vk_fence.rs +++ b/src/renderer/vulkan/vk_fence.rs @@ -5,7 +5,7 @@ use std::sync::Arc; pub struct VkFence { device: Arc, - pub(super) handle: vk::Fence, + pub handle: vk::Fence, } impl VkFence { diff --git a/src/renderer/vulkan/vk_framebuffer.rs b/src/renderer/vulkan/vk_framebuffer.rs index 21d2c4f..8486fb5 100644 --- a/src/renderer/vulkan/vk_framebuffer.rs +++ b/src/renderer/vulkan/vk_framebuffer.rs @@ -7,7 +7,7 @@ pub struct VkFramebuffer { image_view: Arc, render_pass: Arc, - pub(super) handle: vk::Framebuffer, + pub handle: vk::Framebuffer, } impl VkFramebuffer { diff --git a/src/renderer/vulkan/vk_graphics_pipeline.rs b/src/renderer/vulkan/vk_graphics_pipeline.rs index a979a2e..a9af298 100644 --- a/src/renderer/vulkan/vk_graphics_pipeline.rs +++ b/src/renderer/vulkan/vk_graphics_pipeline.rs @@ -7,8 +7,8 @@ pub struct VkGraphicsPipeline { device: Arc, render_pass: Arc, - pub(super) pipeline_layout: vk::PipelineLayout, - pub(super) pipeline: vk::Pipeline, + pub pipeline_layout: vk::PipelineLayout, + pub pipeline: vk::Pipeline, vertex_shader: VkShaderModule, fragment_shader: VkShaderModule, } diff --git a/src/renderer/vulkan/vk_instance.rs b/src/renderer/vulkan/vk_instance.rs index ddf520b..6f13f3c 100644 --- a/src/renderer/vulkan/vk_instance.rs +++ b/src/renderer/vulkan/vk_instance.rs @@ -7,9 +7,9 @@ use ash::{vk, Entry, Instance}; use std::ffi::{c_char, CStr, CString}; pub struct VkInstance { - pub(super) entry: Entry, - pub(super) handle: Instance, - pub(super) surface_loader: surface::Instance, + pub entry: Entry, + pub handle: Instance, + pub surface_loader: surface::Instance, } impl VkInstance { diff --git a/src/renderer/vulkan/vk_physical_device.rs b/src/renderer/vulkan/vk_physical_device.rs index e2a9d56..2edc8e3 100644 --- a/src/renderer/vulkan/vk_physical_device.rs +++ b/src/renderer/vulkan/vk_physical_device.rs @@ -3,7 +3,7 @@ use ash::vk; pub struct VkPhysicalDevice { // Vulkan properties - pub(super) handle: vk::PhysicalDevice, + pub handle: vk::PhysicalDevice, pub properties: vk::PhysicalDeviceProperties, pub features: vk::PhysicalDeviceFeatures, pub queue_family_properties: Vec, diff --git a/src/renderer/vulkan/vk_render_context.rs b/src/renderer/vulkan/vk_render_context.rs index 55fb4e8..aa39b39 100644 --- a/src/renderer/vulkan/vk_render_context.rs +++ b/src/renderer/vulkan/vk_render_context.rs @@ -4,6 +4,7 @@ use super::{ }; use ash::vk; use std::sync::Arc; +use crate::renderer::Renderable; pub struct VkRenderContext { instance: Arc, @@ -13,7 +14,7 @@ pub struct VkRenderContext { swapchain: Arc, render_pass: Arc, framebuffers: Vec>, - pipeline: Arc, + command_pool: VkCommandPool, command_buffers: Vec, image_available_semaphore: VkSemaphore, @@ -62,8 +63,6 @@ impl VkRenderContext { .create_framebuffers(&render_pass) .ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?; - let pipeline = Arc::new(VkGraphicsPipeline::new(&device, &render_pass)?); - let command_pool = VkCommandPool::new(&device)?; // Destroyed with command pool @@ -82,7 +81,6 @@ impl VkRenderContext { swapchain, render_pass, framebuffers, - pipeline, command_pool, command_buffers, @@ -93,7 +91,7 @@ impl VkRenderContext { }) } - pub fn render(&mut self) -> anyhow::Result<()> { + pub fn render(&mut self, scene: Option<&Box>) -> anyhow::Result<()> { unsafe { self.device.handle.wait_for_fences(&[self.in_flight_fence.handle], true, u64::MAX)? }; unsafe { self.device.handle.reset_fences(&[self.in_flight_fence.handle])? }; @@ -133,26 +131,9 @@ impl VkRenderContext { ); }; - unsafe { - self.device.handle.cmd_bind_pipeline( - command_buffer, - vk::PipelineBindPoint::GRAPHICS, - self.pipeline.pipeline, - ) - }; - - let viewport = vk::Viewport::default() - .width(self.swapchain.surface_resolution.width as f32) - .height(self.swapchain.surface_resolution.height as f32) - .max_depth(1.0); - - unsafe { self.device.handle.cmd_set_viewport(command_buffer, 0, &[viewport]) } - - let scissor = self.swapchain.surface_resolution.into(); - - unsafe { self.device.handle.cmd_set_scissor(command_buffer, 0, &[scissor]) } - - unsafe { self.device.handle.cmd_draw(command_buffer, 3, 1, 0, 0) }; + if let Some(scene) = scene { + scene.render(&self.device, &self.swapchain, &command_buffer)?; + } unsafe { self.device.handle.cmd_end_render_pass(command_buffer) }; @@ -204,6 +185,10 @@ impl VkRenderContext { unsafe { self.device.handle.device_wait_idle().unwrap() } } + pub fn init_scene(&self, scene: &mut Box) -> anyhow::Result<()> { + scene.init(&self.device, &self.render_pass) + } + fn update_swapchain(&mut self) -> anyhow::Result<()> { match Arc::get_mut(&mut self.swapchain) { Some(swapchain) => { diff --git a/src/renderer/vulkan/vk_render_pass.rs b/src/renderer/vulkan/vk_render_pass.rs index a37ab8c..e9819fe 100644 --- a/src/renderer/vulkan/vk_render_pass.rs +++ b/src/renderer/vulkan/vk_render_pass.rs @@ -6,7 +6,7 @@ use std::sync::Arc; pub struct VkRenderPass { device: Arc, - pub(super) handle: vk::RenderPass, + pub handle: vk::RenderPass, } impl VkRenderPass { diff --git a/src/renderer/vulkan/vk_semaphore.rs b/src/renderer/vulkan/vk_semaphore.rs index df5896f..facaf4e 100644 --- a/src/renderer/vulkan/vk_semaphore.rs +++ b/src/renderer/vulkan/vk_semaphore.rs @@ -5,7 +5,7 @@ use std::sync::Arc; pub struct VkSemaphore { device: Arc, - pub(super) handle: vk::Semaphore, + pub handle: vk::Semaphore, } impl VkSemaphore { diff --git a/src/renderer/vulkan/vk_shader_module.rs b/src/renderer/vulkan/vk_shader_module.rs index 11e927a..96ddcc5 100644 --- a/src/renderer/vulkan/vk_shader_module.rs +++ b/src/renderer/vulkan/vk_shader_module.rs @@ -6,7 +6,7 @@ use std::sync::Arc; pub struct VkShaderModule { device: Arc, - pub(super) handle: vk::ShaderModule, + pub handle: vk::ShaderModule, } impl VkShaderModule { diff --git a/src/renderer/vulkan/vk_surface.rs b/src/renderer/vulkan/vk_surface.rs index 788311a..9aace7c 100644 --- a/src/renderer/vulkan/vk_surface.rs +++ b/src/renderer/vulkan/vk_surface.rs @@ -13,7 +13,7 @@ pub struct SwapchainSupportDetails( pub struct VkSurface { instance: Arc, - pub(super) handle: vk::SurfaceKHR, + pub handle: vk::SurfaceKHR, } impl VkSurface { diff --git a/src/renderer/vulkan/vk_swapchain.rs b/src/renderer/vulkan/vk_swapchain.rs index e578d98..758574a 100644 --- a/src/renderer/vulkan/vk_swapchain.rs +++ b/src/renderer/vulkan/vk_swapchain.rs @@ -8,22 +8,22 @@ pub struct VkSwapchain { surface: Arc, device: Arc, - pub(super) handle: Option, + pub handle: Option, swapchain_support_details: SwapchainSupportDetails, - pub(super) desired_image_count: u32, - pub(super) surface_format: vk::SurfaceFormatKHR, - pub(super) surface_resolution: vk::Extent2D, - pub(super) new_requested_surface_resolution: Option, - pub(super) present_mode: vk::PresentModeKHR, - pub(super) pre_transform: vk::SurfaceTransformFlagsKHR, + pub desired_image_count: u32, + pub surface_format: vk::SurfaceFormatKHR, + pub surface_resolution: vk::Extent2D, + pub new_requested_surface_resolution: Option, + pub present_mode: vk::PresentModeKHR, + pub pre_transform: vk::SurfaceTransformFlagsKHR, - pub(super) present_images: Option>, - pub(super) present_image_views: Option>>, + pub present_images: Option>, + pub present_image_views: Option>>, } impl VkSwapchain { - pub(super) fn new( + pub fn new( window: &Window, surface: &Arc, device: &Arc, @@ -78,7 +78,7 @@ impl VkSwapchain { Ok(swapchain) } - pub(super) fn create_swapchain(&mut self) -> VkResult<()> { + pub fn create_swapchain(&mut self) -> VkResult<()> { if let Some(new_requested_surface_resolution) = self.new_requested_surface_resolution { self.surface_resolution = new_requested_surface_resolution; self.new_requested_surface_resolution = None; @@ -125,7 +125,7 @@ impl VkSwapchain { Ok(()) } - pub(super) fn create_framebuffers( + pub fn create_framebuffers( &self, render_pass: &Arc, ) -> Option>> { @@ -148,7 +148,7 @@ impl VkSwapchain { ) } - pub(super) fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> { + pub fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> { log::debug!("New resolution requested ({width}x{height})"); let chosen_extent = Self::choose_swapchain_extent( @@ -171,7 +171,7 @@ impl VkSwapchain { Ok(()) } - pub(super) fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> { + pub fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> { unsafe { self.device.swapchain_loader.acquire_next_image( self.handle.unwrap(), @@ -182,7 +182,7 @@ impl VkSwapchain { } } - pub(super) fn is_dirty(&self) -> bool { + pub fn is_dirty(&self) -> bool { self.new_requested_surface_resolution.is_some() } diff --git a/src/scene/mod.rs b/src/scene/mod.rs new file mode 100644 index 0000000..4b37d74 --- /dev/null +++ b/src/scene/mod.rs @@ -0,0 +1,2 @@ +mod triangle; +pub use triangle::Triangle as TriangleScene; \ No newline at end of file diff --git a/src/scene/triangle.rs b/src/scene/triangle.rs new file mode 100644 index 0000000..c256429 --- /dev/null +++ b/src/scene/triangle.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; +use ash::vk; +use crate::renderer::vulkan::{VkDevice, VkGraphicsPipeline, VkRenderPass, VkSwapchain}; +use crate::renderer::Renderable; +use ash::vk::CommandBuffer; + +pub struct Triangle { + pipeline: Option, +} + +impl Triangle { + pub fn new() -> Self { + Self { pipeline: None } + } +} + +impl Renderable for Triangle { + fn init(&mut self, device: &Arc, render_pass: &Arc) -> anyhow::Result<()> { + let pipeline = VkGraphicsPipeline::new(&device, &render_pass)?; + self.pipeline = Some(pipeline); + + Ok(()) + } + + fn render(&self, device: &VkDevice, swapchain: &VkSwapchain, command_buffer: &CommandBuffer) -> anyhow::Result<()> { + unsafe { + device.handle.cmd_bind_pipeline( + *command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline.as_ref().unwrap().pipeline, + ) + }; + + let viewport = vk::Viewport::default() + .width(swapchain.surface_resolution.width as f32) + .height(swapchain.surface_resolution.height as f32) + .max_depth(1.0); + + unsafe { device.handle.cmd_set_viewport(*command_buffer, 0, &[viewport]) } + + let scissor = swapchain.surface_resolution.into(); + + unsafe { device.handle.cmd_set_scissor(*command_buffer, 0, &[scissor]) } + + unsafe { device.handle.cmd_draw(*command_buffer, 3, 1, 0, 0) }; + + Ok(()) + } +} \ No newline at end of file