From bd2f2edebba809939e040191eaac32a119c04d89 Mon Sep 17 00:00:00 2001 From: Victoria Fischer Date: Fri, 29 Nov 2024 18:13:22 +0100 Subject: [PATCH] render: effectively rename Display to Output, push remaining common code into Renderer task --- src/animations.rs | 2 +- src/buffers.rs | 21 +++- src/main.rs | 12 ++- src/platform/mod.rs | 5 +- src/platform/smart_leds_lib.rs | 176 ++++++++++++++------------------- src/render.rs | 44 +++++---- 6 files changed, 131 insertions(+), 129 deletions(-) diff --git a/src/animations.rs b/src/animations.rs index 1410c72..c4cd768 100644 --- a/src/animations.rs +++ b/src/animations.rs @@ -64,7 +64,7 @@ impl Shader for GayBarberShader { } impl IdleTask { - pub fn new>(surfaces: &mut S) -> Self { + pub fn new>(surfaces: &mut S) -> Self { IdleTask { solid: surfaces.new_surface(&Rectangle::everything()).unwrap(), surface: surfaces.new_surface(&Rectangle::everything()).unwrap(), diff --git a/src/buffers.rs b/src/buffers.rs index 93ddf95..b17dcd0 100644 --- a/src/buffers.rs +++ b/src/buffers.rs @@ -1,5 +1,6 @@ use crate::geometry::*; -use crate::render::{Surface, Shader, Surfaces}; +use crate::lib8::interpolate::Fract8Ops; +use crate::render::{PixelView, Sample, Shader, Surface, Surfaces}; use std::fmt::Debug; use std::rc::Rc; @@ -158,11 +159,27 @@ impl SurfacePool { } } -impl Surfaces for SurfacePool { +impl Surfaces for SurfacePool { + type Surface = S; fn new_surface(&mut self, area: &Rectangle) -> Result { let mut surface = S::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.iter() { + let opacity = surface.opacity(); + if opacity > 0 { + let rect = surface.rect(); + let mut sample = output.sample(&rect); + surface.with_shader(|shader| { + while let Some((virt_coords, pixel)) = sample.next() { + *pixel = pixel.blend8(shader.draw(&virt_coords, frame).into(), opacity); + } + }) + } + } + } } diff --git a/src/main.rs b/src/main.rs index 73da8d9..0f3a923 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ mod animations; mod mappings; mod buffers; +use buffers::SurfacePool; + use crate::platform::DisplayInit; use crate::render::Surfaces; use crate::geometry::Rectangle; @@ -43,15 +45,17 @@ fn main() { log::info!("Setting up display"); - let mut display = DisplayType::new_display::(); + let display = DisplayType::new_display::(); + + let mut surfaces: SurfacePool = SurfacePool::new(); log::info!("Created new display type {}", core::any::type_name_of_val(&display)); log::info!("Creating runner"); let mut runner = task::Scheduler::new(vec![ - Box::new(animations::IdleTask::new(&mut display)), - Box::new(animations::TestPattern::new(display.new_surface(&Rectangle::everything()).unwrap())), - Box::new(Renderer::new(display)), + Box::new(animations::IdleTask::new(&mut surfaces)), + Box::new(animations::TestPattern::new(surfaces.new_surface(&Rectangle::everything()).unwrap())), + Box::new(Renderer::new(display, surfaces)), ]); log::info!("Runner ready: {:?}", runner); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index bde2c86..e19442e 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -4,8 +4,9 @@ pub mod embedded_graphics_lib; #[cfg(feature="smart-leds")] pub mod smart_leds_lib; -use crate::render::{Surface, Display}; +use crate::render::{Surface, Output}; pub trait DisplayInit { - fn new_display() -> impl Display; + type Output: Output; + fn new_display() -> Self::Output; } diff --git a/src/platform/smart_leds_lib.rs b/src/platform/smart_leds_lib.rs index 6063b1a..ac8014d 100644 --- a/src/platform/smart_leds_lib.rs +++ b/src/platform/smart_leds_lib.rs @@ -1,14 +1,11 @@ use smart_leds_trait::SmartLedsWrite; -use crate::lib8::interpolate::Fract8Ops; -use crate::render::{Display, HardwarePixel, PixelView, Sample, Surface, Surfaces}; -use crate::buffers::SurfacePool; +use crate::render::{HardwarePixel, Output, PixelView, Sample}; use crate::power::{brightness_for_mw, AsMilliwatts}; use crate::geometry::*; use crate::mappings::*; -use std::fmt::{Debug, Formatter}; -use std::io; +use std::fmt::Debug; use std::ops::IndexMut; pub trait Pixbuf: AsMilliwatts + IndexMut { @@ -16,6 +13,7 @@ pub trait Pixbuf: AsMilliwatts + IndexMut { fn new() -> Self; fn blank(&mut self); fn iter_with_brightness(&self, brightness: u8) -> impl Iterator + Send; + fn pixel_count(&self) -> usize; } struct StrideSampler<'a, P: Pixbuf> { @@ -35,12 +33,32 @@ impl<'a, P: Pixbuf> PixelView for StrideSampler<'a, P> { } } -struct StrideOutput { - pixbuf: P, - stride_map: StrideMapping +impl Debug for StrideOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StrideOutput").finish() + } } -impl Sample for StrideOutput

{ +pub struct StrideOutput { + pixbuf: P, + stride_map: StrideMapping, + target: T, + max_mw: u32 +} + +impl StrideOutput { + fn new(pixbuf: P, stride_map: StrideMapping, target: T, max_mw: u32) -> Self { + assert!(stride_map.pixel_count <= pixbuf.pixel_count(), "map needs {} pixels, I only have PIXEL_NUM={}", stride_map.pixel_count, pixbuf.pixel_count()); + StrideOutput { + pixbuf, + stride_map, + target, + max_mw + } + } +} + +impl Sample for StrideOutput { type Pixel = P::Pixel; fn sample(&mut self, rect: &Rectangle) -> impl PixelView { StrideSampler { @@ -50,12 +68,29 @@ impl Sample for StrideOutput

{ } } +impl, T: FastWrite> Output for StrideOutput { + fn blank(&mut self) { + self.pixbuf.blank(); + } + + fn commit(&mut self) { + let b = brightness_for_mw(self.pixbuf.as_milliwatts(), 255, self.max_mw); + if self.target.fast_write(self.pixbuf.iter_with_brightness(b)).is_err() { + panic!("Could not write frame!"); + }; + } +} + 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()) } @@ -64,84 +99,7 @@ impl Pixbuf for [T; PIXEL_NUM] { self.iter().map(move |x| { x.scale8(brightness)}) } } - -struct SmartLedDisplay> { - surfaces : Option>, - output: StrideOutput

, - target: T, - max_mw: u32, - frame: usize -} - -impl> Debug for SmartLedDisplay { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - f.debug_struct("SmartLedDisplay") - .field("total_mw", &self.output.pixbuf.as_milliwatts()) - .field("surfaces", &self.surfaces) - .finish() - } -} - -impl> SmartLedDisplay { - fn new(target: T, max_mw: u32, pixmap: StrideMapping, pixbuf: P) -> Self { - SmartLedDisplay { - output: StrideOutput { pixbuf: pixbuf, stride_map: pixmap }, - surfaces: Some(SurfacePool::new()), - target, - max_mw, - frame: 0 - } - } -} - -impl Surfaces for SmartLedDisplay where -T: FastWrite, -S: Surface, -P: Pixbuf { - fn new_surface(&mut self, area: &Rectangle) -> Result { - if let Some(ref mut s) = self.surfaces { - s.new_surface(area) - } else { - panic!("Could not grab surface list") - } - } -} - -impl Display for SmartLedDisplay where -T: FastWrite, -S: Surface, -P: Pixbuf { - fn start_frame(&mut self) { - self.output.pixbuf.blank(); - } - - fn render_frame(&mut self) { - let surfaces = self.surfaces.take().unwrap(); - for surface in surfaces.iter() { - let rect = surface.rect(); - let opacity = surface.opacity(); - if opacity > 0 { - let mut sample = self.output.sample(&rect); - surface.with_shader(|shader| { - while let Some((virt_coords, pixel)) = sample.next() { - *pixel = pixel.blend8(shader.draw(&virt_coords, self.frame).into(), opacity); - } - }) - } - } - self.surfaces = Some(surfaces); - } - - fn end_frame(&mut self) { - let b = brightness_for_mw(self.output.pixbuf.as_milliwatts(), 255, self.max_mw); - if self.target.fast_write(self.output.pixbuf.iter_with_brightness(b)).is_err() { - panic!("Could not write frame!"); - }; - self.frame += 1; - } -} - -trait FastWrite { +pub trait FastWrite { type Target: SmartLedsWrite; type Color: HardwarePixel; type Error; @@ -153,17 +111,18 @@ trait FastWrite { #[cfg(feature="rmt")] pub mod rmt { - use esp_idf_svc::hal::prelude::Peripherals; + use esp_idf_svc::{hal::prelude::Peripherals, sys::esp_efuse_mac_get_default}; use ws2812_esp32_rmt_driver::driver::color::LedPixelColorGrb24; use smart_leds::SmartLedsWrite; use rgb::Rgb; use ws2812_esp32_rmt_driver::LedPixelEsp32Rmt; use crate::mappings::StrideMapping; - use crate::render::{Display, Surface}; + use crate::platform::smart_leds_lib::StrideOutput; + use crate::render::Surface; use crate::platform::DisplayInit; - use super::{Pixbuf, FastWrite, SmartLedDisplay}; + use super::{Pixbuf, FastWrite}; pub type FastWs2812Esp32Rmt<'a> = LedPixelEsp32Rmt<'a, Rgb, LedPixelColorGrb24>; @@ -180,24 +139,39 @@ pub mod rmt { } impl DisplayInit for FastWs2812Esp32Rmt<'_> { - fn new_display() -> impl Display { - let peripherals = Peripherals::take().unwrap(); - let led_pin = peripherals.pins.gpio14; - //let led_pin = peripherals.pins.gpio5; - let channel = peripherals.rmt.channel0; + type Output = StrideOutput<[Rgb; 310], Self>; + fn new_display() -> Self::Output { const POWER_VOLTS : u32 = 5; const POWER_MA : u32 = 500; const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA; + let peripherals = Peripherals::take().unwrap(); + let channel = peripherals.rmt.channel0; + let pins = peripherals.pins; - //let pixbuf: [Rgb; 310] = Pixbuf::new(); - let pixbuf: [::Color; 310] = Pixbuf::new(); - let pixmap = StrideMapping::new_jar(); + let mut chip_id: [u8; 8] = [0; 8]; + unsafe { + esp_efuse_mac_get_default(&mut chip_id as *mut u8); + } - assert!(pixmap.pixel_count <= pixbuf.len(), "map needs {} pixels, I only have PIXEL_NUM={}", pixmap.pixel_count, pixbuf.len()); + let (pixmap, target) = match chip_id { + [72, 202, 67, 89, 145, 204, 0, 0] => { + (StrideMapping::new_panel(), Self::new(channel, pins.gpio5).unwrap()) + }, + [140, 170, 181, 131, 95, 116, 0, 0] => { + (StrideMapping::new_jar(), Self::new(channel, pins.gpio14).unwrap()) + }, + _ => { + (StrideMapping::new(), Self::new(channel, pins.gpio5).unwrap()) + } + }; - let target = Self::new(channel, led_pin).unwrap(); - return SmartLedDisplay::new(target, MAX_POWER_MW, pixmap, pixbuf); + StrideOutput::new( + Pixbuf::new(), + pixmap, + target, + MAX_POWER_MW + ) } } } diff --git a/src/render.rs b/src/render.rs index 2ecc4f5..925459f 100644 --- a/src/render.rs +++ b/src/render.rs @@ -8,7 +8,6 @@ use crate::power::AsMilliwatts; use crate::task::Task; use crate::time::Periodically; use running_average::RealTimeRunningAverage; -use std::marker::PhantomData; use std::fmt::Debug; pub trait HardwarePixel: Send + Sync + Rgb8Blend + Copy + AsMilliwatts + Default + From> + Fract8Ops {} @@ -30,8 +29,10 @@ pub trait Shader: Send + Debug { fn draw(&self, surface_coords: &VirtualCoordinates, frame: usize) -> Rgb; } -pub trait Surfaces: Debug { - fn new_surface(&mut self, area: &Rectangle) -> Result; +pub trait Surfaces: Debug { + type Surface: Surface; + fn new_surface(&mut self, area: &Rectangle) -> Result; + fn render_to(&self, output: &mut S, frame: usize); } pub trait Surface: Default + Clone + Debug { @@ -45,41 +46,46 @@ pub trait Surface: Default + Clone + Debug { fn set_opacity(&mut self, opacity: u8); } -pub trait Display: Surfaces { - fn start_frame(&mut self) {} - fn render_frame(&mut self); - fn end_frame(&mut self) {} +pub trait Output: Sample { + fn blank(&mut self); + fn commit(&mut self); } #[derive(Debug)] -pub struct Renderer, S: Surface> { - display: T, +pub struct Renderer { + output: T, + surfaces: S, fps: RealTimeRunningAverage, fps_display: Periodically, - _sfc: PhantomData + frame: usize } -impl, S: Surface> Renderer { - pub fn new(display: T) -> Self { +impl Renderer { + pub fn new(output: T, surfaces: S) -> Self { Self { - display, + output, + surfaces: surfaces, fps: RealTimeRunningAverage::default(), fps_display: Periodically::new_every_n_seconds(5), - _sfc: PhantomData + frame: 0 } } } -impl, S: Surface> Task for Renderer { +impl Task for Renderer { fn name(&self) -> &'static str { "Renderer" } fn tick(&mut self) { - self.display.start_frame(); - self.display.render_frame(); - self.display.end_frame(); + self.output.blank(); + + self.surfaces.render_to(&mut self.output, self.frame); + + self.output.commit(); + self.fps.insert(1); + self.frame += 1; self.fps_display.run(|| { - log::info!("FPS: {} {:?}", self.fps.measurement(), self.display); + log::info!("FPS: {}", self.fps.measurement()); }); } }