From b2a4db20288863ef4d0b7f7c57e8dbd4a5eb5de2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 13 Dec 2024 13:18:35 +0530 Subject: [PATCH] Revert metadata row for sprites Store in a separate VAO instead more performant as it uses less VRAM and allows shader lookup co-ords to be passed to fragment shaders without calculation in the fragment shader. --- kitty/cell_vertex.glsl | 5 +---- kitty/fast_data_types.pyi | 2 +- kitty/fonts.c | 12 +++++------- kitty/fonts/box_drawing.py | 4 ++-- kitty/fonts/render.py | 12 +++++------- kitty/shaders.c | 11 +++++------ kitty_tests/fonts.py | 4 ++-- 7 files changed, 21 insertions(+), 29 deletions(-) diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 5cbeceb23..117be4454 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -8,7 +8,7 @@ layout(std140) uniform CellRenderData { uint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted; - uint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx, cell_height; + uint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx; float cursor_x, cursor_y, cursor_w, cursor_opacity; // must have unique entries with 0 being default_bg and unset being UINT32_MAX @@ -109,9 +109,6 @@ vec3 to_sprite_pos(uvec2 pos, uint idx) { uvec3 c = to_sprite_coords(idx); vec2 s_xpos = vec2(c.x, float(c.x) + 1.0f) * (1.0f / float(sprites_xnum)); vec2 s_ypos = vec2(c.y, float(c.y) + 1.0f) * (1.0f / float(sprites_ynum)); - uint texture_height_px = (cell_height + 1u) * sprites_ynum; - float row_height = 1.0f / float(texture_height_px); - s_ypos[1] -= row_height; // skip the metadata row return vec3(s_xpos[pos.x], s_ypos[pos.y], c.z); } diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 7192585da..b7d70da54 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1125,7 +1125,7 @@ def sprite_map_set_limits(w: int, h: int) -> None: def set_send_sprite_to_gpu( - func: Optional[Callable[[int, int, int, bytes, bytes], None]] + func: Optional[Callable[[int, int, int, bytes], None]] ) -> None: pass diff --git a/kitty/fonts.c b/kitty/fonts.c index d8dc7e860..39ac098ec 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -130,23 +130,21 @@ python_send_to_gpu(FontGroup *fg, sprite_index idx, pixel *buf) { unsigned int x, y, z; sprite_index_to_pos(idx, fg->sprite_tracker.xnum, fg->sprite_tracker.ynum, &x, &y, &z); const size_t sprite_size = fg->fcm.cell_width * fg->fcm.cell_height; - PyObject *ret = PyObject_CallFunction(python_send_to_gpu_impl, "IIIy#y#", x, y, z, buf, sprite_size * sizeof(buf[0]), buf + sprite_size, fg->fcm.cell_width * sizeof(buf[0])); + PyObject *ret = PyObject_CallFunction(python_send_to_gpu_impl, "IIIy#", x, y, z, buf, sprite_size * sizeof(buf[0])); if (ret == NULL) PyErr_Print(); else Py_DECREF(ret); } static void current_send_sprite_to_gpu(FontGroup *fg, sprite_index idx, pixel *buf, sprite_index decorations_idx) { - pixel *metadata = buf + fg->fcm.cell_width * fg->fcm.cell_height; - metadata[0] = decorations_idx; - memset(metadata + 1, 0, (fg->fcm.cell_width - 1) * sizeof(metadata[0])); + (void)decorations_idx; if (python_send_to_gpu_impl) python_send_to_gpu(fg, idx, buf); else send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, idx, buf); } static void ensure_canvas_can_fit(FontGroup *fg, unsigned cells, unsigned scale) { -#define cs(cells, scale) (sizeof(fg->canvas.buf[0]) * 3u * cells * fg->fcm.cell_width * (fg->fcm.cell_height + 1) * scale * scale) +#define cs(cells, scale) (sizeof(fg->canvas.buf[0]) * 3u * cells * fg->fcm.cell_width * fg->fcm.cell_height * scale * scale) size_t size_in_bytes = cs(cells, scale); if (size_in_bytes > fg->canvas.size_in_bytes) { free(fg->canvas.buf); @@ -330,7 +328,7 @@ sprite_tracker_current_layout(FONTS_DATA_HANDLE data, unsigned int *x, unsigned static void sprite_tracker_set_layout(GPUSpriteTracker *sprite_tracker, unsigned int cell_width, unsigned int cell_height) { sprite_tracker->xnum = MIN(MAX(1u, max_texture_size / cell_width), (size_t)UINT16_MAX); - sprite_tracker->max_y = MIN(MAX(1u, max_texture_size / (cell_height + 1)), (size_t)UINT16_MAX); + sprite_tracker->max_y = MIN(MAX(1u, max_texture_size / cell_height), (size_t)UINT16_MAX); sprite_tracker->ynum = 1; sprite_tracker->x = 0; sprite_tracker->y = 0; sprite_tracker->z = 0; } @@ -820,7 +818,7 @@ apply_scale_to_font_group(FontGroup *fg, RunFont *rf) { static pixel* pointer_to_space_for_last_sprite(Canvas *canvas, FontCellMetrics fcm) { - return canvas->buf + (canvas->size_in_bytes / sizeof(canvas->buf[0]) - fcm.cell_width * (fcm.cell_height + 1)); + return canvas->buf + (canvas->size_in_bytes / sizeof(canvas->buf[0]) - fcm.cell_width * fcm.cell_height); } static pixel* diff --git a/kitty/fonts/box_drawing.py b/kitty/fonts/box_drawing.py index 823adbae1..4c435bad3 100644 --- a/kitty/fonts/box_drawing.py +++ b/kitty/fonts/box_drawing.py @@ -1439,7 +1439,7 @@ def test_char(ch: str, sz: int = 48) -> None: from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu from .render import display_bitmap, setup_for_testing - with setup_for_testing('monospace', sz) as (_, _, width, height): + with setup_for_testing('monospace', sz) as (_, width, height): buf = bytearray(width * height) try: render_box_char(ch, buf, width, height) @@ -1460,7 +1460,7 @@ def test_drawing(sz: int = 48, family: str = 'monospace', start: int = 0x2500, n from .render import display_bitmap, setup_for_testing - with setup_for_testing(family, sz) as (_, _, width, height): + with setup_for_testing(family, sz) as (_, width, height): space = bytearray(width * height) def join_cells(cells: Iterable[bytes]) -> bytes: diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 5362a53d7..213115ca9 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -236,16 +236,14 @@ class setup_for_testing: self.family, self.size, self.dpi = family, size, dpi self.main_face_path = main_face_path - def __enter__(self) -> tuple[dict[tuple[int, int, int], bytes], dict[tuple[int, int, int], bytes], int, int]: + def __enter__(self) -> tuple[dict[tuple[int, int, int], bytes], int, int]: global descriptor_overrides opts = defaults._replace(font_family=parse_font_spec(self.family), font_size=self.size) set_options(opts) sprites = {} - sprite_metadata = {} - def send_to_gpu(x: int, y: int, z: int, data: bytes, metadata: bytes) -> None: + def send_to_gpu(x: int, y: int, z: int, data: bytes) -> None: sprites[(x, y, z)] = data - sprite_metadata[(x, y, z)] = metadata sprite_map_set_limits(self.xnum, self.ynum) set_send_sprite_to_gpu(send_to_gpu) @@ -256,7 +254,7 @@ class setup_for_testing: try: set_font_family(opts) cell_width, cell_height = create_test_font_group(self.size, self.dpi, self.dpi) - return sprites, sprite_metadata, cell_width, cell_height + return sprites, cell_width, cell_height except Exception: set_send_sprite_to_gpu(None) raise @@ -268,7 +266,7 @@ class setup_for_testing: def render_string(text: str, family: str = 'monospace', size: float = 11.0, dpi: float = 96.0) -> tuple[int, int, list[bytes]]: - with setup_for_testing(family, size, dpi) as (sprites, sprite_metadata, cell_width, cell_height): + with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) s.draw(text) @@ -288,7 +286,7 @@ def render_string(text: str, family: str = 'monospace', size: float = 11.0, dpi: def shape_string( text: str = "abcd", family: str = 'monospace', size: float = 11.0, dpi: float = 96.0, path: Optional[str] = None ) -> list[tuple[int, int, int, tuple[int, ...]]]: - with setup_for_testing(family, size, dpi) as (sprites, sprite_metadata, cell_width, cell_height): + with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) s.draw(text) diff --git a/kitty/shaders.c b/kitty/shaders.c index 0eb754085..8cfc6ca50 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -118,12 +118,12 @@ realloc_sprite_texture(FONTS_DATA_HANDLE fg) { sprite_tracker_current_layout(fg, &xnum, &ynum, &z); znum = z + 1; SpriteMap *sprite_map = (SpriteMap*)fg->sprite_map; - width = xnum * fg->fcm.cell_width; height = ynum * (fg->fcm.cell_height + 1); + width = xnum * fg->fcm.cell_width; height = ynum * fg->fcm.cell_height; glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_SRGB8_ALPHA8, width, height, znum); if (sprite_map->texture_id) { // need to re-alloc src_ynum = MAX(1, sprite_map->last_ynum); - copy_image_sub_data(sprite_map->texture_id, tex, width, src_ynum * (fg->fcm.cell_height + 1), sprite_map->last_num_of_layers); + copy_image_sub_data(sprite_map->texture_id, tex, width, src_ynum * fg->fcm.cell_height, sprite_map->last_num_of_layers); glDeleteTextures(1, &sprite_map->texture_id); } glBindTexture(GL_TEXTURE_2D_ARRAY, 0); @@ -154,8 +154,8 @@ send_sprite_to_gpu(FONTS_DATA_HANDLE fg, sprite_index idx, pixel *buf) { glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map->texture_id); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); sprite_index_to_pos(idx, xnum, ynum, &x, &y, &z); - x *= fg->fcm.cell_width; y *= fg->fcm.cell_height + 1; - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, fg->fcm.cell_width, fg->fcm.cell_height + 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf); + x *= fg->fcm.cell_width; y *= fg->fcm.cell_height; + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, fg->fcm.cell_width, fg->fcm.cell_height, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf); } void @@ -299,7 +299,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c GLuint default_fg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted; - GLuint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx, cell_height; + GLuint xnum, ynum, sprites_xnum, sprites_ynum, cursor_fg_sprite_idx; GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity; GLuint bg_colors0, bg_colors1, bg_colors2, bg_colors3, bg_colors4, bg_colors5, bg_colors6, bg_colors7; GLfloat bg_opacities0, bg_opacities1, bg_opacities2, bg_opacities3, bg_opacities4, bg_opacities5, bg_opacities6, bg_opacities7; @@ -389,7 +389,6 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c unsigned int x, y, z; sprite_tracker_current_layout(os_window->fonts_data, &x, &y, &z); rd->sprites_xnum = x; rd->sprites_ynum = y; - rd->cell_height = os_window->fonts_data->fcm.cell_height; rd->inverted = screen_invert_colors(screen) ? 1 : 0; #undef COLOR diff --git a/kitty_tests/fonts.py b/kitty_tests/fonts.py index b7cdf5ae5..3ce9d34e6 100644 --- a/kitty_tests/fonts.py +++ b/kitty_tests/fonts.py @@ -268,7 +268,7 @@ class FontBaseTest(BaseTest): self.addCleanup(self.rmtree_ignoring_errors, self.tdir) path = self.path_for_font(self.font_name) if self.font_name else '' tc = setup_for_testing(size=self.font_size, dpi=self.dpi, main_face_path=path) - self.sprites, self.sprite_metadata, self.cell_width, self.cell_height = tc.__enter__() + self.sprites, self.cell_width, self.cell_height = tc.__enter__() self.addCleanup(tc.__exit__) self.assertEqual([k[0] for k in self.sprites], list(range(11))) @@ -283,7 +283,7 @@ class Rendering(FontBaseTest): def test_sprite_map(self): sprite_map_set_limits(10, 2) - sprite_map_set_layout(5, 4) # 4 because of metadata row + sprite_map_set_layout(5, 5) self.ae(test_sprite_position_for(0), (0, 0, 0)) self.ae(test_sprite_position_for(1), (1, 0, 0)) self.ae(test_sprite_position_for(2), (0, 1, 0))