-
-
Save rhoot/5d47b0aabe96f6d44659d2f40329860f to your computer and use it in GitHub Desktop.
YellowOnion's vrr cursor patches updated for latest master
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/sway/commands.h b/include/sway/commands.h | |
index 27058587..d7593d58 100644 | |
--- a/include/sway/commands.h | |
+++ b/include/sway/commands.h | |
@@ -152,6 +152,7 @@ sway_cmd cmd_kill; | |
sway_cmd cmd_layout; | |
sway_cmd cmd_log_colors; | |
sway_cmd cmd_mark; | |
+sway_cmd cmd_max_cursor_latency; | |
sway_cmd cmd_max_render_time; | |
sway_cmd cmd_mode; | |
sway_cmd cmd_mouse_warping; | |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h | |
index 960f9d71..ab00e83b 100644 | |
--- a/include/sway/tree/view.h | |
+++ b/include/sway/tree/view.h | |
@@ -122,6 +122,7 @@ struct sway_view { | |
struct wl_listener surface_new_subsurface; | |
int max_render_time; // In milliseconds | |
+ int max_cursor_latency; // In microseconds | |
enum seat_config_shortcuts_inhibit shortcuts_inhibit; | |
}; | |
diff --git a/sway/commands.c b/sway/commands.c | |
index 55eda183..d8b28f42 100644 | |
--- a/sway/commands.c | |
+++ b/sway/commands.c | |
@@ -122,6 +122,7 @@ static const struct cmd_handler command_handlers[] = { | |
{ "kill", cmd_kill }, | |
{ "layout", cmd_layout }, | |
{ "mark", cmd_mark }, | |
+ { "max_cursor_latency", cmd_max_cursor_latency }, | |
{ "max_render_time", cmd_max_render_time }, | |
{ "move", cmd_move }, | |
{ "nop", cmd_nop }, | |
diff --git a/sway/commands/max_cursor_latency.c b/sway/commands/max_cursor_latency.c | |
new file mode 100644 | |
index 00000000..12654c1d | |
--- /dev/null | |
+++ b/sway/commands/max_cursor_latency.c | |
@@ -0,0 +1,32 @@ | |
+#include <strings.h> | |
+#include "sway/commands.h" | |
+#include "sway/config.h" | |
+#include "sway/tree/view.h" | |
+ | |
+struct cmd_results *cmd_max_cursor_latency(int argc, char **argv) { | |
+ if (!argc) { | |
+ return cmd_results_new(CMD_INVALID, "Missing max cursor latency argument."); | |
+ } | |
+ | |
+ int max_cursor_latency; | |
+ if (!strcmp(*argv, "off")) { | |
+ max_cursor_latency = 0; | |
+ } else { | |
+ char *end; | |
+ max_cursor_latency = strtol(*argv, &end, 10); | |
+ if (*end || max_cursor_latency <= 0) { | |
+ return cmd_results_new(CMD_INVALID, "Invalid max cursor latency."); | |
+ } | |
+ } | |
+ | |
+ struct sway_container *container = config->handler_context.container; | |
+ if (!container || !container->view) { | |
+ return cmd_results_new(CMD_INVALID, | |
+ "Only views can have a max_cursor_latency"); | |
+ } | |
+ | |
+ struct sway_view *view = container->view; | |
+ view->max_cursor_latency = max_cursor_latency; | |
+ | |
+ return cmd_results_new(CMD_SUCCESS, NULL); | |
+} | |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c | |
index aed1fdeb..d1376601 100644 | |
--- a/sway/desktop/output.c | |
+++ b/sway/desktop/output.c | |
@@ -565,6 +565,11 @@ static int output_repaint_timer_handler(void *data) { | |
wlr_output->frame_pending = false; | |
+ struct timespec now; | |
+ clock_gettime(CLOCK_MONOTONIC, &now); | |
+ | |
+ wlr_output_cursor_move_any_expired(wlr_output, &now); | |
+ | |
if (!wlr_output->needs_frame && | |
!output->gamma_lut_changed && | |
!pixman_region32_not_empty(&output->damage_ring.current)) { | |
@@ -601,6 +606,9 @@ static int output_repaint_timer_handler(void *data) { | |
pending.committed |= WLR_OUTPUT_STATE_DAMAGE; | |
get_frame_damage(output, &pending.damage); | |
+ if (output->wlr_output->needs_frame) | |
+ wlr_output_cursor_move_all_deferred(wlr_output, &now); | |
+ | |
if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { | |
// Try to scan-out the fullscreen view | |
static bool last_scanned_out = false; | |
@@ -657,9 +665,6 @@ static int output_repaint_timer_handler(void *data) { | |
.pass = render_pass, | |
}; | |
- struct timespec now; | |
- clock_gettime(CLOCK_MONOTONIC, &now); | |
- | |
output_render(&ctx); | |
pixman_region32_fini(&damage); | |
diff --git a/sway/input/seat.c b/sway/input/seat.c | |
index a84e4d52..e9c2af47 100644 | |
--- a/sway/input/seat.c | |
+++ b/sway/input/seat.c | |
@@ -1222,9 +1222,11 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n | |
seat_send_focus(&container->node, seat); | |
} | |
+ int max_cursor_latency = 0; | |
// emit ipc events | |
set_workspace(seat, new_workspace); | |
if (container && container->view) { | |
+ max_cursor_latency = container->view->max_cursor_latency; | |
ipc_event_window(container, "focus"); | |
} | |
@@ -1274,6 +1276,9 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n | |
workspace_consider_destroy(last_workspace); | |
} | |
+ if (seat->cursor) | |
+ wlr_cursor_set_max_latency(seat->cursor->cursor, max_cursor_latency * 1000); | |
+ | |
seat->has_focus = true; | |
if (config->smart_gaps && new_workspace) { | |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c | |
index 58356d4e..48bf63fe 100644 | |
--- a/sway/ipc-json.c | |
+++ b/sway/ipc-json.c | |
@@ -588,6 +588,7 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |
json_object_object_add(object, "geometry", ipc_json_create_rect(&geometry)); | |
json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time)); | |
+ json_object_object_add(object, "max_cursor_latency", json_object_new_int(c->view->max_cursor_latency)); | |
json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view))); | |
diff --git a/sway/meson.build b/sway/meson.build | |
index 3abd778d..550c2290 100644 | |
--- a/sway/meson.build | |
+++ b/sway/meson.build | |
@@ -73,6 +73,7 @@ sway_sources = files( | |
'commands/kill.c', | |
'commands/mark.c', | |
'commands/max_render_time.c', | |
+ 'commands/max_cursor_latency.c', | |
'commands/opacity.c', | |
'commands/include.c', | |
'commands/input.c', | |
diff --git a/sway/tree/view.c b/sway/tree/view.c | |
index ec54fed8..7f9c3b67 100644 | |
--- a/sway/tree/view.c | |
+++ b/sway/tree/view.c | |
@@ -4,6 +4,7 @@ | |
#include <wayland-server-core.h> | |
#include <wlr/render/wlr_renderer.h> | |
#include <wlr/types/wlr_buffer.h> | |
+#include <wlr/types/wlr_cursor.h> | |
#include <wlr/types/wlr_output_layout.h> | |
#include <wlr/types/wlr_server_decoration.h> | |
#include <wlr/types/wlr_subcompositor.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/util/time.h b/include/util/time.h | |
index 3f76aa47..1fcb569c 100644 | |
--- a/include/util/time.h | |
+++ b/include/util/time.h | |
@@ -4,6 +4,8 @@ | |
#include <stdint.h> | |
#include <time.h> | |
+static const long NSEC_PER_SEC = 1000000000; | |
+ | |
/** | |
* Get the current time, in milliseconds. | |
*/ | |
@@ -30,4 +32,6 @@ void timespec_from_nsec(struct timespec *r, int64_t nsec); | |
void timespec_sub(struct timespec *r, const struct timespec *a, | |
const struct timespec *b); | |
+int32_t mhz_to_nsec(int32_t mhz); | |
+ | |
#endif | |
diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h | |
index 004be0f1..c29b9e22 100644 | |
--- a/include/wlr/types/wlr_cursor.h | |
+++ b/include/wlr/types/wlr_cursor.h | |
@@ -34,6 +34,8 @@ struct wlr_cursor { | |
struct wlr_cursor_state *state; | |
double x, y; | |
+ int max_latency; | |
+ | |
/** | |
* The interpretation of these signals is the responsibility of the | |
* compositor, but some helpers are provided for your benefit. If you | |
@@ -166,6 +168,8 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, | |
void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, | |
int32_t hotspot_x, int32_t hotspot_y); | |
+void wlr_cursor_set_max_latency(struct wlr_cursor *cur, int max_latency); | |
+ | |
/** | |
* Attaches this input device to this cursor. The input device must be one of: | |
* | |
diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h | |
index 30331fba..7343fb51 100644 | |
--- a/include/wlr/types/wlr_output.h | |
+++ b/include/wlr/types/wlr_output.h | |
@@ -46,6 +46,10 @@ struct wlr_output_cursor { | |
struct wlr_texture *texture; | |
bool own_texture; | |
struct wl_list link; | |
+ struct timespec last_presentation; | |
+ bool deferred; | |
+ double deferred_x, deferred_y; | |
+ int max_latency; | |
}; | |
enum wlr_output_adaptive_sync_status { | |
@@ -144,6 +148,8 @@ struct wlr_output { | |
enum wlr_output_adaptive_sync_status adaptive_sync_status; | |
uint32_t render_format; | |
+ int max_cursor_latency; | |
+ | |
bool needs_frame; | |
// damage for cursors and fullscreen surface, in output-local coordinates | |
bool frame_pending; | |
@@ -556,6 +562,13 @@ bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor, | |
struct wlr_buffer *buffer, int32_t hotspot_x, int32_t hotspot_y); | |
bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, | |
double x, double y); | |
+/** | |
+ * Call any_expired() before you check needs_frame. | |
+ * call all_deferred() whenever a new frame is needed. | |
+ * */ | |
+void wlr_output_cursor_move_expired(struct wlr_output_cursor *cursor, struct timespec *now); | |
+void wlr_output_cursor_move_any_expired(struct wlr_output *output, struct timespec *now); | |
+void wlr_output_cursor_move_all_deferred(struct wlr_output *output, struct timespec *now); | |
void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor); | |
/** | |
diff --git a/types/output/cursor.c b/types/output/cursor.c | |
index 4d0cc19a..fd61cec3 100644 | |
--- a/types/output/cursor.c | |
+++ b/types/output/cursor.c | |
@@ -1,6 +1,8 @@ | |
+#define _POSIX_C_SOURCE 200809L | |
#include <assert.h> | |
#include <drm_fourcc.h> | |
#include <stdlib.h> | |
+#include <time.h> | |
#include <wlr/interfaces/wlr_output.h> | |
#include <wlr/render/swapchain.h> | |
#include <wlr/render/wlr_renderer.h> | |
@@ -8,6 +10,7 @@ | |
#include <wlr/types/wlr_matrix.h> | |
#include <wlr/util/log.h> | |
#include <wlr/util/region.h> | |
+#include <util/time.h> | |
#include "render/allocator/allocator.h" | |
#include "types/wlr_buffer.h" | |
#include "types/wlr_output.h" | |
@@ -461,15 +464,10 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor, | |
return true; | |
} | |
-bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, | |
- double x, double y) { | |
- // Scale coordinates for the output | |
- x *= cursor->output->scale; | |
- y *= cursor->output->scale; | |
- | |
- if (cursor->x == x && cursor->y == y) { | |
- return true; | |
- } | |
+static bool output_cursor_move(struct wlr_output_cursor *cursor, | |
+ double x, double y, struct timespec *now) { | |
+ cursor->last_presentation = *now; | |
+ cursor->deferred = false; | |
if (cursor->output->hardware_cursor != cursor) { | |
output_cursor_damage_whole(cursor); | |
@@ -494,6 +492,80 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, | |
return cursor->output->impl->move_cursor(cursor->output, (int)x, (int)y); | |
} | |
+static bool output_cursor_move_should_defer(struct wlr_output_cursor *cursor, | |
+ struct timespec *now) { | |
+ int max_latency; | |
+ | |
+ max_latency = cursor->max_latency; | |
+ | |
+ if (!max_latency) | |
+ max_latency = cursor->output->max_cursor_latency; | |
+ | |
+ if (!max_latency | |
+ || !cursor->output->refresh // avoid divide by zero | |
+ || cursor->output->adaptive_sync_status != WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) | |
+ return false; | |
+ | |
+ struct timespec delta; | |
+ int32_t vrr_min = NSEC_PER_SEC / 30; // edid? enforce 30fps minimum for now. | |
+ int32_t vrr_max = mhz_to_nsec(cursor->output->refresh); | |
+ // We want to move cursor *before* it's expired. | |
+ timespec_sub(&delta, now, &cursor->last_presentation); | |
+ if (delta.tv_sec | |
+ || delta.tv_nsec + vrr_max >= max_latency | |
+ || delta.tv_nsec >= vrr_min) | |
+ return false; | |
+ | |
+ return true; | |
+} | |
+ | |
+bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, | |
+ double x, double y) { | |
+ // Scale coordinates for the output | |
+ x *= cursor->output->scale; | |
+ y *= cursor->output->scale; | |
+ | |
+ if (cursor->x == x && cursor->y == y) { | |
+ return true; | |
+ } | |
+ | |
+ struct timespec now; | |
+ clock_gettime(CLOCK_MONOTONIC, &now); | |
+ | |
+ if (output_cursor_move_should_defer(cursor, &now)) { | |
+ cursor->deferred_x = x; | |
+ cursor->deferred_y = y; | |
+ cursor->deferred = true; | |
+ return true; | |
+ } | |
+ | |
+ return output_cursor_move(cursor, x, y, &now); | |
+} | |
+ | |
+void wlr_output_cursor_move_expired(struct wlr_output_cursor *cursor, struct timespec *now) { | |
+ if (cursor->deferred && !output_cursor_move_should_defer(cursor, now)) | |
+ output_cursor_move(cursor, cursor->deferred_x, cursor->deferred_y, now); | |
+} | |
+ | |
+void wlr_output_cursor_move_any_expired(struct wlr_output *output, struct timespec *now) { | |
+ struct wlr_output_cursor *cursor; | |
+ wl_list_for_each(cursor, &output->cursors, link) { | |
+ wlr_output_cursor_move_expired(cursor, now); | |
+ } | |
+} | |
+ | |
+void wlr_output_cursor_move_all_deferred(struct wlr_output *output, struct timespec *now) { | |
+ struct wlr_output_cursor *cursor; | |
+ wl_list_for_each(cursor, &output->cursors, link) { | |
+ if (cursor->deferred) | |
+ output_cursor_move(cursor, cursor->deferred_x, cursor->deferred_y, now); | |
+ else { | |
+ // Should be on wlr_output? | |
+ cursor->last_presentation = *now; | |
+ }; | |
+ } | |
+} | |
+ | |
struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) { | |
struct wlr_output_cursor *cursor = | |
calloc(1, sizeof(struct wlr_output_cursor)); | |
diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c | |
index a228bc9f..491b6eaa 100644 | |
--- a/types/wlr_cursor.c | |
+++ b/types/wlr_cursor.c | |
@@ -277,6 +277,7 @@ static void cursor_warp_unchecked(struct wlr_cursor *cur, | |
double output_x = lx, output_y = ly; | |
wlr_output_layout_output_coords(cur->state->layout, | |
output_cursor->output_cursor->output, &output_x, &output_y); | |
+ output_cursor->output_cursor->max_latency = cur->max_latency; | |
wlr_output_cursor_move(output_cursor->output_cursor, | |
output_x, output_y); | |
} | |
@@ -648,6 +649,11 @@ void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, | |
cursor_update_outputs(cur); | |
} | |
+void wlr_cursor_set_max_latency(struct wlr_cursor *cur, int max_latency) { | |
+ cur->max_latency = max_latency; | |
+ wlr_log(WLR_DEBUG, "setting max_latency %i", max_latency); | |
+} | |
+ | |
static void handle_pointer_motion(struct wl_listener *listener, void *data) { | |
struct wlr_pointer_motion_event *event = data; | |
struct wlr_cursor_device *device = | |
diff --git a/util/time.c b/util/time.c | |
index 78faac56..6a5fa010 100644 | |
--- a/util/time.c | |
+++ b/util/time.c | |
@@ -4,8 +4,6 @@ | |
#include "util/time.h" | |
-static const long NSEC_PER_SEC = 1000000000; | |
- | |
int64_t timespec_to_msec(const struct timespec *a) { | |
return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; | |
} | |
@@ -34,3 +32,7 @@ void timespec_sub(struct timespec *r, const struct timespec *a, | |
r->tv_nsec += NSEC_PER_SEC; | |
} | |
} | |
+ | |
+int32_t mhz_to_nsec(int32_t mhz) { | |
+ return 1000000000000LL / mhz; | |
+} |
Unfortunately I'm away from home for probably the next month. I won't be able to update them until I get back. Hopefully this can just get merged at some point in the not too distant future.
Just updated to swaywm/sway#7780 and I'm not seeing any issues any longer 🙂
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks a ton for this
Just a heads up
These patches are not compatible with latest git