Optimize the hot loop

This commit is contained in:
Kovid Goyal 2016-10-30 17:19:37 +05:30
parent be9b8e993d
commit 2de8c70bb8
2 changed files with 40 additions and 26 deletions

View File

@ -8,7 +8,7 @@ from itertools import chain, repeat
from queue import Queue, Empty from queue import Queue, Empty
from .config import build_ansi_color_tables, to_color, fg_color_table, bg_color_table 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 .fonts import set_font_family
from .shaders import Sprites, ShaderProgram from .shaders import Sprites, ShaderProgram
from .utils import get_logical_dpi from .utils import get_logical_dpi
@ -264,6 +264,20 @@ class CharGrid:
def render(self): def render(self):
' This is the only method in this class called in the UI thread (apart from __init__) ' ' 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 cell_data_changed = False
data = self.last_render_data data = self.last_render_data
while True: while True:
@ -278,30 +292,27 @@ class CharGrid:
if rd.viewport is not None: if rd.viewport is not None:
gl.glViewport(0, 0, self.width, self.height) gl.glViewport(0, 0, self.width, self.height)
data.update(rd) data.update(rd)
if cell_data_changed: return 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)
gl.glClear(gl.GL_COLOR_BUFFER_BIT) def update_sprite_map(self):
if data.screen_geometry is None: spmap, sptext = self.last_render_data.cell_data
return psp = self.sprites.primary_sprite_position
sg = data.screen_geometry 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: with self.program:
ul = self.program.uniform_location ul = self.program.uniform_location
gl.glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum) gl.glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
gl.glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy) gl.glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
gl.glUniform1i(ul('sprites'), self.sprites.sampler_num) gl.glUniform1i(ul('sprites'), self.sprites.sampler_num)
gl.glUniform1i(ul('sprite_map'), self.sprites.buffer_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: with self.sprites:
gl.glDrawArraysInstanced(gl.GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum) 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 render_cursor(self, sg, cursor):
def width(w=2, vert=True): def width(w=2, vert=True):

View File

@ -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 OpenGL.GL.ARB.texture_storage import glTexStorage3D # only present in opengl core >= 4.2
from .fonts import render_cell, cell_size from .fonts import render_cell, cell_size
from .data_types import ITALIC_MASK, BOLD_MASK
GL_VERSION = (3, 3) GL_VERSION = (3, 3)
VERSION = GL_VERSION[0] * 100 + GL_VERSION[1] * 10 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.glBufferData(tgt, ArrayDatatype.arrayByteCount(data), data, gl.GL_STATIC_DRAW)
gl.glBindBuffer(tgt, 0) 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 ' ' Return a 3-tuple (x, y, z) giving the position of this sprite on the sprite sheet '
key = text, bold, italic try:
first = self.first_cell_cache.get(key) return self.first_cell_cache[key]
if first is None: except KeyError:
first, second = render_cell(text, bold, italic) pass
self.first_cell_cache[key] = first = self.add_sprite(first) text, attrs = key
if second is not None: bold, italic = attrs & BOLD_MASK, attrs & ITALIC_MASK
self.second_cell_cache[key] = self.add_sprite(second) 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 return first
def secondary_sprite_position(self, text, bold=False, italic=False): def secondary_sprite_position(self, key):
key = text, bold, italic
ans = self.second_cell_cache.get(key) ans = self.second_cell_cache.get(key)
if ans is None: if ans is None:
self.primary_sprite_position(text, bold, italic) self.primary_sprite_position(key)
ans = self.second_cell_cache.get(key) ans = self.second_cell_cache.get(key)
if ans is None: if ans is None:
return 0, 0, 0 return 0, 0, 0