Add the swapchain
This commit is contained in:
parent
2c5928dac4
commit
f9c423cd47
42
src/app.rs
42
src/app.rs
@ -1,5 +1,5 @@
|
||||
mod functions;
|
||||
use functions::{create_instance, create_logical_device, pick_physical_device};
|
||||
use functions::{create_instance, create_logical_device, create_swapchain, pick_physical_device};
|
||||
|
||||
use crate::VALIDATION_ENABLED;
|
||||
use ::anyhow::{anyhow, Result};
|
||||
@ -7,11 +7,14 @@ use ::log::*;
|
||||
use ::thiserror::Error;
|
||||
use ::vulkanalia::loader::{LibloadingLoader, LIBRARY};
|
||||
use ::vulkanalia::prelude::v1_0::*;
|
||||
use ::vulkanalia::vk::ExtDebugUtilsExtension;
|
||||
use ::vulkanalia::vk::KhrSurfaceExtension;
|
||||
use ::vulkanalia::vk::{ExtDebugUtilsExtension, KhrSurfaceExtension, KhrSwapchainExtension};
|
||||
use ::vulkanalia::window as vk_window;
|
||||
use ::winit::window::Window;
|
||||
|
||||
pub(crate) 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];
|
||||
|
||||
/// Our Vulkan app.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct App {
|
||||
@ -31,6 +34,7 @@ impl App {
|
||||
data.surface = vk_window::create_surface(&instance, window)?;
|
||||
pick_physical_device(&instance, &mut data)?;
|
||||
let device = create_logical_device(&instance, &mut data)?;
|
||||
create_swapchain(window, &instance, &device, &mut data)?;
|
||||
|
||||
Ok(Self {
|
||||
entry,
|
||||
@ -47,6 +51,7 @@ impl App {
|
||||
|
||||
/// Destroys our Vulkan app.
|
||||
pub unsafe fn destroy(&mut self) {
|
||||
self.device.destroy_swapchain_khr(self.data.swapchain, None);
|
||||
self.device.destroy_device(None);
|
||||
|
||||
if VALIDATION_ENABLED {
|
||||
@ -62,13 +67,18 @@ impl App {
|
||||
/// The Vulkan handles and associated properties used by our Vulkan app.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct AppData {
|
||||
surface: vk::SurfaceKHR,
|
||||
// Debug
|
||||
messenger: vk::DebugUtilsMessengerEXT,
|
||||
// Surface
|
||||
surface: vk::SurfaceKHR,
|
||||
// Physical Device / Logical Device
|
||||
physical_device: vk::PhysicalDevice,
|
||||
graphics_queue: vk::Queue,
|
||||
present_queue: vk::Queue,
|
||||
swapchain_format: vk::Format,
|
||||
swapchain_extent: vk::Extent2D,
|
||||
swapchain: vk::SwapchainKHR,
|
||||
swapchain_images: Vec<vk::Image>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@ -115,3 +125,27 @@ impl QueueFamilyIndicies {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SwapchainSupport {
|
||||
capabilities: vk::SurfaceCapabilitiesKHR,
|
||||
formats: Vec<vk::SurfaceFormatKHR>,
|
||||
present_modes: Vec<vk::PresentModeKHR>,
|
||||
}
|
||||
|
||||
impl SwapchainSupport {
|
||||
unsafe fn get(
|
||||
instance: &Instance,
|
||||
data: &AppData,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
capabilities: instance
|
||||
.get_physical_device_surface_capabilities_khr(physical_device, data.surface)?,
|
||||
formats: instance
|
||||
.get_physical_device_surface_formats_khr(physical_device, data.surface)?,
|
||||
present_modes: instance
|
||||
.get_physical_device_surface_present_modes_khr(physical_device, data.surface)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::{VALIDATION_ENABLED, VALIDATION_LAYER};
|
||||
use crate::VALIDATION_ENABLED;
|
||||
|
||||
use ::anyhow::{anyhow, Result};
|
||||
use ::log::*;
|
||||
@ -139,10 +139,35 @@ pub(super) unsafe fn check_physical_device(
|
||||
physical_device: vk::PhysicalDevice,
|
||||
) -> Result<()> {
|
||||
QueueFamilyIndicies::get(instance, data, physical_device)?;
|
||||
check_physical_device_extensions(instance, physical_device)?;
|
||||
|
||||
let support = SwapchainSupport::get(instance, data, physical_device)?;
|
||||
if support.formats.is_empty() || support.present_modes.is_empty() {
|
||||
return Err(anyhow!(SuitabilityError("Insufficient swapchain support.")));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) unsafe fn check_physical_device_extensions(
|
||||
instance: &Instance,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
) -> Result<()> {
|
||||
let extensions = instance
|
||||
.enumerate_device_extension_properties(physical_device, None)?
|
||||
.iter()
|
||||
.map(|e| e.extension_name)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
if DEVICE_EXTENSIONS.iter().all(|e| extensions.contains(e)) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(SuitabilityError(
|
||||
"Missing required device extensions."
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn create_logical_device(
|
||||
instance: &Instance,
|
||||
data: &mut AppData,
|
||||
@ -172,15 +197,19 @@ pub(super) unsafe fn create_logical_device(
|
||||
};
|
||||
|
||||
// Extensions
|
||||
let extension_names = if instance
|
||||
let mut extensions = DEVICE_EXTENSIONS
|
||||
.iter()
|
||||
.map(|n| n.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// mac OS Metal -> Vulkan rendering fix
|
||||
if instance
|
||||
.enumerate_device_extension_properties(data.physical_device, None)?
|
||||
.iter()
|
||||
.any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name)
|
||||
{
|
||||
vec![vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
|
||||
}
|
||||
|
||||
// Features
|
||||
let features = vk::PhysicalDeviceFeatures::builder();
|
||||
@ -189,8 +218,8 @@ pub(super) unsafe fn create_logical_device(
|
||||
let info = vk::DeviceCreateInfo::builder()
|
||||
.queue_create_infos(&queue_infos)
|
||||
.enabled_layer_names(&layers)
|
||||
.enabled_features(&features)
|
||||
.enabled_extension_names(&extension_names);
|
||||
.enabled_extension_names(&extensions)
|
||||
.enabled_features(&features);
|
||||
|
||||
let device = instance.create_device(data.physical_device, &info, None)?;
|
||||
|
||||
@ -200,3 +229,103 @@ pub(super) unsafe fn create_logical_device(
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
pub(super) fn get_swapchain_surface_format(
|
||||
formats: &[vk::SurfaceFormatKHR],
|
||||
) -> vk::SurfaceFormatKHR {
|
||||
formats
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|f| {
|
||||
f.format == vk::Format::B8G8R8A8_SRGB
|
||||
&& f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
|
||||
})
|
||||
.unwrap_or_else(|| formats[0])
|
||||
}
|
||||
|
||||
pub(super) fn get_swapchain_present_mode(
|
||||
present_modes: &[vk::PresentModeKHR],
|
||||
) -> vk::PresentModeKHR {
|
||||
present_modes
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|m| *m == vk::PresentModeKHR::MAILBOX)
|
||||
.unwrap_or(vk::PresentModeKHR::FIFO)
|
||||
}
|
||||
|
||||
pub(super) fn get_swapchain_extent(
|
||||
window: &Window,
|
||||
capabilities: vk::SurfaceCapabilitiesKHR,
|
||||
) -> vk::Extent2D {
|
||||
if capabilities.current_extent.width != u32::MAX {
|
||||
capabilities.current_extent
|
||||
} else {
|
||||
let size = window.inner_size();
|
||||
let clamp = |min: u32, max: u32, v: u32| min.max(max.min(v));
|
||||
vk::Extent2D::builder()
|
||||
.width(clamp(
|
||||
capabilities.min_image_extent.width,
|
||||
capabilities.max_image_extent.width,
|
||||
size.width,
|
||||
))
|
||||
.height(clamp(
|
||||
capabilities.min_image_extent.height,
|
||||
capabilities.max_image_extent.height,
|
||||
size.height,
|
||||
))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn create_swapchain(
|
||||
window: &Window,
|
||||
instance: &Instance,
|
||||
device: &Device,
|
||||
data: &mut AppData,
|
||||
) -> Result<()> {
|
||||
let indices = QueueFamilyIndicies::get(instance, data, data.physical_device)?;
|
||||
let support = SwapchainSupport::get(instance, data, data.physical_device)?;
|
||||
|
||||
let surface_format = get_swapchain_surface_format(&support.formats);
|
||||
let present_mode = get_swapchain_present_mode(&support.present_modes);
|
||||
let extent = get_swapchain_extent(window, support.capabilities);
|
||||
|
||||
let mut image_count = support.capabilities.min_image_count + 1;
|
||||
if support.capabilities.max_image_count != 0
|
||||
&& image_count > support.capabilities.max_image_count
|
||||
{
|
||||
image_count = support.capabilities.max_image_count;
|
||||
}
|
||||
|
||||
let mut queue_family_indices = vec![];
|
||||
let image_sharing_mode = if indices.graphics != indices.present {
|
||||
queue_family_indices.push(indices.graphics);
|
||||
queue_family_indices.push(indices.present);
|
||||
vk::SharingMode::CONCURRENT
|
||||
} else {
|
||||
vk::SharingMode::EXCLUSIVE
|
||||
};
|
||||
|
||||
let info = vk::SwapchainCreateInfoKHR::builder()
|
||||
.surface(data.surface)
|
||||
.min_image_count(image_count)
|
||||
.image_format(surface_format.format)
|
||||
.image_color_space(surface_format.color_space)
|
||||
.image_extent(extent)
|
||||
.image_array_layers(1)
|
||||
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
||||
.image_sharing_mode(image_sharing_mode)
|
||||
.queue_family_indices(&queue_family_indices)
|
||||
.pre_transform(support.capabilities.current_transform)
|
||||
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
||||
.present_mode(present_mode)
|
||||
.clipped(true)
|
||||
.old_swapchain(vk::SwapchainKHR::null());
|
||||
|
||||
data.swapchain = device.create_swapchain_khr(&info, None)?;
|
||||
data.swapchain_images = device.get_swapchain_images_khr(data.swapchain)?;
|
||||
data.swapchain_format = surface_format.format;
|
||||
data.swapchain_extent = extent;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,12 +2,9 @@ mod app;
|
||||
pub use app::App;
|
||||
|
||||
use ::anyhow::Result;
|
||||
use ::vulkanalia::prelude::v1_0::*;
|
||||
use ::winit::window::Window;
|
||||
|
||||
pub const VALIDATION_ENABLED: bool = cfg!(debug_assertions);
|
||||
pub const VALIDATION_LAYER: vk::ExtensionName =
|
||||
vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation");
|
||||
|
||||
pub fn create_app(window: &Window) -> Result<App> {
|
||||
Ok(unsafe { App::create(&window)? })
|
||||
|
Loading…
Reference in New Issue
Block a user