From 50ce35e9da4e2604b0adb15703cfcd87204472e5 Mon Sep 17 00:00:00 2001 From: nyorain Date: Tue, 20 Jun 2017 18:27:05 +0200 Subject: [PATCH] Implement wayland backend output --- backend/wayland/backend.c | 27 +++++++++++- backend/wayland/output.c | 88 +++++++++++++++++++++++++++++++++++++-- include/backend/wayland.h | 6 +++ 3 files changed, 117 insertions(+), 4 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 6d3e2f32..e57cfed9 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -9,6 +9,23 @@ #include #include +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); + 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 @@ -34,7 +51,7 @@ static bool wlr_wl_backend_init(struct wlr_backend_state* state) { return false; } - wlr_egl_init(&state->egl, EGL_PLATFORM_WAYLAND_KHR, state->remote_display); + 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); @@ -42,6 +59,14 @@ static bool wlr_wl_backend_init(struct wlr_backend_state* state) { } } + 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; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index e6c7cf99..f8751c3c 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -1,19 +1,70 @@ +#include #include #include #include #include #include +#include #include "types.h" #include "backend/wayland.h" #include "common/log.h" -// TODO +static struct wl_callback_listener frame_listener; + +static void surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) { + struct wlr_output_state *output = data; + assert(output); + + if (!eglMakeCurrent(output->backend->egl.display, + output->egl_surface, output->egl_surface, + output->backend->egl.context)) { + wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + return; + } + + wl_signal_emit(&output->output->events.frame, output->output); + output->frame_callback = wl_surface_frame(output->surface); + wl_callback_add_listener(output->frame_callback, &frame_listener, output); + wl_callback_destroy(cb); + + if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { + wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + return; + } +} + +static struct wl_callback_listener frame_listener = { + .done = surface_frame_callback +}; + +// TODO: enable/cursor etc static void wlr_wl_output_enable(struct wlr_output_state *output, bool enable) { } static bool wlr_wl_output_set_mode(struct wlr_output_state *output, struct wlr_output_mode *mode) { output->output->current_mode = mode; + + // start rendering loop per callbacks by rendering first frame + if (!eglMakeCurrent(output->backend->egl.display, + output->egl_surface, output->egl_surface, + output->backend->egl.context)) { + wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + return false; + } + + glViewport(0, 0, output->width, output->height); + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + output->frame_callback = wl_surface_frame(output->surface); + wl_callback_add_listener(output->frame_callback, &frame_listener, output); + + if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { + wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + return false; + } + return true; } @@ -47,11 +98,32 @@ static struct wlr_output_impl output_impl = { .destroy = wlr_wl_output_destroy, }; +void handle_ping(void* data, struct wl_shell_surface* ssurface, uint32_t serial) { + struct wlr_output_state *output = data; + assert(output && output->shell_surface == ssurface); + wl_shell_surface_pong(ssurface, serial); +} + +void handle_configure(void *data, struct wl_shell_surface *wl_shell_surface, + uint32_t edges, int32_t width, int32_t height){ + wlr_log(L_DEBUG, "resize %d %d", width, height); +} + +void handle_popup_done(void *data, struct wl_shell_surface *wl_shell_surface) { + wlr_log(L_ERROR, "Unexpected call"); +} + +static struct wl_shell_surface_listener shell_surface_listener = { + .ping = handle_ping, + .configure = handle_configure, + .popup_done = handle_popup_done +}; + struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, size_t id) { // TODO: dont hardcode stuff like size - static unsigned int width = 1100; - static unsigned int height = 720; + static unsigned int width = 800; + static unsigned int height = 500; struct wlr_output_state *ostate; if (!(ostate = calloc(sizeof(struct wlr_output_state), 1))) { @@ -82,9 +154,19 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, list_add(wlr_output->modes, &mode); ostate->id = id; + ostate->width = width; + ostate->height = height; + ostate->backend = backend; ostate->output = wlr_output; + + // TODO: error handling ostate->surface = wl_compositor_create_surface(backend->compositor); ostate->shell_surface = wl_shell_get_shell_surface(backend->shell, ostate->surface); + + wl_shell_surface_set_class(ostate->shell_surface, "sway"); + wl_shell_surface_set_title(ostate->shell_surface, "sway-wl"); + wl_shell_surface_add_listener(ostate->shell_surface, &shell_surface_listener, ostate); + ostate->egl_window = wl_egl_window_create(ostate->surface, width, height); ostate->egl_surface = wlr_egl_create_surface(&backend->egl, ostate->egl_window); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 4cad565d..d2f1fb1d 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -23,6 +23,8 @@ struct wlr_backend_state { struct wlr_backend *backend; list_t *devices; + struct wl_event_source* remote_display_src; + size_t num_outputs; struct wlr_output **outputs; struct wlr_egl egl; @@ -30,10 +32,14 @@ struct wlr_backend_state { struct wlr_output_state { size_t id; + unsigned int width; + unsigned int height; + struct wlr_backend_state *backend; struct wlr_output *output; struct wl_surface *surface; struct wl_shell_surface *shell_surface; struct wl_egl_window* egl_window; + struct wl_callback* frame_callback; void* egl_surface; };