From b9d36c8149536cff1aa229f59337dcfa2f70a37b Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 20 Jun 2017 17:51:45 -0400 Subject: [PATCH] Add dynamic output resizing for Wayland backend This allows outputs to: - Not support modesetting - Resize themselves --- backend/drm/drm.c | 1 + backend/wayland/backend.c | 9 ++-- backend/wayland/output.c | 98 ++++++++++++++------------------------- example/pointer.c | 17 ++++--- example/rotation.c | 13 +++--- example/shared.c | 4 +- include/backend/wayland.h | 2 - include/types.h | 1 + include/wlr/types.h | 2 + types/wlr_output.c | 18 ++++++- 10 files changed, 75 insertions(+), 90 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index befbfb94..5afdf3c3 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -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); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 9623a168..344cc35d 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -12,18 +12,17 @@ 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) + if (mask & WL_EVENT_READABLE) { count = wl_display_dispatch(state->remote_display); - if(mask & WL_EVENT_WRITABLE) + } + 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; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index ee977415..de4d2f4d 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -38,49 +38,9 @@ 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; -} - static void wlr_wl_output_transform(struct wlr_output_state *output, enum wl_output_transform transform) { -} - -static bool wlr_wl_output_set_cursor(struct wlr_output_state *output, - const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height) { - return false; -} - -static bool wlr_wl_output_move_cursor(struct wlr_output_state *output, - int x, int y) { - return false; + // TODO } static void wlr_wl_output_destroy(struct wlr_output_state *output) { @@ -93,11 +53,7 @@ static void wlr_wl_output_destroy(struct wlr_output_state *output) { } static struct wlr_output_impl output_impl = { - .enable = wlr_wl_output_enable, - .set_mode = wlr_wl_output_set_mode, .transform = wlr_wl_output_transform, - .set_cursor = wlr_wl_output_set_cursor, - .move_cursor = wlr_wl_output_move_cursor, .destroy = wlr_wl_output_destroy, }; @@ -109,11 +65,18 @@ void handle_ping(void* data, struct wl_shell_surface* ssurface, uint32_t 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); + struct wlr_output_state *ostate = data; + assert(ostate && ostate->shell_surface == wl_shell_surface); + struct wlr_output *output = ostate->output; + wl_egl_window_resize(ostate->egl_window, width, height, 0, 0); + output->width = width; + output->height = height; + wlr_output_update_matrix(output); + wl_signal_emit(&output->events.resolution, output); } void handle_popup_done(void *data, struct wl_shell_surface *wl_shell_surface) { - wlr_log(L_ERROR, "Unexpected call"); + wlr_log(L_ERROR, "Unexpected wl_shell_surface.popup_done event"); } static struct wl_shell_surface_listener shell_surface_listener = { @@ -124,10 +87,6 @@ static struct wl_shell_surface_listener shell_surface_listener = { 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 = 800; - static unsigned int height = 500; - struct wlr_output_state *ostate; if (!(ostate = calloc(sizeof(struct wlr_output_state), 1))) { wlr_log(L_ERROR, "Failed to allocate wlr_output_state"); @@ -141,24 +100,14 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, return NULL; } - wlr_output->width = width; - wlr_output->height = height; + wlr_output->width = 640; + wlr_output->height = 480; wlr_output->scale = 1; strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make)); strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%d", 1); - struct wlr_output_mode mode = { - .width = width, - .height = height, - .refresh = 60, - .flags = 0, - }; - list_add(wlr_output->modes, &mode); - ostate->id = id; - ostate->width = width; - ostate->height = height; ostate->backend = backend; ostate->output = wlr_output; @@ -171,9 +120,30 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend_state* backend, wl_shell_surface_add_listener(ostate->shell_surface, &shell_surface_listener, ostate); wl_shell_surface_set_toplevel(ostate->shell_surface); - ostate->egl_window = wl_egl_window_create(ostate->surface, width, height); + ostate->egl_window = wl_egl_window_create(ostate->surface, + wlr_output->width, wlr_output->height); ostate->egl_surface = wlr_egl_create_surface(&backend->egl, ostate->egl_window); + // start rendering loop per callbacks by rendering first frame + if (!eglMakeCurrent(ostate->backend->egl.display, + ostate->egl_surface, ostate->egl_surface, + ostate->backend->egl.context)) { + wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + return false; + } + + glViewport(0, 0, wlr_output->width, wlr_output->height); + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + ostate->frame_callback = wl_surface_frame(ostate->surface); + wl_callback_add_listener(ostate->frame_callback, &frame_listener, ostate); + + if (!eglSwapBuffers(ostate->backend->egl.display, ostate->egl_surface)) { + wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + return false; + } + wl_signal_emit(&backend->backend->events.output_add, wlr_output); return wlr_output; } diff --git a/example/pointer.c b/example/pointer.c index 1da77b85..8735c61e 100644 --- a/example/pointer.c +++ b/example/pointer.c @@ -110,15 +110,14 @@ int main(int argc, char *argv[]) { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, .clear_color = { 0.25f, 0.25f, 0.25f, 1 } }; - struct compositor_state compositor = { 0, - .data = &state, - .output_add_cb = handle_output_add, - .output_frame_cb = handle_output_frame, - .keyboard_key_cb = handle_keyboard_key, - .pointer_motion_cb = handle_pointer_motion, - .pointer_button_cb = handle_pointer_button, - .pointer_axis_cb = handle_pointer_axis, - }; + struct compositor_state compositor = { 0 }; + compositor.data = &state; + compositor.output_add_cb = handle_output_add; + compositor.output_frame_cb = handle_output_frame; + compositor.keyboard_key_cb = handle_keyboard_key; + compositor.pointer_motion_cb = handle_pointer_motion; + compositor.pointer_button_cb = handle_pointer_button; + compositor.pointer_axis_cb = handle_pointer_axis; compositor_init(&compositor); state.renderer = wlr_gles3_renderer_init(); diff --git a/example/rotation.c b/example/rotation.c index a1c77013..d7b6b169 100644 --- a/example/rotation.c +++ b/example/rotation.c @@ -197,13 +197,12 @@ int main(int argc, char *argv[]) { wl_list_init(&state.config); parse_args(argc, argv, &state.config); - struct compositor_state compositor = { 0, - .data = &state, - .output_add_cb = handle_output_add, - .output_remove_cb = handle_output_remove, - .output_frame_cb = handle_output_frame, - .keyboard_key_cb = handle_keyboard_key, - }; + struct compositor_state compositor = { 0 }; + compositor.data = &state; + compositor.output_add_cb = handle_output_add; + compositor.output_remove_cb = handle_output_remove; + compositor.output_frame_cb = handle_output_frame; + compositor.keyboard_key_cb = handle_keyboard_key; compositor_init(&compositor); state.renderer = wlr_gles3_renderer_init(); diff --git a/example/shared.c b/example/shared.c index 0fe7270f..6af3042b 100644 --- a/example/shared.c +++ b/example/shared.c @@ -383,7 +383,9 @@ static void output_add_notify(struct wl_listener *listener, void *data) { fprintf(stderr, "Output '%s' added\n", output->name); fprintf(stderr, "%s %s %"PRId32"mm x %"PRId32"mm\n", output->make, output->model, output->phys_width, output->phys_height); - wlr_output_set_mode(output, output->modes->items[0]); + if (output->modes->length > 0) { + wlr_output_set_mode(output, output->modes->items[0]); + } struct output_state *ostate = calloc(1, sizeof(struct output_state)); clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame); ostate->output = output; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index d2f1fb1d..03667c9a 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -32,8 +32,6 @@ 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; diff --git a/include/types.h b/include/types.h index 54aa5606..f53cac02 100644 --- a/include/types.h +++ b/include/types.h @@ -20,6 +20,7 @@ struct wlr_output_impl { struct wlr_output *wlr_output_create(struct wlr_output_impl *impl, struct wlr_output_state *state); void wlr_output_free(struct wlr_output *output); +void wlr_output_update_matrix(struct wlr_output *output); struct wlr_keyboard_impl { void (*destroy)(struct wlr_keyboard_state *state); diff --git a/include/wlr/types.h b/include/wlr/types.h index 1d2abab5..6b6a3389 100644 --- a/include/wlr/types.h +++ b/include/wlr/types.h @@ -33,11 +33,13 @@ struct wlr_output { float transform_matrix[16]; + /* Note: some backends may have zero modes */ list_t *modes; struct wlr_output_mode *current_mode; struct { struct wl_signal frame; + struct wl_signal resolution; } events; }; diff --git a/types/wlr_output.c b/types/wlr_output.c index 8c21f706..28996fa7 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -65,6 +65,10 @@ static void set_matrix(float mat[static 16], int32_t width, int32_t height, mat[15] = 1.0f; } +void wlr_output_update_matrix(struct wlr_output *output) { + set_matrix(output->transform_matrix, output->width, output->height, output->transform); +} + struct wlr_output *wlr_output_create(struct wlr_output_impl *impl, struct wlr_output_state *state) { struct wlr_output *output = calloc(1, sizeof(struct wlr_output)); @@ -73,6 +77,7 @@ struct wlr_output *wlr_output_create(struct wlr_output_impl *impl, output->modes = list_create(); output->transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_signal_init(&output->events.frame); + wl_signal_init(&output->events.resolution); return output; } @@ -81,22 +86,31 @@ void wlr_output_enable(struct wlr_output *output, bool enable) { } bool wlr_output_set_mode(struct wlr_output *output, struct wlr_output_mode *mode) { - set_matrix(output->transform_matrix, mode->width, mode->height, output->transform); + if (!output->impl || !output->impl->set_mode) { + return false; + } + wlr_output_update_matrix(output); return output->impl->set_mode(output->state, mode); } void wlr_output_transform(struct wlr_output *output, enum wl_output_transform transform) { - set_matrix(output->transform_matrix, output->width, output->height, transform); + wlr_output_update_matrix(output); output->impl->transform(output->state, transform); } bool wlr_output_set_cursor(struct wlr_output *output, const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height) { + if (!output->impl || !output->impl->set_cursor) { + return false; + } return output->impl->set_cursor(output->state, buf, stride, width, height); } bool wlr_output_move_cursor(struct wlr_output *output, int x, int y) { + if (!output->impl || !output->impl->move_cursor) { + return false; + } return output->impl->move_cursor(output->state, x, y); }