Skip to main content

cvkg_render_gpu/types/
thermal.rs

1/// Device thermal state for quality scaling.
2#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
3pub enum ThermalState {
4    /// Normal operation, no thermal pressure.
5    #[default]
6    Nominal,
7    /// Slight thermal pressure, reduce non-essential effects.
8    Fair,
9    /// Significant thermal pressure, reduce quality.
10    Serious,
11    /// Critical thermal pressure, minimal rendering.
12    Critical,
13}
14
15impl ThermalState {
16    /// Determine thermal state from a normalized temperature reading (0.0-1.0).
17    pub fn from_temperature(temp: f32) -> Self {
18        if temp < 0.6 {
19            ThermalState::Nominal
20        } else if temp < 0.75 {
21            ThermalState::Fair
22        } else if temp < 0.9 {
23            ThermalState::Serious
24        } else {
25            ThermalState::Critical
26        }
27    }
28
29    /// Returns the quality scale factor for this thermal state.
30    pub fn quality_scale(&self) -> f32 {
31        match self {
32            ThermalState::Nominal => 1.0,
33            ThermalState::Fair => 0.75,
34            ThermalState::Serious => 0.5,
35            ThermalState::Critical => 0.25,
36        }
37    }
38
39    /// Whether volumetric effects should be enabled at this thermal state.
40    pub fn enable_volumetric(&self) -> bool {
41        matches!(self, ThermalState::Nominal)
42    }
43
44    /// Whether bloom should be enabled at this thermal state.
45    pub fn enable_bloom(&self) -> bool {
46        matches!(self, ThermalState::Nominal | ThermalState::Fair)
47    }
48
49    /// Returns the MSAA sample count for this thermal state.
50    pub fn msaa_sample_count(&self) -> u32 {
51        match self {
52            ThermalState::Nominal => 4,
53            ThermalState::Fair => 2,
54            ThermalState::Serious | ThermalState::Critical => 1,
55        }
56    }
57}
58
59/// Thermal monitoring configuration.
60#[derive(Clone, Copy, Debug)]
61pub struct ThermalConfig {
62    /// How often to check thermal state (in frames).
63    pub check_interval_frames: u32,
64    /// Hysteresis: how much the temperature must drop before improving quality.
65    pub hysteresis: f32,
66}
67
68impl Default for ThermalConfig {
69    fn default() -> Self {
70        Self {
71            check_interval_frames: 60, // Check once per second at 60fps
72            hysteresis: 0.05,
73        }
74    }
75}
76
77#[cfg(test)]
78mod p2_27_thermal_tests {
79    use super::*;
80
81    #[test]
82    fn thermal_state_from_temperature() {
83        assert_eq!(ThermalState::from_temperature(0.3), ThermalState::Nominal);
84        assert_eq!(ThermalState::from_temperature(0.7), ThermalState::Fair);
85        assert_eq!(ThermalState::from_temperature(0.85), ThermalState::Serious);
86        assert_eq!(ThermalState::from_temperature(0.95), ThermalState::Critical);
87    }
88
89    #[test]
90    fn thermal_quality_scale() {
91        assert_eq!(ThermalState::Nominal.quality_scale(), 1.0);
92        assert_eq!(ThermalState::Fair.quality_scale(), 0.75);
93        assert_eq!(ThermalState::Serious.quality_scale(), 0.5);
94        assert_eq!(ThermalState::Critical.quality_scale(), 0.25);
95    }
96
97    #[test]
98    fn thermal_effect_enabling() {
99        assert!(ThermalState::Nominal.enable_volumetric());
100        assert!(!ThermalState::Fair.enable_volumetric());
101        assert!(!ThermalState::Serious.enable_volumetric());
102
103        assert!(ThermalState::Nominal.enable_bloom());
104        assert!(ThermalState::Fair.enable_bloom());
105        assert!(!ThermalState::Serious.enable_bloom());
106    }
107
108    #[test]
109    fn thermal_msaa_samples() {
110        assert_eq!(ThermalState::Nominal.msaa_sample_count(), 4);
111        assert_eq!(ThermalState::Fair.msaa_sample_count(), 2);
112        assert_eq!(ThermalState::Serious.msaa_sample_count(), 1);
113        assert_eq!(ThermalState::Critical.msaa_sample_count(), 1);
114    }
115
116    #[test]
117    fn thermal_config_default() {
118        let config = ThermalConfig::default();
119        assert_eq!(config.check_interval_frames, 60);
120        assert_eq!(config.hysteresis, 0.05);
121    }
122}