use std::ops::Deref;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, MutexGuard,
};
use crate::backend::allocator::{Allocator, Buffer, Fourcc, Modifier};
pub const SLOT_CAP: usize = 4;
#[derive(Debug)]
pub struct Swapchain<A: Allocator<B>, B: Buffer, U: 'static> {
pub allocator: A,
width: u32,
height: u32,
fourcc: Fourcc,
modifiers: Vec<Modifier>,
slots: [Arc<InternalSlot<B, U>>; SLOT_CAP],
}
#[derive(Debug)]
pub struct Slot<B: Buffer, U: 'static>(Arc<InternalSlot<B, U>>);
#[derive(Debug)]
struct InternalSlot<B: Buffer, U: 'static> {
buffer: Option<B>,
acquired: AtomicBool,
userdata: Mutex<Option<U>>,
}
impl<B: Buffer, U: 'static> Slot<B, U> {
pub fn userdata(&self) -> MutexGuard<'_, Option<U>> {
self.0.userdata.lock().unwrap()
}
}
impl<B: Buffer, U: 'static> Default for InternalSlot<B, U> {
fn default() -> Self {
InternalSlot {
buffer: None,
acquired: AtomicBool::new(false),
userdata: Mutex::new(None),
}
}
}
impl<B: Buffer, U: 'static> Deref for Slot<B, U> {
type Target = B;
fn deref(&self) -> &B {
Option::as_ref(&self.0.buffer).unwrap()
}
}
impl<B: Buffer, U: 'static> Drop for Slot<B, U> {
fn drop(&mut self) {
self.0.acquired.store(false, Ordering::SeqCst);
}
}
impl<A, B, U> Swapchain<A, B, U>
where
A: Allocator<B>,
B: Buffer,
U: 'static,
{
pub fn new(
allocator: A,
width: u32,
height: u32,
fourcc: Fourcc,
modifiers: Vec<Modifier>,
) -> Swapchain<A, B, U> {
Swapchain {
allocator,
width,
height,
fourcc,
modifiers,
slots: Default::default(),
}
}
pub fn acquire(&mut self) -> Result<Option<Slot<B, U>>, A::Error> {
if let Some(free_slot) = self
.slots
.iter_mut()
.find(|s| !s.acquired.swap(true, Ordering::SeqCst))
{
if free_slot.buffer.is_none() {
let mut free_slot =
Arc::get_mut(free_slot).expect("Acquired was false, but Arc is not unique?");
free_slot.buffer = Some(self.allocator.create_buffer(
self.width,
self.height,
self.fourcc,
&self.modifiers,
)?);
}
assert!(free_slot.buffer.is_some());
return Ok(Some(Slot(free_slot.clone())));
}
Ok(None)
}
pub fn resize(&mut self, width: u32, height: u32) {
if self.width == width && self.height == height {
return;
}
self.width = width;
self.height = height;
self.slots = Default::default();
}
}