Skip to main content

par_term_render/
error.rs

1//! Typed error types for par-term-render.
2//!
3//! This module provides structured error types so callers at the crate boundary
4//! can match on specific error variants instead of relying on opaque `anyhow`
5//! strings.
6//!
7//! TODO(QA-010): Other workspace crates (53 files) use bare `anyhow::Result`.
8//! Consider migrating each crate's error types to thiserror-based enums for
9//! better error handling. Priority: `par-term-mcp` (IPC protocol errors),
10//! `par-term-terminal` (PTY/terminal errors).
11
12use thiserror::Error;
13
14/// Top-level error type for the GPU rendering engine.
15///
16/// Covers the main failure categories that callers may want to distinguish:
17/// - GPU initialisation (adapter, device, surface)
18/// - Shader compilation and reload
19/// - Image / texture loading
20/// - GPU surface / presentation
21/// - Screenshot capture
22#[derive(Debug, Error)]
23pub enum RenderError {
24    // -----------------------------------------------------------------------
25    // GPU initialisation
26    // -----------------------------------------------------------------------
27    /// A suitable wgpu GPU adapter could not be found for the given surface.
28    #[error("GPU adapter not found: no compatible GPU adapter available for this surface")]
29    AdapterNotFound,
30
31    /// The wgpu device could not be created or the device was lost.
32    #[error("GPU device error: {0}")]
33    DeviceError(String),
34
35    /// The wgpu surface could not be created for the window.
36    #[error("GPU surface creation failed: {0}")]
37    SurfaceCreation(String),
38
39    // -----------------------------------------------------------------------
40    // Shader errors
41    // -----------------------------------------------------------------------
42    /// The shader source file could not be read from disk.
43    #[error("Shader file read failed for '{path}': {source}")]
44    ShaderFileRead {
45        /// Path to the shader file that could not be read.
46        path: String,
47        /// Underlying I/O error.
48        #[source]
49        source: std::io::Error,
50    },
51
52    /// The GLSL source could not be parsed (transpilation step 1).
53    #[error("GLSL parse error in '{name}':\n{details}")]
54    GlslParse {
55        /// Shader name or path.
56        name: String,
57        /// Human-readable parse error messages.
58        details: String,
59    },
60
61    /// The intermediate WGSL source could not be parsed.
62    #[error("WGSL parse error for '{name}': {details}")]
63    WgslParse {
64        /// Shader name or path.
65        name: String,
66        /// Human-readable parse error details.
67        details: String,
68    },
69
70    /// The shader module failed naga validation.
71    #[error("Shader validation failed for '{name}': {details}")]
72    ShaderValidation {
73        /// Shader name or path.
74        name: String,
75        /// Human-readable validation error details.
76        details: String,
77    },
78
79    /// WGSL generation (from the naga IR) failed.
80    #[error("WGSL code generation failed for '{name}': {details}")]
81    WgslGeneration {
82        /// Shader name or path.
83        name: String,
84        /// Human-readable generation error details.
85        details: String,
86    },
87
88    /// A shader reload was requested but no shader is currently active,
89    /// or a shader compilation error occurred during reload.
90    #[error("Shader error: {0}")]
91    NoActiveShader(String),
92
93    // -----------------------------------------------------------------------
94    // Image / texture loading
95    // -----------------------------------------------------------------------
96    /// An image file could not be opened or decoded.
97    #[error("Image load failed for '{path}': {source}")]
98    ImageLoad {
99        /// Path to the image that failed to load.
100        path: String,
101        /// Underlying image error.
102        #[source]
103        source: image::ImageError,
104    },
105
106    /// The supplied raw RGBA byte slice has an unexpected length.
107    #[error("Invalid RGBA data size: expected {expected} bytes, got {actual} bytes")]
108    InvalidTextureData {
109        /// Expected byte count (`width * height * 4`).
110        expected: usize,
111        /// Actual byte count received.
112        actual: usize,
113    },
114
115    /// A cubemap face image is not square or all faces are not the same size.
116    #[error("Cubemap geometry error: {0}")]
117    CubemapGeometry(String),
118
119    /// A required cubemap face file could not be found on disk.
120    #[error("Cubemap face file not found: {0}")]
121    CubemapFaceNotFound(String),
122
123    // -----------------------------------------------------------------------
124    // Shader / renderer state
125    // -----------------------------------------------------------------------
126    /// A shader renderer that was previously active is no longer available,
127    /// typically due to GPU device loss. The frame should be skipped and
128    /// reinitialization attempted on the next frame.
129    #[error("Shader renderer unavailable (possible GPU device loss): {0}")]
130    ShaderUnavailable(String),
131
132    // -----------------------------------------------------------------------
133    // Surface / presentation
134    // -----------------------------------------------------------------------
135    /// `Surface::get_current_texture()` returned a non-recoverable state
136    /// (outdated, lost, timeout, occluded, validation).
137    #[error("GPU surface error: {0}")]
138    Surface(String),
139
140    // -----------------------------------------------------------------------
141    // Screenshot
142    // -----------------------------------------------------------------------
143    /// The GPU buffer could not be mapped back to CPU memory, or a render
144    /// step during screenshot capture failed.
145    #[error("Screenshot capture failed: {0}")]
146    ScreenshotMap(String),
147
148    /// The pixel data could not be assembled into a final `RgbaImage`.
149    #[error("Screenshot image assembly failed")]
150    ScreenshotImageAssembly,
151}
152
153// ---------------------------------------------------------------------------
154// Convenience conversions from common upstream error types
155// ---------------------------------------------------------------------------
156
157impl From<wgpu::CreateSurfaceError> for RenderError {
158    fn from(e: wgpu::CreateSurfaceError) -> Self {
159        RenderError::SurfaceCreation(e.to_string())
160    }
161}
162
163impl From<wgpu::RequestDeviceError> for RenderError {
164    fn from(e: wgpu::RequestDeviceError) -> Self {
165        RenderError::DeviceError(e.to_string())
166    }
167}