use glam::{uvec2, UVec2}; pub struct Viewport<'a> { surface: wgpu::Surface<'a>, config: wgpu::SurfaceConfiguration, sample_count: u32, multisample: Multisample, } impl<'a> Viewport<'a> { pub fn new(adapter: &wgpu::Adapter, device: &wgpu::Device, surface: wgpu::Surface<'a>, size: UVec2) -> Self { let caps = surface.get_capabilities(adapter); let format = wgpu::TextureFormat::Bgra8UnormSrgb; let sample_count = adapter .get_texture_format_features(format) .flags .supported_sample_counts() .into_iter() .max() .unwrap(); eprintln!("Using x{sample_count} mutlisampling"); let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format, width: size.x, height: size.y, present_mode: wgpu::PresentMode::Fifo, alpha_mode: caps.alpha_modes[0], view_formats: vec![], desired_maximum_frame_latency: 2, }; let multisample = Multisample::new(device, format, size, sample_count); Self { surface, config, sample_count, multisample, } } pub fn configure(&mut self, device: &wgpu::Device) { self.surface.configure(&device, &self.config); self.multisample = Multisample::new(device, self.format(), self.size(), self.sample_count); } pub fn resize(&mut self, device: &wgpu::Device, size: UVec2) { self.config.width = size.x; self.config.height = size.y; self.configure(&device); } pub fn size(&self) -> UVec2 { uvec2(self.config.width, self.config.height) } pub fn format(&self) -> wgpu::TextureFormat { self.config.format } pub fn sample_count(&self) -> u32 { self.sample_count } pub fn render_single_pass( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, f: impl FnOnce(wgpu::RenderPass), ) -> Result<(), wgpu::SurfaceError> { let output = self.surface.get_current_texture()?; let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render CommandEncoder"), }); let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("RenderPass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &self.multisample.view, resolve_target: Some(&view), ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color { r: 0., g: 0., b: 0., a: 1., }), store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, occlusion_query_set: None, timestamp_writes: None, }); f(render_pass); queue.submit(std::iter::once(encoder.finish())); output.present(); Ok(()) } } struct Multisample { view: wgpu::TextureView, } impl Multisample { fn new(device: &wgpu::Device, format: wgpu::TextureFormat, size: UVec2, sample_count: u32) -> Multisample { let tex = device.create_texture(&wgpu::TextureDescriptor { label: Some("Multisample texture"), size: wgpu::Extent3d { width: size.x, height: size.y, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count, dimension: wgpu::TextureDimension::D2, format, usage: wgpu::TextureUsages::RENDER_ATTACHMENT, view_formats: &[], }); let view = tex.create_view(&wgpu::TextureViewDescriptor::default()); Multisample { view } } }