use crate::gpu::cpu::SoftbufferPresenter;
use crate::gpu::{GpuContext, Renderer};
use std::sync::Arc;
use winit::event_loop::ActiveEventLoop;
use winit::window::Window;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Preference {
Auto,
Gpu,
Cpu,
}
fn preference(value: Option<&str>) -> Preference {
match value.map(str::to_ascii_lowercase).as_deref() {
Some("cpu" | "software") => Preference::Cpu,
Some("gpu") => Preference::Gpu,
_ => Preference::Auto,
}
}
fn gpu(event_loop: &ActiveEventLoop, window: &Arc<Window>, size: (u32, u32)) -> Result<GpuContext, String> {
let descriptor = wgpu::InstanceDescriptor::new_with_display_handle(Box::new(event_loop.owned_display_handle()));
pollster::block_on(GpuContext::new(descriptor, window.clone(), size.0, size.1)).map_err(|error| error.to_string())
}
pub(crate) fn create(
event_loop: &ActiveEventLoop,
window: &Arc<Window>,
size: (u32, u32),
) -> Result<Renderer, Box<dyn std::error::Error>> {
let requested = std::env::var("AURA_RENDERER").ok();
let renderer = choose(event_loop, window, size, preference(requested.as_deref()))?;
if requested.is_some() {
crate::app::console::warn(format_args!("se dibuja con {}", renderer.description()));
}
Ok(renderer)
}
fn choose(
event_loop: &ActiveEventLoop,
window: &Arc<Window>,
size: (u32, u32),
wanted: Preference,
) -> Result<Renderer, Box<dyn std::error::Error>> {
if wanted != Preference::Cpu {
let reason = match gpu(event_loop, window, size) {
Ok(context) if !context.is_software() || wanted == Preference::Gpu => match Renderer::gpu(context) {
Ok(renderer) => return Ok(renderer),
Err(error) if wanted == Preference::Gpu => return Err(error.into()),
Err(error) => error.to_string(),
},
Ok(context) => format!("la GPU «{}» es emulada por software", context.adapter.name),
Err(error) if wanted == Preference::Gpu => return Err(error.into()),
Err(error) => error,
};
crate::app::console::warn(format_args!("sin GPU utilizable ({reason}); se dibuja con la CPU"));
}
let presenter = SoftbufferPresenter::new(window.clone(), window.clone())?;
Ok(Renderer::cpu(Box::new(presenter), size.0, size.1))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn la_preferencia_se_lee_sin_distinguir_mayusculas() {
assert_eq!(preference(Some("CPU")), Preference::Cpu);
assert_eq!(preference(Some("software")), Preference::Cpu);
assert_eq!(preference(Some("gpu")), Preference::Gpu);
assert_eq!(preference(Some("otra")), Preference::Auto);
assert_eq!(preference(None), Preference::Auto);
}
}