// ───────────────────────────────────────────────────────────────────────────── // state.rs — global state shared across all hooks // ───────────────────────────────────────────────────────────────────────────── use crate::config::ShaderHashSet; use crate::dispatch::NextDeviceFn; use crate::encode::PipelineHandle; use ash::vk; use dashmap::DashMap; use once_cell::sync::Lazy; use std::sync::Arc; // Holds capture-specific resources instead of re-creating them *each frame* pub struct CaptureResources { pub command_pool: vk::CommandPool, pub command_buffers: [vk::CommandBuffer; 4], pub fences: [vk::Fence; 4], pub current: usize, } // ── Per-pipeline records ────────────────────────────────────────────────────── #[derive(Clone, Debug, Default)] pub struct PipelineHashes { pub vert_hash: Option, pub frag_hash: Option, } #[derive(Clone, Debug, Default)] pub struct PipelineState { pub blend_enabled: bool, pub depth_test_enabled: bool, pub depth_write_enabled: bool, } // ── Per-device state ────────────────────────────────────────────────────────── pub struct DeviceState { pub raw: vk::Device, pub physical_device: vk::PhysicalDevice, pub fp: NextDeviceFn, // Phase 1: shader / pipeline pub shader_registry: DashMap, pub pipeline_registry: DashMap, pub pipeline_state: DashMap, // Phase 2: view / framebuffer tracking pub view_to_image: DashMap, pub view_format: DashMap, pub framebuffer_to_views: DashMap>, pub framebuffer_extent: DashMap, // Phase 3: shader hash config pub shader_hashes: Option, // Phase 4: HUDless capture (optional — HUDLESS_CAPTURE_HUDLESS=1) pub hudless_image: std::sync::Mutex>, pub hudless_memory: std::sync::Mutex>, pub hudless_size: std::sync::Mutex<(u32, u32, vk::Format)>, // Phase 4: final-frame capture (DMA-BUF exportable) pub final_image: std::sync::Mutex>, pub final_memory: std::sync::Mutex>, pub final_size: std::sync::Mutex<(u32, u32, vk::Format)>, /// Row stride in bytes of `final_image`, queried once after allocation. /// Zero until the first frame is captured. pub final_stride: std::sync::atomic::AtomicU32, // Phase 4: swapchain tracking pub swapchain: std::sync::Mutex>, pub swapchain_images: std::sync::Mutex>, pub swapchain_format: std::sync::Mutex, /// Raw `VkColorSpaceKHR` value, captured from vkCreateSwapchainKHR. /// Used to derive color space for the encoder (SDR vs HDR10 etc.). pub swapchain_colorspace: std::sync::atomic::AtomicU32, pub swapchain_extent: std::sync::Mutex, pub frame_counter: std::sync::atomic::AtomicU64, pub largest_extent: std::sync::Mutex, // Phase 3/4: per-frame HUD detection flags pub hud_detected_frame: std::sync::atomic::AtomicBool, pub pending_capture_frame: std::sync::atomic::AtomicBool, pub capture_injected_frame: std::sync::atomic::AtomicBool, pub skipped_draws_frame: std::sync::atomic::AtomicU32, // Phase 7: encode + IPC pipeline (lazy-init on first frame) pub encoder: std::sync::Mutex>, // Re-usable capture resources (double-buffered) pub capture_resources: std::sync::Mutex>, /// Dedicated queue for capture submissions (separate from game rendering). pub capture_queue: std::sync::Mutex, // Fake swapchain pool (headless — no real present) pub fake_images: std::sync::Mutex>, pub fake_memories: std::sync::Mutex>, pub fake_fds: std::sync::Mutex>, pub fake_strides: std::sync::Mutex>, pub fake_available: std::sync::Mutex>, pub fake_image_count: std::sync::atomic::AtomicU32, pub fake_swapchain: std::sync::Mutex>, pub signal_queue: std::sync::Mutex, pub next_acquire: std::sync::atomic::AtomicU32, pub memory_properties: std::sync::Mutex, pub acquire_dummy_pool: std::sync::Mutex, pub acquire_dummy_cb: std::sync::Mutex, /// Cached DMA-BUF fd for final_memory (-1 = not cached). /// Avoids a kernel ioctl per frame. pub cached_dmabuf_fd: std::sync::atomic::AtomicI32, // ── Frame-rate throttle ─────────────────────────────────────────── /// Target FPS for capture throttling (set from HUDLESS_FPS on pipeline init). pub target_fps: std::sync::atomic::AtomicU32, /// Timestamp of last captured frame (for rate limiting). pub last_capture_time: std::sync::Mutex>, /// Channel for threaded capture worker (present → worker). pub capture_tx: std::sync::Mutex>>, } // ── Per-command-buffer state ────────────────────────────────────────────────── #[derive(Default, Clone)] pub struct CbState { pub device_key: usize, pub current_color_image: Option, pub current_image_format: Option, pub current_image_extent: Option, pub active_vert_hash: Option, pub active_frag_hash: Option, pub hud_captured: bool, pub pending_capture: bool, pub capture_injected: bool, pub hud_detected: bool, pub draw_counter: u32, } // ── Global state ────────────────────────────────────────────────────────────── pub static INSTANCE_STATE: Lazy>> = Lazy::new(DashMap::new); pub static DEVICE_STATE: Lazy>> = Lazy::new(DashMap::new); pub static CB_STATE: Lazy> = Lazy::new(DashMap::new); /// VkQueue → device dispatch key pub static QUEUE_TO_DEVICE_KEY: Lazy> = Lazy::new(DashMap::new); /// VkCommandBuffer → device dispatch key pub static CMD_BUF_TO_DEVICE_KEY: Lazy> = Lazy::new(DashMap::new);