Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Basic Wayland backend #17

Merged
merged 14 commits into from
Jun 20, 2017
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
.clang_complete
*.swp
*.o
*.a
Expand Down
9 changes: 4 additions & 5 deletions backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ include_directories(
)

add_library(wlr-backend
#wayland/backend.c
#wayland/registry.c
#wayland/wl_seat.c
#wayland/wl_output.c

wayland/backend.c
wayland/registry.c
wayland/wl_seat.c
wayland/output.c
drm/backend.c
drm/drm.c

Expand Down
4 changes: 4 additions & 0 deletions backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <wlr/backend/interface.h>
#include <wlr/backend/drm.h>
#include <wlr/backend/libinput.h>
#include <wlr/backend/wayland.h>
#include <wlr/backend/multi.h>
#include "backend/libinput.h"
#include "backend/udev.h"
Expand Down Expand Up @@ -42,6 +43,9 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
struct wlr_session *session) {
// TODO: Choose the most appropriate backend for the situation
// Attempt DRM+libinput
if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY")) {
return wlr_wl_backend_create(display, 1);
}
struct wlr_udev *udev;
if (!(udev = wlr_udev_create(display))) {
wlr_log(L_ERROR, "Failed to start udev");
Expand Down
1 change: 1 addition & 0 deletions backend/drm/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ static bool wlr_drm_output_set_mode(struct wlr_output_state *output,
output->width = output->wlr_output->width = mode->width;
output->height = output->wlr_output->height = mode->height;
output->wlr_output->current_mode = mode;
wl_signal_emit(&output->wlr_output->events.resolution, output->wlr_output);

if (!display_init_renderer(&state->renderer, output)) {
wlr_log(L_ERROR, "Failed to initalise renderer for %s", output->wlr_output->name);
Expand Down
18 changes: 13 additions & 5 deletions backend/egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "backend/egl.h"
#include "common/log.h"

static const char *egl_error(void) {
const char *egl_error(void) {
switch (eglGetError()) {
case EGL_SUCCESS:
return "Success";
Expand Down Expand Up @@ -68,24 +68,31 @@ static bool egl_exts() {
return true;
}

static bool egl_get_config(EGLDisplay disp, EGLConfig *out) {
static bool egl_get_config(EGLDisplay disp, EGLConfig *out, EGLenum platform) {
EGLint count = 0, matched = 0, ret;

ret = eglGetConfigs(disp, NULL, 0, &count);
if (ret == EGL_FALSE || count == 0) {
wlr_log(L_ERROR, "eglGetConfigs returned no configs");
return false;
}

EGLConfig configs[count];

ret = eglChooseConfig(disp, NULL, configs, count, &matched);
if (ret == EGL_FALSE) {
wlr_log(L_ERROR, "eglChooseConfig failed");
return false;
}

for (int i = 0; i < matched; ++i) {
EGLint gbm_format;

if(platform == EGL_PLATFORM_WAYLAND_EXT) {
*out = configs[i];
return true;
}

if (!eglGetConfigAttrib(disp,
configs[i],
EGL_NATIVE_VISUAL_ID,
Expand All @@ -101,6 +108,7 @@ static bool egl_get_config(EGLDisplay disp, EGLConfig *out) {
}
}

wlr_log(L_ERROR, "no valid egl config found");
return false;
}

Expand All @@ -109,7 +117,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) {
if (!egl_exts()) {
return false;
}

if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error());
goto error;
Expand All @@ -127,7 +135,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) {
goto error;
}

if (!egl_get_config(egl->display, &egl->config)) {
if (!egl_get_config(egl->display, &egl->config, platform)) {
wlr_log(L_ERROR, "Failed to get EGL config");
goto error;
}
Expand Down Expand Up @@ -163,7 +171,7 @@ void wlr_egl_free(struct wlr_egl *egl) {
eglDestroyContext(egl->display, egl->context);
eglTerminate(egl->display);
eglReleaseThread();
eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}

EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) {
Expand Down
155 changes: 121 additions & 34 deletions backend/wayland/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,145 @@
#include <stdint.h>
#include <wayland-server.h>
#include <assert.h>
#include <wlr/backend/interface.h>
#include <wlr/types.h>
#include "backend/wayland.h"
#include "common/log.h"
#include "types.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>

void wlr_wl_backend_free(struct wlr_wl_backend *backend) {
if (!backend) {
return;
static int dispatch_events(int fd, uint32_t mask, void *data) {
struct wlr_backend_state *state = data;
int count = 0;
if (mask & WL_EVENT_READABLE) {
count = wl_display_dispatch(state->remote_display);
}
// TODO: Free surfaces
for (size_t i = 0; backend->outputs && i < backend->outputs->length; ++i) {
struct wlr_wl_output *output = backend->outputs->items[i];
wlr_wl_output_free(output);
}
list_free(backend->outputs);
if (backend->seat) wlr_wl_seat_free(backend->seat);
if (backend->shm) wl_shm_destroy(backend->shm);
if (backend->shell) wl_shell_destroy(backend->shell);
if (backend->compositor) wl_compositor_destroy(backend->compositor);
if (backend->registry) wl_registry_destroy(backend->registry);
if (backend->remote_display) wl_display_disconnect(backend->remote_display);
free(backend);
if (mask & WL_EVENT_WRITABLE) {
count = wl_display_flush(state->remote_display);
}
if (mask == 0) {
count = wl_display_dispatch_pending(state->remote_display);
wl_display_flush(state->remote_display);
}
return count;
}

/*
* Initializes the wayland backend. Opens a connection to a remote wayland
* compositor and creates surfaces for each output, then registers globals on
* the specified display.
*/
struct wlr_wl_backend *wlr_wl_backend_init(
struct wl_display *display, size_t outputs) {
assert(display);
struct wlr_wl_backend *backend;
if (!(backend = calloc(sizeof(struct wlr_wl_backend), 1))) {
wlr_log(L_ERROR, "Could not allocate backend");
goto error;
static bool wlr_wl_backend_init(struct wlr_backend_state* state) {
wlr_log(L_INFO, "Initializating wayland backend");

state->remote_display = wl_display_connect(getenv("_WAYLAND_DISPLAY"));
if (!state->remote_display) {
wlr_log_errno(L_ERROR, "Could not connect to remote display");
return false;
}
if (!(backend->outputs = list_create())) {
wlr_log(L_ERROR, "Could not allocate output list");
goto error;

if (!(state->registry = wl_display_get_registry(state->remote_display))) {
wlr_log_errno(L_ERROR, "Could not obtain reference to remote registry");
return false;
}

wlr_wl_registry_poll(state);
if (!(state->compositor) || (!(state->shell))) {
wlr_log_errno(L_ERROR, "Could not obtain retrieve required globals");
return false;
}

wlr_egl_init(&state->egl, EGL_PLATFORM_WAYLAND_EXT, state->remote_display);
for (size_t i = 0; i < state->num_outputs; ++i) {
if(!(state->outputs[i] = wlr_wl_output_create(state, i))) {
wlr_log_errno(L_ERROR, "Failed to create %zuth output", i);
return false;
}
}

struct wl_event_loop *loop = wl_display_get_event_loop(state->local_display);
int fd = wl_display_get_fd(state->remote_display);
int events = WL_EVENT_READABLE | WL_EVENT_ERROR |
WL_EVENT_HANGUP | WL_EVENT_WRITABLE;
state->remote_display_src = wl_event_loop_add_fd(loop, fd, events,
dispatch_events, state);
wl_event_source_check(state->remote_display_src);

return true;
}

static void wlr_wl_backend_destroy(struct wlr_backend_state *state) {
if (!state) {
return;
}

for (size_t i = 0; i < state->num_outputs; ++i) {
wlr_output_destroy(state->outputs[i]);
}
backend->local_display = display;
backend->remote_display = wl_display_connect(getenv("_WAYLAND_DISPLAY"));
if (!backend->remote_display) {
wlr_log(L_ERROR, "Could not connect to remote display");

for (size_t i = 0; state->devices && i < state->devices->length; ++i) {
wlr_input_device_destroy(state->devices->items[i]);
}

list_free(state->devices);

wlr_egl_free(&state->egl);
free(state->outputs);
if (state->seat) wl_seat_destroy(state->seat);
if (state->shm) wl_shm_destroy(state->shm);
if (state->shell) wl_shell_destroy(state->shell);
if (state->compositor) wl_compositor_destroy(state->compositor);
if (state->registry) wl_registry_destroy(state->registry);
if (state->remote_display) wl_display_disconnect(state->remote_display);
free(state);
}

static struct wlr_backend_impl backend_impl = {
.init = wlr_wl_backend_init,
.destroy = wlr_wl_backend_destroy
};


struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
size_t num_outputs) {
wlr_log(L_INFO, "Creating wayland backend");

struct wlr_backend_state *state = calloc(1, sizeof(struct wlr_backend_state));
if (!state) {
wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno));
return NULL;
}

struct wlr_backend *backend = wlr_backend_create(&backend_impl, state);
if (!backend) {
wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno));
return NULL;
}

if (!(state->devices = list_create())) {
wlr_log(L_ERROR, "Could not allocate devices list");
goto error;
}
if (!(backend->registry = wl_display_get_registry(backend->remote_display))) {
wlr_log(L_ERROR, "Could not obtain reference to remote registry");

if (!(state->outputs = calloc(sizeof(void*), num_outputs))) {
wlr_log(L_ERROR, "Could not allocate outputs list");
goto error;
}
wlr_wlb_registry_poll(backend);

state->local_display = display;
state->backend = backend;
state->num_outputs = num_outputs;

return backend;

error:
wlr_wl_backend_free(backend);
if (state) {
free(state->outputs);
free(state->devices);
free(state->devices);
}
free(state);
free(backend);
return NULL;
}
Loading