Actually display a triangle on screen!

This commit is contained in:
Timothy Warren 2023-04-07 11:20:48 -04:00
parent b0159a299c
commit 61bd125414
3 changed files with 94 additions and 9 deletions

View File

@ -2,7 +2,7 @@ mod functions;
use functions::{ use functions::{
create_command_buffers, create_command_pool, create_framebuffers, create_instance, create_command_buffers, create_command_pool, create_framebuffers, create_instance,
create_logical_device, create_pipeline, create_render_pass, create_swapchain, 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; use crate::VALIDATION_ENABLED;
@ -13,11 +13,21 @@ use ::vulkanalia::loader::{LibloadingLoader, LIBRARY};
use ::vulkanalia::prelude::v1_0::*; use ::vulkanalia::prelude::v1_0::*;
use ::vulkanalia::vk::{ExtDebugUtilsExtension, KhrSurfaceExtension, KhrSwapchainExtension}; use ::vulkanalia::vk::{ExtDebugUtilsExtension, KhrSurfaceExtension, KhrSwapchainExtension};
use ::vulkanalia::window as vk_window; use ::vulkanalia::window as vk_window;
use ::vulkanalia::Version;
use ::winit::window::Window; 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"); 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. /// Our Vulkan app.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -25,7 +35,8 @@ pub struct App {
entry: Entry, entry: Entry,
instance: Instance, instance: Instance,
data: AppData, data: AppData,
device: Device, pub device: Device,
frame: usize,
} }
impl App { impl App {
@ -51,12 +62,14 @@ impl App {
create_framebuffers(&device, &mut data)?; create_framebuffers(&device, &mut data)?;
create_command_pool(&instance, &device, &mut data)?; create_command_pool(&instance, &device, &mut data)?;
create_command_buffers(&device, &mut data)?; create_command_buffers(&device, &mut data)?;
create_sync_objects(&device, &mut data)?;
Ok(Self { Ok(Self {
entry, entry,
instance, instance,
data, data,
device, device,
frame: 0,
}) })
} }
@ -65,6 +78,41 @@ impl App {
/// # Safety /// # Safety
/// Here be Dragons /// Here be Dragons
pub unsafe fn render(&mut self, _window: &Window) -> Result<()> { 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(()) Ok(())
} }
@ -73,6 +121,14 @@ impl App {
/// # Safety /// # Safety
/// Here be Dragons /// Here be Dragons
pub unsafe fn destroy(&mut self) { 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 self.device
.destroy_command_pool(self.data.command_pool, None); .destroy_command_pool(self.data.command_pool, None);
self.data self.data
@ -127,6 +183,9 @@ pub struct AppData {
command_pool: vk::CommandPool, command_pool: vk::CommandPool,
// Command Buffers // Command Buffers
command_buffers: Vec<vk::CommandBuffer>, command_buffers: Vec<vk::CommandBuffer>,
// Sync Objects
image_available_semaphores: Vec<vk::Semaphore>,
render_finished_semaphores: Vec<vk::Semaphore>,
} }
impl AppData {} impl AppData {}

View File

@ -76,11 +76,13 @@ pub(super) unsafe fn create_instance(
} }
// Compatibility extension for macOS // Compatibility extension for macOS
let flags = if entry let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION)
|| entry
.enumerate_instance_extension_properties(None)? .enumerate_instance_extension_properties(None)?
.iter() .iter()
.any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) .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_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
extensions.push( extensions.push(
vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION
@ -397,12 +399,21 @@ pub(super) unsafe fn create_render_pass(
let subpass = vk::SubpassDescription::builder() let subpass = vk::SubpassDescription::builder()
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
.color_attachments(color_attachments); .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 attachments = &[color_attachment];
let subpasses = &[subpass]; let subpasses = &[subpass];
let dependencies = &[dependency];
let info = vk::RenderPassCreateInfo::builder() let info = vk::RenderPassCreateInfo::builder()
.attachments(attachments) .attachments(attachments)
.subpasses(subpasses); .subpasses(subpasses)
.dependencies(dependencies);
data.render_pass = device.create_render_pass(&info, None)?; 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(()) 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(())
}

View File

@ -2,6 +2,7 @@ mod app;
pub use app::App; pub use app::App;
use ::anyhow::Result; use ::anyhow::Result;
use ::vulkanalia::vk::DeviceV1_0;
use ::winit::dpi::LogicalSize; use ::winit::dpi::LogicalSize;
use ::winit::event::{Event, WindowEvent}; use ::winit::event::{Event, WindowEvent};
use ::winit::event_loop::{ControlFlow, EventLoop}; use ::winit::event_loop::{ControlFlow, EventLoop};
@ -33,6 +34,7 @@ pub fn run() -> Result<()> {
destroying = true; destroying = true;
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
unsafe { unsafe {
app.device.device_wait_idle().unwrap();
app.destroy(); app.destroy();
} }
} }