mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-11 13:51:01 -05:00
Add render time meter
Optimization is impossible without measurement!
This commit is contained in:
parent
c70acbac0b
commit
855ae75697
5 changed files with 173 additions and 23 deletions
10
src/grid.rs
10
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 {
|
||||
|
|
69
src/main.rs
69
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();
|
||||
|
||||
let y_inverted = (height as f32) - y - (cell_height as f32);
|
||||
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);
|
||||
|
||||
renderer.render(glyph, x, y_inverted);
|
||||
let y_inverted = (height as f32) - y - (cell_height as f32);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
104
src/meter.rs
Normal file
104
src/meter.rs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue