diff options
author | Joe Wilm <joe@jwilm.com> | 2016-05-21 11:08:50 -0700 |
---|---|---|
committer | Joe Wilm <joe@jwilm.com> | 2016-05-21 11:08:50 -0700 |
commit | 855ae756973990be35186d554562a75f692c06e7 (patch) | |
tree | 82506bd1a0e75cf3d04cac86e0043fcc0dd6ba8f | |
parent | c70acbac0b721ea2f1b1442898c22aee0f360ef2 (diff) | |
download | alacritty-855ae756973990be35186d554562a75f692c06e7.tar.gz alacritty-855ae756973990be35186d554562a75f692c06e7.zip |
Add render time meter
Optimization is impossible without measurement!
-rw-r--r-- | src/grid.rs | 10 | ||||
-rw-r--r-- | src/main.rs | 69 | ||||
-rw-r--r-- | src/meter.rs | 104 | ||||
-rw-r--r-- | src/renderer/mod.rs | 11 | ||||
-rw-r--r-- | src/text.rs | 2 |
5 files changed, 173 insertions, 23 deletions
diff --git a/src/grid.rs b/src/grid.rs index 0418ed53..86a2e45f 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -9,13 +9,15 @@ pub fn num_cells_axis(cell_width: u32, cell_sep: i32, screen_width: u32) -> u32 #[derive(Clone)] pub struct Cell { - pub character: Option<String>, + pub character: String, } impl Cell { - pub fn new(c: Option<String>) -> Cell { + pub fn new<S>(c: S) -> Cell + where S: Into<String> + { Cell { - character: c, + character: c.into(), } } } @@ -76,7 +78,7 @@ pub struct Row(Vec<Cell>); impl Row { pub fn new(columns: usize) -> Row { - Row(vec![Cell::new(None); columns]) + Row(vec![Cell::new(""); columns]) } pub fn cols(&self) -> usize { diff --git a/src/main.rs b/src/main.rs index ef025bea..3b1d7335 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod list_fonts; mod text; mod renderer; mod grid; +mod meter; use renderer::{Glyph, QuadRenderer}; use text::FontDesc; @@ -25,6 +26,28 @@ static INIT_LIST: &'static str = "abcdefghijklmnopqrstuvwxyz\ 01234567890\ ~`!@#$%^&*()[]{}-_=+\\|\"/?.,<>;:"; +type GlyphCache = HashMap<String, renderer::Glyph>; + +/// Render a string in a predefined location. Used for printing render time for profiling and +/// optimization. +fn render_string(s: &str, + renderer: &QuadRenderer, + glyph_cache: &GlyphCache, + cell_width: u32, + color: &renderer::Rgb) +{ + let (mut x, mut y) = (200f32, 20f32); + + for c in s.chars() { + let s: String = c.escape_default().collect(); + if let Some(glyph) = glyph_cache.get(&s[..]) { + renderer.render(glyph, x, y, color); + } + + x += cell_width as f32 + 2f32; + } +} + fn main() { let window = glutin::Window::new().unwrap(); let (width, height) = window.get_inner_size_pixels().unwrap(); @@ -83,7 +106,7 @@ fn main() { continue; } - grid[row][col] = grid::Cell::new(Some(c.escape_default().collect())); + grid[row][col] = grid::Cell::new(c.escape_default().collect::<String>()); col += 1; } @@ -102,35 +125,49 @@ fn main() { let renderer = QuadRenderer::new(width, height); - for event in window.wait_events() { + let mut meter = meter::Meter::new(); + 'main_loop: loop { + for event in window.poll_events() { + match event { + glutin::Event::Closed => break 'main_loop, + _ => println!("event: {:?}", event) + } + } + unsafe { gl::ClearColor(0.0, 0.0, 0.00, 1.0); gl::Clear(gl::COLOR_BUFFER_BIT); } - for i in 0..grid.rows() { - let row = &grid[i]; - for j in 0..row.cols() { - let cell = &row[j]; - if let Some(ref c) = cell.character { - if let Some(glyph) = glyph_cache.get(&c[..]) { - let y = (cell_height as f32 + sep_y as f32) * (i as f32); - let x = (cell_width as f32 + sep_x as f32) * (j as f32); + { + let color = renderer::Rgb { r: 0.917, g: 0.917, b: 0.917 }; + let _sampler = meter.sampler(); + + for i in 0..grid.rows() { + let row = &grid[i]; + for j in 0..row.cols() { + let cell = &row[j]; + if !cell.character.is_empty() { + if let Some(glyph) = glyph_cache.get(&cell.character[..]) { + let y = (cell_height as f32 + sep_y as f32) * (i as f32); + let x = (cell_width as f32 + sep_x as f32) * (j as f32); - let y_inverted = (height as f32) - y - (cell_height as f32); + let y_inverted = (height as f32) - y - (cell_height as f32); - renderer.render(glyph, x, y_inverted); + renderer.render(glyph, x, y_inverted, &color); + } } } } } + let timing = format!("{:.3} usec", meter.average()); + let color = renderer::Rgb { r: 0.835, g: 0.306, b: 0.325 }; + render_string(&timing[..], &renderer, &glyph_cache, cell_width, &color); + window.swap_buffers().unwrap(); - match event { - glutin::Event::Closed => break, - _ => () - } + // ::std::thread::sleep(::std::time::Duration::from_millis(17)); } } diff --git a/src/meter.rs b/src/meter.rs new file mode 100644 index 00000000..3badf330 --- /dev/null +++ b/src/meter.rs @@ -0,0 +1,104 @@ +//! Rendering time meter +//! +//! Used to track rendering times and provide moving averages. +//! +//! # Examples +//! +//! ```rust +//! // create a meter +//! let mut meter = Meter::new(); +//! +//! // Sample something. +//! { +//! let _sampler = meter.sampler(); +//! } +//! +//! // Get the moving average. The meter tracks a fixed number of samles, and the average won't mean +//! // much until it's filled up at least once. +//! printf!("Average time: {}", meter.average()); + +use std::time::{Instant, Duration}; + +const NUM_SAMPLES: usize = 60; + +/// The meter +pub struct Meter { + /// Track last 60 timestamps + times: [f64; NUM_SAMPLES], + + /// Average sample time in microseconds + avg: f64, + + /// Index of next time to update. + index: usize, +} + +/// Sampler +/// +/// Samplers record how long they are "alive" for and update the meter on drop. +pub struct Sampler<'a> { + /// Reference to meter that created the sampler + meter: &'a mut Meter, + + // When the sampler was created + created_at: Instant, +} + +impl<'a> Sampler<'a> { + fn new(meter: &'a mut Meter) -> Sampler<'a> { + Sampler { + meter: meter, + created_at: Instant::now(), + } + } + + #[inline] + fn alive_duration(&self) -> Duration { + self.created_at.elapsed() + } +} + +impl<'a> Drop for Sampler<'a> { + fn drop(&mut self) { + // Work around borrowck + let duration = self.alive_duration(); + self.meter.add_sample(duration); + } +} + +impl Meter { + /// Create a meter + pub fn new() -> Meter { + Meter { + times: [0.0; NUM_SAMPLES], + avg: 0.0, + index: 0, + } + } + + /// Get a sampler + pub fn sampler(&mut self) -> Sampler { + Sampler::new(self) + } + + /// Get the current average sample duration in microseconds + pub fn average(&self) -> f64 { + self.avg + } + + /// Add a sample + /// + /// Used by Sampler::drop. + fn add_sample(&mut self, sample: Duration) { + let mut usec = 0f64; + + usec += (sample.subsec_nanos() as f64) / 1e3; + usec += (sample.as_secs() as f64) * 1e6; + + let prev = self.times[self.index]; + self.times[self.index] = usec; + self.avg -= prev / NUM_SAMPLES as f64; + self.avg += usec / NUM_SAMPLES as f64; + self.index = (self.index + 1) % NUM_SAMPLES; + } +} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 4666981b..b88357b3 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -32,6 +32,13 @@ pub struct PackedVertex { v: f32, } +#[derive(Debug)] +pub struct Rgb { + pub r: f32, + pub g: f32, + pub b: f32, +} + impl QuadRenderer { // TODO should probably hand this a transform instead of width/height pub fn new(width: u32, height: u32) -> QuadRenderer { @@ -92,11 +99,11 @@ impl QuadRenderer { } } - pub fn render(&self, glyph: &Glyph, x: f32, y: f32) { + pub fn render(&self, glyph: &Glyph, x: f32, y: f32, color: &Rgb) { self.program.activate(); unsafe { // set color - gl::Uniform3f(self.program.u_color, 0.917, 0.917, 0.917); + gl::Uniform3f(self.program.u_color, color.r, color.g, color.b); } let rect = get_rect(glyph, x, y); diff --git a/src/text.rs b/src/text.rs index 0eb08606..a5ec3114 100644 --- a/src/text.rs +++ b/src/text.rs @@ -93,7 +93,7 @@ impl Rasterizer { unsafe { let ft_lib = self.library.raw(); - freetype::ffi::FT_Library_SetLcdFilter(ft_lib, freetype::ffi::FT_LCD_FILTER_LIGHT); + freetype::ffi::FT_Library_SetLcdFilter(ft_lib, freetype::ffi::FT_LCD_FILTER_DEFAULT); } let bitmap = glyph.bitmap(); |