Skip to content

Commit f28142e

Browse files
authored
Merge pull request #25 from ckaznable/optimize
perf: optimize render frequency
2 parents 8332c06 + 5d2876c commit f28142e

File tree

9 files changed

+80
-40
lines changed

9 files changed

+80
-40
lines changed

src/app.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crossterm::{
88
use ratatui::{backend::CrosstermBackend, Terminal};
99

1010
use crate::{
11-
cli::Args, state::{EachFrameImpl, State}, tui::{Event, Tui}, ui::ui, widget::AsWeatherWidget
11+
cli::Args, state::{EachFrameImpl, ShouldRender, State}, tui::{Event, Tui}, ui::ui, widget::AsWeatherWidget
1212
};
1313

1414
#[derive(Copy, Clone)]
@@ -21,6 +21,7 @@ pub struct App<T> {
2121
tui: Tui,
2222
state: State<T>,
2323
should_quit: bool,
24+
should_render: ShouldRender,
2425
args: Args,
2526
frame_in_second: usize,
2627
runtime_info: AppRuntimeInfo,
@@ -46,6 +47,7 @@ where
4647
args,
4748
tui: Tui::new(args.fps as f64, args.tps as f64)?,
4849
should_quit: false,
50+
should_render: ShouldRender::Render,
4951
frame_in_second: 0,
5052
runtime_info: AppRuntimeInfo { fps: 0 },
5153
})
@@ -64,7 +66,7 @@ where
6466
Key(key) => self.handle_keyboard(key),
6567
Tick => self.on_tick(),
6668
Timer => self.on_timer(),
67-
Resize(columns, rows) => self.state.on_resize(columns, rows),
69+
Resize(columns, rows) => self.on_resize(columns, rows),
6870
};
6971
};
7072

@@ -83,8 +85,13 @@ where
8385
}
8486
}
8587

88+
fn on_resize(&mut self, columns: u16, rows: u16) {
89+
self.state.on_resize(columns, rows);
90+
self.should_render = ShouldRender::Render;
91+
}
92+
8693
fn on_tick(&mut self) {
87-
self.state.tick();
94+
self.should_render = self.should_render.or(self.state.tick());
8895
self.frame_in_second = self.frame_in_second.saturating_add(1);
8996
}
9097

@@ -93,14 +100,19 @@ where
93100
self.on_tick()
94101
}
95102

96-
self.terminal.draw(|f| ui(f, &mut self.state, self.args, self.runtime_info))?;
103+
if self.should_render.is_render() {
104+
self.should_render = ShouldRender::Skip;
105+
self.terminal.draw(|f| ui(f, &mut self.state, self.args, self.runtime_info))?;
106+
}
107+
97108
Ok(())
98109
}
99110

100111
fn on_timer(&mut self) {
101112
self.state.tick_timer();
102113
self.runtime_info.fps = self.frame_in_second;
103114
self.frame_in_second = 0;
115+
self.should_render = ShouldRender::Render;
104116
}
105117
}
106118

src/state/dropping.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{buffer::RenderBuffer, Cell, Column, CellType, Mode, EachFrameImpl};
1+
use super::{buffer::RenderBuffer, Cell, CellType, Column, EachFrameImpl, Mode, ShouldRender};
22

