CRAWL/src/context.rs

134 lines
4.0 KiB
Rust

use std::sync::Arc;
use thiserror::Error;
use winit::{
dpi::PhysicalSize, event::WindowEvent, event_loop::EventLoopWindowTarget, window::Window,
};
#[derive(Error, Debug)]
pub enum ContextError {
#[error("Surface creation failed: {0}")]
Surface(#[from] wgpu::CreateSurfaceError),
#[error("Surface configuration failed: {0}")]
SurfaceConfig(String),
#[error("No compatible adapter found")]
Adapter,
#[error("Device request failed: {0}")]
Device(#[from] wgpu::RequestDeviceError),
}
pub struct Context<'window> {
pub window: Arc<Window>,
pub instance: wgpu::Instance,
pub size: PhysicalSize<u32>,
pub surface: wgpu::Surface<'window>,
pub surface_config: wgpu::SurfaceConfiguration,
pub adapter: wgpu::Adapter,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}
impl<'window> Context<'window> {
pub async fn new(
window: Arc<Window>,
backends: wgpu::Backends,
required_features: wgpu::Features,
required_limits: wgpu::Limits,
) -> Result<Self, ContextError> {
log::info!("Initialising WGPU context...");
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends,
dx12_shader_compiler: Default::default(),
..Default::default()
});
// To be able to start drawing we need a few things:
// - A surface
// - A GPU device to draw to the surface
// - A draw command queue
log::info!("Initialising window surface...");
let surface = instance.create_surface(window.clone())?;
log::info!("Requesting GPU adapter...");
let adapter = match instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: Some(&surface),
})
.await
{
Some(val) => val,
None => return Err(ContextError::Adapter),
};
log::info!("Checking GPU adapter meets requirements");
log::info!("Requesting GPU device...");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features,
required_limits,
},
None,
)
.await?;
log::info!("Configuring window surface...");
let size = window.inner_size();
let surface_config = match surface.get_default_config(&adapter, size.width, size.height) {
Some(val) => val,
None => {
return Err(ContextError::SurfaceConfig(
"Surface configuration unsupported by adapter".to_string(),
))
}
};
surface.configure(&device, &surface_config);
Ok(Self {
window,
instance,
size,
surface,
surface_config,
adapter,
device,
queue,
})
}
pub fn resize_surface(&mut self, new_size: PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.surface_config.width = new_size.width;
self.surface_config.height = new_size.height;
self.surface.configure(&self.device, &self.surface_config);
}
}
pub fn handle_window_event(
&mut self,
event: &WindowEvent,
elwt: &EventLoopWindowTarget<()>,
) -> bool {
let mut handled = true;
match event {
WindowEvent::CloseRequested => {
elwt.exit();
}
WindowEvent::Resized(physical_size) => {
self.resize_surface(*physical_size);
}
WindowEvent::ScaleFactorChanged { .. } => {
self.resize_surface(self.window.inner_size());
}
_ => handled = false,
}
handled
}
}