diff options
Diffstat (limited to 'alacritty/src/renderer/mod.rs')
-rw-r--r-- | alacritty/src/renderer/mod.rs | 238 |
1 files changed, 34 insertions, 204 deletions
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index 715d33b5..6e3d2ab9 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use std::fmt::{self, Display, Formatter}; use std::hash::BuildHasherDefault; use std::mem::size_of; -use std::{io, ptr}; +use std::{fmt, ptr}; use bitflags::bitflags; use crossfont::{ @@ -24,9 +23,18 @@ use crate::display::content::RenderableCell; use crate::gl; use crate::gl::types::*; use crate::renderer::rects::{RectRenderer, RenderRect}; +use crate::renderer::shader::{ShaderError, ShaderProgram}; pub mod builtin_font; pub mod rects; +mod shader; + +macro_rules! cstr { + ($s:literal) => { + // This can be optimized into an no-op with pre-allocated NUL-terminated bytes. + unsafe { std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr().cast()) } + }; +} // Shader source. static TEXT_SHADER_F: &str = include_str!("../../res/text.f.glsl"); @@ -45,30 +53,31 @@ pub trait LoadGlyph { #[derive(Debug)] pub enum Error { - ShaderCreation(ShaderCreationError), + /// Shader error. + Shader(ShaderError), } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Error::ShaderCreation(err) => err.source(), + Error::Shader(err) => err.source(), } } } -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Error::ShaderCreation(err) => { + Error::Shader(err) => { write!(f, "There was an error initializing the shaders: {}", err) }, } } } -impl From<ShaderCreationError> for Error { - fn from(val: ShaderCreationError) -> Self { - Error::ShaderCreation(val) +impl From<ShaderError> for Error { + fn from(val: ShaderError) -> Self { + Error::Shader(val) } } @@ -77,8 +86,8 @@ impl From<ShaderCreationError> for Error { /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a". #[derive(Debug)] pub struct TextShaderProgram { - /// Program id. - id: GLuint, + /// Shader program. + program: ShaderProgram, /// Projection scale and offset uniform. u_projection: GLint, @@ -707,7 +716,7 @@ impl QuadRenderer { F: FnOnce(RenderApi<'_>) -> T, { unsafe { - gl::UseProgram(self.program.id); + gl::UseProgram(self.program.id()); self.program.set_term_uniforms(props); gl::BindVertexArray(self.vao); @@ -756,7 +765,7 @@ impl QuadRenderer { self.set_viewport(size); // Update projection. - gl::UseProgram(self.program.id); + gl::UseProgram(self.program.id()); self.program.update_projection( size.width(), size.height(), @@ -1004,56 +1013,18 @@ impl<'a> Drop for RenderApi<'a> { } impl TextShaderProgram { - pub fn new() -> Result<TextShaderProgram, ShaderCreationError> { - let vertex_shader = create_shader(gl::VERTEX_SHADER, TEXT_SHADER_V)?; - let fragment_shader = create_shader(gl::FRAGMENT_SHADER, TEXT_SHADER_F)?; - let program = create_program(vertex_shader, fragment_shader)?; - - unsafe { - gl::DeleteShader(fragment_shader); - gl::DeleteShader(vertex_shader); - gl::UseProgram(program); - } - - macro_rules! cptr { - ($thing:expr) => { - $thing.as_ptr() as *const _ - }; - } - - macro_rules! assert_uniform_valid { - ($uniform:expr) => { - assert!($uniform != gl::INVALID_VALUE as i32); - assert!($uniform != gl::INVALID_OPERATION as i32); - }; - ( $( $uniform:expr ),* ) => { - $( assert_uniform_valid!($uniform); )* - }; - } - - // get uniform locations - let (projection, cell_dim, background) = unsafe { - ( - gl::GetUniformLocation(program, cptr!(b"projection\0")), - gl::GetUniformLocation(program, cptr!(b"cellDim\0")), - gl::GetUniformLocation(program, cptr!(b"backgroundPass\0")), - ) - }; - - assert_uniform_valid!(projection, cell_dim, background); - - let shader = Self { - id: program, - u_projection: projection, - u_cell_dim: cell_dim, - u_background: background, - }; - - unsafe { - gl::UseProgram(0); - } + pub fn new() -> Result<TextShaderProgram, Error> { + let program = ShaderProgram::new(TEXT_SHADER_V, TEXT_SHADER_F)?; + Ok(Self { + u_projection: program.get_uniform_location(cstr!("projection"))?, + u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?, + u_background: program.get_uniform_location(cstr!("backgroundPass"))?, + program, + }) + } - Ok(shader) + fn id(&self) -> GLuint { + self.program.id() } fn update_projection(&self, width: f32, height: f32, padding_x: f32, padding_y: f32) { @@ -1090,147 +1061,6 @@ impl TextShaderProgram { } } -impl Drop for TextShaderProgram { - fn drop(&mut self) { - unsafe { - gl::DeleteProgram(self.id); - } - } -} - -pub fn create_program(vertex: GLuint, fragment: GLuint) -> Result<GLuint, ShaderCreationError> { - unsafe { - let program = gl::CreateProgram(); - gl::AttachShader(program, vertex); - gl::AttachShader(program, fragment); - gl::LinkProgram(program); - - let mut success: GLint = 0; - gl::GetProgramiv(program, gl::LINK_STATUS, &mut success); - - if success == i32::from(gl::TRUE) { - Ok(program) - } else { - Err(ShaderCreationError::Link(get_program_info_log(program))) - } - } -} - -pub fn create_shader(kind: GLenum, source: &'static str) -> Result<GLuint, ShaderCreationError> { - let len: [GLint; 1] = [source.len() as GLint]; - - let shader = unsafe { - let shader = gl::CreateShader(kind); - gl::ShaderSource(shader, 1, &(source.as_ptr() as *const _), len.as_ptr()); - gl::CompileShader(shader); - shader - }; - - let mut success: GLint = 0; - unsafe { - gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); - } - - if success == GLint::from(gl::TRUE) { - Ok(shader) - } else { - // Read log. - let log = get_shader_info_log(shader); - - // Cleanup. - unsafe { - gl::DeleteShader(shader); - } - - Err(ShaderCreationError::Compile(log)) - } -} - -fn get_program_info_log(program: GLuint) -> String { - // Get expected log length. - let mut max_length: GLint = 0; - unsafe { - gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut max_length); - } - - // Read the info log. - let mut actual_length: GLint = 0; - let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize); - unsafe { - gl::GetProgramInfoLog(program, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _); - } - - // Build a string. - unsafe { - buf.set_len(actual_length as usize); - } - - // XXX should we expect OpenGL to return garbage? - String::from_utf8(buf).unwrap() -} - -fn get_shader_info_log(shader: GLuint) -> String { - // Get expected log length. - let mut max_length: GLint = 0; - unsafe { - gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut max_length); - } - - // Read the info log. - let mut actual_length: GLint = 0; - let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize); - unsafe { - gl::GetShaderInfoLog(shader, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _); - } - - // Build a string. - unsafe { - buf.set_len(actual_length as usize); - } - - // XXX should we expect OpenGL to return garbage? - String::from_utf8(buf).unwrap() -} - -#[derive(Debug)] -pub enum ShaderCreationError { - /// Error reading file. - Io(io::Error), - - /// Error compiling shader. - Compile(String), - - /// Problem linking. - Link(String), -} - -impl std::error::Error for ShaderCreationError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - ShaderCreationError::Io(err) => err.source(), - _ => None, - } - } -} - -impl Display for ShaderCreationError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - ShaderCreationError::Io(err) => write!(f, "Unable to read shader: {}", err), - ShaderCreationError::Compile(log) => { - write!(f, "Failed compiling shader: {}", log) - }, - ShaderCreationError::Link(log) => write!(f, "Failed linking shader: {}", log), - } - } -} - -impl From<io::Error> for ShaderCreationError { - fn from(val: io::Error) -> Self { - ShaderCreationError::Io(val) - } -} - /// Manages a single texture atlas. /// /// The strategy for filling an atlas looks roughly like this: |