From 72e2da24f9af2b1fa0edff4b5bec5c43bcc5e4cc Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 1 Feb 2023 13:57:15 +0100 Subject: [PATCH] backend-vnc: render bypass support If there is an opaque full-screen view with a compatible SHM client buffer left after peeling off the client-side cursor view, bypass the renderer and let Neat VNC read from the client buffer directly. Signed-off-by: Philipp Zabel --- libweston/backend-vnc/vnc.c | 87 +++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/libweston/backend-vnc/vnc.c b/libweston/backend-vnc/vnc.c index 3ba81fbf3..4566a8ca8 100644 --- a/libweston/backend-vnc/vnc.c +++ b/libweston/backend-vnc/vnc.c @@ -83,6 +83,7 @@ struct vnc_backend { struct vnc_output { struct weston_output base; struct weston_plane cursor_plane; + struct weston_plane scanout_plane; struct weston_surface *cursor_surface; struct vnc_backend *backend; struct wl_event_source *finish_frame_timer; @@ -742,6 +743,7 @@ vnc_output_enable(struct weston_output *base) backend->output = output; weston_plane_init(&output->cursor_plane, backend->compositor); + weston_plane_init(&output->scanout_plane, backend->compositor); switch (renderer->type) { case WESTON_RENDERER_PIXMAN: { @@ -823,6 +825,7 @@ vnc_output_disable(struct weston_output *base) wl_event_source_remove(output->finish_frame_timer); backend->output = NULL; + weston_plane_release(&output->scanout_plane); weston_plane_release(&output->cursor_plane); return 0; @@ -990,10 +993,44 @@ vnc_clients_support_cursor(struct vnc_output *output) return true; } +static struct nvnc_fb * +vnc_fb_get_from_view(struct weston_view *view) +{ + struct weston_buffer *buffer = view->surface->buffer_ref.buffer; + int32_t stride; + + if (view->alpha != 1.0f) + return NULL; + + if (!weston_view_is_opaque(view, &view->transform.boundingbox)) + return NULL; + + if (!buffer) + return NULL; + + if (buffer->type != WESTON_BUFFER_SHM || !buffer->shm_buffer) + return NULL; + + if (buffer->pixel_format->format != DRM_FORMAT_ARGB8888 && + buffer->pixel_format->format != DRM_FORMAT_XRGB8888) + return NULL; + + stride = wl_shm_buffer_get_stride(buffer->shm_buffer); + if (stride % 4) + return NULL; + + return nvnc_fb_from_buffer(wl_shm_buffer_get_data(buffer->shm_buffer), + buffer->width, buffer->height, + DRM_FORMAT_XRGB8888, stride / 4); +} + static void vnc_output_assign_planes(struct weston_output *base) { + struct weston_plane *primary = &base->compositor->primary_plane; struct vnc_output *output = to_vnc_output(base); + struct weston_paint_node *pnode; + bool topmost = true; assert(output); @@ -1003,6 +1040,56 @@ vnc_output_assign_planes(struct weston_output *base) /* Update VNC cursor and move cursor view to plane */ if (vnc_clients_support_cursor(output)) vnc_output_update_cursor(output); + + wl_list_for_each(pnode, &output->base.paint_node_z_order_list, z_order_link) { + struct weston_view *view = pnode->view; + struct nvnc_fb *fb = NULL; + + /* If this view doesn't touch our output at all, there's no + * reason to do anything with it. */ + /* TODO: turn this into assert once z_order_list is pruned. */ + if (!(view->output_mask & (1u << output->base.id))) + continue; + + /* Skip cursor view */ + if (view->plane == &output->cursor_plane) + continue; + + if (topmost && + pixman_region32_equal(&view->transform.boundingbox, + &output->base.region) && + (fb = vnc_fb_get_from_view(view))) { + struct weston_buffer *buffer; + pixman_region32_t local_damage; + pixman_region16_t nvnc_damage; + + weston_view_move_to_plane(view, &output->scanout_plane); + + /* Convert to local coordinates */ + pixman_region32_init(&local_damage); + weston_region_global_to_output(&local_damage, &output->base, + &output->base.region); + + /* Convert to 16-bit */ + pixman_region_init(&nvnc_damage); + vnc_region32_to_region16(&nvnc_damage, &local_damage); + + buffer = view->surface->buffer_ref.buffer; + wl_shm_buffer_begin_access(buffer->shm_buffer); + nvnc_display_feed_buffer(output->display, fb, + &nvnc_damage); + wl_shm_buffer_end_access(buffer->shm_buffer); + + pixman_region32_fini(&local_damage); + pixman_region_fini(&nvnc_damage); + + nvnc_fb_unref(fb); + } else { + weston_view_move_to_plane(view, primary); + } + + topmost = false; + } } static struct weston_mode *