Copy cell data to the GPU in a single pass
This commit is contained in:
parent
f324d8ec4f
commit
906937149e
@ -5,7 +5,7 @@
|
||||
import re
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from ctypes import addressof, memmove, sizeof
|
||||
from ctypes import addressof, sizeof
|
||||
from enum import Enum
|
||||
|
||||
from .config import build_ansi_color_table, defaults
|
||||
@ -159,10 +159,11 @@ class CharGrid:
|
||||
def __init__(self, screen, opts):
|
||||
self.vao_id = None
|
||||
self.current_selection = Selection()
|
||||
self.scroll_changed = False
|
||||
self.last_rendered_selection = None
|
||||
self.render_buf_is_dirty = True
|
||||
self.render_data = None
|
||||
self.scrolled_by = 0
|
||||
self.data_buffer_size = 0
|
||||
self.screen = screen
|
||||
self.opts = opts
|
||||
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
@ -173,7 +174,6 @@ 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.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
|
||||
|
||||
def escape(chars):
|
||||
return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-')
|
||||
@ -194,12 +194,8 @@ class CharGrid:
|
||||
|
||||
def resize(self, window_geometry):
|
||||
self.update_position(window_geometry)
|
||||
rt = (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.data_buffer_size = sizeof(GLuint) * self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE
|
||||
self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))()
|
||||
self.render_buf_is_dirty = True
|
||||
self.current_selection.clear()
|
||||
|
||||
def change_colors(self, changes):
|
||||
@ -228,21 +224,17 @@ class CharGrid:
|
||||
y = max(0, min(self.scrolled_by + amt, self.screen.historybuf.count))
|
||||
if y != self.scrolled_by:
|
||||
self.scrolled_by = y
|
||||
self.update_cell_data()
|
||||
self.scroll_changed = True
|
||||
|
||||
def update_cell_data(self, force_full_refresh=False):
|
||||
cursor_changed, history_line_added_count = self.screen.update_cell_data(
|
||||
addressof(self.main_sprite_map), force_full_refresh)
|
||||
if self.scrolled_by:
|
||||
self.scrolled_by = min(self.scrolled_by + history_line_added_count, self.screen.historybuf.count)
|
||||
self.screen.set_scroll_cell_data(
|
||||
addressof(self.main_sprite_map), self.scrolled_by, addressof(self.scroll_sprite_map))
|
||||
def update_cell_data(self, cell_program, force_full_refresh=False):
|
||||
if self.data_buffer_size == 0:
|
||||
return
|
||||
with cell_program.mapped_vertex_data(self.vao_id, self.data_buffer_size) as address:
|
||||
cursor_changed, self.scrolled_by = self.screen.update_cell_data(
|
||||
address, self.scrolled_by, force_full_refresh)
|
||||
|
||||
data = self.scroll_sprite_map if self.scrolled_by else self.main_sprite_map
|
||||
self.current_selection.clear()
|
||||
memmove(self.render_buf, data, sizeof(type(data)))
|
||||
self.render_data = self.screen_geometry
|
||||
self.render_buf_is_dirty = True
|
||||
if cursor_changed:
|
||||
c = self.screen.cursor
|
||||
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)
|
||||
|
||||
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:
|
||||
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)
|
||||
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):
|
||||
|
||||
@ -1193,38 +1193,24 @@ screen_update_cell_data(Screen *self, PyObject *args) {
|
||||
PyObject *dp;
|
||||
unsigned int *data;
|
||||
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);
|
||||
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 (!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);
|
||||
|
||||
if (scrolled_by) scrolled_by = MIN(scrolled_by + history_line_added_count, self->historybuf->count);
|
||||
tracker_reset(self->change_tracker);
|
||||
for (index_type y = 0; y < MIN(self->lines, scrolled_by); y++) {
|
||||
historybuf_init_line(self->historybuf, scrolled_by - 1 - y, self->historybuf->line);
|
||||
self->historybuf->line->ynum = y;
|
||||
if (!update_cell_range_data(&(self->modes), self->historybuf->line, 0, self->columns - 1, data)) return NULL;
|
||||
}
|
||||
if (scrolled_by < self->lines) {
|
||||
// Less than a full screen has been scrolled, copy some lines from the screen buffer to the scroll buffer
|
||||
unsigned int line_size = DATA_CELL_SIZE * self->columns;
|
||||
index_type num_to_copy = self->lines - scrolled_by;
|
||||
index_type offset = line_size * scrolled_by;
|
||||
memcpy(data + offset, src, line_size * num_to_copy * sizeof(unsigned int));
|
||||
for (index_type y = scrolled_by; y < self->lines; y++) {
|
||||
linebuf_init_line(self->linebuf, y - scrolled_by);
|
||||
self->linebuf->line->ynum = y;
|
||||
if (!update_cell_range_data(&(self->modes), self->linebuf->line, 0, self->columns - 1, data)) return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("OI", cursor_changed, scrolled_by);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@ -1331,7 +1317,6 @@ static PyMethodDef methods[] = {
|
||||
MND(mark_as_dirty, METH_NOARGS)
|
||||
MND(resize, METH_VARARGS)
|
||||
MND(set_margins, METH_VARARGS)
|
||||
MND(set_scroll_cell_data, METH_VARARGS)
|
||||
MND(apply_selection, METH_VARARGS)
|
||||
MND(toggle_alt_screen, METH_NOARGS)
|
||||
MND(reset_callbacks, METH_NOARGS)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user