use std::fmt;
#[derive(Debug)]
pub struct Error(pub String);
impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "error de GPU: {}", self.0)
}
}
impl std::error::Error for Error {}
fn gpu_error(error: impl fmt::Display) -> Error {
Error(error.to_string())
}
pub struct GpuContext {
pub adapter: wgpu::AdapterInfo,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub surface: wgpu::Surface<'static>,
pub config: wgpu::SurfaceConfiguration,
}
impl GpuContext {
pub async fn new(
descriptor: wgpu::InstanceDescriptor,
target: impl Into<wgpu::SurfaceTarget<'static>>,
width: u32,
height: u32,
) -> Result<Self, Error> {
let instance = wgpu::Instance::new(descriptor);
let surface = instance.create_surface(target).map_err(gpu_error)?;
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::LowPower,
compatible_surface: Some(&surface),
..Default::default()
})
.await
.map_err(gpu_error)?;
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: Some("aura_device"),
memory_hints: wgpu::MemoryHints::MemoryUsage,
required_limits: wgpu::Limits::default().or_worse_values_from(&adapter.limits()),
..Default::default()
})
.await
.map_err(gpu_error)?;
let mut config = surface
.get_default_config(&adapter, width.max(1), height.max(1))
.ok_or_else(|| Error("la superficie no es compatible con el adaptador".into()))?;
let capabilities = surface.get_capabilities(&adapter);
if let Some(format) = Self::preferred_format(&capabilities.formats) {
config.format = format;
}
config.present_mode = wgpu::PresentMode::Fifo;
config.desired_maximum_frame_latency = 1;
surface.configure(&device, &config);
Ok(Self { adapter: adapter.get_info(), device, queue, surface, config })
}
pub fn is_software(&self) -> bool {
self.adapter.device_type == wgpu::DeviceType::Cpu
}
fn preferred_format(formats: &[wgpu::TextureFormat]) -> Option<wgpu::TextureFormat> {
formats.iter().copied().find(|format| !format.is_srgb())
}
pub fn resize(&mut self, width: u32, height: u32) {
if width == 0 || height == 0 {
return;
}
self.config.width = width;
self.config.height = height;
self.surface.configure(&self.device, &self.config);
}
}