use crate::geometry::*; use crate::lib8::interpolate::Fract8Ops; use crate::power::AsMilliwatts; use crate::render::{PixelView, Sample, Shader, Surface, Surfaces, HardwarePixel}; use crate::task::Task; use std::fmt::Debug; use std::io; use std::ops::IndexMut; use std::sync::atomic::AtomicBool; use std::sync::RwLock; use std::sync::{Arc, Mutex}; #[derive(Debug)] struct ShaderBinding { shader: Option>, rect: Rectangle, opacity: u8 } #[derive(Debug)] struct SurfaceUpdate { shader: Option>>, rect: Option>, opacity: Option, slot: usize } impl SurfaceUpdate { fn merge(&mut self, mut other: Self) { if other.shader.is_some() { self.shader = other.shader.take() } if other.rect.is_some() { self.rect = other.rect.take() } if other.opacity.is_some() { self.opacity = other.opacity.take() } } } impl Debug for Box { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Shader").finish() } } impl Default for SurfaceUpdate { fn default() -> Self { SurfaceUpdate { shader: None, rect: None, opacity: None, slot: usize::MAX } } } #[derive(Debug)] pub struct BufferedSurface { updater: Arc, slot: usize } impl Surface for BufferedSurface { fn clear_shader(&mut self) { self.updater.push(SurfaceUpdate { shader: None, slot: self.slot, ..Default::default() }); } fn set_opacity(&mut self, opacity: u8) { self.updater.push(SurfaceUpdate { opacity: Some(opacity), slot: self.slot, ..Default::default() }); } fn set_rect(&mut self, rect: &Rectangle) { self.updater.push(SurfaceUpdate { rect: Some(rect.clone()), slot: self.slot, ..Default::default() }); } fn set_shader(&mut self, shader: Box) { self.updater.push(SurfaceUpdate { shader: Some(Some(shader)), slot: self.slot, ..Default::default() }); } } #[derive(Debug)] struct UpdateQueue { pending: Mutex>, damaged: AtomicBool } impl UpdateQueue { fn new() -> Self { UpdateQueue { pending: Mutex::new(Vec::new()), damaged: AtomicBool::new(false) } } fn push(&self, update: SurfaceUpdate) { let mut locked = self.pending.lock().unwrap(); let mut existing_slot = None; for existing in locked.iter_mut() { if existing.slot == update.slot { existing_slot = Some(existing); break } } match existing_slot { Some(tgt) => { log::debug!("Updating existing shader update"); tgt.merge(update); } _ => { log::debug!("Pushing new shader update"); locked.push(update); self.damaged.store(true, std::sync::atomic::Ordering::Relaxed); } } } } #[derive(Debug)] pub struct ShaderChain { bindings: Vec, updates: Arc } impl ShaderChain { pub fn new() -> Self { ShaderChain { bindings: Vec::new(), updates: Arc::new(UpdateQueue::new()) } } pub fn is_dirty(&self) -> bool { self.updates.damaged.load(std::sync::atomic::Ordering::Relaxed) } pub fn commit(&mut self) { let mut queue: Vec = { let mut updates = self.updates.pending.lock().unwrap(); std::mem::take(updates.as_mut()) }; for update in queue.iter_mut() { let target_slot = &mut self.bindings[update.slot]; if let Some(shader) = update.shader.take() { target_slot.shader = shader; } if let Some(opacity) = update.opacity.take() { target_slot.opacity = opacity; } if let Some(rect) = update.rect.take() { target_slot.rect = rect; } } self.updates.damaged.store(false, std::sync::atomic::Ordering::Relaxed); } } impl Surfaces for ShaderChain { type Error = (); type Surface = BufferedSurface; fn new_surface(&mut self, area: &Rectangle) -> Result { let next_slot = self.bindings.len(); self.bindings.push(ShaderBinding { opacity: 255, shader: None, rect: area.clone() }); Ok(BufferedSurface { updater: Arc::clone(&self.updates), slot: next_slot }) } fn render_to(&self, output: &mut S, frame: usize) { for surface in self.bindings.iter() { let opacity = surface.opacity; if opacity > 0 { let rect = surface.rect; let mut sample = output.sample(&rect); if let Some(ref shader) = surface.shader { while let Some((virt_coords, pixel)) = sample.next() { *pixel = pixel.blend8(shader.draw(&virt_coords, frame).into(), opacity); } } } } } } #[derive(Clone)] pub struct BufferedSurfacePool { pool: Arc> } impl BufferedSurfacePool { pub fn new() -> Self { BufferedSurfacePool { pool: Arc::new(RwLock::new(ShaderChain::new())) } } } impl Surfaces for BufferedSurfacePool { type Error = (); type Surface = ::Surface; fn new_surface(&mut self, area: &crate::geometry::Rectangle) -> Result { self.pool.write().unwrap().new_surface(area) } fn render_to(&self, output: &mut S, frame: usize) { self.pool.read().unwrap().render_to(output, frame); } } impl Task for BufferedSurfacePool { fn tick(&mut self) { if self.pool.read().unwrap().is_dirty() { self.pool.write().unwrap().commit(); } } } #[derive(Clone)] pub struct SharedSurface { binding: Arc> } impl Default for SharedSurface { fn default() -> Self { Self { binding: Arc::new(Mutex::new(ShaderBinding { shader: None, rect: Rectangle::everything(), opacity: 255 })), } } } impl Surface for SharedSurface { fn set_shader(&mut self, shader: Box) { self.binding.lock().unwrap().shader = Some(shader); } fn clear_shader(&mut self) { self.binding.lock().unwrap().shader = None; } fn set_rect(&mut self, rect: &Rectangle) { self.binding.lock().unwrap().rect = rect.clone(); } fn set_opacity(&mut self, opacity: u8) { self.binding.lock().unwrap().opacity = opacity } } #[derive(Clone)] pub struct SurfacePool { surfaces: Vec } impl SurfacePool { pub const fn new() -> Self { Self { surfaces: Vec::new() } } } impl Surfaces for SurfacePool { type Surface = SharedSurface; type Error = io::Error; fn new_surface(&mut self, area: &Rectangle) -> Result { let mut surface = SharedSurface::default(); surface.set_rect(area); self.surfaces.push(surface.clone()); return Ok(surface); } fn render_to(&self, output: &mut Sampler, frame: usize) { for surface in self.surfaces.iter() { let binding = surface.binding.lock().unwrap(); let opacity = binding.opacity; if opacity > 0 { let rect = binding.rect; let mut sample = output.sample(&rect); if let Some(ref shader) = binding.shader { while let Some((virt_coords, pixel)) = sample.next() { *pixel = pixel.blend8(shader.draw(&virt_coords, frame).into(), opacity); } } } } } } pub trait Pixbuf: AsMilliwatts + IndexMut + Send { type Pixel: HardwarePixel; fn new() -> Self; fn blank(&mut self); fn iter_with_brightness(&self, brightness: u8) -> impl Iterator + Send; fn pixel_count(&self) -> usize; } impl Pixbuf for [T; PIXEL_NUM] { type Pixel = T; fn new() -> Self { [T::default(); PIXEL_NUM] } fn pixel_count(&self) -> usize { self.len() } fn blank(&mut self) { self.fill(T::default()) } fn iter_with_brightness(&self, brightness: u8) -> impl Iterator + Send { self.iter().map(move |x| { x.scale8(brightness)}) } }