mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 13:52:55 +03:00
split shaders, adjust srgb opengl render settings
https://learnopengl.com/Advanced-Lighting/Gamma-Correction suggests some good practices: * Only enable SRGB output on the final draw call, so that all prior stages can operate on linear values and avoid converting to/from linear multiple times. * The SRGBA textures automatically linearize when sampled, but: * The RGB data must be SRGB (non-linear) * The A channel is assumed to be linear! This commit nudges us closer to that by: * Converting the freetype coverage map from its linear value to non-linear when rasterizing. * Splitting the shader files into one per stage (background, lines, glyphs) and only setting outputs_srgb for the glyph stage refs: #491
This commit is contained in:
parent
dd70a8a53b
commit
4e2b2eddba
@ -7,6 +7,7 @@ use anyhow::bail;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
use window::color::linear_u8_to_srgb8;
|
||||||
|
|
||||||
pub struct FreeTypeRasterizer {
|
pub struct FreeTypeRasterizer {
|
||||||
has_color: bool,
|
has_color: bool,
|
||||||
@ -112,12 +113,19 @@ impl FreeTypeRasterizer {
|
|||||||
let src_offset = y * pitch;
|
let src_offset = y * pitch;
|
||||||
let dest_offset = y * width * 4;
|
let dest_offset = y * width * 4;
|
||||||
for x in 0..width {
|
for x in 0..width {
|
||||||
let gray = data[src_offset + x];
|
let linear_gray = data[src_offset + x];
|
||||||
|
|
||||||
|
let gray = linear_u8_to_srgb8(linear_gray);
|
||||||
|
|
||||||
|
// Texture is SRGBA, which in OpenGL means
|
||||||
|
// that the RGB values are gamma adjusted
|
||||||
|
// non-linear values, but the A value is
|
||||||
|
// linear!
|
||||||
|
|
||||||
rgba[dest_offset + (x * 4)] = gray;
|
rgba[dest_offset + (x * 4)] = gray;
|
||||||
rgba[dest_offset + (x * 4) + 1] = gray;
|
rgba[dest_offset + (x * 4) + 1] = gray;
|
||||||
rgba[dest_offset + (x * 4) + 2] = gray;
|
rgba[dest_offset + (x * 4) + 2] = gray;
|
||||||
rgba[dest_offset + (x * 4) + 3] = gray;
|
rgba[dest_offset + (x * 4) + 3] = linear_gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RasterizedGlyph {
|
RasterizedGlyph {
|
||||||
@ -151,6 +159,16 @@ impl FreeTypeRasterizer {
|
|||||||
let green = data[src_offset + (x * 3) + 1];
|
let green = data[src_offset + (x * 3) + 1];
|
||||||
let blue = data[src_offset + (x * 3) + 2];
|
let blue = data[src_offset + (x * 3) + 2];
|
||||||
let alpha = red.min(green).min(blue);
|
let alpha = red.min(green).min(blue);
|
||||||
|
|
||||||
|
// Texture is SRGBA, which in OpenGL means
|
||||||
|
// that the RGB values are gamma adjusted
|
||||||
|
// non-linear values, but the A value is
|
||||||
|
// linear!
|
||||||
|
|
||||||
|
let red = linear_u8_to_srgb8(red);
|
||||||
|
let green = linear_u8_to_srgb8(green);
|
||||||
|
let blue = linear_u8_to_srgb8(blue);
|
||||||
|
|
||||||
rgba[dest_offset + (x * 4)] = red;
|
rgba[dest_offset + (x * 4)] = red;
|
||||||
rgba[dest_offset + (x * 4) + 1] = green;
|
rgba[dest_offset + (x * 4) + 1] = green;
|
||||||
rgba[dest_offset + (x * 4) + 2] = blue;
|
rgba[dest_offset + (x * 4) + 2] = blue;
|
||||||
|
20
wezterm-gui/src/gui/background-frag.glsl
Normal file
20
wezterm-gui/src/gui/background-frag.glsl
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// This shader is responsible for coloring the window background.
|
||||||
|
|
||||||
|
// Note: fragment-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
uniform sampler2D atlas_linear_sampler;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
if (o_has_color == 2.0) {
|
||||||
|
// We're the window background image.
|
||||||
|
color = texture(atlas_linear_sampler, o_tex);
|
||||||
|
// Apply window_background_image_opacity to the background image
|
||||||
|
color.a = o_bg_color.a;
|
||||||
|
} else if (o_has_color == 3.0) {
|
||||||
|
color = o_bg_color;
|
||||||
|
} else {
|
||||||
|
// Nothing else should render on the background layer
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
color = apply_hsv(color, o_hsv);
|
||||||
|
}
|
16
wezterm-gui/src/gui/background-vertex.glsl
Normal file
16
wezterm-gui/src/gui/background-vertex.glsl
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// This is the window background shader.
|
||||||
|
// It places the background image in the full viewport.
|
||||||
|
|
||||||
|
// Note: vertex-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
pass_through_vertex();
|
||||||
|
|
||||||
|
if (o_has_color == 2.0) {
|
||||||
|
// Background image takes up its full coordinates
|
||||||
|
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||||
|
} else {
|
||||||
|
// Nothing else should render on the background layer
|
||||||
|
gl_Position = off_screen();
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// This file is automatically prepended to the various -frag shaders.
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
in float o_has_color;
|
in float o_has_color;
|
||||||
@ -10,18 +12,10 @@ in vec4 o_cursor_color;
|
|||||||
in vec4 o_fg_color;
|
in vec4 o_fg_color;
|
||||||
in vec4 o_underline_color;
|
in vec4 o_underline_color;
|
||||||
|
|
||||||
uniform mat4 projection;
|
out vec4 color;
|
||||||
uniform bool window_bg_layer;
|
|
||||||
uniform bool bg_and_line_layer;
|
|
||||||
uniform bool has_background_image;
|
|
||||||
|
|
||||||
uniform sampler2D atlas_nearest_sampler;
|
|
||||||
uniform sampler2D atlas_linear_sampler;
|
|
||||||
|
|
||||||
uniform vec3 foreground_text_hsb;
|
uniform vec3 foreground_text_hsb;
|
||||||
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
float multiply_one(float src, float dst, float inv_dst_alpha, float inv_src_alpha) {
|
float multiply_one(float src, float dst, float inv_dst_alpha, float inv_src_alpha) {
|
||||||
return (src * dst) + (src * (inv_dst_alpha)) + (dst * (inv_src_alpha));
|
return (src * dst) + (src * (inv_dst_alpha)) + (dst * (inv_src_alpha));
|
||||||
}
|
}
|
||||||
@ -56,9 +50,9 @@ vec3 hsv2rgb(vec3 c)
|
|||||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 apply_hsv(vec4 c)
|
vec4 apply_hsv(vec4 c, vec3 transform)
|
||||||
{
|
{
|
||||||
vec3 hsv = rgb2hsv(c.rgb) * o_hsv;
|
vec3 hsv = rgb2hsv(c.rgb) * transform;
|
||||||
return vec4(hsv2rgb(hsv).rgb, c.a);
|
return vec4(hsv2rgb(hsv).rgb, c.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,73 +87,4 @@ vec4 colorize_hsv(vec4 glyph, vec4 color) {
|
|||||||
return vec4(hsv2rgb(hsv * foreground_text_hsb), glyph.a);
|
return vec4(hsv2rgb(hsv * foreground_text_hsb), glyph.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
|
||||||
if (window_bg_layer) {
|
|
||||||
if (o_has_color == 2.0) {
|
|
||||||
// We're the window background image.
|
|
||||||
color = texture(atlas_linear_sampler, o_tex);
|
|
||||||
// Apply window_background_image_opacity to the background image
|
|
||||||
color.a = o_bg_color.a;
|
|
||||||
} else if (o_has_color == 3.0) {
|
|
||||||
color = o_bg_color;
|
|
||||||
} else {
|
|
||||||
// Nothing else should render on the background layer
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (bg_and_line_layer) {
|
|
||||||
if (o_has_color >= 2.0) {
|
|
||||||
// Don't render the background image on anything other than
|
|
||||||
// the window_bg_layer.
|
|
||||||
discard;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Note that o_bg_color is set to transparent if the background
|
|
||||||
// color is "default" and there is a window background attachment
|
|
||||||
color = o_bg_color;
|
|
||||||
|
|
||||||
// Sample the underline glyph texture for this location.
|
|
||||||
// Note that the texture is whitespace in the case where this is
|
|
||||||
// no underline or strikethrough.
|
|
||||||
vec4 under_color = texture(atlas_nearest_sampler, o_underline);
|
|
||||||
if (under_color.a != 0.0) {
|
|
||||||
// if the underline glyph isn't transparent in this position then
|
|
||||||
// we take the underline color, otherwise we'll leave the color
|
|
||||||
// at the background color.
|
|
||||||
color = o_underline_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to the above: if the cursor texture isn't transparent
|
|
||||||
// in this location, we'll use the cursor color instead of the background.
|
|
||||||
// The cursor color overrides any underline color we might have picked
|
|
||||||
// in the section above.
|
|
||||||
vec4 cursor_outline = texture(atlas_nearest_sampler, o_cursor);
|
|
||||||
if (cursor_outline.a != 0.0) {
|
|
||||||
color = o_cursor_color;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (o_has_color >= 2.0) {
|
|
||||||
// Don't render the background image on anything other than
|
|
||||||
// the window_bg_layer.
|
|
||||||
discard;
|
|
||||||
} else {
|
|
||||||
color = texture(atlas_nearest_sampler, o_tex);
|
|
||||||
if (o_has_color == 0.0) {
|
|
||||||
// if it's not a color emoji it will be grayscale
|
|
||||||
// and we need to tint with the fg_color
|
|
||||||
if (o_fg_color == o_bg_color) {
|
|
||||||
// However, if we're a monochrome glyph and the foreground and
|
|
||||||
// background colors are the same, just render a transparent pixel
|
|
||||||
// instead; this avoids generating shadowy anti-aliasing artifacts
|
|
||||||
// for something that should otherwise be invisible.
|
|
||||||
color = vec4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
discard;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
color = colorize_hsv(color, o_fg_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
color = apply_hsv(color);
|
|
||||||
}
|
|
35
wezterm-gui/src/gui/glyph-frag.glsl
Normal file
35
wezterm-gui/src/gui/glyph-frag.glsl
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// This is the Glyph fragment shader.
|
||||||
|
// It is the last stage in drawing, and is responsible
|
||||||
|
// for laying down the glyph graphics on top of the other layers.
|
||||||
|
|
||||||
|
// Note: fragment-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
uniform sampler2D atlas_nearest_sampler;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
if (o_has_color >= 2.0) {
|
||||||
|
// Don't render the background image on anything other than
|
||||||
|
// the window_bg_layer.
|
||||||
|
discard;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = texture(atlas_nearest_sampler, o_tex);
|
||||||
|
if (o_has_color == 0.0) {
|
||||||
|
// if it's not a color emoji it will be grayscale
|
||||||
|
// and we need to tint with the fg_color
|
||||||
|
if (o_fg_color == o_bg_color) {
|
||||||
|
// However, if we're a monochrome glyph and the foreground and
|
||||||
|
// background colors are the same, just render a transparent pixel
|
||||||
|
// instead; this avoids generating shadowy anti-aliasing artifacts
|
||||||
|
// for something that should otherwise be invisible.
|
||||||
|
color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
discard;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
color = colorize_hsv(color, o_fg_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color = apply_hsv(color, o_hsv);
|
||||||
|
}
|
18
wezterm-gui/src/gui/glyph-vertex.glsl
Normal file
18
wezterm-gui/src/gui/glyph-vertex.glsl
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// This is the Glyph vertex shader.
|
||||||
|
// It is responsible for placing the glyph images in the
|
||||||
|
// correct place on screen.
|
||||||
|
|
||||||
|
// Note: vertex-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
pass_through_vertex();
|
||||||
|
|
||||||
|
if (o_has_color == 2.0) {
|
||||||
|
// If we're the background image and we're not rendering
|
||||||
|
// the background layer, then move this off screen
|
||||||
|
gl_Position = off_screen();
|
||||||
|
} else {
|
||||||
|
// Use only the adjusted cell position to render the glyph
|
||||||
|
gl_Position = projection * vec4(position + adjust, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
41
wezterm-gui/src/gui/line-frag.glsl
Normal file
41
wezterm-gui/src/gui/line-frag.glsl
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// This shader is responsible for coloring the underline and
|
||||||
|
// glyph background graphics.
|
||||||
|
|
||||||
|
// Note: fragment-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
uniform sampler2D atlas_nearest_sampler;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
if (o_has_color >= 2.0) {
|
||||||
|
// Don't render the background image on anything other than
|
||||||
|
// the window_bg_layer.
|
||||||
|
discard;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that o_bg_color is set to transparent if the background
|
||||||
|
// color is "default" and there is a window background attachment
|
||||||
|
color = o_bg_color;
|
||||||
|
|
||||||
|
// Sample the underline glyph texture for this location.
|
||||||
|
// Note that the texture is whitespace in the case where this is
|
||||||
|
// no underline or strikethrough.
|
||||||
|
vec4 under_color = texture(atlas_nearest_sampler, o_underline);
|
||||||
|
if (under_color.a != 0.0) {
|
||||||
|
// if the underline glyph isn't transparent in this position then
|
||||||
|
// we take the underline color, otherwise we'll leave the color
|
||||||
|
// at the background color.
|
||||||
|
color = o_underline_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to the above: if the cursor texture isn't transparent
|
||||||
|
// in this location, we'll use the cursor color instead of the background.
|
||||||
|
// The cursor color overrides any underline color we might have picked
|
||||||
|
// in the section above.
|
||||||
|
vec4 cursor_outline = texture(atlas_nearest_sampler, o_cursor);
|
||||||
|
if (cursor_outline.a != 0.0) {
|
||||||
|
color = o_cursor_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = apply_hsv(color, o_hsv);
|
||||||
|
}
|
17
wezterm-gui/src/gui/line-vertex.glsl
Normal file
17
wezterm-gui/src/gui/line-vertex.glsl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// This is the underline/strikethrough and text-background color
|
||||||
|
// shader. It is responsible for locating the cell boundaries.
|
||||||
|
|
||||||
|
// Note: vertex-common.glsl is automatically prepended!
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
pass_through_vertex();
|
||||||
|
|
||||||
|
if (o_has_color == 2.0) {
|
||||||
|
// If we're the background image and we're not rendering
|
||||||
|
// the background layer, then move this off screen
|
||||||
|
gl_Position = off_screen();
|
||||||
|
} else {
|
||||||
|
// Want to fill the whole cell when painting backgrounds
|
||||||
|
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ use ::window::glium::backend::Context as GliumContext;
|
|||||||
use ::window::glium::texture::SrgbTexture2d;
|
use ::window::glium::texture::SrgbTexture2d;
|
||||||
use ::window::glium::{IndexBuffer, VertexBuffer};
|
use ::window::glium::{IndexBuffer, VertexBuffer};
|
||||||
use ::window::*;
|
use ::window::*;
|
||||||
use anyhow::anyhow;
|
|
||||||
use config::configuration;
|
use config::configuration;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -16,7 +15,9 @@ pub struct RenderState {
|
|||||||
pub context: Rc<GliumContext>,
|
pub context: Rc<GliumContext>,
|
||||||
pub glyph_cache: RefCell<GlyphCache<SrgbTexture2d>>,
|
pub glyph_cache: RefCell<GlyphCache<SrgbTexture2d>>,
|
||||||
pub util_sprites: UtilSprites<SrgbTexture2d>,
|
pub util_sprites: UtilSprites<SrgbTexture2d>,
|
||||||
pub program: glium::Program,
|
pub background_prog: glium::Program,
|
||||||
|
pub line_prog: glium::Program,
|
||||||
|
pub glyph_prog: glium::Program,
|
||||||
pub glyph_vertex_buffer: RefCell<VertexBuffer<Vertex>>,
|
pub glyph_vertex_buffer: RefCell<VertexBuffer<Vertex>>,
|
||||||
pub glyph_index_buffer: IndexBuffer<u32>,
|
pub glyph_index_buffer: IndexBuffer<u32>,
|
||||||
pub quads: Quads,
|
pub quads: Quads,
|
||||||
@ -37,32 +38,12 @@ impl RenderState {
|
|||||||
let result = UtilSprites::new(&mut *glyph_cache.borrow_mut(), metrics);
|
let result = UtilSprites::new(&mut *glyph_cache.borrow_mut(), metrics);
|
||||||
match result {
|
match result {
|
||||||
Ok(util_sprites) => {
|
Ok(util_sprites) => {
|
||||||
let mut errors = vec![];
|
let background_prog =
|
||||||
let mut program = None;
|
Self::compile_prog(&context, false, Self::background_shader)?;
|
||||||
for version in &["330", "300 es"] {
|
let line_prog = Self::compile_prog(&context, false, Self::line_shader)?;
|
||||||
let source = glium::program::ProgramCreationInput::SourceCode {
|
|
||||||
vertex_shader: &Self::vertex_shader(version),
|
|
||||||
fragment_shader: &Self::fragment_shader(version),
|
|
||||||
outputs_srgb: true,
|
|
||||||
tessellation_control_shader: None,
|
|
||||||
tessellation_evaluation_shader: None,
|
|
||||||
transform_feedback_varyings: None,
|
|
||||||
uses_point_size: false,
|
|
||||||
geometry_shader: None,
|
|
||||||
};
|
|
||||||
log::trace!("compiling a prog with version {}", version);
|
|
||||||
match glium::Program::new(&context, source) {
|
|
||||||
Ok(prog) => {
|
|
||||||
program = Some(prog);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(err) => errors.push(err.to_string()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let program = program.ok_or_else(|| {
|
// Last prog outputs srgb for gamma correction
|
||||||
anyhow!("Failed to compile shaders: {}", errors.join("\n"))
|
let glyph_prog = Self::compile_prog(&context, true, Self::glyph_shader)?;
|
||||||
})?;
|
|
||||||
|
|
||||||
let (glyph_vertex_buffer, glyph_index_buffer, quads) = Self::compute_vertices(
|
let (glyph_vertex_buffer, glyph_index_buffer, quads) = Self::compute_vertices(
|
||||||
&context,
|
&context,
|
||||||
@ -75,7 +56,9 @@ impl RenderState {
|
|||||||
context,
|
context,
|
||||||
glyph_cache,
|
glyph_cache,
|
||||||
util_sprites,
|
util_sprites,
|
||||||
program,
|
background_prog,
|
||||||
|
line_prog,
|
||||||
|
glyph_prog,
|
||||||
glyph_vertex_buffer: RefCell::new(glyph_vertex_buffer),
|
glyph_vertex_buffer: RefCell::new(glyph_vertex_buffer),
|
||||||
glyph_index_buffer,
|
glyph_index_buffer,
|
||||||
quads,
|
quads,
|
||||||
@ -91,6 +74,36 @@ impl RenderState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_prog(
|
||||||
|
context: &Rc<GliumContext>,
|
||||||
|
outputs_srgb: bool,
|
||||||
|
fragment_shader: fn(&str) -> (String, String),
|
||||||
|
) -> anyhow::Result<glium::Program> {
|
||||||
|
let mut errors = vec![];
|
||||||
|
for version in &["330", "300 es"] {
|
||||||
|
let (vertex_shader, fragment_shader) = fragment_shader(version);
|
||||||
|
let source = glium::program::ProgramCreationInput::SourceCode {
|
||||||
|
vertex_shader: &vertex_shader,
|
||||||
|
fragment_shader: &fragment_shader,
|
||||||
|
outputs_srgb,
|
||||||
|
tessellation_control_shader: None,
|
||||||
|
tessellation_evaluation_shader: None,
|
||||||
|
transform_feedback_varyings: None,
|
||||||
|
uses_point_size: false,
|
||||||
|
geometry_shader: None,
|
||||||
|
};
|
||||||
|
log::trace!("compiling a prog with version {}", version);
|
||||||
|
match glium::Program::new(context, source) {
|
||||||
|
Ok(prog) => {
|
||||||
|
return Ok(prog);
|
||||||
|
}
|
||||||
|
Err(err) => errors.push(err.to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::bail!("Failed to compile shaders: {}", errors.join("\n"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn advise_of_window_size_change(
|
pub fn advise_of_window_size_change(
|
||||||
&mut self,
|
&mut self,
|
||||||
metrics: &RenderMetrics,
|
metrics: &RenderMetrics,
|
||||||
@ -110,12 +123,55 @@ impl RenderState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vertex_shader(version: &str) -> String {
|
fn glyph_shader(version: &str) -> (String, String) {
|
||||||
format!("#version {}\n{}", version, include_str!("vertex.glsl"))
|
(
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("vertex-common.glsl"),
|
||||||
|
include_str!("glyph-vertex.glsl")
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("fragment-common.glsl"),
|
||||||
|
include_str!("glyph-frag.glsl")
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fragment_shader(version: &str) -> String {
|
fn line_shader(version: &str) -> (String, String) {
|
||||||
format!("#version {}\n{}", version, include_str!("fragment.glsl"))
|
(
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("vertex-common.glsl"),
|
||||||
|
include_str!("line-vertex.glsl")
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("fragment-common.glsl"),
|
||||||
|
include_str!("line-frag.glsl")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn background_shader(version: &str) -> (String, String) {
|
||||||
|
(
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("vertex-common.glsl"),
|
||||||
|
include_str!("background-vertex.glsl")
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"#version {}\n{}\n{}",
|
||||||
|
version,
|
||||||
|
include_str!("fragment-common.glsl"),
|
||||||
|
include_str!("background-frag.glsl")
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a vertex buffer to hold the quads that comprise the visible
|
/// Compute a vertex buffer to hold the quads that comprise the visible
|
||||||
|
@ -2774,8 +2774,6 @@ impl TermWindow {
|
|||||||
.magnify_filter(MagnifySamplerFilter::Linear)
|
.magnify_filter(MagnifySamplerFilter::Linear)
|
||||||
.minify_filter(MinifySamplerFilter::Linear);
|
.minify_filter(MinifySamplerFilter::Linear);
|
||||||
|
|
||||||
let has_background_image = self.window_background.is_some();
|
|
||||||
|
|
||||||
let foreground_text_hsb = configuration().foreground_text_hsb;
|
let foreground_text_hsb = configuration().foreground_text_hsb;
|
||||||
let foreground_text_hsb = (
|
let foreground_text_hsb = (
|
||||||
foreground_text_hsb.hue,
|
foreground_text_hsb.hue,
|
||||||
@ -2787,14 +2785,10 @@ impl TermWindow {
|
|||||||
frame.draw(
|
frame.draw(
|
||||||
&*vb,
|
&*vb,
|
||||||
&gl_state.glyph_index_buffer,
|
&gl_state.glyph_index_buffer,
|
||||||
&gl_state.program,
|
&gl_state.background_prog,
|
||||||
&uniform! {
|
&uniform! {
|
||||||
projection: projection,
|
projection: projection,
|
||||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
|
||||||
atlas_linear_sampler: atlas_linear_sampler,
|
atlas_linear_sampler: atlas_linear_sampler,
|
||||||
window_bg_layer: true,
|
|
||||||
bg_and_line_layer: false,
|
|
||||||
has_background_image: has_background_image,
|
|
||||||
foreground_text_hsb: foreground_text_hsb,
|
foreground_text_hsb: foreground_text_hsb,
|
||||||
},
|
},
|
||||||
&alpha_blending,
|
&alpha_blending,
|
||||||
@ -2804,14 +2798,11 @@ impl TermWindow {
|
|||||||
frame.draw(
|
frame.draw(
|
||||||
&*vb,
|
&*vb,
|
||||||
&gl_state.glyph_index_buffer,
|
&gl_state.glyph_index_buffer,
|
||||||
&gl_state.program,
|
&gl_state.line_prog,
|
||||||
&uniform! {
|
&uniform! {
|
||||||
projection: projection,
|
projection: projection,
|
||||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
atlas_nearest_sampler: atlas_nearest_sampler,
|
||||||
atlas_linear_sampler: atlas_linear_sampler,
|
atlas_linear_sampler: atlas_linear_sampler,
|
||||||
window_bg_layer: false,
|
|
||||||
bg_and_line_layer: true,
|
|
||||||
has_background_image: has_background_image,
|
|
||||||
foreground_text_hsb: foreground_text_hsb,
|
foreground_text_hsb: foreground_text_hsb,
|
||||||
},
|
},
|
||||||
&alpha_blending,
|
&alpha_blending,
|
||||||
@ -2861,14 +2852,11 @@ impl TermWindow {
|
|||||||
frame.draw(
|
frame.draw(
|
||||||
&*vb,
|
&*vb,
|
||||||
&gl_state.glyph_index_buffer,
|
&gl_state.glyph_index_buffer,
|
||||||
&gl_state.program,
|
&gl_state.glyph_prog,
|
||||||
&uniform! {
|
&uniform! {
|
||||||
projection: projection,
|
projection: projection,
|
||||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
atlas_nearest_sampler: atlas_nearest_sampler,
|
||||||
atlas_linear_sampler: atlas_linear_sampler,
|
atlas_linear_sampler: atlas_linear_sampler,
|
||||||
window_bg_layer: false,
|
|
||||||
bg_and_line_layer: false,
|
|
||||||
has_background_image: has_background_image,
|
|
||||||
foreground_text_hsb: foreground_text_hsb,
|
foreground_text_hsb: foreground_text_hsb,
|
||||||
},
|
},
|
||||||
&blend_but_set_alpha_to_one,
|
&blend_but_set_alpha_to_one,
|
||||||
|
49
wezterm-gui/src/gui/vertex-common.glsl
Normal file
49
wezterm-gui/src/gui/vertex-common.glsl
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// This file is automatically prepended to the various
|
||||||
|
// vertex.glsl files.
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
in vec2 position;
|
||||||
|
in vec2 adjust;
|
||||||
|
in vec2 tex;
|
||||||
|
in vec2 underline;
|
||||||
|
in vec4 bg_color;
|
||||||
|
in vec4 fg_color;
|
||||||
|
in vec4 underline_color;
|
||||||
|
in float has_color;
|
||||||
|
in vec2 cursor;
|
||||||
|
in vec4 cursor_color;
|
||||||
|
in vec3 hsv;
|
||||||
|
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
out float o_has_color;
|
||||||
|
out vec2 o_cursor;
|
||||||
|
out vec2 o_tex;
|
||||||
|
out vec2 o_underline;
|
||||||
|
out vec3 o_hsv;
|
||||||
|
out vec4 o_bg_color;
|
||||||
|
out vec4 o_cursor_color;
|
||||||
|
out vec4 o_fg_color;
|
||||||
|
out vec4 o_underline_color;
|
||||||
|
|
||||||
|
void pass_through_vertex() {
|
||||||
|
o_tex = tex;
|
||||||
|
o_has_color = has_color;
|
||||||
|
o_fg_color = fg_color;
|
||||||
|
o_bg_color = bg_color;
|
||||||
|
o_underline = underline;
|
||||||
|
o_underline_color = underline_color;
|
||||||
|
o_cursor = cursor;
|
||||||
|
o_cursor_color = cursor_color;
|
||||||
|
o_hsv = hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a position that is outside of the viewport,
|
||||||
|
// such that this vertex effectively won't contribute
|
||||||
|
// the scene being rendered.
|
||||||
|
// There may be a better way to do this.
|
||||||
|
vec4 off_screen() {
|
||||||
|
return vec4(100.0, 100.0, 100.0, 100.0);
|
||||||
|
}
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
precision highp float;
|
|
||||||
|
|
||||||
in vec2 position;
|
|
||||||
in vec2 adjust;
|
|
||||||
in vec2 tex;
|
|
||||||
in vec2 underline;
|
|
||||||
in vec4 bg_color;
|
|
||||||
in vec4 fg_color;
|
|
||||||
in vec4 underline_color;
|
|
||||||
in float has_color;
|
|
||||||
in vec2 cursor;
|
|
||||||
in vec4 cursor_color;
|
|
||||||
in vec3 hsv;
|
|
||||||
|
|
||||||
uniform mat4 projection;
|
|
||||||
uniform bool window_bg_layer;
|
|
||||||
uniform bool bg_and_line_layer;
|
|
||||||
uniform bool has_background_image;
|
|
||||||
|
|
||||||
out float o_has_color;
|
|
||||||
out vec2 o_cursor;
|
|
||||||
out vec2 o_tex;
|
|
||||||
out vec2 o_underline;
|
|
||||||
out vec3 o_hsv;
|
|
||||||
out vec4 o_bg_color;
|
|
||||||
out vec4 o_cursor_color;
|
|
||||||
out vec4 o_fg_color;
|
|
||||||
out vec4 o_underline_color;
|
|
||||||
|
|
||||||
// Returns a position that is outside of the viewport,
|
|
||||||
// such that this vertex effectively won't contribute
|
|
||||||
// the scene being rendered.
|
|
||||||
// There may be a better way to do this.
|
|
||||||
vec4 off_screen() {
|
|
||||||
return vec4(100.0, 100.0, 100.0, 100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
o_tex = tex;
|
|
||||||
o_has_color = has_color;
|
|
||||||
o_fg_color = fg_color;
|
|
||||||
o_bg_color = bg_color;
|
|
||||||
o_underline = underline;
|
|
||||||
o_underline_color = underline_color;
|
|
||||||
o_cursor = cursor;
|
|
||||||
o_cursor_color = cursor_color;
|
|
||||||
o_hsv = hsv;
|
|
||||||
|
|
||||||
if (window_bg_layer) {
|
|
||||||
if (o_has_color == 2.0) {
|
|
||||||
// Background image takes up its full coordinates
|
|
||||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
|
||||||
} else {
|
|
||||||
// Nothing else should render on the background layer
|
|
||||||
gl_Position = off_screen();
|
|
||||||
}
|
|
||||||
} else if (o_has_color == 2.0) {
|
|
||||||
// If we're the background image and we're not rendering
|
|
||||||
// the background layer, then move this off screen
|
|
||||||
gl_Position = off_screen();
|
|
||||||
} else if (bg_and_line_layer) {
|
|
||||||
// Want to fill the whole cell when painting backgrounds
|
|
||||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
|
||||||
} else {
|
|
||||||
// Use only the adjusted cell position to render the glyph
|
|
||||||
gl_Position = projection * vec4(position + adjust, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,16 @@ use palette::{Blend, LinSrgb, LinSrgba, Srgb, Srgba};
|
|||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref SRGB_TO_F32_TABLE: [f32;256] = generate_srgb8_to_linear_f32_table();
|
static ref SRGB_TO_F32_TABLE: [f32;256] = generate_srgb8_to_linear_f32_table();
|
||||||
static ref F32_TO_U8_TABLE: [u32;104] = generate_linear_f32_to_srgb8_table();
|
static ref F32_TO_U8_TABLE: [u32;104] = generate_linear_f32_to_srgb8_table();
|
||||||
|
static ref RGB_TO_SRGB_TABLE: [u8;256] = generate_rgb_to_srgb8_table();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_rgb_to_srgb8_table() -> [u8; 256] {
|
||||||
|
let mut table = [0; 256];
|
||||||
|
for (val, entry) in table.iter_mut().enumerate() {
|
||||||
|
let linear = (val as f32) / 255.0;
|
||||||
|
*entry = linear_f32_to_srgb8_using_table(linear);
|
||||||
|
}
|
||||||
|
table
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_srgb8_to_linear_f32_table() -> [f32; 256] {
|
fn generate_srgb8_to_linear_f32_table() -> [f32; 256] {
|
||||||
@ -107,6 +117,10 @@ fn linear_f32_to_srgbf32(f: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pub fn linear_u8_to_srgb8(f: u8) -> u8 {
|
||||||
|
unsafe { *RGB_TO_SRGB_TABLE.get_unchecked(f as usize) }
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::unreadable_literal)]
|
#[allow(clippy::unreadable_literal)]
|
||||||
const ALMOST_ONE: u32 = 0x3f7fffff;
|
const ALMOST_ONE: u32 = 0x3f7fffff;
|
||||||
#[allow(clippy::unreadable_literal)]
|
#[allow(clippy::unreadable_literal)]
|
||||||
@ -289,6 +303,16 @@ impl Color {
|
|||||||
Color(word.to_be())
|
Color(word.to_be())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_linear_rgba_u8(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
|
||||||
|
Self::rgba(
|
||||||
|
linear_u8_to_srgb8(red),
|
||||||
|
linear_u8_to_srgb8(green),
|
||||||
|
linear_u8_to_srgb8(blue),
|
||||||
|
linear_u8_to_srgb8(alpha),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_rgba(self) -> (u8, u8, u8, u8) {
|
pub fn as_rgba(self) -> (u8, u8, u8, u8) {
|
||||||
let host = u32::from_be(self.0);
|
let host = u32::from_be(self.0);
|
||||||
|
Loading…
Reference in New Issue
Block a user