diff --git a/kitty/boss.py b/kitty/boss.py index dbfbebc64..c522a38ed 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -54,13 +54,12 @@ def __init__(self, window, window_width, window_height, opts, args, child): 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 @@ def signal_received(self): 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(): diff --git a/kitty/char_grid.py b/kitty/char_grid.py index b66eb485e..f8859d027 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -172,17 +172,14 @@ def __init__(self, screen, opts, window_width, window_height): 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 diff --git a/kitty/develop_gl.py b/kitty/develop_gl.py index 1abe45777..ba72afe3f 100644 --- a/kitty/develop_gl.py +++ b/kitty/develop_gl.py @@ -42,7 +42,6 @@ def __init__(self, w, h): 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): diff --git a/kitty/fonts.py b/kitty/fonts.py index aea4bdd39..4082e85c9 100644 --- a/kitty/fonts.py +++ b/kitty/fonts.py @@ -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] diff --git a/kitty/shaders.py b/kitty/shaders.py index ed57363b8..d92a5cd5f 100644 --- a/kitty/shaders.py +++ b/kitty/shaders.py @@ -46,11 +46,8 @@ def __init__(self): 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 @@ def do_layout(self, cell_width=1, cell_height=1): 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 @@ def send_to_gpu(self, x, y, z, buf): 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) diff --git a/kitty/sprites.c b/kitty/sprites.c index 9e33bc86d..26c2fd971 100644 --- a/kitty/sprites.c +++ b/kitty/sprites.c @@ -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 */ };