Skip to main content

molgfx_render/
error.rs

1//! The render error type.
2
3use thiserror::Error;
4
5/// Everything that can go wrong constructing or driving the engine.
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum RenderError {
9    /// A device-level failure, carried upward with its own code.
10    #[error(transparent)]
11    Gpu(#[from] molgfx_gpu::GpuError),
12
13    /// A CPU-built hierarchy exceeded the compact GPU index layout.
14    #[error(transparent)]
15    Acceleration(#[from] molgfx_math::BvhBuildError),
16
17    /// A logical entity row cannot be encoded in a chunk-local GPU identity.
18    #[error(transparent)]
19    Entity(#[from] molgfx_core::EntityIdError),
20
21    /// A bounded global picking page transition or readback was invalid.
22    #[error(transparent)]
23    Picking(#[from] molgfx_core::PickingError),
24
25    /// A chunk span used by a resident pick page was invalid.
26    #[error(transparent)]
27    Dataset(#[from] molgfx_core::DatasetError),
28
29    /// A visible scene entity references a structure that is no longer resident.
30    #[error("picking entity owner is not resident")]
31    PickingOwnerMissing,
32
33    /// A GPU record requested a namespace absent from the bounded page table.
34    #[error("dataset {dataset} has no resident {kind:?} picking page")]
35    PickingPageMissing {
36        /// Dataset whose page was required.
37        dataset: molgfx_core::DatasetId,
38        /// Entity namespace whose page was required.
39        kind: molgfx_core::EntityKind,
40    },
41
42    /// A validated dynamic relation source is not resident in the GPU scene.
43    #[error("dynamic relation source {domain:?} is not resident")]
44    RelationSourceMissing {
45        /// Spatial table required by the relation stream.
46        domain: molgfx_core::RowDomain,
47    },
48
49    /// CPU lowering exceeded a compact GPU record field.
50    #[error(transparent)]
51    Packing(#[from] molgfx_geometry::PackingError),
52
53    /// The render graph contains a dependency cycle.
54    #[error("render graph cycle involving pass {pass:?}")]
55    GraphCycle {
56        /// A pass on the cycle.
57        pass: &'static str,
58    },
59
60    /// A pass referenced a resource id the graph never declared.
61    #[error("pass {pass:?} references undeclared resource {resource}")]
62    UnknownResource {
63        /// The offending pass.
64        pass: &'static str,
65        /// The undeclared id.
66        resource: u32,
67    },
68
69    /// Off-screen dimensions overflowed a portable texture/readback layout.
70    #[error("invalid off-screen image dimensions")]
71    InvalidImageSize,
72
73    /// A physical representation requires source annotations not exposed by its provider.
74    #[error("molecular source does not provide {capability}")]
75    SourceCapabilityMissing {
76        /// Required provider capability.
77        capability: &'static str,
78    },
79
80    /// Sequence timestamps or buffering parameters violate the deterministic contract.
81    #[error("invalid render sequence: {reason}")]
82    InvalidSequence {
83        /// Stable caller-actionable reason.
84        reason: &'static str,
85    },
86
87    /// The caller must drain a completed sequence frame before submitting more work.
88    #[error("render sequence reached its {max_in_flight}-frame in-flight limit")]
89    SequenceBackpressure {
90        /// Configured bounded readback depth.
91        max_in_flight: u8,
92    },
93
94    /// A scene-tracked optical target is stale, empty, or behind the camera.
95    #[error("invalid optical focus target: {reason}")]
96    InvalidFocusTarget {
97        /// Stable, caller-actionable reason.
98        reason: &'static str,
99    },
100
101    /// The mapped image could not be encoded for publication.
102    #[error("image encoding failed: {summary}")]
103    ImageEncoding {
104        /// Encoder-provided diagnostic.
105        summary: String,
106    },
107
108    /// A render session could not be encoded or decoded.
109    #[error("render session encoding failed: {summary}")]
110    SessionEncoding {
111        /// Serializer-provided diagnostic.
112        summary: String,
113    },
114
115    /// Fixed residency capacity or lifecycle state rejected frame work.
116    #[error("residency operation failed: {reason}")]
117    Residency {
118        /// Stable failure category without backend-specific text allocation.
119        reason: &'static str,
120    },
121
122    /// Provider chunk residency failed with a typed lifecycle or capacity error.
123    #[error(transparent)]
124    ChunkResidency(#[from] crate::engine::ChunkResidencyError),
125
126    /// Sparse volume atlas validation, capacity or lifecycle failure.
127    #[error(transparent)]
128    BrickAtlas(#[from] crate::scene_gpu::brick_atlas::types::BrickAtlasError),
129
130    /// One caller-owned dataset id was reused for different immutable data.
131    #[error(
132        "dataset {dataset} identifies conflicting immutable assets ({resident_fingerprint:#018x} != {incoming_fingerprint:#018x})"
133    )]
134    AssetIdentityCollision {
135        /// Caller-owned dataset identity that collided.
136        dataset: molgfx_core::DatasetId,
137        /// Fingerprint already resident for the dataset.
138        resident_fingerprint: u64,
139        /// Fingerprint supplied by the incoming placement.
140        incoming_fingerprint: u64,
141    },
142
143    /// Sampled-surface component lowering exceeded its bounded working set.
144    #[error("surface component filtering failed: {reason}")]
145    SurfaceComponents {
146        /// Stable validation or capacity reason.
147        reason: &'static str,
148    },
149
150    /// Immutable GPU storage could not allocate or relocate safely.
151    #[error(transparent)]
152    AssetArena(#[from] crate::scene_gpu::AssetArenaError),
153}
154
155impl RenderError {
156    /// The stable registry code for this condition.
157    #[must_use]
158    pub fn code(&self) -> &'static str {
159        match self {
160            Self::Gpu(e) => e.code(),
161            Self::Acceleration(_) => "MOLGFX-E0077",
162            Self::Entity(_) => "MOLGFX-E0078",
163            Self::Picking(_) => "MOLGFX-E0082",
164            Self::Dataset(_) => "MOLGFX-E0083",
165            Self::PickingOwnerMissing => "MOLGFX-E0084",
166            Self::PickingPageMissing { .. } => "MOLGFX-E0085",
167            Self::RelationSourceMissing { .. } => "MOLGFX-E0091",
168            Self::Packing(_) => "MOLGFX-E0079",
169            Self::GraphCycle { .. } => "MOLGFX-E0070",
170            Self::UnknownResource { .. } => "MOLGFX-E0071",
171            Self::InvalidImageSize => "MOLGFX-E0072",
172            Self::SourceCapabilityMissing { .. } => "MOLGFX-E0092",
173            Self::InvalidSequence { .. } => "MOLGFX-E0089",
174            Self::SequenceBackpressure { .. } => "MOLGFX-E0090",
175            Self::InvalidFocusTarget { .. } => "MOLGFX-E0073",
176            Self::ImageEncoding { .. } => "MOLGFX-E0074",
177            Self::SessionEncoding { .. } => "MOLGFX-E0075",
178            Self::Residency { .. } => "MOLGFX-E0076",
179            Self::ChunkResidency(_) => "MOLGFX-E0086",
180            Self::BrickAtlas(_) => "MOLGFX-E0088",
181            Self::AssetIdentityCollision { .. } => "MOLGFX-E0080",
182            Self::SurfaceComponents { .. } => "MOLGFX-E0087",
183            Self::AssetArena(_) => "MOLGFX-E0081",
184        }
185    }
186}