mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-02-01 11:34:59 +01:00
This was needed to fix various corner cases when doing blending of colors in linear space. The new architecture has the same performance as the old in the common case of opaque rendering with no UI layers or images. In the case of only positive z-index images there is a performance decrease as the OS Window is now rendered to a offscreen texture and then blitted to screen. However, in the future when we move to Vulkan or I can figure out how to get Wayland to accept buffers with colors in linear space, this performance penalty can be removed. The performance penalty was not significant on my system but this is highly GPU dependent. Modern GPUs are supposedly optimised for rendering to offscreen buffers, so we will see. The awrit project might be a good test case. Now either we have 1-shot rendering for the case of opaque with only ext or all the various pieces are rendered in successive draw calls into an offscreen buffer that is blitted to the output buffer after all drawing is done. Fixes #8869
114 lines
3.8 KiB
Python
114 lines
3.8 KiB
Python
#!/usr/bin/env python
|
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
from collections.abc import Iterable
|
|
from enum import IntFlag
|
|
from functools import partial
|
|
from typing import NamedTuple
|
|
|
|
from .fast_data_types import BORDERS_PROGRAM, get_options, init_borders_program, set_borders_rects
|
|
from .shaders import program_for
|
|
from .typing_compat import LayoutType
|
|
from .utils import color_as_int
|
|
from .window_list import WindowGroup, WindowList
|
|
|
|
|
|
class BorderColor(IntFlag):
|
|
# These are indices into the array of colors in the border vertex shader
|
|
default_bg, active, inactive, window_bg, bell, tab_bar_bg, tab_bar_margin_color, tab_bar_left_edge_color, tab_bar_right_edge_color = range(9)
|
|
|
|
|
|
class Border(NamedTuple):
|
|
left: int
|
|
top: int
|
|
right: int
|
|
bottom: int
|
|
color: BorderColor
|
|
|
|
|
|
def vertical_edge(rects: list[Border], color: BorderColor, width: int, top: int, bottom: int, left: int) -> None:
|
|
if width > 0:
|
|
rects.append(Border(left, top, left + width, bottom, color))
|
|
|
|
|
|
def horizontal_edge(rects: list[Border], color: BorderColor, height: int, left: int, right: int, top: int) -> None:
|
|
if height > 0:
|
|
rects.append(Border(left, top, right, top + height, color))
|
|
|
|
|
|
def add_borders(rects: list[Border], color: BorderColor, wg: WindowGroup) -> None:
|
|
geometry = wg.geometry
|
|
if geometry is None:
|
|
return
|
|
pl, pt = wg.effective_padding('left'), wg.effective_padding('top')
|
|
pr, pb = wg.effective_padding('right'), wg.effective_padding('bottom')
|
|
left = geometry.left - pl
|
|
top = geometry.top - pt
|
|
lr = geometry.right
|
|
right = lr + pr
|
|
bt = geometry.bottom
|
|
bottom = bt + pb
|
|
h = partial(horizontal_edge, rects, color)
|
|
v = partial(vertical_edge, rects, color)
|
|
width = wg.effective_border()
|
|
bt = bottom
|
|
lr = right
|
|
left -= width
|
|
top -= width
|
|
right += width
|
|
bottom += width
|
|
pl = pr = pb = pt = width
|
|
h(pt, left, right, top)
|
|
h(pb, left, right, bt)
|
|
v(pl, top, bottom, left)
|
|
v(pr, top, bottom, lr)
|
|
|
|
|
|
def load_borders_program() -> None:
|
|
program_for('border').compile(BORDERS_PROGRAM)
|
|
init_borders_program()
|
|
|
|
|
|
class Borders:
|
|
|
|
def __init__(self, os_window_id: int, tab_id: int):
|
|
self.os_window_id = os_window_id
|
|
self.tab_id = tab_id
|
|
|
|
def __call__(
|
|
self,
|
|
all_windows: WindowList,
|
|
current_layout: LayoutType,
|
|
tab_bar_rects: Iterable[Border],
|
|
draw_window_borders: bool = True,
|
|
) -> None:
|
|
opts = get_options()
|
|
draw_active_borders = opts.active_border_color is not None
|
|
draw_minimal_borders = opts.draw_minimal_borders and max(opts.window_margin_width) < 1
|
|
rects: list[Border] = []
|
|
for br in current_layout.blank_rects:
|
|
rects.append(Border(*br, BorderColor.default_bg))
|
|
rects.extend(tab_bar_rects)
|
|
bw = 0
|
|
groups = tuple(all_windows.iter_all_layoutable_groups(only_visible=True))
|
|
if groups:
|
|
bw = groups[0].effective_border()
|
|
draw_borders = bw > 0 and draw_window_borders
|
|
active_group = all_windows.active_group
|
|
|
|
for i, wg in enumerate(groups):
|
|
window_bg = color_as_int(wg.default_bg)
|
|
window_bg = (window_bg << 8) | BorderColor.window_bg
|
|
if draw_borders and not draw_minimal_borders:
|
|
# Draw the border rectangles
|
|
if wg is active_group and draw_active_borders:
|
|
color = BorderColor.active
|
|
else:
|
|
color = BorderColor.bell if wg.needs_attention else BorderColor.inactive
|
|
add_borders(rects, color, wg)
|
|
|
|
if draw_minimal_borders:
|
|
for border_line in current_layout.get_minimal_borders(all_windows):
|
|
rects.append(Border(*border_line.edges, border_line.color))
|
|
set_borders_rects(self.os_window_id, self.tab_id, rects)
|