vnc: Fix cursor updates

Now that overlapping outputs are a thing, we have a problem with vnc
cursors.

The surface->damage used to update the vnc cursor might actually be
flushed by a previous output's repaint cycle, leading to a missing cursor
update to the vnc client.

Instead we should use the damage accumulated on the cursor plane to choose
when to update the cursor. This damage is in output coordinates, so let's
be lazy and just use the presence of damage as an indicator that the
cursor needs an update.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
Derek Foreman 2023-11-03 09:59:18 -05:00
parent 0def955a48
commit bbaba601c8
3 changed files with 54 additions and 27 deletions

View File

@ -534,14 +534,57 @@ vnc_output_update_cursor(struct vnc_output *output)
struct vnc_backend *backend = output->backend; struct vnc_backend *backend = output->backend;
struct weston_pointer *pointer; struct weston_pointer *pointer;
struct weston_paint_node *pointer_pnode = NULL; struct weston_paint_node *pointer_pnode = NULL;
struct weston_view *view; bool update_cursor;
pixman_region32_t damage;
struct weston_buffer *buffer; struct weston_buffer *buffer;
struct weston_surface *cursor_surface;
struct nvnc_fb *fb; struct nvnc_fb *fb;
int32_t stride; int32_t stride;
uint32_t format;
uint8_t *src, *dst; uint8_t *src, *dst;
int i; int i;
pointer = vnc_output_get_pointer(output, &pointer_pnode);
pixman_region32_init(&damage);
weston_output_flush_damage_for_plane(&output->base, &output->cursor_plane, &damage);
update_cursor = pixman_region32_not_empty(&damage);
pixman_region32_fini(&damage);
if (!update_cursor)
return;
cursor_surface = output->cursor_surface;
buffer = cursor_surface->buffer_ref.buffer;
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
fb = nvnc_fb_new(buffer->width, buffer->height, DRM_FORMAT_ARGB8888,
buffer->width);
assert(fb);
src = wl_shm_buffer_get_data(buffer->shm_buffer);
dst = nvnc_fb_get_addr(fb);
wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < buffer->height; i++)
memcpy(dst + i * 4 * buffer->width, src + i * stride,
4 * buffer->width);
wl_shm_buffer_end_access(buffer->shm_buffer);
nvnc_set_cursor(backend->server, fb, buffer->width, buffer->height,
pointer->hotspot.c.x, pointer->hotspot.c.y, true);
nvnc_fb_unref(fb);
}
static void
vnc_output_assign_cursor_plane(struct vnc_output *output)
{
struct weston_pointer *pointer;
struct weston_paint_node *pointer_pnode = NULL;
struct weston_view *view;
struct weston_buffer *buffer;
uint32_t format;
pointer = vnc_output_get_pointer(output, &pointer_pnode); pointer = vnc_output_get_pointer(output, &pointer_pnode);
if (!pointer) if (!pointer)
return; return;
@ -562,30 +605,7 @@ vnc_output_update_cursor(struct vnc_output *output)
weston_paint_node_move_to_plane(pointer_pnode, &output->cursor_plane); weston_paint_node_move_to_plane(pointer_pnode, &output->cursor_plane);
if (view->surface == output->cursor_surface &&
!pixman_region32_not_empty(&view->surface->damage))
return;
output->cursor_surface = view->surface; output->cursor_surface = view->surface;
stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
fb = nvnc_fb_new(buffer->width, buffer->height, DRM_FORMAT_ARGB8888,
buffer->width);
assert(fb);
src = wl_shm_buffer_get_data(buffer->shm_buffer);
dst = nvnc_fb_get_addr(fb);
wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < buffer->height; i++)
memcpy(dst + i * 4 * buffer->width, src + i * stride,
4 * buffer->width);
wl_shm_buffer_end_access(buffer->shm_buffer);
nvnc_set_cursor(backend->server, fb, buffer->width, buffer->height,
pointer->hotspot.c.x, pointer->hotspot.c.y, true);
nvnc_fb_unref(fb);
} }
static void static void
@ -994,6 +1014,8 @@ vnc_output_repaint(struct weston_output *base, pixman_region32_t *damage)
if (wl_list_empty(&output->peers)) if (wl_list_empty(&output->peers))
weston_output_power_off(base); weston_output_power_off(base);
vnc_output_update_cursor(output);
if (pixman_region32_not_empty(damage)) { if (pixman_region32_not_empty(damage)) {
vnc_update_buffer(output->display, damage); vnc_update_buffer(output->display, damage);
} }
@ -1036,7 +1058,7 @@ vnc_output_assign_planes(struct weston_output *base)
/* Update VNC cursor and move cursor view to plane */ /* Update VNC cursor and move cursor view to plane */
if (vnc_clients_support_cursor(output)) if (vnc_clients_support_cursor(output))
vnc_output_update_cursor(output); vnc_output_assign_cursor_plane(output);
} }
static int static int

View File

@ -322,4 +322,9 @@ void
notify_tablet_tool_frame(struct weston_tablet_tool *tool, notify_tablet_tool_frame(struct weston_tablet_tool *tool,
const struct timespec *time); const struct timespec *time);
bool
weston_output_flush_damage_for_plane(struct weston_output *output,
struct weston_plane *plane,
pixman_region32_t *damage);
#endif #endif

View File

@ -3364,7 +3364,7 @@ weston_output_take_feedback_list(struct weston_output *output,
wl_list_init(&surface->feedback_list); wl_list_init(&surface->feedback_list);
} }
static bool WL_EXPORT bool
weston_output_flush_damage_for_plane(struct weston_output *output, weston_output_flush_damage_for_plane(struct weston_output *output,
struct weston_plane *plane, struct weston_plane *plane,
pixman_region32_t *damage) pixman_region32_t *damage)