SolarEngine/solar_engine/src/engine_state.rs
2025-05-20 02:44:41 +02:00

228 lines
7.3 KiB
Rust

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<u32>,
window: Arc<Window>,
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<u32>, 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<u32>) {
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<GpuMaterial>) {
self.material_manager.set_materials(&self.device, materials);
}
pub fn set_instances(&mut self, instances: Vec<RenderInstance>) {
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
}
}