aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-25 04:37:24 +0300
committerValentin Popov <valentin@popov.link>2026-06-25 10:45:35 +0300
commit0de511857528c9757ed21bdb084636b9e370ee57 (patch)
treead3e2d127c3d0cbe3986f0b5499df27e96f6f55a
parent0d139b1aae20c44249dc8217b759db78bac96fdc (diff)
downloadfparkan-0de511857528c9757ed21bdb084636b9e370ee57.tar.xz
fparkan-0de511857528c9757ed21bdb084636b9e370ee57.zip
refactor(vulkan-backend): extract planning facade module
-rw-r--r--adapters/fparkan-render-vulkan/src/ffi.rs165
-rw-r--r--adapters/fparkan-render-vulkan/src/lib.rs2
-rw-r--r--adapters/fparkan-render-vulkan/src/planning_backend.rs157
3 files changed, 171 insertions, 153 deletions
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<VulkanFrameSubmissionPlan>,
-}
-
-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<FrameOutput, RenderError> {
- 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<VulkanFrameSubmissionPlan>,
+}
+
+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<FrameOutput, RenderError> {
+ 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,
+ }
+}