Move rendering of selection to GPU

This commit is contained in:
Kovid Goyal 2017-08-29 19:46:50 +05:30
parent a5bec84554
commit 34f946fd98
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 50 additions and 37 deletions

View File

@ -3,10 +3,11 @@ uniform uvec2 dimensions; // xnum, ynum
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 uvec2 default_colors; // The default foreground and background colors
uniform uvec4 default_colors; // The default colors
uniform uint color_table[256]; // The color table
in uvec3 sprite_coords;
in uvec3 colors;
in float is_selected;
out vec3 sprite_pos;
out vec3 underline_pos;
out vec3 strike_pos;
@ -56,6 +57,10 @@ vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
return vec3(s_xpos[pos.x], s_ypos[pos.y], z);
}
vec3 apply_selection(vec3 color, uint which) {
return is_selected * color_to_vec(which) + (1.0 - is_selected) * color;
}
void main() {
uint instance_id = uint(gl_InstanceID);
uint r = instance_id / dimensions[0];
@ -71,9 +76,9 @@ void main() {
uint fg = colors[color_indices[0]];
uint bg = colors[color_indices[1]];
uint decoration = colors[2];
foreground = to_color(fg, default_colors[color_indices[0]]);
background = to_color(bg, default_colors[color_indices[1]]);
decoration_fg = to_color(decoration, default_colors[0]);
foreground = apply_selection(to_color(fg, default_colors[color_indices[0]]), default_colors[2]);
background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]);
decoration_fg = to_color(decoration, default_colors[color_indices[0]]);
underline_pos = to_sprite_pos(pos, (sprite_coords.z >> 24) & SMASK, ZERO, ZERO);
strike_pos = to_sprite_pos(pos, (sprite_coords.z >> 26) & SMASK, ZERO, ZERO);
}

View File

@ -11,13 +11,13 @@ from threading import Lock
from .config import build_ansi_color_table, defaults
from .constants import (
GLuint, ScreenGeometry, cell_size, get_boss, viewport_size
GLfloat, GLuint, ScreenGeometry, cell_size, get_boss, viewport_size
)
from .fast_data_types import (
CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND,
GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, glDrawArrays,
glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, glUniform2i,
glUniform2ui, glUniform4f, glUniform1uiv
GL_FLOAT, GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable,
glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform1uiv,
glUniform2f, glUniform2i, glUniform2ui, glUniform4f, glUniform4ui
)
from .rgb import to_color
from .shaders import ShaderProgram, load_shaders
@ -36,11 +36,13 @@ class DynamicColor(Enum):
class CellProgram(ShaderProgram):
def create_sprite_map(self):
stride = DATA_CELL_SIZE * sizeof(GLuint)
size = DATA_CELL_SIZE // 2
with self.array_object_creator() as add_attribute:
stride = DATA_CELL_SIZE * sizeof(GLuint)
size = DATA_CELL_SIZE // 2
add_attribute('sprite_coords', size=size, dtype=GL_UNSIGNED_INT, stride=stride, divisor=1)
add_attribute('colors', size=size, dtype=GL_UNSIGNED_INT, stride=stride, offset=stride // 2, divisor=1)
add_attribute.newbuf()
add_attribute('is_selected', size=1, dtype=GL_FLOAT, stride=sizeof(GLfloat), divisor=1)
return add_attribute.vao_id
@ -124,7 +126,7 @@ 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):
ul = cell_program.uniform_location
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
glUniform2ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg)
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)
@ -142,7 +144,7 @@ class CharGrid:
self.buffer_lock = Lock()
self.vao_id = None
self.current_selection = Selection()
self.last_rendered_selection = self.current_selection.limits(0, screen.lines, screen.columns)
self.last_rendered_selection = None
self.render_buf_is_dirty = True
self.render_data = None
self.scrolled_by = 0
@ -156,7 +158,7 @@ class CharGrid:
self.opts = opts
self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
self.opts = opts
self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
def escape(chars):
return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-')
@ -177,12 +179,12 @@ class CharGrid:
def resize(self, window_geometry):
self.update_position(window_geometry)
self.sprite_map_type = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE))
self.main_sprite_map = self.sprite_map_type()
self.scroll_sprite_map = self.sprite_map_type()
rt = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE))
self.main_sprite_map = rt()
self.scroll_sprite_map = rt()
with self.buffer_lock:
self.render_buf = self.sprite_map_type()
self.selection_buf = self.sprite_map_type()
self.render_buf = rt()
self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))()
self.render_buf_is_dirty = True
self.current_selection.clear()
@ -360,19 +362,15 @@ class CharGrid:
return
if self.vao_id is None:
self.vao_id = cell_program.create_sprite_map()
buf = self.render_buf
start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns)
if start != end:
buf = self.selection_buf
if self.render_buf_is_dirty or sel != self.last_rendered_selection:
memmove(buf, self.render_buf, sizeof(type(buf)))
fg = self.screen.color_profile.highlight_fg
bg = self.screen.color_profile.highlight_bg
self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], fg, bg)
if self.render_buf_is_dirty or self.last_rendered_selection != sel:
cell_program.send_vertex_data(self.vao_id, buf)
self.render_buf_is_dirty = False
selection_changed = sel != self.last_rendered_selection
if selection_changed:
self.screen.apply_selection(addressof(self.selection_buf), start[0], start[1], end[0], end[1], len(self.selection_buf))
cell_program.send_vertex_data(self.vao_id, self.selection_buf, bufnum=1)
self.last_rendered_selection = sel
if self.render_buf_is_dirty:
cell_program.send_vertex_data(self.vao_id, self.render_buf)
self.render_buf_is_dirty = False
return sg
def render_cells(self, sg, cell_program, sprites, invert_colors=False):

