Pre-render the sprites for blank/underline/strikethrough

This commit is contained in:
Kovid Goyal
2016-11-22 11:50:28 +05:30
parent e9bb1b3d46
commit e53c3076ef
6 changed files with 39 additions and 22 deletions

View File

@@ -54,13 +54,12 @@ class Boss(Thread):
self.signal_fd = handle_unix_signals()
self.readers = [self.child_fd, self.signal_fd, self.read_wakeup_fd]
self.writers = [self.child_fd]
self.queue_action(self.initialize)
self.profile = args.profile
self.window, self.opts = window, opts
self.screen = Screen(self, 24, 80, opts.scrollback_lines)
self.char_grid = CharGrid(self.screen, opts, window_width, window_height)
self.read_bytes = partial(read_bytes_dump, print) if args.dump_commands else read_bytes
self.write_buf = memoryview(b'')
self.char_grid = CharGrid(self.screen, opts, window_width, window_height)
glfw.glfwSetCharModsCallback(window, self.on_text_input)
glfw.glfwSetKeyCallback(window, self.on_key)
glfw.glfwSetMouseButtonCallback(window, self.on_mouse_button)
@@ -95,10 +94,6 @@ class Boss(Thread):
if signal.SIGINT in signals or signal.SIGTERM in signals:
self.shutdown()
def initialize(self):
self.char_grid.initialize()
glfw.glfwPostEmptyEvent()
def on_focus(self, window, focused):
if focused:
if self.screen.enable_focus_tracking():

View File

@@ -172,17 +172,14 @@ class CharGrid:
self.render_queue.put(RenderData(
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
def destroy(self):
self.sprites.destroy()
def initialize(self):
self.default_bg = color_as_int(self.original_bg)
self.default_fg = color_as_int(self.original_fg)
self.apply_opts(self.opts)
def destroy(self):
self.sprites.destroy()
def apply_opts(self, opts):
self.dpix, self.dpiy = get_logical_dpi()
self.opts = opts

View File

@@ -42,7 +42,6 @@ class Renderer:
self.color_profile = ColorProfile()
self.program = ShaderProgram(*cell_shader)
self.sprites = Sprites()
self.sprites.initialize()
self.do_layout()
def on_resize(self, window, w, h):

View File

@@ -249,7 +249,7 @@ def add_curl(buf, position, thickness):
buf[offset + x] = 255
def render_cell(text, bold=False, italic=False, underline=0, strikeout=False):
def render_cell(text=' ', bold=False, italic=False, underline=0, strikeout=False):
# TODO: Handle non-normalizable combining chars. Probably need to use
# harfbuzz for that
text = unicodedata.normalize('NFC', text)[0]

View File

@@ -46,11 +46,8 @@ class Sprites:
self.texture_id = self.buffer_id = self.buffer_texture_id = None
self.last_num_of_layers = 1
self.last_ynum = -1
def initialize(self):
self.texture_unit = GL_TEXTURE0
self.backend = SpriteMap(glGetIntegerv(GL_MAX_TEXTURE_SIZE), glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS))
self.do_layout(getattr(self, 'cell_width', 1), getattr(self, 'cell_height', 1))
def do_layout(self, cell_width=1, cell_height=1):
self.cell_width, self.cell_height = cell_width, cell_height
@@ -58,6 +55,25 @@ class Sprites:
if self.texture_id is not None:
glDeleteTexture(self.texture_id)
self.texture_id = None
self.ensure_state()
self.pre_render()
def pre_render(self):
# Pre-render the basic cells to ensure they have known sprite numbers
def send(*a, **kw):
buf = render_cell(*a, **kw)[0]
x, y, z = self.backend.increment()
self.send_to_gpu(x, y, z, buf)
return x
send() # blank
send(underline=1)
send(strikeout=True)
send(underline=1, strikeout=True)
send(underline=2)
if send(underline=2, strikeout=True) != 5:
raise RuntimeError('Available OpenGL texture size is too small')
@property
def layout(self):
@@ -82,12 +98,10 @@ class Sprites:
glBindTexture(tgt, self.texture_id)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
x, y = x * self.cell_width, y * self.cell_height
glTexSubImage3D(tgt, 0, x, y, self.backend.z, self.cell_width, self.cell_height, 1, GL_RED, GL_UNSIGNED_BYTE, addressof(buf))
glTexSubImage3D(tgt, 0, x, y, z, self.cell_width, self.cell_height, 1, GL_RED, GL_UNSIGNED_BYTE, addressof(buf))
glBindTexture(tgt, 0)
def realloc_texture(self):
if self.texture_id is None:
self.initialize()
tgt = GL_TEXTURE_2D_ARRAY
tex = glGenTextures(1)
glBindTexture(tgt, tex)

View File

@@ -46,6 +46,7 @@ layout(SpriteMap *self, PyObject *args) {
self->xnum = MAX(1, self->max_texture_size / cell_width);
self->max_y = MAX(1, self->max_texture_size / cell_height);
self->ynum = 1;
self->x = 0; self->y = 0; self->z = 0;
for (size_t i = 0; i < sizeof(self->cache)/sizeof(self->cache[0]); i++) {
SpritePosition *s = &(self->cache[i]);
@@ -62,7 +63,7 @@ layout(SpriteMap *self, PyObject *args) {
}
static void
increment(SpriteMap *self, int *error) {
do_increment(SpriteMap *self, int *error) {
self->x++;
if (self->x >= self->xnum) {
self->x = 0; self->y++;
@@ -100,7 +101,7 @@ sprite_position_for(SpriteMap *self, char_type ch, combining_type cc, bool is_se
s->filled = true;
s->rendered = false;
s->x = self->x; s->y = self->y; s->z = self->z;
increment(self, error);
do_increment(self, error);
self->dirty = true;
return s;
}
@@ -116,6 +117,16 @@ static void set_sprite_error(int error) {
}
}
static PyObject*
increment(SpriteMap *self) {
#define increment_doc "Increment the current position and return the old (x, y, z) values"
unsigned int x = self->x, y = self->y, z = self->z;
int error = 0;
do_increment(self, &error);
if (error) { set_sprite_error(error); return NULL; }
return Py_BuildValue("III", x, y, z);
}
static PyObject*
position_for(SpriteMap *self, PyObject *args) {
#define position_for_doc "position_for(ch, cc, is_second) -> x, y, z the sprite position for the specified text"
@@ -217,6 +228,7 @@ static PyMethodDef methods[] = {
METHOD(position_for, METH_VARARGS)
METHOD(render_dirty_cells, METH_VARARGS)
METHOD(update_cell_data, METH_VARARGS)
METHOD(increment, METH_NOARGS)
{NULL} /* Sentinel */
};