//! # 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) -> Result { // 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(()) } }