pub struct Frame<'a> { pub gpu: &'a mut Gpu, pub encoder: wgpu::CommandEncoder, pub output: wgpu::SurfaceTexture, pub view: wgpu::TextureView, } impl<'a> Frame<'a> { pub fn new(gpu: &'a mut Gpu) -> Result { let output = gpu.surface.get_current_texture()?; let view = output .texture .create_view(&wgpu::TextureViewDescriptor::default()); let encoder = gpu .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); Ok(Self { gpu, encoder, output, view, }) } pub fn pass(&mut self) -> wgpu::RenderPass { self.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &self.view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color { r: 0x87 as f64 / 255.0, g: 0xCE as f64 / 255.0, b: 0xEB as f64 / 255.0, a: 1.0, }), store: true, }, })], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { view: &self.gpu.depth_texture, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: true, }), stencil_ops: None, }), }) } pub fn finish(self) { self.gpu.queue.submit(Some(self.encoder.finish())); self.output.present(); } } pub struct Gpu { pub surface: wgpu::Surface, pub device: wgpu::Device, pub queue: wgpu::Queue, pub config: wgpu::SurfaceConfiguration, pub depth_texture: wgpu::TextureView, } impl Gpu { pub async fn new(window: &winit::window::Window) -> Self { let size = window.inner_size(); let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: wgpu::Backends::all(), dx12_shader_compiler: Default::default(), }); let surface = unsafe { instance.create_surface(window) }.unwrap(); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), compatible_surface: Some(&surface), force_fallback_adapter: false, }) .await .unwrap(); let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: Default::default(), label: None, }, None, ) .await .unwrap(); let surface_caps = surface.get_capabilities(&adapter); let surface_format = surface_caps .formats .iter() .copied() .find(|f| f.describe().srgb) .unwrap_or(surface_caps.formats[0]); let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: surface_format, width: size.width, height: size.height, present_mode: surface_caps.present_modes[0], alpha_mode: surface_caps.alpha_modes[0], view_formats: vec![], }; let depth_texture = Self::create_depth_texture(&config, &device); let mut state = Self { surface, device, queue, config, depth_texture, }; state.resize(size); state } pub fn create_depth_texture( config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, ) -> wgpu::TextureView { device .create_texture(&wgpu::TextureDescriptor { label: Some("depth texture"), size: wgpu::Extent3d { width: config.width, height: config.height, 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, view_formats: &[], }) .create_view(&wgpu::TextureViewDescriptor::default()) } pub fn resize(&mut self, size: winit::dpi::PhysicalSize) { if size.width > 0 && size.height > 0 { self.config.width = size.width; self.config.height = size.height; self.configure_surface(); self.depth_texture = Self::create_depth_texture(&self.config, &self.device); } } pub fn configure_surface(&mut self) { self.surface.configure(&self.device, &self.config); } }