Eliminate extra renders

Currently has a bug where screen is blank at startup. That aside,
Alacritty uses basically 0 CPU now. The input thread is still separate
from the render thread, but, given the ability to wake the event loop,
it may be possible to merge them again. I'm not sure if that's actually
desirable.

Performance is seemingly unchanged.
This commit is contained in:
Joe Wilm 2016-08-31 21:16:17 -07:00
parent 0a94ccfcca
commit 0517f376be
3 changed files with 98 additions and 32 deletions

6
Cargo.lock generated
View File

@ -7,7 +7,7 @@ dependencies = [
"errno 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"font 0.1.0",
"gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c)",
"glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403)",
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -285,7 +285,7 @@ dependencies = [
[[package]]
name = "glutin"
version = "0.6.1"
source = "git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c#45092a8e2f6706a7b2c613ff212341754e346c9c"
source = "git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403#16ed800f68022a37203434bd3b542ff5400c1403"
dependencies = [
"android_glue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -906,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "65256ec4dc2592e6f05bfc1ca3b956a4e0698aa90b1dff1f5687d55a5a3fd59a"
"checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55"
"checksum gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "13a363b2a5264b600e530db2f14b3c487098e6dee0655f2810ea779385cbac5a"
"checksum glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c)" = "<none>"
"checksum glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403)" = "<none>"
"checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c"
"checksum inotify 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8458c07bdbdaf309c80e2c3304d14c3db64e7465d4f07cf589ccb83fd0ff31a"
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"

View File

@ -13,7 +13,7 @@ notify = "2.6"
bitflags = "*"
font = { path = "./font" }
errno = "0.1.6"
parking_lot = "0.3.1"
parking_lot = { version = "0.3.1", features = ["nightly"] }
serde = "0.8"
serde_yaml = "0.4"
serde_macros = "0.8"

View File

@ -52,21 +52,45 @@ mod io;
mod sync;
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};
use sync::PriorityMutex;
use parking_lot::{Condvar, Mutex};
use config::Config;
use io::{Utf8Chars, Utf8CharsError};
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use sync::PriorityMutex;
use term::Term;
use tty::process_should_exit;
use util::thread;
use io::{Utf8Chars, Utf8CharsError};
/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;
struct Waiter {
mutex: Mutex<bool>,
cond: Condvar,
}
impl Waiter {
pub fn new() -> Waiter {
Waiter {
mutex: Mutex::new(false),
cond: Condvar::new(),
}
}
pub fn notify(&self) {
self.cond.notify_one();
}
pub fn wait(&self) {
let mut guard = self.mutex.lock();
self.cond.wait(&mut guard);
}
}
/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
unsafe {
@ -126,6 +150,9 @@ fn main() {
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);
let waiter = Arc::new(Waiter::new());
let dirty = Arc::new(AtomicBool::new(false));
// Create renderer
let mut renderer = QuadRenderer::new(width, height);
@ -163,7 +190,11 @@ fn main() {
let terminal = Arc::new(PriorityMutex::new(terminal));
let pty_reader_thread = spawn_pty_reader(terminal.clone(), reader);
let pty_reader_thread = spawn_pty_reader(terminal.clone(),
reader,
waiter.clone(),
dirty.clone(),
window.create_window_proxy());
let window = Arc::new(window);
@ -173,11 +204,15 @@ fn main() {
renderer,
glyph_cache,
render_timer,
rx);
rx,
waiter.clone(),
dirty);
handle_window_events(&mut writer, terminal, window);
pty_reader_thread.join().ok();
waiter.notify();
render_thread.join().ok();
println!("Goodbye");
}
@ -219,12 +254,23 @@ fn handle_window_events<W>(writer: &mut W,
&mut input::WriteNotifier(writer),
*terminal.mode())
},
glutin::Event::Awakened => {
if process_should_exit() {
println!("input thread exitting");
break;
}
}
_ => (),
}
}
}
fn spawn_pty_reader<R>(terminal: Arc<PriorityMutex<Term>>, mut pty: R) -> std::thread::JoinHandle<()>
fn spawn_pty_reader<R>(terminal: Arc<PriorityMutex<Term>>,
mut pty: R,
waiter: Arc<Waiter>,
dirty: Arc<AtomicBool>,
proxy: ::glutin::WindowProxy) -> std::thread::JoinHandle<()>
where R: std::io::Read + Send + 'static,
{
thread::spawn_named("pty reader", move || {
@ -233,40 +279,51 @@ fn spawn_pty_reader<R>(terminal: Arc<PriorityMutex<Term>>, mut pty: R) -> std::t
let mut pty_parser = ansi::Parser::new();
loop {
let got = pty.read(&mut buf[start..]).expect("pty fd active");
let mut remain = 0;
if let Ok(got) = pty.read(&mut buf[start..]) {
let mut remain = 0;
// if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes.
let end = start + got;
let mut terminal = terminal.lock_low();
for c in Utf8Chars::new(&buf[..end]) {
match c {
Ok(c) => pty_parser.advance(&mut *terminal, c),
Err(err) => match err {
Utf8CharsError::IncompleteUtf8(unused) => {
remain = unused;
break;
},
_ => panic!("{}", err),
// if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes.
let end = start + got;
{
let mut terminal = terminal.lock_low();
for c in Utf8Chars::new(&buf[..end]) {
match c {
Ok(c) => pty_parser.advance(&mut *terminal, c),
Err(err) => match err {
Utf8CharsError::IncompleteUtf8(unused) => {
remain = unused;
break;
},
_ => panic!("{}", err),
}
}
}
}
}
// Move any leftover bytes to front of buffer
for i in 0..remain {
buf[i] = buf[end - (remain - i)];
dirty.store(true, Ordering::Release);
waiter.notify();
// Move any leftover bytes to front of buffer
for i in 0..remain {
buf[i] = buf[end - (remain - i)];
}
start = remain;
} else {
proxy.wakeup_event_loop();
break;
}
start = remain;
}
})
}
fn spawn_renderer(window: Arc<glutin::Window>,
terminal: Arc<PriorityMutex<Term>>,
terminal_mutex: Arc<PriorityMutex<Term>>,
mut renderer: QuadRenderer,
mut glyph_cache: GlyphCache,
render_timer: bool,
rx: mpsc::Receiver<(u32, u32)>) -> std::thread::JoinHandle<()> {
rx: mpsc::Receiver<(u32, u32)>,
waiter: Arc<Waiter>,
dirty: Arc<AtomicBool>) -> std::thread::JoinHandle<()> {
thread::spawn_named("render", move || {
unsafe {
let _ = window.make_current();
@ -277,7 +334,15 @@ fn spawn_renderer(window: Arc<glutin::Window>,
// Scope ensures terminal lock isn't held when calling swap_buffers
{
// Acquire term lock
let mut terminal = terminal.lock_high();
let mut terminal = terminal_mutex.lock_high();
if !dirty.load(Ordering::Acquire) {
drop(terminal);
waiter.wait();
terminal = terminal_mutex.lock_high();
}
dirty.store(false, Ordering::Release);
// Resize events new_size and are handled outside the poll_events
// iterator. This has the effect of coalescing multiple resize
@ -328,6 +393,7 @@ fn spawn_renderer(window: Arc<glutin::Window>,
if process_should_exit() {
break;
} else {
}
}
})