diff options
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/ffi.rs')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi.rs | 163 |
1 files changed, 8 insertions, 155 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi.rs b/adapters/fparkan-render-vulkan/src/ffi.rs index 070c2ad..9be61eb 100644 --- a/adapters/fparkan-render-vulkan/src/ffi.rs +++ b/adapters/fparkan-render-vulkan/src/ffi.rs @@ -28,6 +28,7 @@ //! This crate is the declared low-level Vulkan boundary. mod instance; +mod surface; pub use self::instance::{ create_vulkan_instance_probe, plan_vulkan_instance, probe_vulkan_loader, @@ -37,19 +38,20 @@ pub use self::instance::{ }; #[cfg(test)] use self::instance::{cstring_vec, ensure_instance_extensions_available}; +#[cfg(test)] +use self::surface::extension_name; +pub use self::surface::{ + create_vulkan_surface_probe, plan_vulkan_surface, render_surface_plan_json, VulkanSurfaceError, + VulkanSurfacePlan, VulkanSurfaceProbe, +}; use crate::policy::*; use crate::shader_manifest::{ triangle_shader_manifest, validate_shader_manifest, VulkanShaderManifestError, }; -use ash::{ - khr::{surface, swapchain}, - vk, -}; +use ash::{khr::swapchain, vk}; use fparkan_platform::NativeWindowHandles; -use serde::Serialize; use std::collections::BTreeSet; use std::ffi::{CStr, CString}; -use std::os::raw::c_char; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Mutex; /// Minimum Vulkan API version accepted by the Stage 0 backend. @@ -442,74 +444,6 @@ pub(crate) const TRIANGLE_FRAGMENT_SHADER_WORDS: &[u32] = &[ 0x0001_0038, ]; -/// Deterministic Vulkan surface creation plan. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct VulkanSurfacePlan { - /// Report schema version. - pub schema: u32, - /// Instance extensions required by the native display backend. - pub required_instance_extensions: Vec<String>, -} - -/// Vulkan surface bootstrap error. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum VulkanSurfaceError { - /// No native raw window/display handles were available. - MissingNativeHandles, - /// Required platform surface extensions could not be enumerated. - RequiredExtensionsFailed { - /// Vulkan result. - result: vk::Result, - }, - /// A required extension pointer was not valid UTF-8. - InvalidExtensionName, - /// Surface creation failed. - CreateFailed { - /// Vulkan result. - result: vk::Result, - }, -} - -impl std::fmt::Display for VulkanSurfaceError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::MissingNativeHandles => { - write!( - f, - "native window/display handles are required for Vulkan surface creation" - ) - } - Self::RequiredExtensionsFailed { result } => write!( - f, - "failed to enumerate required Vulkan surface extensions: {result:?}" - ), - Self::InvalidExtensionName => { - write!(f, "Vulkan surface extension name is not valid UTF-8") - } - Self::CreateFailed { result } => { - write!(f, "Vulkan surface creation failed: {result:?}") - } - } - } -} - -impl std::error::Error for VulkanSurfaceError {} - -/// Created Vulkan surface probe. -pub struct VulkanSurfaceProbe { - loader: surface::Instance, - surface: vk::SurfaceKHR, - /// Deterministic surface creation report. - pub report: VulkanSurfacePlan, -} - -impl Drop for VulkanSurfaceProbe { - fn drop(&mut self) { - // SAFETY: The `SurfaceKHR` was created by this probe and is destroyed once during drop. - unsafe { self.loader.destroy_surface(self.surface, None) }; - } -} - /// Live Vulkan device/surface capability probe. #[derive(Clone, Debug, Eq, PartialEq)] pub struct VulkanRuntimeCapabilityProbe { @@ -2308,61 +2242,6 @@ impl std::fmt::Display for VulkanSwapchainProbeError { impl std::error::Error for VulkanSwapchainProbeError {} -/// Builds a deterministic Vulkan surface plan from native window handles. -/// -/// # Errors -/// -/// Returns [`VulkanSurfaceError`] when no native handles exist or the platform -/// display backend has no Vulkan surface extension mapping. -pub fn plan_vulkan_surface( - handles: Option<NativeWindowHandles>, -) -> Result<VulkanSurfacePlan, VulkanSurfaceError> { - let handles = handles.ok_or(VulkanSurfaceError::MissingNativeHandles)?; - let required = ash_window::enumerate_required_extensions(handles.display) - .map_err(|error| VulkanSurfaceError::RequiredExtensionsFailed { result: error })?; - let mut required_instance_extensions = Vec::with_capacity(required.len()); - for extension in required { - let name = extension_name(*extension)?; - required_instance_extensions.push(name); - } - required_instance_extensions.sort(); - required_instance_extensions.dedup(); - Ok(VulkanSurfacePlan { - schema: 1, - required_instance_extensions, - }) -} - -/// Creates a Vulkan surface probe from native window handles. -/// -/// # Errors -/// -/// Returns [`VulkanSurfaceError`] when handles are missing, required extensions -/// cannot be planned, or `vkCreate*SurfaceKHR` fails. -pub fn create_vulkan_surface_probe( - instance: &VulkanInstanceProbe, - handles: Option<NativeWindowHandles>, -) -> Result<VulkanSurfaceProbe, VulkanSurfaceError> { - let handles = handles.ok_or(VulkanSurfaceError::MissingNativeHandles)?; - let report = plan_vulkan_surface(Some(handles))?; - // SAFETY: The platform handles are only used to create a child surface owned by this probe. - let surface = unsafe { - ash_window::create_surface( - &instance.entry, - &instance.instance, - handles.display, - handles.window, - None, - ) - } - .map_err(|error| VulkanSurfaceError::CreateFailed { result: error })?; - Ok(VulkanSurfaceProbe { - loader: surface::Instance::new(&instance.entry, &instance.instance), - surface, - report, - }) -} - /// Probes live Vulkan device, queue, surface and swapchain capabilities. /// /// # Errors @@ -2841,32 +2720,6 @@ fn live_surface_capabilities( }) } -/// Renders a deterministic JSON Vulkan surface plan. -#[must_use] -pub fn render_surface_plan_json(plan: &VulkanSurfacePlan) -> String { - #[derive(Serialize)] - struct SurfacePlanJson<'a> { - schema: u32, - required_instance_extensions: &'a [String], - } - - serialize_json_or_fallback( - &SurfacePlanJson { - schema: plan.schema, - required_instance_extensions: &plan.required_instance_extensions, - }, - "{\"schema\":0,\"required_instance_extensions\":[]}", - ) -} - -fn extension_name(extension: *const c_char) -> Result<String, VulkanSurfaceError> { - // SAFETY: `ash-window` returns extension pointers to static NUL-terminated Vulkan names. - let name = unsafe { CStr::from_ptr(extension) }; - name.to_str() - .map(str::to_string) - .map_err(|_| VulkanSurfaceError::InvalidExtensionName) -} - #[cfg(test)] mod tests { use super::*; |
