use crate::draw::{CustomPipe, DrawPipe, DrawWindow};
use kas::cast::Cast;
use kas::draw::color::Rgba;
use kas::draw::{DrawIface, DrawSharedImpl, WindowCommon};
use kas::geom::Size;
use kas::runner::{raw_window_handle as rwh, Error, WindowSurface};
use std::time::Instant;
pub struct Surface<'a, C: CustomPipe> {
surface: wgpu::Surface<'a>,
sc_desc: wgpu::SurfaceConfiguration,
draw: DrawWindow<C::Window>,
}
impl<'a, C: CustomPipe> Surface<'a, C> {
pub fn new<W>(
shared: &mut <Self as WindowSurface>::Shared,
window: W,
transparent: bool,
) -> Result<Self, Error>
where
W: rwh::HasWindowHandle + rwh::HasDisplayHandle + Send + Sync + 'a,
Self: Sized,
{
let surface = shared
.instance
.create_surface(window)
.map_err(|e| Error::Graphics(Box::new(e)))?;
use wgpu::CompositeAlphaMode::{Inherit, Opaque, PostMultiplied, PreMultiplied};
let caps = surface.get_capabilities(&shared.adapter);
let alpha_mode = match transparent {
true if caps.alpha_modes.contains(&PreMultiplied) => PreMultiplied,
true if caps.alpha_modes.contains(&PostMultiplied) => PostMultiplied,
_ if caps.alpha_modes.contains(&Opaque) => Opaque,
_ => Inherit, };
log::debug!("Surface::new: using alpha_mode={alpha_mode:?}");
let sc_desc = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: crate::draw::RENDER_TEX_FORMAT,
width: 0,
height: 0,
present_mode: wgpu::PresentMode::Fifo,
desired_maximum_frame_latency: 2,
alpha_mode,
view_formats: vec![],
};
Ok(Surface {
surface,
sc_desc,
draw: shared.new_window(),
})
}
}
impl<'a, C: CustomPipe> WindowSurface for Surface<'a, C> {
type Shared = DrawPipe<C>;
fn size(&self) -> Size {
Size::new(self.sc_desc.width.cast(), self.sc_desc.height.cast())
}
fn do_resize(&mut self, shared: &mut Self::Shared, size: Size) -> bool {
if size == self.size() {
return false;
}
let size = size.min(Size::splat(shared.max_texture_dimension_2d().cast()));
let time = Instant::now();
shared.resize(&mut self.draw, size);
self.sc_desc.width = size.0.cast();
self.sc_desc.height = size.1.cast();
self.surface.configure(&shared.device, &self.sc_desc);
log::trace!(
target: "kas_perf::wgpu::window",
"do_resize: {}µs",
time.elapsed().as_micros()
);
true
}
fn draw_iface<'iface>(
&'iface mut self,
shared: &'iface mut kas::draw::SharedState<Self::Shared>,
) -> DrawIface<'iface, Self::Shared> {
DrawIface::new(&mut self.draw, shared)
}
fn common_mut(&mut self) -> &mut WindowCommon {
&mut self.draw.common
}
fn present(&mut self, shared: &mut Self::Shared, clear_color: Rgba) -> Instant {
let frame = match self.surface.get_current_texture() {
Ok(frame) => frame,
Err(e) => {
log::error!("WindowSurface::present: failed to get frame texture: {}", e);
return Instant::now();
}
};
#[cfg(debug_assertions)]
if frame.suboptimal {
log::warn!("WindowSurface::present: sub-optimal frame should be re-created");
}
let view = frame.texture.create_view(&Default::default());
let clear_color = to_wgpu_color(clear_color);
shared.render(&mut self.draw, &view, clear_color);
let pre_present = Instant::now();
frame.present();
pre_present
}
}
fn to_wgpu_color(c: Rgba) -> wgpu::Color {
wgpu::Color {
r: c.r as f64,
g: c.g as f64,
b: c.b as f64,
a: c.a as f64,
}
}