output: limit rate of hardware cursor texture change

A client that generates lots of cursor image changes could cause a
high render load, or deplete the output's cursor swapchain on some
backends.

Limit to two renders per frame, and catch up after output commit if
necessary.
This commit is contained in:
Félix Poisot 2026-03-21 08:45:48 +00:00
parent fd870f6d27
commit c5641f6de5
4 changed files with 22 additions and 1 deletions

View file

@ -14,6 +14,11 @@
#include "types/wlr_buffer.h"
#include "types/wlr_output.h"
// Maximum of hardware cursor renders per frame.
// Many clients don't regroup the buffer commit and the hotspot change in a
// single message : typical burst of 2 must still be processed without delay
#define MAX_UPLOADS_PER_FRAME 2
static bool output_set_hardware_cursor(struct wlr_output *output,
struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
if (!output->impl->set_cursor) {
@ -55,6 +60,7 @@ static void output_disable_hardware_cursor(struct wlr_output *output) {
output_set_hardware_cursor(output, NULL, 0, 0);
output_cursor_damage_whole(output->hardware_cursor);
output->hardware_cursor = NULL;
output->cursor_pending_upload = NULL;
}
void wlr_output_lock_software_cursors(struct wlr_output *output, bool lock) {
@ -288,7 +294,7 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
return buffer;
}
static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
struct wlr_output *output = cursor->output;
if (!output->impl->set_cursor || output->software_cursor_locks > 0) {
@ -297,6 +303,11 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
struct wlr_texture *texture = cursor->texture;
if (texture != NULL && output->cursor_uploaded_this_frame >= MAX_UPLOADS_PER_FRAME) {
output->cursor_pending_upload = cursor;
return true;
}
// If the cursor was hidden or was a software cursor, the hardware
// cursor position is outdated
output_move_hardware_cursor(cursor->output, (int)cursor->x, (int)cursor->y);
@ -308,6 +319,7 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
wlr_log(WLR_DEBUG, "Failed to render cursor buffer");
return false;
}
output->cursor_uploaded_this_frame++;
}
struct wlr_box hotspot = {

View file

@ -841,6 +841,12 @@ bool wlr_output_commit_state(struct wlr_output *output,
wlr_buffer_unlock(pending.buffer);
}
output->cursor_uploaded_this_frame = 0;
if (output->cursor_pending_upload) {
output_cursor_attempt_hardware(output->cursor_pending_upload);
output->cursor_pending_upload = NULL;
}
return true;
}