use std::sync::Arc;
use winit::window::Window;
use crate::device::GpuDevice;
use crate::device::choose_surface_format;
use crate::error::WgpuBackendError;
pub struct DepthTexture {
pub texture: wgpu::Texture,
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
}
impl DepthTexture {
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self {
let texture = device.create_texture(&wgpu::TextureDescriptor {
size: wgpu::Extent3d {
width: config.width.max(1),
height: config.height.max(1),
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
label: Some("cotis-wgpu depth texture"),
view_formats: &[],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
compare: Some(wgpu::CompareFunction::LessEqual),
lod_min_clamp: 0.0,
lod_max_clamp: 100.0,
..Default::default()
});
Self {
texture,
view,
sampler,
}
}
}
pub struct SurfaceState {
surface: wgpu::Surface<'static>,
pub config: wgpu::SurfaceConfiguration,
pub depth: DepthTexture,
}
impl SurfaceState {
pub fn new(
gpu: &GpuDevice,
window: &Arc<Window>,
width: u32,
height: u32,
) -> Result<Self, WgpuBackendError> {
let surface_target = unsafe { wgpu::SurfaceTargetUnsafe::from_window(window.as_ref()) }
.map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;
let surface = unsafe { gpu.instance.create_surface_unsafe(surface_target) }
.map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;
let capabilities = surface.get_capabilities(&gpu.adapter);
let format = choose_surface_format(&capabilities.formats);
let (width, height) = non_zero_size(width, height);
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format,
width,
height,
present_mode: capabilities.present_modes[0],
desired_maximum_frame_latency: 2,
alpha_mode: capabilities.alpha_modes[0],
view_formats: vec![],
};
surface.configure(&gpu.device, &config);
let depth = DepthTexture::new(&gpu.device, &config);
Ok(Self {
surface,
config,
depth,
})
}
pub fn resize(&mut self, gpu: &GpuDevice, width: u32, height: u32) {
let (width, height) = non_zero_size(width, height);
if width == 0 || height == 0 {
return;
}
self.config.width = width;
self.config.height = height;
self.surface.configure(&gpu.device, &self.config);
self.depth = DepthTexture::new(&gpu.device, &self.config);
}
pub fn reconfigure(&mut self, gpu: &GpuDevice) {
self.surface.configure(&gpu.device, &self.config);
self.depth = DepthTexture::new(&gpu.device, &self.config);
}
pub fn acquire_frame(
&mut self,
gpu: &GpuDevice,
) -> Result<wgpu::SurfaceTexture, WgpuBackendError> {
match self.surface.get_current_texture() {
Ok(frame) => Ok(frame),
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
self.reconfigure(gpu);
self.surface
.get_current_texture()
.map_err(WgpuBackendError::Surface)
}
Err(error) => Err(WgpuBackendError::Surface(error)),
}
}
pub fn format(&self) -> wgpu::TextureFormat {
self.config.format
}
}
fn non_zero_size(width: u32, height: u32) -> (u32, u32) {
(width.max(1), height.max(1))
}