mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-11 13:51:01 -05:00
Fix cursor and underlines always being black
Some old hardware doesn't like universal shader approach for all the rectangle kinds leading to ALU instruction limits. This commit fixes it by splitting the shader per rectangle kind. Fixes #6417.
This commit is contained in:
parent
c3b915b695
commit
5b1dd38806
6 changed files with 97 additions and 67 deletions
|
@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- `--help` output for `--class` does not match man pages
|
- `--help` output for `--class` does not match man pages
|
||||||
|
- Cursor and underlines always being black on very old hardware
|
||||||
|
|
||||||
## 0.11.0
|
## 0.11.0
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ flat in color_t color;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform int rectKind;
|
|
||||||
uniform float_t cellWidth;
|
uniform float_t cellWidth;
|
||||||
uniform float_t cellHeight;
|
uniform float_t cellHeight;
|
||||||
uniform float_t paddingY;
|
uniform float_t paddingY;
|
||||||
|
@ -27,12 +26,9 @@ uniform float_t underlineThickness;
|
||||||
|
|
||||||
uniform float_t undercurlPosition;
|
uniform float_t undercurlPosition;
|
||||||
|
|
||||||
#define UNDERCURL 1
|
|
||||||
#define DOTTED 2
|
|
||||||
#define DASHED 3
|
|
||||||
|
|
||||||
#define PI 3.1415926538
|
#define PI 3.1415926538
|
||||||
|
|
||||||
|
#if defined(DRAW_UNDERCURL)
|
||||||
color_t draw_undercurl(float_t x, float_t y) {
|
color_t draw_undercurl(float_t x, float_t y) {
|
||||||
// We use `undercurlPosition` as an amplitude, since it's half of the descent
|
// We use `undercurlPosition` as an amplitude, since it's half of the descent
|
||||||
// value.
|
// value.
|
||||||
|
@ -55,7 +51,9 @@ color_t draw_undercurl(float_t x, float_t y) {
|
||||||
// The result is an alpha mask on a rect, which leaves only curve opaque.
|
// The result is an alpha mask on a rect, which leaves only curve opaque.
|
||||||
return vec4(color.rgb, alpha);
|
return vec4(color.rgb, alpha);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DRAW_DOTTED)
|
||||||
// When the dot size increases we can use AA to make spacing look even and the
|
// When the dot size increases we can use AA to make spacing look even and the
|
||||||
// dots rounded.
|
// dots rounded.
|
||||||
color_t draw_dotted_aliased(float_t x, float_t y) {
|
color_t draw_dotted_aliased(float_t x, float_t y) {
|
||||||
|
@ -96,7 +94,9 @@ color_t draw_dotted(float_t x, float_t y) {
|
||||||
|
|
||||||
return vec4(color.rgb, alpha);
|
return vec4(color.rgb, alpha);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DRAW_DASHED)
|
||||||
color_t draw_dashed(float_t x) {
|
color_t draw_dashed(float_t x) {
|
||||||
// Since dashes of adjacent cells connect with each other our dash length is
|
// Since dashes of adjacent cells connect with each other our dash length is
|
||||||
// half of the desired total length.
|
// half of the desired total length.
|
||||||
|
@ -111,22 +111,23 @@ color_t draw_dashed(float_t x) {
|
||||||
|
|
||||||
return vec4(color.rgb, alpha);
|
return vec4(color.rgb, alpha);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float_t x = floor(mod(gl_FragCoord.x - paddingX, cellWidth));
|
float_t x = floor(mod(gl_FragCoord.x - paddingX, cellWidth));
|
||||||
float_t y = floor(mod(gl_FragCoord.y - paddingY, cellHeight));
|
float_t y = floor(mod(gl_FragCoord.y - paddingY, cellHeight));
|
||||||
|
|
||||||
if (rectKind == UNDERCURL) {
|
#if defined(DRAW_UNDERCURL)
|
||||||
FRAG_COLOR = draw_undercurl(x, y);
|
FRAG_COLOR = draw_undercurl(x, y);
|
||||||
} else if (rectKind == DOTTED) {
|
#elif defined(DRAW_DOTTED)
|
||||||
if (underlineThickness < 2.) {
|
if (underlineThickness < 2.) {
|
||||||
FRAG_COLOR = draw_dotted(x, y);
|
FRAG_COLOR = draw_dotted(x, y);
|
||||||
} else {
|
|
||||||
FRAG_COLOR = draw_dotted_aliased(x, y);
|
|
||||||
}
|
|
||||||
} else if (rectKind == DASHED) {
|
|
||||||
FRAG_COLOR = draw_dashed(x);
|
|
||||||
} else {
|
} else {
|
||||||
FRAG_COLOR = color;
|
FRAG_COLOR = draw_dotted_aliased(x, y);
|
||||||
}
|
}
|
||||||
|
#elif defined(DRAW_DASHED)
|
||||||
|
FRAG_COLOR = draw_dashed(x);
|
||||||
|
#else
|
||||||
|
FRAG_COLOR = color;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,8 +249,7 @@ pub struct RectRenderer {
|
||||||
vao: GLuint,
|
vao: GLuint,
|
||||||
vbo: GLuint,
|
vbo: GLuint,
|
||||||
|
|
||||||
program: RectShaderProgram,
|
programs: [RectShaderProgram; 4],
|
||||||
|
|
||||||
vertices: [Vec<Vertex>; 4],
|
vertices: [Vec<Vertex>; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +257,11 @@ impl RectRenderer {
|
||||||
pub fn new(shader_version: ShaderVersion) -> Result<Self, renderer::Error> {
|
pub fn new(shader_version: ShaderVersion) -> Result<Self, renderer::Error> {
|
||||||
let mut vao: GLuint = 0;
|
let mut vao: GLuint = 0;
|
||||||
let mut vbo: GLuint = 0;
|
let mut vbo: GLuint = 0;
|
||||||
let program = RectShaderProgram::new(shader_version)?;
|
|
||||||
|
let rect_program = RectShaderProgram::new(shader_version, RectKind::Normal)?;
|
||||||
|
let undercurl_program = RectShaderProgram::new(shader_version, RectKind::Undercurl)?;
|
||||||
|
let dotted_program = RectShaderProgram::new(shader_version, RectKind::DottedUnderline)?;
|
||||||
|
let dashed_program = RectShaderProgram::new(shader_version, RectKind::DashedUnderline)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Allocate buffers.
|
// Allocate buffers.
|
||||||
|
@ -300,7 +303,8 @@ impl RectRenderer {
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
|
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { vao, vbo, program, vertices: Default::default() })
|
let programs = [rect_program, undercurl_program, dotted_program, dashed_program];
|
||||||
|
Ok(Self { vao, vbo, programs, vertices: Default::default() })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) {
|
pub fn draw(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) {
|
||||||
|
@ -310,9 +314,6 @@ impl RectRenderer {
|
||||||
|
|
||||||
// Bind VBO only once for buffer data upload only.
|
// Bind VBO only once for buffer data upload only.
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
|
gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
|
||||||
|
|
||||||
gl::UseProgram(self.program.id());
|
|
||||||
self.program.update_uniforms(size_info, metrics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let half_width = size_info.width() / 2.;
|
let half_width = size_info.width() / 2.;
|
||||||
|
@ -333,7 +334,9 @@ impl RectRenderer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.program.set_rect_kind(rect_kind);
|
let program = &self.programs[rect_kind as usize];
|
||||||
|
gl::UseProgram(program.id());
|
||||||
|
program.update_uniforms(size_info, metrics);
|
||||||
|
|
||||||
// Upload accumulated undercurl vertices.
|
// Upload accumulated undercurl vertices.
|
||||||
gl::BufferData(
|
gl::BufferData(
|
||||||
|
@ -399,44 +402,47 @@ pub struct RectShaderProgram {
|
||||||
/// Shader program.
|
/// Shader program.
|
||||||
program: ShaderProgram,
|
program: ShaderProgram,
|
||||||
|
|
||||||
/// Kind of rect we're drawing.
|
|
||||||
u_rect_kind: GLint,
|
|
||||||
|
|
||||||
/// Cell width.
|
/// Cell width.
|
||||||
u_cell_width: GLint,
|
u_cell_width: Option<GLint>,
|
||||||
|
|
||||||
/// Cell height.
|
/// Cell height.
|
||||||
u_cell_height: GLint,
|
u_cell_height: Option<GLint>,
|
||||||
|
|
||||||
/// Terminal padding.
|
/// Terminal padding.
|
||||||
u_padding_x: GLint,
|
u_padding_x: Option<GLint>,
|
||||||
|
|
||||||
/// A padding from the bottom of the screen to viewport.
|
/// A padding from the bottom of the screen to viewport.
|
||||||
u_padding_y: GLint,
|
u_padding_y: Option<GLint>,
|
||||||
|
|
||||||
/// Underline position.
|
/// Underline position.
|
||||||
u_underline_position: GLint,
|
u_underline_position: Option<GLint>,
|
||||||
|
|
||||||
/// Underline thickness.
|
/// Underline thickness.
|
||||||
u_underline_thickness: GLint,
|
u_underline_thickness: Option<GLint>,
|
||||||
|
|
||||||
/// Undercurl position.
|
/// Undercurl position.
|
||||||
u_undercurl_position: GLint,
|
u_undercurl_position: Option<GLint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RectShaderProgram {
|
impl RectShaderProgram {
|
||||||
pub fn new(shader_version: ShaderVersion) -> Result<Self, ShaderError> {
|
pub fn new(shader_version: ShaderVersion, kind: RectKind) -> Result<Self, ShaderError> {
|
||||||
let program = ShaderProgram::new(shader_version, RECT_SHADER_V, RECT_SHADER_F)?;
|
// XXX: This must be in-sync with fragment shader defines.
|
||||||
|
let header = match kind {
|
||||||
|
RectKind::Undercurl => Some("#define DRAW_UNDERCURL\n"),
|
||||||
|
RectKind::DottedUnderline => Some("#define DRAW_DOTTED\n"),
|
||||||
|
RectKind::DashedUnderline => Some("#define DRAW_DASHED\n"),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let program = ShaderProgram::new(shader_version, header, RECT_SHADER_V, RECT_SHADER_F)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
u_rect_kind: program.get_uniform_location(cstr!("rectKind"))?,
|
u_cell_width: program.get_uniform_location(cstr!("cellWidth")).ok(),
|
||||||
u_cell_width: program.get_uniform_location(cstr!("cellWidth"))?,
|
u_cell_height: program.get_uniform_location(cstr!("cellHeight")).ok(),
|
||||||
u_cell_height: program.get_uniform_location(cstr!("cellHeight"))?,
|
u_padding_x: program.get_uniform_location(cstr!("paddingX")).ok(),
|
||||||
u_padding_x: program.get_uniform_location(cstr!("paddingX"))?,
|
u_padding_y: program.get_uniform_location(cstr!("paddingY")).ok(),
|
||||||
u_padding_y: program.get_uniform_location(cstr!("paddingY"))?,
|
u_underline_position: program.get_uniform_location(cstr!("underlinePosition")).ok(),
|
||||||
u_underline_position: program.get_uniform_location(cstr!("underlinePosition"))?,
|
u_underline_thickness: program.get_uniform_location(cstr!("underlineThickness")).ok(),
|
||||||
u_underline_thickness: program.get_uniform_location(cstr!("underlineThickness"))?,
|
u_undercurl_position: program.get_uniform_location(cstr!("undercurlPosition")).ok(),
|
||||||
u_undercurl_position: program.get_uniform_location(cstr!("undercurlPosition"))?,
|
|
||||||
program,
|
program,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -445,12 +451,6 @@ impl RectShaderProgram {
|
||||||
self.program.id()
|
self.program.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rect_kind(&self, ty: u8) {
|
|
||||||
unsafe {
|
|
||||||
gl::Uniform1i(self.u_rect_kind, ty as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_uniforms(&self, size_info: &SizeInfo, metrics: &Metrics) {
|
pub fn update_uniforms(&self, size_info: &SizeInfo, metrics: &Metrics) {
|
||||||
let position = (0.5 * metrics.descent).abs();
|
let position = (0.5 * metrics.descent).abs();
|
||||||
let underline_position = metrics.descent.abs() - metrics.underline_position.abs();
|
let underline_position = metrics.descent.abs() - metrics.underline_position.abs();
|
||||||
|
@ -460,13 +460,27 @@ impl RectShaderProgram {
|
||||||
- (viewport_height / size_info.cell_height()).floor() * size_info.cell_height();
|
- (viewport_height / size_info.cell_height()).floor() * size_info.cell_height();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::Uniform1f(self.u_cell_width, size_info.cell_width());
|
if let Some(u_cell_width) = self.u_cell_width {
|
||||||
gl::Uniform1f(self.u_cell_height, size_info.cell_height());
|
gl::Uniform1f(u_cell_width, size_info.cell_width());
|
||||||
gl::Uniform1f(self.u_padding_y, padding_y);
|
}
|
||||||
gl::Uniform1f(self.u_padding_x, size_info.padding_x());
|
if let Some(u_cell_height) = self.u_cell_height {
|
||||||
gl::Uniform1f(self.u_underline_position, underline_position);
|
gl::Uniform1f(u_cell_height, size_info.cell_height());
|
||||||
gl::Uniform1f(self.u_underline_thickness, metrics.underline_thickness);
|
}
|
||||||
gl::Uniform1f(self.u_undercurl_position, position);
|
if let Some(u_padding_y) = self.u_padding_y {
|
||||||
|
gl::Uniform1f(u_padding_y, padding_y);
|
||||||
|
}
|
||||||
|
if let Some(u_padding_x) = self.u_padding_x {
|
||||||
|
gl::Uniform1f(u_padding_x, size_info.padding_x());
|
||||||
|
}
|
||||||
|
if let Some(u_underline_position) = self.u_underline_position {
|
||||||
|
gl::Uniform1f(u_underline_position, underline_position);
|
||||||
|
}
|
||||||
|
if let Some(u_underline_thickness) = self.u_underline_thickness {
|
||||||
|
gl::Uniform1f(u_underline_thickness, metrics.underline_thickness);
|
||||||
|
}
|
||||||
|
if let Some(u_undercurl_position) = self.u_undercurl_position {
|
||||||
|
gl::Uniform1f(u_undercurl_position, position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,14 @@ impl ShaderVersion {
|
||||||
impl ShaderProgram {
|
impl ShaderProgram {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shader_version: ShaderVersion,
|
shader_version: ShaderVersion,
|
||||||
|
shader_header: Option<&str>,
|
||||||
vertex_shader: &'static str,
|
vertex_shader: &'static str,
|
||||||
fragment_shader: &'static str,
|
fragment_shader: &'static str,
|
||||||
) -> Result<Self, ShaderError> {
|
) -> Result<Self, ShaderError> {
|
||||||
let vertex_shader = Shader::new(shader_version, gl::VERTEX_SHADER, vertex_shader)?;
|
let vertex_shader =
|
||||||
let fragment_shader = Shader::new(shader_version, gl::FRAGMENT_SHADER, fragment_shader)?;
|
Shader::new(shader_version, shader_header, gl::VERTEX_SHADER, vertex_shader)?;
|
||||||
|
let fragment_shader =
|
||||||
|
Shader::new(shader_version, shader_header, gl::FRAGMENT_SHADER, fragment_shader)?;
|
||||||
|
|
||||||
let program = unsafe { Self(gl::CreateProgram()) };
|
let program = unsafe { Self(gl::CreateProgram()) };
|
||||||
|
|
||||||
|
@ -82,12 +85,23 @@ struct Shader(GLuint);
|
||||||
impl Shader {
|
impl Shader {
|
||||||
fn new(
|
fn new(
|
||||||
shader_version: ShaderVersion,
|
shader_version: ShaderVersion,
|
||||||
|
shader_header: Option<&str>,
|
||||||
kind: GLenum,
|
kind: GLenum,
|
||||||
source: &'static str,
|
source: &'static str,
|
||||||
) -> Result<Self, ShaderError> {
|
) -> Result<Self, ShaderError> {
|
||||||
let header = shader_version.shader_header();
|
let version_header = shader_version.shader_header();
|
||||||
let len: [GLint; 2] = [header.len() as GLint, source.len() as GLint];
|
let mut sources = Vec::<*const GLchar>::with_capacity(3);
|
||||||
let source = [header.as_ptr() as *const _, source.as_ptr() as *const _];
|
let mut lengthes = Vec::<GLint>::with_capacity(3);
|
||||||
|
sources.push(version_header.as_ptr().cast());
|
||||||
|
lengthes.push(version_header.len() as GLint);
|
||||||
|
|
||||||
|
if let Some(shader_header) = shader_header {
|
||||||
|
sources.push(shader_header.as_ptr().cast());
|
||||||
|
lengthes.push(shader_header.len() as GLint);
|
||||||
|
}
|
||||||
|
|
||||||
|
sources.push(source.as_ptr().cast());
|
||||||
|
lengthes.push(source.len() as GLint);
|
||||||
|
|
||||||
let shader = unsafe { Self(gl::CreateShader(kind)) };
|
let shader = unsafe { Self(gl::CreateShader(kind)) };
|
||||||
|
|
||||||
|
@ -95,9 +109,9 @@ impl Shader {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ShaderSource(
|
gl::ShaderSource(
|
||||||
shader.id(),
|
shader.id(),
|
||||||
len.len() as GLint,
|
lengthes.len() as GLint,
|
||||||
source.as_ptr() as *const _,
|
sources.as_ptr().cast(),
|
||||||
len.as_ptr(),
|
lengthes.as_ptr(),
|
||||||
);
|
);
|
||||||
gl::CompileShader(shader.id());
|
gl::CompileShader(shader.id());
|
||||||
gl::GetShaderiv(shader.id(), gl::COMPILE_STATUS, &mut success);
|
gl::GetShaderiv(shader.id(), gl::COMPILE_STATUS, &mut success);
|
||||||
|
|
|
@ -474,7 +474,7 @@ impl TextShaderProgram {
|
||||||
let fragment_shader =
|
let fragment_shader =
|
||||||
if dual_source_blending { &glsl3::TEXT_SHADER_F } else { &TEXT_SHADER_F };
|
if dual_source_blending { &glsl3::TEXT_SHADER_F } else { &TEXT_SHADER_F };
|
||||||
|
|
||||||
let program = ShaderProgram::new(shader_version, TEXT_SHADER_V, fragment_shader)?;
|
let program = ShaderProgram::new(shader_version, None, TEXT_SHADER_V, fragment_shader)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
u_projection: program.get_uniform_location(cstr!("projection"))?,
|
u_projection: program.get_uniform_location(cstr!("projection"))?,
|
||||||
|
|
|
@ -424,7 +424,7 @@ pub struct TextShaderProgram {
|
||||||
|
|
||||||
impl TextShaderProgram {
|
impl TextShaderProgram {
|
||||||
pub fn new(shader_version: ShaderVersion) -> Result<TextShaderProgram, Error> {
|
pub fn new(shader_version: ShaderVersion) -> Result<TextShaderProgram, Error> {
|
||||||
let program = ShaderProgram::new(shader_version, TEXT_SHADER_V, TEXT_SHADER_F)?;
|
let program = ShaderProgram::new(shader_version, None, TEXT_SHADER_V, TEXT_SHADER_F)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
u_projection: program.get_uniform_location(cstr!("projection"))?,
|
u_projection: program.get_uniform_location(cstr!("projection"))?,
|
||||||
u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?,
|
u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?,
|
||||||
|
|
Loading…
Reference in a new issue