From 0de511857528c9757ed21bdb084636b9e370ee57 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Thu, 25 Jun 2026 05:37:24 +0400 Subject: refactor(vulkan-backend): extract planning facade module --- adapters/fparkan-render-vulkan/src/ffi.rs | 165 ++------------------- adapters/fparkan-render-vulkan/src/lib.rs | 2 + .../fparkan-render-vulkan/src/planning_backend.rs | 157 ++++++++++++++++++++ 3 files changed, 171 insertions(+), 153 deletions(-) create mode 100644 adapters/fparkan-render-vulkan/src/planning_backend.rs diff --git a/adapters/fparkan-render-vulkan/src/ffi.rs b/adapters/fparkan-render-vulkan/src/ffi.rs index ea0249f..cf6901c 100644 --- a/adapters/fparkan-render-vulkan/src/ffi.rs +++ b/adapters/fparkan-render-vulkan/src/ffi.rs @@ -32,11 +32,8 @@ use ash::{ vk, }; use fparkan_binary::{sha256, sha256_hex}; -use fparkan_platform::{NativeWindowHandles, RenderRequest}; -use fparkan_render::{ - canonical_capture, validate_command_list, FrameOutput, RenderBackend, RenderCommand, - RenderCommandList, RenderError, -}; +use fparkan_platform::NativeWindowHandles; +use fparkan_render::{validate_command_list, RenderCommand, RenderCommandList, RenderError}; use serde::Serialize; use std::collections::BTreeSet; use std::ffi::{CStr, CString}; @@ -3600,23 +3597,6 @@ fn render_shader_manifest_without_hash_json(modules: &[VulkanShaderModuleReport] } } -/// Vulkan backend migration readiness. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum VulkanPlanningBackendState { - /// Adapter prepared and able to accept commands. - Ready, - /// Adapter is tracking a recoverable runtime surface/depth pipeline fault. - Degraded, - /// Adapter has encountered a non-recoverable error. - Error, -} - -impl Default for VulkanPlanningBackendState { - fn default() -> Self { - Self::Degraded - } -} - /// Synthetic physical-device type used by deterministic capability scoring. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum VulkanDeviceType { @@ -4320,139 +4300,12 @@ fn format_api_version(version: u32) -> String { ) } -/// Diagnostics for Vulkan planning backend setup and frame progression. -#[derive(Clone, Debug, PartialEq)] -pub struct VulkanPlanningBackendReport { - /// Total frames executed. - pub frames_executed: u64, - /// Total command submissions. - pub submissions: u64, - /// Last command-capture byte size. - pub last_capture_size: usize, - /// Number of simulated present calls issued by the planning facade. - pub simulated_presents: u64, - /// Number of resize-driven surface plan refreshes. - pub resize_rebuilds: u64, - /// Last render request observed. - pub request: RenderRequest, - /// Last deterministic frame submission plan. - pub last_frame_submission: Option, -} - -impl Default for VulkanPlanningBackendReport { - fn default() -> Self { - Self { - frames_executed: 0, - submissions: 0, - last_capture_size: 0, - simulated_presents: 0, - resize_rebuilds: 0, - request: RenderRequest::conservative(), - last_frame_submission: None, - } - } -} - -/// Vulkan planning backend façade used by the game entrypoint. -#[derive(Debug)] -pub struct VulkanPlanningBackend { - state: VulkanPlanningBackendState, - report: VulkanPlanningBackendReport, - swapchain_plan: VulkanSwapchainPlan, -} - -impl Default for VulkanPlanningBackend { - fn default() -> Self { - Self::new() - } -} - -impl VulkanPlanningBackend { - /// Creates a new Vulkan planning backend façade. - #[must_use] - pub fn new() -> Self { - Self { - state: VulkanPlanningBackendState::Ready, - report: VulkanPlanningBackendReport::default(), - swapchain_plan: default_stage0_swapchain_plan(), - } - } - - /// Replaces active surface/profile request. - pub fn set_render_request(&mut self, request: RenderRequest) { - self.report.request = request; - self.report.resize_rebuilds = self.report.resize_rebuilds.saturating_add(1); - } - - /// Returns active render request policy. - #[must_use] - pub const fn render_request(&self) -> RenderRequest { - self.report.request - } - - /// Replaces active swapchain plan used for frame submission planning. - pub fn set_swapchain_plan(&mut self, plan: VulkanSwapchainPlan) { - self.swapchain_plan = plan; - } - - /// Returns active swapchain plan. - #[must_use] - pub const fn swapchain_plan(&self) -> &VulkanSwapchainPlan { - &self.swapchain_plan - } - - /// Returns adapter state. - #[must_use] - pub const fn state(&self) -> VulkanPlanningBackendState { - self.state - } - - /// Returns backend report. - #[must_use] - pub fn report(&self) -> &VulkanPlanningBackendReport { - &self.report - } - - fn simulate_present(&mut self) { - self.report.simulated_presents = self.report.simulated_presents.saturating_add(1); - } -} - -impl RenderBackend for VulkanPlanningBackend { - fn execute(&mut self, commands: &RenderCommandList) -> Result { - if !matches!( - self.state, - VulkanPlanningBackendState::Ready | VulkanPlanningBackendState::Degraded - ) { - return Err(RenderError::InvalidRange); - } - let capture = canonical_capture(commands)?; - let frame_plan = plan_vulkan_frame_submission(&self.swapchain_plan, commands)?; - self.report.frames_executed = self.report.frames_executed.saturating_add(1); - self.report.submissions = self.report.submissions.saturating_add(1); - self.report.last_capture_size = capture.len(); - self.report.last_frame_submission = Some(frame_plan); - self.simulate_present(); - Ok(FrameOutput) - } -} - -fn default_stage0_swapchain_plan() -> VulkanSwapchainPlan { - VulkanSwapchainPlan { - schema: 1, - extent: (1, 1), - format: VulkanSurfaceFormat { - format: vk::Format::B8G8R8A8_SRGB.as_raw(), - color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(), - }, - present_mode: vk::PresentModeKHR::FIFO.as_raw(), - image_count: 2, - } -} - #[cfg(test)] mod tests { use super::*; + use crate::*; + use fparkan_platform::RenderRequest; + use fparkan_render::RenderBackend; use fparkan_render::{ DrawCommand, DrawId, GpuMaterialId, GpuMeshId, IndexRange, RenderCommand, RenderPhase, }; @@ -4522,8 +4375,14 @@ mod tests { ], }; let swapchain = VulkanSwapchainPlan { + schema: 1, + extent: (1, 1), + format: VulkanSurfaceFormat { + format: vk::Format::B8G8R8A8_SRGB.as_raw(), + color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(), + }, + present_mode: vk::PresentModeKHR::FIFO.as_raw(), image_count: 3, - ..default_stage0_swapchain_plan() }; let plan = plan_vulkan_frame_submission(&swapchain, &commands)?; diff --git a/adapters/fparkan-render-vulkan/src/lib.rs b/adapters/fparkan-render-vulkan/src/lib.rs index dc09c0d..f5cf625 100644 --- a/adapters/fparkan-render-vulkan/src/lib.rs +++ b/adapters/fparkan-render-vulkan/src/lib.rs @@ -2,5 +2,7 @@ //! Vulkan adapter public surface. mod ffi; +mod planning_backend; pub use ffi::*; +pub use planning_backend::*; diff --git a/adapters/fparkan-render-vulkan/src/planning_backend.rs b/adapters/fparkan-render-vulkan/src/planning_backend.rs new file mode 100644 index 0000000..7486047 --- /dev/null +++ b/adapters/fparkan-render-vulkan/src/planning_backend.rs @@ -0,0 +1,157 @@ +use ash::vk; +use fparkan_platform::RenderRequest; +use fparkan_render::{ + canonical_capture, FrameOutput, RenderBackend, RenderCommandList, RenderError, +}; + +use crate::{ + plan_vulkan_frame_submission, VulkanFrameSubmissionPlan, VulkanSurfaceFormat, + VulkanSwapchainPlan, +}; + +/// Vulkan backend migration readiness. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum VulkanPlanningBackendState { + /// Adapter prepared and able to accept commands. + Ready, + /// Adapter is tracking a recoverable runtime surface/depth pipeline fault. + Degraded, + /// Adapter has encountered a non-recoverable error. + Error, +} + +impl Default for VulkanPlanningBackendState { + fn default() -> Self { + Self::Degraded + } +} + +/// Diagnostics for Vulkan planning backend setup and frame progression. +#[derive(Clone, Debug, PartialEq)] +pub struct VulkanPlanningBackendReport { + /// Total frames executed. + pub frames_executed: u64, + /// Total command submissions. + pub submissions: u64, + /// Last command-capture byte size. + pub last_capture_size: usize, + /// Number of simulated present calls issued by the planning facade. + pub simulated_presents: u64, + /// Number of resize-driven surface plan refreshes. + pub resize_rebuilds: u64, + /// Last render request observed. + pub request: RenderRequest, + /// Last deterministic frame submission plan. + pub last_frame_submission: Option, +} + +impl Default for VulkanPlanningBackendReport { + fn default() -> Self { + Self { + frames_executed: 0, + submissions: 0, + last_capture_size: 0, + simulated_presents: 0, + resize_rebuilds: 0, + request: RenderRequest::conservative(), + last_frame_submission: None, + } + } +} + +/// Vulkan planning backend facade used by the game entrypoint. +#[derive(Debug)] +pub struct VulkanPlanningBackend { + state: VulkanPlanningBackendState, + report: VulkanPlanningBackendReport, + swapchain_plan: VulkanSwapchainPlan, +} + +impl Default for VulkanPlanningBackend { + fn default() -> Self { + Self::new() + } +} + +impl VulkanPlanningBackend { + /// Creates a new Vulkan planning backend facade. + #[must_use] + pub fn new() -> Self { + Self { + state: VulkanPlanningBackendState::Ready, + report: VulkanPlanningBackendReport::default(), + swapchain_plan: default_stage0_swapchain_plan(), + } + } + + /// Replaces active surface/profile request. + pub fn set_render_request(&mut self, request: RenderRequest) { + self.report.request = request; + self.report.resize_rebuilds = self.report.resize_rebuilds.saturating_add(1); + } + + /// Returns active render request policy. + #[must_use] + pub const fn render_request(&self) -> RenderRequest { + self.report.request + } + + /// Replaces active swapchain plan used for frame submission planning. + pub fn set_swapchain_plan(&mut self, plan: VulkanSwapchainPlan) { + self.swapchain_plan = plan; + } + + /// Returns active swapchain plan. + #[must_use] + pub const fn swapchain_plan(&self) -> &VulkanSwapchainPlan { + &self.swapchain_plan + } + + /// Returns adapter state. + #[must_use] + pub const fn state(&self) -> VulkanPlanningBackendState { + self.state + } + + /// Returns backend report. + #[must_use] + pub fn report(&self) -> &VulkanPlanningBackendReport { + &self.report + } + + fn simulate_present(&mut self) { + self.report.simulated_presents = self.report.simulated_presents.saturating_add(1); + } +} + +impl RenderBackend for VulkanPlanningBackend { + fn execute(&mut self, commands: &RenderCommandList) -> Result { + if !matches!( + self.state, + VulkanPlanningBackendState::Ready | VulkanPlanningBackendState::Degraded + ) { + return Err(RenderError::InvalidRange); + } + let capture = canonical_capture(commands)?; + let frame_plan = plan_vulkan_frame_submission(&self.swapchain_plan, commands)?; + self.report.frames_executed = self.report.frames_executed.saturating_add(1); + self.report.submissions = self.report.submissions.saturating_add(1); + self.report.last_capture_size = capture.len(); + self.report.last_frame_submission = Some(frame_plan); + self.simulate_present(); + Ok(FrameOutput) + } +} + +fn default_stage0_swapchain_plan() -> VulkanSwapchainPlan { + VulkanSwapchainPlan { + schema: 1, + extent: (1, 1), + format: VulkanSurfaceFormat { + format: vk::Format::B8G8R8A8_SRGB.as_raw(), + color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(), + }, + present_mode: vk::PresentModeKHR::FIFO.as_raw(), + image_count: 2, + } +} -- cgit v1.2.3