From e165cdf2100bdf96f53c463c3ab49dafb3c82c63 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sat, 31 Jul 2021 07:28:52 -0700 Subject: [PATCH] Consolidate shader logic Now that we have a single pass, we don't need to "include" snippets, and that makes the shaders a lot easier to follow. refs: #986 --- wezterm-gui/src/fragment-common.glsl | 113 --------------------------- wezterm-gui/src/glyph-frag.glsl | 106 ++++++++++++++++++++++++- wezterm-gui/src/glyph-vertex.glsl | 25 +++++- wezterm-gui/src/renderstate.rs | 10 +-- wezterm-gui/src/vertex-common.glsl | 34 -------- 5 files changed, 130 insertions(+), 158 deletions(-) delete mode 100644 wezterm-gui/src/fragment-common.glsl delete mode 100644 wezterm-gui/src/vertex-common.glsl diff --git a/wezterm-gui/src/fragment-common.glsl b/wezterm-gui/src/fragment-common.glsl deleted file mode 100644 index 1577e7fd2..000000000 --- a/wezterm-gui/src/fragment-common.glsl +++ /dev/null @@ -1,113 +0,0 @@ -// This file is automatically prepended to the various -frag shaders. - -precision highp float; - -in float o_has_color; -in vec2 o_tex; -in vec3 o_hsv; -in vec4 o_fg_color; - -out vec4 color; - -uniform vec3 foreground_text_hsb; - -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)); -} - -// Alpha-regulated multiply to colorize the glyph bitmap. -vec4 multiply(vec4 src, vec4 dst) { - float inv_src_alpha = 1.0 - src.a; - float inv_dst_alpha = 1.0 - dst.a; - - return vec4( - multiply_one(src.r, dst.r, inv_dst_alpha, inv_src_alpha), - multiply_one(src.g, dst.g, inv_dst_alpha, inv_src_alpha), - multiply_one(src.b, dst.b, inv_dst_alpha, inv_src_alpha), - dst.a); -} - -vec3 rgb2hsv(vec3 c) -{ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) -{ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - -const vec3 unit3 = vec3(1.0, 1.0, 1.0); - -vec4 apply_hsv(vec4 c, vec3 transform) -{ - if (transform == unit3) { - return c; - } - vec3 hsv = rgb2hsv(c.rgb) * transform; - return vec4(hsv2rgb(hsv).rgb, c.a); -} - -// Given glyph, the greyscale rgba value computed by freetype, -// and color, the desired color, compute the resultant pixel -// value for rendering over the top of the given background -// color. -// -// The freetype glyph is greyscale (R=G=B=A) when font_antialias=Greyscale, -// where each channel holds the brightness of the pixel. -// It holds separate intensity values for the R, G and B channels when -// subpixel anti-aliasing is in use, with an approximated A value -// derived from the R, G, B values. -// -// In sub-pixel mode we don't want to look at glyph.a as we effective -// have per-channel alpha. In greyscale mode, glyph.a is the same -// as the other channels, so this routine ignores glyph.a when -// computing the blend, but does include that value for the returned -// alpha value. -// -// See also: https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-gamma-correct-font-rendering/ -vec4 colorize(vec4 glyph, vec4 color, vec4 background) { - float r = glyph.r * color.r + (1.0 - glyph.r) * background.r; - float g = glyph.g * color.g + (1.0 - glyph.g) * background.g; - float b = glyph.b * color.b + (1.0 - glyph.b) * background.b; - - return vec4(r, g, b, glyph.a); -// return vec4(glyph.rgb * color.rgb, glyph.a); -} - -vec4 colorize2(vec4 glyph, vec4 color) { - float r = glyph.r * color.r;// + (1.0 - glyph.r) * background.r; - float g = glyph.g * color.g;// + (1.0 - glyph.g) * background.g; - float b = glyph.b * color.b;// + (1.0 - glyph.b) * background.b; - - return vec4(r, g, b, glyph.a); -// return vec4(glyph.rgb * color.rgb, glyph.a); -} - -vec4 from_linear(vec4 v) { - return pow(v, vec4(2.2)); -} - -vec4 to_gamma(vec4 v) { - return pow(v, vec4(1.0/2.2)); -} - -// For reasons that I haven't been able to figure out, we need -// to gamma correct the data that we read from the textures that -// are supplied to OpenGL, otherwise they appear too dark. -// AFAICT, I've done what I thought were all of the right things -// (but are perhaps only some of the right things) to tell OpenGL/EGL -// that everything is already SRGB, so this function should really -// just be a call to `texture` and not do the gamma conversion. -vec4 sample_texture(sampler2D s, vec2 coords) { - vec4 color = texture(s, coords); - return to_gamma(color); -} diff --git a/wezterm-gui/src/glyph-frag.glsl b/wezterm-gui/src/glyph-frag.glsl index f177b48a9..1b537ac2d 100644 --- a/wezterm-gui/src/glyph-frag.glsl +++ b/wezterm-gui/src/glyph-frag.glsl @@ -1,11 +1,115 @@ // This is the Glyph fragment shader. // It is responsible for laying down the glyph graphics on top of the other layers. -// Note: fragment-common.glsl is automatically prepended! +precision highp float; +in float o_has_color; +in vec2 o_tex; +in vec3 o_hsv; +in vec4 o_fg_color; + +out vec4 color; + +uniform vec3 foreground_text_hsb; uniform sampler2D atlas_nearest_sampler; uniform sampler2D atlas_linear_sampler; + +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)); +} + +// Alpha-regulated multiply to colorize the glyph bitmap. +vec4 multiply(vec4 src, vec4 dst) { + float inv_src_alpha = 1.0 - src.a; + float inv_dst_alpha = 1.0 - dst.a; + + return vec4( + multiply_one(src.r, dst.r, inv_dst_alpha, inv_src_alpha), + multiply_one(src.g, dst.g, inv_dst_alpha, inv_src_alpha), + multiply_one(src.b, dst.b, inv_dst_alpha, inv_src_alpha), + dst.a); +} + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +const vec3 unit3 = vec3(1.0, 1.0, 1.0); + +vec4 apply_hsv(vec4 c, vec3 transform) +{ + if (transform == unit3) { + return c; + } + vec3 hsv = rgb2hsv(c.rgb) * transform; + return vec4(hsv2rgb(hsv).rgb, c.a); +} + +// Given glyph, the greyscale rgba value computed by freetype, +// and color, the desired color, compute the resultant pixel +// value for rendering over the top of the given background +// color. +// +// The freetype glyph is greyscale (R=G=B=A) when font_antialias=Greyscale, +// where each channel holds the brightness of the pixel. +// It holds separate intensity values for the R, G and B channels when +// subpixel anti-aliasing is in use, with an approximated A value +// derived from the R, G, B values. +// +// In sub-pixel mode we don't want to look at glyph.a as we effective +// have per-channel alpha. In greyscale mode, glyph.a is the same +// as the other channels, so this routine ignores glyph.a when +// computing the blend, but does include that value for the returned +// alpha value. +// +// See also: https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-gamma-correct-font-rendering/ +vec4 colorize(vec4 glyph, vec4 color, vec4 background) { + float r = glyph.r * color.r + (1.0 - glyph.r) * background.r; + float g = glyph.g * color.g + (1.0 - glyph.g) * background.g; + float b = glyph.b * color.b + (1.0 - glyph.b) * background.b; + + return vec4(r, g, b, glyph.a); +} + +vec4 colorize2(vec4 glyph, vec4 color) { + return vec4(glyph.rgb * color.rgb, glyph.a); +} + +vec4 from_linear(vec4 v) { + return pow(v, vec4(2.2)); +} + +vec4 to_gamma(vec4 v) { + return pow(v, vec4(1.0/2.2)); +} + +// For reasons that I haven't been able to figure out, we need +// to gamma correct the data that we read from the textures that +// are supplied to OpenGL, otherwise they appear too dark. +// AFAICT, I've done what I thought were all of the right things +// (but are perhaps only some of the right things) to tell OpenGL/EGL +// that everything is already SRGB, so this function should really +// just be a call to `texture` and not do the gamma conversion. +vec4 sample_texture(sampler2D s, vec2 coords) { + vec4 color = texture(s, coords); + return to_gamma(color); +} + void main() { if (o_has_color == 2.0) { // The window background attachment diff --git a/wezterm-gui/src/glyph-vertex.glsl b/wezterm-gui/src/glyph-vertex.glsl index 83fb9bf66..cf601415b 100644 --- a/wezterm-gui/src/glyph-vertex.glsl +++ b/wezterm-gui/src/glyph-vertex.glsl @@ -2,11 +2,32 @@ // It is responsible for placing the glyph images in the // correct place on screen. -// Note: vertex-common.glsl is automatically prepended! +precision highp float; + +in vec2 position; +in vec2 adjust; +in vec2 tex; +in vec4 fg_color; +in float has_color; +in vec3 hsv; + +uniform mat4 projection; + +out float o_has_color; +out vec2 o_tex; +out vec3 o_hsv; +out vec4 o_fg_color; + +void pass_through_vertex() { + o_tex = tex; + o_has_color = has_color; + o_fg_color = fg_color; + o_hsv = hsv; +} void main() { pass_through_vertex(); - // Use only the adjusted cell position to render the glyph + // Use the adjusted cell position to render the quad gl_Position = projection * vec4(position + adjust, 0.0, 1.0); } diff --git a/wezterm-gui/src/renderstate.rs b/wezterm-gui/src/renderstate.rs index 3caa2b074..0b1b1604e 100644 --- a/wezterm-gui/src/renderstate.rs +++ b/wezterm-gui/src/renderstate.rs @@ -188,17 +188,11 @@ impl RenderState { fn glyph_shader(version: &str) -> (String, String) { ( format!( - "#version {}\n{}\n{}", + "#version {}\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") - ), + format!("#version {}\n{}", version, include_str!("glyph-frag.glsl")), ) } diff --git a/wezterm-gui/src/vertex-common.glsl b/wezterm-gui/src/vertex-common.glsl deleted file mode 100644 index e596f4916..000000000 --- a/wezterm-gui/src/vertex-common.glsl +++ /dev/null @@ -1,34 +0,0 @@ -// This file is automatically prepended to the various -// vertex.glsl files. - -precision highp float; - -in vec2 position; -in vec2 adjust; -in vec2 tex; -in vec4 fg_color; -in float has_color; -in vec3 hsv; - -uniform mat4 projection; - -out float o_has_color; -out vec2 o_tex; -out vec3 o_hsv; -out vec4 o_fg_color; - -void pass_through_vertex() { - o_tex = tex; - o_has_color = has_color; - o_fg_color = fg_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); -} -