use crate::display_backend::{DisplayBackend, DisplayError};
use crate::framebuffer::DmaReadyFramebuffer;
pub struct SwapChain<const W: usize, const H: usize, B: DisplayBackend<W, H>> {
front: DmaReadyFramebuffer<W, H>,
back: DmaReadyFramebuffer<W, H>,
backend: B,
frame_count: u64,
}
impl<const W: usize, const H: usize, B: DisplayBackend<W, H>> SwapChain<W, H, B> {
pub fn new(
front_ptr: *mut core::ffi::c_void,
back_ptr: *mut core::ffi::c_void,
big_endian: bool,
backend: B,
) -> Self {
Self {
front: DmaReadyFramebuffer::new(front_ptr, big_endian),
back: DmaReadyFramebuffer::new(back_ptr, big_endian),
backend,
frame_count: 0,
}
}
pub fn get_back_buffer(&mut self) -> &mut DmaReadyFramebuffer<W, H> {
&mut self.back
}
pub fn get_front_buffer(&self) -> &DmaReadyFramebuffer<W, H> {
&self.front
}
pub fn present(&mut self) -> Result<(), DisplayError> {
self.backend.wait_for_dma();
core::mem::swap(&mut self.front, &mut self.back);
self.backend.start_dma_transfer(&self.front)?;
self.frame_count += 1;
Ok(())
}
pub fn try_present(&mut self) -> Result<(), DisplayError> {
if !self.backend.is_dma_ready() {
return Err(DisplayError::Busy);
}
core::mem::swap(&mut self.front, &mut self.back);
self.backend.start_dma_transfer(&self.front)?;
self.frame_count += 1;
Ok(())
}
pub fn wait_for_vsync(&mut self) {
self.backend.wait_for_dma();
}
pub fn is_ready(&self) -> bool {
self.backend.is_dma_ready()
}
pub fn frame_count(&self) -> u64 {
self.frame_count
}
pub fn reset_frame_count(&mut self) {
self.frame_count = 0;
}
pub fn dimensions(&self) -> (usize, usize) {
(W, H)
}
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
use crate::display_backend::SimulatorBackend;
#[test]
fn test_swapchain_creation() {
let mut fb0_data = [0u16; 320 * 240];
let mut fb1_data = [0u16; 320 * 240];
let swap_chain = SwapChain::<320, 240, _>::new(
fb0_data.as_mut_ptr() as *mut core::ffi::c_void,
fb1_data.as_mut_ptr() as *mut core::ffi::c_void,
false,
SimulatorBackend::new(),
);
assert_eq!(swap_chain.dimensions(), (320, 240));
assert_eq!(swap_chain.frame_count(), 0);
assert!(swap_chain.is_ready());
}
#[test]
fn test_swapchain_present() {
let mut fb0_data = [0u16; 320 * 240];
let mut fb1_data = [0u16; 320 * 240];
let mut swap_chain = SwapChain::<320, 240, _>::new(
fb0_data.as_mut_ptr() as *mut core::ffi::c_void,
fb1_data.as_mut_ptr() as *mut core::ffi::c_void,
false,
SimulatorBackend::new(),
);
swap_chain.get_back_buffer().as_mut_slice().fill(0x1234);
assert!(swap_chain.present().is_ok());
assert_eq!(swap_chain.frame_count(), 1);
let back = swap_chain.get_back_buffer();
assert_eq!(back.as_slice()[0], 0);
assert_eq!(swap_chain.get_front_buffer().as_slice()[0], 0x1234);
}
#[test]
fn test_swapchain_multiple_presents() {
let mut fb0_data = [0u16; 320 * 240];
let mut fb1_data = [0u16; 320 * 240];
let mut swap_chain = SwapChain::<320, 240, _>::new(
fb0_data.as_mut_ptr() as *mut core::ffi::c_void,
fb1_data.as_mut_ptr() as *mut core::ffi::c_void,
false,
SimulatorBackend::new(),
);
for i in 0..5 {
swap_chain.get_back_buffer().as_mut_slice().fill(i as u16);
assert!(swap_chain.present().is_ok());
}
assert_eq!(swap_chain.frame_count(), 5);
}
#[test]
fn test_swapchain_try_present() {
let mut fb0_data = [0u16; 320 * 240];
let mut fb1_data = [0u16; 320 * 240];
let mut swap_chain = SwapChain::<320, 240, _>::new(
fb0_data.as_mut_ptr() as *mut core::ffi::c_void,
fb1_data.as_mut_ptr() as *mut core::ffi::c_void,
false,
SimulatorBackend::new(),
);
assert!(swap_chain.try_present().is_ok());
assert_eq!(swap_chain.frame_count(), 1);
}
#[test]
fn test_swapchain_frame_counter() {
let mut fb0_data = [0u16; 320 * 240];
let mut fb1_data = [0u16; 320 * 240];
let mut swap_chain = SwapChain::<320, 240, _>::new(
fb0_data.as_mut_ptr() as *mut core::ffi::c_void,
fb1_data.as_mut_ptr() as *mut core::ffi::c_void,
false,
SimulatorBackend::new(),
);
assert_eq!(swap_chain.frame_count(), 0);
swap_chain.present().unwrap();
assert_eq!(swap_chain.frame_count(), 1);
swap_chain.present().unwrap();
assert_eq!(swap_chain.frame_count(), 2);
swap_chain.reset_frame_count();
assert_eq!(swap_chain.frame_count(), 0);
}
}