cyborg/src/viewport.rs

167 lines
5.1 KiB
Rust

use std::sync::Arc;
#[derive(Clone)]
pub struct ViewportInfo {
pub output_format: wgpu::TextureFormat,
pub depth_format: wgpu::TextureFormat,
}
pub struct ViewportViews<'a> {
pub output: &'a wgpu::TextureView,
pub depth: &'a wgpu::TextureView,
}
pub trait Viewport {
fn get_info(&self) -> ViewportInfo;
fn get_queue(&self) -> &wgpu::Queue;
fn get_views(&self) -> ViewportViews;
}
pub struct WinitViewport {
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub size: winit::dpi::PhysicalSize<u32>,
surface: wgpu::Surface,
config: wgpu::SurfaceConfiguration,
info: ViewportInfo,
depth_texture: wgpu::Texture,
depth_texture_view: wgpu::TextureView,
surface_texture: Option<wgpu::SurfaceTexture>,
output_view: Option<wgpu::TextureView>,
}
impl WinitViewport {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
pub async fn from_window(window: &winit::window::Window) -> Self {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
let surface = unsafe { instance.create_surface(window) };
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::LowPower,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
})
.await
.unwrap();
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
label: None,
},
None,
)
.await
.unwrap();
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: *surface.get_supported_formats(&adapter).first().unwrap(),
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
};
surface.configure(&device, &config);
let device = Arc::new(device);
let queue = Arc::new(queue);
let info = ViewportInfo {
output_format: config.format,
depth_format: Self::DEPTH_FORMAT,
};
let (depth_texture, depth_texture_view) = Self::make_depth_texture(&device, &config);
Self {
device,
queue,
size,
surface,
config,
info,
depth_texture,
depth_texture_view,
surface_texture: None,
output_view: None,
}
}
pub fn acquire(&mut self) -> Result<(), wgpu::SurfaceError> {
if self.output_view.is_none() {
let surface_texture = self.surface.get_current_texture()?;
self.output_view = Some(
surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default()),
);
self.surface_texture = Some(surface_texture);
}
Ok(())
}
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.config.width = new_size.width;
self.config.height = new_size.height;
self.surface.configure(&self.device, &self.config);
let (depth_texture, depth_texture_view) =
Self::make_depth_texture(&self.device, &self.config);
self.depth_texture = depth_texture;
self.depth_texture_view = depth_texture_view;
}
}
pub fn present(&mut self) {
if let Some(surface_texture) = self.surface_texture.take() {
surface_texture.present();
self.output_view.take();
}
}
fn make_depth_texture(
device: &wgpu::Device,
config: &wgpu::SurfaceConfiguration,
) -> (wgpu::Texture, wgpu::TextureView) {
let size = wgpu::Extent3d {
width: config.width,
height: config.height,
depth_or_array_layers: 1,
};
let desc = wgpu::TextureDescriptor {
label: Some("Depth Texture"),
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: Self::DEPTH_FORMAT,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
};
let texture = device.create_texture(&desc);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
(texture, view)
}
}
impl Viewport for WinitViewport {
fn get_info(&self) -> ViewportInfo {
self.info.clone()
}
fn get_queue(&self) -> &wgpu::Queue {
&self.queue
}
fn get_views(&self) -> ViewportViews {
let output = self.output_view.as_ref().unwrap();
ViewportViews {
output,
depth: &self.depth_texture_view,
}
}
}