From d9515e91edc328763806d87d2fa66a643ddb8bc5 Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Wed, 16 Oct 2024 13:57:13 +0900 Subject: [PATCH 1/7] skip target cursor update, instead of skipping trail update when cursor is not valid target --- kitty/cursor_trail.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index 68525b2e7..4ec404b51 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -42,8 +42,10 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi #define EDGE(axis, index) ct->cursor_edge_##axis[index] - if (!WD.screen->paused_rendering.expires_at && !get_cursor_edge(&EDGE(x, 0), &EDGE(x, 1), &EDGE(y, 0), &EDGE(y, 1), w)) { - return needs_render_prev; + if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->updated_at) { + if (!get_cursor_edge(&EDGE(x, 0), &EDGE(x, 1), &EDGE(y, 0), &EDGE(y, 1), w)) { + return needs_render_prev; + } } // the decay time for the trail to reach 1/1024 of its distance from the cursor corner @@ -55,7 +57,8 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi ct->corner_x[i] = EDGE(x, ci[i][0]); ct->corner_y[i] = EDGE(y, ci[i][1]); } - } else if (OPT(cursor_trail) < now - WD.screen->cursor->position_changed_by_client_at && ct->updated_at < now) { + } + else if (ct->updated_at < now) { float cursor_center_x = (EDGE(x, 0) + EDGE(x, 1)) * 0.5f; float cursor_center_y = (EDGE(y, 0) + EDGE(y, 1)) * 0.5f; float cursor_diag_2 = norm(EDGE(x, 1) - EDGE(x, 0), EDGE(y, 1) - EDGE(y, 0)) * 0.5f; From af8b563eb0a58e65a820bd5949ba4be7fa5386a8 Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 16:30:54 +0900 Subject: [PATCH 2/7] fix: cursor trail target not updated correctly --- kitty/cursor_trail.c | 48 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index 4ec404b51..ad4f547c6 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -5,27 +5,36 @@ norm(float x, float y) { return sqrtf(x * x + y * y); } -inline static bool -get_cursor_edge(float *left, float *right, float *top, float *bottom, Window *w) { +static void +update_cursor_trail_target(CursorTrail *ct, Window *w) { +// EDGE(x, 0) left +// EDGE(x, 1) right +// EDGE(y, 0) top +// EDGE(y, 1) bottom +#define EDGE(axis, index) ct->cursor_edge_##axis[index] #define WD w->render_data - *left = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; - *bottom = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; switch (WD.screen->cursor_render_info.shape) { case CURSOR_BLOCK: case CURSOR_HOLLOW: - *right = *left + WD.dx; - *top = *bottom + WD.dy; - return true; + EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; + EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; + EDGE(x, 1) = EDGE(x, 0) + WD.dx; + EDGE(y, 0) = EDGE(y, 1) + WD.dy; + break; case CURSOR_BEAM: - *right = *left + WD.dx / WD.screen->cell_size.width * OPT(cursor_beam_thickness); - *top = *bottom + WD.dy; - return true; + EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; + EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; + EDGE(x, 1) = EDGE(x, 0) + WD.dx / WD.screen->cell_size.width * OPT(cursor_beam_thickness); + EDGE(y, 0) = EDGE(y, 1) + WD.dy; + break; case CURSOR_UNDERLINE: - *right = *left + WD.dx; - *top = *bottom + WD.dy / WD.screen->cell_size.height * OPT(cursor_underline_thickness); - return true; + EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; + EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; + EDGE(x, 1) = EDGE(x, 0) + WD.dx; + EDGE(y, 0) = EDGE(y, 1) + WD.dy / WD.screen->cell_size.height * OPT(cursor_underline_thickness); + break; default: - return false; + break; } } @@ -40,12 +49,8 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi bool needs_render_prev = ct->needs_render; ct->needs_render = false; -#define EDGE(axis, index) ct->cursor_edge_##axis[index] - - if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->updated_at) { - if (!get_cursor_edge(&EDGE(x, 0), &EDGE(x, 1), &EDGE(y, 0), &EDGE(y, 1), w)) { - return needs_render_prev; - } + if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->position_changed_by_client_at) { + update_cursor_trail_target(ct, w); } // the decay time for the trail to reach 1/1024 of its distance from the cursor corner @@ -101,9 +106,8 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi ct->color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color).rgb; } +#undef WD #undef EDGE // returning true here will cause the cells to be drawn return ct->needs_render || needs_render_prev; } - -#undef WD From f64d2d27fb13be4d4481b7ab337bd8649358d04b Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 16:53:06 +0900 Subject: [PATCH 3/7] separate update_cursor_trail function in smaller pieces --- kitty/cursor_trail.c | 76 +++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index ad4f547c6..fb4c4fbd9 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -1,4 +1,5 @@ #include "state.h" +#include "float.h" inline static float norm(float x, float y) { @@ -7,51 +8,51 @@ norm(float x, float y) { static void update_cursor_trail_target(CursorTrail *ct, Window *w) { -// EDGE(x, 0) left -// EDGE(x, 1) right -// EDGE(y, 0) top -// EDGE(y, 1) bottom #define EDGE(axis, index) ct->cursor_edge_##axis[index] #define WD w->render_data + float left, right, top, bottom; switch (WD.screen->cursor_render_info.shape) { case CURSOR_BLOCK: case CURSOR_HOLLOW: - EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; - EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; - EDGE(x, 1) = EDGE(x, 0) + WD.dx; - EDGE(y, 0) = EDGE(y, 1) + WD.dy; + case CURSOR_BEAM: + case CURSOR_UNDERLINE: + left = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; + bottom = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; + break; + default: + left = FLT_MAX; + bottom = FLT_MAX; + } + switch (WD.screen->cursor_render_info.shape) { + case CURSOR_BLOCK: + case CURSOR_HOLLOW: + right = left + WD.dx; + top = bottom + WD.dy; break; case CURSOR_BEAM: - EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; - EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; - EDGE(x, 1) = EDGE(x, 0) + WD.dx / WD.screen->cell_size.width * OPT(cursor_beam_thickness); - EDGE(y, 0) = EDGE(y, 1) + WD.dy; + right = left + WD.dx / WD.screen->cell_size.width * OPT(cursor_beam_thickness); + top = bottom + WD.dy; break; case CURSOR_UNDERLINE: - EDGE(x, 0) = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; - EDGE(y, 1) = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; - EDGE(x, 1) = EDGE(x, 0) + WD.dx; - EDGE(y, 0) = EDGE(y, 1) + WD.dy / WD.screen->cell_size.height * OPT(cursor_underline_thickness); + right = left + WD.dx; + top = bottom + WD.dy / WD.screen->cell_size.height * OPT(cursor_underline_thickness); break; default: break; } + if (left != FLT_MAX) { + EDGE(x, 0) = left; + EDGE(x, 1) = right; + EDGE(y, 0) = top; + EDGE(y, 1) = bottom; + } } -bool -update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_window) { +static bool +update_cursor_trail_corners(CursorTrail *ct, monotonic_t now, OSWindow *os_window, float dx_threshold, float dy_threshold) { // the trail corners move towards the cursor corner at a speed proportional to their distance from the cursor corner. // equivalent to exponential ease out animation. - static const int ci[4][2] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}}; - const float dx_threshold = WD.dx / WD.screen->cell_size.width; - const float dy_threshold = WD.dy / WD.screen->cell_size.height; - bool needs_render_prev = ct->needs_render; - ct->needs_render = false; - - if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->position_changed_by_client_at) { - update_cursor_trail_target(ct, w); - } // the decay time for the trail to reach 1/1024 of its distance from the cursor corner float decay_fast = OPT(cursor_trail_decay_fast); @@ -91,15 +92,32 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi ct->corner_y[i] += dy * step; } } + ct->updated_at = now; for (int i = 0; i < 4; ++i) { float dx = fabsf(EDGE(x, ci[i][0]) - ct->corner_x[i]); float dy = fabsf(EDGE(y, ci[i][1]) - ct->corner_y[i]); if (dx_threshold <= dx || dy_threshold <= dy) { - ct->needs_render = true; - break; + return true; } } + return false; +} + +bool +update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_window) { + const float dx_threshold = WD.dx / WD.screen->cell_size.width; + const float dy_threshold = WD.dy / WD.screen->cell_size.height; + bool needs_render_prev = ct->needs_render; + ct->needs_render = false; + + if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->position_changed_by_client_at) { + update_cursor_trail_target(ct, w); + } + + if (update_cursor_trail_corners(ct, now, os_window, dx_threshold, dy_threshold)) { + ct->needs_render = true; + } if (ct->needs_render) { ColorProfile *cp = WD.screen->color_profile; From 85bc56b81336468c448ed3ffa309985d83977dbd Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 17:25:30 +0900 Subject: [PATCH 4/7] move trail color decision logic to shader.c --- kitty/cursor_trail.c | 11 ++++------- kitty/shaders.c | 4 +++- kitty/state.h | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index fb4c4fbd9..3127b3ed5 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -45,6 +45,7 @@ update_cursor_trail_target(CursorTrail *ct, Window *w) { EDGE(x, 1) = right; EDGE(y, 0) = top; EDGE(y, 1) = bottom; + ct->screen = WD.screen; } } @@ -119,13 +120,9 @@ update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_wi ct->needs_render = true; } - if (ct->needs_render) { - ColorProfile *cp = WD.screen->color_profile; - ct->color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color).rgb; - } - -#undef WD -#undef EDGE // returning true here will cause the cells to be drawn return ct->needs_render || needs_render_prev; } + +#undef WD +#undef EDGE diff --git a/kitty/shaders.c b/kitty/shaders.c index 38a5cc3ab..a44cb4b86 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -1154,7 +1154,9 @@ draw_cursor_trail(CursorTrail *trail) { glUniform2fv(trail_program_layout.uniforms.cursor_edge_x, 1, trail->cursor_edge_x); glUniform2fv(trail_program_layout.uniforms.cursor_edge_y, 1, trail->cursor_edge_y); - color_vec3(trail_program_layout.uniforms.trail_color, trail->color); + ColorProfile *cp = trail->screen->color_profile; + color_type color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color).rgb; + color_vec3(trail_program_layout.uniforms.trail_color, color); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); diff --git a/kitty/state.h b/kitty/state.h index 08a592001..a121073c7 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -218,7 +218,7 @@ typedef struct { typedef struct { bool needs_render; monotonic_t updated_at; - color_type color; + Screen* screen; float corner_x[4]; float corner_y[4]; float cursor_edge_x[2]; From 25caf90a80f8679c291c45adaaf96c36b8d05910 Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 18:15:46 +0900 Subject: [PATCH 5/7] minor refactor --- kitty/cursor_trail.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index 3127b3ed5..0ef5c0c8a 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -50,10 +50,12 @@ update_cursor_trail_target(CursorTrail *ct, Window *w) { } static bool -update_cursor_trail_corners(CursorTrail *ct, monotonic_t now, OSWindow *os_window, float dx_threshold, float dy_threshold) { +update_cursor_trail_corners(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_window) { // the trail corners move towards the cursor corner at a speed proportional to their distance from the cursor corner. // equivalent to exponential ease out animation. static const int ci[4][2] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}}; + const float dx_threshold = WD.dx / WD.screen->cell_size.width; + const float dy_threshold = WD.dy / WD.screen->cell_size.height; // the decay time for the trail to reach 1/1024 of its distance from the cursor corner float decay_fast = OPT(cursor_trail_decay_fast); @@ -107,16 +109,14 @@ update_cursor_trail_corners(CursorTrail *ct, monotonic_t now, OSWindow *os_windo bool update_cursor_trail(CursorTrail *ct, Window *w, monotonic_t now, OSWindow *os_window) { - const float dx_threshold = WD.dx / WD.screen->cell_size.width; - const float dy_threshold = WD.dy / WD.screen->cell_size.height; - bool needs_render_prev = ct->needs_render; - ct->needs_render = false; - if (!WD.screen->paused_rendering.expires_at && OPT(cursor_trail) < now - WD.screen->cursor->position_changed_by_client_at) { update_cursor_trail_target(ct, w); } - if (update_cursor_trail_corners(ct, now, os_window, dx_threshold, dy_threshold)) { + bool needs_render_prev = ct->needs_render; + ct->needs_render = false; + + if (update_cursor_trail_corners(ct, w, now, os_window)) { ct->needs_render = true; } From fe63c6ddfd440512ec3680bdd9b3e2a628d10b4c Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 18:16:26 +0900 Subject: [PATCH 6/7] last rendered cursor_bg color and re-use it when trail rendering --- kitty/screen.h | 1 + kitty/shaders.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/kitty/screen.h b/kitty/screen.h index 71e78ecfb..e71c6ac6a 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -97,6 +97,7 @@ typedef struct { struct { unsigned int cursor_x, cursor_y, scrolled_by; index_type lines, columns; + color_type cursor_bg; } last_rendered; bool is_dirty, scroll_changed, reload_all_gpu_data; Cursor *cursor; diff --git a/kitty/shaders.c b/kitty/shaders.c index a44cb4b86..e64440169 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -385,6 +385,9 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c #undef COLOR rd->url_color = OPT(url_color); rd->url_style = OPT(url_style); + // store last rendered cursor color for trail rendering + screen->last_rendered.cursor_bg = rd->cursor_bg; + unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL; } @@ -1154,9 +1157,7 @@ draw_cursor_trail(CursorTrail *trail) { glUniform2fv(trail_program_layout.uniforms.cursor_edge_x, 1, trail->cursor_edge_x); glUniform2fv(trail_program_layout.uniforms.cursor_edge_y, 1, trail->cursor_edge_y); - ColorProfile *cp = trail->screen->color_profile; - color_type color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color).rgb; - color_vec3(trail_program_layout.uniforms.trail_color, color); + color_vec3(trail_program_layout.uniforms.trail_color, trail->screen->last_rendered.cursor_bg); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); From 0ef7a4eb1f2e3f85cbf1bac8f4a943b89eabb986 Mon Sep 17 00:00:00 2001 From: Rick Choi Date: Sat, 19 Oct 2024 19:15:43 +0900 Subject: [PATCH 7/7] fix build error in linux ci --- kitty/cursor_trail.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kitty/cursor_trail.c b/kitty/cursor_trail.c index 0ef5c0c8a..1240407f3 100644 --- a/kitty/cursor_trail.c +++ b/kitty/cursor_trail.c @@ -10,7 +10,7 @@ static void update_cursor_trail_target(CursorTrail *ct, Window *w) { #define EDGE(axis, index) ct->cursor_edge_##axis[index] #define WD w->render_data - float left, right, top, bottom; + float left = FLT_MAX, right = FLT_MAX, top = FLT_MAX, bottom = FLT_MAX; switch (WD.screen->cursor_render_info.shape) { case CURSOR_BLOCK: case CURSOR_HOLLOW: @@ -18,10 +18,8 @@ update_cursor_trail_target(CursorTrail *ct, Window *w) { case CURSOR_UNDERLINE: left = WD.xstart + WD.screen->cursor_render_info.x * WD.dx; bottom = WD.ystart - (WD.screen->cursor_render_info.y + 1) * WD.dy; - break; default: - left = FLT_MAX; - bottom = FLT_MAX; + break; } switch (WD.screen->cursor_render_info.shape) { case CURSOR_BLOCK: