buffers: refactor locking structure for higher fps and automatic surface commit

This commit is contained in:
Torrie Fischer 2024-12-15 17:58:28 +01:00
parent 9c773f0335
commit 3a49e7e390

View File

@ -1,15 +1,12 @@
use crate::events::EventBus;
use crate::geometry::*; use crate::geometry::*;
use crate::lib8::interpolate::Fract8Ops; use crate::lib8::interpolate::Fract8Ops;
use crate::power::AsMilliwatts; use crate::power::AsMilliwatts;
use crate::render::{PixelView, Sample, Shader, Surface, Surfaces, HardwarePixel}; use crate::render::{PixelView, Sample, Shader, Surface, Surfaces, HardwarePixel};
use crate::task::Task;
use std::fmt::Debug; use std::cell::RefCell;
use std::ops::IndexMut; use std::ops::IndexMut;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::RwLock;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
struct ShaderBinding { struct ShaderBinding {
@ -80,9 +77,9 @@ impl Surface for BufferedSurface {
}); });
} }
fn set_shader(&mut self, shader: Box<dyn Shader>) { fn set_shader<T: Shader + 'static>(&mut self, shader: T) {
self.updater.push(SurfaceUpdate { self.updater.push(SurfaceUpdate {
shader: Some(Some(shader)), shader: Some(Some(Box::new(shader))),
slot: self.slot, slot: self.slot,
..Default::default() ..Default::default()
}); });
@ -143,6 +140,7 @@ impl ShaderChain {
} }
pub fn commit(&mut self) { pub fn commit(&mut self) {
if self.is_dirty() {
let mut queue: Vec<SurfaceUpdate> = { let mut queue: Vec<SurfaceUpdate> = {
let mut updates = self.updates.pending.lock().unwrap(); let mut updates = self.updates.pending.lock().unwrap();
std::mem::take(updates.as_mut()) std::mem::take(updates.as_mut())
@ -161,13 +159,9 @@ impl ShaderChain {
} }
self.updates.damaged.store(false, std::sync::atomic::Ordering::Relaxed); self.updates.damaged.store(false, std::sync::atomic::Ordering::Relaxed);
} }
} }
impl Surfaces for ShaderChain { fn new_surface(&mut self, area: Rectangle<Virtual>) -> Result<BufferedSurface, ()> {
type Error = ();
type Surface = BufferedSurface;
fn new_surface(&mut self, area: Rectangle<Virtual>) -> Result<Self::Surface, Self::Error> {
let next_slot = self.bindings.len(); let next_slot = self.bindings.len();
self.bindings.push(ShaderBinding { self.bindings.push(ShaderBinding {
opacity: 255, opacity: 255,
@ -182,12 +176,12 @@ impl Surfaces for ShaderChain {
} }
fn render_to<S: Sample>(&self, output: &mut S, frame: usize) { fn render_to<S: Sample>(&self, output: &mut S, frame: usize) {
for surface in self.bindings.iter() { for surface in &self.bindings {
let opacity = surface.opacity; let opacity = surface.opacity;
if opacity > 0 { if opacity > 0 {
if let Some(ref shader) = surface.shader {
let rect = surface.rect; let rect = surface.rect;
let mut sample = output.sample(&rect); let mut sample = output.sample(&rect);
if let Some(ref shader) = surface.shader {
while let Some((virt_coords, pixel)) = sample.next() { while let Some((virt_coords, pixel)) = sample.next() {
*pixel = pixel.blend8(shader.draw(&virt_coords, frame).into(), opacity); *pixel = pixel.blend8(shader.draw(&virt_coords, frame).into(), opacity);
} }
@ -197,37 +191,29 @@ impl Surfaces for ShaderChain {
} }
} }
#[derive(Clone)]
pub struct BufferedSurfacePool { pub struct BufferedSurfacePool {
pool: Arc<RwLock<ShaderChain>> pool: RefCell<ShaderChain>
} }
impl BufferedSurfacePool { impl BufferedSurfacePool {
pub fn new() -> Self { pub fn new() -> Self {
BufferedSurfacePool { BufferedSurfacePool {
pool: Arc::new(RwLock::new(ShaderChain::new())) pool: RefCell::new(ShaderChain::new())
} }
} }
} }
impl Surfaces for BufferedSurfacePool { impl Surfaces for BufferedSurfacePool {
type Error = (); type Error = ();
type Surface = <ShaderChain as Surfaces>::Surface; type Surface = BufferedSurface;
fn new_surface(&mut self, area: crate::geometry::Rectangle<crate::geometry::Virtual>) -> Result<Self::Surface, Self::Error> { fn new_surface(&mut self, area: crate::geometry::Rectangle<crate::geometry::Virtual>) -> Result<Self::Surface, Self::Error> {
self.pool.write().unwrap().new_surface(area) self.pool.borrow_mut().new_surface(area)
} }
fn render_to<S: crate::render::Sample>(&self, output: &mut S, frame: usize) { fn render_to<S: crate::render::Sample>(&self, output: &mut S, frame: usize) {
self.pool.read().unwrap().render_to(output, frame); let mut b = self.pool.borrow_mut();
} b.commit();
} b.render_to(output, frame);
impl Task for BufferedSurfacePool {
fn on_tick(&mut self, _bus: &mut EventBus) {
if self.pool.read().unwrap().is_dirty() {
self.pool.write().unwrap().commit();
}
} }
} }