View File

@ -84,6 +84,16 @@ Uniform2ui(PyObject UNUSED *self, PyObject *args) {
Py_RETURN_NONE;
}
static PyObject*
Uniform4ui(PyObject UNUSED *self, PyObject *args) {
int location;
unsigned int a, b, c, d;
if (!PyArg_ParseTuple(args, "iIIII", &location, &a, &b, &c, &d)) return NULL;
glUniform4ui(location, a, b, c, d);
CHECK_ERROR;
Py_RETURN_NONE;
}
static PyObject*
Uniform1uiv(PyObject UNUSED *self, PyObject *args) {
int location;
@ -784,6 +794,7 @@ int add_module_gl_constants(PyObject *module) {
METH(GetProgramiv, METH_VARARGS) \
METH(GetShaderiv, METH_VARARGS) \
METH(Uniform2ui, METH_VARARGS) \
METH(Uniform4ui, METH_VARARGS) \
METH(Uniform1uiv, METH_VARARGS) \
METH(Uniform2i, METH_VARARGS) \
METH(Uniform1i, METH_VARARGS) \

View File

@ -1208,16 +1208,15 @@ set_scroll_cell_data(Screen *self, PyObject *args) {
static PyObject*
apply_selection(Screen *self, PyObject *args) {
unsigned int fg, bg, startx, endx, starty, endy;
unsigned int size, startx, endx, starty, endy, i, end;
PyObject *l;
if (!PyArg_ParseTuple(args, "O!IIIIII", &PyLong_Type, &l, &startx, &starty, &endx, &endy, &fg, &bg)) return NULL;
if (!PyArg_ParseTuple(args, "O!IIIII", &PyLong_Type, &l, &startx, &starty, &endx, &endy, &size)) return NULL;
if (startx >= self->columns || starty >= self->lines || endx >= self->columns || endy >= self->lines) { Py_RETURN_NONE; }
unsigned int *data = PyLong_AsVoidPtr(l), offset;
for(unsigned int i = starty * self->columns + startx; i <= endy * self->columns + endx; i++) {
offset = DATA_CELL_SIZE * i;
data[offset + 3] = fg;
data[offset + 4] = bg;
}
float *data = PyLong_AsVoidPtr(l);
memset(data, 0, size * sizeof(float));
end = endy * self->columns + endx;
i = starty * self->columns + startx;
if (i != end) { for(; i <= end; i++) data[i] = 1; }
Py_RETURN_NONE;
}