use std::sync::{Arc, atomic::{AtomicBool, Ordering}}; use std::ops::Deref; use crate::backend::allocator::{Allocator, Buffer, Format}; pub const SLOT_CAP: usize = 3; pub struct Swapchain, B: Buffer> { allocator: A, width: u32, height: u32, format: Format, slots: [Slot; SLOT_CAP], } pub struct Slot { buffer: Arc>, acquired: Arc, } impl Default for Slot { fn default() -> Self { Slot { buffer: Arc::new(None), acquired: Arc::new(AtomicBool::new(false)), } } } impl Clone for Slot { fn clone(&self) -> Self { Slot { buffer: self.buffer.clone(), acquired: self.acquired.clone(), } } } impl Deref for Slot { type Target = B; fn deref(&self) -> &B { Option::as_ref(&*self.buffer).unwrap() } } impl Drop for Slot { fn drop(&mut self) { self.acquired.store(false, Ordering::AcqRel); } } impl, B: Buffer> Swapchain { pub fn new(allocator: A, width: u32, height: u32, format: Format) -> Swapchain { Swapchain { allocator, width, height, format, slots: Default::default(), } } pub fn acquire(&mut self) -> Result>, A::Error> { if let Some(free_slot) = self.slots.iter_mut().filter(|s| !s.acquired.load(Ordering::SeqCst)).next() { if free_slot.buffer.is_none() { free_slot.buffer = Arc::new(Some(self.allocator.create_buffer(self.width, self.height, self.format)?)); } assert!(!free_slot.buffer.is_some()); if !free_slot.acquired.swap(true, Ordering::AcqRel) { return Ok(Some(free_slot.clone())); } } // no free slots 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; for mut slot in &mut self.slots { let _ = std::mem::replace(&mut slot, &mut Slot::default()); } } }