diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 210e5274d..7d6672bc8 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -7,6 +7,7 @@ uniform uvec4 default_colors; // The default colors uniform ColorTable { uint color_table[256]; // The color table }; +in uint text_attrs; in uvec3 sprite_coords; in uvec3 colors; in float is_selected; @@ -24,11 +25,13 @@ const uvec2 pos_map[] = uvec2[4]( uvec2(0, 0) // left, top ); -const uint strike_map[] = uint[2](uint(0), uint(3)); const uint BYTE_MASK = uint(0xFF); const uint SHORT_MASK = uint(0xFFFF); const uint ZERO = uint(0); -const uint SMASK = uint(3); +const uint ONE = uint(1); +const uint THREE = uint(3); +const uint DECORATION_MASK = uint(3); +const uint STRIKE_MASK = uint(1); vec3 color_to_vec(uint c) { uint r, g, b; @@ -76,12 +79,13 @@ void main() { gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1); sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK); - uint fg = colors[color_indices[0]]; - uint bg = colors[color_indices[1]]; + uint reverse = (text_attrs >> 30) & STRIKE_MASK; + uint fg = colors[color_indices[reverse]]; + uint bg = colors[color_indices[ONE - reverse]]; uint decoration = colors[2]; foreground = apply_selection(to_color(fg, default_colors[color_indices[0]]), default_colors[2]); background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]); decoration_fg = to_color(decoration, default_colors[color_indices[0]]); - underline_pos = to_sprite_pos(pos, (sprite_coords.z >> 24) & SMASK, ZERO, ZERO); - strike_pos = to_sprite_pos(pos, strike_map[(sprite_coords.z >> 26)] & SMASK, ZERO, ZERO); + underline_pos = to_sprite_pos(pos, (text_attrs >> 26) & DECORATION_MASK, ZERO, ZERO); + strike_pos = to_sprite_pos(pos, ((text_attrs >> 31) & STRIKE_MASK) * THREE, ZERO, ZERO); } diff --git a/kitty/char_grid.py b/kitty/char_grid.py index 7a6d59774..67fd36e90 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -13,10 +13,10 @@ from .constants import ( GLfloat, GLuint, ScreenGeometry, cell_size, viewport_size ) from .fast_data_types import ( - CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND, - GL_FLOAT, GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, glDisable, - glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, - glUniform2i, glUniform2ui, glUniform4f, glUniform4ui + CELL, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, GL_BLEND, GL_FLOAT, + GL_LINE_LOOP, GL_TRIANGLE_FAN, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT, + glDisable, glDrawArrays, glDrawArraysInstanced, glEnable, glUniform1i, + glUniform2f, glUniform2i, glUniform2ui, glUniform4f, glUniform4ui ) from .rgb import to_color from .shaders import ShaderProgram, load_shaders @@ -51,10 +51,10 @@ class CellProgram(ShaderProgram): def create_sprite_map(self): with self.array_object_creator() as add_attribute: - stride = DATA_CELL_SIZE * sizeof(GLuint) - size = DATA_CELL_SIZE // 2 - add_attribute('sprite_coords', size=size, dtype=GL_UNSIGNED_INT, stride=stride, divisor=1) - add_attribute('colors', size=size, dtype=GL_UNSIGNED_INT, stride=stride, offset=stride // 2, divisor=1) + stride = CELL['size'] + add_attribute('text_attrs', size=1, dtype=GL_UNSIGNED_INT, offset=CELL['ch'], stride=stride, divisor=1) + add_attribute('sprite_coords', size=3, dtype=GL_UNSIGNED_SHORT, offset=CELL['sprite_x'], stride=stride, divisor=1) + add_attribute('colors', size=3, dtype=GL_UNSIGNED_INT, stride=stride, offset=CELL['fg'], divisor=1) add_attribute.newbuf() add_attribute('is_selected', size=1, dtype=GL_FLOAT, stride=sizeof(GLfloat), divisor=1) return add_attribute.vao_id @@ -137,16 +137,18 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy) -def render_cells(vao_id, sg, cell_program, sprites, color_profile, invert_colors=False): +def render_cells(vao_id, sg, cell_program, sprites, color_profile, invert_colors=False, screen_reversed=False): if color_profile.dirty: cell_program.send_color_table(color_profile) color_profile.dirty = False ul = cell_program.uniform_location glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum) glUniform4ui(ul('default_colors'), color_profile.default_fg, color_profile.default_bg, color_profile.highlight_fg, color_profile.highlight_bg) - glUniform2i(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1) + inverted = invert_colors or screen_reversed + glUniform2i(ul('color_indices'), 1 if inverted else 0, 0 if inverted else 1) glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy) glUniform1i(ul('sprites'), sprites.sampler_num) + glUniform1i(ul('screen_reversed'), 1 if screen_reversed else 0) glUniform2f(ul('sprite_layout'), *(sprites.layout)) with cell_program.bound_vertex_array(vao_id), cell_program.bound_uniform_buffer(color_profile.ubo): glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum) @@ -159,6 +161,7 @@ class CharGrid: def __init__(self, screen, opts): self.vao_id = None self.current_selection = Selection() + self.screen_reversed = False self.scroll_changed = False self.last_rendered_selection = None self.render_data = None @@ -194,7 +197,7 @@ class CharGrid: def resize(self, window_geometry): self.update_position(window_geometry) - self.data_buffer_size = sizeof(GLuint) * self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE + self.data_buffer_size = self.screen_geometry.ynum * self.screen_geometry.xnum * CELL['size'] self.selection_buf = (GLfloat * (self.screen_geometry.ynum * self.screen_geometry.xnum))() self.current_selection.clear() @@ -230,7 +233,7 @@ class CharGrid: 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( + cursor_changed, self.scrolled_by, self.screen_reversed = self.screen.update_cell_data( address, self.scrolled_by, force_full_refresh) self.current_selection.clear() @@ -370,7 +373,7 @@ class CharGrid: return sg def render_cells(self, sg, cell_program, sprites, invert_colors=False): - render_cells(self.vao_id, sg, cell_program, sprites, self.screen.color_profile, invert_colors=invert_colors) + render_cells(self.vao_id, sg, cell_program, sprites, self.screen.color_profile, invert_colors=invert_colors, screen_reversed=self.screen_reversed) def render_cursor(self, sg, cursor_program, is_focused): cursor = self.current_cursor diff --git a/kitty/data-types.c b/kitty/data-types.c index 76a09ec32..012dd2d49 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -145,7 +145,6 @@ PyInit_fast_data_types(void) { PyModule_AddIntMacro(m, DECCOLM); PyModule_AddIntMacro(m, DECOM); PyModule_AddIntMacro(m, IRM); - PyModule_AddIntMacro(m, DATA_CELL_SIZE); PyModule_AddIntMacro(m, ANY_MODE); PyModule_AddIntMacro(m, MOTION_MODE); PyModule_AddIntMacro(m, BUTTON_MODE); diff --git a/kitty/data-types.h b/kitty/data-types.h index 1531a744f..c0a375c6f 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -38,8 +38,6 @@ typedef uint16_t sprite_index; #define SGR_PROTOCOL 2 #define URXVT_PROTOCOL 3 -#define DATA_CELL_SIZE 6 - #define BLANK_CHAR 32 #define CHAR_MASK 0xFFFFFF #define ATTRS_SHIFT 24 @@ -313,7 +311,6 @@ void cursor_reset(Cursor*); Cursor* cursor_copy(Cursor*); void cursor_copy_to(Cursor *src, Cursor *dest); void cursor_reset_display_attrs(Cursor*); -bool update_cell_range_data(ScreenModes *modes, Line *, unsigned int, unsigned int, unsigned int *); void set_sprite_position(Cell *cell, Cell *previous_cell); PyObject* line_text_at(char_type, combining_type); diff --git a/kitty/gl.h b/kitty/gl.h index 15951166b..223efb5a8 100644 --- a/kitty/gl.h +++ b/kitty/gl.h @@ -826,7 +826,7 @@ int add_module_gl_constants(PyObject *module) { GLC(GL_TEXTURE_MIN_FILTER); GLC(GL_TEXTURE_MAG_FILTER); GLC(GL_TEXTURE_WRAP_S); GLC(GL_TEXTURE_WRAP_T); GLC(GL_UNPACK_ALIGNMENT); - GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_R32UI); GLC(GL_RGB32UI); GLC(GL_RGBA); + GLC(GL_R8); GLC(GL_RED); GLC(GL_UNSIGNED_BYTE); GLC(GL_UNSIGNED_SHORT); GLC(GL_R32UI); GLC(GL_RGB32UI); GLC(GL_RGBA); GLC(GL_TEXTURE_BUFFER); GLC(GL_STATIC_DRAW); GLC(GL_STREAM_DRAW); GLC(GL_DYNAMIC_DRAW); GLC(GL_SRC_ALPHA); GLC(GL_ONE_MINUS_SRC_ALPHA); GLC(GL_WRITE_ONLY); GLC(GL_READ_ONLY); GLC(GL_READ_WRITE); diff --git a/kitty/screen.c b/kitty/screen.c index d8b764ed8..2835c7634 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1178,10 +1178,17 @@ change_scrollback_size(Screen *self, PyObject *args) { Py_RETURN_NONE; } +static inline void +update_line_data(Line *line, unsigned int dest_y, uint8_t *data) { + size_t base = dest_y * line->xnum * sizeof(Cell); + memcpy(data + base, line->cells, line->xnum * sizeof(Cell)); +} + + static PyObject* -screen_update_cell_data(Screen *self, PyObject *args) { +update_cell_data(Screen *self, PyObject *args) { PyObject *dp; - unsigned int *data; + uint8_t *data; int force_screen_refresh; unsigned int scrolled_by; unsigned int history_line_added_count = self->history_line_added_count; @@ -1192,15 +1199,13 @@ screen_update_cell_data(Screen *self, PyObject *args) { reset_dirty(self); 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; + update_line_data(self->historybuf->line, y, data); } 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; + update_line_data(self->linebuf->line, y, data); } - return Py_BuildValue("OI", cursor_changed, scrolled_by); + return Py_BuildValue("OIO", cursor_changed, scrolled_by, self->modes.mDECSCNM ? Py_True : Py_False); } static PyObject* @@ -1303,7 +1308,7 @@ static PyMethodDef methods[] = { MND(apply_selection, METH_VARARGS) MND(toggle_alt_screen, METH_NOARGS) MND(reset_callbacks, METH_NOARGS) - {"update_cell_data", (PyCFunction)screen_update_cell_data, METH_VARARGS, ""}, + {"update_cell_data", (PyCFunction)update_cell_data, METH_VARARGS, ""}, {"select_graphic_rendition", (PyCFunction)_select_graphic_rendition, METH_VARARGS, ""}, {NULL} /* Sentinel */ diff --git a/kitty/sprites.c b/kitty/sprites.c index 0e732468d..462ee30eb 100644 --- a/kitty/sprites.c +++ b/kitty/sprites.c @@ -167,28 +167,6 @@ sprite_position_for(PyObject UNUSED *self, PyObject *args) { return Py_BuildValue("III", pos->x, pos->y, pos->z); } -bool -update_cell_range_data(ScreenModes *modes, Line *line, unsigned int xstart, unsigned int xmax, unsigned int *data) { - char_type ch; - const bool screen_reversed = modes->mDECSCNM; - - size_t base = line->ynum * line->xnum * DATA_CELL_SIZE; - for (size_t i = xstart, offset = base + xstart * DATA_CELL_SIZE; i <= xmax; i++, offset += DATA_CELL_SIZE) { - ch = line->cells[i].ch; - char_type attrs = ch >> ATTRS_SHIFT; - unsigned int decoration = (attrs >> DECORATION_SHIFT) & DECORATION_MASK; - unsigned int strikethrough = ((attrs >> STRIKE_SHIFT) & 1) ? 3 : 0; - bool reverse = ((attrs >> REVERSE_SHIFT) & 1) ^ screen_reversed; - data[offset] = line->cells[i].sprite_x; - data[offset+1] = line->cells[i].sprite_y; - data[offset+2] = line->cells[i].sprite_z | (decoration << 24) | (strikethrough << 26); - data[offset+(reverse ? 4 : 3)] = line->cells[i].fg; - data[offset+(reverse ? 3 : 4)] = line->cells[i].bg; - data[offset+5] = line->cells[i].fg; - } - return true; -} - PyObject* render_dirty_sprites(PyObject UNUSED *s_) { #define render_dirty_cells_doc "Render all cells that are marked as dirty" diff --git a/kitty/tabs.py b/kitty/tabs.py index e07ac6e88..d55ebfe13 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -3,7 +3,6 @@ # License: GPL v3 Copyright: 2016, Kovid Goyal from collections import deque, namedtuple -from ctypes import sizeof from functools import partial from .borders import Borders @@ -15,7 +14,7 @@ from .constants import ( shell_path, viewport_size ) from .fast_data_types import ( - DATA_CELL_SIZE, DECAWM, Screen, glfw_post_empty_event + CELL, DECAWM, Screen, glfw_post_empty_event ) from .layout import Rect, all_layouts from .utils import color_as_int @@ -234,7 +233,7 @@ class TabBar: s.resize(1, ncells) s.reset_mode(DECAWM) self.selection_buf = (GLuint * (s.lines * s.columns))() - self.data_buffer_size = sizeof(GLuint) * s.lines * s.columns * DATA_CELL_SIZE + self.data_buffer_size = s.lines * s.columns * CELL['size'] self.selection_buf_changed = True margin = (viewport_width - ncells * cell_width) // 2 self.window_geometry = g = WindowGeometry(