Skip to content

Commit

Permalink
Merge pull request #2038 from hannobraun/render
Browse files Browse the repository at this point in the history
Try all adapters, if one fails to return a device
  • Loading branch information
hannobraun authored Sep 29, 2023
2 parents 0452802 + 720fd5f commit 6f9b3e2
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 25 deletions.
77 changes: 76 additions & 1 deletion crates/fj-viewer/src/graphics/device.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,72 @@
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), wgpu::RequestDeviceError> {
) -> Result<(Self, wgpu::Features), DeviceError> {
let features = {
let desired_features = wgpu::Features::POLYGON_MODE_LINE;
let available_features = adapter.features();
Expand Down Expand Up @@ -49,3 +108,19 @@ impl Device {
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,
}
1 change: 1 addition & 0 deletions crates/fj-viewer/src/graphics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod uniforms;
mod vertices;

pub use self::{
device::DeviceError,
draw_config::DrawConfig,
renderer::{DrawError, Renderer, RendererInitError},
};
Expand Down
50 changes: 27 additions & 23 deletions crates/fj-viewer/src/graphics/renderer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{io, mem::size_of, vec};

use thiserror::Error;
use tracing::{debug, trace};
use tracing::{debug, error, trace};
use wgpu::util::DeviceExt as _;

use crate::{
Expand All @@ -13,7 +13,7 @@ use super::{
device::Device, draw_config::DrawConfig, drawables::Drawables,
geometries::Geometries, navigation_cube::NavigationCubeRenderer,
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
Expand Down Expand Up @@ -50,18 +50,28 @@ impl Renderer {
debug!("Available adapter: {:?}", adapter.get_info());
}

let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::None,
force_fallback_adapter: false,
compatible_surface: Some(&surface),
})
.await
.ok_or(RendererInitError::RequestAdapter)?;

debug!("Using adapter: {:?}", adapter.get_info());

let (device, features) = Device::new(&adapter).await?;
let result = Device::from_preferred_adapter(&instance, &surface).await;
let (device, adapter, features) = match result {
Ok((device, adapter, features)) => (device, adapter, features),
Err(_) => {
error!("Failed to acquire device from preferred adapter");

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"
);

return Err(err.into());
}
}
}
};

let color_format = 'color_format: {
let capabilities = surface.get_capabilities(&adapter);
Expand Down Expand Up @@ -374,15 +384,9 @@ pub enum RendererInitError {
#[error("Error creating surface")]
CreateSurface(#[from] wgpu::CreateSurfaceError),

/// Graphics accelerator acquisition error
#[error("Error request adapter")]
RequestAdapter,

/// Device request errors
///
/// See: [wgpu::RequestDeviceError](https://docs.rs/wgpu/latest/wgpu/struct.RequestDeviceError.html)
#[error("Error requesting device")]
RequestDevice(#[from] wgpu::RequestDeviceError),
/// Device error
#[error(transparent)]
Device(#[from] DeviceError),
}

/// Draw error
Expand Down
2 changes: 1 addition & 1 deletion crates/fj-viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod screen;
mod viewer;

pub use self::{
graphics::RendererInitError,
graphics::{DeviceError, RendererInitError},
input::InputEvent,
screen::{NormalizedScreenPosition, Screen, ScreenSize},
viewer::Viewer,
Expand Down

0 comments on commit 6f9b3e2

Please sign in to comment.