diff --git a/src/display/app.rs b/src/display/app.rs index 5c30801..129422f 100644 --- a/src/display/app.rs +++ b/src/display/app.rs @@ -1,9 +1,9 @@ +use crate::display::window::Window; +use crate::vulkan::VkRenderContext; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; -use winit::window::{WindowId}; -use crate::display::window::Window; -use crate::vulkan::VkRenderContext; +use winit::window::WindowId; pub struct App { window: Window, @@ -34,7 +34,29 @@ impl ApplicationHandler for App { log::debug!("The close button was pressed; stopping"); event_loop.exit(); } - _ => self.window.window_event(event_loop, id, event), + WindowEvent::Resized(size) => { + match self.render_context.as_mut() { + Some(render_context) => { + if let Err(error) = render_context.update_resolution(size.width, size.height) { + log::error!("Failed to update resolution of render context : {}", error); + } + } + None => log::warn!("Window resized but no render context found") + }; + } + WindowEvent::RedrawRequested => { + match self.render_context.as_mut() { + Some(render_context) => { + if let Err(error) = render_context.render() { + log::error!("Failed to render with render context : {}", error); + } + } + None => log::warn!("Window resized but no render context found") + }; + + self.window.request_redraw(); + } + _ => {} } } } diff --git a/src/display/window.rs b/src/display/window.rs index e6cf12f..e5048cd 100644 --- a/src/display/window.rs +++ b/src/display/window.rs @@ -6,7 +6,7 @@ use winit::window::WindowId; pub struct Window { handle: Option, - window_attributes: winit::window::WindowAttributes + window_attributes: winit::window::WindowAttributes, } impl Window { @@ -49,20 +49,15 @@ impl Window { pub fn handle(&self) -> Option<&winit::window::Window> { self.handle.as_ref() } - + pub fn size(&self) -> Option { self.window_attributes.inner_size } - pub fn window_event(&mut self, _event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::RedrawRequested => { - match self.handle.as_ref() { - Some(window) => window.request_redraw(), - None => log::warn!("Redraw requested but no window found") - } - } - _ => (), + pub fn request_redraw(&self) { + match self.handle.as_ref() { + Some(window) => window.request_redraw(), + None => log::warn!("Redraw requested but no window found") } } } diff --git a/src/main.rs b/src/main.rs index 66299aa..309a2f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,12 +10,11 @@ fn main() { let window_attributes = winit::window::Window::default_attributes() .with_title("Rust ASH Test") - .with_visible(true) .with_inner_size(winit::dpi::LogicalSize::new( f64::from(800), f64::from(600), )); - + let window = display::Window::new(window_attributes); let mut app = display::App::new(window); diff --git a/src/vulkan/vk_device.rs b/src/vulkan/vk_device.rs index f0fd6ca..8c445ad 100644 --- a/src/vulkan/vk_device.rs +++ b/src/vulkan/vk_device.rs @@ -1,13 +1,14 @@ -use ash::vk; use crate::vulkan::{VkInstance, VkPhysicalDevice}; +use ash::prelude::VkResult; +use ash::vk; pub struct VkDevice { - pub(crate) handle: ash::Device, - queue_family_index: u32 + pub(super) handle: ash::Device, + queue_family_index: u32, } impl VkDevice { - pub fn new_graphics_device( + pub(super) fn new_graphics_device( instance: &VkInstance, physical_device: &VkPhysicalDevice, queue_family_index: u32, @@ -37,15 +38,55 @@ impl VkDevice { Ok(Self { handle: device, - queue_family_index + queue_family_index, }) } - - pub fn get_device_queue(&self, queue_index: u32) -> vk::Queue { + + pub(super) fn get_device_queue(&self, queue_index: u32) -> vk::Queue { unsafe { self.handle.get_device_queue(self.queue_family_index, queue_index) } } + + pub(super) fn create_image_view(&self, image: vk::Image, surface_format: vk::SurfaceFormatKHR) -> VkResult { + let create_view_info = vk::ImageViewCreateInfo::default() + .view_type(vk::ImageViewType::TYPE_2D) + .format(surface_format.format) + .components(vk::ComponentMapping { + r: vk::ComponentSwizzle::R, + g: vk::ComponentSwizzle::G, + b: vk::ComponentSwizzle::B, + a: vk::ComponentSwizzle::A, + }) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: 1, + base_array_layer: 0, + layer_count: 1, + }) + .image(image); + + unsafe { self.handle.create_image_view(&create_view_info, None) } + } + + pub(super) fn create_command_pool(&self, info: &vk::CommandPoolCreateInfo) -> VkResult { + let info = info.queue_family_index(self.queue_family_index); + + unsafe { self.handle.create_command_pool(&info, None) } + } + + pub(super) 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 { + unsafe { self.handle.create_fence(&info, None) } + } + + pub(super) fn create_semaphore(&self, info: &vk::SemaphoreCreateInfo) -> VkResult { + unsafe { self.handle.create_semaphore(&info, None) } + } } impl Drop for VkDevice { diff --git a/src/vulkan/vk_render_context.rs b/src/vulkan/vk_render_context.rs index cc47472..2257988 100644 --- a/src/vulkan/vk_render_context.rs +++ b/src/vulkan/vk_render_context.rs @@ -1,11 +1,28 @@ use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain}; +use ash::vk; use ash::vk::QueueFlags; pub struct VkRenderContext { instance: VkInstance, surface: VkSurface, device: VkDevice, + swapchain: VkSwapchain, + present_images: Vec, + present_image_views: Vec, + + present_queue: vk::Queue, + + pool: vk::CommandPool, + + setup_command_buffer: vk::CommandBuffer, + draw_command_buffer: vk::CommandBuffer, + + draw_commands_reuse_fence: vk::Fence, + setup_commands_reuse_fence: vk::Fence, + + present_complete_semaphore: vk::Semaphore, + rendering_complete_semaphore: vk::Semaphore, } impl VkRenderContext { @@ -28,20 +45,134 @@ impl VkRenderContext { let device = VkDevice::new_graphics_device(&instance, &physical_device, queue_family_index) .expect("Unable to create device"); - let mut swapchain = surface.create_swapchain( + let swapchain = surface.create_swapchain( &window, &instance, &device, &physical_device, ).expect("Unable to create swapchain"); - // let present_queue = device.get_device_queue(0); + let present_images = swapchain.get_swapchain_images() + .expect("Failed to get present images"); + let present_image_views = present_images + .iter() + .map(|i| { + device.create_image_view(*i, swapchain.surface_format) + .expect("Failed to create image view") + }) + .collect::>(); + + let present_queue = device.get_device_queue(0); + + let pool_create_info = vk::CommandPoolCreateInfo::default() + .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER); + + let pool = device.create_command_pool(&pool_create_info) + .expect("Failed to create command pool"); + + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::default() + .command_buffer_count(2) + .command_pool(pool) + .level(vk::CommandBufferLevel::PRIMARY); + + let command_buffers = device + .allocate_command_buffers(&command_buffer_allocate_info) + .expect("Failed to create command buffers"); + let setup_command_buffer = command_buffers[0]; + let draw_command_buffer = command_buffers[1]; + + let fence_create_info = + vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED); + + let draw_commands_reuse_fence = device + .create_fence(&fence_create_info) + .expect("Failed to create draw commands fence"); + let setup_commands_reuse_fence = device + .create_fence(&fence_create_info) + .expect("Failed to create setup commands fence"); + + let semaphore_create_info = vk::SemaphoreCreateInfo::default(); + + let present_complete_semaphore = device + .create_semaphore(&semaphore_create_info) + .expect("Failed to create present complete semaphore"); + let rendering_complete_semaphore = device + .create_semaphore(&semaphore_create_info) + .expect("Failed to create rendering complete semaphore"); Ok(Self { instance, surface, device, + swapchain, + present_images, + present_image_views, + + present_queue, + + pool, + + setup_command_buffer, + draw_command_buffer, + + present_complete_semaphore, + rendering_complete_semaphore, + + draw_commands_reuse_fence, + setup_commands_reuse_fence, }) } -} \ No newline at end of file + + pub fn render(&mut self) -> anyhow::Result<()> { + unsafe { + self.device.handle + .wait_for_fences(&[self.draw_commands_reuse_fence], true, u64::MAX) + .expect("Wait for fence failed."); + + self.device.handle + .reset_fences(&[self.draw_commands_reuse_fence]) + .expect("Reset fences failed."); + + self.device.handle + .reset_command_buffer( + self.draw_command_buffer, + vk::CommandBufferResetFlags::RELEASE_RESOURCES, + ) + .expect("Reset command buffer failed."); + + let command_buffer_begin_info = vk::CommandBufferBeginInfo::default() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + + self.device.handle + .begin_command_buffer(self.draw_command_buffer, &command_buffer_begin_info) + .expect("Begin commandbuffer"); + + self.device.handle + .end_command_buffer(self.draw_command_buffer) + .expect("End commandbuffer"); + + let command_buffers = vec![self.draw_command_buffer]; + let semaphores = vec![self.rendering_complete_semaphore]; + let wait_mask = vec![vk::PipelineStageFlags::default()]; + + let submit_info = vk::SubmitInfo::default() + .wait_semaphores(&semaphores) + .wait_dst_stage_mask(&wait_mask) + .command_buffers(&command_buffers) + .signal_semaphores(&semaphores); + + self.device.handle + .queue_submit(self.present_queue, &[submit_info], self.draw_commands_reuse_fence) + .expect("queue submit failed."); + } + + Ok(()) + } + + pub fn update_resolution(&mut self, width: u32, height: u32) -> anyhow::Result<()> { + self.swapchain.update_resolution(&self.surface, width, height)?; + + Ok(()) + } +} diff --git a/src/vulkan/vk_swapchain.rs b/src/vulkan/vk_swapchain.rs index e531fc5..18e6081 100644 --- a/src/vulkan/vk_swapchain.rs +++ b/src/vulkan/vk_swapchain.rs @@ -1,27 +1,26 @@ use crate::vulkan::{VkSurface, LOG_TARGET}; use ash::prelude::VkResult; use ash::vk; -use ash::vk::{Extent2D, PresentModeKHR, SurfaceFormatKHR, SurfaceTransformFlagsKHR, SwapchainCreateInfoKHR, SwapchainKHR}; pub struct VkSwapchain { - swapchain_loader: ash::khr::swapchain::Device, + pub(super) swapchain_loader: ash::khr::swapchain::Device, swapchain: Option, - desired_image_count: u32, - surface_format: SurfaceFormatKHR, - surface_resolution: Extent2D, - present_mode: PresentModeKHR, - pre_transform: SurfaceTransformFlagsKHR, + pub(super) desired_image_count: u32, + pub(super) surface_format: vk::SurfaceFormatKHR, + pub(super) surface_resolution: vk::Extent2D, + pub(super) present_mode: vk::PresentModeKHR, + pub(super) pre_transform: vk::SurfaceTransformFlagsKHR, } impl VkSwapchain { - pub fn new( + pub(super) fn new( swapchain_loader: ash::khr::swapchain::Device, desired_image_count: u32, - surface_format: SurfaceFormatKHR, - surface_resolution: Extent2D, - present_mode: PresentModeKHR, - pre_transform: SurfaceTransformFlagsKHR, + surface_format: vk::SurfaceFormatKHR, + surface_resolution: vk::Extent2D, + present_mode: vk::PresentModeKHR, + pre_transform: vk::SurfaceTransformFlagsKHR, ) -> Self { Self { swapchain_loader, @@ -34,7 +33,7 @@ impl VkSwapchain { } } - pub fn create_swapchain(&mut self, surface: &VkSurface) -> VkResult<()> { + pub(super) fn create_swapchain(&mut self, surface: &VkSurface) -> VkResult<()> { let mut swapchain_create_info = self.create_swapchain_info(surface); if let Some(old_swapchain) = self.swapchain { @@ -44,15 +43,40 @@ impl VkSwapchain { let swapchain = unsafe { self.swapchain_loader.create_swapchain(&swapchain_create_info, None)? }; - log::debug!(target: LOG_TARGET, "Swapchain created : {swapchain_create_info:#?}"); + + match self.swapchain { + Some(_) => log::debug!(target: LOG_TARGET, "Swapchain created : {swapchain_create_info:#?}"), + None => log::debug!(target: LOG_TARGET, "Swapchain updated : {swapchain_create_info:#?}") + } self.swapchain = Some(swapchain); Ok(()) } - fn create_swapchain_info(&self, surface: &VkSurface) -> SwapchainCreateInfoKHR { - SwapchainCreateInfoKHR::default() + pub(super) fn update_resolution(&mut self, surface: &VkSurface, width: u32, height: u32) -> VkResult<()> { + log::debug!(target: LOG_TARGET, "New resolution requested for swapchain {width}x{height}"); + self.surface_resolution = vk::Extent2D { + width, + height, + }; + + self.create_swapchain(surface)?; + + Ok(()) + } + + pub(super) fn get_swapchain_images(&self) -> anyhow::Result> { + let swapchain = self.swapchain + .ok_or_else(|| anyhow::anyhow!("Can't get swapchain images : Swapchain is not set"))?; + + let images = unsafe { self.swapchain_loader.get_swapchain_images(swapchain)? }; + + Ok(images) + } + + fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR { + vk::SwapchainCreateInfoKHR::default() .surface(surface.surface) .min_image_count(self.desired_image_count) .image_color_space(self.surface_format.color_space)