Commit b79574ee authored by Joe Wilm's avatar Joe Wilm Committed by GitHub

Fix solid background color opacity (#847)

Since landing the patch adding transparency support to Alacritty,
there's been an issue where othewise solid background cells were also
being rendered partially transparent. Now, all filled background cells
are rendered fully opaque.

Some logic was added to support discarding filled backgrounds which had
the same color as the default background. This means that, if the
default background is #000 and a cell has that background, it will never
be rendered opaque. This may not be correct.

Note that many truecolor vim color schemes print spaces for default
colored background cells. Performance can be dramatically improved by
using ctermbg=NONE guibg=NONE to skip rendering those cells.
parent 7a5eebd0
......@@ -14,7 +14,7 @@
#version 330 core
in vec2 TexCoords;
in vec3 fg;
in vec3 bg;
in vec4 bg;
flat in float vb;
flat in int background;
......@@ -27,8 +27,11 @@ uniform sampler2D mask;
void main()
{
if (background != 0) {
if (bg.a == 0.0)
discard;
alphaMask = vec4(1.0);
color = vec4(bg + vb, 1.0) * bgOpacity;
color = vec4(bg.rgb + vb, 1.0);
} else {
vec3 textColor = texture(mask, TexCoords).rgb;
alphaMask = vec4(textColor, textColor.r);
......
......@@ -26,11 +26,11 @@ layout (location = 3) in vec4 uv;
// text fg color
layout (location = 4) in vec3 textColor;
// Background color
layout (location = 5) in vec3 backgroundColor;
layout (location = 5) in vec4 backgroundColor;
out vec2 TexCoords;
out vec3 fg;
out vec3 bg;
out vec4 bg;
// Terminal properties
uniform vec2 termDim;
......@@ -63,7 +63,6 @@ void main()
gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0);
TexCoords = vec2(0, 0);
} else {
// Glyphs are offset within their cell; account for y-flip
vec2 cellOffset = vec2(glyphOffset.x, glyphOffset.y - glyphSize.y);
......@@ -76,6 +75,6 @@ void main()
vb = visualBell;
background = backgroundPass;
bg = backgroundColor / vec3(255.0, 255.0, 255.0);
bg = vec4(backgroundColor.rgb / 255.0, backgroundColor.a);
fg = textColor / vec3(255.0, 255.0, 255.0);
}
#!/bin/bash
printf "Fg=Black, Bg=Background \e[30;49mTEST\e[m\n"
printf "Fg=Black, Bg=Black \e[30;40mTEST\e[m\n"
printf "Fg=Foreground,Bg=Background \e[39;49mTEST\e[m\n"
printf "Fg=Foreground,Bg=Black \e[39;40mTEST\e[m\n"
printf "Fg=Foreground,Bg=White \e[39;47mTEST\e[m\n"
printf "Fg=White, Bg=Foreground \e[37;39mTEST\e[m\n"
printf "Fg=Black, Bg=Background, Inverse \e[7;30;49mTEST\e[m\n"
printf "Fg=Black, Bg=Black, Inverse \e[7;30;40mTEST\e[m\n"
printf "Fg=Foreground,Bg=Background, Inverse \e[7;39;49mTEST\e[m\n"
printf "Fg=Foreground,Bg=Black, Inverse \e[7;39;40mTEST\e[m\n"
printf "Fg=Foreground,Bg=White, Inverse \e[7;39;47mTEST\e[m\n"
printf "Fg=White, Bg=Foreground, Inverse \e[7;37;39mTEST\e[m\n"
......@@ -186,6 +186,7 @@ impl Alpha {
self.0 = Self::clamp_to_valid_range(value);
}
#[inline(always)]
pub fn get(&self) -> f32 {
self.0
}
......@@ -1093,6 +1094,7 @@ impl Config {
&self.colors
}
#[inline]
pub fn background_opacity(&self) -> Alpha {
self.background_opacity
}
......
......@@ -125,8 +125,6 @@ pub struct ShaderProgram {
padding_x: f32,
padding_y: f32,
u_bg_opacity: GLint,
}
......@@ -351,6 +349,7 @@ struct InstanceData {
bg_r: f32,
bg_g: f32,
bg_b: f32,
bg_a: f32,
}
#[derive(Debug)]
......@@ -436,6 +435,7 @@ impl Batch {
bg_r: cell.bg.r as f32,
bg_g: cell.bg.g as f32,
bg_b: cell.bg.b as f32,
bg_a: cell.bg_alpha,
});
}
......@@ -568,7 +568,7 @@ impl QuadRenderer {
gl::EnableVertexAttribArray(4);
gl::VertexAttribDivisor(4, 1);
// color
gl::VertexAttribPointer(5, 3,
gl::VertexAttribPointer(5, 4,
gl::FLOAT, gl::FALSE,
size_of::<InstanceData>() as i32,
(13 * size_of::<f32>()) as *const _);
......@@ -648,7 +648,6 @@ impl QuadRenderer {
self.program.activate();
self.program.set_term_uniforms(props);
self.program.set_visual_bell(visual_bell_intensity as _);
self.program.set_bg_opacity(config.background_opacity().get());
gl::BindVertexArray(self.vao);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
......@@ -692,17 +691,22 @@ impl QuadRenderer {
}
pub fn reload_shaders(&mut self, config: &Config, size: Size<Pixels<u32>>) {
info!("Reloading shaders");
warn!("Reloading shaders ...");
let program = match ShaderProgram::new(config, size) {
Ok(program) => program,
Ok(program) => {
warn!(" ... OK");
program
},
Err(err) => {
match err {
ShaderCreationError::Io(err) => {
error!("Error reading shader file: {}", err);
},
ShaderCreationError::Compile(path, log) => {
error!("Error compiling shader at {:?}", path);
let _ = io::copy(&mut log.as_bytes(), &mut io::stdout());
error!("Error compiling shader at {:?}\n{}", path, log);
}
ShaderCreationError::Link(log) => {
error!("Error reloading shaders: {}", log);
}
}
......@@ -791,6 +795,7 @@ impl<'a> RenderApi<'a> {
bg: color,
fg: Rgb { r: 0, g: 0, b: 0 },
flags: cell::Flags::empty(),
bg_alpha: 1.0
})
.collect::<Vec<_>>();
......@@ -957,7 +962,7 @@ impl ShaderProgram {
gl::FRAGMENT_SHADER,
frag_source
)?;
let program = ShaderProgram::create_program(vertex_shader, fragment_shader);
let program = ShaderProgram::create_program(vertex_shader, fragment_shader)?;
unsafe {
gl::DeleteShader(vertex_shader);
......@@ -980,14 +985,13 @@ impl ShaderProgram {
}
// get uniform locations
let (projection, term_dim, cell_dim, visual_bell, background, bg_opacity) = unsafe {
let (projection, term_dim, cell_dim, visual_bell, background) = unsafe {
(
gl::GetUniformLocation(program, cptr!(b"projection\0")),
gl::GetUniformLocation(program, cptr!(b"termDim\0")),
gl::GetUniformLocation(program, cptr!(b"cellDim\0")),
gl::GetUniformLocation(program, cptr!(b"visualBell\0")),
gl::GetUniformLocation(program, cptr!(b"backgroundPass\0")),
gl::GetUniformLocation(program, cptr!(b"bgOpacity\0")),
)
};
......@@ -1002,7 +1006,6 @@ impl ShaderProgram {
u_background: background,
padding_x: config.padding().x.floor(),
padding_y: config.padding().y.floor(),
u_bg_opacity: bg_opacity,
};
shader.update_projection(*size.width as f32, *size.height as f32);
......@@ -1063,13 +1066,7 @@ impl ShaderProgram {
}
}
fn set_bg_opacity(&self, bg_opacity: f32) {
unsafe {
gl::Uniform1f(self.u_bg_opacity, bg_opacity);
}
}
fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {
fn create_program(vertex: GLuint, fragment: GLuint) -> Result<GLuint, ShaderCreationError> {
unsafe {
let program = gl::CreateProgram();
gl::AttachShader(program, vertex);
......@@ -1080,10 +1077,10 @@ impl ShaderProgram {
gl::GetProgramiv(program, gl::LINK_STATUS, &mut success);
if success != (gl::TRUE as GLint) {
error!("{}", get_program_info_log(program));
panic!("failed to link shader program");
Err(ShaderCreationError::Link(get_program_info_log(program)))
} else {
Ok(program)
}
program
}
}
......@@ -1198,13 +1195,16 @@ pub enum ShaderCreationError {
/// Error compiling shader
Compile(PathBuf, String),
/// Problem linking
Link(String),
}
impl ::std::error::Error for ShaderCreationError {
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
ShaderCreationError::Io(ref err) => Some(err),
ShaderCreationError::Compile(_, _) => None,
_ => None,
}
}
......@@ -1212,6 +1212,7 @@ impl ::std::error::Error for ShaderCreationError {
match *self {
ShaderCreationError::Io(ref err) => err.description(),
ShaderCreationError::Compile(ref _path, ref s) => s.as_str(),
ShaderCreationError::Link(ref s) => s.as_str(),
}
}
}
......@@ -1223,6 +1224,9 @@ impl ::std::fmt::Display for ShaderCreationError {
ShaderCreationError::Compile(ref _path, ref s) => {
write!(f, "failed compiling shader: {}", s)
},
ShaderCreationError::Link(ref s) => {
write!(f, "failed linking shader: {}", s)
},
}
}
}
......
......@@ -299,6 +299,14 @@ impl<'a> RenderableCellsIter<'a> {
}
}
#[inline]
fn compute_bg_alpha(&self, bg: &Color) -> f32 {
match *bg {
Color::Named(NamedColor::Background) => 0.0,
_ => 1.0
}
}
fn compute_bg_rgb(&self, bg: &Color) -> Rgb {
match *bg {
Color::Spec(rgb) => rgb,
......@@ -314,6 +322,7 @@ pub struct RenderableCell {
pub c: char,
pub fg: Rgb,
pub bg: Rgb,
pub bg_alpha: f32,
pub flags: cell::Flags,
}
......@@ -363,19 +372,35 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
};
// Apply inversion and lookup RGB values
let (fg, bg) = if selected || cell.inverse() {
(self.compute_bg_rgb(&cell.bg), self.compute_fg_rgb(&cell.fg, &cell))
let mut bg_alpha = 1.0;
let fg_rgb;
let bg_rgb;
let invert = selected ^ cell.inverse();
if invert {
if cell.fg == cell.bg {
bg_rgb = self.colors[NamedColor::Foreground];
fg_rgb = self.colors[NamedColor::Background];
bg_alpha = 1.0
} else {
bg_rgb = self.compute_fg_rgb(&cell.fg, &cell);
fg_rgb = self.compute_bg_rgb(&cell.bg);
}
} else {
(self.compute_fg_rgb(&cell.fg, &cell), self.compute_bg_rgb(&cell.bg))
};
fg_rgb = self.compute_fg_rgb(&cell.fg, &cell);
bg_rgb = self.compute_bg_rgb(&cell.bg);
bg_alpha = self.compute_bg_alpha(&cell.bg);
}
return Some(RenderableCell {
line: line,
column: column,
flags: cell.flags,
c: cell.c,
fg: fg,
bg: bg,
fg: fg_rgb,
bg: bg_rgb,
bg_alpha: bg_alpha,
})
}
......@@ -976,7 +1001,7 @@ impl Term {
self.mode,
config,
selection,
self.cursor_style
self.cursor_style,
)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment