Move the update_cell_data() inner loop to native code
This commit is contained in:
parent
dbd4bab212
commit
c8a71ef5f8
@ -235,8 +235,7 @@ class Boss(Thread):
|
||||
|
||||
def apply_update_screen(self):
|
||||
self.pending_update_screen = None
|
||||
changes = self.screen.consolidate_changes()
|
||||
self.char_grid.update_cell_data(changes)
|
||||
self.char_grid.update_cell_data()
|
||||
glfw.glfwPostEmptyEvent()
|
||||
|
||||
def title_changed(self, new_title):
|
||||
|
||||
@ -141,6 +141,10 @@ class RenderData:
|
||||
empty_cell = (' ', 0)
|
||||
|
||||
|
||||
def color_as_int(val):
|
||||
return val[0] << 16 | val[1] << 8 | val[2]
|
||||
|
||||
|
||||
class CharGrid:
|
||||
|
||||
def __init__(self, screen, opts, window_width, window_height):
|
||||
@ -161,7 +165,7 @@ class CharGrid:
|
||||
self.last_render_data = RenderData()
|
||||
self.default_cursor = Cursor(0, 0, False, opts.cursor_shape, opts.cursor, opts.cursor_blink)
|
||||
self.render_queue.put(RenderData(
|
||||
viewport=Size(self.width, self.height), clear_color=self.original_bg,
|
||||
viewport=Size(self.width, self.height), clear_color=color_as_int(self.original_bg),
|
||||
cursor=self.default_cursor))
|
||||
self.sprites.ensure_state()
|
||||
self.clear_count = 4
|
||||
@ -170,7 +174,8 @@ class CharGrid:
|
||||
self.sprites.destroy()
|
||||
|
||||
def initialize(self):
|
||||
self.default_bg, self.default_fg = self.original_bg, self.original_fg
|
||||
self.default_bg = color_as_int(self.original_bg)
|
||||
self.default_fg = color_as_int(self.original_fg)
|
||||
self.apply_opts(self.opts)
|
||||
|
||||
def apply_opts(self, opts):
|
||||
@ -202,51 +207,30 @@ class CharGrid:
|
||||
for which, val in changes.items():
|
||||
if which in ('fg', 'bg'):
|
||||
if not val:
|
||||
setattr(self, 'default_' + which, getattr(self, 'original_' + which))
|
||||
setattr(self, 'default_' + which, color_as_int(getattr(self, 'original_' + which)))
|
||||
dirtied = True
|
||||
else:
|
||||
val = to_color(val)
|
||||
if val is not None:
|
||||
setattr(self, 'default_' + which, val)
|
||||
setattr(self, 'default_' + which, color_as_int(val))
|
||||
dirtied = True
|
||||
if dirtied:
|
||||
self.render_queue.put(RenderData(clear_color=self.default_bg))
|
||||
self.clear_count = 4
|
||||
|
||||
def update_cell_data(self, changes=None, add_viewport_data=False):
|
||||
def update_cell_data(self, add_viewport_data=False):
|
||||
rd = RenderData(sprite_layout=self.sprites.layout)
|
||||
if add_viewport_data:
|
||||
rd.viewport = Size(self.width, self.height)
|
||||
rd.screen_geometry = self.screen_geometry
|
||||
if changes is None:
|
||||
changes = {'screen': True}
|
||||
sg = self.screen_geometry
|
||||
cell_data_changed = changes['screen'] or changes['cells'] or changes['lines']
|
||||
if cell_data_changed:
|
||||
if changes['screen']:
|
||||
lines = range(sg.ynum)
|
||||
cell_ranges = {}
|
||||
else:
|
||||
lines = changes['lines']
|
||||
cell_ranges = changes['cells']
|
||||
ptr = addressof(self.sprite_map)
|
||||
with self.lock:
|
||||
cursor_changed = self.screen.update_cell_data(
|
||||
self.sprites.backend, self.color_profile, ptr, self.default_fg, self.default_bg, add_viewport_data)
|
||||
|
||||
dfbg = self.default_bg
|
||||
dffg = self.default_fg
|
||||
dfbg = dfbg[0] << 16 | dfbg[1] << 8 | dfbg[2]
|
||||
dffg = dffg[0] << 16 | dffg[1] << 8 | dffg[2]
|
||||
ptr = addressof(self.sprite_map)
|
||||
|
||||
with self.lock:
|
||||
for y in lines:
|
||||
self.update_line(y, [(0, sg.xnum - 1)], dffg, dfbg, ptr)
|
||||
|
||||
for y, ranges in cell_ranges.items():
|
||||
self.update_line(y, ranges, dffg, dfbg, ptr)
|
||||
|
||||
rd.cell_data = copy(self.sprite_map)
|
||||
rd.sprite_layout = self.sprites.layout
|
||||
c = changes.get('cursor')
|
||||
if c:
|
||||
rd.cell_data = copy(self.sprite_map)
|
||||
rd.sprite_layout = self.sprites.layout
|
||||
if cursor_changed:
|
||||
c = self.screen.cursor
|
||||
rd.cursor = Cursor(c.x, c.y, c.hidden, c.shape, c.color, c.blink)
|
||||
self.render_queue.put(rd)
|
||||
@ -287,7 +271,7 @@ class CharGrid:
|
||||
cell_data_changed |= rd.cell_data is not None
|
||||
if rd.clear_color is not None:
|
||||
bg = rd.clear_color
|
||||
glClearColor(bg[0] / 255, bg[1] / 255, bg[2] / 255, 1)
|
||||
glClearColor((bg >> 16) / 255, ((bg >> 8) & 0xff) / 255, (bg & 0xff) / 255, 1)
|
||||
if rd.viewport is not None:
|
||||
glViewport(0, 0, self.width, self.height)
|
||||
data.update(rd)
|
||||
|
||||
@ -90,6 +90,13 @@ dealloc(LineBuf* self) {
|
||||
(l)->decoration_fg = (lb)->decoration_fg + (ynum) * (lb)->xnum; \
|
||||
(l)->combining_chars = (lb)->combining_chars + (ynum) * (lb)->xnum;
|
||||
|
||||
void linebuf_init_line(LineBuf *self, index_type idx) {
|
||||
self->line->ynum = idx;
|
||||
self->line->xnum = self->xnum;
|
||||
self->line->continued = self->continued_map[idx];
|
||||
INIT_LINE(self, self->line, self->line_map[idx]);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
line(LineBuf *self, PyObject *y) {
|
||||
#define line_doc "Return the specified line as a Line object. Note the Line Object is a live view into the underlying buffer. And only a single line object can be used at a time."
|
||||
@ -98,10 +105,7 @@ line(LineBuf *self, PyObject *y) {
|
||||
PyErr_SetString(PyExc_IndexError, "Line number too large");
|
||||
return NULL;
|
||||
}
|
||||
self->line->ynum = idx;
|
||||
self->line->xnum = self->xnum;
|
||||
self->line->continued = self->continued_map[idx];
|
||||
INIT_LINE(self, self->line, self->line_map[idx]);
|
||||
linebuf_init_line(self, idx);
|
||||
Py_INCREF(self->line);
|
||||
return (PyObject*)self->line;
|
||||
}
|
||||
@ -351,7 +355,7 @@ static PyMemberDef members[] = {
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyTypeObject LineBuf_Type = {
|
||||
PyTypeObject LineBuf_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.LineBuf",
|
||||
.tp_basicsize = sizeof(LineBuf),
|
||||
|
||||
@ -87,6 +87,9 @@ class Screen:
|
||||
def line(self, i):
|
||||
return self.linebuf.line(i)
|
||||
|
||||
def update_cell_data(self, *a):
|
||||
return self.tracker.update_cell_data(self.linebuf, *a)
|
||||
|
||||
def __repr__(self):
|
||||
return ("{0}({1}, {2})".format(self.__class__.__name__,
|
||||
self.columns, self.lines))
|
||||
|
||||
@ -46,12 +46,10 @@ class Sprites:
|
||||
self.texture_id = self.buffer_id = self.buffer_texture_id = None
|
||||
self.last_num_of_layers = 1
|
||||
self.last_ynum = -1
|
||||
self.update_cell_data = lambda *a: None
|
||||
|
||||
def initialize(self):
|
||||
self.texture_unit = GL_TEXTURE0
|
||||
self.backend = SpriteMap(glGetIntegerv(GL_MAX_TEXTURE_SIZE), glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS))
|
||||
self.update_cell_data = self.backend.update_cell_data
|
||||
self.do_layout(getattr(self, 'cell_width', 1), getattr(self, 'cell_height', 1))
|
||||
|
||||
def do_layout(self, cell_width=1, cell_height=1):
|
||||
|
||||
@ -133,32 +133,22 @@ position_for(SpriteMap *self, PyObject *args) {
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
update_cell_data(SpriteMap *self, PyObject *args) {
|
||||
bool
|
||||
update_cell_range_data(SpriteMap *self, Line *line, unsigned int xstart, unsigned int xmax, ColorProfile *color_profile, const uint32_t default_bg, const uint32_t default_fg, unsigned int *data) {
|
||||
#define update_cell_data_doc "update_cell_data(line, xstart, xmax, color_profile, default_bg, default_fg, data_pointer) -> Update the range [xstart, xmax] in data_pointer with the data from line"
|
||||
Line *line;
|
||||
unsigned int xstart, xlimit;
|
||||
SpritePosition *sp;
|
||||
PyObject *dp;
|
||||
char_type previous_ch=0, ch;
|
||||
color_type color;
|
||||
uint32_t bg, fg;
|
||||
uint8_t previous_width = 0;
|
||||
ColorProfile *color_profile;
|
||||
unsigned long default_bg, default_fg;
|
||||
int err = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!IIO!kkO!", &Line_Type, &line, &xstart, &xlimit, &ColorProfile_Type, &color_profile, &default_bg, &default_fg, &PyLong_Type, &dp)) return NULL;
|
||||
|
||||
unsigned int *data = PyLong_AsVoidPtr(dp);
|
||||
size_t base = line->ynum * line->xnum * 9;
|
||||
default_fg &= COL_MASK;
|
||||
default_bg &= COL_MASK;
|
||||
for (size_t i = xstart, offset = base + xstart * 9; i <= xlimit; i++, offset += 9) {
|
||||
for (size_t i = xstart, offset = base + xstart * 9; i <= xmax; i++, offset += 9) {
|
||||
ch = line->chars[i];
|
||||
if (previous_width == 2) sp = sprite_position_for(self, previous_ch, 0, true, &err);
|
||||
else sp = sprite_position_for(self, ch, line->combining_chars[i], false, &err);
|
||||
if (sp == NULL) { set_sprite_error(err); return NULL; }
|
||||
if (sp == NULL) { set_sprite_error(err); return false; }
|
||||
data[offset] = sp->x;
|
||||
data[offset+1] = sp->y;
|
||||
data[offset+2] = sp->z;
|
||||
@ -170,8 +160,7 @@ update_cell_data(SpriteMap *self, PyObject *args) {
|
||||
PACK_COL(offset + 3, fg);
|
||||
PACK_COL(offset + 6, bg);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@ -222,13 +211,12 @@ static PyMemberDef members[] = {
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(layout, METH_VARARGS)
|
||||
METHOD(position_for, METH_VARARGS)
|
||||
METHOD(update_cell_data, METH_VARARGS)
|
||||
METHOD(render_dirty_cells, METH_VARARGS)
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyTypeObject SpriteMap_Type = {
|
||||
PyTypeObject SpriteMap_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.SpriteMap",
|
||||
.tp_basicsize = sizeof(SpriteMap),
|
||||
|
||||
@ -7,7 +7,11 @@
|
||||
|
||||
#include "data-types.h"
|
||||
#include "tracker.h"
|
||||
#include <structmember.h>
|
||||
extern PyTypeObject SpriteMap_Type;
|
||||
extern PyTypeObject ColorProfile_Type;
|
||||
extern PyTypeObject LineBuf_Type;
|
||||
extern bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
|
||||
extern void linebuf_init_line(LineBuf *, index_type);
|
||||
|
||||
#define RESET_STATE_VARS(self) \
|
||||
self->screen_changed = false; self->cursor_changed = false; self->dirty = false; self->history_line_added_count = 0;
|
||||
@ -104,6 +108,62 @@ update_cell_range(ChangeTracker *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
update_cell_data(ChangeTracker *self, PyObject *args) {
|
||||
#define update_cell_data_doc "update_cell_data(line_buf, sprite_map, color_profile, data_ptr, default_fg, default_bg, force_screen_refresh)"
|
||||
SpriteMap *spm;
|
||||
LineBuf *lb;
|
||||
ColorProfile *color_profile;
|
||||
PyObject *dp;
|
||||
unsigned int *data, y;
|
||||
unsigned long default_bg, default_fg;
|
||||
Py_ssize_t start;
|
||||
int force_screen_refresh;
|
||||
if (!PyArg_ParseTuple(args, "O!O!O!O!kkp", &LineBuf_Type, &lb, &SpriteMap_Type, &spm, &ColorProfile_Type, &color_profile, &PyLong_Type, &dp, &default_fg, &default_bg, &force_screen_refresh)) return NULL;
|
||||
data = PyLong_AsVoidPtr(dp);
|
||||
default_fg &= COL_MASK;
|
||||
default_bg &= COL_MASK;
|
||||
|
||||
#define UPDATE_RANGE(xstart, xmax) \
|
||||
linebuf_init_line(lb, y); \
|
||||
if (!update_cell_range_data(spm, lb->line, (xstart), (xmax), color_profile, default_bg, default_fg, data)) return NULL;
|
||||
|
||||
if (self->screen_changed || force_screen_refresh) {
|
||||
for (y = 0; y < self->ynum; y++) {
|
||||
UPDATE_RANGE(0, self->xnum - 1);
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < self->ynum; y++) {
|
||||
if (self->changed_lines[y]) {
|
||||
UPDATE_RANGE(0, self->xnum - 1);
|
||||
} else if (self->lines_with_changed_cells[y]) {
|
||||
start = -1;
|
||||
bool *line = self->changed_cells + y * self->xnum;
|
||||
for (unsigned int i = 0; i < self->xnum; i++) {
|
||||
if (line[i]) {
|
||||
if (start == -1) {
|
||||
start = i;
|
||||
}
|
||||
} else {
|
||||
if (start != -1) {
|
||||
UPDATE_RANGE(start, i - 1);
|
||||
start = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start != -1) {
|
||||
UPDATE_RANGE(start, self->xnum - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *cursor_changed = self->cursor_changed ? Py_True : Py_False;
|
||||
reset_inner(self);
|
||||
Py_INCREF(cursor_changed);
|
||||
return cursor_changed;
|
||||
}
|
||||
|
||||
static inline PyObject*
|
||||
get_ranges(bool *line, unsigned int xnum) {
|
||||
PyObject *ans = PyList_New(0), *t;
|
||||
@ -199,6 +259,7 @@ static PyGetSetDef getseters[] = {
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(resize, METH_VARARGS)
|
||||
METHOD(update_cell_data, METH_VARARGS)
|
||||
METHOD(reset, METH_NOARGS)
|
||||
METHOD(cursor_changed, METH_NOARGS)
|
||||
METHOD(consolidate_changes, METH_NOARGS)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user