Skip to main content

cvkg_render_gpu/types/
thermal.rs

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