mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-06 08:01:58 +02:00
Centralize the cell shader defines
This commit is contained in:
35
kitty/cell_defines.glsl
Normal file
35
kitty/cell_defines.glsl
Normal file
@@ -0,0 +1,35 @@
|
||||
#define PHASE_BOTH 1
|
||||
#define PHASE_BACKGROUND 2
|
||||
#define PHASE_SPECIAL 3
|
||||
#define PHASE_FOREGROUND 4
|
||||
|
||||
#define PHASE {WHICH_PHASE}
|
||||
#define HAS_TRANSPARENCY {TRANSPARENT}
|
||||
#define FG_OVERRIDE {FG_OVERRIDE}
|
||||
#define FG_OVERRIDE_THRESHOLD {FG_OVERRIDE_THRESHOLD}
|
||||
#define TEXT_NEW_GAMMA {TEXT_NEW_GAMMA}
|
||||
|
||||
#define DECORATION_SHIFT {DECORATION_SHIFT}
|
||||
#define REVERSE_SHIFT {REVERSE_SHIFT}
|
||||
#define STRIKE_SHIFT {STRIKE_SHIFT}
|
||||
#define DIM_SHIFT {DIM_SHIFT}
|
||||
#define MARK_SHIFT {MARK_SHIFT}
|
||||
#define MARK_MASK {MARK_MASK}
|
||||
#define USE_SELECTION_FG
|
||||
#define NUM_COLORS 256
|
||||
|
||||
#if (PHASE == PHASE_BOTH) || (PHASE == PHASE_BACKGROUND) || (PHASE == PHASE_SPECIAL)
|
||||
#define NEEDS_BACKROUND
|
||||
#endif
|
||||
|
||||
#if (PHASE == PHASE_BOTH) || (PHASE == PHASE_FOREGROUND)
|
||||
#define NEEDS_FOREGROUND
|
||||
#endif
|
||||
|
||||
#if (HAS_TRANSPARENCY == 1)
|
||||
#define TRANSPARENT
|
||||
#endif
|
||||
|
||||
#if defined(TRANSPARENT) || (PHASE == PHASE_SPECIAL)
|
||||
#define NEEDS_BG_ALPHA
|
||||
#endif
|
||||
@@ -1,23 +1,11 @@
|
||||
#pragma kitty_include_shader <alpha_blend.glsl>
|
||||
#pragma kitty_include_shader <linear2srgb.glsl>
|
||||
|
||||
#define {WHICH_PROGRAM}
|
||||
#define NOT_TRANSPARENT
|
||||
#define NO_FG_OVERRIDE
|
||||
#define TEXT_NEW_GAMMA
|
||||
|
||||
#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL)
|
||||
#define NEEDS_BACKROUND
|
||||
#endif
|
||||
|
||||
#if defined(SIMPLE) || defined(FOREGROUND)
|
||||
#define NEEDS_FOREGROUND
|
||||
#endif
|
||||
#pragma kitty_include_shader <cell_defines.glsl>
|
||||
|
||||
#ifdef NEEDS_BACKROUND
|
||||
in vec3 background;
|
||||
in float draw_bg;
|
||||
#if defined(TRANSPARENT) || defined(SPECIAL)
|
||||
#ifdef NEEDS_BG_ALPHA
|
||||
in float bg_alpha;
|
||||
#endif
|
||||
#endif
|
||||
@@ -53,8 +41,10 @@ vec4 vec4_premul(vec4 rgba) {
|
||||
|
||||
/*
|
||||
* Explanation of rendering:
|
||||
* There are a couple of cases, in order of increasing complexity:
|
||||
* 1) Simple -- this path is used when there are either no images, or all images are
|
||||
* There are two types of rendering, single pass and multi-pass. Multi-pass rendering is used when there
|
||||
* are images that are below the foreground. Single pass rendering has PHASE=PHASE_BOTH. Otherwise, there
|
||||
* are three passes, PHASE=PHASE_BACKGROUND, PHASE=PHASE_SPECIAL, PHASE=PHASE_FOREGROUND.
|
||||
* 1) Single pass -- this path is used when there are either no images, or all images are
|
||||
* drawn on top of text and the background is opaque. In this case, there is a single pass,
|
||||
* of this shader with cell foreground and background colors blended directly.
|
||||
* Expected output is a color premultiplied by alpha, with an alpha specified as well.
|
||||
@@ -77,10 +67,9 @@ vec4 vec4_premul(vec4 rgba) {
|
||||
* 2b) Transparent bg with images
|
||||
* Same as (2a) except blending is done with PREMULT_BLEND and TRANSPARENT is defined in the shaders. background_opacity
|
||||
* is applied to default colored background cells in step (1).
|
||||
*
|
||||
* In this shader exactly *one* of SIMPLE, SPECIAL, FOREGROUND or BACKGROUND will be defined, corresponding
|
||||
* to the appropriate rendering pass from above.
|
||||
*/
|
||||
|
||||
// foreground functions {{{
|
||||
#ifdef NEEDS_FOREGROUND
|
||||
// sRGB luminance values
|
||||
const vec3 Y = vec3(0.2126, 0.7152, 0.0722);
|
||||
@@ -92,12 +81,12 @@ float clamp_to_unit_float(float x) {
|
||||
return clamp(x, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
#ifdef FG_OVERRIDE
|
||||
#if (FG_OVERRIDE == 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);
|
||||
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));
|
||||
}
|
||||
@@ -107,7 +96,7 @@ vec4 foreground_contrast(vec4 over, vec3 under) {
|
||||
float under_luminance = dot(under, Y);
|
||||
float over_lumininace = dot(over.rgb, Y);
|
||||
|
||||
#ifdef FG_OVERRIDE
|
||||
#if (FG_OVERRIDE == 1)
|
||||
over.rgb = fg_override(under_luminance, over_lumininace, over.rgb);
|
||||
#endif
|
||||
|
||||
@@ -117,12 +106,12 @@ vec4 foreground_contrast(vec4 over, vec3 under) {
|
||||
return over;
|
||||
}
|
||||
|
||||
#ifdef TEXT_OLD_GAMMA
|
||||
#if (TEXT_NEW_GAMMA == 0)
|
||||
vec4 foreground_contrast_incorrect(vec4 over, vec3 under) {
|
||||
// Simulation of gamma-incorrect blending
|
||||
float under_luminance = dot(under, Y);
|
||||
float over_lumininace = dot(over.rgb, Y);
|
||||
#ifdef FG_OVERRIDE
|
||||
#if (FG_OVERRIDE == 1)
|
||||
over.rgb = fg_override(under_luminance, over_lumininace, over.rgb);
|
||||
#endif
|
||||
// This is the original gamma-incorrect rendering, it is the solution of the following equation:
|
||||
@@ -156,7 +145,7 @@ vec4 calculate_premul_foreground_from_sprites(vec4 text_fg) {
|
||||
vec4 adjust_foreground_contrast_with_background(vec4 text_fg, vec3 bg) {
|
||||
// When rendering on a background we can adjust the alpha channel contrast
|
||||
// to improve legibility based on the source and destination colors
|
||||
#ifdef TEXT_OLD_GAMMA
|
||||
#if (TEXT_NEW_GAMMA == 0)
|
||||
return foreground_contrast_incorrect(text_fg, bg);
|
||||
#else
|
||||
return foreground_contrast(text_fg, bg);
|
||||
@@ -164,6 +153,7 @@ vec4 adjust_foreground_contrast_with_background(vec4 text_fg, vec3 bg) {
|
||||
}
|
||||
|
||||
#endif
|
||||
// end foreground functions }}}
|
||||
|
||||
float adjust_alpha_for_incorrect_blending_by_compositor(float text_fg_alpha, float final_alpha) {
|
||||
// Adjust the transparent alpha-channel to account for incorrect
|
||||
@@ -179,7 +169,7 @@ float adjust_alpha_for_incorrect_blending_by_compositor(float text_fg_alpha, flo
|
||||
}
|
||||
|
||||
void main() {
|
||||
#ifdef SIMPLE
|
||||
#if (PHASE == PHASE_BOTH)
|
||||
vec4 text_fg = load_text_foreground_color();
|
||||
text_fg = adjust_foreground_contrast_with_background(text_fg, background);
|
||||
vec4 text_fg_premul = calculate_premul_foreground_from_sprites(text_fg);
|
||||
@@ -191,7 +181,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SPECIAL
|
||||
#if (PHASE == PHASE_SPECIAL)
|
||||
#ifdef TRANSPARENT
|
||||
final_color = vec4_premul(background, bg_alpha);
|
||||
#else
|
||||
@@ -199,7 +189,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BACKGROUND
|
||||
#if (PHASE == PHASE_BACKGROUND)
|
||||
#ifdef TRANSPARENT
|
||||
final_color = vec4_premul(background, bg_alpha);
|
||||
#else
|
||||
@@ -207,7 +197,7 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FOREGROUND
|
||||
#if (PHASE == PHASE_FOREGROUND)
|
||||
vec4 text_fg = load_text_foreground_color();
|
||||
vec4 text_fg_premul = calculate_premul_foreground_from_sprites(text_fg);
|
||||
final_color = text_fg_premul;
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
#extension GL_ARB_explicit_attrib_location : require
|
||||
#pragma kitty_include_shader <srgb_gamma.glsl>
|
||||
#pragma kitty_include_shader <cell_defines.glsl>
|
||||
|
||||
#define {WHICH_PROGRAM}
|
||||
#define NOT_TRANSPARENT
|
||||
#define DECORATION_SHIFT {DECORATION_SHIFT}
|
||||
#define REVERSE_SHIFT {REVERSE_SHIFT}
|
||||
#define STRIKE_SHIFT {STRIKE_SHIFT}
|
||||
#define DIM_SHIFT {DIM_SHIFT}
|
||||
#define MARK_SHIFT {MARK_SHIFT}
|
||||
#define MARK_MASK {MARK_MASK}
|
||||
#define USE_SELECTION_FG
|
||||
#define NUM_COLORS 256
|
||||
|
||||
// Inputs {{{
|
||||
layout(std140) uniform CellRenderData {
|
||||
@@ -23,7 +14,7 @@ layout(std140) uniform CellRenderData {
|
||||
|
||||
uint color_table[NUM_COLORS + MARK_MASK + MARK_MASK + 2];
|
||||
};
|
||||
#ifdef BACKGROUND
|
||||
#if (PHASE == PHASE_BACKGROUND)
|
||||
uniform uint draw_bg_bitfield;
|
||||
#endif
|
||||
|
||||
@@ -43,18 +34,10 @@ const uvec2 cell_pos_map[] = uvec2[4](
|
||||
// }}}
|
||||
|
||||
|
||||
#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL)
|
||||
#define NEEDS_BACKROUND
|
||||
#endif
|
||||
|
||||
#if defined(SIMPLE) || defined(FOREGROUND)
|
||||
#define NEEDS_FOREGROUND
|
||||
#endif
|
||||
|
||||
#ifdef NEEDS_BACKROUND
|
||||
out vec3 background;
|
||||
out float draw_bg;
|
||||
#if defined(TRANSPARENT) || defined(SPECIAL)
|
||||
#ifdef NEEDS_BG_ALPHA
|
||||
out float bg_alpha;
|
||||
#endif
|
||||
#endif
|
||||
@@ -217,7 +200,7 @@ void main() {
|
||||
float cell_has_non_default_bg = step(1, float(abs(bg_as_uint - default_colors[1])));
|
||||
draw_bg = 1;
|
||||
|
||||
#if defined(BACKGROUND)
|
||||
#if (PHASE == PHASE_BACKGROUND)
|
||||
background = bg;
|
||||
// draw_bg_bitfield has bit 0 set to draw default bg cells and bit 1 set to draw non-default bg cells
|
||||
uint draw_bg_mask = uint(2 * cell_has_non_default_bg + (1 - cell_has_non_default_bg));
|
||||
@@ -230,21 +213,21 @@ void main() {
|
||||
// On other cells it should be 1. For the SPECIAL program it should be 1 on cells with
|
||||
// selections/block cursor and 0 everywhere else.
|
||||
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
|
||||
#ifndef SPECIAL
|
||||
#if (PHASE != PHASE_SPECIAL)
|
||||
is_special_cell += cell_has_non_default_bg + float(is_reversed);
|
||||
#endif
|
||||
bg_alpha = step(0.5, is_special_cell);
|
||||
#ifndef SPECIAL
|
||||
#if (PHASE != PHASE_SPECIAL)
|
||||
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity;
|
||||
bg_alpha *= draw_bg;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SPECIAL) || defined(SIMPLE)
|
||||
#if (PHASE == PHASE_SPECIAL) || (PHASE == PHASE_BOTH)
|
||||
// Selection and cursor
|
||||
bg = choose_color(float(is_selected & ONE), choose_color(use_cell_for_selection_bg, color_to_vec(fg_as_uint), color_to_vec(highlight_bg)), bg);
|
||||
background = choose_color(cell_has_block_cursor, color_to_vec(cursor_bg), bg);
|
||||
#if !defined(TRANSPARENT) && defined(SPECIAL)
|
||||
#if !defined(TRANSPARENT) && (PHASE == PHASE_SPECIAL)
|
||||
float is_special_cell = cell_has_block_cursor + float(is_selected & ONE);
|
||||
bg_alpha = step(0.5, is_special_cell);
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import re
|
||||
from functools import lru_cache, partial
|
||||
from itertools import count
|
||||
from typing import Any, Callable, Dict, Iterator, Optional
|
||||
from typing import Any, Callable, Dict, Iterator, Optional, Set
|
||||
|
||||
from .constants import read_kitty_resource
|
||||
from .fast_data_types import (
|
||||
@@ -53,16 +53,17 @@ class Program:
|
||||
Program.include_pat = re.compile(r'^#pragma\s+kitty_include_shader\s+<(.+?)>', re.MULTILINE)
|
||||
self.vertex_name = vertex_name or f'{name}_vertex.glsl'
|
||||
self.fragment_name = fragment_name or f'{name}_fragment.glsl'
|
||||
self.original_vertex_sources = tuple(self._load_sources(self.vertex_name))
|
||||
self.original_fragment_sources = tuple(self._load_sources(self.fragment_name))
|
||||
self.original_vertex_sources = tuple(self._load_sources(self.vertex_name, set()))
|
||||
self.original_fragment_sources = tuple(self._load_sources(self.fragment_name, set()))
|
||||
self.vertex_sources = self.original_vertex_sources
|
||||
self.fragment_sources = self.original_fragment_sources
|
||||
|
||||
def _load_sources(self, name: str, level: int = 0) -> Iterator[str]:
|
||||
def _load_sources(self, name: str, seen: Set[str], level: int = 0) -> Iterator[str]:
|
||||
if level == 0:
|
||||
yield f'#version {GLSL_VERSION}\n'
|
||||
if name in self.filename_map:
|
||||
if name in seen:
|
||||
return
|
||||
seen.add(name)
|
||||
self.filename_map[name] = fnum = next(self.filename_number_counter)
|
||||
src = read_kitty_resource(name).decode('utf-8')
|
||||
pos = 0
|
||||
@@ -74,7 +75,7 @@ class Program:
|
||||
yield f'\n#line {lnum} {fnum}\n{prefix}'
|
||||
lnum += prefix.count('\n')
|
||||
iname = m.group(1)
|
||||
yield from self._load_sources(iname, level+1)
|
||||
yield from self._load_sources(iname, seen, level+1)
|
||||
pos = m.end()
|
||||
if pos < len(src):
|
||||
yield f'\n#line {lnum} {fnum}\n{src[pos:]}'
|
||||
@@ -161,32 +162,24 @@ class LoadShaderPrograms:
|
||||
STRIKE_SPRITE_INDEX=NUM_UNDERLINE_STYLES + 1,
|
||||
)
|
||||
|
||||
def resolve_cell_vertex_defines(which: str, v: str) -> str:
|
||||
self.cell_program_replacer.replacements['WHICH_PROGRAM'] = which
|
||||
v = self.cell_program_replacer(v)
|
||||
if semi_transparent:
|
||||
v = v.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')
|
||||
return v
|
||||
|
||||
def resolve_cell_fragment_defines(which: str, f: str) -> str:
|
||||
f = f.replace('{WHICH_PROGRAM}', which)
|
||||
if self.text_fg_override_threshold != 0.:
|
||||
f = f.replace('#define NO_FG_OVERRIDE', f'#define FG_OVERRIDE {self.text_fg_override_threshold}')
|
||||
if self.text_old_gamma:
|
||||
f = f.replace('#define TEXT_NEW_GAMMA', '#define TEXT_OLD_GAMMA')
|
||||
if semi_transparent:
|
||||
f = f.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')
|
||||
return f
|
||||
def resolve_cell_defines(which: str, src: str) -> str:
|
||||
r = self.cell_program_replacer.replacements
|
||||
r['WHICH_PHASE'] = f'PHASE_{which}'
|
||||
r['TRANSPARENT'] = '1' if semi_transparent else '0'
|
||||
r['FG_OVERRIDE_THRESHOLD'] = str(self.text_fg_override_threshold)
|
||||
r['FG_OVERRIDE'] = '1' if self.text_fg_override_threshold != 0. else '0'
|
||||
r['TEXT_NEW_GAMMA'] = '0' if self.text_old_gamma else '1'
|
||||
return self.cell_program_replacer(src)
|
||||
|
||||
for which, p in {
|
||||
'SIMPLE': CELL_PROGRAM,
|
||||
'BOTH': CELL_PROGRAM,
|
||||
'BACKGROUND': CELL_BG_PROGRAM,
|
||||
'SPECIAL': CELL_SPECIAL_PROGRAM,
|
||||
'FOREGROUND': CELL_FG_PROGRAM,
|
||||
}.items():
|
||||
cell.apply_to_sources(
|
||||
vertex=partial(resolve_cell_vertex_defines, which),
|
||||
frag=partial(resolve_cell_fragment_defines, which),
|
||||
vertex=partial(resolve_cell_defines, which),
|
||||
frag=partial(resolve_cell_defines, which),
|
||||
)
|
||||
cell.compile(p, allow_recompile)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user