Move text_fg_override code into vertex shader

This should be a ~100x speedup (depending on pixels per cell) for using this code. Note that it also means
that color emoji do not have their colors overridden. This makes sense
since overriding color sin them is not desired anyway and even otherwise
the performance benefits are too large.
This commit is contained in:
Kovid Goyal 2025-03-19 22:27:18 +05:30
parent 5ec653bf86
commit c6db9b0b21
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 50 additions and 48 deletions

View file

@ -30,3 +30,6 @@
#if (HAS_TRANSPARENCY == 1)
#define TRANSPARENT
#endif
// sRGB luminance values
const vec3 Y = vec3(0.2126, 0.7152, 0.0722);

View file

@ -1,5 +1,4 @@
#pragma kitty_include_shader <alpha_blend.glsl>
#pragma kitty_include_shader <hsluv.glsl>
#pragma kitty_include_shader <linear2srgb.glsl>
#pragma kitty_include_shader <cell_defines.glsl>
@ -68,8 +67,6 @@ vec4 vec4_premul(vec4 rgba) {
// foreground functions {{{
#ifdef NEEDS_FOREGROUND
// sRGB luminance values
const vec3 Y = vec3(0.2126, 0.7152, 0.0722);
// Scaling factor for the extra text-alpha adjustment for luminance-difference.
const float text_gamma_scaling = 0.5;
@ -78,47 +75,10 @@ float clamp_to_unit_float(float x) {
return clamp(x, 0.0f, 1.0f);
}
#if (FG_OVERRIDE_ALGO == 1)
vec3 fg_override(float under_luminance, float over_lumininace, vec3 over) {
// If the difference in luminance is too small,
// force the foreground color to be black or white.
float diff_luminance = abs(under_luminance - over_lumininace);
float override_level = (1.f - colored_sprite) * step(diff_luminance, FG_OVERRIDE_THRESHOLD);
float original_level = 1.f - override_level;
return original_level * over + override_level * vec3(step(under_luminance, 0.5f));
}
#else
float contrast_ratio(float under_luminance, float over_luminance) {
return clamp((max(under_luminance, over_luminance) + 0.05f) / (min(under_luminance, over_luminance) + 0.05f), 1.f, 21.f);
}
vec3 apply_min_contrast_ratio(float under_luminance, float over_luminance, vec3 under, vec3 over) {
float ratio = contrast_ratio(under_luminance, over_luminance);
vec3 diff = abs(under - over);
vec3 over_hsluv = rgbToHsluv(over);
const float min_contrast_ratio = FG_OVERRIDE_THRESHOLD;
float target_lum_a = clamp((under_luminance + 0.05f) * min_contrast_ratio - 0.05f, 0.f, 1.f);
float target_lum_b = clamp((under_luminance + 0.05f) / min_contrast_ratio - 0.05f, 0.f, 1.f);
vec3 result_a = clamp(hsluvToRgb(vec3(over_hsluv.x, over_hsluv.y, target_lum_a * 100.f)), 0.f, 1.f);
vec3 result_b = clamp(hsluvToRgb(vec3(over_hsluv.x, over_hsluv.y, target_lum_b * 100.f)), 0.f, 1.f);
float result_a_ratio = contrast_ratio(under_luminance, dot(result_a, Y));
float result_b_ratio = contrast_ratio(under_luminance, dot(result_b, Y));
vec3 result = mix(result_a, result_b, step(result_a_ratio, result_b_ratio));
return mix(result, over, max(step(diff.r + diff.g + diff.g, 0.001f), step(min_contrast_ratio, ratio)));
}
#endif
#if TEXT_NEW_GAMMA == 1
vec4 foreground_contrast(vec4 over, vec3 under) {
float under_luminance = dot(under, Y);
float over_lumininace = dot(over.rgb, Y);
#if DO_FG_OVERRIDE == 1
#if FG_OVERRIDE_ALGO == 1
over.rgb = fg_override(under_luminance, over_lumininace, over.rgb);
#else
over.rgb = apply_min_contrast_ratio(under_luminance, over_lumininace, under, over.rgb);
#endif
over_lumininace = dot(over.rgb, Y);
#endif
// Apply additional gamma-adjustment scaled by the luminance difference, the darker the foreground the more adjustment we apply.
// A multiplicative contrast is also available to increase saturation.
over.a = clamp_to_unit_float(mix(over.a, pow(over.a, text_gamma_adjustment), (1 - over_lumininace + under_luminance) * text_gamma_scaling) * text_contrast);
@ -131,14 +91,6 @@ vec4 foreground_contrast(vec4 over, vec3 under) {
// Simulation of gamma-incorrect blending
float under_luminance = dot(under, Y);
float over_lumininace = dot(over.rgb, Y);
#if DO_FG_OVERRIDE == 1
#if FG_OVERRIDE_ALGO == 1
over.rgb = fg_override(under_luminance, over_lumininace, over.rgb);
#else
over.rgb = apply_min_contrast_ratio(under_luminance, over_lumininace, under, over.rgb);
#endif
over_lumininace = dot(over.rgb, Y);
#endif
// This is the original gamma-incorrect rendering, it is the solution of the following equation:
//
// linear2srgb(over * overA2 + under * (1 - overA2)) = linear2srgb(over) * over.a + linear2srgb(under) * (1 - over.a)

View file

@ -208,6 +208,48 @@ float calc_background_opacity(uint bg) {
);
}
#if defined(NEEDS_FOREGROUND) && DO_FG_OVERRIDE == 1
#define OVERRIDE_FG_COLORS
#pragma kitty_include_shader <hsluv.glsl>
#if (FG_OVERRIDE_ALGO == 1)
vec3 fg_override(float under_luminance, float over_lumininace, vec3 under, vec3 over) {
// If the difference in luminance is too small,
// force the foreground color to be black or white.
float diff_luminance = abs(under_luminance - over_lumininace);
float override_level = (1.f - colored_sprite) * step(diff_luminance, FG_OVERRIDE_THRESHOLD);
float original_level = 1.f - override_level;
return original_level * over + override_level * vec3(step(under_luminance, 0.5f));
}
#else
float contrast_ratio(float under_luminance, float over_luminance) {
return clamp((max(under_luminance, over_luminance) + 0.05f) / (min(under_luminance, over_luminance) + 0.05f), 1.f, 21.f);
}
vec3 fg_override(float under_luminance, float over_luminance, vec3 under, vec3 over) {
float ratio = contrast_ratio(under_luminance, over_luminance);
vec3 diff = abs(under - over);
vec3 over_hsluv = rgbToHsluv(over);
const float min_contrast_ratio = FG_OVERRIDE_THRESHOLD;
float target_lum_a = clamp((under_luminance + 0.05f) * min_contrast_ratio - 0.05f, 0.f, 1.f);
float target_lum_b = clamp((under_luminance + 0.05f) / min_contrast_ratio - 0.05f, 0.f, 1.f);
vec3 result_a = clamp(hsluvToRgb(vec3(over_hsluv.x, over_hsluv.y, target_lum_a * 100.f)), 0.f, 1.f);
vec3 result_b = clamp(hsluvToRgb(vec3(over_hsluv.x, over_hsluv.y, target_lum_b * 100.f)), 0.f, 1.f);
float result_a_ratio = contrast_ratio(under_luminance, dot(result_a, Y));
float result_b_ratio = contrast_ratio(under_luminance, dot(result_b, Y));
vec3 result = mix(result_a, result_b, step(result_a_ratio, result_b_ratio));
return mix(result, over, max(step(diff.r + diff.g + diff.g, 0.001f), step(min_contrast_ratio, ratio)));
}
#endif
vec3 override_foreground_color(vec3 over, vec3 under) {
float under_luminance = dot(under, Y);
float over_lumininace = dot(over.rgb, Y);
return fg_override(under_luminance, over_lumininace, under, over);
}
#endif
void main() {
CellData cell_data = set_vertex_position();
@ -292,4 +334,9 @@ void main() {
float effective_cursor_opacity = max(cursor_opacity, orig_bg_alpha) * draw_bg;
bg_alpha = choose_alpha(cell_data.has_block_cursor, effective_cursor_opacity, bg_alpha);
// }}}
#ifdef OVERRIDE_FG_COLORS
decoration_fg = override_foreground_color(decoration_fg, background);
foreground = override_foreground_color(foreground, background);
#endif
}