wlroots/backend/backend.c
Simon Ser 4b03bdc3ab Remove wlr_create_renderer_func_t
This callback allowed compositors to customize the EGL config used by
the renderer. However with renderer v6 EGL configs aren't used anymore.
Instead, buffers are allocated via GBM and GL FBOs are rendered to. So
customizing the EGL config is a no-op.
2020-12-30 17:09:40 +01:00

312 lines
7.7 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <errno.h>
#include <libinput.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/backend/drm.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/interface.h>
#include <wlr/backend/libinput.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/noop.h>
#include <wlr/backend/session.h>
#include <wlr/backend/wayland.h>
#include <wlr/config.h>
#include <wlr/util/log.h>
#include "backend/multi.h"
#if WLR_HAS_X11_BACKEND
#include <wlr/backend/x11.h>
#endif
void wlr_backend_init(struct wlr_backend *backend,
const struct wlr_backend_impl *impl) {
assert(backend);
backend->impl = impl;
wl_signal_init(&backend->events.destroy);
wl_signal_init(&backend->events.new_input);
wl_signal_init(&backend->events.new_output);
}
bool wlr_backend_start(struct wlr_backend *backend) {
if (backend->impl->start) {
return backend->impl->start(backend);
}
return true;
}
void wlr_backend_destroy(struct wlr_backend *backend) {
if (!backend) {
return;
}
if (backend->impl && backend->impl->destroy) {
backend->impl->destroy(backend);
} else {
free(backend);
}
}
struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend) {
if (backend->impl->get_renderer) {
return backend->impl->get_renderer(backend);
}
return NULL;
}
struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) {
if (backend->impl->get_session) {
return backend->impl->get_session(backend);
}
return NULL;
}
clockid_t wlr_backend_get_presentation_clock(struct wlr_backend *backend) {
if (backend->impl->get_presentation_clock) {
return backend->impl->get_presentation_clock(backend);
}
return CLOCK_MONOTONIC;
}
static size_t parse_outputs_env(const char *name) {
const char *outputs_str = getenv(name);
if (outputs_str == NULL) {
return 1;
}
char *end;
int outputs = (int)strtol(outputs_str, &end, 10);
if (*end || outputs < 0) {
wlr_log(WLR_ERROR, "%s specified with invalid integer, ignoring", name);
return 1;
}
return outputs;
}
static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
struct wlr_backend *backend = wlr_wl_backend_create(display, NULL);
if (backend == NULL) {
return NULL;
}
size_t outputs = parse_outputs_env("WLR_WL_OUTPUTS");
for (size_t i = 0; i < outputs; ++i) {
wlr_wl_output_create(backend);
}
return backend;
}
#if WLR_HAS_X11_BACKEND
static struct wlr_backend *attempt_x11_backend(struct wl_display *display,
const char *x11_display) {
struct wlr_backend *backend = wlr_x11_backend_create(display, x11_display);
if (backend == NULL) {
return NULL;
}
size_t outputs = parse_outputs_env("WLR_X11_OUTPUTS");
for (size_t i = 0; i < outputs; ++i) {
wlr_x11_output_create(backend);
}
return backend;
}
#endif
static struct wlr_backend *attempt_headless_backend(
struct wl_display *display) {
struct wlr_backend *backend = wlr_headless_backend_create(display);
if (backend == NULL) {
return NULL;
}
size_t outputs = parse_outputs_env("WLR_HEADLESS_OUTPUTS");
for (size_t i = 0; i < outputs; ++i) {
wlr_headless_add_output(backend, 1280, 720);
}
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) {
struct wlr_device *gpus[8];
size_t num_gpus = wlr_session_find_gpus(session, 8, gpus);
struct wlr_backend *primary_drm = NULL;
wlr_log(WLR_INFO, "Found %zu GPUs", num_gpus);
for (size_t i = 0; i < num_gpus; ++i) {
struct wlr_backend *drm = wlr_drm_backend_create(display, session,
gpus[i], primary_drm);
if (!drm) {
wlr_log(WLR_ERROR, "Failed to create DRM backend");
continue;
}
if (!primary_drm) {
primary_drm = drm;
}
wlr_multi_backend_add(backend, drm);
}
return primary_drm;
}
static struct wlr_backend *attempt_backend_by_name(struct wl_display *display,
struct wlr_backend *backend, struct wlr_session **session,
const char *name) {
if (strcmp(name, "wayland") == 0) {
return attempt_wl_backend(display);
#if WLR_HAS_X11_BACKEND
} else if (strcmp(name, "x11") == 0) {
return attempt_x11_backend(display, NULL);
#endif
} else if (strcmp(name, "headless") == 0) {
return attempt_headless_backend(display);
} 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) {
*session = wlr_session_create(display);
if (!*session) {
wlr_log(WLR_ERROR, "failed to start a session");
return NULL;
}
}
if (strcmp(name, "libinput") == 0) {
return wlr_libinput_backend_create(display, *session);
} else {
return attempt_drm_backend(display, backend, *session);
}
}
wlr_log(WLR_ERROR, "unrecognized backend '%s'", name);
return NULL;
}
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
struct wlr_backend *backend = wlr_multi_backend_create(display);
struct wlr_multi_backend *multi = (struct wlr_multi_backend *)backend;
if (!backend) {
wlr_log(WLR_ERROR, "could not allocate multibackend");
return NULL;
}
char *names = getenv("WLR_BACKENDS");
if (names) {
names = strdup(names);
if (names == NULL) {
wlr_log(WLR_ERROR, "allocation failed");
wlr_backend_destroy(backend);
return NULL;
}
char *saveptr;
char *name = strtok_r(names, ",", &saveptr);
while (name != NULL) {
struct wlr_backend *subbackend = attempt_backend_by_name(display,
backend, &multi->session, name);
if (subbackend == NULL) {
wlr_log(WLR_ERROR, "failed to start backend '%s'", name);
wlr_session_destroy(multi->session);
wlr_backend_destroy(backend);
free(names);
return NULL;
}
if (!wlr_multi_backend_add(backend, subbackend)) {
wlr_log(WLR_ERROR, "failed to add backend '%s'", name);
wlr_session_destroy(multi->session);
wlr_backend_destroy(backend);
free(names);
return NULL;
}
name = strtok_r(NULL, ",", &saveptr);
}
free(names);
return backend;
}
if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) {
struct wlr_backend *wl_backend = attempt_wl_backend(display);
if (!wl_backend) {
goto error;
}
wlr_multi_backend_add(backend, wl_backend);
return backend;
}
#if WLR_HAS_X11_BACKEND
const char *x11_display = getenv("DISPLAY");
if (x11_display) {
struct wlr_backend *x11_backend =
attempt_x11_backend(display, x11_display);
if (!x11_backend) {
goto error;
}
wlr_multi_backend_add(backend, x11_backend);
return backend;
}
#endif
// Attempt DRM+libinput
multi->session = wlr_session_create(display);
if (!multi->session) {
wlr_log(WLR_ERROR, "Failed to start a DRM session");
wlr_backend_destroy(backend);
return NULL;
}
struct wlr_backend *libinput = wlr_libinput_backend_create(display,
multi->session);
if (!libinput) {
wlr_log(WLR_ERROR, "Failed to start libinput backend");
wlr_session_destroy(multi->session);
wlr_backend_destroy(backend);
return NULL;
}
wlr_multi_backend_add(backend, libinput);
struct wlr_backend *primary_drm =
attempt_drm_backend(display, backend, multi->session);
if (!primary_drm) {
wlr_log(WLR_ERROR, "Failed to open any DRM device");
wlr_backend_destroy(libinput);
wlr_session_destroy(multi->session);
wlr_backend_destroy(backend);
return NULL;
}
return backend;
error:
wlr_backend_destroy(backend);
return NULL;
}