refraction/src/bin/wireframe/viewport.rs

125 lines
3.2 KiB
Rust

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 }
}
}