1use std::sync::Arc;
10
11use winit::window::Window;
12
13use crate::device::GpuDevice;
14use crate::device::choose_surface_format;
15use crate::error::WgpuBackendError;
16
17pub struct DepthTexture {
19 pub texture: wgpu::Texture,
21 pub view: wgpu::TextureView,
23 pub sampler: wgpu::Sampler,
25}
26
27impl DepthTexture {
28 pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self {
30 let texture = device.create_texture(&wgpu::TextureDescriptor {
31 size: wgpu::Extent3d {
32 width: config.width.max(1),
33 height: config.height.max(1),
34 depth_or_array_layers: 1,
35 },
36 mip_level_count: 1,
37 sample_count: 1,
38 dimension: wgpu::TextureDimension::D2,
39 format: wgpu::TextureFormat::Depth32Float,
40 usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
41 label: Some("cotis-wgpu depth texture"),
42 view_formats: &[],
43 });
44
45 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
46
47 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
48 address_mode_u: wgpu::AddressMode::ClampToEdge,
49 address_mode_v: wgpu::AddressMode::ClampToEdge,
50 address_mode_w: wgpu::AddressMode::ClampToEdge,
51 mag_filter: wgpu::FilterMode::Linear,
52 min_filter: wgpu::FilterMode::Linear,
53 mipmap_filter: wgpu::FilterMode::Nearest,
54 compare: Some(wgpu::CompareFunction::LessEqual),
55 lod_min_clamp: 0.0,
56 lod_max_clamp: 100.0,
57 ..Default::default()
58 });
59
60 Self {
61 texture,
62 view,
63 sampler,
64 }
65 }
66}
67
68pub struct SurfaceState {
70 surface: wgpu::Surface<'static>,
71 pub config: wgpu::SurfaceConfiguration,
73 pub depth: DepthTexture,
75}
76
77impl SurfaceState {
78 pub fn new(
84 gpu: &GpuDevice,
85 window: &Arc<Window>,
86 width: u32,
87 height: u32,
88 ) -> Result<Self, WgpuBackendError> {
89 let surface_target = unsafe { wgpu::SurfaceTargetUnsafe::from_window(window.as_ref()) }
90 .map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;
91 let surface = unsafe { gpu.instance.create_surface_unsafe(surface_target) }
92 .map_err(|error| WgpuBackendError::CreateSurface(error.to_string()))?;
93
94 let capabilities = surface.get_capabilities(&gpu.adapter);
95 let format = choose_surface_format(&capabilities.formats);
96 let (width, height) = non_zero_size(width, height);
97
98 let config = wgpu::SurfaceConfiguration {
99 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
100 format,
101 width,
102 height,
103 present_mode: capabilities.present_modes[0],
104 desired_maximum_frame_latency: 2,
105 alpha_mode: capabilities.alpha_modes[0],
106 view_formats: vec![],
107 };
108
109 surface.configure(&gpu.device, &config);
110 let depth = DepthTexture::new(&gpu.device, &config);
111
112 Ok(Self {
113 surface,
114 config,
115 depth,
116 })
117 }
118
119 pub fn resize(&mut self, gpu: &GpuDevice, width: u32, height: u32) {
123 let (width, height) = non_zero_size(width, height);
124 if width == 0 || height == 0 {
125 return;
126 }
127
128 self.config.width = width;
129 self.config.height = height;
130 self.surface.configure(&gpu.device, &self.config);
131 self.depth = DepthTexture::new(&gpu.device, &self.config);
132 }
133
134 pub fn reconfigure(&mut self, gpu: &GpuDevice) {
138 self.surface.configure(&gpu.device, &self.config);
139 self.depth = DepthTexture::new(&gpu.device, &self.config);
140 }
141
142 pub fn acquire_frame(
148 &mut self,
149 gpu: &GpuDevice,
150 ) -> Result<wgpu::SurfaceTexture, WgpuBackendError> {
151 match self.surface.get_current_texture() {
152 Ok(frame) => Ok(frame),
153 Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
154 self.reconfigure(gpu);
155 self.surface
156 .get_current_texture()
157 .map_err(WgpuBackendError::Surface)
158 }
159 Err(error) => Err(WgpuBackendError::Surface(error)),
160 }
161 }
162
163 pub fn format(&self) -> wgpu::TextureFormat {
165 self.config.format
166 }
167}
168
169fn non_zero_size(width: u32, height: u32) -> (u32, u32) {
170 (width.max(1), height.max(1))
171}