use alloc::rc::Rc;
use core::cell::Cell;
use crate::web_dev::{call, Device, Handle, CALL_CONTEXT, CALL_CURRENT, CALL_RESERVE, CALL_RESIZE, CALL_RGBA};
use crate::*;
pub(crate) struct SurfInner {
canvas: Handle,
window: i32,
}
#[derive(Clone)]
pub struct Surface(pub(crate) Rc<SurfInner>);
impl Surface {
pub fn track_size(&self) {}
pub fn new(instance: &Instance, window: i32) -> Result<Surface> {
let nw = plat::win_gpu_child(window).ok_or(GpuError::NotReady)?;
Surface::native(instance, nw, window)
}
pub fn native(_instance: &Instance, nw: plat::NativeWindow, window: i32) -> Result<Surface> {
Ok(Surface(Rc::new(SurfInner { canvas: Handle { h: nw.take(), destroy: false }, window })))
}
}
pub struct Frame {
size: (u32, u32),
}
#[must_use]
pub enum TryAcquire {
Frame(Frame),
NotReady,
Stale,
NoArea,
}
impl Frame {
pub fn index(&self) -> u32 {
0
}
pub fn size(&self) -> (u32, u32) {
self.size
}
}
pub struct Swapchain {
dev: Device,
surf: Surface,
ctx: Handle,
size: Cell<(u32, u32)>,
format: Format,
texture: Texture,
view: TextureView,
stale: Cell<bool>,
}
impl Device {
pub fn create_swapchain(&self, surface: &Surface, desc: &SwapchainDesc) -> Result<Swapchain> {
self.d.check()?;
let (w, h) = plat::win_size(surface.0.window);
let (w, h) = (w.max(0) as u32, h.max(0) as u32);
if w == 0 || h == 0 {
return Err(GpuError::NotReady);
}
let ctx = call(CALL_CONTEXT, &[self.d.h, surface.0.canvas.h, w, h, desc.copy_src as u32, desc.srgb as u32]);
if ctx == 0 {
return Err(GpuError::SurfaceLost);
}
let rgba = call(CALL_RGBA, &[]) != 0;
let format = match (rgba, desc.srgb) {
(false, false) => Format::Bgra8Unorm,
(false, true) => Format::Bgra8Srgb,
(true, false) => Format::Rgba8Unorm,
(true, true) => Format::Rgba8Srgb,
};
let usage = TextureUsage::COLOR_TARGET | if desc.copy_src { TextureUsage::COPY_SRC } else { TextureUsage::NONE };
let view = TextureView::for_frame(call(CALL_RESERVE, &[]), format, w, h);
let texture = Texture::for_frame(call(CALL_RESERVE, &[]), view.clone(), format, w, h, usage);
Ok(Swapchain { dev: self.clone(), surf: surface.clone(), ctx: Handle { h: ctx, destroy: false }, size: Cell::new((w, h)), format, texture, view, stale: Cell::new(false) })
}
}
impl Swapchain {
pub fn rebuild(&mut self) -> Result<()> {
let (w, h) = plat::win_size(self.surf.0.window);
let (w, h) = (w.max(0) as u32, h.max(0) as u32);
if w != 0 && h != 0 {
call(CALL_RESIZE, &[self.ctx.h, w, h]);
let usage = self.texture.usage();
let view = TextureView::for_frame(call(CALL_RESERVE, &[]), self.format, w, h);
self.texture = Texture::for_frame(call(CALL_RESERVE, &[]), view.clone(), self.format, w, h, usage);
self.view = view;
}
self.size.set((w, h));
self.stale.set(false);
Ok(())
}
pub fn try_acquire(&mut self) -> Result<TryAcquire> {
self.dev.d.check()?;
let (w, h) = plat::win_size(self.surf.0.window);
if w <= 0 || h <= 0 {
return Ok(TryAcquire::NoArea);
}
if self.stale.get() || self.size.get() != (w as u32, h as u32) {
return Ok(TryAcquire::Stale);
}
match call(CALL_CURRENT, &[self.ctx.h, self.texture.handle(), self.view.handle()]) {
0 => Err(GpuError::SurfaceLost),
_ => Ok(TryAcquire::Frame(Frame { size: self.size.get() })),
}
}
pub fn acquire(&mut self) -> Result<Option<Frame>> {
match self.try_acquire()? {
TryAcquire::Frame(f) => Ok(Some(f)),
TryAcquire::Stale => {
self.rebuild()?;
match self.try_acquire()? {
TryAcquire::Frame(f) => Ok(Some(f)),
_ => Ok(None),
}
}
_ => Ok(None),
}
}
pub fn view(&self, _frame: &Frame) -> &TextureView {
&self.view
}
pub fn texture(&self, _frame: &Frame) -> &Texture {
&self.texture
}
pub fn present<'a, I: IntoIterator<Item = CommandBuffer<'a>>>(&self, _frame: Frame, cmds: I) -> Result<SubmitId> {
self.dev.queue().submit(cmds)
}
pub fn prepare(&mut self) -> Result<bool> {
Ok(true)
}
pub fn flush(&self) -> Result<bool> {
Ok(true)
}
pub fn busy(&self) -> bool {
false
}
pub fn next_look(&self, retry: u64) -> u64 {
retry
}
pub fn damage(&self, _rects: Option<&[[i32; 4]]>) {}
pub fn resize(&mut self) {
self.stale.set(true);
}
pub fn set_present_mode(&mut self, _m: PresentMode) {}
pub fn present_mode(&self) -> PresentMode {
PresentMode::Mailbox
}
pub fn format(&self) -> Format {
self.format
}
pub fn size(&self) -> (u32, u32) {
self.size.get()
}
pub fn image_count(&self) -> usize {
1
}
}