graphics: rewrite the DisplayControls to use a write-ack mechanism between the renderer and ui tasks
This commit is contained in:
@@ -29,9 +29,9 @@ impl<S: Surface> AnimationActor<Fract8> for S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnimDisplay<'a>(pub &'a mut DisplayControls);
|
pub struct AnimDisplay<'a, 'b>(pub &'a mut DisplayControls<'b>);
|
||||||
|
|
||||||
impl<'a> AnimationActor<Fract8> for AnimDisplay<'a> {
|
impl<'a> AnimationActor<Fract8> for AnimDisplay<'a, '_> {
|
||||||
fn get_value(&self) -> Fract8 {
|
fn get_value(&self) -> Fract8 {
|
||||||
self.0.brightness()
|
self.0.brightness()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,8 +82,10 @@ async fn main(spawner: Spawner) {
|
|||||||
let mut surfaces = UiSurfacePool::default();
|
let mut surfaces = UiSurfacePool::default();
|
||||||
let ui = Ui::new(&mut surfaces);
|
let ui = Ui::new(&mut surfaces);
|
||||||
|
|
||||||
let display_controls = DisplayControls::default();
|
static MAIN_DISPLAY_SWITCH: ConstStaticCell<DisplayControlResources> = ConstStaticCell::new(DisplayControlResources::new());
|
||||||
let oled_controls = DisplayControls::default();
|
static OLED_DISPLAY_SWITCH: ConstStaticCell<DisplayControlResources> = ConstStaticCell::new(DisplayControlResources::new());
|
||||||
|
let display_controls = DisplayControls::new(MAIN_DISPLAY_SWITCH.take());
|
||||||
|
let oled_controls = DisplayControls::new(OLED_DISPLAY_SWITCH.take());
|
||||||
|
|
||||||
let mut oled_surfaces = OledUiSurfacePool::default();
|
let mut oled_surfaces = OledUiSurfacePool::default();
|
||||||
let oled_uniforms = Default::default();
|
let oled_uniforms = Default::default();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal, watch::{Receiver, Watch}};
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal, watch::{Receiver, Watch}};
|
||||||
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
use figments::{liber8tion::interpolate::Fract8, prelude::*};
|
||||||
use portable_atomic::AtomicU32;
|
use portable_atomic::AtomicU32;
|
||||||
use core::{fmt::Debug, ops::Mul, sync::atomic::{AtomicBool, AtomicU8}};
|
use core::{cell::RefCell, fmt::Debug, ops::Mul, sync::atomic::{AtomicBool, AtomicU8}};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
use figments_render::{
|
use figments_render::{
|
||||||
@@ -14,7 +14,7 @@ pub const NUM_PIXELS: usize = 178;
|
|||||||
pub struct BikeOutput<T, Color> {
|
pub struct BikeOutput<T, Color> {
|
||||||
pixbuf: [Color; NUM_PIXELS],
|
pixbuf: [Color; NUM_PIXELS],
|
||||||
writer: PowerManagedWriter<T>,
|
writer: PowerManagedWriter<T>,
|
||||||
controls: DisplayControls
|
controls: DisplayControls<'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Color> GammaCorrected for BikeOutput<T, Color> {
|
impl<T, Color> GammaCorrected for BikeOutput<T, Color> {
|
||||||
@@ -24,7 +24,7 @@ impl<T, Color> GammaCorrected for BikeOutput<T, Color> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Color: Default + Copy> BikeOutput<T, Color> {
|
impl<T, Color: Default + Copy> BikeOutput<T, Color> {
|
||||||
pub fn new(target: T, controls: DisplayControls) -> Self {
|
pub fn new(target: T, controls: DisplayControls<'static>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pixbuf: [Default::default(); NUM_PIXELS],
|
pixbuf: [Default::default(); NUM_PIXELS],
|
||||||
writer: PowerManagedWriter::new(target, controls.max_power()),
|
writer: PowerManagedWriter::new(target, controls.max_power()),
|
||||||
@@ -40,7 +40,7 @@ impl<T, Color: Default + Copy> BikeOutput<T, Color> {
|
|||||||
impl<'a, T: SmartLedsWrite + 'a> Output<'a, SegmentSpace> for BikeOutput<T, T::Color> where T::Color: AsMilliwatts + Copy + Mul<Fract8, Output = T::Color> + WithGamma + Default + Debug + 'a + 'static {
|
impl<'a, T: SmartLedsWrite + 'a> Output<'a, SegmentSpace> for BikeOutput<T, T::Color> where T::Color: AsMilliwatts + Copy + Mul<Fract8, Output = T::Color> + WithGamma + Default + Debug + 'a + 'static {
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
type Controls = DisplayControls;
|
type Controls = DisplayControls<'static>;
|
||||||
|
|
||||||
fn commit(&mut self) -> Result<(), Self::Error> {
|
fn commit(&mut self) -> Result<(), Self::Error> {
|
||||||
self.writer.controls().set_brightness(self.controls.brightness());
|
self.writer.controls().set_brightness(self.controls.brightness());
|
||||||
@@ -66,7 +66,7 @@ impl<'a, T: SmartLedsWriteAsync + 'a> OutputAsync<'a, SegmentSpace> for BikeOutp
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
type Controls = DisplayControls;
|
type Controls = DisplayControls<'static>;
|
||||||
|
|
||||||
fn controls(&mut self) -> Option<&mut Self::Controls> {
|
fn controls(&mut self) -> Option<&mut Self::Controls> {
|
||||||
Some(&mut self.controls)
|
Some(&mut self.controls)
|
||||||
@@ -184,27 +184,56 @@ impl Default for ControlData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A watch that indicates whether or not the rendering engine is running. If the display is off or sleeping, this will be false.
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
static RENDER_IS_RUNNING: Watch<CriticalSectionRawMutex, bool, 7> = Watch::new();
|
pub enum RenderState {
|
||||||
|
On,
|
||||||
// TODO: Implement something similar for a system-wide sleep mechanism
|
Off
|
||||||
pub struct DisplayControls {
|
|
||||||
data: Arc<ControlData>,
|
|
||||||
display_is_on: Arc<Signal<CriticalSectionRawMutex, bool>>,
|
|
||||||
render_run_receiver: Receiver<'static, CriticalSectionRawMutex, bool, 7>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for DisplayControls {
|
pub struct DisplayControlResources {
|
||||||
|
state_rx: Watch<CriticalSectionRawMutex, RenderState, 7>,
|
||||||
|
state_ack: Watch<CriticalSectionRawMutex, RenderState, 7>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayControlResources {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state_rx: Watch::new_with(RenderState::On),
|
||||||
|
state_ack: Watch::new_with(RenderState::On)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement something similar for a system-wide sleep mechanism
|
||||||
|
pub struct DisplayControls<'a> {
|
||||||
|
data: Arc<ControlData>,
|
||||||
|
render_run_receiver: Receiver<'a, CriticalSectionRawMutex, RenderState, 7>,
|
||||||
|
render_ack_receiver: Receiver<'a, CriticalSectionRawMutex, RenderState, 7>,
|
||||||
|
resources: &'a DisplayControlResources,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for DisplayControls<'_> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Arc::clone(&self.data),
|
data: Arc::clone(&self.data),
|
||||||
display_is_on: Arc::clone(&self.display_is_on),
|
render_run_receiver: self.resources.state_rx.receiver().expect("Could not create enough render running receivers"),
|
||||||
render_run_receiver: RENDER_IS_RUNNING.receiver().expect("Could not create enough render running receivers")
|
resources: self.resources,
|
||||||
|
render_ack_receiver: self.resources.state_ack.receiver().expect("Could not create enough render ack receivers"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayControls {
|
|
||||||
|
impl<'a> DisplayControls<'a> {
|
||||||
|
pub fn new(resources: &'a DisplayControlResources) -> Self {
|
||||||
|
Self {
|
||||||
|
data: Default::default(),
|
||||||
|
render_run_receiver: resources.state_rx.receiver().expect("Could not create enough render running receivers"),
|
||||||
|
render_ack_receiver: resources.state_ack.receiver().expect("Could not create enough render ack receivers"),
|
||||||
|
resources
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_on(&self) -> bool {
|
pub fn is_on(&self) -> bool {
|
||||||
self.data.on.load(core::sync::atomic::Ordering::Relaxed)
|
self.data.on.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
@@ -221,21 +250,6 @@ impl DisplayControls {
|
|||||||
self.data.fps.store(value, core::sync::atomic::Ordering::Relaxed);
|
self.data.fps.store(value, core::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wait_until_display_is_turned_on(&self) {
|
|
||||||
while !self.display_is_on.wait().await { log::info!("wait for display") }
|
|
||||||
log::trace!("display says on!");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notify_render_is_running(&mut self, value: bool) {
|
|
||||||
log::trace!("render is running!");
|
|
||||||
RENDER_IS_RUNNING.sender().send(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wait_until_render_is_running(&mut self) {
|
|
||||||
while !self.render_run_receiver.changed().await { log::info!("wait for render run") }
|
|
||||||
log::trace!("render says run!");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_max_power(&mut self, mw: Milliwatts) {
|
pub fn set_max_power(&mut self, mw: Milliwatts) {
|
||||||
self.data.max_power_mw.store(mw.0, core::sync::atomic::Ordering::Relaxed);
|
self.data.max_power_mw.store(mw.0, core::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -243,44 +257,48 @@ impl DisplayControls {
|
|||||||
pub fn max_power(&self) -> Milliwatts {
|
pub fn max_power(&self) -> Milliwatts {
|
||||||
Milliwatts(self.data.max_power_mw.load(core::sync::atomic::Ordering::Relaxed))
|
Milliwatts(self.data.max_power_mw.load(core::sync::atomic::Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_state(&mut self, state: RenderState) {
|
||||||
|
self.render_run_receiver.get_and(|cur| { *cur == state }).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_ack(&mut self, state: RenderState) {
|
||||||
|
self.render_ack_receiver.get_and(|cur| { *cur == state }).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates the current state has been applied to the hardware, which can wake up tasks waiting for the power to turn on/off.
|
||||||
|
pub async fn ack(&mut self) {
|
||||||
|
let next_state = self.render_run_receiver.get().await;
|
||||||
|
let is_on = next_state == RenderState::On;
|
||||||
|
self.data.on.store(is_on, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
self.resources.state_ack.sender().send(if self.is_on() { RenderState::On } else { RenderState::Off });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GammaCorrected for DisplayControls {
|
impl GammaCorrected for DisplayControls<'_> {
|
||||||
fn set_gamma(&mut self, _gamma: GammaCurve) {
|
fn set_gamma(&mut self, _gamma: GammaCurve) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Brightness for DisplayControls {
|
impl Brightness for DisplayControls<'_> {
|
||||||
fn set_brightness(&mut self, brightness: Fract8) {
|
fn set_brightness(&mut self, brightness: Fract8) {
|
||||||
self.data.brightness.store(brightness.to_raw(), core::sync::atomic::Ordering::Relaxed);
|
self.data.brightness.store(brightness.to_raw(), core::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_on(&mut self, is_on: bool) {
|
fn set_on(&mut self, is_on: bool) {
|
||||||
self.data.on.store(is_on, core::sync::atomic::Ordering::Relaxed);
|
self.resources.state_rx.sender().send(if is_on { RenderState::On } else { RenderState::Off });
|
||||||
log::trace!("display is on {is_on}");
|
log::trace!("display is on {is_on}");
|
||||||
self.display_is_on.signal(is_on);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for DisplayControls {
|
impl core::fmt::Debug for DisplayControls<'_> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
f.debug_struct("DisplayControls")
|
f.debug_struct("DisplayControls")
|
||||||
.field("on", &self.data.on)
|
.field("on", &self.data.on)
|
||||||
.field("brightness", &self.data.brightness)
|
.field("brightness", &self.data.brightness)
|
||||||
.field("fps", &self.data.fps)
|
.field("fps", &self.data.fps)
|
||||||
.field("render_pause_signaled", &self.display_is_on.signaled())
|
|
||||||
.field("max_power_mw", &self.data.max_power_mw)
|
.field("max_power_mw", &self.data.max_power_mw)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DisplayControls {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
data: Default::default(),
|
|
||||||
display_is_on: Default::default(),
|
|
||||||
render_run_receiver: RENDER_IS_RUNNING.receiver().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ impl<'a> Iterator for SsdSampler<'a> {
|
|||||||
pub struct SsdOutput {
|
pub struct SsdOutput {
|
||||||
pixbuf: [u8; 128 * 64 / 8],
|
pixbuf: [u8; 128 * 64 / 8],
|
||||||
target: ssd1306::Ssd1306Async<ssd1306::prelude::I2CInterface<esp_hal::i2c::master::I2c<'static, esp_hal::Async>>, ssd1306::prelude::DisplaySize128x64, ssd1306::mode::BasicMode>,
|
target: ssd1306::Ssd1306Async<ssd1306::prelude::I2CInterface<esp_hal::i2c::master::I2c<'static, esp_hal::Async>>, ssd1306::prelude::DisplaySize128x64, ssd1306::mode::BasicMode>,
|
||||||
controls: DisplayControls,
|
controls: DisplayControls<'static>,
|
||||||
is_on: bool,
|
is_on: bool,
|
||||||
last_brightness: Fract8,
|
last_brightness: Fract8,
|
||||||
reset_pin: Output<'static>
|
reset_pin: Output<'static>
|
||||||
@@ -124,7 +124,7 @@ impl SsdOutput {
|
|||||||
Some(SsdPixel { byte: pixref, bit, coords })
|
Some(SsdPixel { byte: pixref, bit, coords })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(i2c: I2c<'static, Async>, reset_pin: Output<'static>, controls: DisplayControls) -> Self {
|
pub async fn new(i2c: I2c<'static, Async>, reset_pin: Output<'static>, controls: DisplayControls<'static>) -> Self {
|
||||||
let interface = I2CDisplayInterface::new(i2c);
|
let interface = I2CDisplayInterface::new(i2c);
|
||||||
let target = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0);
|
let target = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0);
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ impl OriginDimensions for SsdOutput {
|
|||||||
impl<'a> OutputAsync<'a, Matrix2DSpace> for SsdOutput {
|
impl<'a> OutputAsync<'a, Matrix2DSpace> for SsdOutput {
|
||||||
type Error = DisplayError;
|
type Error = DisplayError;
|
||||||
|
|
||||||
type Controls = DisplayControls;
|
type Controls = DisplayControls<'static>;
|
||||||
|
|
||||||
async fn commit_async(&mut self) -> Result<(), Self::Error> {
|
async fn commit_async(&mut self) -> Result<(), Self::Error> {
|
||||||
let new_brightness = self.controls.brightness();
|
let new_brightness = self.controls.brightness();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub type LockedUniforms = Arc<Mutex<CriticalSectionRawMutex, OledUniforms>>;
|
|||||||
|
|
||||||
pub struct OledUI<S: Surface + core::fmt::Debug> {
|
pub struct OledUI<S: Surface + core::fmt::Debug> {
|
||||||
overlay: S,
|
overlay: S,
|
||||||
controls: DisplayControls,
|
controls: DisplayControls<'static>,
|
||||||
uniforms: LockedUniforms
|
uniforms: LockedUniforms
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ impl Shader<OledUniforms, Matrix2DSpace, BinaryColor> for OverlayShader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = BinaryColor, Uniforms = OledUniforms>> OledUI<S> {
|
impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = BinaryColor, Uniforms = OledUniforms>> OledUI<S> {
|
||||||
pub fn new<SS: Surfaces<Surface = S>>(surfaces: &mut SS, controls: DisplayControls, uniforms: LockedUniforms) -> Self where SS::Error: core::fmt::Debug {
|
pub fn new<SS: Surfaces<Surface = S>>(surfaces: &mut SS, controls: DisplayControls<'static>, uniforms: LockedUniforms) -> Self where SS::Error: core::fmt::Debug {
|
||||||
Self {
|
Self {
|
||||||
overlay: SurfaceBuilder::build(surfaces)
|
overlay: SurfaceBuilder::build(surfaces)
|
||||||
.rect(Rectangle::everything())
|
.rect(Rectangle::everything())
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ use figments_render::gamma::GammaCurve;
|
|||||||
use figments_render::output::{GammaCorrected, OutputAsync};
|
use figments_render::output::{GammaCorrected, OutputAsync};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
use crate::graphics::display::NUM_PIXELS;
|
use crate::graphics::display::{NUM_PIXELS, RenderState};
|
||||||
use crate::{graphics::display::{BikeOutput, DisplayControls, Uniforms}, tasks::ui::UiSurfacePool};
|
use crate::{graphics::display::{BikeOutput, DisplayControls, Uniforms}, tasks::ui::UiSurfacePool};
|
||||||
|
|
||||||
static SPI_BUFFERS: static_cell::ConstStaticCell<DmaBuffers<u8, {NUM_PIXELS * 12 + 140}>> = static_cell::ConstStaticCell::new(DmaBuffers::new(0));
|
static SPI_BUFFERS: static_cell::ConstStaticCell<DmaBuffers<u8, {NUM_PIXELS * 12 + 140}>> = static_cell::ConstStaticCell::new(DmaBuffers::new(0));
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: AnyPin<'static>, mut surfaces: UiSurfacePool, mut safety_surfaces: UiSurfacePool, mut controls: DisplayControls, mut wdt: Wdt<esp_hal::peripherals::TIMG0<'static>>) {
|
pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: AnyPin<'static>, mut surfaces: UiSurfacePool, mut safety_surfaces: UiSurfacePool, mut controls: DisplayControls<'static>, mut wdt: Wdt<esp_hal::peripherals::TIMG0<'static>>) {
|
||||||
info!("Starting rendering task");
|
info!("Starting rendering task");
|
||||||
|
|
||||||
let buffers = SPI_BUFFERS.take();
|
let buffers = SPI_BUFFERS.take();
|
||||||
@@ -41,7 +41,6 @@ pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: An
|
|||||||
output.set_gamma(GammaCurve::new(1.3));
|
output.set_gamma(GammaCurve::new(1.3));
|
||||||
|
|
||||||
info!("Rendering started! {}ms since boot", Instant::now().as_millis());
|
info!("Rendering started! {}ms since boot", Instant::now().as_millis());
|
||||||
controls.notify_render_is_running(true);
|
|
||||||
|
|
||||||
let mut requested_fps= controls.fps() as u64;
|
let mut requested_fps= controls.fps() as u64;
|
||||||
let mut render_budget = Duration::from_millis(1000 / requested_fps);
|
let mut render_budget = Duration::from_millis(1000 / requested_fps);
|
||||||
@@ -74,15 +73,15 @@ pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: An
|
|||||||
|
|
||||||
if !controls.is_on() {
|
if !controls.is_on() {
|
||||||
warn!("Renderer is sleeping zzzz");
|
warn!("Renderer is sleeping zzzz");
|
||||||
controls.notify_render_is_running(false);
|
|
||||||
output.blank();
|
output.blank();
|
||||||
output.commit_async().await.expect("Failed to commit low power frame");
|
output.commit_async().await.expect("Failed to commit low power frame");
|
||||||
wdt.disable();
|
wdt.disable();
|
||||||
controls.wait_until_display_is_turned_on().await;
|
controls.ack().await;
|
||||||
|
controls.wait_for_state(RenderState::On).await;
|
||||||
|
controls.ack().await;
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
wdt.enable();
|
wdt.enable();
|
||||||
warn!("Renderer is awake !!!!");
|
warn!("Renderer is awake !!!!");
|
||||||
controls.notify_render_is_running(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the FPS cap where we sleep if we are rendering fast enough
|
// Apply the FPS cap where we sleep if we are rendering fast enough
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ pub struct SafetyUi<S: Surface> {
|
|||||||
|
|
||||||
// The overlay covers everything and is used to implement a power-on and power-off animation.
|
// The overlay covers everything and is used to implement a power-on and power-off animation.
|
||||||
overlay: AnimatedSurface<S>,
|
overlay: AnimatedSurface<S>,
|
||||||
display: DisplayControls
|
display: DisplayControls<'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pixel = Rgba<u8>>> SafetyUi<S> {
|
impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pixel = Rgba<u8>>> SafetyUi<S> {
|
||||||
pub fn new<SS: Surfaces<Surface = S>>(surfaces: &mut SS, display: DisplayControls) -> Self where SS::Error: Debug {
|
pub fn new<SS: Surfaces<Surface = S>>(surfaces: &mut SS, display: DisplayControls<'static>) -> Self where SS::Error: Debug {
|
||||||
let ret = Self {
|
let ret = Self {
|
||||||
overlay: SurfaceBuilder::build(surfaces)
|
overlay: SurfaceBuilder::build(surfaces)
|
||||||
.rect(Rectangle::everything())
|
.rect(Rectangle::everything())
|
||||||
@@ -68,7 +68,7 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
|||||||
self.display.set_brightness(Fract8::MIN);
|
self.display.set_brightness(Fract8::MIN);
|
||||||
self.display.set_on(true);
|
self.display.set_on(true);
|
||||||
// Wait for the renderer to start running again
|
// Wait for the renderer to start running again
|
||||||
self.display.wait_until_render_is_running().await;
|
self.display.wait_for_ack(RenderState::On).await;
|
||||||
|
|
||||||
trace!("Fading in brightness with overlay={:?}", self.overlay);
|
trace!("Fading in brightness with overlay={:?}", self.overlay);
|
||||||
self.overlay.set_opacity(Fract8::MAX);
|
self.overlay.set_opacity(Fract8::MAX);
|
||||||
|
|||||||
Reference in New Issue
Block a user