diff options
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi.rs | 11 | ||||
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/runtime.rs | 223 | ||||
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/swapchain.rs | 220 | ||||
| -rw-r--r-- | xtask/src/main.rs | 1 |
4 files changed, 237 insertions, 218 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi.rs b/adapters/fparkan-render-vulkan/src/ffi.rs index 8b5312e..a2daef7 100644 --- a/adapters/fparkan-render-vulkan/src/ffi.rs +++ b/adapters/fparkan-render-vulkan/src/ffi.rs @@ -33,6 +33,7 @@ mod runtime; mod smoke; mod smoke_types; mod surface; +mod swapchain; mod swapchain_resources; mod validation; @@ -50,11 +51,9 @@ use self::resources::{ VulkanFrameSync, }; pub use self::runtime::{ - create_vulkan_logical_device_probe, create_vulkan_swapchain_probe, - create_vulkan_swapchain_probe_for_extent, probe_vulkan_runtime_capabilities, + create_vulkan_logical_device_probe, probe_vulkan_runtime_capabilities, VulkanLogicalDeviceError, VulkanLogicalDeviceProbe, VulkanLogicalDeviceReport, - VulkanRuntimeCapabilityError, VulkanRuntimeCapabilityProbe, VulkanSwapchainProbe, - VulkanSwapchainProbeError, VulkanSwapchainReport, + VulkanRuntimeCapabilityError, VulkanRuntimeCapabilityProbe, }; pub use self::smoke_types::{ VulkanSmokeFrameOutcome, VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, @@ -66,6 +65,10 @@ pub use self::surface::{ create_vulkan_surface_probe, plan_vulkan_surface, render_surface_plan_json, VulkanSurfaceError, VulkanSurfacePlan, VulkanSurfaceProbe, }; +pub use self::swapchain::{ + create_vulkan_swapchain_probe, create_vulkan_swapchain_probe_for_extent, VulkanSwapchainProbe, + VulkanSwapchainProbeError, VulkanSwapchainReport, +}; use self::swapchain_resources::{ create_swapchain_resources, destroy_swapchain_resources, VulkanSwapchainResources, }; diff --git a/adapters/fparkan-render-vulkan/src/ffi/runtime.rs b/adapters/fparkan-render-vulkan/src/ffi/runtime.rs index 56d4041..b1c98df 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/runtime.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/runtime.rs @@ -1,14 +1,14 @@ #![allow(unsafe_code)] -use ash::{khr::swapchain, vk}; +use ash::vk; use std::ffi::{CStr, CString}; use super::{VulkanInstanceProbe, VulkanSurfaceProbe}; use crate::policy::{ - compare_reports, plan_vulkan_swapchain, select_composite_alpha, validate_device, - VulkanCapabilityError, VulkanCapabilityReport, VulkanDeviceType, VulkanPhysicalDeviceRecord, - VulkanQueueFamily, VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan, - VulkanSwapchainRequest, VulkanSwapchainSurfaceCapabilities, + compare_reports, plan_vulkan_swapchain, validate_device, VulkanCapabilityError, + VulkanCapabilityReport, VulkanDeviceType, VulkanPhysicalDeviceRecord, VulkanQueueFamily, + VulkanSurfaceFormat, VulkanSwapchainError, VulkanSwapchainPlan, VulkanSwapchainRequest, + VulkanSwapchainSurfaceCapabilities, }; /// Live Vulkan device/surface capability probe. @@ -86,46 +86,6 @@ pub struct VulkanLogicalDeviceReport { pub enabled_extensions: Vec<String>, } -/// Created Vulkan swapchain probe. -pub struct VulkanSwapchainProbe { - loader: swapchain::Device, - swapchain: vk::SwapchainKHR, - /// Deterministic swapchain creation report. - pub report: VulkanSwapchainReport, -} - -impl Drop for VulkanSwapchainProbe { - fn drop(&mut self) { - // SAFETY: The swapchain was created by this probe and is destroyed once during drop. - unsafe { self.loader.destroy_swapchain(self.swapchain, None) }; - } -} - -impl VulkanSwapchainProbe { - /// Returns the live swapchain handle. - #[must_use] - pub fn swapchain(&self) -> vk::SwapchainKHR { - self.swapchain - } - - /// Returns the swapchain extension loader for this live swapchain. - #[must_use] - pub fn loader(&self) -> &swapchain::Device { - &self.loader - } -} - -/// Runtime swapchain creation report. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct VulkanSwapchainReport { - /// Report schema version. - pub schema: u32, - /// Deterministic swapchain policy used for creation. - pub plan: VulkanSwapchainPlan, - /// Number of images returned by `vkGetSwapchainImagesKHR`. - pub image_count: u32, -} - /// Live Vulkan device/surface capability probe error. #[derive(Clone, Debug, Eq, PartialEq)] pub enum VulkanRuntimeCapabilityError { @@ -254,50 +214,6 @@ impl std::fmt::Display for VulkanLogicalDeviceError { impl std::error::Error for VulkanLogicalDeviceError {} -/// Vulkan swapchain creation error. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum VulkanSwapchainProbeError { - /// Live runtime capability probing failed before swapchain creation. - Runtime(VulkanRuntimeCapabilityError), - /// Deterministic swapchain planning failed before create. - Plan(VulkanSwapchainError), - /// Surface capability query failed. - SurfaceCapabilitiesFailed { - /// Vulkan result. - result: vk::Result, - }, - /// Swapchain creation failed. - CreateFailed { - /// Vulkan result. - result: vk::Result, - }, - /// Swapchain image query failed. - ImagesFailed { - /// Vulkan result. - result: vk::Result, - }, -} - -impl std::fmt::Display for VulkanSwapchainProbeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Runtime(error) => write!(f, "{error}"), - Self::Plan(error) => write!(f, "{error}"), - Self::SurfaceCapabilitiesFailed { result } => { - write!(f, "Vulkan surface capabilities query failed: {result:?}") - } - Self::CreateFailed { result } => { - write!(f, "Vulkan swapchain creation failed: {result:?}") - } - Self::ImagesFailed { result } => { - write!(f, "Vulkan swapchain image query failed: {result:?}") - } - } - } -} - -impl std::error::Error for VulkanSwapchainProbeError {} - /// Probes live Vulkan device, queue, surface and swapchain capabilities. /// /// # Errors @@ -377,127 +293,6 @@ pub fn create_vulkan_logical_device_probe( }) } -/// Creates a Vulkan swapchain for the live logical device and surface. -/// -/// # Errors -/// -/// Returns [`VulkanSwapchainProbeError`] when live surface capability queries, -/// swapchain creation, or swapchain image enumeration fails. -pub fn create_vulkan_swapchain_probe( - instance: &VulkanInstanceProbe, - surface: &VulkanSurfaceProbe, - device: &VulkanLogicalDeviceProbe, -) -> Result<VulkanSwapchainProbe, VulkanSwapchainProbeError> { - create_vulkan_swapchain_probe_for_extent( - instance, - surface, - device, - device.runtime.swapchain.extent, - vk::SwapchainKHR::null(), - ) -} - -/// Creates a Vulkan swapchain for the live logical device and surface at a specific extent. -/// -/// # Errors -/// -/// Returns [`VulkanSwapchainProbeError`] when live surface capability queries, -/// swapchain creation, or swapchain image enumeration fails. -pub fn create_vulkan_swapchain_probe_for_extent( - instance: &VulkanInstanceProbe, - surface: &VulkanSurfaceProbe, - device: &VulkanLogicalDeviceProbe, - drawable_extent: (u32, u32), - old_swapchain: vk::SwapchainKHR, -) -> Result<VulkanSwapchainProbe, VulkanSwapchainProbeError> { - let raw_capabilities = { - // SAFETY: The physical device and surface are live query inputs and no handles are retained. - unsafe { - surface - .loader - .get_physical_device_surface_capabilities(device.physical_device(), surface.surface) - } - } - .map_err(|error| VulkanSwapchainProbeError::SurfaceCapabilitiesFailed { result: error })?; - let surface_formats = live_surface_formats( - surface, - device.physical_device(), - &device.report.device_name, - ) - .map_err(VulkanSwapchainProbeError::Runtime)?; - let present_modes = live_present_modes( - surface, - device.physical_device(), - &device.report.device_name, - ) - .map_err(VulkanSwapchainProbeError::Runtime)?; - let capabilities = live_surface_capabilities( - surface, - device.physical_device(), - &device.report.device_name, - ) - .map_err(VulkanSwapchainProbeError::Runtime)?; - let plan = plan_vulkan_swapchain(&VulkanSwapchainRequest { - drawable_extent, - formats: surface_formats, - present_modes, - capabilities, - preferred_present_mode: vk::PresentModeKHR::MAILBOX.as_raw(), - }) - .map_err(VulkanSwapchainProbeError::Plan)?; - let queue_family_indices = unique_queue_families( - device.runtime.capability.graphics_queue_family, - device.runtime.capability.present_queue_family, - ); - let sharing_mode = if queue_family_indices.len() > 1 { - vk::SharingMode::CONCURRENT - } else { - vk::SharingMode::EXCLUSIVE - }; - let create_info = vk::SwapchainCreateInfoKHR::default() - .surface(surface.surface) - .min_image_count(plan.image_count) - .image_format(vk::Format::from_raw(plan.format.format)) - .image_color_space(vk::ColorSpaceKHR::from_raw(plan.format.color_space)) - .image_extent(vk::Extent2D { - width: plan.extent.0, - height: plan.extent.1, - }) - .image_array_layers(1) - .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) - .image_sharing_mode(sharing_mode) - .queue_family_indices(&queue_family_indices) - .pre_transform(raw_capabilities.current_transform) - .composite_alpha(select_composite_alpha( - raw_capabilities.supported_composite_alpha, - )) - .present_mode(vk::PresentModeKHR::from_raw(plan.present_mode)) - .old_swapchain(old_swapchain) - .clipped(true); - let loader = swapchain::Device::new(&instance.instance, device.device()); - // SAFETY: The create info references live instance/device/surface handles for this call. - let swapchain = unsafe { loader.create_swapchain(&create_info, None) } - .map_err(|error| VulkanSwapchainProbeError::CreateFailed { result: error })?; - // SAFETY: The swapchain was created above and the returned image handles are owned by it. - let images = match unsafe { loader.get_swapchain_images(swapchain) } { - Ok(images) => images, - Err(error) => { - // SAFETY: The swapchain was created above on this loader/device pair and is destroyed on setup failure. - unsafe { loader.destroy_swapchain(swapchain, None) }; - return Err(VulkanSwapchainProbeError::ImagesFailed { result: error }); - } - }; - Ok(VulkanSwapchainProbe { - loader, - swapchain, - report: VulkanSwapchainReport { - schema: 1, - plan, - image_count: images.len().try_into().unwrap_or(u32::MAX), - }, - }) -} - struct SelectedLiveDevice { physical_device: vk::PhysicalDevice, runtime: VulkanRuntimeCapabilityProbe, @@ -636,7 +431,7 @@ fn live_device_candidate( }) } -fn unique_queue_families(graphics: u32, present: u32) -> Vec<u32> { +pub(super) fn unique_queue_families(graphics: u32, present: u32) -> Vec<u32> { if graphics == present { vec![graphics] } else { @@ -697,7 +492,7 @@ fn live_device_extensions( Ok(extensions) } -fn live_surface_formats( +pub(super) fn live_surface_formats( surface: &VulkanSurfaceProbe, device: vk::PhysicalDevice, name: &str, @@ -723,7 +518,7 @@ fn live_surface_formats( .collect()) } -fn live_present_modes( +pub(super) fn live_present_modes( surface: &VulkanSurfaceProbe, device: vk::PhysicalDevice, name: &str, @@ -743,7 +538,7 @@ fn live_present_modes( Ok(modes.into_iter().map(vk::PresentModeKHR::as_raw).collect()) } -fn live_surface_capabilities( +pub(super) fn live_surface_capabilities( surface: &VulkanSurfaceProbe, device: vk::PhysicalDevice, name: &str, diff --git a/adapters/fparkan-render-vulkan/src/ffi/swapchain.rs b/adapters/fparkan-render-vulkan/src/ffi/swapchain.rs new file mode 100644 index 0000000..adfca60 --- /dev/null +++ b/adapters/fparkan-render-vulkan/src/ffi/swapchain.rs @@ -0,0 +1,220 @@ +#![allow(unsafe_code)] + +use ash::{khr::swapchain, vk}; + +use super::{ + runtime::{ + live_present_modes, live_surface_capabilities, live_surface_formats, unique_queue_families, + }, + VulkanInstanceProbe, VulkanLogicalDeviceProbe, VulkanRuntimeCapabilityError, + VulkanSurfaceProbe, +}; +use crate::policy::{ + plan_vulkan_swapchain, select_composite_alpha, VulkanSwapchainError, VulkanSwapchainPlan, + VulkanSwapchainRequest, +}; + +/// Created Vulkan swapchain probe. +pub struct VulkanSwapchainProbe { + loader: swapchain::Device, + swapchain: vk::SwapchainKHR, + /// Deterministic swapchain creation report. + pub report: VulkanSwapchainReport, +} + +impl Drop for VulkanSwapchainProbe { + fn drop(&mut self) { + // SAFETY: The swapchain was created by this probe and is destroyed once during drop. + unsafe { self.loader.destroy_swapchain(self.swapchain, None) }; + } +} + +impl VulkanSwapchainProbe { + /// Returns the live swapchain handle. + #[must_use] + pub fn swapchain(&self) -> vk::SwapchainKHR { + self.swapchain + } + + /// Returns the swapchain extension loader for this live swapchain. + #[must_use] + pub fn loader(&self) -> &swapchain::Device { + &self.loader + } +} + +/// Runtime swapchain creation report. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VulkanSwapchainReport { + /// Report schema version. + pub schema: u32, + /// Deterministic swapchain policy used for creation. + pub plan: VulkanSwapchainPlan, + /// Number of images returned by `vkGetSwapchainImagesKHR`. + pub image_count: u32, +} + +/// Vulkan swapchain creation error. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum VulkanSwapchainProbeError { + /// Live runtime capability probing failed before swapchain creation. + Runtime(VulkanRuntimeCapabilityError), + /// Deterministic swapchain planning failed before create. + Plan(VulkanSwapchainError), + /// Surface capability query failed. + SurfaceCapabilitiesFailed { + /// Vulkan result. + result: vk::Result, + }, + /// Swapchain creation failed. + CreateFailed { + /// Vulkan result. + result: vk::Result, + }, + /// Swapchain image query failed. + ImagesFailed { + /// Vulkan result. + result: vk::Result, + }, +} + +impl std::fmt::Display for VulkanSwapchainProbeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Runtime(error) => write!(f, "{error}"), + Self::Plan(error) => write!(f, "{error}"), + Self::SurfaceCapabilitiesFailed { result } => { + write!(f, "Vulkan surface capabilities query failed: {result:?}") + } + Self::CreateFailed { result } => { + write!(f, "Vulkan swapchain creation failed: {result:?}") + } + Self::ImagesFailed { result } => { + write!(f, "Vulkan swapchain image query failed: {result:?}") + } + } + } +} + +impl std::error::Error for VulkanSwapchainProbeError {} + +/// Creates a Vulkan swapchain for the live logical device and surface. +/// +/// # Errors +/// +/// Returns [`VulkanSwapchainProbeError`] when live surface capability queries, +/// swapchain creation, or swapchain image enumeration fails. +pub fn create_vulkan_swapchain_probe( + instance: &VulkanInstanceProbe, + surface: &VulkanSurfaceProbe, + device: &VulkanLogicalDeviceProbe, +) -> Result<VulkanSwapchainProbe, VulkanSwapchainProbeError> { + create_vulkan_swapchain_probe_for_extent( + instance, + surface, + device, + device.runtime.swapchain.extent, + vk::SwapchainKHR::null(), + ) +} + +/// Creates a Vulkan swapchain for the live logical device and surface at a specific extent. +/// +/// # Errors +/// +/// Returns [`VulkanSwapchainProbeError`] when live surface capability queries, +/// swapchain creation, or swapchain image enumeration fails. +pub fn create_vulkan_swapchain_probe_for_extent( + instance: &VulkanInstanceProbe, + surface: &VulkanSurfaceProbe, + device: &VulkanLogicalDeviceProbe, + drawable_extent: (u32, u32), + old_swapchain: vk::SwapchainKHR, +) -> Result<VulkanSwapchainProbe, VulkanSwapchainProbeError> { + let raw_capabilities = { + // SAFETY: The physical device and surface are live query inputs and no handles are retained. + unsafe { + surface + .loader + .get_physical_device_surface_capabilities(device.physical_device(), surface.surface) + } + } + .map_err(|error| VulkanSwapchainProbeError::SurfaceCapabilitiesFailed { result: error })?; + let surface_formats = live_surface_formats( + surface, + device.physical_device(), + &device.report.device_name, + ) + .map_err(VulkanSwapchainProbeError::Runtime)?; + let present_modes = live_present_modes( + surface, + device.physical_device(), + &device.report.device_name, + ) + .map_err(VulkanSwapchainProbeError::Runtime)?; + let capabilities = live_surface_capabilities( + surface, + device.physical_device(), + &device.report.device_name, + ) + .map_err(VulkanSwapchainProbeError::Runtime)?; + let plan = plan_vulkan_swapchain(&VulkanSwapchainRequest { + drawable_extent, + formats: surface_formats, + present_modes, + capabilities, + preferred_present_mode: vk::PresentModeKHR::MAILBOX.as_raw(), + }) + .map_err(VulkanSwapchainProbeError::Plan)?; + let queue_family_indices = unique_queue_families( + device.runtime.capability.graphics_queue_family, + device.runtime.capability.present_queue_family, + ); + let sharing_mode = if queue_family_indices.len() > 1 { + vk::SharingMode::CONCURRENT + } else { + vk::SharingMode::EXCLUSIVE + }; + let create_info = vk::SwapchainCreateInfoKHR::default() + .surface(surface.surface) + .min_image_count(plan.image_count) + .image_format(vk::Format::from_raw(plan.format.format)) + .image_color_space(vk::ColorSpaceKHR::from_raw(plan.format.color_space)) + .image_extent(vk::Extent2D { + width: plan.extent.0, + height: plan.extent.1, + }) + .image_array_layers(1) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(sharing_mode) + .queue_family_indices(&queue_family_indices) + .pre_transform(raw_capabilities.current_transform) + .composite_alpha(select_composite_alpha( + raw_capabilities.supported_composite_alpha, + )) + .present_mode(vk::PresentModeKHR::from_raw(plan.present_mode)) + .old_swapchain(old_swapchain) + .clipped(true); + let loader = swapchain::Device::new(&instance.instance, device.device()); + // SAFETY: The create info references live instance/device/surface handles for this call. + let swapchain = unsafe { loader.create_swapchain(&create_info, None) } + .map_err(|error| VulkanSwapchainProbeError::CreateFailed { result: error })?; + // SAFETY: The swapchain was created above and the returned image handles are owned by it. + let images = match unsafe { loader.get_swapchain_images(swapchain) } { + Ok(images) => images, + Err(error) => { + // SAFETY: The swapchain was created above on this loader/device pair and is destroyed on setup failure. + unsafe { loader.destroy_swapchain(swapchain, None) }; + return Err(VulkanSwapchainProbeError::ImagesFailed { result: error }); + } + }; + Ok(VulkanSwapchainProbe { + loader, + swapchain, + report: VulkanSwapchainReport { + schema: 1, + plan, + image_count: images.len().try_into().unwrap_or(u32::MAX), + }, + }) +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 412934e..484e9c5 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1245,6 +1245,7 @@ const AUDITED_UNSAFE_SOURCE_FILES: &[&str] = &[ "adapters/fparkan-render-vulkan/src/ffi/resources.rs", "adapters/fparkan-render-vulkan/src/ffi/runtime.rs", "adapters/fparkan-render-vulkan/src/ffi/smoke.rs", + "adapters/fparkan-render-vulkan/src/ffi/swapchain.rs", "adapters/fparkan-render-vulkan/src/ffi/swapchain_resources.rs", "adapters/fparkan-render-vulkan/src/ffi/surface.rs", "adapters/fparkan-render-vulkan/src/ffi/validation.rs", |
