feat(renderer): finalize swapchain initialization
Negotiated swapchain settings (format, present mode, extent), created the swapchain and its images, and ensured correct destruction order. Added comprehensive documentation for all new fields and methods.
This commit is contained in:
parent
5ee9fc1bd6
commit
76450da41f
|
|
@ -1,7 +1,7 @@
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
use std::ffi::{CStr, c_char};
|
use std::ffi::{CStr, c_char};
|
||||||
use ash::{Device, Entry, Instance, ext, khr, vk};
|
use ash::{Device, Entry, Instance, ext, khr, vk::{self, SurfaceKHR}};
|
||||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
|
|
@ -25,8 +25,20 @@ pub struct Renderer {
|
||||||
graphics_queue: vk::Queue,
|
graphics_queue: vk::Queue,
|
||||||
/// The index of the graphics queue family.
|
/// The index of the graphics queue family.
|
||||||
graphics_queue_index: u32,
|
graphics_queue_index: u32,
|
||||||
|
/// The surface loader instance.
|
||||||
surface_loader: khr::surface::Instance,
|
surface_loader: khr::surface::Instance,
|
||||||
|
/// The window surface handle.
|
||||||
surface: vk::SurfaceKHR,
|
surface: vk::SurfaceKHR,
|
||||||
|
/// The swapchain loader instance.
|
||||||
|
swapchain_loader: khr::swapchain::Device,
|
||||||
|
/// The swapchain handle.
|
||||||
|
swapchain: vk::SwapchainKHR,
|
||||||
|
/// The images retrieved from the swapchain.
|
||||||
|
swapchain_images: Vec<vk::Image>,
|
||||||
|
/// The pixel format of the swapchain images.
|
||||||
|
swapchain_format: vk::Format,
|
||||||
|
/// The resolution of the swapchain images.
|
||||||
|
swapchain_extent: vk::Extent2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
|
|
@ -105,6 +117,8 @@ impl Renderer {
|
||||||
// Create the logical device
|
// Create the logical device
|
||||||
let (device, graphics_queue) = Self::create_logical_device(&instance, physical_device, graphics_queue_index)?;
|
let (device, graphics_queue) = Self::create_logical_device(&instance, physical_device, graphics_queue_index)?;
|
||||||
|
|
||||||
|
let (swapchain_loader, swapchain, swapchain_images, swapchain_format, swapchain_extent) = Self::create_swapchain(&instance, physical_device, &device, &surface_loader, surface)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_entry: entry,
|
_entry: entry,
|
||||||
instance,
|
instance,
|
||||||
|
|
@ -116,6 +130,11 @@ impl Renderer {
|
||||||
graphics_queue_index,
|
graphics_queue_index,
|
||||||
surface_loader,
|
surface_loader,
|
||||||
surface,
|
surface,
|
||||||
|
swapchain_loader,
|
||||||
|
swapchain,
|
||||||
|
swapchain_images,
|
||||||
|
swapchain_format,
|
||||||
|
swapchain_extent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,24 +231,88 @@ impl Renderer {
|
||||||
|
|
||||||
Ok((device, graphics_queue))
|
Ok((device, graphics_queue))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a swapchain and retrieves its images.
|
||||||
|
///
|
||||||
|
/// This function negotiates with the surface to find a suitable color format,
|
||||||
|
/// presentation mode, and image resolution.
|
||||||
|
fn create_swapchain(
|
||||||
|
instance: &Instance,
|
||||||
|
physical_device: vk::PhysicalDevice,
|
||||||
|
device: &Device,
|
||||||
|
surface_loader: &khr::surface::Instance,
|
||||||
|
surface: vk::SurfaceKHR,
|
||||||
|
) -> Result<
|
||||||
|
(khr::swapchain::Device, vk::SwapchainKHR, Vec<vk::Image>, vk::Format, vk::Extent2D),
|
||||||
|
RendererError,
|
||||||
|
> {
|
||||||
|
let surface_capabilities = unsafe { surface_loader.get_physical_device_surface_capabilities(physical_device, surface)? };
|
||||||
|
|
||||||
|
let surface_formats = unsafe { surface_loader.get_physical_device_surface_formats(physical_device, surface)? };
|
||||||
|
|
||||||
|
let surface_present_modes = unsafe { surface_loader.get_physical_device_surface_present_modes(physical_device, surface)?};
|
||||||
|
|
||||||
|
// 1. Pick the best color format (Prefer SRGB for accurate colors)
|
||||||
|
let format = surface_formats.iter()
|
||||||
|
.find(|f| f.format == vk::Format::B8G8R8A8_SRGB && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR)
|
||||||
|
.unwrap_or(&surface_formats[0]);
|
||||||
|
|
||||||
|
// 2. Pick the best presentation mode (Mailbox = Triple Buffering, FIFO = VSync)
|
||||||
|
let present_mode = surface_present_modes.into_iter()
|
||||||
|
.find(|&m| m == vk::PresentModeKHR::MAILBOX)
|
||||||
|
.unwrap_or(vk::PresentModeKHR::FIFO);
|
||||||
|
|
||||||
|
let extent = surface_capabilities.current_extent;
|
||||||
|
|
||||||
|
let mut image_count = surface_capabilities.min_image_count + 1;
|
||||||
|
|
||||||
|
if surface_capabilities.max_image_count > 0 && image_count > surface_capabilities.max_image_count {
|
||||||
|
image_count = surface_capabilities.max_image_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
let swapchain_loader = khr::swapchain::Device::new(instance, device);
|
||||||
|
|
||||||
|
let create_info = vk::SwapchainCreateInfoKHR::default()
|
||||||
|
.surface(surface)
|
||||||
|
.min_image_count(image_count)
|
||||||
|
.image_format(format.format)
|
||||||
|
.image_color_space(format.color_space)
|
||||||
|
.image_extent(extent)
|
||||||
|
.image_array_layers(1)
|
||||||
|
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
||||||
|
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||||
|
.pre_transform(surface_capabilities.current_transform)
|
||||||
|
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
||||||
|
.present_mode(present_mode)
|
||||||
|
.clipped(true);
|
||||||
|
|
||||||
|
let swapchain = unsafe { swapchain_loader.create_swapchain(&create_info, None)? };
|
||||||
|
|
||||||
|
let images = unsafe { swapchain_loader.get_swapchain_images(swapchain)? };
|
||||||
|
|
||||||
|
Ok((swapchain_loader, swapchain, images, format.format, extent ))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures all Vulkan resources are destroyed in the correct order.
|
/// Ensures all Vulkan resources are destroyed in the correct order.
|
||||||
impl Drop for Renderer {
|
impl Drop for Renderer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// 1. Destroy the logical device first
|
// 1. Destroy the swapchain BEFORE the device it belongs to
|
||||||
|
self.swapchain_loader.destroy_swapchain(self.swapchain, None);
|
||||||
|
|
||||||
|
// 2. Destroy the logical device
|
||||||
self.device.destroy_device(None);
|
self.device.destroy_device(None);
|
||||||
|
|
||||||
// 2. Destroy the surface
|
// 3. Destroy the surface
|
||||||
self.surface_loader.destroy_surface(self.surface, None);
|
self.surface_loader.destroy_surface(self.surface, None);
|
||||||
|
|
||||||
// 3. Destroy the debug messenger if we created one
|
// 4. Destroy the debug messenger if we created one
|
||||||
if let Some(utils) = &self.debug_utils {
|
if let Some(utils) = &self.debug_utils {
|
||||||
utils.destroy_debug_utils_messenger(self.debug_messenger, None);
|
utils.destroy_debug_utils_messenger(self.debug_messenger, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Finally, destroy the instance
|
// 5. Finally, destroy the instance
|
||||||
self.instance.destroy_instance(None);
|
self.instance.destroy_instance(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue