use tracing::{debug, error};
#[derive(Debug)]
pub struct Device {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}
impl Device {
pub async fn from_preferred_adapter(
instance: &wgpu::Instance,
surface: &wgpu::Surface,
) -> Result<(Self, wgpu::Adapter, wgpu::Features), DeviceError> {
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::None,
force_fallback_adapter: false,
compatible_surface: Some(surface),
})
.await
.ok_or(DeviceError::RequestAdapter)?;
debug!("Using adapter: {:?}", adapter.get_info());
let (device, features) = Device::new(&adapter).await?;
Ok((device, adapter, features))
}
pub async fn try_from_all_adapters(
instance: &wgpu::Instance,
) -> Result<(Self, wgpu::Adapter, wgpu::Features), DeviceError> {
let mut all_adapters =
instance.enumerate_adapters(wgpu::Backends::all());
let result = loop {
let Some(adapter) = all_adapters.next() else {
debug!("No more adapters to try");
break None;
};
let (device, features) = match Device::new(&adapter).await {
Ok((device, adapter)) => (device, adapter),
Err(err) => {
error!(
"Failed to get device from adapter {:?}: {:?}",
adapter.get_info(),
err,
);
continue;
}
};
break Some((device, adapter, features));
};
for adapter in all_adapters {
debug!(
"Remaining adapter that wasn't tried: {:?}",
adapter.get_info()
);
}
result.ok_or(DeviceError::FoundNoWorkingAdapter)
}
pub async fn new(
adapter: &wgpu::Adapter,
) -> Result<(Self, wgpu::Features), DeviceError> {
let features = {
let desired_features = wgpu::Features::POLYGON_MODE_LINE;
let available_features = adapter.features();
desired_features.intersection(available_features)
};
let limits = {
let lowest_limits = wgpu::Limits::downlevel_webgl2_defaults();
let supported_limits = adapter.limits();
lowest_limits.using_resolution(supported_limits)
};
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features,
limits,
},
None,
)
.await?;
Ok((Device { device, queue }, features))
}
}
#[derive(Debug, thiserror::Error)]
pub enum DeviceError {
#[error("Failed to request adapter")]
RequestAdapter,
#[error("Failed to request device")]
RequestDevice(#[from] wgpu::RequestDeviceError),
#[error("Found no working adapter to get a device from")]
FoundNoWorkingAdapter,
}