use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
use wgpu::{
Adapter, Device, Instance, PresentMode, SurfaceConfiguration, SurfaceError, SurfaceTexture,
TextureFormat, TextureUsages,
};
use winit::window::Window;
pub struct ISurface {
instance: Arc<Instance>,
surface: wgpu::Surface,
window: Arc<Window>,
}
pub struct Surface {
device: Arc<Device>,
surface: ISurface,
format: TextureFormat,
present_mode: PresentMode,
width: u32,
height: u32,
}
impl ISurface {
pub fn new(window: Arc<Window>, instance: Arc<Instance>) -> Self {
let surface = unsafe { instance.create_surface(window.as_ref()) };
Self {
instance,
surface,
window,
}
}
pub fn complete(self, adapter: &Adapter, device: Arc<Device>) -> Surface {
let surface = self;
let format = surface
.surface
.get_preferred_format(adapter)
.expect("Surface is not incompatible");
let mut surface = Surface {
device,
surface,
format,
present_mode: PresentMode::Mailbox,
width: 0, height: 0,
};
surface.configure();
surface
}
pub fn get_window(&self) -> Arc<Window> {
self.window.clone()
}
}
impl Surface {
pub fn set_vsync(&mut self, on: bool) {
let new = if on {
PresentMode::Mailbox } else {
PresentMode::Immediate
};
let updated = self.present_mode != new;
self.present_mode = new;
if updated {
self.configure();
}
}
pub fn get_vsync(&self) -> bool {
match self.present_mode {
PresentMode::Immediate => false,
PresentMode::Mailbox => true,
PresentMode::Fifo => true,
}
}
pub fn configure(&mut self) {
let window = self.surface.window.as_ref();
let size = window.inner_size();
let (width, height) = (size.width, size.height);
let format = self.format;
self.width = width;
self.height = height;
self.surface.surface.configure(
&self.device,
&SurfaceConfiguration {
usage: TextureUsages::RENDER_ATTACHMENT,
format,
width,
height,
present_mode: self.present_mode,
},
);
}
pub fn recreate(&mut self) {
let window = self.surface.window.clone();
let instance = self.surface.instance.clone();
self.surface = ISurface::new(window, instance);
}
pub fn acquire(&mut self) -> SurfaceTexture {
loop {
match self.surface.get_current_texture() {
Ok(
texture @ SurfaceTexture {
suboptimal: false, ..
},
) => return texture,
Err(SurfaceError::OutOfMemory) => panic!("Out of memory"),
Err(SurfaceError::Timeout) => {
log::debug!("Timeout");
}
Err(SurfaceError::Lost) => {
log::debug!("Lost");
self.recreate();
}
x @ (Ok(SurfaceTexture {
suboptimal: true, ..
})
| Err(SurfaceError::Outdated)) => {
log::debug!("Outdated | Suboptimal");
drop(x);
self.configure();
}
}
}
}
pub fn format(&self) -> TextureFormat {
self.format
}
pub fn get_window(&self) -> Arc<Window> {
self.surface.get_window()
}
pub fn get_dim(&self) -> (u32, u32) {
(self.width, self.height)
}
}
impl Deref for ISurface {
type Target = wgpu::Surface;
fn deref(&self) -> &Self::Target {
&self.surface
}
}
impl DerefMut for ISurface {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.surface
}
}
impl Deref for Surface {
type Target = wgpu::Surface;
fn deref(&self) -> &Self::Target {
&self.surface
}
}
impl DerefMut for Surface {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.surface
}
}