From 9b4be5a59506a81175ab2eb9248f4035176df5f0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 17 Jan 2019 20:13:55 +1000 Subject: [PATCH] Introduce noop backend The noop backend is similar to headless, but it doesn't contain a renderer. It can be used as a place to stash views for when there's no physical outputs connected. --- backend/backend.c | 17 +++++++++ backend/meson.build | 2 + backend/noop/backend.c | 68 ++++++++++++++++++++++++++++++++++ backend/noop/output.c | 75 ++++++++++++++++++++++++++++++++++++++ docs/env_vars.md | 2 +- include/backend/noop.h | 24 ++++++++++++ include/wlr/backend/noop.h | 31 ++++++++++++++++ 7 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 backend/noop/backend.c create mode 100644 backend/noop/output.c create mode 100644 include/backend/noop.h create mode 100644 include/wlr/backend/noop.h diff --git a/backend/backend.c b/backend/backend.c index b369a135..33ad20f2 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,20 @@ static struct wlr_backend *attempt_headless_backend( return backend; } +static struct wlr_backend *attempt_noop_backend(struct wl_display *display) { + struct wlr_backend *backend = wlr_noop_backend_create(display); + if (backend == NULL) { + return NULL; + } + + size_t outputs = parse_outputs_env("WLR_NOOP_OUTPUTS"); + for (size_t i = 0; i < outputs; ++i) { + wlr_noop_add_output(backend); + } + + return backend; +} + static struct wlr_backend *attempt_drm_backend(struct wl_display *display, struct wlr_backend *backend, struct wlr_session *session, wlr_renderer_create_func_t create_renderer_func) { @@ -170,6 +185,8 @@ static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, #endif } else if (strcmp(name, "headless") == 0) { return attempt_headless_backend(display, create_renderer_func); + } else if (strcmp(name, "noop") == 0) { + return attempt_noop_backend(display); } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { // DRM and libinput need a session if (!*session) { diff --git a/backend/meson.build b/backend/meson.build index bf9b4f83..39769ecd 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -20,6 +20,8 @@ backend_files = files( 'libinput/tablet_tool.c', 'libinput/touch.c', 'multi/backend.c', + 'noop/backend.c', + 'noop/output.c', 'session/direct-ipc.c', 'session/session.c', 'wayland/backend.c', diff --git a/backend/noop/backend.c b/backend/noop/backend.c new file mode 100644 index 00000000..340fce0d --- /dev/null +++ b/backend/noop/backend.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "backend/noop.h" +#include "util/signal.h" + +struct wlr_noop_backend *noop_backend_from_backend( + struct wlr_backend *wlr_backend) { + assert(wlr_backend_is_noop(wlr_backend)); + return (struct wlr_noop_backend *)wlr_backend; +} + +static bool backend_start(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + wlr_log(WLR_INFO, "Starting noop backend"); + + struct wlr_noop_output *output; + wl_list_for_each(output, &backend->outputs, link) { + wlr_output_update_enabled(&output->wlr_output, true); + wlr_signal_emit_safe(&backend->backend.events.new_output, + &output->wlr_output); + } + + backend->started = true; + return true; +} + +static void backend_destroy(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + if (!wlr_backend) { + return; + } + + struct wlr_noop_output *output, *output_tmp; + wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) { + wlr_output_destroy(&output->wlr_output); + } + + wlr_signal_emit_safe(&wlr_backend->events.destroy, backend); + + free(backend); +} + +static const struct wlr_backend_impl backend_impl = { + .start = backend_start, + .destroy = backend_destroy, +}; + +struct wlr_backend *wlr_noop_backend_create(struct wl_display *display) { + wlr_log(WLR_INFO, "Creating noop backend"); + + struct wlr_noop_backend *backend = + calloc(1, sizeof(struct wlr_noop_backend)); + if (!backend) { + wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_backend"); + return NULL; + } + wlr_backend_init(&backend->backend, &backend_impl); + backend->display = display; + wl_list_init(&backend->outputs); + + return &backend->backend; +} + +bool wlr_backend_is_noop(struct wlr_backend *backend) { + return backend->impl == &backend_impl; +} diff --git a/backend/noop/output.c b/backend/noop/output.c new file mode 100644 index 00000000..a2595eff --- /dev/null +++ b/backend/noop/output.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include "backend/noop.h" +#include "util/signal.h" + +static struct wlr_noop_output *noop_output_from_output( + struct wlr_output *wlr_output) { + assert(wlr_output_is_noop(wlr_output)); + return (struct wlr_noop_output *)wlr_output; +} + +static void output_transform(struct wlr_output *wlr_output, + enum wl_output_transform transform) { + // empty +} + +static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) { + return true; +} + +static bool output_swap_buffers(struct wlr_output *wlr_output, + pixman_region32_t *damage) { + return true; +} + +static void output_destroy(struct wlr_output *wlr_output) { + struct wlr_noop_output *output = + noop_output_from_output(wlr_output); + + wl_list_remove(&output->link); + + free(output); +} + +static const struct wlr_output_impl output_impl = { + .transform = output_transform, + .destroy = output_destroy, + .make_current = output_make_current, + .swap_buffers = output_swap_buffers, +}; + +bool wlr_output_is_noop(struct wlr_output *wlr_output) { + return wlr_output->impl == &output_impl; +} + +struct wlr_output *wlr_noop_add_output(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + + struct wlr_noop_output *output = calloc(1, sizeof(struct wlr_noop_output)); + if (output == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_output"); + return NULL; + } + output->backend = backend; + wlr_output_init(&output->wlr_output, &backend->backend, &output_impl, + backend->display); + struct wlr_output *wlr_output = &output->wlr_output; + + strncpy(wlr_output->make, "noop", sizeof(wlr_output->make)); + strncpy(wlr_output->model, "noop", sizeof(wlr_output->model)); + snprintf(wlr_output->name, sizeof(wlr_output->name), "NOOP-%d", + wl_list_length(&backend->outputs) + 1); + + wl_list_insert(&backend->outputs, &output->link); + + if (backend->started) { + wlr_output_update_enabled(wlr_output, true); + wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); + } + + return wlr_output; +} diff --git a/docs/env_vars.md b/docs/env_vars.md index b67d1652..fd8fcbac 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -11,7 +11,7 @@ wlroots specific control instead of the atomic interface * *WLR_LIBINPUT_NO_DEVICES*: set to 1 to not fail without any input devices * *WLR_BACKENDS*: comma-separated list of backends to use (available backends: - wayland, x11, headless) + wayland, x11, headless, noop) * *WLR_WL_OUTPUTS*: when using the wayland backend specifies the number of outputs * *WLR_X11_OUTPUTS*: when using the X11 backend specifies the number of outputs * *WLR_HEADLESS_OUTPUTS*: when using the headless backend specifies the number diff --git a/include/backend/noop.h b/include/backend/noop.h new file mode 100644 index 00000000..4198baad --- /dev/null +++ b/include/backend/noop.h @@ -0,0 +1,24 @@ +#ifndef BACKEND_NOOP_H +#define BACKEND_NOOP_H + +#include +#include + +struct wlr_noop_backend { + struct wlr_backend backend; + struct wl_display *display; + struct wl_list outputs; + bool started; +}; + +struct wlr_noop_output { + struct wlr_output wlr_output; + + struct wlr_noop_backend *backend; + struct wl_list link; +}; + +struct wlr_noop_backend *noop_backend_from_backend( + struct wlr_backend *wlr_backend); + +#endif diff --git a/include/wlr/backend/noop.h b/include/wlr/backend/noop.h new file mode 100644 index 00000000..592b8f35 --- /dev/null +++ b/include/wlr/backend/noop.h @@ -0,0 +1,31 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_BACKEND_NOOP_H +#define WLR_BACKEND_NOOP_H + +#include +#include + +/** + * Creates a noop backend. Noop backends do not have a framebuffer and are not + * capable of rendering anything. They are useful for when there's no real + * outputs connected; you can stash your views on a noop output until an output + * is connected. + */ +struct wlr_backend *wlr_noop_backend_create(struct wl_display *display); + +/** + * Create a new noop output. + */ +struct wlr_output *wlr_noop_add_output(struct wlr_backend *backend); + +bool wlr_backend_is_noop(struct wlr_backend *backend); +bool wlr_output_is_noop(struct wlr_output *output); + +#endif