Skip to main content

goud_engine/libs/graphics/backend/null/
backend.rs

1//! NullBackend struct and constructor.
2
3use std::collections::HashMap;
4
5use crate::core::handle::HandleAllocator;
6use crate::libs::graphics::backend::capabilities::{BackendCapabilities, BackendInfo};
7use crate::libs::graphics::backend::types::{
8    BufferHandle, BufferMarker, BufferType, ShaderMarker, TextureHandle, TextureMarker,
9};
10
11/// Metadata stored for each null buffer.
12#[derive(Debug, Clone)]
13pub(super) struct NullBufferMeta {
14    pub size: usize,
15    pub _buffer_type: BufferType,
16}
17
18/// Metadata stored for each null texture.
19#[derive(Debug, Clone)]
20pub(super) struct NullTextureMeta {
21    pub width: u32,
22    pub height: u32,
23}
24
25/// A no-op render backend that tracks resource state without GPU access.
26///
27/// This backend is designed for headless testing in CI environments where no
28/// GPU or display server is available. All operations succeed immediately,
29/// and resource handles are tracked via generational allocators so that
30/// lifecycle tests (create/destroy/use-after-free) work correctly.
31pub struct NullBackend {
32    pub(super) info: BackendInfo,
33    pub(super) clear_color: [f32; 4],
34
35    // State tracking
36    pub(super) depth_test_enabled: bool,
37    pub(super) blending_enabled: bool,
38    pub(super) culling_enabled: bool,
39    pub(super) depth_mask_enabled: bool,
40    pub(super) viewport: (i32, i32, u32, u32),
41    pub(super) line_width: f32,
42
43    // Buffer management
44    pub(super) buffer_allocator: HandleAllocator<BufferMarker>,
45    pub(super) buffers: HashMap<BufferHandle, NullBufferMeta>,
46
47    // Texture management
48    pub(super) texture_allocator: HandleAllocator<TextureMarker>,
49    pub(super) textures: HashMap<TextureHandle, NullTextureMeta>,
50
51    // Shader management
52    pub(super) shader_allocator: HandleAllocator<ShaderMarker>,
53}
54
55// SAFETY: NullBackend contains only pure Rust data (no raw pointers,
56// no thread-local state). Send + Sync is safe.
57unsafe impl Send for NullBackend {}
58unsafe impl Sync for NullBackend {}
59
60impl NullBackend {
61    /// Creates a new headless null backend.
62    pub fn new() -> Self {
63        let capabilities = BackendCapabilities {
64            max_texture_units: 8,
65            max_texture_size: 4096,
66            max_vertex_attributes: 16,
67            max_uniform_buffer_size: 16384,
68            supports_instancing: true,
69            supports_compute_shaders: false,
70            supports_geometry_shaders: false,
71            supports_tessellation: false,
72            supports_multisampling: false,
73            supports_anisotropic_filtering: false,
74        };
75
76        let info = BackendInfo {
77            name: "Null",
78            version: "1.0".to_string(),
79            vendor: "Software".to_string(),
80            renderer: "NullBackend".to_string(),
81            capabilities,
82        };
83
84        Self {
85            info,
86            clear_color: [0.0, 0.0, 0.0, 1.0],
87            depth_test_enabled: false,
88            blending_enabled: false,
89            culling_enabled: false,
90            depth_mask_enabled: true,
91            viewport: (0, 0, 800, 600),
92            line_width: 1.0,
93            buffer_allocator: HandleAllocator::new(),
94            buffers: HashMap::new(),
95            texture_allocator: HandleAllocator::new(),
96            textures: HashMap::new(),
97            shader_allocator: HandleAllocator::new(),
98        }
99    }
100}
101
102impl Default for NullBackend {
103    fn default() -> Self {
104        Self::new()
105    }
106}