diff options
| author | Valentin Popov <valentin@popov.link> | 2026-06-23 21:43:54 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-06-23 21:43:54 +0300 |
| commit | 8ea1fd5c188998a005d9bf48c090af4324608eff (patch) | |
| tree | 418eadb7de0b2acdb8cf4c2a0da1cadfa40b1734 /adapters/fparkan-render-vulkan/src/lib.rs | |
| parent | 69c032accab677b53f3dff61f3afb870c2e8e0a8 (diff) | |
| download | fparkan-8ea1fd5c188998a005d9bf48c090af4324608eff.tar.xz fparkan-8ea1fd5c188998a005d9bf48c090af4324608eff.zip | |
feat: probe Vulkan loader boundary
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/lib.rs')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/lib.rs | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/adapters/fparkan-render-vulkan/src/lib.rs b/adapters/fparkan-render-vulkan/src/lib.rs index 75447e8..9973676 100644 --- a/adapters/fparkan-render-vulkan/src/lib.rs +++ b/adapters/fparkan-render-vulkan/src/lib.rs @@ -1,4 +1,4 @@ -#![forbid(unsafe_code)] +#![allow(unsafe_code)] #![cfg_attr( test, allow( @@ -32,6 +32,7 @@ use fparkan_platform::RenderRequest; use fparkan_render::{ canonical_capture, FrameOutput, RenderBackend, RenderCommandList, RenderError, }; +use std::ffi::CStr; use std::time::{SystemTime, UNIX_EPOCH}; /// Minimum Vulkan API version accepted by the Stage 0 backend. @@ -39,6 +40,87 @@ pub const MIN_VULKAN_API_VERSION: u32 = vk::API_VERSION_1_1; const KHR_SWAPCHAIN_EXTENSION: &str = "VK_KHR_swapchain"; const KHR_PORTABILITY_SUBSET_EXTENSION: &str = "VK_KHR_portability_subset"; +/// Deterministic Vulkan loader probe report. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VulkanLoaderProbeReport { + /// Report schema version. + pub schema: u32, + /// Whether the Vulkan loader was opened successfully. + pub loader_available: bool, + /// Reported loader instance API version. + pub instance_api_version: u32, +} + +/// Vulkan loader bootstrap error. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum VulkanLoaderError { + /// The Vulkan loader library could not be opened. + Unavailable { + /// Loader error text. + message: String, + }, +} + +impl std::fmt::Display for VulkanLoaderError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Unavailable { message } => { + write!(f, "Vulkan loader is unavailable: {message}") + } + } + } +} + +impl std::error::Error for VulkanLoaderError {} + +/// Opens the Vulkan loader and reports the supported instance API version. +/// +/// # Errors +/// +/// Returns [`VulkanLoaderError`] when no Vulkan loader library can be opened on +/// the host. +pub fn probe_vulkan_loader() -> Result<VulkanLoaderProbeReport, VulkanLoaderError> { + // SAFETY: Loading the entry only resolves loader symbols; no raw Vulkan handles escape. + let entry = unsafe { ash::Entry::load() }.map_err(|error| VulkanLoaderError::Unavailable { + message: error.to_string(), + })?; + // SAFETY: The resolved entry only queries the loader-supported instance API version. + let version = unsafe { entry.try_enumerate_instance_version() } + .map_err(|error| VulkanLoaderError::Unavailable { + message: error.to_string(), + })? + .unwrap_or(vk::API_VERSION_1_0); + Ok(VulkanLoaderProbeReport { + schema: 1, + loader_available: true, + instance_api_version: version, + }) +} + +/// Returns the static Vulkan entry name used by loader probes. +#[must_use] +pub fn vulkan_entry_symbol_name() -> &'static CStr { + c"vkGetInstanceProcAddr" +} + +/// Renders a deterministic JSON Vulkan loader report. +#[must_use] +pub fn render_loader_probe_report_json(report: &VulkanLoaderProbeReport) -> String { + let mut out = String::new(); + out.push_str("{\"schema\":"); + out.push_str(&report.schema.to_string()); + out.push_str(",\"loader_available\":"); + out.push_str(if report.loader_available { + "true" + } else { + "false" + }); + out.push_str(",\"instance_api\":\""); + out.push_str(&format_api_version(report.instance_api_version)); + out.push_str("\"}"); + out +} + /// Vulkan backend migration readiness. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum VulkanBackendState { @@ -641,6 +723,33 @@ mod tests { ); } + #[test] + fn loader_probe_report_json_is_stable() { + assert_eq!( + vulkan_entry_symbol_name().to_bytes(), + b"vkGetInstanceProcAddr" + ); + assert_eq!( + render_loader_probe_report_json(&VulkanLoaderProbeReport { + schema: 1, + loader_available: true, + instance_api_version: vk::API_VERSION_1_2, + }), + "{\"schema\":1,\"loader_available\":true,\"instance_api\":\"1.2.0\"}" + ); + } + + #[test] + fn loader_error_display_is_actionable() { + assert_eq!( + VulkanLoaderError::Unavailable { + message: "dlopen failed".to_string(), + } + .to_string(), + "Vulkan loader is unavailable: dlopen failed" + ); + } + fn device( name: &str, device_type: VulkanDeviceType, |
