2025-05-05 15:42:37 +02:00
|
|
|
use std::sync::{Arc};
|
2025-05-05 15:33:22 +02:00
|
|
|
use log::info;
|
|
|
|
|
use pollster::FutureExt;
|
2025-05-08 20:24:00 +02:00
|
|
|
use wgpu::{Adapter, Device, Instance, PresentMode, Queue, Surface, SurfaceCapabilities, SurfaceConfiguration, SurfaceError};
|
2025-05-05 15:33:22 +02:00
|
|
|
use winit::dpi::PhysicalSize;
|
2025-05-05 15:42:37 +02:00
|
|
|
use winit::window::{Window};
|
2025-05-05 20:07:20 +02:00
|
|
|
use crate::camera::Camera;
|
2025-05-08 20:17:31 +02:00
|
|
|
use crate::geometry_manager::GeometryManager;
|
2025-05-20 02:44:41 +02:00
|
|
|
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};
|
2025-05-08 20:24:00 +02:00
|
|
|
|
|
|
|
|
pub struct SampleCount(pub u32);
|
2025-05-20 02:44:41 +02:00
|
|
|
type RenderResult = Result<(), SurfaceError>;
|
2025-05-08 20:24:00 +02:00
|
|
|
|
|
|
|
|
impl SampleCount {
|
|
|
|
|
pub fn get(&self) -> u32 {
|
|
|
|
|
self.0
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-05 15:33:22 +02:00
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
pub struct EngineState<'a> {
|
2025-05-05 15:33:22 +02:00
|
|
|
surface: Surface<'a>,
|
|
|
|
|
device: Device,
|
|
|
|
|
queue: Queue,
|
|
|
|
|
config: SurfaceConfiguration,
|
|
|
|
|
sample_count: SampleCount,
|
|
|
|
|
size: PhysicalSize<u32>,
|
2025-05-05 20:07:20 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
window: Arc<Window>,
|
|
|
|
|
pub camera: Camera,
|
2025-05-06 17:12:22 +02:00
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
pub globals_manager: GlobalsManager,
|
2025-05-08 20:17:31 +02:00
|
|
|
pub geometry_manager: GeometryManager,
|
|
|
|
|
pub instance_manager: InstanceManager,
|
2025-05-06 17:12:22 +02:00
|
|
|
pub light_manager: LightManager,
|
2025-05-10 19:49:05 +02:00
|
|
|
pub material_manager: MaterialManager,
|
2025-05-20 02:44:41 +02:00
|
|
|
pub render_manager: RenderManager,
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
impl<'a> EngineState<'a> {
|
2025-05-05 15:33:22 +02:00
|
|
|
pub(crate) fn new(window: Window) -> Self {
|
2025-05-08 20:17:31 +02:00
|
|
|
let window = Arc::new(window);
|
|
|
|
|
let size = window.inner_size();
|
2025-05-05 15:33:22 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
let instance = Self::create_gpu_instance();
|
2025-05-05 15:33:22 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
let surface = instance.create_surface(window.clone()).unwrap();
|
2025-05-05 20:07:20 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
let adapter = Self::create_adapter(instance, &surface);
|
2025-05-05 15:33:22 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
let (device, queue) = Self::create_device(&adapter);
|
2025-05-06 17:12:22 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
let capabilities = surface.get_capabilities(&adapter);
|
|
|
|
|
let config = Self::create_surface_config(size, capabilities);
|
|
|
|
|
surface.configure(&device, &config);
|
2025-05-05 15:33:22 +02:00
|
|
|
|
2025-05-08 20:17:31 +02:00
|
|
|
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);
|
|
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
let globals_manager = GlobalsManager::new(&device, config.width, config.height, &camera);
|
2025-05-08 20:17:31 +02:00
|
|
|
let geometry_manager = GeometryManager::new(&device);
|
|
|
|
|
let instance_manager = InstanceManager::new(&device);
|
|
|
|
|
let mut light_manager = LightManager::new(&device, 100);
|
|
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
let mut material_manager = MaterialManager::new(&device);
|
2025-05-10 19:49:05 +02:00
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
let render_manager = RenderManager::new(
|
2025-05-08 20:17:31 +02:00
|
|
|
&device,
|
|
|
|
|
&config,
|
2025-05-20 02:44:41 +02:00
|
|
|
&globals_manager,
|
2025-05-08 20:17:31 +02:00
|
|
|
&mut light_manager,
|
2025-05-10 19:49:05 +02:00
|
|
|
&material_manager,
|
2025-05-08 20:17:31 +02:00
|
|
|
&camera,
|
|
|
|
|
sample_count.get(),
|
|
|
|
|
);
|
2025-05-05 21:59:27 +02:00
|
|
|
|
2025-05-05 15:33:22 +02:00
|
|
|
Self {
|
|
|
|
|
surface,
|
|
|
|
|
device,
|
|
|
|
|
queue,
|
|
|
|
|
config,
|
|
|
|
|
sample_count,
|
|
|
|
|
size,
|
2025-05-08 20:17:31 +02:00
|
|
|
window,
|
2025-05-05 20:07:20 +02:00
|
|
|
camera,
|
2025-05-20 02:44:41 +02:00
|
|
|
globals_manager,
|
2025-05-08 20:17:31 +02:00
|
|
|
geometry_manager,
|
|
|
|
|
instance_manager,
|
|
|
|
|
light_manager,
|
2025-05-10 19:49:05 +02:00
|
|
|
material_manager,
|
2025-05-20 02:44:41 +02:00
|
|
|
render_manager,
|
2025-05-05 21:52:42 +02:00
|
|
|
}
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-10 12:12:00 +02:00
|
|
|
2 // fallback
|
2025-05-05 15:33:22 +02:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>) {
|
2025-05-08 20:17:31 +02:00
|
|
|
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);
|
2025-05-20 02:44:41 +02:00
|
|
|
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);
|
2025-05-08 20:17:31 +02:00
|
|
|
}
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
pub fn update(&mut self) {}
|
|
|
|
|
|
|
|
|
|
pub fn render(&mut self) -> RenderResult {
|
2025-05-05 15:33:22 +02:00
|
|
|
let output = self.surface.get_current_texture()?;
|
2025-05-08 20:17:31 +02:00
|
|
|
let view = output.texture.create_view(&Default::default());
|
|
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
self.render_manager.render_frame(
|
2025-05-08 20:17:31 +02:00
|
|
|
&self.device,
|
|
|
|
|
&self.queue,
|
|
|
|
|
output,
|
|
|
|
|
&view,
|
|
|
|
|
self.config.format,
|
2025-05-20 02:44:41 +02:00
|
|
|
&mut self.globals_manager,
|
2025-05-08 20:17:31 +02:00
|
|
|
&self.camera,
|
|
|
|
|
&mut self.light_manager,
|
|
|
|
|
&self.geometry_manager,
|
|
|
|
|
&self.instance_manager,
|
2025-05-10 19:49:05 +02:00
|
|
|
&mut self.material_manager
|
2025-05-08 20:17:31 +02:00
|
|
|
)
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|
2025-05-08 20:17:31 +02:00
|
|
|
|
2025-05-20 02:44:41 +02:00
|
|
|
pub fn set_materials(&mut self, materials: Vec<GpuMaterial>) {
|
|
|
|
|
self.material_manager.set_materials(&self.device, materials);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-05 15:33:22 +02:00
|
|
|
pub fn set_instances(&mut self, instances: Vec<RenderInstance>) {
|
2025-05-08 20:17:31 +02:00
|
|
|
self.instance_manager.set_instances(&self.device, &self.queue, instances);
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn window(&self) -> &Window {
|
|
|
|
|
&self.window
|
|
|
|
|
}
|
2025-05-05 21:29:51 +02:00
|
|
|
|
|
|
|
|
pub fn camera_mut(&mut self) -> &mut crate::camera::Camera {
|
|
|
|
|
&mut self.camera
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn camera(&self) -> &crate::camera::Camera {
|
|
|
|
|
&self.camera
|
|
|
|
|
}
|
2025-05-05 15:33:22 +02:00
|
|
|
}
|