33
pub struct DroppingState {
44
pub threshold: u16,
@@ -104,13 +104,14 @@ impl DroppingState {
104104
}
105105

106106
impl EachFrameImpl for DroppingState {
107-
fn on_frame(&mut self, rb: &mut super::buffer::RenderBuffer, seed: u64, frame: u64) {
107+
fn on_frame(&mut self, rb: &mut super::buffer::RenderBuffer, seed: u64, frame: u64) -> ShouldRender {
108108
// each column
109109
for i in 0..rb.buf.len() {
110110
Self::clean_latest_drop(&mut rb.buf[i]);
111111
Self::drop(&mut rb.buf[i], frame, self.mode);
112112
}
113113

114114
self.new_drop(rb, seed);
115+
ShouldRender::Render
115116
}
116117
}

src/state/mod.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,28 @@ pub type Cell = ArrayVec<[CellType; 3]>;
2020
pub type Column = Rc<RefCell<Vec<Cell>>>;
2121

2222
pub trait EachFrameImpl {
23-
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64);
23+
fn on_frame(&mut self, _: &mut RenderBuffer, _: u64, _: u64) -> ShouldRender {
24+
ShouldRender::Skip
25+
}
26+
}
27+
28+
#[derive(PartialEq, Eq, Copy, Clone)]
29+
pub enum ShouldRender {
30+
Render,
31+
Skip,
32+
}
33+
34+
impl ShouldRender {
35+
pub fn or(self, sr: Self) -> Self {
36+
match sr {
37+
Self::Skip => self,
38+
Self::Render => sr,
39+
}
40+
}
41+
42+
pub fn is_render(&self) -> bool {
43+
*self == Self::Render
44+
}
2445
}
2546

2647
#[derive(Copy, Clone, Default)]
@@ -225,11 +246,12 @@ impl<T: EachFrameImpl> State<T> {
225246
self.timer = Timer::new();
226247
}
227248

228-
pub fn tick(&mut self) {
249+
pub fn tick(&mut self) -> ShouldRender {
229250
self.frame = if self.frame == u64::MAX { 0 } else { self.frame.saturating_add(1) };
230251
self.seed = self.rng.next_u64();
231-
self.weather.on_frame(&mut self.rb, self.seed, self.frame);
232-
self.timer_state.on_frame(&mut self.rb, self.seed, self.frame);
252+
253+
self.weather.on_frame(&mut self.rb, self.seed, self.frame)
254+
.or(self.timer_state.on_frame(&mut self.rb, self.seed, self.frame))
233255
}
234256
}
235257

src/state/tail.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cell::RefCell;
22

3-
use super::{buffer::RenderBuffer, wind::WindMode, Cell, Column, CellType, EachFrameImpl};
3+
use super::{buffer::RenderBuffer, wind::WindMode, Cell, CellType, Column, EachFrameImpl, ShouldRender};
44

55
#[derive(Default, Copy, Clone, Eq, PartialEq)]
66
pub enum TailMode {
@@ -110,11 +110,13 @@ impl TailState {
110110
}
111111

112112
impl EachFrameImpl for TailState {
113-
fn on_frame(&mut self, rb: &mut RenderBuffer, _seed: u64, _frame: u64) {
113+
fn on_frame(&mut self, rb: &mut RenderBuffer, _seed: u64, _frame: u64) -> ShouldRender {
114114
match self.mode {
115115
TailMode::Left => Self::render_left_tail(&mut rb.buf),
116116
TailMode::Right => Self::render_right_tail(&mut rb.buf),
117117
TailMode::Default => Self::render_default_tail(&mut rb.buf),
118-
}
118+
};
119+
120+
ShouldRender::Render
119121
}
120122
}

src/state/timer.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ratatui::layout::Rect;
66

77
use crate::widget::timer::{TIMER_LAYOUT_HEIGHT, TIMER_LAYOUT_WIDTH};
88

9-
use super::{buffer::RenderBuffer, Direction, EachFrameImpl, Position};
9+
use super::{buffer::RenderBuffer, Direction, EachFrameImpl, Position, ShouldRender};
1010

1111
#[derive(Copy, Clone)]
1212
pub struct Timer {
@@ -90,9 +90,12 @@ impl ColonState {
9090
}
9191

9292
impl EachFrameImpl for ColonState {
93-
fn on_frame(&mut self, _: &mut RenderBuffer, _: u64, frame: u64) {
93+
fn on_frame(&mut self, _: &mut RenderBuffer, _: u64, frame: u64) -> ShouldRender {
9494
if self.blink && frame % 24 == 0 {
95-
self.toggle()
95+
self.toggle();
96+
ShouldRender::Render
97+
} else {
98+
ShouldRender::Skip
9699
}
97100
}
98101
}
@@ -166,26 +169,27 @@ impl TimerState {
166169
self.pos.1 == 0 || (self.pos.1 + TIMER_LAYOUT_HEIGHT) >= self.boundary.height
167170
}
168171

169-
fn handle_mode(&mut self, frame: u64) {
172+
fn handle_mode(&mut self, frame: u64) -> ShouldRender {
170173
if self.mode.is_none() {
171-
return;
174+
return ShouldRender::Skip;
172175
}
173176

174177
if frame % 8 > 0 {
175-
return;
178+
return ShouldRender::Skip;
176179
}
177180

178181
match self.mode.unwrap() {
179182
TimerRenderMode::Dvd(_) => self.on_dvd_frame(),
180183
}
181184

182185
self.area = Self::get_area_with_pos(self.pos);
186+
ShouldRender::Render
183187
}
184188
}
185189

186190
impl EachFrameImpl for TimerState {
187-
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) {
188-
self.handle_mode(frame);
189-
self.colon.on_frame(rb, seed, frame);
191+
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) -> ShouldRender {
192+
self.handle_mode(frame)
193+
.or(self.colon.on_frame(rb, seed, frame))
190194
}
191195
}

src/state/wind.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{buffer::RenderBuffer, EachFrameImpl};
1+
use super::{buffer::RenderBuffer, EachFrameImpl, ShouldRender};
22

33
pub trait WindImpl {
44
fn direction(&self) -> WindDirection;
@@ -74,7 +74,7 @@ impl WindState {
7474
}
7575

7676
impl EachFrameImpl for WindState {
77-
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, _: u64) {
77+
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, _: u64) -> ShouldRender {
7878
self.direction = match self.mode {
7979
WindMode::Disable => WindDirection::None,
8080
WindMode::OnlyLeft => WindDirection::Left,
@@ -83,7 +83,7 @@ impl EachFrameImpl for WindState {
8383
};
8484

8585
if self.mode == WindMode::Disable {
86-
return;
86+
return ShouldRender::Skip;
8787
}
8888

8989
if self.frame == 0 || self.direction == WindDirection::None {
@@ -98,7 +98,7 @@ impl EachFrameImpl for WindState {
9898
}
9999

100100
if self.direction == WindDirection::None {
101-
return;
101+
return ShouldRender::Skip;
102102
}
103103

104104
self.frame = self.frame.saturating_sub(1);
@@ -114,5 +114,7 @@ impl EachFrameImpl for WindState {
114114
if self.direction == WindDirection::Left {
115115
rb.buf.reverse();
116116
}
117+
118+
ShouldRender::Render
117119
}
118120
}

src/weather/dropping.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
cli::Args,
3-
state::{buffer::RenderBuffer, dropping::DroppingState, tail::TailState, wind::WindState, EachFrameImpl, Mode},
3+
state::{buffer::RenderBuffer, dropping::DroppingState, tail::TailState, wind::WindState, EachFrameImpl, Mode, ShouldRender},
44
widget::{weather::GeneralWeatherWidget, AsWeatherWidget},
55
};
66

@@ -29,9 +29,9 @@ impl GeneralDropping {
2929
impl WeatherImpl for GeneralDropping {}
3030

3131
impl EachFrameImpl for GeneralDropping {
32-
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) {
33-
self.wind.on_frame(rb, seed, frame);
34-
self.dropping.on_frame(rb, seed, frame);
32+
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) -> ShouldRender {
33+
self.wind.on_frame(rb, seed, frame)
34+
.or(self.dropping.on_frame(rb, seed, frame))
3535
}
3636
}
3737

@@ -70,10 +70,10 @@ impl TailDropping {
7070
impl WeatherImpl for TailDropping {}
7171

7272
impl EachFrameImpl for TailDropping {
73-
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) {
74-
self.wind.on_frame(rb, seed, frame);
75-
self.dropping.on_frame(rb, seed, frame);
76-
self.tail.on_frame(rb, seed, frame);
73+
fn on_frame(&mut self, rb: &mut RenderBuffer, seed: u64, frame: u64) -> ShouldRender {
74+
self.wind.on_frame(rb, seed, frame)
75+
.or(self.dropping.on_frame(rb, seed, frame))
76+
.or(self.tail.on_frame(rb, seed, frame))
7777
}
7878
}
7979

src/weather/empty.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ use super::WeatherImpl;
77

88
pub struct EmptyWeather;
99

10-
impl EachFrameImpl for EmptyWeather {
11-
fn on_frame(&mut self, _: &mut crate::state::buffer::RenderBuffer, _: u64, _: u64) {}
12-
}
13-
1410
impl AsWeatherWidget for EmptyWeather {
1511
type Weather = GeneralWeatherWidget;
1612

@@ -19,4 +15,5 @@ impl AsWeatherWidget for EmptyWeather {
1915
}
2016
}
2117

18+
impl EachFrameImpl for EmptyWeather {}
2219
impl WeatherImpl for EmptyWeather {}

src/weather/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
cli::Args,
3-
state::{EachFrameImpl, Mode},
3+
state::{EachFrameImpl, Mode, ShouldRender},
44
weather::{dropping::{GeneralDropping, TailDropping}, empty::EmptyWeather}, widget::{weather::GeneralWeatherWidget, AsWeatherWidget},
55
};
66

@@ -23,7 +23,7 @@ impl Weather {
2323
}
2424

2525
impl EachFrameImpl for Weather {
26-
fn on_frame(&mut self, rb: &mut crate::state::buffer::RenderBuffer, seed: u64, frame: u64) {
26+
fn on_frame(&mut self, rb: &mut crate::state::buffer::RenderBuffer, seed: u64, frame: u64) -> ShouldRender {
2727
self.0.on_frame(rb, seed, frame)
2828
}
2929
}

0 commit comments

Comments
 (0)