cyborg/src/viewport.rs

183 lines
5.3 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;
}
pub trait ViewportImage<'a> {
type Viewport: Viewport;
fn get_viewport(&self) -> &Self::Viewport;
fn get_views(&self) -> ViewportViews;
}
pub struct WinitViewport {
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub size: winit::dpi::PhysicalSize<u32>,
pub surface: wgpu::Surface,
pub config: wgpu::SurfaceConfiguration,
pub info: ViewportInfo,
pub depth_texture: wgpu::Texture,
pub depth_texture_view: 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::all());
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_preferred_format(&adapter).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,
}
}
pub fn acquire(&mut self) -> Result<WinitImage, wgpu::SurfaceError> {
let surface_texture = self.surface.get_current_texture()?;
let output_view = surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let depth_view = &self.depth_texture_view;
Ok(WinitImage {
viewport: self,
surface_texture,
output_view,
depth_view,
})
}
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;
}
}
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
}
}
pub struct WinitImage<'a> {
viewport: &'a WinitViewport,
surface_texture: wgpu::SurfaceTexture,
output_view: wgpu::TextureView,
depth_view: &'a wgpu::TextureView,
}
impl<'a> WinitImage<'a> {
pub fn present(self) {
self.surface_texture.present();
}
}
impl<'a> ViewportImage<'a> for WinitImage<'a> {
type Viewport = WinitViewport;
fn get_viewport(&self) -> &WinitViewport {
self.viewport
}
fn get_views(&self) -> ViewportViews {
ViewportViews {
output: &self.output_view,
depth: self.depth_view,
}
}
}