From e503baf2e753a1cc8c287f10fb1460635d093168 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 27 Oct 2016 08:43:23 -0700 Subject: [PATCH] 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. --- Cargo.toml | 6 ++- res/text.f.glsl | 1 - src/renderer/mod.rs | 98 +++++++++++++++++++++++++++++++-------------- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f87a0cbe..d3132ddc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ name = "alacritty" version = "0.1.0" authors = ["Joe Wilm "] license = "Apache-2.0" -exclude = ["res/*"] build = "build.rs" [dependencies] @@ -21,6 +20,11 @@ vte = "0.1.2" mio = "0.6" copypasta = { path = "./copypasta" } +[features] +default = [] +# Enabling this feature makes shaders automatically reload when changed +live-shader-reload = [] + [build-dependencies] gl_generator = "0.5" diff --git a/res/text.f.glsl b/res/text.f.glsl index 3bdcbe20..770c1a36 100644 --- a/res/text.f.glsl +++ b/res/text.f.glsl @@ -31,5 +31,4 @@ void main() alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0); color = vec4(fg, 1.0); } - } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 7ddf1d01..f1b30373 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. use std::collections::HashMap; -use std::ffi::CString; use std::fs::File; use std::io::{self, Read}; use std::mem::size_of; @@ -33,9 +32,18 @@ use term::{self, cell, Cell}; 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_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 pub trait LoadGlyph { /// Load the rasterized glyph into GPU memory @@ -448,34 +456,36 @@ impl QuadRenderer { let should_reload = Arc::new(AtomicBool::new(false)); let should_reload2 = should_reload.clone(); - ::std::thread::spawn(move || { - let (tx, rx) = ::std::sync::mpsc::channel(); - let mut watcher = Watcher::new(tx).unwrap(); - watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); - watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); + if cfg!(feature = "live-shader-reload") { + ::std::thread::spawn(move || { + let (tx, rx) = ::std::sync::mpsc::channel(); + let mut watcher = Watcher::new(tx).unwrap(); + watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); + watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); - loop { - let event = rx.recv().expect("watcher event"); - let ::notify::Event { path, op } = event; + loop { + let event = rx.recv().expect("watcher event"); + let ::notify::Event { path, op } = event; - if let Ok(op) = op { - if op.contains(op::RENAME) { - 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); - } + if let Ok(op) = op { + if op.contains(op::RENAME) { + continue; } - // This is last event we see after saving in vim - should_reload2.store(true, Ordering::Relaxed); + 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 + should_reload2.store(true, Ordering::Relaxed); + } } } - } - }); + }); + } let mut renderer = QuadRenderer { program: program, @@ -751,9 +761,26 @@ impl ShaderProgram { } pub fn new(width: u32, height: u32) -> Result { - let vertex_shader = ShaderProgram::create_shader(TEXT_SHADER_V_PATH, gl::VERTEX_SHADER)?; - let fragment_shader = ShaderProgram::create_shader(TEXT_SHADER_F_PATH, - gl::FRAGMENT_SHADER)?; + let vertex_source = if cfg!(feature = "live-shader-reload") { + None + } 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); unsafe { @@ -855,11 +882,24 @@ impl ShaderProgram { } - fn create_shader(path: &str, kind: GLenum) -> Result { - let source = CString::new(read_file(path)?).unwrap(); + fn create_shader( + path: &str, + kind: GLenum, + source: Option<&'static str> + ) -> Result { + 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 = 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); shader };