Skip to content

Commit

Permalink
Support dual source blending in GLES2 renderer
Browse files Browse the repository at this point in the history
GLES2 has GL_EXT_blend_func_extended extension that enables
dual-source blending, so essentially we can reuse fragment shader
from GLSL3 renderer and do 1 rendering pass instead of 3 for the
text.

Co-authored-by: Kirill Chibisov <[email protected]>
Co-authored-by: Christian Duerr <[email protected]>
  • Loading branch information
3 people authored Jun 8, 2022
1 parent 29b1ff5 commit 6dc670c
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 72 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions alacritty/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ libc = "0.2"
unicode-width = "0.1"
bitflags = "1"
dirs = "3.0.1"
once_cell = "1.12"

[build-dependencies]
gl_generator = "0.14.0"
Expand Down
65 changes: 49 additions & 16 deletions alacritty/res/glsl3/text.f.glsl
Original file line number Diff line number Diff line change
@@ -1,40 +1,73 @@
#if defined(GLES2_RENDERER)
// Require extension for dual source blending to work on GLES2.
#extension GL_EXT_blend_func_extended: require

#define int_t highp int
#define float_t highp float
#define vec3_t mediump vec3
#define texture texture2D

varying mediump vec2 TexCoords;
varying mediump vec3 fg;
varying highp float colored;
varying mediump vec4 bg;

#define FRAG_COLOR gl_FragColor
#define ALPHA_MASK gl_SecondaryFragColorEXT
#else

#define int_t int
#define float_t float
#define vec3_t vec3

in vec2 TexCoords;
flat in vec4 fg;
flat in vec4 bg;
uniform int backgroundPass;

layout(location = 0, index = 0) out vec4 color;
layout(location = 0, index = 1) out vec4 alphaMask;

uniform sampler2D mask;
#define FRAG_COLOR color
#define ALPHA_MASK alphaMask
#endif

#define COLORED 2
#define COLORED 1

uniform int_t renderingPass;
uniform sampler2D mask;

void main() {
if (backgroundPass != 0) {
if (renderingPass == 0) {
if (bg.a == 0.0) {
discard;
}

alphaMask = vec4(1.0);

ALPHA_MASK = vec4(1.0);
// Premultiply background color by alpha.
color = vec4(bg.rgb * bg.a, bg.a);
} else if ((int(fg.a) & COLORED) != 0) {
FRAG_COLOR = vec4(bg.rgb * bg.a, bg.a);
return;
}

#if !defined(GLES2_RENDERER)
float_t colored = fg.a;
#endif

// The wide char information is already stripped, so it's safe to check for equality here.
if (int(colored) == COLORED) {
// Color glyphs, like emojis.
vec4 glyphColor = texture(mask, TexCoords);
alphaMask = vec4(glyphColor.a);
FRAG_COLOR = texture(mask, TexCoords);
ALPHA_MASK = vec4(FRAG_COLOR.a);

// Revert alpha premultiplication.
if (glyphColor.a != 0) {
glyphColor.rgb = vec3(glyphColor.rgb / glyphColor.a);
if (FRAG_COLOR.a != 0.0) {
FRAG_COLOR.rgb = vec3(FRAG_COLOR.rgb / FRAG_COLOR.a);
}

color = vec4(glyphColor.rgb, 1.0);
FRAG_COLOR = vec4(FRAG_COLOR.rgb, 1.0);
} else {
// Regular text glyphs.
vec3 textColor = texture(mask, TexCoords).rgb;
alphaMask = vec4(textColor, textColor.r);
color = vec4(fg.rgb, 1.0);
vec3_t textColor = texture(mask, TexCoords).rgb;
ALPHA_MASK = vec4(textColor, textColor.r);
FRAG_COLOR = vec4(fg.rgb, 1.0);
}
}
28 changes: 18 additions & 10 deletions alacritty/res/glsl3/text.v.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ flat out vec4 bg;
uniform vec2 cellDim;
uniform vec4 projection;

uniform int backgroundPass;
uniform int renderingPass;

#define WIDE_CHAR 1
#define WIDE_CHAR 2

void main() {
vec2 projectionOffset = projection.xy;
Expand All @@ -39,12 +39,23 @@ void main() {
// Position of cell from top-left
vec2 cellPosition = cellDim * gridCoords;

if (backgroundPass != 0) {
fg = vec4(textColor.rgb / 255.0, textColor.a);
bg = backgroundColor / 255.0;

float occupiedCells = 1;
if ((int(fg.a) >= WIDE_CHAR)) {
// Update wide char x dimension so it'll cover the following spacer.
occupiedCells = 2;

// Since we don't perform bitwise operations due to limitations of
// the GLES2 renderer,we subtract wide char bits keeping only colored.
fg.a = round(fg.a - WIDE_CHAR);
}

if (renderingPass == 0) {
vec2 backgroundDim = cellDim;
if ((int(textColor.a) & WIDE_CHAR) != 0) {
// Update wide char x dimension so it'll cover the following spacer.
backgroundDim.x *= 2;
}
backgroundDim.x *= occupiedCells;

vec2 finalPosition = cellPosition + backgroundDim * position;
gl_Position =
vec4(projectionOffset + projectionScale * finalPosition, 0.0, 1.0);
Expand All @@ -63,7 +74,4 @@ void main() {
vec2 uvSize = uv.zw;
TexCoords = uvOffset + position * uvSize;
}

bg = backgroundColor / 255.0;
fg = vec4(textColor.rgb / 255.0, textColor.a);
}
1 change: 0 additions & 1 deletion alacritty/res/rect.f.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ varying color_t color;

#else
#define float_t float
#define int_t int
#define color_t vec4

out vec4 FragColor;
Expand Down
39 changes: 39 additions & 0 deletions alacritty/src/renderer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::collections::HashSet;
use std::ffi::CStr;
use std::fmt;

use crossfont::Metrics;
use log::info;
use once_cell::sync::OnceCell;

use alacritty_terminal::index::Point;
use alacritty_terminal::term::cell::Flags;
Expand Down Expand Up @@ -218,3 +220,40 @@ impl Renderer {
}
}
}

struct GlExtensions;

impl GlExtensions {
/// Check if the given `extension` is supported.
///
/// This function will lazyly load OpenGL extensions.
fn contains(extension: &str) -> bool {
static OPENGL_EXTENSIONS: OnceCell<HashSet<&'static str>> = OnceCell::new();

OPENGL_EXTENSIONS.get_or_init(Self::load_extensions).contains(extension)
}

/// Load available OpenGL extensions.
fn load_extensions() -> HashSet<&'static str> {
unsafe {
let extensions = gl::GetString(gl::EXTENSIONS);

if extensions.is_null() {
let mut extensions_number = 0;
gl::GetIntegerv(gl::NUM_EXTENSIONS, &mut extensions_number);

(0..extensions_number as gl::types::GLuint)
.flat_map(|i| {
let extension = CStr::from_ptr(gl::GetStringi(gl::EXTENSIONS, i) as *mut _);
extension.to_str()
})
.collect()
} else {
match CStr::from_ptr(extensions as *mut _).to_str() {
Ok(ext) => ext.split_whitespace().collect(),
Err(_) => HashSet::new(),
}
}
}
}
}
Loading

0 comments on commit 6dc670c

Please sign in to comment.