From f8bcfd4b81a7ea384ad34944f1bd108ceae115b0 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 29 Sep 2023 16:02:31 +0200 Subject: [PATCH 1/4] Add `DeviceError` --- crates/fj-viewer/src/graphics/device.rs | 10 +++++++++- crates/fj-viewer/src/graphics/mod.rs | 1 + crates/fj-viewer/src/graphics/renderer.rs | 10 ++++------ crates/fj-viewer/src/lib.rs | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/crates/fj-viewer/src/graphics/device.rs b/crates/fj-viewer/src/graphics/device.rs index 0062d5ea2..d1438fe52 100644 --- a/crates/fj-viewer/src/graphics/device.rs +++ b/crates/fj-viewer/src/graphics/device.rs @@ -7,7 +7,7 @@ pub struct Device { impl Device { 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(); @@ -49,3 +49,11 @@ impl Device { Ok((Device { device, queue }, features)) } } + +/// Render device initialization error +#[derive(Debug, thiserror::Error)] +pub enum DeviceError { + /// Failed to request device + #[error("Failed to request device")] + RequestDevice(#[from] wgpu::RequestDeviceError), +} diff --git a/crates/fj-viewer/src/graphics/mod.rs b/crates/fj-viewer/src/graphics/mod.rs index abda85fb1..0785f08de 100644 --- a/crates/fj-viewer/src/graphics/mod.rs +++ b/crates/fj-viewer/src/graphics/mod.rs @@ -15,6 +15,7 @@ mod uniforms; mod vertices; pub use self::{ + device::DeviceError, draw_config::DrawConfig, renderer::{DrawError, Renderer, RendererInitError}, }; diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index 469c26f2c..a73590191 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -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 @@ -378,11 +378,9 @@ pub enum RendererInitError { #[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 diff --git a/crates/fj-viewer/src/lib.rs b/crates/fj-viewer/src/lib.rs index 6819762f7..b3532ef05 100644 --- a/crates/fj-viewer/src/lib.rs +++ b/crates/fj-viewer/src/lib.rs @@ -18,7 +18,7 @@ mod screen; mod viewer; pub use self::{ - graphics::RendererInitError, + graphics::{DeviceError, RendererInitError}, input::InputEvent, screen::{NormalizedScreenPosition, Screen, ScreenSize}, viewer::Viewer, From 6edf455a185180c82f1052dbe11247280efe80ae Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 29 Sep 2023 16:04:49 +0200 Subject: [PATCH 2/4] Refactor to prepare for follow-on change --- crates/fj-viewer/src/graphics/device.rs | 4 ++++ crates/fj-viewer/src/graphics/renderer.rs | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/fj-viewer/src/graphics/device.rs b/crates/fj-viewer/src/graphics/device.rs index d1438fe52..d7972a351 100644 --- a/crates/fj-viewer/src/graphics/device.rs +++ b/crates/fj-viewer/src/graphics/device.rs @@ -53,6 +53,10 @@ impl Device { /// 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), diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index a73590191..26fa5884f 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -57,7 +57,7 @@ impl Renderer { compatible_surface: Some(&surface), }) .await - .ok_or(RendererInitError::RequestAdapter)?; + .ok_or(RendererInitError::Device(DeviceError::RequestAdapter))?; debug!("Using adapter: {:?}", adapter.get_info()); @@ -374,10 +374,6 @@ pub enum RendererInitError { #[error("Error creating surface")] CreateSurface(#[from] wgpu::CreateSurfaceError), - /// Graphics accelerator acquisition error - #[error("Error request adapter")] - RequestAdapter, - /// Device error #[error(transparent)] Device(#[from] DeviceError), From 8e1900679b4e8ccd61e59a7c94e3192adde1ed45 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 29 Sep 2023 16:06:55 +0200 Subject: [PATCH 3/4] Add `Device::from_preferred_adapter` --- crates/fj-viewer/src/graphics/device.rs | 22 ++++++++++++++++++++++ crates/fj-viewer/src/graphics/renderer.rs | 14 ++------------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/crates/fj-viewer/src/graphics/device.rs b/crates/fj-viewer/src/graphics/device.rs index d7972a351..73b35f053 100644 --- a/crates/fj-viewer/src/graphics/device.rs +++ b/crates/fj-viewer/src/graphics/device.rs @@ -1,3 +1,5 @@ +use tracing::debug; + #[derive(Debug)] pub struct Device { pub device: wgpu::Device, @@ -5,6 +7,26 @@ pub struct 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 new( adapter: &wgpu::Adapter, ) -> Result<(Self, wgpu::Features), DeviceError> { diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index 26fa5884f..424017ad1 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -50,18 +50,8 @@ 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::Device(DeviceError::RequestAdapter))?; - - debug!("Using adapter: {:?}", adapter.get_info()); - - let (device, features) = Device::new(&adapter).await?; + let (device, adapter, features) = + Device::from_preferred_adapter(&instance, &surface).await?; let color_format = 'color_format: { let capabilities = surface.get_capabilities(&adapter); From 720fd5f4e12aec478b059758bd4ff3cbf4a28a3c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 29 Sep 2023 16:27:13 +0200 Subject: [PATCH 4/4] Try other adapters, if one fails to return device --- crates/fj-viewer/src/graphics/device.rs | 43 ++++++++++++++++++++++- crates/fj-viewer/src/graphics/renderer.rs | 26 ++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/crates/fj-viewer/src/graphics/device.rs b/crates/fj-viewer/src/graphics/device.rs index 73b35f053..63d3bee21 100644 --- a/crates/fj-viewer/src/graphics/device.rs +++ b/crates/fj-viewer/src/graphics/device.rs @@ -1,4 +1,4 @@ -use tracing::debug; +use tracing::{debug, error}; #[derive(Debug)] pub struct Device { @@ -27,6 +27,43 @@ impl Device { 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> { @@ -82,4 +119,8 @@ pub enum DeviceError { /// 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, } diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index 424017ad1..6f3960db7 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -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::{ @@ -50,8 +50,28 @@ impl Renderer { debug!("Available adapter: {:?}", adapter.get_info()); } - let (device, adapter, features) = - Device::from_preferred_adapter(&instance, &surface).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);