molgfx_render/engine/config.rs
1//! Engine configuration and frame outcomes.
2
3use super::{AdaptiveQualityConfig, DerivedCacheBudget, QualityTier, RenderProfile};
4use crate::ResidencyConfig;
5use molgfx_core::ResidencyBudget;
6use molgfx_gpu::PowerPreference;
7
8/// Presentation result independent of streaming completeness.
9#[derive(Clone, Copy, PartialEq, Eq, Debug)]
10pub enum FrameStatus {
11 /// The frame reached the presentation surface.
12 Presented,
13 /// The frame was skipped (surface lost or outdated); the surface was
14 /// reconfigured and the next call recovers.
15 Skipped,
16}
17
18/// Whether every requested resource contributed at full fidelity.
19#[derive(Clone, Copy, PartialEq, Eq, Debug)]
20pub enum FrameCompleteness {
21 /// No provider or upload work remains pending.
22 Complete,
23 /// The frame is valid but more resident detail is still arriving.
24 Progressive {
25 /// Bounded uploads awaiting fence completion.
26 pending_chunks: u64,
27 },
28}
29
30/// Allocation-free bitset describing explicit realtime degradation.
31#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)]
32pub struct FrameDegradation(u8);
33
34impl FrameDegradation {
35 /// Non-resident detail is represented by the paged/proxy path.
36 pub const STREAMING_PROXY: Self = Self(1);
37
38 /// True when every bit in `feature` is active.
39 #[must_use]
40 pub const fn contains(self, feature: Self) -> bool {
41 self.0 & feature.0 == feature.0
42 }
43
44 pub(super) const fn streaming_proxy(enabled: bool) -> Self {
45 if enabled {
46 Self::STREAMING_PROXY
47 } else {
48 Self(0)
49 }
50 }
51}
52
53/// Stable, allocation-free counters captured with a frame report.
54#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)]
55pub struct FrameMetrics {
56 /// Provider chunks tracked by the GPU residency layer.
57 pub tracked_chunks: usize,
58 /// Upload bytes still protected by GPU fences.
59 pub upload_in_flight_bytes: u64,
60 /// Presentation submissions not yet reported complete by the GPU.
61 pub pending_frame_submissions: u32,
62 /// Monotonic identifier for the most recently submitted frame.
63 pub last_submission_id: u64,
64 /// Submission timestamp in the engine monotonic clock, in nanoseconds:
65 /// host time when the frame's encoder reached the queue. CPU cost of the
66 /// frame is separately observable as the duration of the native `render`
67 /// call; this is not device execution time.
68 pub submission_timestamp_ns: u64,
69 /// Host timestamp when the last submission's fence was observed complete,
70 /// in the same monotonic clock. `None` while the frame is pending, and
71 /// `None` on native backends because the engine only observes the fence on
72 /// the browser path; even when set, this is host-observation latency, not
73 /// exact device completion or GPU execution time. GPU execution time
74 /// requires timestamp queries via the profiling path.
75 pub completion_timestamp_ns: Option<u64>,
76 /// Retained recomputable device bytes.
77 pub derived_cache_gpu_bytes: u64,
78 /// Peak recomputable device bytes since engine construction.
79 pub derived_cache_peak_gpu_bytes: u64,
80 /// Live physical GPU buffer bytes owned through the device boundary.
81 pub physical_buffer_bytes: u64,
82 /// Live physical GPU texture bytes owned through the device boundary.
83 pub physical_texture_bytes: u64,
84 /// Total live physical GPU bytes owned through the device boundary.
85 pub physical_total_bytes: u64,
86 /// Peak live physical GPU bytes since device construction.
87 pub physical_peak_bytes: u64,
88}
89
90/// Explicit frame status, completeness and degradation report.
91#[derive(Clone, Copy, PartialEq, Eq, Debug)]
92pub struct FrameReport {
93 /// Presentation result.
94 pub status: FrameStatus,
95 /// Whether full requested detail was available.
96 pub completeness: FrameCompleteness,
97 /// Explicit approximations used by the selected mode.
98 pub degradation: FrameDegradation,
99 /// Residency counters captured after submission.
100 pub metrics: FrameMetrics,
101 /// True while temporal convergence, streaming, or surface recovery needs
102 /// another caller-scheduled frame.
103 pub needs_another_frame: bool,
104 /// The adaptive quality tier this frame rendered at.
105 pub quality_tier: QualityTier,
106}
107
108/// Which rendering mode the engine runs.
109#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
110pub enum RenderMode {
111 /// The interactive raster path.
112 #[default]
113 Realtime,
114 /// Progressive, deterministic high-fidelity rendering. Camera motion
115 /// resets temporal history but never changes the selected render path.
116 Cinematic,
117}
118
119/// Engine construction options.
120#[derive(Clone, Debug)]
121pub struct EngineConfig {
122 /// Adapter preference.
123 pub power: PowerPreference,
124 /// Initial frame width, pixels.
125 pub width: u32,
126 /// Initial frame height, pixels.
127 pub height: u32,
128 /// Rendering strategy. Backend selection remains capability-driven.
129 pub mode: RenderMode,
130 /// Adaptive quality policy. A configuration that disables adaptation
131 /// holds one tier, so converged output stays reproducible.
132 pub adaptive: AdaptiveQualityConfig,
133 /// Reusable presentation recipe resolved once during engine construction.
134 pub profile: RenderProfile,
135 /// Fixed page, staging, command and lifecycle capacities.
136 pub residency: ResidencyConfig,
137 /// One coordinated limit set for caller/provider-owned source data.
138 pub source_budget: ResidencyBudget,
139 /// Hard limits for recomputable data, separate from source residency.
140 pub derived_cache: DerivedCacheBudget,
141 /// Hard ceiling for live physical GPU buffers and textures.
142 pub resource_memory_limit_bytes: Option<u64>,
143 /// Maximum number of simultaneously resident dataset/namespace pick pages.
144 pub picking_page_capacity: u32,
145}
146
147impl Default for EngineConfig {
148 fn default() -> Self {
149 Self {
150 power: PowerPreference::HighPerformance,
151 width: 1280,
152 height: 800,
153 mode: RenderMode::Realtime,
154 adaptive: AdaptiveQualityConfig::default(),
155 profile: RenderProfile::inspection(),
156 residency: ResidencyConfig::default(),
157 source_budget: ResidencyBudget::default(),
158 derived_cache: DerivedCacheBudget::default(),
159 resource_memory_limit_bytes: None,
160 picking_page_capacity: 1_024,
161 }
162 }
163}
164
165#[cfg(test)]
166#[path = "config_tests.rs"]
167mod tests;