Skip to content

Commit

Permalink
Add fallback GLES2 renderer
Browse files Browse the repository at this point in the history
Currently Alacritty only works on hardware which supports OpenGL 3.3 or
more, which can become problematic with older devices. This patch adds a
new GLES2 renderer, since it is much more widely supported, especially
on weaker hardware like phones or a Raspberry Pi.

While the GLES2 renderer is slower than the OpenGL 3.3+ version, it is
still significantly faster than software rendering. However because of
this performance difference it is only used when necessary and there
should be no difference for machines supporting OpenGL 3.3+.

The two renderers are largely independent and separated in the
`renderer/text/glsl3` and `renderer/text/gles2` modules. Separate
shaders are also required for text rendering. The rectangle rendering
for underlines and the visual bell works identically for both versions,
but does have some version-specific shader code.

Fixes alacritty#128.

Co-authored-by: Christian Duerr <[email protected]>
  • Loading branch information
kchibisov and chrisduerr authored Mar 2, 2022
1 parent 00383ae commit 1880522
Show file tree
Hide file tree
Showing 18 changed files with 2,066 additions and 1,241 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Track and report surface damage information to Wayland compositors
- Escape sequence for undercurl, dotted and dashed underlines (`CSI 4 : [3-5] m`)
- `ToggleMaximized` key binding action to (un-)maximize the active window, not bound by default
- Support for OpenGL ES 2.0

### Changed

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For everyone else, the detailed instructions to install Alacritty can be found

### Requirements

- OpenGL 3.3 or higher
- At least OpenGL ES 2.0
- [Windows] ConPTY support (Windows 10 version 1809 or higher)

## Configuration
Expand Down
57 changes: 57 additions & 0 deletions alacritty/res/gles2/text.f.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
varying mediump vec2 TexCoords;
varying mediump vec3 fg;
varying highp float colored;
varying mediump vec4 bg;

uniform highp int renderingPass;
uniform sampler2D mask;

#define COLORED 1

mediump float max_rgb(mediump vec3 mask) {
return max(max(mask.r, mask.g), mask.b);
}

void render_text() {
mediump vec4 mask = texture2D(mask, TexCoords);
mediump float m_rgb = max_rgb(mask.rgb);

if (renderingPass == 1) {
gl_FragColor = vec4(mask.rgb, m_rgb);
} else if (renderingPass == 2) {
gl_FragColor = bg * (vec4(m_rgb) - vec4(mask.rgb, m_rgb));
} else {
gl_FragColor = vec4(fg, 1.) * vec4(mask.rgb, m_rgb);
}
}

// Render colored bitmaps.
void render_bitmap() {
if (renderingPass == 2) {
discard;
}
mediump vec4 mask = texture2D(mask, TexCoords);
if (renderingPass == 1) {
gl_FragColor = mask.aaaa;
} else {
gl_FragColor = mask;
}
}

void main() {
// Handle background pass drawing before anything else.
if (renderingPass == 0) {
if (bg.a == 0.0) {
discard;
}

gl_FragColor = vec4(bg.rgb * bg.a, bg.a);
return;
}

if (int(colored) == COLORED) {
render_bitmap();
} else {
render_text();
}
}
46 changes: 46 additions & 0 deletions alacritty/res/gles2/text.v.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Cell coords.
attribute vec2 cellCoords;

// Glyph coords.
attribute vec2 glyphCoords;

// uv mapping.
attribute vec2 uv;

// Text foreground rgb packed together with cell flags. textColor.a
// are the bitflags; consult RenderingGlyphFlags in renderer/mod.rs
// for the possible values.
attribute vec4 textColor;

// Background color.
attribute vec4 backgroundColor;

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

uniform highp int renderingPass;
uniform vec4 projection;

