mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-11 13:51:01 -05:00
Reduce InstanceData footprint
The InstanceData type in the rendering subsystem was previously 17 f32s plus one u8 which occupied a total of 72 bytes per instance. This meant that for every character or background cell drawn, 72 bytes were sent to the GPU. In the case of a 400x100 cell grid, a total of 2.9MB would be sent. This patch reduces InstanceData's size to 36 bytes, a 50% improvement! Using the above example for comparison, a worst case of 1.44MB would be transferred. The motivation for this patch comes from macOS. Once the terminal grid would reach a certain size, performance experienced a sharp and dramatic drop (render times would go from ~3ms to ~16ms). I don't want to speculate too much on the underlying issue, but suffice it to say that this patch alleviates the problem in my testing. While the performance impact was most significant on macOS, with rendering times cut by more than 50% in some cases, this also results in a measurable performance difference on other systems with high density grids. Co-authored-by: Christian Duerr <contact@christianduerr.com>
This commit is contained in:
parent
de84ab2072
commit
99c34c7ce9
4 changed files with 99 additions and 127 deletions
|
@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Incorrect window location with negative `window.position` config options
|
- Incorrect window location with negative `window.position` config options
|
||||||
|
- Slow rendering performance with HiDPI displays, especially on macOS
|
||||||
|
|
||||||
## 0.5.0
|
## 0.5.0
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#version 330 core
|
#version 330 core
|
||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
flat in vec3 fg;
|
flat in vec4 fg;
|
||||||
flat in vec4 bg;
|
flat in vec4 bg;
|
||||||
flat in int colored;
|
|
||||||
uniform int backgroundPass;
|
uniform int backgroundPass;
|
||||||
|
|
||||||
layout(location = 0, index = 0) out vec4 color;
|
layout(location = 0, index = 0) out vec4 color;
|
||||||
|
@ -32,7 +31,7 @@ void main()
|
||||||
alphaMask = vec4(1.0);
|
alphaMask = vec4(1.0);
|
||||||
color = vec4(bg.rgb, 1.0);
|
color = vec4(bg.rgb, 1.0);
|
||||||
} else {
|
} else {
|
||||||
if (colored != 0) {
|
if (fg.a != 0.0) {
|
||||||
// Color glyphs, like emojis.
|
// Color glyphs, like emojis.
|
||||||
vec4 glyphColor = texture(mask, TexCoords);
|
vec4 glyphColor = texture(mask, TexCoords);
|
||||||
alphaMask = vec4(glyphColor.a);
|
alphaMask = vec4(glyphColor.a);
|
||||||
|
@ -47,7 +46,7 @@ void main()
|
||||||
// Regular text glyphs.
|
// Regular text glyphs.
|
||||||
vec3 textColor = texture(mask, TexCoords).rgb;
|
vec3 textColor = texture(mask, TexCoords).rgb;
|
||||||
alphaMask = vec4(textColor, textColor.r);
|
alphaMask = vec4(textColor, textColor.r);
|
||||||
color = vec4(fg, 1.0);
|
color = vec4(fg.rgb, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,15 @@ layout (location = 1) in vec4 glyph;
|
||||||
// uv mapping.
|
// uv mapping.
|
||||||
layout (location = 2) in vec4 uv;
|
layout (location = 2) in vec4 uv;
|
||||||
|
|
||||||
// Text fg color.
|
// Text foreground rgb packed together with multicolor flag.
|
||||||
layout (location = 3) in vec3 textColor;
|
layout (location = 3) in vec4 textColor;
|
||||||
|
|
||||||
// Background color.
|
// Background color.
|
||||||
layout (location = 4) in vec4 backgroundColor;
|
layout (location = 4) in vec4 backgroundColor;
|
||||||
|
|
||||||
// Set to 1 if the glyph colors should be kept.
|
|
||||||
layout (location = 5) in int coloredGlyph;
|
|
||||||
|
|
||||||
out vec2 TexCoords;
|
out vec2 TexCoords;
|
||||||
flat out vec3 fg;
|
flat out vec4 fg;
|
||||||
flat out vec4 bg;
|
flat out vec4 bg;
|
||||||
flat out int colored;
|
|
||||||
|
|
||||||
// Terminal properties
|
// Terminal properties
|
||||||
uniform vec2 cellDim;
|
uniform vec2 cellDim;
|
||||||
|
@ -74,6 +70,5 @@ void main()
|
||||||
}
|
}
|
||||||
|
|
||||||
bg = vec4(backgroundColor.rgb / 255.0, backgroundColor.a);
|
bg = vec4(backgroundColor.rgb / 255.0, backgroundColor.a);
|
||||||
fg = textColor / vec3(255.0, 255.0, 255.0);
|
fg = vec4(textColor.rgb / 255.0, textColor.a);
|
||||||
colored = coloredGlyph;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,11 +124,11 @@ pub struct RectShaderProgram {
|
||||||
#[derive(Copy, Debug, Clone)]
|
#[derive(Copy, Debug, Clone)]
|
||||||
pub struct Glyph {
|
pub struct Glyph {
|
||||||
tex_id: GLuint,
|
tex_id: GLuint,
|
||||||
colored: bool,
|
multicolor: u8,
|
||||||
top: f32,
|
top: i16,
|
||||||
left: f32,
|
left: i16,
|
||||||
width: f32,
|
width: i16,
|
||||||
height: f32,
|
height: i16,
|
||||||
uv_bot: f32,
|
uv_bot: f32,
|
||||||
uv_left: f32,
|
uv_left: f32,
|
||||||
uv_width: f32,
|
uv_width: f32,
|
||||||
|
@ -392,31 +392,31 @@ impl GlyphCache {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct InstanceData {
|
struct InstanceData {
|
||||||
// Coords.
|
// Coords.
|
||||||
col: f32,
|
col: u16,
|
||||||
row: f32,
|
row: u16,
|
||||||
// Glyph offset.
|
// Glyph offset.
|
||||||
left: f32,
|
left: i16,
|
||||||
top: f32,
|
top: i16,
|
||||||
// Glyph scale.
|
// Glyph size.
|
||||||
width: f32,
|
width: i16,
|
||||||
height: f32,
|
height: i16,
|
||||||
// uv offset.
|
// UV offset.
|
||||||
uv_left: f32,
|
uv_left: f32,
|
||||||
uv_bot: f32,
|
uv_bot: f32,
|
||||||
// uv scale.
|
// uv scale.
|
||||||
uv_width: f32,
|
uv_width: f32,
|
||||||
uv_height: f32,
|
uv_height: f32,
|
||||||
// Color.
|
// Color.
|
||||||
r: f32,
|
r: u8,
|
||||||
g: f32,
|
g: u8,
|
||||||
b: f32,
|
b: u8,
|
||||||
// Background color.
|
// Flag indicating that a glyph uses multiple colors; like an Emoji.
|
||||||
bg_r: f32,
|
|
||||||
bg_g: f32,
|
|
||||||
bg_b: f32,
|
|
||||||
bg_a: f32,
|
|
||||||
// Flag indicating that glyph uses multiple colors, like an Emoji.
|
|
||||||
multicolor: u8,
|
multicolor: u8,
|
||||||
|
// Background color.
|
||||||
|
bg_r: u8,
|
||||||
|
bg_g: u8,
|
||||||
|
bg_b: u8,
|
||||||
|
bg_a: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -471,8 +471,8 @@ impl Batch {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.instances.push(InstanceData {
|
self.instances.push(InstanceData {
|
||||||
col: cell.column.0 as f32,
|
col: cell.column.0 as u16,
|
||||||
row: cell.line.0 as f32,
|
row: cell.line.0 as u16,
|
||||||
|
|
||||||
top: glyph.top,
|
top: glyph.top,
|
||||||
left: glyph.left,
|
left: glyph.left,
|
||||||
|
@ -484,15 +484,15 @@ impl Batch {
|
||||||
uv_width: glyph.uv_width,
|
uv_width: glyph.uv_width,
|
||||||
uv_height: glyph.uv_height,
|
uv_height: glyph.uv_height,
|
||||||
|
|
||||||
r: f32::from(cell.fg.r),
|
r: cell.fg.r,
|
||||||
g: f32::from(cell.fg.g),
|
g: cell.fg.g,
|
||||||
b: f32::from(cell.fg.b),
|
b: cell.fg.b,
|
||||||
|
|
||||||
bg_r: f32::from(cell.bg.r),
|
bg_r: cell.bg.r,
|
||||||
bg_g: f32::from(cell.bg.g),
|
bg_g: cell.bg.g,
|
||||||
bg_b: f32::from(cell.bg.b),
|
bg_b: cell.bg.b,
|
||||||
bg_a: cell.bg_alpha,
|
bg_a: (cell.bg_alpha * 255.0) as u8,
|
||||||
multicolor: glyph.colored as u8,
|
multicolor: glyph.multicolor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,72 +581,49 @@ impl QuadRenderer {
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
gl::STREAM_DRAW,
|
gl::STREAM_DRAW,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
let mut size = 0;
|
||||||
|
|
||||||
|
macro_rules! add_attr {
|
||||||
|
($count:expr, $gl_type:expr, $type:ty) => {
|
||||||
|
gl::VertexAttribPointer(
|
||||||
|
index,
|
||||||
|
$count,
|
||||||
|
$gl_type,
|
||||||
|
gl::FALSE,
|
||||||
|
size_of::<InstanceData>() as i32,
|
||||||
|
size as *const _,
|
||||||
|
);
|
||||||
|
gl::EnableVertexAttribArray(index);
|
||||||
|
gl::VertexAttribDivisor(index, 1);
|
||||||
|
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
{
|
||||||
|
size += $count * size_of::<$type>();
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Coords.
|
// Coords.
|
||||||
gl::VertexAttribPointer(
|
add_attr!(2, gl::UNSIGNED_SHORT, u16);
|
||||||
0,
|
|
||||||
2,
|
// Glyph offset and size.
|
||||||
gl::FLOAT,
|
add_attr!(4, gl::SHORT, i16);
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
// UV offset.
|
||||||
ptr::null(),
|
add_attr!(4, gl::FLOAT, f32);
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(0);
|
// Color and multicolor flag.
|
||||||
gl::VertexAttribDivisor(0, 1);
|
//
|
||||||
// Glyph offset.
|
// These are packed together because of an OpenGL driver issue on macOS, which caused a
|
||||||
gl::VertexAttribPointer(
|
// `vec3(u8)` text color and a `u8` multicolor flag to increase the rendering time by a
|
||||||
1,
|
// huge margin.
|
||||||
4,
|
add_attr!(4, gl::UNSIGNED_BYTE, u8);
|
||||||
gl::FLOAT,
|
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
|
||||||
(2 * size_of::<f32>()) as *const _,
|
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(1);
|
|
||||||
gl::VertexAttribDivisor(1, 1);
|
|
||||||
// uv.
|
|
||||||
gl::VertexAttribPointer(
|
|
||||||
2,
|
|
||||||
4,
|
|
||||||
gl::FLOAT,
|
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
|
||||||
(6 * size_of::<f32>()) as *const _,
|
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(2);
|
|
||||||
gl::VertexAttribDivisor(2, 1);
|
|
||||||
// Color.
|
|
||||||
gl::VertexAttribPointer(
|
|
||||||
3,
|
|
||||||
3,
|
|
||||||
gl::FLOAT,
|
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
|
||||||
(10 * size_of::<f32>()) as *const _,
|
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(3);
|
|
||||||
gl::VertexAttribDivisor(3, 1);
|
|
||||||
// Background color.
|
// Background color.
|
||||||
gl::VertexAttribPointer(
|
add_attr!(4, gl::UNSIGNED_BYTE, u8);
|
||||||
4,
|
|
||||||
4,
|
|
||||||
gl::FLOAT,
|
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
|
||||||
(13 * size_of::<f32>()) as *const _,
|
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(4);
|
|
||||||
gl::VertexAttribDivisor(4, 1);
|
|
||||||
// Multicolor flag.
|
|
||||||
gl::VertexAttribPointer(
|
|
||||||
5,
|
|
||||||
1,
|
|
||||||
gl::BYTE,
|
|
||||||
gl::FALSE,
|
|
||||||
size_of::<InstanceData>() as i32,
|
|
||||||
(17 * size_of::<f32>()) as *const _,
|
|
||||||
);
|
|
||||||
gl::EnableVertexAttribArray(5);
|
|
||||||
gl::VertexAttribDivisor(5, 1);
|
|
||||||
|
|
||||||
// Rectangle setup.
|
// Rectangle setup.
|
||||||
gl::GenVertexArrays(1, &mut rect_vao);
|
gl::GenVertexArrays(1, &mut rect_vao);
|
||||||
|
@ -1089,7 +1066,7 @@ impl<'a> RenderApi<'a> {
|
||||||
// right side of the preceding character. Since we render the
|
// right side of the preceding character. Since we render the
|
||||||
// zero-width characters inside the preceding character, the
|
// zero-width characters inside the preceding character, the
|
||||||
// anchor has been moved to the right by one cell.
|
// anchor has been moved to the right by one cell.
|
||||||
glyph.left += glyph_cache.metrics.average_advance as f32;
|
glyph.left += glyph_cache.metrics.average_advance as i16;
|
||||||
|
|
||||||
self.add_render_item(cell, &glyph);
|
self.add_render_item(cell, &glyph);
|
||||||
}
|
}
|
||||||
|
@ -1121,15 +1098,15 @@ fn load_glyph(
|
||||||
},
|
},
|
||||||
Err(AtlasInsertError::GlyphTooLarge) => Glyph {
|
Err(AtlasInsertError::GlyphTooLarge) => Glyph {
|
||||||
tex_id: atlas[*current_atlas].id,
|
tex_id: atlas[*current_atlas].id,
|
||||||
colored: false,
|
multicolor: 0,
|
||||||
top: 0.0,
|
top: 0,
|
||||||
left: 0.0,
|
left: 0,
|
||||||
width: 0.0,
|
width: 0,
|
||||||
height: 0.0,
|
height: 0,
|
||||||
uv_bot: 0.0,
|
uv_bot: 0.,
|
||||||
uv_left: 0.0,
|
uv_left: 0.,
|
||||||
uv_width: 0.0,
|
uv_width: 0.,
|
||||||
uv_height: 0.0,
|
uv_height: 0.,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1590,7 +1567,7 @@ impl Atlas {
|
||||||
let offset_x = self.row_extent;
|
let offset_x = self.row_extent;
|
||||||
let height = glyph.height as i32;
|
let height = glyph.height as i32;
|
||||||
let width = glyph.width as i32;
|
let width = glyph.width as i32;
|
||||||
let colored;
|
let multicolor;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindTexture(gl::TEXTURE_2D, self.id);
|
gl::BindTexture(gl::TEXTURE_2D, self.id);
|
||||||
|
@ -1598,11 +1575,11 @@ impl Atlas {
|
||||||
// Load data into OpenGL.
|
// Load data into OpenGL.
|
||||||
let (format, buf) = match &glyph.buf {
|
let (format, buf) = match &glyph.buf {
|
||||||
BitmapBuffer::RGB(buf) => {
|
BitmapBuffer::RGB(buf) => {
|
||||||
colored = false;
|
multicolor = false;
|
||||||
(gl::RGB, buf)
|
(gl::RGB, buf)
|
||||||
},
|
},
|
||||||
BitmapBuffer::RGBA(buf) => {
|
BitmapBuffer::RGBA(buf) => {
|
||||||
colored = true;
|
multicolor = true;
|
||||||
(gl::RGBA, buf)
|
(gl::RGBA, buf)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1637,11 +1614,11 @@ impl Atlas {
|
||||||
|
|
||||||
Glyph {
|
Glyph {
|
||||||
tex_id: self.id,
|
tex_id: self.id,
|
||||||
colored,
|
multicolor: multicolor as u8,
|
||||||
top: glyph.top as f32,
|
top: glyph.top as i16,
|
||||||
width: width as f32,
|
left: glyph.left as i16,
|
||||||
height: height as f32,
|
width: width as i16,
|
||||||
left: glyph.left as f32,
|
height: height as i16,
|
||||||
uv_bot,
|
uv_bot,
|
||||||
uv_left,
|
uv_left,
|
||||||
uv_width,
|
uv_width,
|
||||||
|
|
Loading…
Reference in a new issue