Lines Matching +full:display +full:- +full:backend

4 Subject: [PATCH 83/93] backend-vnc: add VNC support using Neat VNC library
8 loop library. The backend makes use of AML's integrated epoll backend
14 Co-authored-by: Philipp Zabel <p.zabel@pengutronix.de>
15 Co-authored-by: Rouven Czerwinski <r.czerwinski@pengutronix.de>
16 Signed-off-by: Stefan Agner <stefan@agner.ch>
18 - use new (as of 0.5.0) Neat VNC buffer API, with a buffer pool]
19 Signed-off-by: Rouven Czerwinski <r.czerwinski@pengutronix.de>
21 - transform repaint damage to output coordinates
22 - transform pointer coordinates into global space
23 - check that outputs and heads are in fact ours, see aab722bb1785..060ef82d9360
24 - track damage across multiple frame buffers
25 - choose pixel format by drm_fourcc, see 8b6c3fe0ad4b
26 - enable ctrl and alt modifiers
27 - fix frame timing to achieve a constant repaint rate
28 - pass initial size explicitly, see f4559b076008
29 - use resize_output with pixman-renderer, see 55d08f9634e8..84b5d0eb4bee
30 - allow configuring the refresh rate]
31 Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
33 Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
34 ---
36 include/libweston/backend-vnc.h | 71 ++
39 libweston/backend-vnc/meson.build | 32 +
40 libweston/backend-vnc/vnc.c | 1032 +++++++++++++++++++++++++++++
45 create mode 100644 include/libweston/backend-vnc.h
46 create mode 100644 libweston/backend-vnc/meson.build
47 create mode 100644 libweston/backend-vnc/vnc.c
49 diff --git a/compositor/main.c b/compositor/main.c
51 --- a/compositor/main.c
53 @@ -61,6 +61,7 @@
54 #include <libweston/backend-drm.h>
55 #include <libweston/backend-headless.h>
56 #include <libweston/backend-rdp.h>
57 +#include <libweston/backend-vnc.h>
58 #include <libweston/backend-x11.h>
59 #include <libweston/backend-wayland.h>
60 #include <libweston/windowed-output-api.h>
61 @@ -653,6 +654,9 @@ usage(int error_code)
63 "\t\t\t\trdp-backend.so\n"
66 + "\t\t\t\tvnc-backend.so\n"
69 "\t\t\t\twayland-backend.so\n"
71 @@ -720,6 +724,15 @@ usage(int error_code)
77 + "Options for vnc-backend.so:\n\n"
78 + " --width=WIDTH\t\tWidth of desktop\n"
79 + " --height=HEIGHT\tHeight of desktop\n"
80 + " --port=PORT\t\tThe port to listen on\n"
86 "Options for wayland-backend.so:\n\n"
87 @@ -3177,6 +3190,90 @@ load_rdp_backend(struct weston_compositor *c,
94 + struct wet_compositor *compositor = to_wet_compositor(output->compositor);
95 + struct wet_output_config *parsed_options = compositor->parsed_options;
96 + const struct weston_vnc_output_api *api = weston_vnc_output_get_api(output->compositor);
104 + return -1;
107 + if (parsed_options->width)
108 + width = parsed_options->width;
110 + if (parsed_options->height)
111 + height = parsed_options->height;
116 + if (api->output_set_size(output, width, height) < 0) {
118 + output->name);
119 + return -1;
130 + config->base.struct_version = WESTON_VNC_BACKEND_CONFIG_VERSION;
131 + config->base.struct_size = sizeof(struct weston_vnc_backend_config);
133 + config->bind_address = NULL;
134 + config->port = 5900;
135 + config->refresh_rate = VNC_DEFAULT_FREQ;
148 + return -1;
153 + { WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width },
154 + { WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height },
163 + weston_config_section_get_int(section, "refresh-rate",
178 @@ -3422,6 +3519,8 @@ load_backend(struct weston_compositor *compositor, const char *backend,
180 else if (strstr(backend, "rdp-backend.so"))
182 + else if (strstr(backend, "vnc-backend.so"))
184 else if (strstr(backend, "drm-backend.so"))
186 else if (strstr(backend, "x11-backend.so"))
187 diff --git a/include/libweston/backend-vnc.h b/include/libweston/backend-vnc.h
190 --- /dev/null
191 +++ b/include/libweston/backend-vnc.h
192 @@ -0,0 +1,71 @@
226 +#include <libweston/plugin-registry.h>
234 + * Returns 0 on success, -1 on failure.
264 diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
266 --- a/include/libweston/libweston.h
268 @@ -2090,6 +2090,7 @@ enum weston_compositor_backend {
276 diff --git a/include/libweston/meson.build b/include/libweston/meson.build
278 --- a/include/libweston/meson.build
280 @@ -14,6 +14,7 @@ install_headers(
281 backend_drm_h = files('backend-drm.h')
282 backend_headless_h = files('backend-headless.h')
283 backend_rdp_h = files('backend-rdp.h')
284 +backend_vnc_h = files('backend-vnc.h')
285 backend_wayland_h = files('backend-wayland.h')
286 backend_x11_h = files('backend-x11.h')
288 diff --git a/libweston/backend-vnc/meson.build b/libweston/backend-vnc/meson.build
291 --- /dev/null
292 +++ b/libweston/backend-vnc/meson.build
293 @@ -0,0 +1,32 @@
294 +if not get_option('backend-vnc')
301 + error('VNC backend requires neatvnc which was not found. Or, you can use \'-Dbackend-vnc=false\'.…
306 + error('VNC backend requires libaml which was not found. Or, you can use \'-Dbackend-vnc=false\'.')
316 + 'vnc-backend',
324 +env_modmap += 'vnc-backend.so=@0@;'.format(plugin_vnc.full_path())
326 diff --git a/libweston/backend-vnc/vnc.c b/libweston/backend-vnc/vnc.c
329 --- /dev/null
330 +++ b/libweston/backend-vnc/vnc.c
331 @@ -0,0 +1,1032 @@
333 + * Copyright © 2019-2020 Stefan Agner <stefan@agner.ch>
334 + * Copyright © 2021-2022 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
336 + * based on backend-rdp:
373 +#include <xkbcommon/xkbcommon-keysyms.h>
381 +#include "shared/timespec-util.h"
383 +#include <libweston/backend-vnc.h>
384 +#include "pixel-formats.h"
385 +#include "pixman-renderer.h"
408 + struct nvnc_display *display;
417 + struct vnc_backend *backend;
438 + return container_of(base->backend, struct vnc_backend, base);
447 + if (base->destroy != vnc_output_destroy)
458 + if (base->backend_id != vnc_head_destroy)
653 + notify_key(peer->seat, &time, KEY_LEFTSHIFT,
658 + notify_key(peer->seat, &time, key, state, state_update);
662 + notify_key(peer->seat, &time, KEY_LEFTSHIFT,
672 + struct vnc_output *output = peer->backend->output;
678 + if (x < output->base.width && y < output->base.height) {
681 + weston_output_transform_coordinate(&output->base, x, y,
683 + notify_motion_absolute(peer->seat, &time, global_x, global_y);
686 + changed_button_mask = peer->last_button_mask ^ button_mask;
689 + notify_button(peer->seat, &time, BTN_LEFT,
695 + notify_button(peer->seat, &time, BTN_MIDDLE,
701 + notify_button(peer->seat, &time, BTN_RIGHT,
712 + /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c */
714 + weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
719 + notify_axis(peer->seat, &time, &weston_event);
722 + peer->last_button_mask = button_mask;
724 + notify_pointer_frame(peer->seat);
732 + wl_list_remove(&peer->link);
733 + weston_seat_release_keyboard(peer->seat);
734 + weston_seat_release_pointer(peer->seat);
735 + weston_seat_release(peer->seat);
745 + wl_list_remove(&fb_side_data->link);
746 + pixman_region32_fini(&fb_side_data->damage);
747 + pixman_image_unref(fb_side_data->pixman_image);
753 + * Convert damage rectangles from 32-bit global coordinates to 16-bit local
772 + dest_rects[i].x1 = src_rects[i].x1 - x;
773 + dest_rects[i].y1 = src_rects[i].y1 - y;
774 + dest_rects[i].x2 = src_rects[i].x2 - x;
775 + dest_rects[i].y2 = src_rects[i].y2 - y;
783 +vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage)
785 + struct nvnc *server = nvnc_display_get_server(display);
786 + struct vnc_backend *backend = nvnc_get_userdata(server);
787 + struct vnc_output *output = backend->output;
788 + struct weston_compositor *ec = output->base.compositor;
793 + fb = nvnc_fb_pool_acquire(output->fb_pool);
803 + fb_side_data->pixman_image =
804 + pixman_image_create_bits(pfmt->pixman_format,
805 + output->base.width,
806 + output->base.height,
808 + output->base.width * 4);
811 + pixman_region32_copy(&fb_side_data->damage,
812 + &output->base.region);
815 + wl_list_insert(&output->fb_side_data_list, &fb_side_data->link);
818 + pixman_renderer_output_set_buffer(&output->base,
819 + fb_side_data->pixman_image);
821 + ec->renderer->repaint_output(&output->base, &fb_side_data->damage);
825 + vnc_convert_damage(&local_damage, &fb_side_data->damage,
826 + output->base.x, output->base.y);
829 + pixman_region32_clear(&fb_side_data->damage);
831 + nvnc_display_feed_buffer(output->display, fb, &local_damage);
840 + struct vnc_backend *backend = nvnc_get_userdata(server);
841 + struct vnc_output *output = backend->output;
848 + peer->client = client;
849 + peer->backend = backend;
850 + peer->seat = zalloc(sizeof(*peer->seat));
852 + if (!peer->seat) {
856 + weston_seat_init(peer->seat, backend->compositor, seat_name);
857 + weston_seat_init_pointer(peer->seat);
858 + weston_seat_init_keyboard(peer->seat, backend->xkb_keymap);
860 + wl_list_insert(&output->peers, &peer->link);
869 + weston_output_schedule_repaint(&output->base);
877 + int refresh_nsec = millihz_to_nsec(output->base.current_mode->refresh);
885 + timespec_add_nsec(&ts, &output->base.frame_time, refresh_nsec);
888 + weston_compositor_read_presentation_clock(output->base.compositor, &now);
893 + weston_output_finish_frame(&output->base, &ts, 0);
902 + struct vnc_backend *backend;
907 + .width = output->base.width,
908 + .height = output->base.height,
914 + backend = to_vnc_backend(base->compositor);
915 + backend->output = output;
917 + if (pixman_renderer_output_create(&output->base, &options) < 0)
918 + return -1;
920 + loop = wl_display_get_event_loop(backend->compositor->wl_display);
921 + output->finish_frame_timer = wl_event_loop_add_timer(loop,
925 + output->fb_pool = nvnc_fb_pool_new(output->base.width,
926 + output->base.height,
928 + output->base.width);
930 + output->display = nvnc_display_new(0, 0);
932 + wl_list_init(&output->fb_side_data_list);
934 + nvnc_add_display(backend->server, output->display);
937 + * Neat VNC warns when a client connects before a display buffer has
940 + vnc_update_buffer(output->display, &output->base.region);
949 + struct vnc_backend *backend;
953 + backend = to_vnc_backend(base->compositor);
955 + if (!output->base.enabled)
958 + pixman_renderer_output_destroy(&output->base);
960 + nvnc_display_unref(output->display);
961 + nvnc_fb_pool_unref(output->fb_pool);
963 + wl_event_source_remove(output->finish_frame_timer);
964 + backend->output = NULL;
977 + vnc_output_disable(&output->base);
978 + weston_output_release(&output->base);
992 + weston_output_init(&output->base, compositor, name);
994 + output->base.destroy = vnc_output_destroy;
995 + output->base.disable = vnc_output_disable;
996 + output->base.enable = vnc_output_enable;
997 + output->base.attach_head = NULL;
999 + weston_compositor_add_pending_output(&output->base, compositor);
1001 + return &output->base;
1008 + struct vnc_backend *backend = to_vnc_backend(ec);
1010 + nvnc_close(backend->server);
1014 + wl_event_source_remove(backend->aml_event);
1016 + aml_unref(backend->aml);
1018 + wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
1021 + xkb_keymap_unref(backend->xkb_keymap);
1023 + free(backend);
1033 + return -1;
1035 + weston_head_init(&head->base, name);
1037 + head->base.backend_id = vnc_head_destroy;
1039 + weston_head_set_connection_status(&head->base, true);
1040 + weston_compositor_add_head(compositor, &head->base);
1053 + weston_head_release(&head->base);
1062 + weston_compositor_read_presentation_clock(output->compositor, &ts);
1072 + struct weston_compositor *ec = output->base.compositor;
1073 + struct vnc_backend *backend = to_vnc_backend(ec);
1075 + int refresh_nsec = millihz_to_nsec(output->base.current_mode->refresh);
1085 + wl_list_for_each(fb_side_data, &output->fb_side_data_list, link)
1086 + pixman_region32_union(&fb_side_data->damage,
1087 + &fb_side_data->damage, damage);
1090 + if (!wl_list_empty(&output->peers))
1091 + vnc_update_buffer(output->display, damage);
1093 + pixman_region32_subtract(&ec->primary_plane.damage,
1094 + &ec->primary_plane.damage, damage);
1103 + aml_dispatch(backend->aml);
1106 + timespec_add_nsec(&target, &output->base.frame_time, refresh_nsec);
1114 + wl_event_source_timer_update(output->finish_frame_timer,
1129 + mode->width = width;
1130 + mode->height = height;
1131 + mode->refresh = rate;
1132 + wl_list_insert(&output->mode_list, &mode->link);
1141 + struct vnc_backend *backend = to_vnc_backend(output->compositor);
1144 + wl_list_for_each(local, &output->mode_list, link) {
1145 + if ((local->width == target->width) &&
1146 + (local->height == target->height))
1150 + return vnc_insert_new_mode(output, target->width, target->height,
1151 + backend->vnc_monitor_refresh_rate);
1166 + target_mode->width, target_mode->height);
1167 + return -ENOENT;
1170 + if (local_mode == base->current_mode)
1173 + base->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
1175 + base->current_mode = base->native_mode = local_mode;
1176 + base->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
1178 + fb_size.width = target_mode->width;
1179 + fb_size.height = target_mode->height;
1183 + nvnc_fb_pool_unref(output->fb_pool);
1185 + output->fb_pool = nvnc_fb_pool_new(target_mode->width,
1186 + target_mode->height,
1188 + target_mode->width * 4);
1197 + struct vnc_backend *backend = to_vnc_backend(base->compositor);
1203 + assert(!output->base.current_mode);
1205 + wl_list_for_each(head, &output->base.head_list, output_link) {
1211 + wl_list_init(&output->peers);
1216 + init_mode.refresh = backend->vnc_monitor_refresh_rate;
1218 + current_mode = vnc_ensure_matching_mode(&output->base, &init_mode);
1220 + return -1;
1222 + output->base.current_mode = output->base.native_mode = current_mode;
1224 + output->base.start_repaint_loop = vnc_output_start_repaint_loop;
1225 + output->base.repaint = vnc_output_repaint;
1226 + output->base.assign_planes = NULL;
1227 + output->base.set_backlight = NULL;
1228 + output->base.set_dpms = NULL;
1229 + output->base.switch_mode = vnc_switch_mode;
1253 + struct vnc_backend *backend;
1259 + backend = zalloc(sizeof *backend);
1260 + if (backend == NULL)
1263 + backend->compositor = compositor;
1264 + backend->base.destroy = vnc_destroy;
1265 + backend->base.create_output = vnc_create_output;
1266 + backend->vnc_monitor_refresh_rate = config->refresh_rate * 1000;
1268 + compositor->backend = &backend->base;
1279 + compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
1281 + backend->xkb_rule_name.rules = strdup("evdev");
1282 + backend->xkb_rule_name.model = strdup("pc105");
1283 + backend->xkb_rule_name.layout = strdup("us");
1285 + backend->xkb_keymap = xkb_keymap_new_from_names(
1286 + backend->compositor->xkb_context,
1287 + &backend->xkb_rule_name, 0);
1289 + loop = wl_display_get_event_loop(backend->compositor->wl_display);
1291 + backend->aml = aml_new();
1292 + if (!backend->aml)
1294 + aml_set_default(backend->aml);
1296 + fd = aml_get_fd(backend->aml);
1298 + backend->aml_event = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1300 + backend->aml);
1302 + backend->server = nvnc_open(config->bind_address, config->port);
1303 + if (!backend->server)
1306 + nvnc_set_new_client_fn(backend->server, vnc_new_client);
1307 + nvnc_set_pointer_fn(backend->server, vnc_pointer_event);
1308 + nvnc_set_key_fn(backend->server, vnc_handle_key_event);
1309 + nvnc_set_userdata(backend->server, backend, NULL);
1310 + nvnc_set_name(backend->server, "Weston VNC backend");
1319 + return backend;
1322 + if (backend->output)
1323 + weston_output_release(&backend->output->base);
1324 + wl_list_for_each_safe(base, next, &compositor->head_list, compositor_link)
1328 + free(backend);
1335 + config->bind_address = NULL;
1336 + config->port = 5900;
1337 + config->refresh_rate = VNC_DEFAULT_FREQ;
1344 + struct vnc_backend *backend;
1347 + weston_log("Initializing VNC backend\n");
1350 + config_base->struct_version != WESTON_VNC_BACKEND_CONFIG_VERSION ||
1351 + config_base->struct_size > sizeof(struct weston_vnc_backend_config)) {
1352 + weston_log("VNC backend config structure is invalid\n");
1353 + return -1;
1357 + memcpy(&config, config_base, config_base->struct_size);
1359 + backend = vnc_backend_create(compositor, &config);
1360 + if (backend == NULL)
1361 + return -1;
1364 diff --git a/libweston/compositor.c b/libweston/compositor.c
1366 --- a/libweston/compositor.c
1368 @@ -9101,6 +9101,7 @@ static const char * const backend_map[] = {
1369 [WESTON_BACKEND_DRM] = "drm-backend.so",
1370 [WESTON_BACKEND_HEADLESS] = "headless-backend.so",
1371 [WESTON_BACKEND_RDP] = "rdp-backend.so",
1372 + [WESTON_BACKEND_VNC] = "vnc-backend.so",
1373 [WESTON_BACKEND_WAYLAND] = "wayland-backend.so",
1374 [WESTON_BACKEND_X11] = "x11-backend.so",
1376 diff --git a/libweston/meson.build b/libweston/meson.build
1378 --- a/libweston/meson.build
1380 @@ -241,5 +241,6 @@ subdir('renderer-gl')
1381 subdir('backend-drm')
1382 subdir('backend-headless')
1383 subdir('backend-rdp')
1384 +subdir('backend-vnc')
1385 subdir('backend-wayland')
1386 subdir('backend-x11')
1387 diff --git a/meson_options.txt b/meson_options.txt
1389 --- a/meson_options.txt
1391 @@ -32,6 +32,12 @@ option(
1393 description: 'Compositor: RDP screen-sharing support'
1396 + 'backend-vnc',
1399 + description: 'Weston backend: VNC remote screensharing'
1402 'backend-wayland',
1404 --