Copy cell data to the GPU in a single pass

This commit is contained in:
Kovid Goyal
2017-09-08 18:20:23 +05:30
parent f324d8ec4f
commit 906937149e
2 changed files with 25 additions and 50 deletions

View File

@@ -5,7 +5,7 @@
import re import re
import sys import sys
from collections import namedtuple from collections import namedtuple
from ctypes import addressof, memmove, sizeof from ctypes import addressof, sizeof
from enum import Enum from enum import Enum
from .config import build_ansi_color_table, defaults from .config import build_ansi_color_table, defaults
@@ -159,10 +159,11 @@ class CharGrid:
def __init__(self, screen, opts): def __init__(self, screen, opts):
self.vao_id = None self.vao_id = None
self.current_selection = Selection() self.current_selection = Selection()
self.scroll_changed = False
self.last_rendered_selection = None self.last_rendered_selection = None
self.render_buf_is_dirty = True
self.render_data = None self.render_data = None
self.scrolled_by = 0 self.scrolled_by = 0
self.data_buffer_size = 0
self.screen = screen self.screen = screen
self.opts = opts self.opts = opts
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts)) self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
@@ -173,7 +174,6 @@ class CharGrid:
self.opts = opts self.opts = opts
self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0) self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
self.opts = opts self.opts = opts
self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
def escape(chars): def escape(chars):
return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-') return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-')
@@ -194,12 +194,8 @@ class CharGrid:
def resize(self, window_geometry): def resize(self, window_geometry):
self.update_position(window_geometry) self.update_position(window_geometry)
rt = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE)) self.data_buffer_size = sizeof(GLuint) * self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE
self.main_sprite_map = rt()
self.scroll_sprite_map = rt()
self.render_buf = rt()
self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))() self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))()
self.render_buf_is_dirty = True
self.current_selection.clear() self.current_selection.clear()
def change_colors(self, changes): def change_colors(self, changes):
@@ -228,21 +224,17 @@ class CharGrid:
y = max(0, min(self.scrolled_by + amt, self.screen.historybuf.count)) y = max(0, min(self.scrolled_by + amt, self.screen.historybuf.count))
if y != self.scrolled_by: if y != self.scrolled_by:
self.scrolled_by = y self.scrolled_by = y
self.update_cell_data() self.scroll_changed = True
def update_cell_data(self, force_full_refresh=False): def update_cell_data(self, cell_program, force_full_refresh=False):
cursor_changed, history_line_added_count = self.screen.update_cell_data( if self.data_buffer_size == 0:
addressof(self.main_sprite_map), force_full_refresh) return
if self.scrolled_by: with cell_program.mapped_vertex_data(self.vao_id, self.data_buffer_size) as address:
self.scrolled_by = min(self.scrolled_by + history_line_added_count, self.screen.historybuf.count) cursor_changed, self.scrolled_by = self.screen.update_cell_data(
self.screen.set_scroll_cell_data( address, self.scrolled_by, force_full_refresh)
addressof(self.main_sprite_map), self.scrolled_by, addressof(self.scroll_sprite_map))
data = self.scroll_sprite_map if self.scrolled_by else self.main_sprite_map
self.current_selection.clear() self.current_selection.clear()
memmove(self.render_buf, data, sizeof(type(data)))
self.render_data = self.screen_geometry self.render_data = self.screen_geometry
self.render_buf_is_dirty = True
if cursor_changed: if cursor_changed:
c = self.screen.cursor c = self.screen.cursor
self.current_cursor = Cursor(c.x, c.y, c.shape, c.blink) self.current_cursor = Cursor(c.x, c.y, c.shape, c.blink)
@@ -363,20 +355,18 @@ class CharGrid:
return s.text(self.screen.linebuf, self.screen.historybuf) return s.text(self.screen.linebuf, self.screen.historybuf)
def prepare_for_render(self, cell_program): def prepare_for_render(self, cell_program):
if self.screen.is_dirty():
self.update_cell_data()
sg = self.render_data
if self.vao_id is None: if self.vao_id is None:
self.vao_id = cell_program.create_sprite_map() self.vao_id = cell_program.create_sprite_map()
if self.scroll_changed or self.screen.is_dirty():
self.update_cell_data(cell_program)
self.scroll_changed = False
sg = self.render_data
start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns) start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns)
selection_changed = sel != self.last_rendered_selection selection_changed = sel != self.last_rendered_selection
if selection_changed: if selection_changed:
self.screen.apply_selection(addressof(self.selection_buf), start[0], start[1], end[0], end[1], len(self.selection_buf)) 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) cell_program.send_vertex_data(self.vao_id, self.selection_buf, bufnum=1)
self.last_rendered_selection = sel 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 return sg
def render_cells(self, sg, cell_program, sprites, invert_colors=False): def render_cells(self, sg, cell_program, sprites, invert_colors=False):

