Skip to main content

goud_engine/core/providers/impls/
null_render.rs

1//! Null render provider -- silent no-op for headless testing.
2
3use crate::core::error::GoudResult;
4use crate::core::providers::render::RenderProvider;
5use crate::core::providers::types::{
6    BufferDesc, BufferHandle, CameraData, DrawCommand, FrameContext, MeshDrawCommand,
7    ParticleDrawCommand, PipelineDesc, PipelineHandle, RenderCapabilities, RenderTargetDesc,
8    RenderTargetHandle, ShaderDesc, ShaderHandle, TextDrawCommand, TextureDesc, TextureHandle,
9};
10use crate::core::providers::{Provider, ProviderLifecycle};
11
12/// A render provider that does nothing. Used for headless testing and as
13/// a default before a real renderer is configured.
14pub struct NullRenderProvider {
15    capabilities: RenderCapabilities,
16}
17
18impl NullRenderProvider {
19    /// Create a new null render provider.
20    pub fn new() -> Self {
21        Self {
22            capabilities: RenderCapabilities {
23                max_texture_units: 0,
24                max_texture_size: 0,
25                supports_instancing: false,
26                supports_compute: false,
27                supports_msaa: false,
28            },
29        }
30    }
31}
32
33impl Default for NullRenderProvider {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl Provider for NullRenderProvider {
40    fn name(&self) -> &str {
41        "null"
42    }
43
44    fn version(&self) -> &str {
45        "0.0.0"
46    }
47
48    fn capabilities(&self) -> Box<dyn std::any::Any> {
49        Box::new(self.capabilities.clone())
50    }
51}
52
53impl ProviderLifecycle for NullRenderProvider {
54    fn init(&mut self) -> GoudResult<()> {
55        Ok(())
56    }
57
58    fn update(&mut self, _delta: f32) -> GoudResult<()> {
59        Ok(())
60    }
61
62    fn shutdown(&mut self) {}
63}
64
65impl RenderProvider for NullRenderProvider {
66    fn render_capabilities(&self) -> &RenderCapabilities {
67        &self.capabilities
68    }
69
70    fn begin_frame(&mut self) -> GoudResult<FrameContext> {
71        Ok(FrameContext { _id: 0 })
72    }
73
74    fn end_frame(&mut self, _frame: FrameContext) -> GoudResult<()> {
75        Ok(())
76    }
77
78    fn resize(&mut self, _width: u32, _height: u32) -> GoudResult<()> {
79        Ok(())
80    }
81
82    fn create_texture(&mut self, _desc: &TextureDesc) -> GoudResult<TextureHandle> {
83        Ok(TextureHandle(0))
84    }
85
86    fn destroy_texture(&mut self, _handle: TextureHandle) {}
87
88    fn create_buffer(&mut self, _desc: &BufferDesc) -> GoudResult<BufferHandle> {
89        Ok(BufferHandle(0))
90    }
91
92    fn destroy_buffer(&mut self, _handle: BufferHandle) {}
93
94    fn create_shader(&mut self, _desc: &ShaderDesc) -> GoudResult<ShaderHandle> {
95        Ok(ShaderHandle(0))
96    }
97
98    fn destroy_shader(&mut self, _handle: ShaderHandle) {}
99
100    fn create_pipeline(&mut self, _desc: &PipelineDesc) -> GoudResult<PipelineHandle> {
101        Ok(PipelineHandle(0))
102    }
103
104    fn destroy_pipeline(&mut self, _handle: PipelineHandle) {}
105
106    fn create_render_target(&mut self, _desc: &RenderTargetDesc) -> GoudResult<RenderTargetHandle> {
107        Ok(RenderTargetHandle(0))
108    }
109
110    fn destroy_render_target(&mut self, _handle: RenderTargetHandle) {}
111
112    fn draw(&mut self, _cmd: &DrawCommand) -> GoudResult<()> {
113        Ok(())
114    }
115
116    fn draw_batch(&mut self, _cmds: &[DrawCommand]) -> GoudResult<()> {
117        Ok(())
118    }
119
120    fn draw_mesh(&mut self, _cmd: &MeshDrawCommand) -> GoudResult<()> {
121        Ok(())
122    }
123
124    fn draw_text(&mut self, _cmd: &TextDrawCommand) -> GoudResult<()> {
125        Ok(())
126    }
127
128    fn draw_particles(&mut self, _cmd: &ParticleDrawCommand) -> GoudResult<()> {
129        Ok(())
130    }
131
132    fn set_viewport(&mut self, _x: i32, _y: i32, _width: u32, _height: u32) {}
133
134    fn set_camera(&mut self, _camera: &CameraData) {}
135
136    fn set_render_target(&mut self, _handle: Option<RenderTargetHandle>) {}
137
138    fn clear(&mut self, _color: [f32; 4]) {}
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_null_render_construction() {
147        let provider = NullRenderProvider::new();
148        assert_eq!(provider.name(), "null");
149        assert_eq!(provider.version(), "0.0.0");
150    }
151
152    #[test]
153    fn test_null_render_default() {
154        let provider = NullRenderProvider::default();
155        assert_eq!(provider.name(), "null");
156    }
157
158    #[test]
159    fn test_null_render_init_shutdown() {
160        let mut provider = NullRenderProvider::new();
161        assert!(provider.init().is_ok());
162        assert!(provider.update(0.016).is_ok());
163        provider.shutdown();
164    }
165
166    #[test]
167    fn test_null_render_capabilities() {
168        let provider = NullRenderProvider::new();
169        let caps = provider.render_capabilities();
170        assert_eq!(caps.max_texture_size, 0);
171        assert_eq!(caps.max_texture_units, 0);
172        assert!(!caps.supports_instancing);
173        assert!(!caps.supports_compute);
174        assert!(!caps.supports_msaa);
175    }
176
177    #[test]
178    fn test_null_render_generic_capabilities() {
179        let provider = NullRenderProvider::new();
180        let caps = provider.capabilities();
181        let render_caps = caps.downcast_ref::<RenderCapabilities>().unwrap();
182        assert_eq!(render_caps.max_texture_size, 0);
183    }
184
185    #[test]
186    fn test_null_render_frame_lifecycle() {
187        let mut provider = NullRenderProvider::new();
188        let frame = provider.begin_frame().unwrap();
189        assert!(provider.end_frame(frame).is_ok());
190    }
191
192    #[test]
193    fn test_null_render_resource_creation() {
194        let mut provider = NullRenderProvider::new();
195        let tex = provider.create_texture(&TextureDesc::default()).unwrap();
196        assert_eq!(tex, TextureHandle(0));
197        provider.destroy_texture(tex);
198
199        let buf = provider.create_buffer(&BufferDesc::default()).unwrap();
200        assert_eq!(buf, BufferHandle(0));
201        provider.destroy_buffer(buf);
202
203        let shader = provider.create_shader(&ShaderDesc::default()).unwrap();
204        assert_eq!(shader, ShaderHandle(0));
205        provider.destroy_shader(shader);
206
207        let pipeline = provider.create_pipeline(&PipelineDesc::default()).unwrap();
208        assert_eq!(pipeline, PipelineHandle(0));
209        provider.destroy_pipeline(pipeline);
210
211        let rt = provider
212            .create_render_target(&RenderTargetDesc::default())
213            .unwrap();
214        assert_eq!(rt, RenderTargetHandle(0));
215        provider.destroy_render_target(rt);
216    }
217
218    #[test]
219    fn test_null_render_resize() {
220        let mut provider = NullRenderProvider::new();
221        assert!(provider.resize(1920, 1080).is_ok());
222    }
223
224    #[test]
225    fn test_null_render_state_operations() {
226        let mut provider = NullRenderProvider::new();
227        provider.set_viewport(0, 0, 800, 600);
228        provider.set_camera(&CameraData::default());
229        provider.set_render_target(None);
230        provider.clear([0.0, 0.0, 0.0, 1.0]);
231    }
232}