Skip to content
Commits on Source (18)
This diff is collapsed.
......@@ -42,6 +42,17 @@ by your GPU when suitable drivers are installed. The other uses the
rendered. You can select between these with the ``--renderer=gl`` and
``--renderer=pixman`` arguments when starting Weston.
Multi-back-end support
----------------------
Some back-ends can be selected via a comma-separated list to run in parallel,
for example ``-B drm,vnc``. The first back-end in the list is the *primary*
back-end. It creates the renderer and creates its outputs first. The following
back-ends are *secondary* backends. They reuse the renderer and create their
outputs afterwards. Currently, all back-ends support being loaded as the primary
back-end. The PipeWire and VNC backends support being loaded as secondary
backends.
Additional set-up steps
-----------------------
......
......@@ -1439,7 +1439,10 @@ struct weston_compositor {
struct weston_renderer *renderer;
const struct pixel_format_info *read_format;
struct weston_backend *backend;
/* Pointer to the first backend on backend_list */
struct weston_backend *primary_backend;
struct wl_list backend_list;
struct weston_launcher *launcher;
struct weston_dmabuf_feedback *default_dmabuf_feedback;
......@@ -1478,6 +1481,9 @@ struct weston_compositor {
/* Whether to let the compositor run without any input device. */
bool require_input;
/* Whether to load multiple backends. */
bool multi_backend;
/* Test suite data */
struct weston_testsuite_data test_data;
......@@ -2326,7 +2332,7 @@ enum weston_renderer_type {
WESTON_RENDERER_GL = 3,
};
int
struct weston_backend *
weston_compositor_load_backend(struct weston_compositor *compositor,
enum weston_compositor_backend backend,
struct weston_backend_config *config_base);
......
......@@ -739,7 +739,14 @@ to_drm_output(struct weston_output *base)
static inline struct drm_backend *
to_drm_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct drm_backend, base);
struct weston_backend *backend;
wl_list_for_each(backend, &base->backend_list, link) {
if (backend->destroy == drm_destroy)
return container_of(backend, struct drm_backend, base);
}
return NULL;
}
static inline struct drm_mode *
......
......@@ -3263,6 +3263,8 @@ drm_destroy(struct weston_backend *backend)
struct drm_crtc *crtc, *crtc_tmp;
struct drm_writeback *writeback, *writeback_tmp;
wl_list_remove(&b->base.link);
wl_list_for_each_safe(crtc, crtc_tmp, &b->drm->crtc_list, link)
drm_crtc_destroy(crtc);
......@@ -3802,7 +3804,7 @@ drm_backend_create(struct weston_compositor *compositor,
"Debug messages from DRM/KMS backend\n",
NULL, NULL, NULL);
compositor->backend = &b->base;
wl_list_insert(&compositor->backend_list, &b->base.link);
if (parse_gbm_format(config->gbm_format,
pixel_format_get_info(DRM_FORMAT_XRGB8888),
......@@ -4021,6 +4023,7 @@ err_udev:
err_launcher:
weston_launcher_destroy(compositor->launcher);
err_compositor:
wl_list_remove(&b->base.link);
#ifdef BUILD_DRM_GBM
if (b->gbm)
gbm_device_destroy(b->gbm);
......@@ -4050,6 +4053,11 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
weston_log("drm backend must be the primary backend\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -503,6 +503,8 @@ headless_destroy(struct weston_backend *backend)
struct weston_compositor *ec = b->compositor;
struct weston_head *base, *next;
wl_list_remove(&b->base.link);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_headless_head(base))
headless_head_destroy(base);
......@@ -537,7 +539,7 @@ headless_backend_create(struct weston_compositor *compositor,
return NULL;
b->compositor = compositor;
compositor->backend = &b->base;
wl_list_insert(&compositor->backend_list, &b->base.link);
b->base.supported_presentation_clocks =
WESTON_PRESENTATION_CLOCKS_SOFTWARE;
......@@ -621,6 +623,7 @@ err_input:
if (b->theme)
theme_destroy(b->theme);
err_free:
wl_list_remove(&b->base.link);
free(b);
return NULL;
}
......@@ -644,6 +647,11 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
weston_log("headless backend must be the primary backend\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -628,6 +628,8 @@ pipewire_destroy(struct weston_backend *base)
weston_log_scope_destroy(b->debug);
b->debug = NULL;
wl_list_remove(&b->base.link);
pw_loop_leave(b->loop);
pw_loop_destroy(b->loop);
wl_event_source_remove(b->loop_source);
......@@ -996,7 +998,7 @@ pipewire_backend_create(struct weston_compositor *compositor,
backend->base.destroy = pipewire_destroy;
backend->base.create_output = pipewire_create_output;
compositor->backend = &backend->base;
wl_list_insert(&compositor->backend_list, &backend->base.link);
backend->formats_count = ARRAY_LENGTH(pipewire_formats);
backend->formats = pixel_format_get_array(pipewire_formats,
......@@ -1005,32 +1007,34 @@ pipewire_backend_create(struct weston_compositor *compositor,
backend->base.supported_presentation_clocks =
WESTON_PRESENTATION_CLOCKS_SOFTWARE;
switch (config->renderer) {
case WESTON_RENDERER_AUTO:
case WESTON_RENDERER_PIXMAN:
ret = weston_compositor_init_renderer(compositor,
WESTON_RENDERER_PIXMAN,
NULL);
break;
case WESTON_RENDERER_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = backend->formats,
.formats_count = backend->formats_count,
};
ret = weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base);
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_compositor;
if (!compositor->renderer) {
switch (config->renderer) {
case WESTON_RENDERER_AUTO:
case WESTON_RENDERER_PIXMAN:
ret = weston_compositor_init_renderer(compositor,
WESTON_RENDERER_PIXMAN,
NULL);
break;
case WESTON_RENDERER_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = backend->formats,
.formats_count = backend->formats_count,
};
ret = weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base);
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_compositor;
}
if (ret < 0)
goto err_compositor;
}
if (ret < 0)
goto err_compositor;
compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
ret = weston_pipewire_init(backend);
......@@ -1055,6 +1059,7 @@ pipewire_backend_create(struct weston_compositor *compositor,
return backend;
err_compositor:
wl_list_remove(&backend->base.link);
free(backend);
return NULL;
}
......@@ -1082,6 +1087,17 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
switch (compositor->renderer->type) {
case WESTON_RENDERER_PIXMAN:
case WESTON_RENDERER_GL:
break;
default:
weston_log("Renderer not supported by PipeWire backend\n");
return -1;
}
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -665,6 +665,8 @@ rdp_destroy(struct weston_backend *backend)
b->verbose = NULL;
}
wl_list_remove(&b->base.link);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_rdp_head(base))
rdp_head_destroy(base);
......@@ -1845,7 +1847,7 @@ rdp_backend_create(struct weston_compositor *compositor,
"Debug messages from RDP backend clipboard\n",
NULL, NULL, NULL);
compositor->backend = &b->base;
wl_list_insert(&compositor->backend_list, &b->base.link);
if (config->server_cert && config->server_key) {
b->server_cert = strdup(config->server_cert);
......@@ -1878,29 +1880,31 @@ rdp_backend_create(struct weston_compositor *compositor,
b->formats_count = ARRAY_LENGTH(rdp_formats);
b->formats = pixel_format_get_array(rdp_formats, b->formats_count);
switch (config->renderer) {
case WESTON_RENDERER_PIXMAN:
case WESTON_RENDERER_AUTO:
if (weston_compositor_init_renderer(compositor, WESTON_RENDERER_PIXMAN,
NULL) < 0)
goto err_compositor;
break;
case WESTON_RENDERER_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = b->formats,
.formats_count = b->formats_count,
};
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base) < 0)
if (!compositor->renderer) {
switch (config->renderer) {
case WESTON_RENDERER_PIXMAN:
case WESTON_RENDERER_AUTO:
if (weston_compositor_init_renderer(compositor, WESTON_RENDERER_PIXMAN,
NULL) < 0)
goto err_compositor;
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_free_strings;
break;
case WESTON_RENDERER_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = b->formats,
.formats_count = b->formats_count,
};
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base) < 0)
goto err_compositor;
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_free_strings;
}
}
rdp_head_create(b, NULL);
......@@ -1959,6 +1963,7 @@ err_compositor:
rdp_head_destroy(base);
}
err_free_strings:
wl_list_remove(&b->base.link);
if (b->clipboard_debug)
weston_log_scope_destroy(b->clipboard_debug);
if (b->clipboard_verbose)
......@@ -2016,6 +2021,17 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
switch (compositor->renderer->type) {
case WESTON_RENDERER_PIXMAN:
case WESTON_RENDERER_GL:
break;
default:
weston_log("Renderer not supported by RDP backend\n");
return -1;
}
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -874,6 +874,8 @@ vnc_destroy(struct weston_backend *base)
struct weston_compositor *ec = backend->compositor;
struct weston_head *head, *next;
wl_list_remove(&backend->base.link);
wl_event_source_remove(backend->aml_event);
aml_unref(backend->aml);
......@@ -1144,6 +1146,8 @@ vnc_backend_create(struct weston_compositor *compositor,
if (backend == NULL)
return NULL;
wl_list_init(&backend->base.link);
backend->compositor = compositor;
backend->base.shutdown = vnc_shutdown;
backend->base.destroy = vnc_destroy;
......@@ -1155,7 +1159,7 @@ vnc_backend_create(struct weston_compositor *compositor,
"Debug messages from VNC backend\n",
NULL, NULL, NULL);
compositor->backend = &backend->base;
wl_list_insert(&compositor->backend_list, &backend->base.link);
backend->base.supported_presentation_clocks =
WESTON_PRESENTATION_CLOCKS_SOFTWARE;
......@@ -1163,30 +1167,31 @@ vnc_backend_create(struct weston_compositor *compositor,
backend->formats_count = ARRAY_LENGTH(vnc_formats);
backend->formats = pixel_format_get_array(vnc_formats,
backend->formats_count);
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_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = backend->formats,
.formats_count = backend->formats_count,
};
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base) < 0)
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_GL: {
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.formats = backend->formats,
.formats_count = backend->formats_count,
};
if (weston_compositor_init_renderer(compositor,
WESTON_RENDERER_GL,
&options.base) < 0)
goto err_compositor;
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_compositor;
break;
}
default:
weston_log("Unsupported renderer requested\n");
goto err_compositor;
}
}
vnc_head_create(backend, "vnc");
......@@ -1266,6 +1271,7 @@ err_output:
wl_list_for_each_safe(base, next, &compositor->head_list, compositor_link)
vnc_head_destroy(base);
err_compositor:
wl_list_remove(&backend->base.link);
free(backend);
return NULL;
}
......@@ -1294,6 +1300,17 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
switch (compositor->renderer->type) {
case WESTON_RENDERER_PIXMAN:
case WESTON_RENDERER_GL:
break;
default:
weston_log("Renderer not supported by VNC backend\n");
return -1;
}
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -2775,6 +2775,8 @@ wayland_destroy(struct weston_backend *backend)
struct wayland_parent_output *output, *next_output;
struct wayland_input *input, *next_input;
wl_list_remove(&b->base.link);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
if (to_wayland_head(base))
wayland_head_destroy(base);
......@@ -2887,7 +2889,7 @@ wayland_backend_create(struct weston_compositor *compositor,
return NULL;
b->compositor = compositor;
compositor->backend = &b->base;
wl_list_insert(&compositor->backend_list, &b->base.link);
b->base.supported_presentation_clocks =
WESTON_PRESENTATION_CLOCKS_SOFTWARE;
......@@ -2987,6 +2989,7 @@ err_renderer:
err_display:
wl_display_disconnect(b->parent.wl_display);
err_compositor:
wl_list_remove(&b->base.link);
free(b->formats);
free(b);
return NULL;
......@@ -3003,6 +3006,7 @@ wayland_backend_destroy(struct wayland_backend *b)
cairo_device_destroy(b->frame_device);
wl_cursor_theme_destroy(b->cursor_theme);
wl_list_remove(&b->base.link);
cleanup_after_cairo();
free(b->formats);
free(b);
......@@ -3034,6 +3038,11 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
weston_log("wayland backend must be the primary backend\n");
return -1;
}
config_init_to_defaults(&new_config);
memcpy(&new_config, config_base, config_base->struct_size);
......
......@@ -1239,10 +1239,12 @@ x11_head_destroy(struct weston_head *base)
static struct x11_output *
x11_backend_find_output(struct x11_backend *b, xcb_window_t window)
{
struct x11_output *output;
struct weston_output *base;
wl_list_for_each(base, &b->compositor->output_list, link) {
struct x11_output *output = to_x11_output(base);
wl_list_for_each(output, &b->compositor->output_list, base.link) {
if (output->window == window)
if (output && output->window == window)
return output;
}
......@@ -1838,6 +1840,8 @@ x11_shutdown(struct weston_backend *base)
{
struct x11_backend *backend = to_x11_backend(base);
wl_list_remove(&backend->base.link);
wl_event_source_remove(backend->xcb_source);
x11_input_destroy(backend);
}
......@@ -1880,7 +1884,7 @@ x11_backend_create(struct weston_compositor *compositor,
b->fullscreen = config->fullscreen;
b->no_input = config->no_input;
compositor->backend = &b->base;
wl_list_insert(&compositor->backend_list, &b->base.link);
b->base.supported_presentation_clocks =
WESTON_PRESENTATION_CLOCKS_SOFTWARE;
......@@ -2009,6 +2013,11 @@ weston_backend_init(struct weston_compositor *compositor,
return -1;
}
if (compositor->renderer) {
weston_log("X11 backend must be the primary backend\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
......
......@@ -40,6 +40,8 @@
struct weston_hdr_metadata_type1;
struct weston_backend {
struct wl_list link; /**< in weston_compositor::backend_list */
/** Bitfield of supported presentation clocks
*
* Bit positions correspond to system clock IDs.
......
......@@ -3084,8 +3084,12 @@ output_accumulate_damage(struct weston_output *output)
* later, keep_buffer is true. Otherwise, drop the core
* reference now, and allow early buffer release. This enables
* clients to use single-buffering.
* The assumption that the backend has seen the surface only
* holds for one backend, so skip this optimization when
* multiple backends are involved.
*/
if (!pnode->surface->keep_buffer) {
if (!output->compositor->multi_backend &&
!pnode->surface->keep_buffer) {
weston_buffer_reference(&pnode->surface->buffer_ref,
pnode->surface->buffer_ref.buffer,
BUFFER_WILL_NOT_BE_ACCESSED);
......@@ -3530,6 +3534,7 @@ static int
output_repaint_timer_handler(void *data)
{
struct weston_compositor *compositor = data;
struct weston_backend *backend;
struct weston_output *output;
struct timespec now;
int ret = 0;
......@@ -3537,8 +3542,10 @@ output_repaint_timer_handler(void *data)
weston_compositor_read_presentation_clock(compositor, &now);
compositor->last_repaint_start = now;
if (compositor->backend->repaint_begin)
compositor->backend->repaint_begin(compositor->backend);
wl_list_for_each(backend, &compositor->backend_list, link) {
if (backend->repaint_begin)
backend->repaint_begin(backend);
}
wl_list_for_each(output, &compositor->output_list, link) {
ret = weston_output_maybe_repaint(output, &now);
......@@ -3547,11 +3554,15 @@ output_repaint_timer_handler(void *data)
}
if (ret == 0) {
if (compositor->backend->repaint_flush)
ret = compositor->backend->repaint_flush(compositor->backend);
wl_list_for_each(backend, &compositor->backend_list, link) {
if (backend->repaint_flush)
ret = backend->repaint_flush(backend);
}
} else {
if (compositor->backend->repaint_cancel)
compositor->backend->repaint_cancel(compositor->backend);
wl_list_for_each(backend, &compositor->backend_list, link) {
if (backend->repaint_cancel)
backend->repaint_cancel(backend);
}
}
if (ret != 0) {
......@@ -8973,6 +8984,8 @@ weston_compositor_create(struct wl_display *display,
wl_list_init(&ec->debug_binding_list);
wl_list_init(&ec->tablet_manager_resource_list);
wl_list_init(&ec->backend_list);
wl_list_init(&ec->plugin_api_list);
wl_data_device_manager_init(ec->wl_display);
......@@ -9134,8 +9147,15 @@ weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
WL_EXPORT int
weston_compositor_backends_loaded(struct weston_compositor *compositor)
{
struct weston_backend *backend = compositor->backend;
uint32_t supported_clocks = backend->supported_presentation_clocks;
struct weston_backend *backend;
uint32_t supported_clocks = 0xffffffff;
compositor->primary_backend =
wl_container_of(compositor->backend_list.prev,
compositor->primary_backend, link);
wl_list_for_each(backend, &compositor->backend_list, link)
supported_clocks &= backend->supported_presentation_clocks;
if (weston_compositor_set_presentation_clock(compositor,
supported_clocks) < 0) {
......@@ -9234,12 +9254,17 @@ WL_EXPORT bool
weston_compositor_dmabuf_can_scanout(struct weston_compositor *compositor,
struct linux_dmabuf_buffer *buffer)
{
struct weston_backend *backend = compositor->backend;
struct weston_backend *backend;
if (backend->can_scanout_dmabuf == NULL)
return false;
wl_list_for_each(backend, &compositor->backend_list, link) {
if (backend->can_scanout_dmabuf == NULL)
return false;
if (!backend->can_scanout_dmabuf(backend, buffer))
return false;
}
return backend->can_scanout_dmabuf(backend, buffer);
return true;
}
WL_EXPORT void
......@@ -9399,6 +9424,25 @@ weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor
return true;
}
static void
weston_compositor_shutdown_backends(struct weston_compositor *compositor)
{
struct weston_backend *backend;
wl_list_for_each(backend, &compositor->backend_list, link)
if (backend->shutdown)
backend->shutdown(backend);
}
static void
weston_compositor_destroy_backends(struct weston_compositor *compositor)
{
struct weston_backend *backend, *tmp;
wl_list_for_each_safe(backend, tmp, &compositor->backend_list, link)
backend->destroy(backend);
}
/** Destroys the compositor.
*
* This function cleans up the compositor state and then destroys it.
......@@ -9417,13 +9461,11 @@ weston_compositor_destroy(struct weston_compositor *compositor)
weston_compositor_xkb_destroy(compositor);
if (compositor->backend && compositor->backend->shutdown)
compositor->backend->shutdown(compositor->backend);
weston_compositor_shutdown_backends(compositor);
weston_compositor_shutdown(compositor);
if (compositor->backend)
compositor->backend->destroy(compositor->backend);
weston_compositor_destroy_backends(compositor);
/* The backend is responsible for destroying the heads. */
assert(wl_list_empty(&compositor->head_list));
......@@ -9499,38 +9541,35 @@ static const char * const backend_map[] = {
* \param config_base A pointer to a backend-specific configuration
* structure's 'base' member.
*
* \return 0 on success, or -1 on error.
* \return A new \c weston_backend on success, or NULL on error.
*
* \ingroup compositor
*/
WL_EXPORT int
WL_EXPORT struct weston_backend *
weston_compositor_load_backend(struct weston_compositor *compositor,
enum weston_compositor_backend backend,
struct weston_backend_config *config_base)
{
int (*backend_init)(struct weston_compositor *c,
struct weston_backend_config *config_base);
if (compositor->backend) {
weston_log("Error: attempt to load a backend when one is already loaded\n");
return -1;
}
struct weston_backend *b;
if (backend >= ARRAY_LENGTH(backend_map))
return -1;
return NULL;
backend_init = weston_load_module(backend_map[backend],
"weston_backend_init",
LIBWESTON_MODULEDIR);
if (!backend_init)
return -1;
return NULL;
if (backend_init(compositor, config_base) < 0) {
compositor->backend = NULL;
return -1;
}
if (backend_init(compositor, config_base) < 0)
return NULL;
return 0;
b = wl_container_of(compositor->backend_list.next, b, link);
/* Return the last loaded backend. */
return b;
}
WL_EXPORT int
......
......@@ -110,17 +110,18 @@ and
.
.SS Weston core options:
.TP
\fB\-\^B\fR\fIbackend\fR, \fB\-\-backend\fR=\fIbackend\fR
Load
.I backend
instead of the default backend, see
\fB\-\^B\fR\fIbackend1,backend2\fR, \fB\-\-backend\fR=\fIbackend1,backend2\fR
Load the comma-separated list of backends instead of the default backend, see
.IR BACKENDS .
The backend module is searched for in
The backend modules are searched for in
.IR "@weston_modules_dir@" .
The default backend is
.I @weston_native_backend@
unless the environment suggests otherwise, see
.IR DISPLAY " and " WAYLAND_DISPLAY .
The first backend is the primary backend, and it provides the renderer. Not all
backends support being loaded as secondary backends, which reuse the primary
backend's renderer.
.TP
\fB\-\^c\fR\fIconfig.ini\fR, \fB\-\-config\fR=\fIconfig.ini\fR
Load
......