linuxOS_AP06/buildroot/package/weston/0074-vnc-Improve-performance-with-gl-renderer.patch
2025-06-03 12:28:32 +08:00

656 lines
19 KiB
Diff

From 1bcbf3013905971f68e14143200df14c418fdea6 Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Mon, 25 Dec 2023 16:58:31 +0800
Subject: [PATCH 74/95] vnc: Improve performance with gl-renderer
Major changes:
1/ Use GBM instead of FBO
2/ Support increasing buffers
Tested on RK3588 EVB with:
1/ Run "weston -B vnc" or "weston -B drm,vnc"
2/ Launch vncviewer on remote PC
3/ Run "weston-simple-egl -f"
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
libweston/backend-vnc/meson.build | 7 +
libweston/backend-vnc/vnc.c | 321 +++++++++++++++----
libweston/renderer-gl/gl-renderer-internal.h | 2 +
libweston/renderer-gl/gl-renderer.c | 27 +-
libweston/renderer-gl/gl-renderer.h | 2 +
5 files changed, 293 insertions(+), 66 deletions(-)
diff --git a/libweston/backend-vnc/meson.build b/libweston/backend-vnc/meson.build
index 39b15cf..53e5037 100644
--- a/libweston/backend-vnc/meson.build
+++ b/libweston/backend-vnc/meson.build
@@ -13,12 +13,19 @@ if not dep_aml.found()
error('VNC backend requires libaml which was not found. Or, you can use \'-Dbackend-vnc=false\'.')
endif
+dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
+if not dep_gbm.found()
+ error('VNC backend requires gbm which was not found. Or, you can use \'-Dbackend-vnc=false\'.')
+endif
+
deps_vnc = [
dep_libweston_private,
dep_neatvnc,
dep_aml,
dep_libdrm_headers,
+ dep_gbm,
]
+
plugin_vnc = shared_library(
'vnc-backend',
[ 'vnc.c' ],
diff --git a/libweston/backend-vnc/vnc.c b/libweston/backend-vnc/vnc.c
index 928e484..574b699 100644
--- a/libweston/backend-vnc/vnc.c
+++ b/libweston/backend-vnc/vnc.c
@@ -47,6 +47,11 @@
#include <neatvnc.h>
#include <drm_fourcc.h>
+#include <gbm.h>
+
+#include <fcntl.h>
+#include <xf86drm.h>
+
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "shared/timespec-util.h"
@@ -60,6 +65,7 @@
#include "shared/weston-egl-ext.h"
#define DEFAULT_AXIS_STEP_DISTANCE 10
+#define VNC_MAX_BUFFERS 16
struct vnc_output;
@@ -79,6 +85,9 @@ struct vnc_backend {
const struct pixel_format_info **formats;
unsigned int formats_count;
+
+ int drm_fd;
+ struct gbm_device *gbm;
};
struct vnc_output {
@@ -94,6 +103,12 @@ struct vnc_output {
struct wl_list peers;
bool resizeable;
+
+ struct gbm_surface *gbm_surfaces[VNC_MAX_BUFFERS];
+ unsigned int num_surfaces;
+
+ struct weston_renderbuffer *renderbuffer[VNC_MAX_BUFFERS];
+ int next_buffer;
};
struct vnc_peer {
@@ -109,6 +124,11 @@ struct vnc_head {
struct weston_head base;
};
+struct vnc_gl_data {
+ struct gbm_surface *gbm_surface;
+ struct gbm_bo *bo;
+};
+
static void
vnc_output_destroy(struct weston_output *base);
@@ -673,52 +693,35 @@ vnc_log_damage(struct vnc_backend *backend, pixman_region32_t *buffer_damage,
weston_log_scope_printf(backend->debug, "\n\n");
}
-static void
-vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage)
+static struct nvnc_fb *
+vnc_output_render_pixman(struct vnc_output *output, struct pixman_region32 *damage)
{
- struct nvnc *server = nvnc_display_get_server(display);
- struct vnc_backend *backend = nvnc_get_userdata(server);
- struct vnc_output *output = backend->output;
struct weston_compositor *ec = output->base.compositor;
struct weston_renderbuffer *renderbuffer;
- pixman_region32_t local_damage;
- pixman_region16_t nvnc_damage;
+ struct vnc_backend *backend = output->backend;
struct nvnc_fb *fb;
fb = nvnc_fb_pool_acquire(output->fb_pool);
- assert(fb);
+ if (!fb)
+ return NULL;
renderbuffer = nvnc_get_userdata(fb);
if (!renderbuffer) {
+ const struct pixman_renderer_interface *pixman;
const struct pixel_format_info *pfmt;
pfmt = pixel_format_get_info(DRM_FORMAT_XRGB8888);
- switch (ec->renderer->type) {
- case WESTON_RENDERER_PIXMAN: {
- const struct pixman_renderer_interface *pixman;
+ pixman = ec->renderer->pixman;
- pixman = ec->renderer->pixman;
-
- renderbuffer =
- pixman->create_image_from_ptr(&output->base, pfmt,
- output->base.width,
- output->base.height,
- nvnc_fb_get_addr(fb),
- output->base.width * 4);
- break;
- }
- case WESTON_RENDERER_GL: {
- renderbuffer =
- ec->renderer->gl->create_fbo(&output->base, pfmt,
- output->base.width,
- output->base.height,
- nvnc_fb_get_addr(fb));
- break;
- }
- default:
- unreachable("cannot have auto renderer at runtime");
- }
+ renderbuffer =
+ pixman->create_image_from_ptr(&output->base, pfmt,
+ output->base.width,
+ output->base.height,
+ nvnc_fb_get_addr(fb),
+ output->base.width * 4);
+ if (!renderbuffer)
+ return NULL;
/* This is a new buffer, so the whole surface is damaged. */
pixman_region32_copy(&renderbuffer->damage,
@@ -732,6 +735,85 @@ vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage)
ec->renderer->repaint_output(&output->base, damage, renderbuffer);
+ return fb;
+}
+
+static void
+vnc_gl_data_cleanup(void* userdata)
+{
+ struct vnc_gl_data *data = userdata;
+
+ gbm_surface_release_buffer(data->gbm_surface, data->bo);
+ free(data);
+}
+
+static struct nvnc_fb *
+vnc_output_render_gl(struct vnc_output *output, struct pixman_region32 *damage)
+{
+ struct weston_compositor *ec = output->base.compositor;
+ struct weston_renderbuffer *renderbuffer;
+ struct vnc_backend *backend = output->backend;
+ struct vnc_gl_data *data;
+ struct nvnc_fb *fb;
+
+ data = zalloc(sizeof *data);
+ if (!data)
+ return NULL;
+
+ data->gbm_surface = output->gbm_surfaces[output->next_buffer];
+ renderbuffer = output->renderbuffer[output->next_buffer];
+ output->next_buffer = (output->next_buffer + 1) % output->num_surfaces;
+
+ vnc_log_damage(backend, &renderbuffer->damage, damage);
+
+ ec->renderer->repaint_output(&output->base, damage, renderbuffer);
+
+ data->bo = gbm_surface_lock_front_buffer(data->gbm_surface);
+ if (!data->bo) {
+ weston_log("failed to lock front buffer: %s\n",
+ strerror(errno));
+ free(data);
+ return NULL;
+ }
+
+ fb = nvnc_fb_from_gbm_bo(data->bo);
+ if (!fb) {
+ weston_log("failed to import gbm bo\n");
+ free(data);
+ return NULL;
+ }
+
+ nvnc_set_userdata(fb, data, (nvnc_cleanup_fn)vnc_gl_data_cleanup);
+
+ return fb;
+}
+
+static void
+vnc_output_render(struct vnc_output *output, struct pixman_region32 *damage)
+{
+ struct weston_compositor *ec = output->base.compositor;
+ pixman_region32_t local_damage;
+ pixman_region16_t nvnc_damage;
+ struct nvnc_fb *fb;
+
+ switch (ec->renderer->type) {
+ case WESTON_RENDERER_PIXMAN: {
+ fb = vnc_output_render_pixman(output, damage);
+ break;
+ }
+ case WESTON_RENDERER_GL: {
+ fb = vnc_output_render_gl(output, damage);
+ break;
+ }
+ default:
+ unreachable("cannot have auto renderer at runtime");
+ }
+
+ if (!fb) {
+ weston_log("failed to render vnc\n");
+ return;
+ }
+
/* Convert to local coordinates */
pixman_region32_init(&local_damage);
weston_region_global_to_output(&local_damage, &output->base, damage);
@@ -791,6 +873,88 @@ finish_frame_handler(void *data)
return 1;
}
+static void
+vnc_output_fini_egl(struct vnc_output *output)
+{
+ struct weston_renderer *renderer = output->base.compositor->renderer;
+ unsigned int i;
+
+ renderer->gl->output_destroy(&output->base);
+
+ for (i = 0; i < output->num_surfaces; i++) {
+ if (output->renderbuffer[i])
+ weston_renderbuffer_unref(output->renderbuffer[i]);
+ output->renderbuffer[i] = NULL;
+ }
+ for (i = 0; i < output->num_surfaces; i++) {
+ if (output->gbm_surfaces[i])
+ gbm_surface_destroy(output->gbm_surfaces[i]);
+ output->gbm_surfaces[i] = NULL;
+ }
+}
+
+static int
+vnc_output_init_egl(struct vnc_output *output, struct vnc_backend *b)
+{
+ const struct weston_renderer *renderer = b->compositor->renderer;
+ struct weston_mode *mode = output->base.current_mode;
+ const struct gl_renderer_interface *gl = renderer->gl;
+ const struct gl_renderer_display_options *display_options =
+ gl->get_display_options(b->compositor);
+ struct gl_renderer_output_options options = {
+ .formats = &b->formats[0],
+ .formats_count = b->formats_count,
+ .area.x = 0,
+ .area.y = 0,
+ .area.width = mode->width,
+ .area.height = mode->height,
+ .fb_size.width = mode->width,
+ .fb_size.height = mode->height,
+ .window_for_legacy = NULL,
+ .window_for_platform = NULL,
+ };
+ uint32_t i;
+
+ if (display_options->egl_platform != EGL_PLATFORM_GBM_KHR ||
+ !display_options->egl_native_display)
+ return -1;
+
+ for (i = 0; i < output->num_surfaces; i++) {
+ struct gbm_device *gbm = display_options->egl_native_display;
+ output->gbm_surfaces[i] =
+ gbm_surface_create(gbm, mode->width, mode->height,
+ b->formats[0]->format,
+ GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING);
+ if (!output->gbm_surfaces[i]) {
+ weston_log("failed to create gbm surface\n");
+ goto err;
+ }
+ }
+
+ if (gl->output_window_create(&output->base, &options) < 0) {
+ weston_log("failed to create gl renderer output state\n");
+ goto err;
+ }
+
+ for (i = 0; i < output->num_surfaces; i++) {
+ options.window_for_legacy =
+ (EGLNativeWindowType) output->gbm_surfaces[i];
+ options.window_for_platform = output->gbm_surfaces[i];
+
+ output->renderbuffer[i] =
+ gl->create_buffer(&output->base, &options);
+ if (!output->renderbuffer[i]) {
+ weston_log("failed to create window surface\n");
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ vnc_output_fini_egl(output);
+ return -1;
+}
+
static int
vnc_output_enable(struct weston_output *base)
{
@@ -817,20 +981,15 @@ vnc_output_enable(struct weston_output *base)
};
if (renderer->pixman->output_create(&output->base, &options) < 0)
return -1;
+
+ output->fb_pool = nvnc_fb_pool_new(output->base.width,
+ output->base.height,
+ backend->formats[0]->format,
+ output->base.width);
break;
}
case WESTON_RENDERER_GL: {
- const struct gl_renderer_fbo_options options = {
- .area = {
- .width = output->base.width,
- .height = output->base.height,
- },
- .fb_size = {
- .width = output->base.width,
- .height = output->base.height,
- },
- };
- if (renderer->gl->output_fbo_create(&output->base, &options) < 0)
+ if (vnc_output_init_egl(output, backend) < 0)
return -1;
break;
}
@@ -843,11 +1002,6 @@ vnc_output_enable(struct weston_output *base)
finish_frame_handler,
output);
- output->fb_pool = nvnc_fb_pool_new(output->base.width,
- output->base.height,
- backend->formats[0]->format,
- output->base.width);
-
output->display = nvnc_display_new(0, 0);
nvnc_add_display(backend->server, output->display);
@@ -871,14 +1025,14 @@ vnc_output_disable(struct weston_output *base)
nvnc_remove_display(backend->server, output->display);
nvnc_display_unref(output->display);
- nvnc_fb_pool_unref(output->fb_pool);
switch (renderer->type) {
case WESTON_RENDERER_PIXMAN:
renderer->pixman->output_destroy(&output->base);
+ nvnc_fb_pool_unref(output->fb_pool);
break;
case WESTON_RENDERER_GL:
- renderer->gl->output_destroy(&output->base);
+ vnc_output_fini_egl(output);
break;
default:
unreachable("cannot have auto renderer at runtime");
@@ -911,6 +1065,8 @@ vnc_create_output(struct weston_backend *backend, const char *name)
{
struct vnc_backend *b = container_of(backend, struct vnc_backend, base);
struct vnc_output *output;
+ const char *env;
+ int num_buffers = 0;
output = zalloc(sizeof *output);
if (output == NULL)
@@ -918,6 +1074,14 @@ vnc_create_output(struct weston_backend *backend, const char *name)
weston_output_init(&output->base, b->compositor, name);
+ env = getenv("WESTON_VNC_MIN_BUFFERS");
+ if (env)
+ num_buffers = atoi(env);
+
+ num_buffers = MIN(MAX(num_buffers, 2), VNC_MAX_BUFFERS);
+ output->num_surfaces = (num_buffers + 1) / 2;
+ weston_log("%s using at least %d buffers\n", name, num_buffers);
+
output->base.destroy = vnc_output_destroy;
output->base.disable = vnc_output_disable;
output->base.enable = vnc_output_enable;
@@ -953,6 +1117,11 @@ vnc_destroy(struct weston_backend *base)
if (backend->debug)
weston_log_scope_destroy(backend->debug);
+ if (backend->gbm) {
+ gbm_device_destroy(backend->gbm);
+ close(backend->drm_fd);
+ }
+
free(backend);
}
@@ -1015,7 +1184,7 @@ vnc_output_repaint(struct weston_output *base)
weston_output_flush_damage_for_primary_plane(base, &damage);
if (pixman_region32_not_empty(&damage)) {
- vnc_update_buffer(output->display, &damage);
+ vnc_output_render(output, &damage);
}
pixman_region32_fini(&damage);
@@ -1064,7 +1233,9 @@ vnc_output_assign_planes(struct weston_output *base)
static int
vnc_switch_mode(struct weston_output *base, struct weston_mode *target_mode)
{
+ struct weston_renderer *renderer = base->compositor->renderer;
struct vnc_output *output = to_vnc_output(base);
+ struct vnc_backend *backend = output->backend;
struct weston_size fb_size;
assert(output);
@@ -1076,9 +1247,23 @@ vnc_switch_mode(struct weston_output *base, struct weston_mode *target_mode)
weston_renderer_resize_output(base, &fb_size, NULL);
- nvnc_fb_pool_resize(output->fb_pool, target_mode->width,
- target_mode->height, DRM_FORMAT_XRGB8888,
- target_mode->width);
+ switch (renderer->type) {
+ case WESTON_RENDERER_PIXMAN:
+ nvnc_fb_pool_resize(output->fb_pool, target_mode->width,
+ target_mode->height, DRM_FORMAT_XRGB8888,
+ target_mode->width);
+ break;
+ case WESTON_RENDERER_GL:
+ vnc_output_fini_egl(output);
+ if (vnc_output_init_egl(output, backend) < 0) {
+ weston_log("failed to init output egl state with "
+ "new mode");
+ return -1;
+ }
+ break;
+ default:
+ unreachable("cannot have auto renderer at runtime");
+ }
return 0;
}
@@ -1165,19 +1350,36 @@ vnc_backend_create(struct weston_compositor *compositor,
backend->formats_count);
if (!compositor->renderer) {
switch (config->renderer) {
- case WESTON_RENDERER_AUTO:
case WESTON_RENDERER_PIXMAN:
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_PIXMAN,
NULL) < 0)
goto err_compositor;
break;
+ case WESTON_RENDERER_AUTO:
case WESTON_RENDERER_GL: {
- const struct gl_renderer_display_options options = {
- .egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
+ struct gl_renderer_display_options options = {
+ .egl_platform = EGL_PLATFORM_GBM_KHR,
+ .egl_surface_type = EGL_WINDOW_BIT,
.formats = backend->formats,
.formats_count = backend->formats_count,
};
+
+ backend->drm_fd = drmOpen("rockchip", NULL);
+ if (backend->drm_fd < 0)
+ backend->drm_fd = open("/dev/dri/card0",
+ O_RDWR | O_CLOEXEC);
+ if (backend->drm_fd < 0)
+ goto err_compositor;
+
+ backend->gbm = gbm_create_device(backend->drm_fd);
+ if (!backend->gbm) {
+ close(backend->drm_fd);
+ goto err_compositor;
+ }
+
+ options.egl_native_display = backend->gbm;
+
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base) < 0)
@@ -1303,6 +1505,11 @@ err_output:
wl_list_for_each_safe(base, next, &compositor->head_list, compositor_link)
vnc_head_destroy(base);
err_compositor:
+ if (backend->gbm) {
+ gbm_device_destroy(backend->gbm);
+ close(backend->drm_fd);
+ }
+
wl_list_remove(&backend->base.link);
free(backend);
return NULL;
diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h
index 49c490a..756a180 100644
--- a/libweston/renderer-gl/gl-renderer-internal.h
+++ b/libweston/renderer-gl/gl-renderer-internal.h
@@ -311,6 +311,8 @@ struct gl_renderer {
int drm_fd;
struct gbm_device *gbm;
+
+ struct gl_renderer_display_options options;
};
static inline struct gl_renderer *
diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c
index e1704ac..7ddf80e 100644
--- a/libweston/renderer-gl/gl-renderer.c
+++ b/libweston/renderer-gl/gl-renderer.c
@@ -732,6 +732,13 @@ gl_renderer_create_fbo(struct weston_output *output,
return &renderbuffer->base;
}
+static const struct gl_renderer_display_options *
+gl_renderer_get_display_options(struct weston_compositor *ec)
+{
+ struct gl_renderer *gr = get_renderer(ec);
+ return &gr->options;
+}
+
static bool
gl_renderer_do_read_pixels(struct gl_renderer *gr,
struct gl_output_state *go,
@@ -4479,8 +4486,6 @@ gl_renderer_display_create(struct weston_compositor *ec,
const struct gl_renderer_display_options *options)
{
struct gl_renderer *gr;
- EGLint egl_surface_type = options->egl_surface_type;
- void *egl_native_display = options->egl_native_display;
int ret;
gr = zalloc(sizeof *gr);
@@ -4491,6 +4496,9 @@ gl_renderer_display_create(struct weston_compositor *ec,
wl_list_init(&gr->shader_list);
gr->platform = options->egl_platform;
+ gr->options = *options;
+ options = &gr->options;
+
gr->renderer_scope = weston_compositor_add_log_scope(ec, "gl-renderer",
"GL-renderer verbose messages\n", NULL, NULL, gr);
if (!gr->renderer_scope)
@@ -4505,10 +4513,10 @@ gl_renderer_display_create(struct weston_compositor *ec,
/* HACK: Fixup options for GBM platform */
if (gr->platform == EGL_PLATFORM_GBM_KHR) {
- if (!egl_surface_type)
- egl_surface_type = EGL_WINDOW_BIT;
+ if (!options->egl_surface_type)
+ gr->options.egl_surface_type = EGL_WINDOW_BIT;
- if (!egl_native_display) {
+ if (!options->egl_native_display) {
gr->drm_fd = drmOpen("rockchip", NULL);
if (gr->drm_fd < 0)
gr->drm_fd = open("/dev/dri/card0",
@@ -4522,7 +4530,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
goto fail;
}
- egl_native_display = gr->gbm;
+ gr->options.egl_native_display = gr->gbm;
}
}
@@ -4537,7 +4545,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
gr->base.buffer_init = gl_renderer_buffer_init;
gr->base.type = WESTON_RENDERER_GL;
- if (gl_renderer_setup_egl_display(gr, egl_native_display) < 0)
+ if (gl_renderer_setup_egl_display(gr, options->egl_native_display) < 0)
goto fail;
gr->allocator = gl_renderer_allocator_create(gr, options);
@@ -4558,11 +4566,11 @@ gl_renderer_display_create(struct weston_compositor *ec,
if (!gr->has_configless_context) {
if (!gr->has_surfaceless_context)
- egl_surface_type |= EGL_PBUFFER_BIT;
+ gr->options.egl_surface_type |= EGL_PBUFFER_BIT;
gr->egl_config =
gl_renderer_get_egl_config(gr,
- egl_surface_type,
+ options->egl_surface_type,
options->formats,
options->formats_count);
if (gr->egl_config == EGL_NO_CONFIG_KHR) {
@@ -4957,4 +4965,5 @@ WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
.output_set_border = gl_renderer_output_set_border,
.create_fence_fd = gl_renderer_create_fence_fd,
.create_fbo = gl_renderer_create_fbo,
+ .get_display_options = gl_renderer_get_display_options,
};
diff --git a/libweston/renderer-gl/gl-renderer.h b/libweston/renderer-gl/gl-renderer.h
index 7e7d1bc..8bc4ace 100644
--- a/libweston/renderer-gl/gl-renderer.h
+++ b/libweston/renderer-gl/gl-renderer.h
@@ -237,4 +237,6 @@ struct gl_renderer_interface {
const struct pixel_format_info *format,
int width, int height,
uint32_t *pixels);
+
+ const struct gl_renderer_display_options *(*get_display_options)(struct weston_compositor *ec);
};
--
2.20.1