Live shader reloading is now a feature

Which means it can be disabled in release builds. No more working on a
renderer feature and actually breaking the Alacritty your editor is
running inside.
This commit is contained in:
Joe Wilm 2016-10-27 08:43:23 -07:00
parent ea07f03ac9
commit e503baf2e7
3 changed files with 74 additions and 31 deletions

View File

@ -3,7 +3,6 @@ name = "alacritty"
version = "0.1.0" version = "0.1.0"
authors = ["Joe Wilm <joe@jwilm.com>"] authors = ["Joe Wilm <joe@jwilm.com>"]
license = "Apache-2.0" license = "Apache-2.0"
exclude = ["res/*"]
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
@ -21,6 +20,11 @@ vte = "0.1.2"
mio = "0.6" mio = "0.6"
copypasta = { path = "./copypasta" } copypasta = { path = "./copypasta" }
[features]
default = []
# Enabling this feature makes shaders automatically reload when changed
live-shader-reload = []
[build-dependencies] [build-dependencies]
gl_generator = "0.5" gl_generator = "0.5"

View File

@ -31,5 +31,4 @@ void main()
alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0); alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0);
color = vec4(fg, 1.0); color = vec4(fg, 1.0);
} }
} }

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CString;
use std::fs::File; use std::fs::File;
use std::io::{self, Read}; use std::io::{self, Read};
use std::mem::size_of; use std::mem::size_of;
@ -33,9 +32,18 @@ use term::{self, cell, Cell};
use super::Rgb; use super::Rgb;
// Shader paths for live reload
static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl"); static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl");
static TEXT_SHADER_V_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl"); static TEXT_SHADER_V_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl");
// Shader source which is used when live-shader-reload feature is disable
static TEXT_SHADER_F: &'static str = include_str!(
concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl")
);
static TEXT_SHADER_V: &'static str = include_str!(
concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl")
);
/// LoadGlyph allows for copying a rasterized glyph into graphics memory /// LoadGlyph allows for copying a rasterized glyph into graphics memory
pub trait LoadGlyph { pub trait LoadGlyph {
/// Load the rasterized glyph into GPU memory /// Load the rasterized glyph into GPU memory
@ -448,34 +456,36 @@ impl QuadRenderer {
let should_reload = Arc::new(AtomicBool::new(false)); let should_reload = Arc::new(AtomicBool::new(false));
let should_reload2 = should_reload.clone(); let should_reload2 = should_reload.clone();
::std::thread::spawn(move || { if cfg!(feature = "live-shader-reload") {
let (tx, rx) = ::std::sync::mpsc::channel(); ::std::thread::spawn(move || {
let mut watcher = Watcher::new(tx).unwrap(); let (tx, rx) = ::std::sync::mpsc::channel();
watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); let mut watcher = Watcher::new(tx).unwrap();
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader");
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader");
loop { loop {
let event = rx.recv().expect("watcher event"); let event = rx.recv().expect("watcher event");
let ::notify::Event { path, op } = event; let ::notify::Event { path, op } = event;
if let Ok(op) = op { if let Ok(op) = op {
if op.contains(op::RENAME) { if op.contains(op::RENAME) {
continue; continue;
}
if op.contains(op::IGNORED) {
if let Some(path) = path.as_ref() {
if let Err(err) = watcher.watch(path) {
println!("failed to establish watch on {:?}: {:?}", path, err);
}
} }
// This is last event we see after saving in vim if op.contains(op::IGNORED) {
should_reload2.store(true, Ordering::Relaxed); if let Some(path) = path.as_ref() {
if let Err(err) = watcher.watch(path) {
println!("failed to establish watch on {:?}: {:?}", path, err);
}
}
// This is last event we see after saving in vim
should_reload2.store(true, Ordering::Relaxed);
}
} }
} }
} });
}); }
let mut renderer = QuadRenderer { let mut renderer = QuadRenderer {
program: program, program: program,
@ -751,9 +761,26 @@ impl ShaderProgram {
} }
pub fn new(width: u32, height: u32) -> Result<ShaderProgram, ShaderCreationError> { pub fn new(width: u32, height: u32) -> Result<ShaderProgram, ShaderCreationError> {
let vertex_shader = ShaderProgram::create_shader(TEXT_SHADER_V_PATH, gl::VERTEX_SHADER)?; let vertex_source = if cfg!(feature = "live-shader-reload") {
let fragment_shader = ShaderProgram::create_shader(TEXT_SHADER_F_PATH, None
gl::FRAGMENT_SHADER)?; } else {
Some(TEXT_SHADER_V)
};
let vertex_shader = ShaderProgram::create_shader(
TEXT_SHADER_V_PATH,
gl::VERTEX_SHADER,
vertex_source
)?;
let frag_source = if cfg!(feature = "live-shader-reload") {
None
} else {
Some(TEXT_SHADER_F)
};
let fragment_shader = ShaderProgram::create_shader(
TEXT_SHADER_F_PATH,
gl::FRAGMENT_SHADER,
frag_source
)?;
let program = ShaderProgram::create_program(vertex_shader, fragment_shader); let program = ShaderProgram::create_program(vertex_shader, fragment_shader);
unsafe { unsafe {
@ -855,11 +882,24 @@ impl ShaderProgram {
} }
fn create_shader(path: &str, kind: GLenum) -> Result<GLuint, ShaderCreationError> { fn create_shader(
let source = CString::new(read_file(path)?).unwrap(); path: &str,
kind: GLenum,
source: Option<&'static str>
) -> Result<GLuint, ShaderCreationError> {
let from_disk;
let source = if let Some(src) = source {
src
} else {
from_disk = read_file(path)?;
&from_disk[..]
};
let len: [GLint; 1] = [source.len() as GLint];
let shader = unsafe { let shader = unsafe {
let shader = gl::CreateShader(kind); let shader = gl::CreateShader(kind);
gl::ShaderSource(shader, 1, &source.as_ptr(), ptr::null()); gl::ShaderSource(shader, 1, &(source.as_ptr() as *const i8), len.as_ptr());
gl::CompileShader(shader); gl::CompileShader(shader);
shader shader
}; };