use std::sync::{Arc}; use log::info; use pollster::FutureExt; use wgpu::{Adapter, Device, Instance, PresentMode, Queue, Surface, SurfaceCapabilities, SurfaceConfiguration, SurfaceError}; use winit::dpi::PhysicalSize; use winit::window::{Window}; use crate::camera::Camera; use crate::geometry_manager::GeometryManager; use crate::globals_manager::GlobalsManager; use crate::instance_manager::{InstanceManager, RenderInstance}; use crate::light_manager::{LightManager}; use crate::material_manager::{GpuMaterial, MaterialManager}; use crate::render_manager::{RenderManager}; pub struct SampleCount(pub u32); type RenderResult = Result<(), SurfaceError>; impl SampleCount { pub fn get(&self) -> u32 { self.0 } } pub struct EngineState<'a> { surface: Surface<'a>, device: Device, queue: Queue, config: SurfaceConfiguration, sample_count: SampleCount, size: PhysicalSize, window: Arc, pub camera: Camera, pub globals_manager: GlobalsManager, pub geometry_manager: GeometryManager, pub instance_manager: InstanceManager, pub light_manager: LightManager, pub material_manager: MaterialManager, pub render_manager: RenderManager, } impl<'a> EngineState<'a> { pub(crate) fn new(window: Window) -> Self { let window = Arc::new(window); let size = window.inner_size(); let instance = Self::create_gpu_instance(); let surface = instance.create_surface(window.clone()).unwrap(); let adapter = Self::create_adapter(instance, &surface); let (device, queue) = Self::create_device(&adapter); let capabilities = surface.get_capabilities(&adapter); let config = Self::create_surface_config(size, capabilities); surface.configure(&device, &config); let sample_count = SampleCount(Self::probe_msaa_support(&device, &config)); info!("MSAA sample count: {}", sample_count.get()); let camera = Camera::new(config.width as f32 / config.height as f32); let globals_manager = GlobalsManager::new(&device, config.width, config.height, &camera); let geometry_manager = GeometryManager::new(&device); let instance_manager = InstanceManager::new(&device); let mut light_manager = LightManager::new(&device, 100); let mut material_manager = MaterialManager::new(&device); let render_manager = RenderManager::new( &device, &config, &globals_manager, &mut light_manager, &material_manager, &camera, sample_count.get(), ); Self { surface, device, queue, config, sample_count, size, window, camera, globals_manager, geometry_manager, instance_manager, light_manager, material_manager, render_manager, } } fn probe_msaa_support(device: &Device, config: &SurfaceConfiguration) -> u32 { pollster::block_on(async { for &count in &[16, 8, 4, 2] { device.push_error_scope(wgpu::ErrorFilter::Validation); let _ = device.create_texture(&wgpu::TextureDescriptor { label: Some("MSAA Probe"), size: wgpu::Extent3d { width: 4, height: 4, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: count, dimension: wgpu::TextureDimension::D2, format: config.format, usage: wgpu::TextureUsages::RENDER_ATTACHMENT, view_formats: &[], }); if device.pop_error_scope().await.is_none() { return count; } } 2 // fallback }) } fn create_surface_config(size: PhysicalSize, capabilities: SurfaceCapabilities) -> wgpu::SurfaceConfiguration { let surface_format = capabilities.formats.iter() .find(|f| f.is_srgb()) .copied() .unwrap_or(capabilities.formats[0]); SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: surface_format, width: size.width, height: size.height, present_mode: PresentMode::AutoVsync, alpha_mode: capabilities.alpha_modes[0], view_formats: vec![], desired_maximum_frame_latency: 2, } } fn create_device(adapter: &Adapter) -> (Device, Queue) { adapter.request_device( &wgpu::DeviceDescriptor { required_features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, required_limits: wgpu::Limits::default(), memory_hints: Default::default(), label: None, trace: Default::default(), }).block_on().unwrap() } fn create_adapter(instance: Instance, surface: &Surface) -> Adapter { instance.request_adapter( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), compatible_surface: Some(&surface), force_fallback_adapter: false, } ).block_on().unwrap() } fn create_gpu_instance() -> Instance { Instance::new(&wgpu::InstanceDescriptor { backends: wgpu::Backends::PRIMARY, ..Default::default() }) } pub(crate) fn resize(&mut self, new_size: PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; self.config.width = new_size.width; self.config.height = new_size.height; self.surface.configure(&self.device, &self.config); self.camera.set_aspect(new_size.width as f32 / new_size.height as f32); self.globals_manager.resize(&self.queue, new_size.width, new_size.height, &self.camera); self.render_manager.resize(&self.device, new_size.width, new_size.height); } } pub fn update(&mut self) {} pub fn render(&mut self) -> RenderResult { let output = self.surface.get_current_texture()?; let view = output.texture.create_view(&Default::default()); self.render_manager.render_frame( &self.device, &self.queue, output, &view, self.config.format, &mut self.globals_manager, &self.camera, &mut self.light_manager, &self.geometry_manager, &self.instance_manager, &mut self.material_manager ) } pub fn set_materials(&mut self, materials: Vec) { self.material_manager.set_materials(&self.device, materials); } pub fn set_instances(&mut self, instances: Vec) { self.instance_manager.set_instances(&self.device, &self.queue, instances); } pub fn window(&self) -> &Window { &self.window } pub fn camera_mut(&mut self) -> &mut crate::camera::Camera { &mut self.camera } pub fn camera(&self) -> &crate::camera::Camera { &self.camera } }