View File

@@ -1193,38 +1193,24 @@ screen_update_cell_data(Screen *self, PyObject *args) {
PyObject *dp; PyObject *dp;
unsigned int *data; unsigned int *data;
int force_screen_refresh; int force_screen_refresh;
if (!PyArg_ParseTuple(args, "O!p", &PyLong_Type, &dp, &force_screen_refresh)) return NULL; unsigned int scrolled_by;
unsigned int history_line_added_count = self->change_tracker->history_line_added_count;
if (!PyArg_ParseTuple(args, "O!Ip", &PyLong_Type, &dp, &scrolled_by, &force_screen_refresh)) return NULL;
data = PyLong_AsVoidPtr(dp); data = PyLong_AsVoidPtr(dp);
PyObject *cursor_changed = self->change_tracker->cursor_changed ? Py_True : Py_False; PyObject *cursor_changed = self->change_tracker->cursor_changed ? Py_True : Py_False;
unsigned int history_line_added_count = self->change_tracker->history_line_added_count; if (scrolled_by) scrolled_by = MIN(scrolled_by + history_line_added_count, self->historybuf->count);
tracker_reset(self->change_tracker);
if (!tracker_update_cell_data(&(self->modes), self->change_tracker, self->linebuf, data, (bool)force_screen_refresh)) return NULL;
return Py_BuildValue("OI", cursor_changed, history_line_added_count);
}
static PyObject*
set_scroll_cell_data(Screen *self, PyObject *args) {
PyObject *dp, *sp;
unsigned int *data, *src, scrolled_by;
if (!PyArg_ParseTuple(args, "O!IO", &PyLong_Type, &sp, &scrolled_by, &dp)) return NULL;
data = PyLong_AsVoidPtr(dp);
src = PyLong_AsVoidPtr(sp);
scrolled_by = MIN(self->historybuf->count, scrolled_by);
for (index_type y = 0; y < MIN(self->lines, scrolled_by); y++) { for (index_type y = 0; y < MIN(self->lines, scrolled_by); y++) {
historybuf_init_line(self->historybuf, scrolled_by - 1 - y, self->historybuf->line); historybuf_init_line(self->historybuf, scrolled_by - 1 - y, self->historybuf->line);
self->historybuf->line->ynum = y; self->historybuf->line->ynum = y;
if (!update_cell_range_data(&(self->modes), self->historybuf->line, 0, self->columns - 1, data)) return NULL; if (!update_cell_range_data(&(self->modes), self->historybuf->line, 0, self->columns - 1, data)) return NULL;
} }
if (scrolled_by < self->lines) { for (index_type y = scrolled_by; y < self->lines; y++) {
// Less than a full screen has been scrolled, copy some lines from the screen buffer to the scroll buffer linebuf_init_line(self->linebuf, y - scrolled_by);
unsigned int line_size = DATA_CELL_SIZE * self->columns; self->linebuf->line->ynum = y;
index_type num_to_copy = self->lines - scrolled_by; if (!update_cell_range_data(&(self->modes), self->linebuf->line, 0, self->columns - 1, data)) return NULL;
index_type offset = line_size * scrolled_by;
memcpy(data + offset, src, line_size * num_to_copy * sizeof(unsigned int));
} }
Py_RETURN_NONE; return Py_BuildValue("OI", cursor_changed, scrolled_by);
} }
static PyObject* static PyObject*
@@ -1331,7 +1317,6 @@ static PyMethodDef methods[] = {
MND(mark_as_dirty, METH_NOARGS) MND(mark_as_dirty, METH_NOARGS)
MND(resize, METH_VARARGS) MND(resize, METH_VARARGS)
MND(set_margins, METH_VARARGS) MND(set_margins, METH_VARARGS)
MND(set_scroll_cell_data, METH_VARARGS)
MND(apply_selection, METH_VARARGS) MND(apply_selection, METH_VARARGS)
MND(toggle_alt_screen, METH_NOARGS) MND(toggle_alt_screen, METH_NOARGS)
MND(reset_callbacks, METH_NOARGS) MND(reset_callbacks, METH_NOARGS)