From 61bd125414b579144ff43704f9243f16f6b55065 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 7 Apr 2023 11:20:48 -0400 Subject: [PATCH] Actually display a triangle on screen! --- src/app.rs | 67 +++++++++++++++++++++++++++++++++++++++++--- src/app/functions.rs | 34 ++++++++++++++++++---- src/lib.rs | 2 ++ 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/src/app.rs b/src/app.rs index 545909e..f1d8efa 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,7 +2,7 @@ mod functions; use functions::{ 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, + create_swapchain_image_views, create_sync_objects, pick_physical_device, }; use crate::VALIDATION_ENABLED; @@ -13,11 +13,21 @@ use ::vulkanalia::loader::{LibloadingLoader, LIBRARY}; use ::vulkanalia::prelude::v1_0::*; use ::vulkanalia::vk::{ExtDebugUtilsExtension, KhrSurfaceExtension, KhrSwapchainExtension}; use ::vulkanalia::window as vk_window; +use ::vulkanalia::Version; use ::winit::window::Window; -pub(crate) const VALIDATION_LAYER: vk::ExtensionName = +/// The name of the validation layers. +pub const VALIDATION_LAYER: vk::ExtensionName = vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); -pub(crate) const DEVICE_EXTENSIONS: &[vk::ExtensionName] = &[vk::KHR_SWAPCHAIN_EXTENSION.name]; + +/// The Vulkan SDK version that started requiring the portability subset extension for macOS. +pub const PORTABILITY_MACOS_VERSION: Version = Version::new(1, 3, 216); + +/// The required device extensions +pub const DEVICE_EXTENSIONS: &[vk::ExtensionName] = &[vk::KHR_SWAPCHAIN_EXTENSION.name]; + +/// The maximum number of frames that can be processed concurrently. +pub const MAX_FRAMES_IN_FLIGHT: usize = 2; /// Our Vulkan app. #[derive(Clone, Debug)] @@ -25,7 +35,8 @@ pub struct App { entry: Entry, instance: Instance, data: AppData, - device: Device, + pub device: Device, + frame: usize, } impl App { @@ -51,12 +62,14 @@ impl App { create_framebuffers(&device, &mut data)?; create_command_pool(&instance, &device, &mut data)?; create_command_buffers(&device, &mut data)?; + create_sync_objects(&device, &mut data)?; Ok(Self { entry, instance, data, device, + frame: 0, }) } @@ -65,6 +78,41 @@ impl App { /// # Safety /// Here be Dragons pub unsafe fn render(&mut self, _window: &Window) -> Result<()> { + let image_index = self + .device + .acquire_next_image_khr( + self.data.swapchain, + u64::max_value(), + self.data.image_available_semaphores[self.frame], + vk::Fence::null(), + )? + .0 as usize; + + let wait_semaphores = &[self.data.image_available_semaphores[self.frame]]; + let wait_stages = &[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let command_buffers = &[self.data.command_buffers[image_index as usize]]; + let signal_semaphores = &[self.data.render_finished_semaphores[self.frame]]; + let submit_info = vk::SubmitInfo::builder() + .wait_semaphores(wait_semaphores) + .wait_dst_stage_mask(wait_stages) + .command_buffers(command_buffers) + .signal_semaphores(signal_semaphores); + + self.device + .queue_submit(self.data.graphics_queue, &[submit_info], vk::Fence::null())?; + + let swapchains = &[self.data.swapchain]; + let image_indices = &[image_index as u32]; + let present_info = vk::PresentInfoKHR::builder() + .wait_semaphores(signal_semaphores) + .swapchains(swapchains) + .image_indices(image_indices); + + self.device + .queue_present_khr(self.data.present_queue, &present_info)?; + + self.frame = (self.frame + 1) % MAX_FRAMES_IN_FLIGHT; + Ok(()) } @@ -73,6 +121,14 @@ impl App { /// # Safety /// Here be Dragons pub unsafe fn destroy(&mut self) { + self.data + .render_finished_semaphores + .iter() + .for_each(|s| self.device.destroy_semaphore(*s, None)); + self.data + .image_available_semaphores + .iter() + .for_each(|s| self.device.destroy_semaphore(*s, None)); self.device .destroy_command_pool(self.data.command_pool, None); self.data @@ -127,6 +183,9 @@ pub struct AppData { command_pool: vk::CommandPool, // Command Buffers command_buffers: Vec, + // Sync Objects + image_available_semaphores: Vec, + render_finished_semaphores: Vec, } impl AppData {} diff --git a/src/app/functions.rs b/src/app/functions.rs index 30ad425..6394cd0 100644 --- a/src/app/functions.rs +++ b/src/app/functions.rs @@ -76,11 +76,13 @@ pub(super) unsafe fn create_instance( } // Compatibility extension for macOS - let flags = if entry - .enumerate_instance_extension_properties(None)? - .iter() - .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) + let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION) + || entry + .enumerate_instance_extension_properties(None)? + .iter() + .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) { + info!("Enabling extensions for macOS compatibility."); extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); extensions.push( vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION @@ -397,12 +399,21 @@ pub(super) unsafe fn create_render_pass( let subpass = vk::SubpassDescription::builder() .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) .color_attachments(color_attachments); + let dependency = vk::SubpassDependency::builder() + .src_subpass(vk::SUBPASS_EXTERNAL) + .dst_subpass(0) + .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags::empty()) + .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); let attachments = &[color_attachment]; let subpasses = &[subpass]; + let dependencies = &[dependency]; let info = vk::RenderPassCreateInfo::builder() .attachments(attachments) - .subpasses(subpasses); + .subpasses(subpasses) + .dependencies(dependencies); data.render_pass = device.create_render_pass(&info, None)?; @@ -615,3 +626,16 @@ pub(super) unsafe fn create_command_buffers(device: &Device, data: &mut AppData) Ok(()) } + +pub(super) unsafe fn create_sync_objects(device: &Device, data: &mut AppData) -> Result<()> { + let semaphore_info = vk::SemaphoreCreateInfo::builder(); + + for _ in 0..MAX_FRAMES_IN_FLIGHT { + data.image_available_semaphores + .push(device.create_semaphore(&semaphore_info, None)?); + data.render_finished_semaphores + .push(device.create_semaphore(&semaphore_info, None)?); + } + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 54fe4b1..44e3bfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ mod app; pub use app::App; use ::anyhow::Result; +use ::vulkanalia::vk::DeviceV1_0; use ::winit::dpi::LogicalSize; use ::winit::event::{Event, WindowEvent}; use ::winit::event_loop::{ControlFlow, EventLoop}; @@ -33,6 +34,7 @@ pub fn run() -> Result<()> { destroying = true; *control_flow = ControlFlow::Exit; unsafe { + app.device.device_wait_idle().unwrap(); app.destroy(); } }