use super::CellRenderer;
use crate::wgpu_conversions::VsyncModeWgpu;
use std::sync::atomic::{AtomicU64, Ordering};
pub fn clamp_surface_extent(width: u32, height: u32, max_dimension: u32) -> (u32, u32) {
(
width.min(max_dimension).max(1),
height.min(max_dimension).max(1),
)
}
pub fn texture_limits(max_texture_dimension_2d: u32) -> wgpu::Limits {
wgpu::Limits {
max_texture_dimension_2d,
..wgpu::Limits::default()
}
}
pub fn install_nonfatal_error_handler(device: &wgpu::Device) {
let seen = AtomicU64::new(0);
device.on_uncaptured_error(std::sync::Arc::new(move |err: wgpu::Error| {
let count = seen.fetch_add(1, Ordering::Relaxed) + 1;
if should_log_uncaptured_error(count) {
log::error!("wgpu uncaptured error #{count}: {err}");
}
}));
}
fn should_log_uncaptured_error(count: u64) -> bool {
count == 1 || count.is_multiple_of(1_000)
}
impl CellRenderer {
pub fn reconfigure_surface(&mut self) {
self.surface.configure(&self.device, &self.config);
}
pub fn supported_present_modes(&self) -> &[wgpu::PresentMode] {
&self.supported_present_modes
}
pub fn is_vsync_mode_supported(&self, mode: par_term_config::VsyncMode) -> bool {
self.supported_present_modes
.contains(&mode.to_present_mode())
}
pub fn update_vsync_mode(
&mut self,
mode: par_term_config::VsyncMode,
) -> (par_term_config::VsyncMode, bool) {
let requested = mode.to_present_mode();
let current = self.config.present_mode;
let actual = if self.supported_present_modes.contains(&requested) {
requested
} else {
log::warn!(
"Requested present mode {:?} not supported, falling back to Fifo",
requested
);
wgpu::PresentMode::Fifo
};
if actual != current {
self.config.present_mode = actual;
self.surface.configure(&self.device, &self.config);
log::info!("VSync mode changed to {:?}", actual);
}
let actual_vsync = match actual {
wgpu::PresentMode::Immediate => par_term_config::VsyncMode::Immediate,
wgpu::PresentMode::Mailbox => par_term_config::VsyncMode::Mailbox,
wgpu::PresentMode::Fifo | wgpu::PresentMode::FifoRelaxed => {
par_term_config::VsyncMode::Fifo
}
_ => par_term_config::VsyncMode::Fifo,
};
(actual_vsync, actual != current)
}
pub fn current_vsync_mode(&self) -> par_term_config::VsyncMode {
match self.config.present_mode {
wgpu::PresentMode::Immediate => par_term_config::VsyncMode::Immediate,
wgpu::PresentMode::Mailbox => par_term_config::VsyncMode::Mailbox,
wgpu::PresentMode::Fifo | wgpu::PresentMode::FifoRelaxed => {
par_term_config::VsyncMode::Fifo
}
_ => par_term_config::VsyncMode::Fifo,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn oversize_extent_is_clamped_to_the_device_limit() {
assert_eq!(clamp_surface_extent(10240, 2822, 8192), (8192, 2822));
}
#[test]
fn extent_within_the_limit_is_unchanged() {
assert_eq!(clamp_surface_extent(3840, 2160, 8192), (3840, 2160));
}
#[test]
fn extent_at_the_limit_is_unchanged() {
assert_eq!(clamp_surface_extent(8192, 8192, 8192), (8192, 8192));
}
#[test]
fn zero_extent_floors_to_one() {
assert_eq!(clamp_surface_extent(0, 0, 8192), (1, 1));
}
#[test]
fn texture_limits_raises_only_the_2d_dimension() {
assert_eq!(
texture_limits(16384),
wgpu::Limits {
max_texture_dimension_2d: 16384,
..wgpu::Limits::default()
}
);
}
#[test]
fn uncaptured_errors_log_the_first_then_every_1000th() {
assert!(should_log_uncaptured_error(1));
assert!(!should_log_uncaptured_error(2));
assert!(!should_log_uncaptured_error(999));
assert!(should_log_uncaptured_error(1000));
assert!(!should_log_uncaptured_error(1001));
}
}