mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-11-13 12:09:35 +03:00
Cache shader source code loading
This commit is contained in:
parent
85a955a796
commit
9f377c5ccb
@ -4,8 +4,8 @@
|
||||
from enum import IntFlag
|
||||
from typing import Iterable, NamedTuple, Sequence
|
||||
|
||||
from .fast_data_types import BORDERS_PROGRAM, add_borders_rect, compile_program, get_options, init_borders_program, os_window_has_background_image
|
||||
from .shaders import load_shaders
|
||||
from .fast_data_types import BORDERS_PROGRAM, add_borders_rect, get_options, init_borders_program, os_window_has_background_image
|
||||
from .shaders import program_for
|
||||
from .typing import LayoutType
|
||||
from .window_list import WindowGroup, WindowList
|
||||
|
||||
@ -61,7 +61,7 @@ def draw_edges(os_window_id: int, tab_id: int, colors: Sequence[int], wg: Window
|
||||
|
||||
|
||||
def load_borders_program() -> None:
|
||||
compile_program(BORDERS_PROGRAM, *load_shaders('border'))
|
||||
program_for('border').compile(BORDERS_PROGRAM)
|
||||
init_borders_program()
|
||||
|
||||
|
||||
|
@ -2,33 +2,56 @@
|
||||
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import re
|
||||
from typing import Iterator, Tuple
|
||||
from functools import lru_cache
|
||||
from typing import Callable, Iterator, Optional
|
||||
|
||||
from .constants import read_kitty_resource
|
||||
from .fast_data_types import GLSL_VERSION
|
||||
from .fast_data_types import GLSL_VERSION, compile_program
|
||||
|
||||
|
||||
def load_shaders(name: str, vertex_name: str = '', fragment_name: str = '') -> Tuple[Tuple[str, ...], Tuple[str, ...]]:
|
||||
pat = re.compile(r'^#pragma\s+kitty_include_shader\s+<(.+?)>', re.MULTILINE)
|
||||
def identity(x: str) -> str:
|
||||
return x
|
||||
|
||||
def load_sources(name: str, level: int = 0) -> Iterator[str]:
|
||||
|
||||
class Program:
|
||||
|
||||
include_pat: Optional['re.Pattern[str]'] = None
|
||||
|
||||
def __init__(self, name: str, vertex_name: str = '', fragment_name: str = '') -> None:
|
||||
self.name = name
|
||||
if Program.include_pat is None:
|
||||
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.vertex_sources = self.original_vertex_sources
|
||||
self.fragment_sources = self.original_fragment_sources
|
||||
|
||||
def _load_sources(self, name: str, level: int = 0) -> Iterator[str]:
|
||||
if level == 0:
|
||||
yield f'#version {GLSL_VERSION}\n'
|
||||
src = read_kitty_resource(name).decode('utf-8')
|
||||
pos = 0
|
||||
for m in pat.finditer(src):
|
||||
assert Program.include_pat is not None
|
||||
for m in Program.include_pat.finditer(src):
|
||||
prefix = src[pos:m.start()]
|
||||
if prefix:
|
||||
yield prefix
|
||||
iname = m.group(1)
|
||||
yield from load_sources(iname, level+1)
|
||||
yield from self._load_sources(iname, level+1)
|
||||
pos = m.start()
|
||||
if pos < len(src):
|
||||
yield src[pos:]
|
||||
|
||||
def load(which: str, lname: str = '') -> Tuple[str, ...]:
|
||||
lname = lname or name
|
||||
main = f'{lname}_{which}.glsl'
|
||||
return tuple(load_sources(main))
|
||||
def apply_to_sources(self, vertex: Callable[[str], str] = identity, frag: Callable[[str], str] = identity) -> None:
|
||||
self.vertex_sources = self.original_vertex_sources if vertex is identity else tuple(map(vertex, self.original_vertex_sources))
|
||||
self.fragment_sources = self.original_fragment_sources if frag is identity else tuple(map(frag, self.original_fragment_sources))
|
||||
|
||||
return load('vertex', vertex_name), load('fragment', fragment_name)
|
||||
def compile(self, program_id: int, allow_recompile: bool = False) -> None:
|
||||
compile_program(program_id, self.vertex_sources, self.fragment_sources, allow_recompile)
|
||||
|
||||
|
||||
@lru_cache(maxsize=64)
|
||||
def program_for(name: str) -> Program:
|
||||
return Program(name)
|
||||
|
@ -78,7 +78,6 @@ from .fast_data_types import (
|
||||
cell_size_for_window,
|
||||
click_mouse_cmd_output,
|
||||
click_mouse_url,
|
||||
compile_program,
|
||||
current_focused_os_window_id,
|
||||
encode_key_for_tty,
|
||||
get_boss,
|
||||
@ -107,7 +106,7 @@ from .notify import (
|
||||
)
|
||||
from .options.types import Options
|
||||
from .rgb import to_color
|
||||
from .shaders import load_shaders
|
||||
from .shaders import program_for
|
||||
from .terminfo import get_capabilities
|
||||
from .types import MouseEvent, OverlayType, WindowGeometry, ac, run_once
|
||||
from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict
|
||||
@ -392,54 +391,63 @@ class LoadShaderPrograms:
|
||||
opts = get_options()
|
||||
self.text_old_gamma = opts.text_composition_strategy == 'legacy'
|
||||
self.text_fg_override_threshold = max(0, min(opts.text_fg_override_threshold, 100)) * 0.01
|
||||
compile_program(BLIT_PROGRAM, *load_shaders('blit'), allow_recompile)
|
||||
vs, fs = load_shaders('cell')
|
||||
program_for('blit').compile(BLIT_PROGRAM, allow_recompile)
|
||||
cell = program_for('cell')
|
||||
|
||||
def resolve_cell_vertex_defines(which: str, v: str) -> str:
|
||||
v = multi_replace(
|
||||
v,
|
||||
WHICH_PROGRAM=which,
|
||||
REVERSE_SHIFT=REVERSE,
|
||||
STRIKE_SHIFT=STRIKETHROUGH,
|
||||
DIM_SHIFT=DIM,
|
||||
DECORATION_SHIFT=DECORATION,
|
||||
MARK_SHIFT=MARK,
|
||||
MARK_MASK=MARK_MASK,
|
||||
DECORATION_MASK=DECORATION_MASK,
|
||||
STRIKE_SPRITE_INDEX=NUM_UNDERLINE_STYLES + 1,
|
||||
)
|
||||
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
|
||||
|
||||
for which, p in {
|
||||
'SIMPLE': CELL_PROGRAM,
|
||||
'BACKGROUND': CELL_BG_PROGRAM,
|
||||
'SPECIAL': CELL_SPECIAL_PROGRAM,
|
||||
'FOREGROUND': CELL_FG_PROGRAM,
|
||||
'SIMPLE': CELL_PROGRAM,
|
||||
'BACKGROUND': CELL_BG_PROGRAM,
|
||||
'SPECIAL': CELL_SPECIAL_PROGRAM,
|
||||
'FOREGROUND': CELL_FG_PROGRAM,
|
||||
}.items():
|
||||
vvs, ffs = [], []
|
||||
for v in vs:
|
||||
vv = multi_replace(
|
||||
v,
|
||||
WHICH_PROGRAM=which,
|
||||
REVERSE_SHIFT=REVERSE,
|
||||
STRIKE_SHIFT=STRIKETHROUGH,
|
||||
DIM_SHIFT=DIM,
|
||||
DECORATION_SHIFT=DECORATION,
|
||||
MARK_SHIFT=MARK,
|
||||
MARK_MASK=MARK_MASK,
|
||||
DECORATION_MASK=DECORATION_MASK,
|
||||
STRIKE_SPRITE_INDEX=NUM_UNDERLINE_STYLES + 1,
|
||||
)
|
||||
if semi_transparent:
|
||||
vv = vv.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')
|
||||
vvs.append(vv)
|
||||
for f in fs:
|
||||
ff = f.replace('{WHICH_PROGRAM}', which)
|
||||
if self.text_fg_override_threshold != 0.:
|
||||
ff = ff.replace('#define NO_FG_OVERRIDE', f'#define FG_OVERRIDE {self.text_fg_override_threshold}')
|
||||
if self.text_old_gamma:
|
||||
ff = ff.replace('#define TEXT_NEW_GAMMA', '#define TEXT_OLD_GAMMA')
|
||||
if semi_transparent:
|
||||
ff = ff.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')
|
||||
ffs.append(ff)
|
||||
compile_program(p, tuple(vvs), tuple(ffs), allow_recompile)
|
||||
cell.apply_to_sources(
|
||||
vertex=partial(resolve_cell_vertex_defines, which),
|
||||
frag=partial(resolve_cell_fragment_defines, which),
|
||||
)
|
||||
cell.compile(p, allow_recompile)
|
||||
|
||||
graphics = program_for('graphics')
|
||||
|
||||
def resolve_graphics_fragment_defines(which: str, f: str) -> str:
|
||||
return f.replace('ALPHA_TYPE', which)
|
||||
|
||||
vs, fs = load_shaders('graphics')
|
||||
for which, p in {
|
||||
'SIMPLE': GRAPHICS_PROGRAM,
|
||||
'PREMULT': GRAPHICS_PREMULT_PROGRAM,
|
||||
'ALPHA_MASK': GRAPHICS_ALPHA_MASK_PROGRAM,
|
||||
'SIMPLE': GRAPHICS_PROGRAM,
|
||||
'PREMULT': GRAPHICS_PREMULT_PROGRAM,
|
||||
'ALPHA_MASK': GRAPHICS_ALPHA_MASK_PROGRAM,
|
||||
}.items():
|
||||
ff = f.replace('ALPHA_TYPE', which)
|
||||
compile_program(p, vs, tuple(f.replace('ALPHA_TYPE', which) for f in fs), allow_recompile)
|
||||
graphics.apply_to_sources(frag=partial(resolve_cell_fragment_defines, which))
|
||||
graphics.compile(p, allow_recompile)
|
||||
|
||||
compile_program(BGIMAGE_PROGRAM, *load_shaders('bgimage'), allow_recompile)
|
||||
compile_program(TINT_PROGRAM, *load_shaders('tint'), allow_recompile)
|
||||
program_for('bgimage').compile(BGIMAGE_PROGRAM, allow_recompile)
|
||||
program_for('tint').compile(TINT_PROGRAM)
|
||||
init_cell_program()
|
||||
|
||||
|
||||
|
@ -31,9 +31,9 @@ class TestBuild(BaseTest):
|
||||
del fdt, rsync
|
||||
|
||||
def test_loading_shaders(self) -> None:
|
||||
from kitty.utils import load_shaders
|
||||
from kitty.shaders import Program
|
||||
for name in 'cell border bgimage tint blit graphics'.split():
|
||||
load_shaders(name)
|
||||
Program(name)
|
||||
|
||||
def test_glfw_modules(self) -> None:
|
||||
from kitty.constants import glfw_path, is_macos
|
||||
|
Loading…
Reference in New Issue
Block a user