From d12573a67d990421ab456339494957bf4e0bbfa6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 30 Aug 2017 10:20:26 +0530 Subject: [PATCH] Dont send the color table to the GPU on every frame --- kitty/cell_vertex.glsl | 4 +++- kitty/char_grid.py | 25 +++++++++++++++++++++---- kitty/colors.c | 18 ++++++++++++++++++ kitty/data-types.h | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 88dfa3bcb..f7c227851 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -4,7 +4,9 @@ uniform vec4 steps; // xstart, ystart, dx, dy uniform vec2 sprite_layout; // dx, dy uniform ivec2 color_indices; // which color to use as fg and which as bg uniform uvec4 default_colors; // The default colors -uniform uint color_table[256]; // The color table +uniform ColorTable { + uint color_table[256]; // The color table +}; in uvec3 sprite_coords; in uvec3 colors; in float is_selected; diff --git a/kitty/char_grid.py b/kitty/char_grid.py index fa5c111e4..01e129f2b 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -16,8 +16,8 @@ from .constants import ( from .fast_data_types import ( CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND, GL_FLOAT, GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, - glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform1uiv, - glUniform2f, glUniform2i, glUniform2ui, glUniform4f, glUniform4ui + glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, + glUniform2i, glUniform2ui, glUniform4f, glUniform4ui ) from .rgb import to_color from .shaders import ShaderProgram, load_shaders @@ -35,6 +35,21 @@ class DynamicColor(Enum): class CellProgram(ShaderProgram): + def __init__(self, *args): + ShaderProgram.__init__(self, *args) + self.color_table_buf = None + + def send_color_table(self, color_profile): + if color_profile.ubo is None: + color_profile.ubo = self.init_uniform_block('ColorTable', 'color_table') + ubo = color_profile.ubo + if self.color_table_buf is None: + self.color_table_buf = (GLuint * (ubo.size // sizeof(GLuint)))() + offset = ubo.offsets['color_table'] // sizeof(GLuint) + stride = ubo.size // (256 * sizeof(GLuint)) + color_profile.copy_color_table(addressof(self.color_table_buf), offset, stride) + self.send_uniform_buffer_data(ubo, self.color_table_buf) + def create_sprite_map(self): with self.array_object_creator() as add_attribute: stride = DATA_CELL_SIZE * sizeof(GLuint) @@ -124,15 +139,17 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell def render_cells(vao_id, sg, cell_program, sprites, color_profile, invert_colors=False): + if color_profile.dirty: + cell_program.send_color_table(color_profile) + color_profile.dirty = False ul = cell_program.uniform_location glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum) glUniform4ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg, color_profile.highlight_fg, color_profile.highlight_bg) - glUniform1uiv(ul('color_table'), 256, color_profile.color_table_address()) glUniform2i(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1) glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy) glUniform1i(ul('sprites'), sprites.sampler_num) glUniform2f(ul('sprite_layout'), *(sprites.layout)) - with cell_program.bound_vertex_array(vao_id): + with cell_program.bound_vertex_array(vao_id), cell_program.bound_uniform_buffer(color_profile.ubo): glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum) diff --git a/kitty/colors.c b/kitty/colors.c index 686fec14b..867a8cc69 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -61,6 +61,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) { memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256)); memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256)); self->dirty = Py_True; Py_INCREF(Py_True); + self->ubo = Py_None; Py_INCREF(Py_None); } return (PyObject*) self; } @@ -68,6 +69,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) { static void dealloc(ColorProfile* self) { Py_DECREF(self->dirty); + Py_DECREF(self->ubo); Py_TYPE(self)->tp_free((PyObject*)self); } @@ -162,6 +164,20 @@ set_configured_colors(ColorProfile *self, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +copy_color_table(ColorProfile *self, PyObject *args) { +#define copy_color_table_doc "copy_color_table(address, offset, stride) -> copy the color table into the memory at address, using the specified offset and stride." + unsigned int offset, stride, i; + PyObject *ptr; + if (!PyArg_ParseTuple(args, "OII", &ptr, &offset, &stride)) return NULL; + color_type *buf = (color_type*)PyLong_AsVoidPtr(ptr); + stride = MAX(1, stride); + for (i = 0, buf = buf + offset; i < sizeof(self->color_table)/sizeof(self->color_table[0]); i++, buf += stride) { + *buf = self->color_table[i]; + } + Py_RETURN_NONE; +} + static PyObject* color_table_address(ColorProfile *self) { #define color_table_address_doc "Pointer address to start of color table" @@ -193,6 +209,7 @@ static PyGetSetDef getsetters[] = { static PyMemberDef members[] = { {"dirty", T_OBJECT_EX, offsetof(ColorProfile, dirty), 0, "dirty"}, + {"ubo", T_OBJECT_EX, offsetof(ColorProfile, ubo), 0, "ubo"}, {NULL} }; @@ -204,6 +221,7 @@ static PyMethodDef methods[] = { METHOD(reset_color, METH_O) METHOD(set_color, METH_VARARGS) METHOD(set_configured_colors, METH_VARARGS) + METHOD(copy_color_table, METH_VARARGS) {NULL} /* Sentinel */ }; diff --git a/kitty/data-types.h b/kitty/data-types.h index 4001f2ed6..094276298 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -184,7 +184,7 @@ typedef struct { typedef struct { PyObject_HEAD - PyObject *dirty; + PyObject *dirty, *ubo; uint32_t color_table[256]; uint32_t orig_color_table[256]; DynamicColor configured, overridden;