void main() {
vec2 projectionOffset = projection.xy;
vec2 projectionScale = projection.zw;

vec2 position;
if (renderingPass == 0) {
TexCoords = vec2(0, 0);
position = cellCoords;
} else {
TexCoords = uv;
position = glyphCoords;
}

fg = vec3(float(textColor.r), float(textColor.g), float(textColor.b)) / 255.;
colored = float(textColor.a);
bg = vec4(float(backgroundColor.r), float(backgroundColor.g), float(backgroundColor.b),
float(backgroundColor.a)) / 255.;

vec2 finalPosition = projectionOffset + position * projectionScale;
gl_Position = vec4(finalPosition, 0., 1.);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#version 330 core
in vec2 TexCoords;
flat in vec4 fg;
flat in vec4 bg;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#version 330 core
// Cell properties.
layout(location = 0) in vec2 gridCoords;

Expand Down
118 changes: 63 additions & 55 deletions alacritty/res/rect.f.glsl
Original file line number Diff line number Diff line change
@@ -1,38 +1,51 @@
#version 330 core
#if defined(GLES2_RENDERER)
#define float_t mediump float
#define color_t mediump vec4
#define FRAG_COLOR gl_FragColor

varying color_t color;

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

flat in vec4 color;
out vec4 FragColor;
uniform int rectKind;
#define FRAG_COLOR FragColor

uniform float cellWidth;
uniform float cellHeight;
uniform float paddingY;
uniform float paddingX;
flat in color_t color;

uniform float underlinePosition;
uniform float underlineThickness;
#endif

uniform float undercurlPosition;
uniform int rectKind;
uniform float_t cellWidth;
uniform float_t cellHeight;
uniform float_t paddingY;
uniform float_t paddingX;

uniform float_t underlinePosition;
uniform float_t underlineThickness;

uniform float_t undercurlPosition;

#define UNDERCURL 1
#define DOTTED 2
#define DASHED 3

#define PI 3.1415926538

vec4 draw_undercurl(int x, int y) {
color_t draw_undercurl(float_t x, float_t y) {
// We use `undercurlPosition` as an amplitude, since it's half of the descent
// value.
float undercurl =
undercurlPosition / 2. * cos(float(x) * 2 * PI / cellWidth) +
+ undercurlPosition - 1.;
float_t undercurl = undercurlPosition / 2. * cos(x * 2. * PI / cellWidth)
+ undercurlPosition - 1.;

float undercurlTop = undercurl + max((underlineThickness - 1), 0);
float undercurlBottom = undercurl - max((underlineThickness - 1), 0);
float_t undercurlTop = undercurl + max((underlineThickness - 1.), 0.);
float_t undercurlBottom = undercurl - max((underlineThickness - 1.), 0.);

// Compute resulted alpha based on distance from `gl_FragCoord.y` to the
// cosine curve.
float alpha = 1.;
float_t alpha = 1.;
if (y > undercurlTop || y < undercurlBottom) {
alpha = 1. - min(abs(undercurlTop - y), abs(undercurlBottom - y));
}
Expand All @@ -43,80 +56,75 @@ vec4 draw_undercurl(int x, int y) {

// When the dot size increases we can use AA to make spacing look even and the
// dots rounded.
vec4 draw_dotted_aliased(float x, float y) {
int dotNumber = int(x / underlineThickness);
color_t draw_dotted_aliased(float_t x, float_t y) {
float_t dotNumber = floor(x / underlineThickness);

float radius = underlineThickness / 2.;
float centerY = underlinePosition - 1.;
float_t radius = underlineThickness / 2.;
float_t centerY = underlinePosition - 1.;

float leftCenter = (dotNumber - dotNumber % 2) * underlineThickness + radius;
float rightCenter = leftCenter + 2 * underlineThickness;
float_t leftCenter = (dotNumber - mod(dotNumber, 2.)) * underlineThickness + radius;
float_t rightCenter = leftCenter + 2. * underlineThickness;

float distanceLeft = sqrt(pow(x - leftCenter, 2) + pow(y - centerY, 2));
float distanceRight = sqrt(pow(x - rightCenter, 2) + pow(y - centerY, 2));
float_t distanceLeft = sqrt(pow(x - leftCenter, 2.) + pow(y - centerY, 2.));
float_t distanceRight = sqrt(pow(x - rightCenter, 2.) + pow(y - centerY, 2.));

float alpha = max(1 - (min(distanceLeft, distanceRight) - radius), 0);
float_t alpha = max(1. - (min(distanceLeft, distanceRight) - radius), 0.);
return vec4(color.rgb, alpha);
}

/// Draw dotted line when dot is just a single pixel.
vec4 draw_dotted(int x, int y) {
int cellEven = 0;
color_t draw_dotted(float_t x, float_t y) {
float_t cellEven = 0.;

// Since the size of the dot and its gap combined is 2px we should ensure that
// spacing will be even. If the cellWidth is even it'll work since we start
// with dot and end with gap. However if cellWidth is odd, the cell will start
// and end with a dot, creating a dash. To resolve this issue, we invert the
// pattern every two cells.
if (int(cellWidth) % 2 != 0) {
cellEven = int((gl_FragCoord.x - paddingX) / cellWidth) % 2;
if (int(mod(cellWidth, 2.)) != 0) {
cellEven = mod((gl_FragCoord.x - paddingX) / cellWidth, 2.);
}

// Since we use the entire descent area for dotted underlines, we limit its
// height to a single pixel so we don't draw bars instead of dots.
float alpha = 1. - abs(round(underlinePosition - 1.) - y);
if (x % 2 != cellEven) {
alpha = 0;
float_t alpha = 1. - abs(floor(underlinePosition - 0.5) - y);
if (int(mod(x, 2.)) != int(cellEven)) {
alpha = 0.;
}

return vec4(color.rgb, alpha);
}

vec4 draw_dashed(int x) {
color_t draw_dashed(float_t x) {
// Since dashes of adjacent cells connect with each other our dash length is
// half of the desired total length.
int halfDashLen = int(cellWidth) / 4;
float_t halfDashLen = floor(cellWidth / 4.);

float alpha = 1.;
float_t alpha = 1.;

// Check if `x` coordinate is where we should draw gap.
if (x > halfDashLen && x < cellWidth - halfDashLen - 1) {
if (x > halfDashLen && x < cellWidth - halfDashLen - 1.) {
alpha = 0.;
}

return vec4(color.rgb, alpha);
}

void main() {
int x = int(gl_FragCoord.x - paddingX) % int(cellWidth);
int y = int(gl_FragCoord.y - paddingY) % int(cellHeight);

switch (rectKind) {
case UNDERCURL:
FragColor = draw_undercurl(x, y);
break;
case DOTTED:
if (underlineThickness < 2) {
FragColor = draw_dotted(x, y);
float_t x = floor(mod(gl_FragCoord.x - paddingX, cellWidth));
float_t y = floor(mod(gl_FragCoord.y - paddingY, cellHeight));

if (rectKind == UNDERCURL) {
FRAG_COLOR = draw_undercurl(x, y);
} else if (rectKind == DOTTED) {
if (underlineThickness < 2.) {
FRAG_COLOR = draw_dotted(x, y);
} else {
FragColor = draw_dotted_aliased(x, y);
FRAG_COLOR = draw_dotted_aliased(x, y);
}
break;
case DASHED:
FragColor = draw_dashed(x);
break;
default:
FragColor = color;
break;
} else if (rectKind == DASHED) {
FRAG_COLOR = draw_dashed(x);
} else {
FRAG_COLOR = color;
}
}
11 changes: 8 additions & 3 deletions alacritty/res/rect.v.glsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#version 330 core
#if defined(GLES2_RENDERER)
attribute vec2 aPos;
attribute vec4 aColor;

varying mediump vec4 color;
#else
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec4 aColor;

flat out vec4 color;
#endif

void main()
{
void main() {
color = aColor;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
Loading

0 comments on commit 1880522

Please sign in to comment.