Skip to main content

cvkg_render_gpu/
error.rs

1use std::fmt;
2
3#[derive(Debug)]
4pub enum RenderError {
5    DeviceLost(String),
6    Surface(String),
7    MaterialCompile { name: String, reason: String },
8    ShaderValidation(String),
9    UnsupportedFormat(wgpu::TextureFormat),
10    VertexOverflow { needed: usize, max: usize },
11    FrameAcquire(String),
12}
13
14impl fmt::Display for RenderError {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        match self {
17            RenderError::DeviceLost(msg) => {
18                write!(f, "GPU device lost: {msg}. Try recreating the renderer.")
19            }
20            RenderError::Surface(msg) => {
21                write!(
22                    f,
23                    "Surface error: {msg}. Check window state and GPU availability."
24                )
25            }
26            RenderError::MaterialCompile { name, reason } => {
27                write!(
28                    f,
29                    "Material compile failed for graph '{name}': {reason}. Validate node connections and types."
30                )
31            }
32            RenderError::ShaderValidation(msg) => {
33                write!(
34                    f,
35                    "Shader validation failed: {msg}. See inner WGSL error for line/column info."
36                )
37            }
38            RenderError::UnsupportedFormat(fmt) => {
39                write!(
40                    f,
41                    "Surface format {fmt:?} not supported by this adapter. Try a different backend."
42                )
43            }
44            RenderError::VertexOverflow { needed, max } => {
45                write!(
46                    f,
47                    "Vertex buffer overflow: needed {needed} vertices, max is {max}. Batch geometry or increase pool size."
48                )
49            }
50            RenderError::FrameAcquire(msg) => {
51                write!(f, "Failed to acquire next frame from surface: {msg}")
52            }
53        }
54    }
55}
56
57impl std::error::Error for RenderError {}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn device_lost_includes_message_and_suggestion() {
65        let err = RenderError::DeviceLost("GPU removed".into());
66        let msg = err.to_string();
67        assert!(msg.contains("GPU removed"), "should contain message");
68        assert!(msg.contains("recreating"), "should suggest recreating");
69    }
70
71    #[test]
72    fn material_compile_includes_name_and_reason() {
73        let err = RenderError::MaterialCompile {
74            name: "graph_0".into(),
75            reason: "cycle detected".into(),
76        };
77        let msg = err.to_string();
78        assert!(msg.contains("graph_0"), "should contain graph name");
79        assert!(msg.contains("cycle detected"), "should contain reason");
80        assert!(msg.contains("node connections"), "should suggest fix");
81    }
82
83    #[test]
84    fn vertex_overflow_includes_counts() {
85        let err = RenderError::VertexOverflow {
86            needed: 100000,
87            max: 65536,
88        };
89        let msg = err.to_string();
90        assert!(msg.contains("100000"), "should contain needed count");
91        assert!(msg.contains("65536"), "should contain max count");
92    }
93
94    #[test]
95    fn shader_validation_includes_detail() {
96        let err = RenderError::ShaderValidation("type mismatch at line 42".into());
97        let msg = err.to_string();
98        assert!(msg.contains("type mismatch"), "should contain detail");
99        assert!(msg.contains("WGSL"), "should mention WGSL");
100    }
101
102    #[test]
103    fn error_trait_satisfied() {
104        let _boxed: Box<dyn std::error::Error> = Box::new(RenderError::FrameAcquire("test".into()));
105    }
106}