Implement rendering of multi cursors in the shaders

This commit is contained in:
Kovid Goyal 2025-08-24 15:22:14 +05:30
parent b2f543f9bd
commit c393c1679e
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
7 changed files with 32 additions and 29 deletions

View file

@ -64,10 +64,8 @@ out float effective_text_alpha;
const uint BYTE_MASK = uint(0xFF);
const uint SPRITE_INDEX_MASK = uint(0x7fffffff);
const uint SPRITE_COLORED_MASK = uint(0x80000000);
const uint SPRITE_COLORED_SHIFT = uint(31);
const uint ZERO = uint(0);
const uint ONE = uint(1);
const uint TWO = uint(2);
const uint SPRITE_COLORED_SHIFT = 31u;
const uint ONE = 1u;
const uint DECORATION_MASK = uint({DECORATION_MASK});
vec3 color_to_vec(uint c) {
@ -168,9 +166,14 @@ CellData set_vertex_position() {
sprite_pos = to_sprite_pos(pos, sprite_idx[0] & SPRITE_INDEX_MASK);
colored_sprite = float((sprite_idx[0] & SPRITE_COLORED_MASK) >> SPRITE_COLORED_SHIFT);
#endif
float is_block_cursor = one_if_equal_zero_otherwise(cursor_shape, 1u);
float has_cursor = is_cursor(column, row);
return CellData(has_cursor, has_cursor * is_block_cursor, pos, cursor_shape_map[cursor_shape]);
float has_main_cursor = is_cursor(column, row);
float multicursor_shape = float((is_selected >> 2) & 3u);
float multicursor_uses_main_cursor_shape = float((is_selected >> 4) & ONE);
multicursor_shape = if_one_then(multicursor_uses_main_cursor_shape, cursor_shape, multicursor_shape);
float final_cursor_shape = if_one_then(has_main_cursor, cursor_shape, multicursor_shape);
float has_cursor = zero_or_one(final_cursor_shape);
float is_block_cursor = has_cursor * one_if_equal_zero_otherwise(final_cursor_shape, 1.0);
return CellData(has_cursor, is_block_cursor, pos, cursor_shape_map[int(final_cursor_shape)]);
}
float background_opacity_for(uint bg, uint colorval, float opacity_if_matched) { // opacity_if_matched if bg == colorval else 1
@ -261,7 +264,7 @@ void main() {
foreground = color_to_vec(fg_as_uint);
float has_dim = float((text_attrs >> DIM_SHIFT) & ONE);
effective_text_alpha = inactive_text_alpha * mix(1.0, dim_opacity, has_dim);
float in_url = float((is_selected & TWO) >> 1);
float in_url = float((is_selected >> 1) & ONE);
decoration_fg = if_one_then(in_url, color_to_vec(url_color), to_color(colors[2], fg_as_uint));
// Selection
vec3 selection_color = if_one_then(use_cell_bg_for_selection_fg, bg, color_to_vec(highlight_fg));

View file

@ -652,9 +652,7 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
static bool
cursor_needs_render(Window *w) {
#define cri w->render_data.screen->cursor_render_info
return w->cursor_opacity_at_last_render != cri.opacity || w->render_data.screen->last_rendered.cursor_x != cri.x || w->render_data.screen->last_rendered.cursor_y != cri.y || w->last_cursor_shape != cri.shape;
#undef cri
return memcmp(&w->render_data.screen->last_rendered.cursor, &w->render_data.screen->cursor_render_info, sizeof(CursorRenderInfo)) != 0;
}
static bool
@ -670,11 +668,13 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow
cursor = rd->screen->paused_rendering.expires_at ? &rd->screen->paused_rendering.cursor : rd->screen->cursor;
ans->x = cursor->x; ans->y = cursor->y;
}
ans->opacity = 0;
if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return cursor_needs_render(w);
ans->is_visible = false; ans->multicursor_count = 0; ans->opacity = 1;
if (rd->screen->scrolled_by) return cursor_needs_render(w);
ans->multicursor_count = screen_multi_cursor_count(rd->screen);
ans->is_visible = screen_is_cursor_visible(rd->screen);
if (!ans->is_visible && ans->multicursor_count == 0) return cursor_needs_render(w);
monotonic_t time_since_start_blink = now - os_window->cursor_blink_zero_time;
bool cursor_blinking = OPT(cursor_blink_interval) > 0 && !cursor->non_blinking && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after));
ans->opacity = 1;
if (cursor_blinking) {
if (animation_is_valid(OPT(animation.cursor))) {
monotonic_t duration = OPT(cursor_blink_interval) * 2;
@ -812,7 +812,6 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co
if (is_active_window) active_window = w;
draw_cells(&WD, os_window, is_active_window, false, num_of_visible_windows == 1, w);
if (WD.screen->start_visual_bell_at != 0) set_maximum_wait(ANIMATION_SAMPLE_WAIT);
w->cursor_opacity_at_last_render = WD.screen->cursor_render_info.opacity; w->last_cursor_shape = WD.screen->cursor_render_info.shape;
}
}
setup_os_window_for_rendering(os_window, tab, active_window, false);

