Skip to content

Commit

Permalink
Add fallback GLES2 renderer
Browse files Browse the repository at this point in the history
This commit adds a fallback GLES2 renderer for platforms not supporting
OpenGL 3.3 providing ability to run alacritty on those. While its
performance is slightly slower than glsl3 version it's way faster than
software rendering with sofware emulated GL (e.g. llvmpipe), since
that's what alacritty used on platforms not supporting required OpenGL
version.

Fixes alacritty#128.
  • Loading branch information
kchibisov committed Feb 22, 2022
1 parent 4734b2b commit 411c73a
Show file tree
Hide file tree
Showing 18 changed files with 2,030 additions and 1,238 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/).
- Option `font.builtin_box_drawing` to disable the built-in font for drawing box characters
- Track and report surface damage information to Wayland compositors
- Escape sequence for undercurl, dotted and dashed underlines (`CSI 4 : [3-5] m`)
- 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
- OpenGL ES 2.0 or higher
- [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
120 changes: 62 additions & 58 deletions alacritty/res/rect.f.glsl
Original file line number Diff line number Diff line change
@@ -1,45 +1,54 @@
#version 330 core
#if defined(GLES2_RENDERER)
#define float_t mediump float
#define color_t mediump vec4
#define FRAG_COLOR gl_FragColor

// We're using `origin_upper_left`, since we only known about padding from left
// and top. If we use default `origin_bottom_left` we won't be able to offset
// `gl_FragCoord` properly to align with the terminal grid.
layout(origin_upper_left) in vec4 gl_FragCoord;
varying color_t color;

flat in vec4 color;
#else
#define float_t float
#define int_t int
#define color_t vec4

out vec4 FragColor;
#define FRAG_COLOR FragColor

uniform int rectKind;
layout(origin_upper_left) in vec4 gl_FragCoord;

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 =
-1. * undercurlPosition / 2. * cos(float(x) * 2 * PI / cellWidth) +
float_t undercurl =
-1. * undercurlPosition / 2. * cos(x * 2. * PI / cellWidth) +
cellHeight - undercurlPosition;

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 @@ -50,80 +59,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 = cellHeight - underlinePosition;
float_t radius = underlineThickness / 2.;
float_t centerY = cellHeight - underlinePosition;

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(cellHeight - underlinePosition) - y);
if (x % 2 != cellEven) {
alpha = 0;
float_t alpha = 1. - abs(floor(cellHeight - 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 411c73a

Please sign in to comment.