fj_viewer/graphics/
device.rs1use tracing::{debug, error};
2
3#[derive(Debug)]
4pub struct Device {
5 pub device: wgpu::Device,
6 pub queue: wgpu::Queue,
7}
8
9impl Device {
10 pub async fn from_preferred_adapter(
11 instance: &wgpu::Instance,
12 surface: &wgpu::Surface<'_>,
13 ) -> Result<(Self, wgpu::Adapter, wgpu::Features), DeviceError> {
14 let adapter = instance
15 .request_adapter(&wgpu::RequestAdapterOptions {
16 power_preference: wgpu::PowerPreference::None,
17 force_fallback_adapter: false,
18 compatible_surface: Some(surface),
19 })
20 .await
21 .ok_or(DeviceError::RequestAdapter)?;
22
23 debug!("Using adapter: {:?}", adapter.get_info());
24
25 let (device, features) = Device::new(&adapter).await?;
26
27 Ok((device, adapter, features))
28 }
29
30 pub async fn try_from_all_adapters(
31 instance: &wgpu::Instance,
32 ) -> Result<(Self, wgpu::Adapter, wgpu::Features), DeviceError> {
33 let mut all_adapters = instance
34 .enumerate_adapters(wgpu::Backends::all())
35 .into_iter();
36
37 let result = loop {
38 let Some(adapter) = all_adapters.next() else {
39 debug!("No more adapters to try");
40 break None;
41 };
42
43 let (device, features) = match Device::new(&adapter).await {
44 Ok((device, adapter)) => (device, adapter),
45 Err(err) => {
46 error!(
47 "Failed to get device from adapter {:?}: {:?}",
48 adapter.get_info(),
49 err,
50 );
51 continue;
52 }
53 };
54
55 break Some((device, adapter, features));
56 };
57
58 for adapter in all_adapters {
59 debug!(
60 "Remaining adapter that wasn't tried: {:?}",
61 adapter.get_info()
62 );
63 }
64
65 result.ok_or(DeviceError::FoundNoWorkingAdapter)
66 }
67
68 pub async fn new(
69 adapter: &wgpu::Adapter,
70 ) -> Result<(Self, wgpu::Features), DeviceError> {
71 let required_features = {
72 let desired_features = wgpu::Features::POLYGON_MODE_LINE;
73 let available_features = adapter.features();
74
75 desired_features.intersection(available_features)
84 };
85
86 let required_limits = {
87 let lowest_limits = wgpu::Limits::downlevel_webgl2_defaults();
90
91 let supported_limits = adapter.limits();
95 lowest_limits.using_resolution(supported_limits)
96 };
97
98 let (device, queue) = adapter
99 .request_device(
100 &wgpu::DeviceDescriptor {
101 label: None,
102 required_features,
103 required_limits,
104 },
105 None,
106 )
107 .await?;
108
109 Ok((Device { device, queue }, required_features))
110 }
111}
112
113#[derive(Debug, thiserror::Error)]
115pub enum DeviceError {
116 #[error("Failed to request adapter")]
118 RequestAdapter,
119
120 #[error("Failed to request device")]
122 RequestDevice(#[from] wgpu::RequestDeviceError),
123
124 #[error("Found no working adapter to get a device from")]
126 FoundNoWorkingAdapter,
127}