cotis-wgpu 0.1.0-alpha

Desktop wgpu renderer backend for Cotis
Documentation
use std::sync::Arc;

use winit::window::Window;

use crate::error::WgpuBackendError;

/// GPU adapter, device, and queue shared by the renderer.
pub struct GpuDevice {
    pub instance: wgpu::Instance,
    pub adapter: wgpu::Adapter,
    pub device: wgpu::Device,
    pub queue: wgpu::Queue,
}

impl GpuDevice {
    /// Initializes wgpu against a window-backed surface.
    pub fn new(window: &Arc<Window>) -> Result<Self, WgpuBackendError> {
        let instance = wgpu::Instance::default();

        let surface_target = unsafe { wgpu::SurfaceTargetUnsafe::from_window(window.as_ref()) }
            .map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;
        let surface = unsafe { instance.create_surface_unsafe(surface_target) }
            .map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;

        let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::default(),
            compatible_surface: Some(&surface),
            force_fallback_adapter: false,
        }))
        .ok_or(WgpuBackendError::NoAdapter)?;

        let (device, queue) = pollster::block_on(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: Some("cotis-wgpu device"),
                required_features: wgpu::Features::empty(),
                required_limits: wgpu::Limits::default(),
                memory_hints: wgpu::MemoryHints::default(),
            },
            None,
        ))
        .map_err(|error| WgpuBackendError::RequestDevice(error.to_string()))?;

        Ok(Self {
            instance,
            adapter,
            device,
            queue,
        })
    }
}

/// Picks the first sRGB-capable surface format, falling back to the first entry.
pub fn choose_surface_format(formats: &[wgpu::TextureFormat]) -> wgpu::TextureFormat {
    formats
        .iter()
        .copied()
        .find(wgpu::TextureFormat::is_srgb)
        .unwrap_or(formats[0])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn prefers_srgb_surface_format() {
        let formats = [
            wgpu::TextureFormat::Rgba16Float,
            wgpu::TextureFormat::Bgra8UnormSrgb,
        ];
        assert_eq!(
            choose_surface_format(&formats),
            wgpu::TextureFormat::Bgra8UnormSrgb
        );
    }
}