From b0159a299c7a7c77f244fd83faf2fd2f5291502d Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 7 Apr 2023 10:48:51 -0400 Subject: [PATCH] Set up Framebuffers, Command Pool, and Command Buffers --- src/app.rs | 30 +++++++++++++- src/app/functions.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 37 +++++++++++++++-- src/main.rs | 43 ++------------------ 4 files changed, 160 insertions(+), 45 deletions(-) diff --git a/src/app.rs b/src/app.rs index 844af22..545909e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,7 @@ mod functions; use functions::{ - create_instance, create_logical_device, create_pipeline, create_render_pass, create_swapchain, + create_command_buffers, create_command_pool, create_framebuffers, create_instance, + create_logical_device, create_pipeline, create_render_pass, create_swapchain, create_swapchain_image_views, pick_physical_device, }; @@ -29,6 +30,9 @@ pub struct App { impl App { /// Creates our Vulkan app. + /// + /// # Safety + /// Here be Dragons pub unsafe fn create(window: &Window) -> Result { let loader = LibloadingLoader::new(LIBRARY)?; let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; @@ -44,6 +48,9 @@ impl App { create_swapchain_image_views(&device, &mut data)?; create_render_pass(&instance, &device, &mut data)?; create_pipeline(&device, &mut data)?; + create_framebuffers(&device, &mut data)?; + create_command_pool(&instance, &device, &mut data)?; + create_command_buffers(&device, &mut data)?; Ok(Self { entry, @@ -54,12 +61,24 @@ impl App { } /// Renders a frame for our Vulkan app. + /// + /// # Safety + /// Here be Dragons pub unsafe fn render(&mut self, _window: &Window) -> Result<()> { Ok(()) } - /// Destroys our Vulkan app. + /// Destroys our Vulkan app, in reverse order of creation + /// + /// # Safety + /// Here be Dragons pub unsafe fn destroy(&mut self) { + self.device + .destroy_command_pool(self.data.command_pool, None); + self.data + .framebuffers + .iter() + .for_each(|f| self.device.destroy_framebuffer(*f, None)); self.device.destroy_pipeline(self.data.pipeline, None); self.device .destroy_pipeline_layout(self.data.pipeline_layout, None); @@ -98,9 +117,16 @@ pub struct AppData { swapchain: vk::SwapchainKHR, swapchain_images: Vec, swapchain_image_views: Vec, + // Pipeline render_pass: vk::RenderPass, pipeline_layout: vk::PipelineLayout, pipeline: vk::Pipeline, + // Framebuffers + framebuffers: Vec, + // Command Pool + command_pool: vk::CommandPool, + // Command Buffers + command_buffers: Vec, } impl AppData {} diff --git a/src/app/functions.rs b/src/app/functions.rs index 55b6583..30ad425 100644 --- a/src/app/functions.rs +++ b/src/app/functions.rs @@ -520,3 +520,98 @@ unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result Result<()> { + data.framebuffers = data + .swapchain_image_views + .iter() + .map(|i| { + let attachments = &[*i]; + let create_info = vk::FramebufferCreateInfo::builder() + .render_pass(data.render_pass) + .attachments(attachments) + .width(data.swapchain_extent.width) + .height(data.swapchain_extent.height) + .layers(1); + + device.create_framebuffer(&create_info, None) + }) + .collect::, _>>()?; + + Ok(()) +} + +//================================================ +// Command Pool +//================================================ + +pub(super) unsafe fn create_command_pool( + instance: &Instance, + device: &Device, + data: &mut AppData, +) -> Result<()> { + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; + + let info = vk::CommandPoolCreateInfo::builder() + .flags(vk::CommandPoolCreateFlags::empty()) + .queue_family_index(indices.graphics); + + data.command_pool = device.create_command_pool(&info, None)?; + + Ok(()) +} + +//================================================ +// Command Buffers +//================================================ + +pub(super) unsafe fn create_command_buffers(device: &Device, data: &mut AppData) -> Result<()> { + // Create the buffers + let allocate_info = vk::CommandBufferAllocateInfo::builder() + .command_pool(data.command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(data.framebuffers.len() as u32); + + data.command_buffers = device.allocate_command_buffers(&allocate_info)?; + + // Add commands + for (i, command_buffer) in data.command_buffers.iter().enumerate() { + let inheritance = vk::CommandBufferInheritanceInfo::builder(); + + let info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::empty()) + .inheritance_info(&inheritance); + + device.begin_command_buffer(*command_buffer, &info)?; + + let render_area = vk::Rect2D::builder() + .offset(vk::Offset2D::default()) + .extent(data.swapchain_extent); + + let color_clear_value = vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }; + + let clear_values = &[color_clear_value]; + let info = vk::RenderPassBeginInfo::builder() + .render_pass(data.render_pass) + .framebuffer(data.framebuffers[i]) + .render_area(render_area) + .clear_values(clear_values); + + device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE); + device.cmd_bind_pipeline( + *command_buffer, + vk::PipelineBindPoint::GRAPHICS, + data.pipeline, + ); + device.cmd_draw(*command_buffer, 3, 1, 0, 0); + device.cmd_end_render_pass(*command_buffer); + + device.end_command_buffer(*command_buffer)?; + } + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 4763a88..54fe4b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,41 @@ mod app; pub use app::App; use ::anyhow::Result; -use ::winit::window::Window; +use ::winit::dpi::LogicalSize; +use ::winit::event::{Event, WindowEvent}; +use ::winit::event_loop::{ControlFlow, EventLoop}; +use ::winit::window::WindowBuilder; pub const VALIDATION_ENABLED: bool = cfg!(debug_assertions); -pub fn create_app(window: &Window) -> Result { - Ok(unsafe { App::create(&window)? }) +pub fn run() -> Result<()> { + // Window + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_title("Vulkan Tutorial (Rust)") + .with_inner_size(LogicalSize::new(1024, 768)) + .build(&event_loop)?; + + // App + let mut app = unsafe { App::create(&window)? }; + let mut destroying = false; + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + match event { + // Render a frame if our Vulkan app is not being destroyed + Event::MainEventsCleared if !destroying => unsafe { app.render(&window) }.unwrap(), + // Destroy our Vulkan app. + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + destroying = true; + *control_flow = ControlFlow::Exit; + unsafe { + app.destroy(); + } + } + _ => {} + } + }); } diff --git a/src/main.rs b/src/main.rs index fe35988..82be460 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,41 +1,4 @@ -use ::anyhow::Result; -use ::winit::dpi::LogicalSize; -use ::winit::event::{Event, WindowEvent}; -use ::winit::event_loop::{ControlFlow, EventLoop}; -use ::winit::window::WindowBuilder; - -use vulkan_tutorial::create_app; - -fn main() -> Result<()> { - pretty_env_logger::init(); - - // Window - let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .with_title("Vulkan Tutorial (Rust)") - .with_inner_size(LogicalSize::new(1024, 768)) - .build(&event_loop)?; - - // App - let mut app = create_app(&window)?; - let mut destroying = false; - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; - match event { - // Render a frame if our Vulkan app is not being destroyed - Event::MainEventsCleared if !destroying => unsafe { app.render(&window) }.unwrap(), - // Destroy our Vulkan app. - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => { - destroying = true; - *control_flow = ControlFlow::Exit; - unsafe { - app.destroy(); - } - } - _ => {} - } - }); +fn main() -> ::anyhow::Result<()> { + ::pretty_env_logger::init(); + ::vulkan_tutorial::run() }