From 2de8c70bb87a7b38e79f051552079b06ef3badc2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 30 Oct 2016 17:19:37 +0530 Subject: [PATCH] Optimize the hot loop --- kitty/char_grid.py | 41 ++++++++++++++++++++++++++--------------- kitty/shaders.py | 25 ++++++++++++++----------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/kitty/char_grid.py b/kitty/char_grid.py index c9f468981..b168b3f0e 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -8,7 +8,7 @@ from itertools import chain, repeat from queue import Queue, Empty from .config import build_ansi_color_tables, to_color, fg_color_table, bg_color_table -from .data_types import COL_MASK, COL_SHIFT, ITALIC_MASK, BOLD_MASK, REVERSE_MASK, as_color +from .data_types import COL_MASK, COL_SHIFT, REVERSE_MASK, as_color from .fonts import set_font_family from .shaders import Sprites, ShaderProgram from .utils import get_logical_dpi @@ -264,6 +264,20 @@ class CharGrid: def render(self): ' This is the only method in this class called in the UI thread (apart from __init__) ' + cell_data_changed = self.get_all_render_changes() + if cell_data_changed: + self.update_sprite_map() + data = self.last_render_data + + gl.glClear(gl.GL_COLOR_BUFFER_BIT) + if data.screen_geometry is None: + return + sg = data.screen_geometry + self.render_cells(sg, data.sprite_layout) + if not data.cursor.hidden: + self.render_cursor(sg, data.cursor) + + def get_all_render_changes(self): cell_data_changed = False data = self.last_render_data while True: @@ -278,30 +292,27 @@ class CharGrid: if rd.viewport is not None: gl.glViewport(0, 0, self.width, self.height) data.update(rd) - if cell_data_changed: - spmap, sptext = data.cell_data - for i, (text, attrs) in enumerate(sptext): - f = i * 9 - spmap[f:f + 3] = self.sprites.primary_sprite_position(text, attrs & BOLD_MASK, attrs & ITALIC_MASK) - self.sprites.set_sprite_map(spmap) + return cell_data_changed - gl.glClear(gl.GL_COLOR_BUFFER_BIT) - if data.screen_geometry is None: - return - sg = data.screen_geometry + def update_sprite_map(self): + spmap, sptext = self.last_render_data.cell_data + psp = self.sprites.primary_sprite_position + for i, key in enumerate(sptext): + f = i * 9 + spmap[f:f + 3] = psp(key) + self.sprites.set_sprite_map(spmap) + + def render_cells(self, sg, sprite_layout): with self.program: ul = self.program.uniform_location gl.glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum) gl.glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy) gl.glUniform1i(ul('sprites'), self.sprites.sampler_num) gl.glUniform1i(ul('sprite_map'), self.sprites.buffer_sampler_num) - gl.glUniform2f(ul('sprite_layout'), *data.sprite_layout) + gl.glUniform2f(ul('sprite_layout'), *sprite_layout) with self.sprites: gl.glDrawArraysInstanced(gl.GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum) - if not data.cursor.hidden: - self.render_cursor(sg, data.cursor) - def render_cursor(self, sg, cursor): def width(w=2, vert=True): diff --git a/kitty/shaders.py b/kitty/shaders.py index 7e7ec8853..ca2cb0249 100644 --- a/kitty/shaders.py +++ b/kitty/shaders.py @@ -10,6 +10,7 @@ from OpenGL.GL.ARB.copy_image import glCopyImageSubData # only present in openg from OpenGL.GL.ARB.texture_storage import glTexStorage3D # only present in opengl core >= 4.2 from .fonts import render_cell, cell_size +from .data_types import ITALIC_MASK, BOLD_MASK GL_VERSION = (3, 3) VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10 @@ -121,22 +122,24 @@ class Sprites: gl.glBufferData(tgt, ArrayDatatype.arrayByteCount(data), data, gl.GL_STATIC_DRAW) gl.glBindBuffer(tgt, 0) - def primary_sprite_position(self, text, bold=False, italic=False): + def primary_sprite_position(self, key): ' Return a 3-tuple (x, y, z) giving the position of this sprite on the sprite sheet ' - key = text, bold, italic - first = self.first_cell_cache.get(key) - if first is None: - first, second = render_cell(text, bold, italic) - self.first_cell_cache[key] = first = self.add_sprite(first) - if second is not None: - self.second_cell_cache[key] = self.add_sprite(second) + try: + return self.first_cell_cache[key] + except KeyError: + pass + text, attrs = key + bold, italic = attrs & BOLD_MASK, attrs & ITALIC_MASK + first, second = render_cell(text, bold, italic) + self.first_cell_cache[key] = first = self.add_sprite(first) + if second is not None: + self.second_cell_cache[key] = self.add_sprite(second) return first - def secondary_sprite_position(self, text, bold=False, italic=False): - key = text, bold, italic + def secondary_sprite_position(self, key): ans = self.second_cell_cache.get(key) if ans is None: - self.primary_sprite_position(text, bold, italic) + self.primary_sprite_position(key) ans = self.second_cell_cache.get(key) if ans is None: return 0, 0, 0