frenderer/
gpu.rs

1//! A wrapper for WGPU state.
2
3use std::sync::Arc;
4
5#[derive(Debug)]
6pub enum FrendererError {
7    NoUsableAdapter,
8}
9impl std::fmt::Display for FrendererError {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        match self {
12            FrendererError::NoUsableAdapter => {
13                f.write_str("No valid adapter found for GPU requirements")
14            }
15        }
16    }
17}
18impl std::error::Error for FrendererError {}
19
20/// A wrapper for a WGPU instance, surface, adapter, device, queue, and surface configuration.
21#[allow(dead_code)]
22pub struct WGPU {
23    instance: Arc<wgpu::Instance>,
24    adapter: Arc<wgpu::Adapter>,
25    device: Arc<wgpu::Device>,
26    queue: Arc<wgpu::Queue>,
27}
28
29impl WGPU {
30    /// Create a WGPU structure with already-created GPU resources.
31    pub fn with_resources(
32        instance: Arc<wgpu::Instance>,
33        adapter: Arc<wgpu::Adapter>,
34        device: Arc<wgpu::Device>,
35        queue: Arc<wgpu::Queue>,
36    ) -> Self {
37        Self {
38            instance,
39            adapter,
40            device,
41            queue,
42        }
43    }
44    /// Create a WGPU structure by initializing WGPU for display onto the given surface.
45    pub async fn new(
46        instance: Arc<wgpu::Instance>,
47        surface: Option<&wgpu::Surface<'static>>,
48    ) -> Result<Self, Box<dyn std::error::Error>> {
49        let adapter = instance
50            .request_adapter(&wgpu::RequestAdapterOptions {
51                power_preference: wgpu::PowerPreference::default(),
52                force_fallback_adapter: false,
53                // Request an adapter which can render to our surface
54                compatible_surface: surface,
55            })
56            .await
57            .ok_or(FrendererError::NoUsableAdapter)?;
58        let is_gl = adapter.get_info().backend == wgpu::Backend::Gl;
59        #[cfg(not(target_arch = "wasm32"))]
60        let is_web = false;
61        #[cfg(target_arch = "wasm32")]
62        let is_web = true;
63        let use_storage = !(is_web && is_gl);
64
65        // Create the logical device and command queue
66        let (device, queue) = adapter
67            .request_device(
68                &wgpu::DeviceDescriptor {
69                    label: None,
70                    required_features: wgpu::Features::empty(),
71                    required_limits: if use_storage {
72                        wgpu::Limits::downlevel_defaults()
73                    } else {
74                        wgpu::Limits::downlevel_webgl2_defaults()
75                    }
76                    .using_resolution(adapter.limits()),
77                },
78                None,
79            )
80            .await?;
81        Ok(Self::with_resources(
82            instance,
83            Arc::new(adapter),
84            Arc::new(device),
85            Arc::new(queue),
86        ))
87    }
88    /// Returns true if this GPU interface is using a GL backend, important to work around some bugs
89    pub fn is_gl(&self) -> bool {
90        self.adapter.get_info().backend == wgpu::Backend::Gl
91    }
92    /// Returns true if this GPU interface is in web mode
93    #[cfg(target_arch = "wasm32")]
94    pub fn is_web(&self) -> bool {
95        true
96    }
97    #[cfg(not(target_arch = "wasm32"))]
98    pub fn is_web(&self) -> bool {
99        false
100    }
101    /// Whether this GPU supports storage buffers
102    pub fn supports_storage(&self) -> bool {
103        !(self.is_gl() && self.is_web())
104            && self
105                .adapter
106                .get_downlevel_capabilities()
107                .flags
108                .contains(wgpu::DownlevelFlags::VERTEX_STORAGE)
109            && self.device.limits().max_storage_buffers_per_shader_stage > 0
110    }
111    /// Returns this GPU wrapper's [`wgpu::Instance`].
112    pub fn instance(&self) -> &wgpu::Instance {
113        &self.instance
114    }
115
116    /// Returns this GPU wrapper's [`wgpu::Adapter`].
117    pub fn adapter(&self) -> &wgpu::Adapter {
118        &self.adapter
119    }
120    /// Returns this GPU wrapper's [`wgpu::Device`].
121    pub fn device(&self) -> &wgpu::Device {
122        &self.device
123    }
124    /// Returns this GPU wrapper's [`wgpu::Queue`].
125    pub fn queue(&self) -> &wgpu::Queue {
126        &self.queue
127    }
128}