Merge pull request #2038 from hannobraun/render

Try all adapters, if one fails to return a device
This commit is contained in:
Hanno Braun 2023-09-29 16:32:33 +02:00 committed by GitHub
commit 6f9b3e2f41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 23 deletions

View File

@ -1,3 +1,5 @@
use tracing::{debug, error};
#[derive(Debug)] #[derive(Debug)]
pub struct Device { pub struct Device {
pub device: wgpu::Device, pub device: wgpu::Device,
@ -5,9 +7,66 @@ pub struct Device {
} }
impl Device { 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( pub async fn new(
adapter: &wgpu::Adapter, adapter: &wgpu::Adapter,
) -> Result<(Self, wgpu::Features), wgpu::RequestDeviceError> { ) -> Result<(Self, wgpu::Features), DeviceError> {
let features = { let features = {
let desired_features = wgpu::Features::POLYGON_MODE_LINE; let desired_features = wgpu::Features::POLYGON_MODE_LINE;
let available_features = adapter.features(); let available_features = adapter.features();
@ -49,3 +108,19 @@ impl Device {
Ok((Device { device, queue }, features)) Ok((Device { device, queue }, features))
} }
} }
/// Render device initialization error
#[derive(Debug, thiserror::Error)]
pub enum DeviceError {
/// Failed to request adapter
#[error("Failed to request adapter")]
RequestAdapter,
/// Failed to request device
#[error("Failed to request device")]
RequestDevice(#[from] wgpu::RequestDeviceError),
/// Found no working adapter to get a device from
#[error("Found no working adapter to get a device from")]
FoundNoWorkingAdapter,
}

View File

@ -15,6 +15,7 @@ mod uniforms;
mod vertices; mod vertices;
pub use self::{ pub use self::{
device::DeviceError,
draw_config::DrawConfig, draw_config::DrawConfig,
renderer::{DrawError, Renderer, RendererInitError}, renderer::{DrawError, Renderer, RendererInitError},
}; };

View File

@ -1,7 +1,7 @@
use std::{io, mem::size_of, vec}; use std::{io, mem::size_of, vec};
use thiserror::Error; use thiserror::Error;
use tracing::{debug, trace}; use tracing::{debug, error, trace};
use wgpu::util::DeviceExt as _; use wgpu::util::DeviceExt as _;
use crate::{ use crate::{
@ -13,7 +13,7 @@ use super::{
device::Device, draw_config::DrawConfig, drawables::Drawables, device::Device, draw_config::DrawConfig, drawables::Drawables,
geometries::Geometries, navigation_cube::NavigationCubeRenderer, geometries::Geometries, navigation_cube::NavigationCubeRenderer,
pipelines::Pipelines, transform::Transform, uniforms::Uniforms, pipelines::Pipelines, transform::Transform, uniforms::Uniforms,
vertices::Vertices, DEPTH_FORMAT, SAMPLE_COUNT, vertices::Vertices, DeviceError, DEPTH_FORMAT, SAMPLE_COUNT,
}; };
/// Graphics rendering state and target abstraction /// Graphics rendering state and target abstraction
@ -50,18 +50,28 @@ impl Renderer {
debug!("Available adapter: {:?}", adapter.get_info()); debug!("Available adapter: {:?}", adapter.get_info());
} }
let adapter = instance let result = Device::from_preferred_adapter(&instance, &surface).await;
.request_adapter(&wgpu::RequestAdapterOptions { let (device, adapter, features) = match result {
power_preference: wgpu::PowerPreference::None, Ok((device, adapter, features)) => (device, adapter, features),
force_fallback_adapter: false, Err(_) => {
compatible_surface: Some(&surface), error!("Failed to acquire device from preferred adapter");
})
.await
.ok_or(RendererInitError::RequestAdapter)?;
debug!("Using adapter: {:?}", adapter.get_info()); match Device::try_from_all_adapters(&instance).await {
Ok((device, adapter, features)) => {
(device, adapter, features)
}
Err(err) => {
error!("Prepend `RUST_LOG=fj_viewer=debug` and re-run");
error!("Then open an issue and post your output");
error!(
"https://github.com/hannobraun/fornjot/issues/new"
);
let (device, features) = Device::new(&adapter).await?; return Err(err.into());
}
}
}
};
let color_format = 'color_format: { let color_format = 'color_format: {
let capabilities = surface.get_capabilities(&adapter); let capabilities = surface.get_capabilities(&adapter);
@ -374,15 +384,9 @@ pub enum RendererInitError {
#[error("Error creating surface")] #[error("Error creating surface")]
CreateSurface(#[from] wgpu::CreateSurfaceError), CreateSurface(#[from] wgpu::CreateSurfaceError),
/// Graphics accelerator acquisition error /// Device error
#[error("Error request adapter")] #[error(transparent)]
RequestAdapter, Device(#[from] DeviceError),
/// Device request errors
///
/// See: [wgpu::RequestDeviceError](https://docs.rs/wgpu/latest/wgpu/struct.RequestDeviceError.html)
#[error("Error requesting device")]
RequestDevice(#[from] wgpu::RequestDeviceError),
} }
/// Draw error /// Draw error

View File

@ -18,7 +18,7 @@ mod screen;
mod viewer; mod viewer;
pub use self::{ pub use self::{
graphics::RendererInitError, graphics::{DeviceError, RendererInitError},
input::InputEvent, input::InputEvent,
screen::{NormalizedScreenPosition, Screen, ScreenSize}, screen::{NormalizedScreenPosition, Screen, ScreenSize},
viewer::Viewer, viewer::Viewer,