Files
wsg/lib/context.rs
T
Jérôme Bousquié 4fd39d32c6 configure context
2026-07-03 21:11:43 +02:00

99 lines
3.7 KiB
Rust

//! # Context Module
//!
//! Initializes the GPU, creates the surface, and holds the Device and Queue. It is static (created once at startup).
use std::sync::Arc;
use wgpu::{Adapter, Device, Instance, Queue, Surface};
use winit::window::Window;
use crate::error::WsgError;
/// Represents the GPU context. Holds all WGPU objects needed for rendering.
/// Created once at startup and shared across frames via Arc.
pub struct Context {
/// The entry point to wgpu — manages connections with graphics drivers (Vulkan, Metal, DX12).
pub instance: Instance,
/// Rendering target surface linking wgpu to the window (winit).
pub surface: Surface<'static>,
/// Physical or software GPU adapter selected by the user.
pub adapter: Adapter,
/// The engine core — creates buffers, textures, pipelines.
pub device: Device,
/// Command submission queue — drawing commands are sent here for execution.
pub queue: Queue,
}
impl Context {
/// Initializes the WGPU context. Creates the surface from the window, requests a device from the adapter,
/// and stores all required objects (instance, surface, adapter, device, queue).
/// Called once at application startup. Returns an error if GPU initialization fails.
pub async fn new(window: Arc<Window>) -> Result<Self, WsgError> {
// WGPU instance
let instance = wgpu::Instance::default();
// Surface (bound to window lifecycle, so unsafe)
let surface = instance
.create_surface(window)
.map_err(|e| WsgError::SurfaceCreation(e))?;
// Request for adapter (GPU)
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
compatible_surface: Some(&surface),
..Default::default()
})
.await
.map_err(|_| WsgError::NoAdapter)?;
// Request for adapter device and queue
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor::default())
.await
.map_err(|_| WsgError::DeviceCreation)?;
Ok(Self {
instance,
surface,
adapter,
device,
queue,
})
}
/// Configures the surface with a render format and alpha mode for rendering.
/// Inputs: adapter (GPU capabilities), width/height (surface resolution).
/// Returns Ok(()) on success or SurfaceIncompatible if no SRGB format + alpha mode exist.
/// Typically called by the renderer when window size changes.
pub fn configure(&self, adapter: &wgpu::Adapter, width: u32, height: u32) -> Result<(), WsgError> {
let caps = self.surface.get_capabilities(adapter);
// Prefer SRGB format for color accuracy; fall back to first available if none (technical point documented above).
let format = caps
.formats
.iter()
.copied()
.find(|f| f.is_srgb())
.or(caps.formats.first().copied())
.ok_or(WsgError::SurfaceIncompatible)?;
let alpha_mode = caps
.alpha_modes
.first()
.copied()
.ok_or(WsgError::SurfaceIncompatible)?;
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format,
width,
height,
present_mode: wgpu::PresentMode::Fifo, // V-Sync activated
alpha_mode, // first supported alpha mode
view_formats: vec![],
color_space: wgpu::SurfaceColorSpace::Srgb,
desired_maximum_frame_latency: 2,
};
self.surface.configure(&self.device, &config);
Ok(())
}
}