use super::config::QualityConfig;
use super::level::QualityLevel;
use super::monitor::FrameTimeMonitor;
use std::time::Duration;
#[derive(Debug, Clone, Copy)]
pub struct GpuCapability {
pub supports_high_quality: bool,
pub is_integrated: bool,
pub performance_tier: u8,
}
impl Default for GpuCapability {
fn default() -> Self {
Self { supports_high_quality: true, is_integrated: false, performance_tier: 3 }
}
}
impl GpuCapability {
#[cfg(feature = "gpu-wgpu")]
pub fn from_adapter_info(adapter_info: &wgpu::AdapterInfo) -> Self {
let supports_high_quality = matches!(
adapter_info.device_type,
wgpu::DeviceType::DiscreteGpu | wgpu::DeviceType::IntegratedGpu
);
let is_integrated = matches!(adapter_info.device_type, wgpu::DeviceType::IntegratedGpu);
let performance_tier = match adapter_info.device_type {
wgpu::DeviceType::DiscreteGpu => 5,
wgpu::DeviceType::IntegratedGpu => 3,
wgpu::DeviceType::Other => 2,
wgpu::DeviceType::VirtualGpu => 2,
wgpu::DeviceType::Cpu => 1,
};
Self { supports_high_quality, is_integrated, performance_tier }
}
pub fn default_capability() -> Self {
Self::default()
}
pub fn recommended_initial_quality(&self) -> QualityLevel {
if self.supports_high_quality && self.performance_tier >= 4 {
QualityLevel::High
} else if self.supports_high_quality && self.performance_tier >= 2 {
QualityLevel::Medium
} else {
QualityLevel::Low
}
}
}
#[derive(Debug, Clone)]
pub struct QualityManager {
current_level: QualityLevel,
config: QualityConfig,
frame_monitor: FrameTimeMonitor,
gpu_capability: GpuCapability,
}
impl QualityManager {
pub fn new() -> Self {
Self::with_config_and_capability(QualityConfig::default(), GpuCapability::default())
}
pub fn with_config(config: QualityConfig) -> Self {
Self::with_config_and_capability(config, GpuCapability::default())
}
pub fn with_config_and_capability(
config: QualityConfig,
gpu_capability: GpuCapability,
) -> Self {
let config = config.normalized();
let initial_quality = gpu_capability
.recommended_initial_quality()
.clamp(config.min_quality, config.max_quality);
let frame_monitor = FrameTimeMonitor::new(config.target_frame_rate);
Self { current_level: initial_quality, config, frame_monitor, gpu_capability }
}
pub fn finish_frame(&mut self, frame_duration: Duration) {
let frame_duration_secs = frame_duration.as_secs_f32();
self.finish_frame_secs(frame_duration_secs);
}
pub fn finish_frame_secs(&mut self, frame_duration: f32) {
self.frame_monitor.record_frame(frame_duration);
self.update_quality_level();
}
fn update_quality_level(&mut self) {
match self.current_level {
QualityLevel::High => {
if self.frame_monitor.should_degrade(
self.config.degrade_frame_duration(),
self.config.degrade_frame_count,
) {
if let Some(lower) = self.current_level.lower() {
if lower >= self.config.min_quality {
self.current_level = lower;
}
}
}
}
QualityLevel::Medium => {
if self.frame_monitor.should_degrade(
self.config.degrade_frame_duration(),
self.config.degrade_frame_count,
) {
if let Some(lower) = self.current_level.lower() {
if lower >= self.config.min_quality {
self.current_level = lower;
}
}
} else if self.frame_monitor.should_upgrade(
self.config.upgrade_frame_duration(),
self.config.upgrade_frame_count,
) {
if let Some(higher) = self.current_level.higher() {
if higher <= self.config.max_quality {
self.current_level = higher;
}
}
}
}
QualityLevel::Low => {
if self.frame_monitor.should_upgrade(
self.config.upgrade_frame_duration(),
self.config.upgrade_frame_count,
) {
if let Some(higher) = self.current_level.higher() {
if higher <= self.config.max_quality {
self.current_level = higher;
}
}
}
}
}
}
pub fn quality_level(&self) -> QualityLevel {
self.current_level
}
pub fn set_quality_level(&mut self, level: QualityLevel) {
self.current_level = level.clamp(self.config.min_quality, self.config.max_quality);
}
pub fn config(&self) -> &QualityConfig {
&self.config
}
pub fn set_config(&mut self, config: QualityConfig) {
self.config = config.normalized();
self.frame_monitor.set_target_frame_rate(self.config.target_frame_rate);
}
pub fn gpu_capability(&self) -> &GpuCapability {
&self.gpu_capability
}
pub fn frame_monitor(&self) -> &FrameTimeMonitor {
&self.frame_monitor
}
pub fn current_fps(&self) -> f32 {
self.frame_monitor.current_fps()
}
pub fn average_frame_time(&self) -> f32 {
self.frame_monitor.average_frame_time()
}
pub fn reset(&mut self) {
self.frame_monitor.reset();
self.current_level = self
.gpu_capability
.recommended_initial_quality()
.clamp(self.config.min_quality, self.config.max_quality);
}
}
impl Default for QualityManager {
fn default() -> Self {
Self::new()
}
}