View file

@ -221,9 +221,9 @@ typedef struct {
} Cursor;
typedef struct {
bool is_focused, render_even_when_unfocused;
bool is_focused, render_even_when_unfocused, is_visible;
CursorShape shape;
unsigned int x, y;
unsigned x, y, multicursor_count;
float opacity;
} CursorRenderInfo;

View file

@ -1900,6 +1900,11 @@ screen_is_cursor_visible(const Screen *self) {
return self->paused_rendering.expires_at ? self->paused_rendering.cursor_visible : self->modes.mDECTCEM;
}
unsigned
screen_multi_cursor_count(const Screen *self) {
return self->paused_rendering.expires_at ? self->paused_rendering.extra_cursors.count : self->extra_cursors.count;
}
void
screen_backspace(Screen *self) {
screen_cursor_move(self, 1, -1, true);
@ -3470,7 +3475,7 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
lnum = y - self->scrolled_by;
linebuf_init_line(self->linebuf, lnum);
if (self->linebuf->line->attrs.has_dirty_text ||
(cursor_has_moved && (self->cursor->y == lnum || self->last_rendered.cursor_y == lnum))) {
(cursor_has_moved && (self->cursor->y == lnum || self->last_rendered.cursor.y == lnum))) {
render_line(fonts_data, self->linebuf->line, lnum, self->cursor, self->disable_ligatures, self->lc);
screen_render_line_graphics(self, self->linebuf->line, y - self->scrolled_by);
if (self->linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(

View file

@ -109,9 +109,10 @@ typedef struct {
id_type window_id;
Selections selections, url_ranges;
struct {
unsigned int cursor_x, cursor_y, scrolled_by;
unsigned int scrolled_by;
index_type lines, columns;
color_type cursor_bg;
CursorRenderInfo cursor;
} last_rendered;
bool is_dirty, scroll_changed, reload_all_gpu_data;
Cursor *cursor;
@ -265,6 +266,7 @@ bool screen_has_selection(Screen*);
bool screen_invert_colors(Screen *self);
void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE, bool cursor_has_moved);
bool screen_is_cursor_visible(const Screen *self);
unsigned screen_multi_cursor_count(const Screen *self);
bool screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end);
bool screen_selection_range_for_word(Screen *self, const index_type x, const index_type y, index_type *, index_type *, index_type *start, index_type *end, bool);
void screen_start_selection(Screen *self, index_type x, index_type y, bool, bool, SelectionExtendMode);

View file

@ -476,7 +476,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, C
// Cursor position
Line *line_for_cursor = NULL;
rd->cursor_opacity = MAX(0, MIN(cursor->opacity, 1));
if (rd->cursor_opacity != 0) {
if (rd->cursor_opacity != 0 && cursor->is_visible) {
rd->cursor_x1 = cursor->x, rd->cursor_y1 = cursor->y;
rd->cursor_x2 = cursor->x, rd->cursor_y2 = cursor->y;
CursorShape cs = (cursor->is_focused || OPT(cursor_shape_unfocused) == NO_CURSOR_SHAPE) ? cursor->shape : OPT(cursor_shape_unfocused);
@ -559,8 +559,8 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, FONTS_DATA_HANDLE fonts_
ensure_sprite_map(fonts_data);
const Cursor *cursor = screen->paused_rendering.expires_at ? &screen->paused_rendering.cursor : screen->cursor;
bool cursor_pos_changed = cursor->x != screen->last_rendered.cursor_x
|| cursor->y != screen->last_rendered.cursor_y;
bool cursor_pos_changed = cursor->x != screen->last_rendered.cursor.x \
|| cursor->y != screen->last_rendered.cursor.y;
bool disable_ligatures = screen->disable_ligatures == DISABLE_LIGATURES_CURSOR;
bool screen_resized = screen->last_rendered.columns != screen->columns || screen->last_rendered.lines != screen->lines;
@ -576,11 +576,6 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, FONTS_DATA_HANDLE fonts_
if (!screen->paused_rendering.cell_data_updated) update_cell_data;
} else if (screen->reload_all_gpu_data || screen->scroll_changed || screen->is_dirty || screen_resized || (disable_ligatures && cursor_pos_changed)) update_cell_data;
if (cursor_pos_changed) {
screen->last_rendered.cursor_x = cursor->x;
screen->last_rendered.cursor_y = cursor->y;
}
#define update_selection_data { \
sz = (size_t)screen->lines * screen->columns; \
address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); \
@ -607,6 +602,7 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, FONTS_DATA_HANDLE fonts_
#undef update_cell_data
screen->last_rendered.columns = screen->columns;
screen->last_rendered.lines = screen->lines;
screen->last_rendered.cursor = screen->cursor_render_info;
return changed;
}

View file

@ -193,8 +193,6 @@ typedef struct WindowBarData {
typedef struct Window {
id_type id;
bool visible;
float cursor_opacity_at_last_render;
CursorShape last_cursor_shape;
PyObject *title;
WindowRenderData render_data;
WindowLogoRenderData window_logo;