use frus_core::Scene;
use crate::compositor::{preferred_sample_count, Painters};
const CLEAR_COLOR: wgpu::Color = wgpu::Color {
r: 0.05,
g: 0.05,
b: 0.08,
a: 1.0,
};
pub struct Renderer {
surface: wgpu::Surface<'static>,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
painters: Painters,
}
impl Renderer {
pub async fn new(
target: impl Into<wgpu::SurfaceTarget<'static>>,
width: u32,
height: u32,
) -> anyhow::Result<Self> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
..wgpu::InstanceDescriptor::new_without_display_handle()
});
let surface = instance.create_surface(target)?;
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
..Default::default()
})
.await?;
log::info!("Adaptateur GPU : {:?}", adapter.get_info());
let required_limits = wgpu::Limits::downlevel_defaults().using_resolution(adapter.limits());
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: Some("frus.device"),
required_features: wgpu::Features::empty(),
required_limits,
memory_hints: wgpu::MemoryHints::Performance,
..Default::default()
})
.await?;
let caps = surface.get_capabilities(&adapter);
let format = caps
.formats
.iter()
.copied()
.find(|f| f.is_srgb())
.unwrap_or(caps.formats[0]);
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format,
color_space: wgpu::SurfaceColorSpace::Auto,
width,
height,
present_mode: caps.present_modes[0],
alpha_mode: caps.alpha_modes[0],
view_formats: vec![],
desired_maximum_frame_latency: 2,
};
surface.configure(&device, &config);
let sample_count = preferred_sample_count(&adapter, format);
log::info!("MSAA: {sample_count}×");
let mut painters = Painters::new(&device, &queue, format, sample_count);
painters.warm_up(&device, &queue, format);
Ok(Self {
surface,
device,
queue,
config,
painters,
})
}
pub fn resize(&mut self, width: u32, height: u32) {
if width > 0 && height > 0 {
self.config.width = width;
self.config.height = height;
self.surface.configure(&self.device, &self.config);
}
}
pub fn reconfigure(&mut self) {
self.surface.configure(&self.device, &self.config);
}
pub fn render(&mut self, scene: &Scene) -> RenderOutcome {
let frame = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(frame)
| wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
wgpu::CurrentSurfaceTexture::Timeout | wgpu::CurrentSurfaceTexture::Occluded => {
return RenderOutcome::Skipped;
}
wgpu::CurrentSurfaceTexture::Outdated | wgpu::CurrentSurfaceTexture::Lost => {
return RenderOutcome::NeedsReconfigure;
}
wgpu::CurrentSurfaceTexture::Validation => {
log::warn!("frame skipped: surface validation error");
return RenderOutcome::Skipped;
}
};
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
self.painters.render(
&self.device,
&self.queue,
self.config.format,
&view,
self.config.width,
self.config.height,
scene,
Some(CLEAR_COLOR),
);
self.queue.present(frame);
RenderOutcome::Presented
}
}
pub enum RenderOutcome {
Presented,
Skipped,
NeedsReconfigure,
}