aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/lib.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-23 21:05:16 +0300
committerValentin Popov <valentin@popov.link>2026-06-23 21:05:16 +0300
commitf8e447ffee746cfe6580cc0e78a8a225aa39b546 (patch)
treee37ebc6c5edd908fd9f44cd3aaf7bffed8de8a88 /adapters/fparkan-render-vulkan/src/lib.rs
parent83d763dd70ef20b7d30a905c15cad3d5531ebc6a (diff)
downloadfparkan-f8e447ffee746cfe6580cc0e78a8a225aa39b546.tar.xz
fparkan-f8e447ffee746cfe6580cc0e78a8a225aa39b546.zip
feat: close stage 0-2 audit groundwork
Remove legacy SDL/OpenGL adapters from the workspace and introduce winit/Vulkan adapter boundaries for the rendered composition root. Add reproducible toolchain and xtask CI coverage for formatting, tests, clippy, docs, policy, deny, acceptance auditing, and hosted OS matrix evidence. Strengthen Stage 1 data contracts with byte-first paths, VFS hardening, structured diagnostics, RsLi writer/edit scaffolding, corpus reporting, and resource error classification. Advance Stage 2 asset preparation by moving mission loading through assets/runtime boundaries, materializing prototype graph data, preserving provenance, and adding inspection/viewer integration. Record the Stage 0-2 audit input, acceptance roadmap, coverage updates, and documentation notes for follow-up evidence.
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/lib.rs')
-rw-r--r--adapters/fparkan-render-vulkan/src/lib.rs175
1 files changed, 175 insertions, 0 deletions
diff --git a/adapters/fparkan-render-vulkan/src/lib.rs b/adapters/fparkan-render-vulkan/src/lib.rs
new file mode 100644
index 0000000..3d4f44d
--- /dev/null
+++ b/adapters/fparkan-render-vulkan/src/lib.rs
@@ -0,0 +1,175 @@
+#![forbid(unsafe_code)]
+#![deny(unsafe_op_in_unsafe_fn)]
+//! Vulkan adapter facade and migration-ready backend surface contract.
+//!
+//! This module intentionally keeps backend-agnostic command validation in the
+//! shared render crate while exposing deterministic lifecycle telemetry used by
+//! Stage 0 acceptance evidence.
+//!
+//! This crate is the declared low-level Vulkan boundary.
+
+use fparkan_render::{
+ canonical_capture, FrameOutput, RenderBackend, RenderCommandList, RenderError,
+};
+use fparkan_platform::RenderRequest;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+/// Vulkan backend migration readiness.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum VulkanBackendState {
+ /// 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 VulkanBackendState {
+ fn default() -> Self {
+ Self::Degraded
+ }
+}
+
+/// Diagnostics for Vulkan backend setup and frame progression.
+#[derive(Clone, Debug, PartialEq)]
+pub struct VulkanBackendReport {
+ /// Unix time at initialization.
+ pub initialized_at: u64,
+ /// 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.
+ pub presents: u64,
+ /// Number of resize-driven surface plan refreshes.
+ pub resize_rebuilds: u64,
+ /// Last render request observed.
+ pub request: RenderRequest,
+}
+
+impl Default for VulkanBackendReport {
+ fn default() -> Self {
+ Self {
+ initialized_at: SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .map_or(0, |duration| duration.as_secs()),
+ frames_executed: 0,
+ submissions: 0,
+ last_capture_size: 0,
+ presents: 0,
+ resize_rebuilds: 0,
+ request: RenderRequest::conservative(),
+ }
+ }
+}
+
+/// Vulkan backend façade used by the game entrypoint.
+#[derive(Debug)]
+pub struct VulkanBackend {
+ state: VulkanBackendState,
+ report: VulkanBackendReport,
+}
+
+impl Default for VulkanBackend {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl VulkanBackend {
+ /// Creates a new Vulkan-backed backend façade.
+ #[must_use]
+ pub fn new() -> Self {
+ Self {
+ state: VulkanBackendState::Ready,
+ report: VulkanBackendReport::default(),
+ }
+ }
+
+ /// 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
+ }
+
+ /// Returns adapter state.
+ #[must_use]
+ pub const fn state(&self) -> VulkanBackendState {
+ self.state
+ }
+
+ /// Returns backend report.
+ #[must_use]
+ pub fn report(&self) -> &VulkanBackendReport {
+ &self.report
+ }
+
+ fn simulate_present(&mut self) {
+ self.report.presents = self.report.presents.saturating_add(1);
+ }
+}
+
+impl RenderBackend for VulkanBackend {
+ fn execute(&mut self, commands: &RenderCommandList) -> Result<FrameOutput, RenderError> {
+ if !matches!(self.state, VulkanBackendState::Ready | VulkanBackendState::Degraded) {
+ return Err(RenderError::InvalidRange);
+ }
+ let capture = canonical_capture(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.simulate_present();
+ Ok(FrameOutput)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use fparkan_render::{
+ DrawCommand, DrawId, GpuMaterialId, GpuMeshId, IndexRange, RenderCommand, RenderPhase,
+ };
+
+ #[test]
+ fn backend_tracks_render_request_and_presents() -> Result<(), RenderError> {
+ let mut backend = VulkanBackend::new();
+ let request = RenderRequest::conservative();
+ backend.set_render_request(request);
+ assert_eq!(backend.render_request(), request);
+ assert_eq!(backend.report().resize_rebuilds, 1);
+
+ let commands = fparkan_render::RenderCommandList {
+ commands: vec![
+ RenderCommand::BeginFrame,
+ RenderCommand::Draw(DrawCommand {
+ id: DrawId(11),
+ phase: RenderPhase::Opaque,
+ object_id: None,
+ mesh: GpuMeshId(1),
+ material: GpuMaterialId(2),
+ transform: [1.0; 16],
+ range: IndexRange { start: 0, count: 3 },
+ stable_order: 7,
+ }),
+ RenderCommand::EndFrame,
+ ],
+ };
+
+ backend.execute(&commands)?;
+ assert_eq!(backend.state(), VulkanBackendState::Ready);
+ assert_eq!(backend.report().frames_executed, 1);
+ assert_eq!(backend.report().submissions, 1);
+ assert_eq!(backend.report().presents, 1);
+ assert!(backend.report().last_capture_size > 0);
+ Ok(())
+ }
+}