From bd387da62d78f25027f1f80d25d85970fd09c235 Mon Sep 17 00:00:00 2001 From: Tobias Langendorf Date: Sat, 18 Jul 2020 21:37:02 +0200 Subject: [PATCH 001/223] xwm: add support for xwayland minimize --- include/wlr/xwayland.h | 10 ++++++ include/xwayland/xwm.h | 2 ++ xwayland/xwm.c | 70 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 03201718c..26a14aea6 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -173,6 +173,7 @@ struct wlr_xwayland_surface { bool modal; bool fullscreen; bool maximized_vert, maximized_horz; + bool minimized; bool has_alpha; @@ -181,6 +182,7 @@ struct wlr_xwayland_surface { struct wl_signal request_configure; struct wl_signal request_move; struct wl_signal request_resize; + struct wl_signal request_minimize; struct wl_signal request_maximize; struct wl_signal request_fullscreen; struct wl_signal request_activate; @@ -221,6 +223,11 @@ struct wlr_xwayland_resize_event { uint32_t edges; }; +struct wlr_xwayland_minimize_event { + struct wlr_xwayland_surface *surface; + bool minimize; +}; + struct wlr_xwayland_server *wlr_xwayland_server_create( struct wl_display *display, struct wlr_xwayland_server_options *options); void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server); @@ -250,6 +257,9 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *surface, void wlr_xwayland_surface_close(struct wlr_xwayland_surface *surface); +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized); + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized); diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 2569092fa..1085cb14e 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -44,7 +44,9 @@ enum atom_name { NET_WM_STATE_FULLSCREEN, NET_WM_STATE_MAXIMIZED_VERT, NET_WM_STATE_MAXIMIZED_HORZ, + NET_WM_STATE_HIDDEN, NET_WM_PING, + WM_CHANGE_STATE, WM_STATE, CLIPBOARD, PRIMARY, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 28e329f39..a3fb61b42 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -42,7 +42,9 @@ const char *atom_map[ATOM_LAST] = { [NET_WM_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN", [NET_WM_STATE_MAXIMIZED_VERT] = "_NET_WM_STATE_MAXIMIZED_VERT", [NET_WM_STATE_MAXIMIZED_HORZ] = "_NET_WM_STATE_MAXIMIZED_HORZ", + [NET_WM_STATE_HIDDEN] = "_NET_WM_STATE_HIDDEN", [NET_WM_PING] = "_NET_WM_PING", + [WM_CHANGE_STATE] = "WM_CHANGE_STATE", [WM_STATE] = "WM_STATE", [CLIPBOARD] = "CLIPBOARD", [PRIMARY] = "PRIMARY", @@ -146,6 +148,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.request_configure); wl_signal_init(&surface->events.request_move); wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.request_maximize); wl_signal_init(&surface->events.request_fullscreen); wl_signal_init(&surface->events.request_activate); @@ -290,7 +293,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[4]; + uint32_t property[5]; int i; i = 0; @@ -306,6 +309,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->maximized_horz) { property[i++] = xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]; } + if (xsurface->minimized) { + property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; + } xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, @@ -664,6 +670,8 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm, xsurface->maximized_vert = true; } else if (atom[i] == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ]) { xsurface->maximized_horz = true; + } else if (atom[i] == xwm->atoms[NET_WM_STATE_HIDDEN]) { + xsurface->minimized = true; } } } @@ -1126,6 +1134,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, bool fullscreen = xsurface->fullscreen; bool maximized = xsurface_is_maximized(xsurface); + bool minimized = xsurface->minimized; uint32_t action = client_message->data.data32[0]; for (size_t i = 0; i < 2; ++i) { @@ -1143,6 +1152,9 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, } else if (property == xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ] && update_state(action, &xsurface->maximized_horz)) { xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[NET_WM_STATE_HIDDEN] && + update_state(action, &xsurface->minimized)) { + xsurface_set_net_wm_state(xsurface); } } // client_message->data.data32[3] is the source indication @@ -1165,6 +1177,19 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.request_maximize, xsurface); } + + if (minimized != xsurface->minimized) { + if (xsurface->minimized) { + xsurface->saved_width = xsurface->width; + xsurface->saved_height = xsurface->height; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = xsurface->minimized, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); + } } static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, @@ -1202,6 +1227,32 @@ static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, wlr_signal_emit_safe(&surface->events.request_activate, surface); } +static void xwm_handle_wm_change_state_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window); + uint32_t detail = ev->data.data32[0]; + + if (xsurface == NULL) { + return; + } + + bool minimize; + if (detail == ICCCM_ICONIC_STATE) { + minimize = true; + } else if (detail == ICCCM_NORMAL_STATE) { + minimize = false; + } else { + wlr_log(WLR_DEBUG, "unhandled wm_change_state event %u", detail); + return; + } + + struct wlr_xwayland_minimize_event minimize_event = { + .surface = xsurface, + .minimize = minimize, + }; + wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); +} + static void xwm_handle_client_message(struct wlr_xwm *xwm, xcb_client_message_event_t *ev) { wlr_log(WLR_DEBUG, "XCB_CLIENT_MESSAGE (%u)", ev->window); @@ -1216,6 +1267,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_wm_protocols_message(xwm, ev); } else if (ev->type == xwm->atoms[NET_ACTIVE_WINDOW]) { xwm_handle_net_active_window_message(xwm, ev); + } else if (ev->type == xwm->atoms[WM_CHANGE_STATE]) { + xwm_handle_wm_change_state_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, @@ -1768,6 +1821,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->atoms[NET_WM_STATE_FULLSCREEN], xwm->atoms[NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[NET_WM_STATE_MAXIMIZED_HORZ], + xwm->atoms[NET_WM_STATE_HIDDEN], xwm->atoms[NET_CLIENT_LIST], }; xcb_change_property(xwm->xcb_conn, @@ -1799,6 +1853,20 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { return xwm; } +void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface, + bool minimized) { + surface->minimized = minimized; + + if (minimized) { + xsurface_set_wm_state(surface, ICCCM_ICONIC_STATE); + } else { + xsurface_set_wm_state(surface, ICCCM_NORMAL_STATE); + } + + xsurface_set_net_wm_state(surface); + xcb_flush(surface->xwm->xcb_conn); +} + void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface, bool maximized) { surface->maximized_horz = maximized; From 9686895b4e6b1e44132389b57b958f8885d97d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Tue, 21 Jul 2020 17:46:33 +0200 Subject: [PATCH 002/223] Fix typos --- examples/output-power-management.c | 2 +- include/backend/drm/drm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/output-power-management.c b/examples/output-power-management.c index 8d91c6c05..43e7c53f6 100644 --- a/examples/output-power-management.c +++ b/examples/output-power-management.c @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) { if (output_power_manager == NULL) { fprintf(stderr, - "compositor doesn't support wlr-output-power-managment-unstable-v1\n"); + "compositor doesn't support wlr-output-power-management-unstable-v1\n"); return EXIT_FAILURE; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index c56850791..80bc76698 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -134,7 +134,7 @@ struct wlr_drm_connector { struct wl_list link; /* - * We've asked for a state change in the kernel, and yet to recieve a + * We've asked for a state change in the kernel, and yet to receive a * notification for its completion. Currently, the kernel only has a * queue length of 1, and no way to modify your submissions after * they're sent. From cd4827b3b6f2b8b47562e58c4dc8669a0976c282 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 12:05:04 +0200 Subject: [PATCH 003/223] xwayland/xwm: don't insert surface in list on error In case wl_event_loop_add_timer errors out, don't insert the free'd wlr_xwayland_surface in the list. Closes: https://github.com/swaywm/wlroots/issues/1721 --- xwayland/xwm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a3fb61b42..50a859851 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -141,7 +141,6 @@ static struct wlr_xwayland_surface *xwayland_surface_create( surface->width = width; surface->height = height; surface->override_redirect = override_redirect; - wl_list_insert(&xwm->surfaces, &surface->link); wl_list_init(&surface->children); wl_list_init(&surface->parent_link); wl_signal_init(&surface->events.destroy); @@ -182,6 +181,8 @@ static struct wlr_xwayland_surface *xwayland_surface_create( return NULL; } + wl_list_insert(&xwm->surfaces, &surface->link); + wlr_signal_emit_safe(&xwm->xwayland->events.new_surface, surface); return surface; From 13f35139d39f3ec40f1f7a20ae15161ef04f03bd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 13:15:00 +0200 Subject: [PATCH 004/223] xwayland/xwm: add prop count assert in xsurface_set_net_wm_state This helps mitigate buffer overflows. --- xwayland/xwm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 50a859851..a34d56a27 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -294,10 +294,9 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[5]; - int i; - i = 0; + uint32_t property[5]; + size_t i = 0; if (xsurface->modal) { property[i++] = xwm->atoms[NET_WM_STATE_MODAL]; } @@ -313,6 +312,7 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->minimized) { property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; } + assert(i <= sizeof(property) / sizeof(property[0])); xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, From c72efcd1ce070dc5a55625de1b0ef2c6630ce8dc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Jul 2020 13:16:28 +0200 Subject: [PATCH 005/223] xwayland/xwm: use initializer for props in xsurface_set_wm_state This avoids uninitialized items and makes it clear where the magic number 2 is coming from. --- xwayland/xwm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a34d56a27..e10503081 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -913,10 +913,7 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, static void xsurface_set_wm_state(struct wlr_xwayland_surface *xsurface, int32_t state) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[2]; - - property[0] = state; - property[1] = XCB_WINDOW_NONE; + uint32_t property[] = { state, XCB_WINDOW_NONE }; xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, @@ -924,7 +921,7 @@ static void xsurface_set_wm_state(struct wlr_xwayland_surface *xsurface, xwm->atoms[WM_STATE], xwm->atoms[WM_STATE], 32, // format - 2, property); + sizeof(property) / sizeof(property[0]), property); } static void xwm_handle_map_request(struct wlr_xwm *xwm, From 39fd2335bf47ca33e28f61ec7a194c15a9ecc61e Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sun, 26 Jul 2020 20:21:53 -0700 Subject: [PATCH 006/223] virtual_pointer: remember current axis for axis events --- types/wlr_virtual_pointer_v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index aed3647be..75238447f 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -103,7 +103,8 @@ static void virtual_pointer_axis(struct wl_client *client, return; } struct wlr_input_device *wlr_dev = &pointer->input_device; - pointer->axis_valid[axis] = true; + pointer->axis = axis; + pointer->axis_valid[pointer->axis] = true; pointer->axis_event[pointer->axis].device = wlr_dev; pointer->axis_event[pointer->axis].time_msec = time; pointer->axis_event[pointer->axis].orientation = axis; From d9bb792794ce476ac79fdc0971fc01aeb3e5c8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 14:33:32 +0200 Subject: [PATCH 007/223] Fix incorrect format parameters --- backend/drm/drm.c | 2 +- backend/session/logind.c | 2 +- backend/wayland/backend.c | 2 +- types/seat/wlr_seat_keyboard.c | 4 ++-- types/wlr_compositor.c | 6 +++--- types/wlr_layer_shell_v1.c | 8 ++++---- types/wlr_linux_dmabuf_v1.c | 4 ++-- types/wlr_surface.c | 8 ++++---- types/wlr_virtual_pointer_v1.c | 8 ++++---- xcursor/wlr_xcursor.c | 4 ++-- xwayland/selection/dnd.c | 4 ++-- xwayland/selection/outgoing.c | 6 +++--- xwayland/xwm.c | 30 ++++++++++++++++-------------- 13 files changed, 45 insertions(+), 43 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 6978c22c1..7ecc28d39 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -800,7 +800,7 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn, return false; } - wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", + wlr_log(WLR_INFO, "Modesetting '%s' with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'", conn->output.name, wlr_mode->width, wlr_mode->height, wlr_mode->refresh); diff --git a/backend/session/logind.c b/backend/session/logind.c index b5acd4e4d..00babcae0 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -142,7 +142,7 @@ static bool logind_change_vt(struct wlr_session *base, unsigned vt) { "/org/freedesktop/login1/seat/seat0", "org.freedesktop.login1.Seat", "SwitchTo", &error, &msg, "u", (uint32_t)vt); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to change to vt '%d'", vt); + wlr_log(WLR_ERROR, "Failed to change to vt '%u'", vt); } sd_bus_error_free(&error); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 8de63acf7..972963e0f 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -97,7 +97,7 @@ static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *iface, uint32_t version) { struct wlr_wl_backend *wl = data; - wlr_log(WLR_DEBUG, "Remote wayland global: %s v%d", iface, version); + wlr_log(WLR_DEBUG, "Remote wayland global: %s v%" PRIu32, iface, version); if (strcmp(iface, wl_compositor_interface.name) == 0) { wl->compositor = wl_registry_bind(registry, name, diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 715bd4ba1..5328de82f 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -267,7 +267,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, for (size_t i = 0; i < num_keycodes; ++i) { uint32_t *p = wl_array_add(&keys, sizeof(uint32_t)); if (!p) { - wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n", + wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n", keycodes[i]); continue; } @@ -449,7 +449,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, for (size_t i = 0; i < num_keycodes; ++i) { uint32_t *p = wl_array_add(&keys, sizeof(uint32_t)); if (!p) { - wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n", + wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n", keycodes[i]); continue; } diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 11f22923e..d49dcc18d 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -39,7 +39,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, if (surface == parent) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d cannot be its own parent", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " cannot be its own parent", msg, id, wl_resource_get_id(surface_resource)); return; } @@ -48,7 +48,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, wlr_subsurface_from_wlr_surface(surface) != NULL) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is already a sub-surface", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is already a sub-surface", msg, id, wl_resource_get_id(surface_resource)); return; } @@ -56,7 +56,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client, if (wlr_surface_get_root_surface(parent) == surface) { wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is an ancestor of parent", + "%s%" PRIu32 ": wl_surface@%" PRIu32 " is an ancestor of parent", msg, id, wl_resource_get_id(surface_resource)); return; } diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 0002f4cbf..db2113e3f 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -74,7 +74,7 @@ static void layer_surface_handle_ack_configure(struct wl_client *client, if (!found) { wl_resource_post_error(resource, ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, - "wrong configure serial: %u", serial); + "wrong configure serial: %" PRIu32, serial); return; } // Then remove old configures from the list @@ -114,7 +114,7 @@ static void layer_surface_handle_set_anchor(struct wl_client *client, if (anchor > max_anchor) { wl_resource_post_error(resource, ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, - "invalid anchor %d", anchor); + "invalid anchor %" PRIu32, anchor); } struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); @@ -187,7 +187,7 @@ static void layer_surface_set_layer(struct wl_client *client, if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { wl_resource_post_error(surface->resource, ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, - "Invalid layer %d", layer); + "Invalid layer %" PRIu32, layer); return; } surface->client_pending.layer = layer; @@ -403,7 +403,7 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client, free(surface); wl_resource_post_error(client_resource, ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, - "Invalid layer %d", layer); + "Invalid layer %" PRIu32, layer); return; } surface->namespace = strdup(namespace); diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 7db99eb6c..acd4cb4c9 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -210,7 +210,7 @@ static void params_create_common(struct wl_client *client, if (buffer->attributes.offset[i] > size) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid offset %i for plane %d", + "invalid offset %" PRIu32 " for plane %d", buffer->attributes.offset[i], i); goto err_out; } @@ -219,7 +219,7 @@ static void params_create_common(struct wl_client *client, buffer->attributes.stride[i] == 0) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, - "invalid stride %i for plane %d", + "invalid stride %" PRIu32 " for plane %d", buffer->attributes.stride[i], i); goto err_out; } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f0a0b1fb1..1b623504b 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -712,7 +712,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface, if (surface->role != NULL && surface->role != role) { if (error_resource != NULL) { wl_resource_post_error(error_resource, error_code, - "Cannot assign role %s to wl_surface@%d, already has role %s\n", + "Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n", role->name, wl_resource_get_id(surface->resource), surface->role->name); } @@ -720,7 +720,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface, } if (surface->role_data != NULL && surface->role_data != role_data) { wl_resource_post_error(error_resource, error_code, - "Cannot reassign role %s to wl_surface@%d," + "Cannot reassign role %s to wl_surface@%" PRIu32 "," "role object still exists", role->name, wl_resource_get_id(surface->resource)); return false; @@ -791,7 +791,7 @@ static void subsurface_handle_place_above(struct wl_client *client, if (!sibling) { wl_resource_post_error(subsurface->resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%d is not a parent or sibling", + "%s: wl_surface@%" PRIu32 "is not a parent or sibling", "place_above", wl_resource_get_id(sibling_surface->resource)); return; } @@ -818,7 +818,7 @@ static void subsurface_handle_place_below(struct wl_client *client, if (!sibling) { wl_resource_post_error(subsurface->resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, - "%s: wl_surface@%d is not a parent or sibling", + "%s: wl_surface@%" PRIu32 " is not a parent or sibling", "place_below", wl_resource_get_id(sibling_surface->resource)); return; } diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index 75238447f..a9d1fd7bc 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -94,7 +94,7 @@ static void virtual_pointer_axis(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -140,7 +140,7 @@ static void virtual_pointer_axis_source(struct wl_client *client, if (source > WL_POINTER_AXIS_SOURCE_WHEEL_TILT) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS_SOURCE, - "Invalid enumeration value %d", source); + "Invalid enumeration value %" PRIu32, source); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -158,7 +158,7 @@ static void virtual_pointer_axis_stop(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = @@ -182,7 +182,7 @@ static void virtual_pointer_axis_discrete(struct wl_client *client, if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { wl_resource_post_error(resource, ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, - "Invalid enumeration value %d", axis); + "Invalid enumeration value %" PRIu32, axis); return; } struct wlr_virtual_pointer_v1 *pointer = diff --git a/xcursor/wlr_xcursor.c b/xcursor/wlr_xcursor.c index 4e1d02ecf..85e76a556 100644 --- a/xcursor/wlr_xcursor.c +++ b/xcursor/wlr_xcursor.c @@ -24,7 +24,7 @@ */ #define _POSIX_C_SOURCE 200809L -#include +#include #include #include #include @@ -245,7 +245,7 @@ struct wlr_xcursor_theme *wlr_xcursor_theme_load(const char *name, int size) { for (size_t i = 0; i < theme->cursor_count; ++i) { struct wlr_xcursor *c = theme->cursors[i]; struct wlr_xcursor_image *i = c->images[0]; - wlr_log(WLR_DEBUG, "%s (%u images) %dx%d+%d,%d", + wlr_log(WLR_DEBUG, "%s (%u images) %" PRIu32 "x%" PRIu32 "+%" PRIu32 ",%" PRIu32, c->name, c->image_count, i->width, i->height, i->hotspot_x, i->hotspot_y); } diff --git a/xwayland/selection/dnd.c b/xwayland/selection/dnd.c index ec5f16c7f..16941558a 100644 --- a/xwayland/selection/dnd.c +++ b/xwayland/selection/dnd.c @@ -192,7 +192,7 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, drag->source->accepted = accepted; wlr_data_source_dnd_action(drag->source, action); - wlr_log(WLR_DEBUG, "DND_STATUS window=%d accepted=%d action=%d", + wlr_log(WLR_DEBUG, "DND_STATUS window=%" PRIu32 " accepted=%d action=%d", target_window, accepted, action); return 1; } else if (ev->type == xwm->atoms[DND_FINISHED]) { @@ -226,7 +226,7 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, wlr_data_source_dnd_finish(source); } - wlr_log(WLR_DEBUG, "DND_FINISH window=%d performed=%d action=%d", + wlr_log(WLR_DEBUG, "DND_FINISH window=%" PRIu32 " performed=%d action=%d", target_window, performed, action); return 1; } else { diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 169f516e7..002c0143c 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -23,9 +23,9 @@ static void xwm_selection_send_notify(struct wlr_xwm *xwm, .property = success ? req->property : XCB_ATOM_NONE, }; - wlr_log(WLR_DEBUG, "SendEvent destination=%d SelectionNotify(31) time=%d " - "requestor=%d selection=%d target=%d property=%d", req->requestor, - req->time, req->requestor, req->selection, req->target, + wlr_log(WLR_DEBUG, "SendEvent destination=%" PRIu32 " SelectionNotify(31) time=%" PRIu32 + " requestor=%" PRIu32 " selection=%" PRIu32 " target=%" PRIu32 " property=%" PRIu32, + req->requestor, req->time, req->requestor, req->selection, req->target, selection_notify.property); xcb_send_event(xwm->xcb_conn, 0, // propagate diff --git a/xwayland/xwm.c b/xwayland/xwm.c index e10503081..692c0f8bb 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -393,8 +393,9 @@ static void read_surface_class(struct wlr_xwm *xwm, surface->class = NULL; } - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_CLASS: %s %s", surface->instance, - surface->class); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_CLASS: %s %s", + surface->instance ? surface->instance : "(null)", + surface->class ? surface->class : "(null)"); wlr_signal_emit_safe(&surface->events.set_class, surface); } @@ -416,7 +417,8 @@ static void read_surface_role(struct wlr_xwm *xwm, xsurface->role = NULL; } - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", xsurface->role); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_WINDOW_ROLE: %s", + xsurface->role ? xsurface->role : "(null)"); wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); } @@ -444,7 +446,7 @@ static void read_surface_title(struct wlr_xwm *xwm, } xsurface->has_utf8_title = is_utf8; - wlr_log(WLR_DEBUG, "XCB_ATOM_WM_NAME: %s", xsurface->title); + wlr_log(WLR_DEBUG, "XCB_ATOM_WM_NAME: %s", xsurface->title ? xsurface->title : "(null)"); wlr_signal_emit_safe(&xsurface->events.set_title, xsurface); } @@ -558,7 +560,7 @@ static void read_surface_hints(struct wlr_xwm *xwm, xsurface->hints->input = true; } - wlr_log(WLR_DEBUG, "WM_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "WM_HINTS (%" PRIu32 ")", reply->value_len); wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface); } #else @@ -610,7 +612,7 @@ static void read_surface_normal_hints(struct wlr_xwm *xwm, xsurface->size_hints->max_height = -1; } - wlr_log(WLR_DEBUG, "WM_NORMAL_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "WM_NORMAL_HINTS (%" PRIu32 ")", reply->value_len); } #else static void read_surface_normal_hints(struct wlr_xwm *xwm, @@ -654,7 +656,7 @@ static void read_surface_motif_hints(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.set_decorations, xsurface); } - wlr_log(WLR_DEBUG, "MOTIF_WM_HINTS (%d)", reply->value_len); + wlr_log(WLR_DEBUG, "MOTIF_WM_HINTS (%" PRIu32 ")", reply->value_len); } static void read_surface_net_wm_state(struct wlr_xwm *xwm, @@ -727,8 +729,8 @@ static void read_surface_property(struct wlr_xwm *xwm, read_surface_role(xwm, xsurface, reply); } else { char *prop_name = xwm_get_atom_name(xwm, property); - wlr_log(WLR_DEBUG, "unhandled X11 property %u (%s) for window %u", - property, prop_name, xsurface->window_id); + wlr_log(WLR_DEBUG, "unhandled X11 property %" PRIu32 " (%s) for window %" PRIu32, + property, prop_name ? prop_name : "(null)", xsurface->window_id); free(prop_name); } @@ -1210,8 +1212,8 @@ static void xwm_handle_wm_protocols_message(struct wlr_xwm *xwm, surface->pinging = false; } else { char *type_name = xwm_get_atom_name(xwm, type); - wlr_log(WLR_DEBUG, "unhandled WM_PROTOCOLS client message %u (%s)", - type, type_name); + wlr_log(WLR_DEBUG, "unhandled WM_PROTOCOLS client message %" PRIu32 " (%s)", + type, type_name ? type_name : "(null)"); free(type_name); } } @@ -1269,8 +1271,8 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_wm_change_state_message(xwm, ev); } else if (!xwm_handle_selection_client_message(xwm, ev)) { char *type_name = xwm_get_atom_name(xwm, ev->type); - wlr_log(WLR_DEBUG, "unhandled x11 client message %u (%s)", ev->type, - type_name); + wlr_log(WLR_DEBUG, "unhandled x11 client message %" PRIu32 " (%s)", ev->type, + type_name ? type_name : "(null)"); free(type_name); } } @@ -1596,7 +1598,7 @@ static void xwm_get_resources(struct wlr_xwm *xwm) { xfixes_reply = xcb_xfixes_query_version_reply(xwm->xcb_conn, xfixes_cookie, NULL); - wlr_log(WLR_DEBUG, "xfixes version: %d.%d", + wlr_log(WLR_DEBUG, "xfixes version: %" PRIu32 ".%" PRIu32, xfixes_reply->major_version, xfixes_reply->minor_version); free(xfixes_reply); From 1ae2d976c0798d5aaaaced277e931e7e18187536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 16:23:51 +0200 Subject: [PATCH 008/223] xwayland: free server in error path --- xwayland/xwayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index ccec7c670..4cb103af0 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -89,7 +89,7 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, }; xwayland->server = wlr_xwayland_server_create(wl_display, &options); if (xwayland->server == NULL) { - free(xwayland->server); + free(xwayland); return NULL; } From 6d0ee53e1a3d270b8b783ffbc50b1da621ef7880 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Mon, 27 Jul 2020 05:41:54 -0600 Subject: [PATCH 009/223] xwm: Set _NET_WM_STATE_FOCUSED property for the focused surface Certain clients require this property to be set for expected behavior. Most notably, steam client CSD maximize button no longer worked after unmaximizing once, unless the state was changed by another method. The state is unset whenever another surface gains focus. --- include/xwayland/xwm.h | 1 + xwayland/xwm.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 1085cb14e..a3e7132d9 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -40,6 +40,7 @@ enum atom_name { NET_ACTIVE_WINDOW, NET_WM_MOVERESIZE, NET_SUPPORTING_WM_CHECK, + NET_WM_STATE_FOCUSED, NET_WM_STATE_MODAL, NET_WM_STATE_FULLSCREEN, NET_WM_STATE_MAXIMIZED_VERT, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 692c0f8bb..88f4c3c5f 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -38,6 +38,7 @@ const char *atom_map[ATOM_LAST] = { [NET_ACTIVE_WINDOW] = "_NET_ACTIVE_WINDOW", [NET_WM_MOVERESIZE] = "_NET_WM_MOVERESIZE", [NET_SUPPORTING_WM_CHECK] = "_NET_SUPPORTING_WM_CHECK", + [NET_WM_STATE_FOCUSED] = "_NET_WM_STATE_FOCUSED", [NET_WM_STATE_MODAL] = "_NET_WM_STATE_MODAL", [NET_WM_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN", [NET_WM_STATE_MAXIMIZED_VERT] = "_NET_WM_STATE_MAXIMIZED_VERT", @@ -238,8 +239,20 @@ static void xwm_set_net_client_list(struct wlr_xwm *xwm) { XCB_ATOM_WINDOW, 32, mapped_surfaces, windows); } -static void xwm_send_focus_window(struct wlr_xwm *xwm, +static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface); + +static void xwm_set_focus_window(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { + struct wlr_xwayland_surface *unfocus_surface = xwm->focus_surface; + + // We handle cases where focus_surface == xsurface because we + // want to be able to deny FocusIn events. + xwm->focus_surface = xsurface; + + if (unfocus_surface) { + xsurface_set_net_wm_state(unfocus_surface); + } + if (!xsurface) { xcb_set_input_focus_checked(xwm->xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, @@ -270,6 +283,8 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm, values[0] = XCB_STACK_MODE_ABOVE; xcb_configure_window(xwm->xcb_conn, xsurface->window_id, XCB_CONFIG_WINDOW_STACK_MODE, values); + + xsurface_set_net_wm_state(xsurface); } static void xwm_surface_activate(struct wlr_xwm *xwm, @@ -285,9 +300,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, xwm_set_net_active_window(xwm, XCB_WINDOW_NONE); } - xwm_send_focus_window(xwm, xsurface); - - xwm->focus_surface = xsurface; + xwm_set_focus_window(xwm, xsurface); xcb_flush(xwm->xcb_conn); } @@ -295,7 +308,7 @@ static void xwm_surface_activate(struct wlr_xwm *xwm, static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { struct wlr_xwm *xwm = xsurface->xwm; - uint32_t property[5]; + uint32_t property[6]; size_t i = 0; if (xsurface->modal) { property[i++] = xwm->atoms[NET_WM_STATE_MODAL]; @@ -312,6 +325,9 @@ static void xsurface_set_net_wm_state(struct wlr_xwayland_surface *xsurface) { if (xsurface->minimized) { property[i++] = xwm->atoms[NET_WM_STATE_HIDDEN]; } + if (xsurface == xwm->focus_surface) { + property[i++] = xwm->atoms[NET_WM_STATE_FOCUSED]; + } assert(i <= sizeof(property) / sizeof(property[0])); xcb_change_property(xwm->xcb_conn, @@ -1299,10 +1315,10 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm, struct wlr_xwayland_surface *requested_focus = lookup_surface(xwm, ev->event); if (xwm->focus_surface && requested_focus && requested_focus->pid == xwm->focus_surface->pid) { - xwm->focus_surface = requested_focus; + xwm_set_focus_window(xwm, requested_focus); + } else { + xwm_set_focus_window(xwm, xwm->focus_surface); } - - xwm_send_focus_window(xwm, xwm->focus_surface); } static void xwm_handle_xcb_error(struct wlr_xwm *xwm, xcb_value_error_t *ev) { @@ -1817,6 +1833,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { xwm->atoms[NET_WM_STATE], xwm->atoms[NET_ACTIVE_WINDOW], xwm->atoms[NET_WM_MOVERESIZE], + xwm->atoms[NET_WM_STATE_FOCUSED], xwm->atoms[NET_WM_STATE_MODAL], xwm->atoms[NET_WM_STATE_FULLSCREEN], xwm->atoms[NET_WM_STATE_MAXIMIZED_VERT], From c32d89ee3efbc0a61c75e8120bdc2bf035c8ffd3 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 22 Feb 2020 14:56:40 +0100 Subject: [PATCH 010/223] examples: remove unnecessary gles2.h imports --- examples/multi-pointer.c | 1 - examples/pointer.c | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 9f7bd6c8e..eceeb6d68 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/examples/pointer.c b/examples/pointer.c index a60807163..703aa59ea 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From 26af316b3b3c15c0c2cbc76f2d398e5c3ac70c64 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:45:24 +0200 Subject: [PATCH 011/223] render/gles2: make wlr_gles2_texture_from_* private These functions are unused by compositors (see e.g. [1]) and prevent wlr_gles2_texture from accessing wlr_gles2_renderer state. This is an issue for proper teardown [2] and for accessing GLES2 extensions. [1]: https://github.com/swaywm/wlroots/pull/1962#issuecomment-569511830 [2]: https://github.com/swaywm/wlroots/pull/1962 --- include/render/gles2.h | 10 ++++++++++ include/wlr/render/gles2.h | 8 -------- render/gles2/renderer.c | 23 +---------------------- render/gles2/texture.c | 15 ++++++++++++--- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 6d25bea05..2853f5b9e 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -102,9 +102,19 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_gl( GLint gl_format, GLint gl_type, bool alpha); const enum wl_shm_format *get_gles2_wl_formats(size_t *len); +struct wlr_gles2_renderer *gles2_get_renderer( + struct wlr_renderer *wlr_renderer); struct wlr_gles2_texture *gles2_get_texture( struct wlr_texture *wlr_texture); +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, + enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, + const void *data); +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, + struct wl_resource *data); +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, + struct wlr_dmabuf_attributes *attribs); + void push_gles2_marker(const char *file, const char *func); void pop_gles2_marker(void); #define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__) diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index 631b11a2a..5a3e9d5c7 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -21,14 +21,6 @@ struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer); bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer, const char *ext); -struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, - enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, - const void *data); -struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, - struct wl_resource *data); -struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, - struct wlr_dmabuf_attributes *attribs); - struct wlr_gles2_texture_attribs { GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */ GLuint tex; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 914f5b77f..17a9caccc 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -25,7 +25,7 @@ struct wlr_gles2_procs gles2_procs = {0}; static const struct wlr_renderer_impl renderer_impl; -static struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *gles2_get_renderer( struct wlr_renderer *wlr_renderer) { assert(wlr_renderer->impl == &renderer_impl); return (struct wlr_gles2_renderer *)wlr_renderer; @@ -442,27 +442,6 @@ restore_context_out: return r; } -static struct wlr_texture *gles2_texture_from_pixels( - struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, - uint32_t stride, uint32_t width, uint32_t height, const void *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_pixels(renderer->egl, wl_fmt, stride, width, - height, data); -} - -static struct wlr_texture *gles2_texture_from_wl_drm( - struct wlr_renderer *wlr_renderer, struct wl_resource *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_wl_drm(renderer->egl, data); -} - -static struct wlr_texture *gles2_texture_from_dmabuf( - struct wlr_renderer *wlr_renderer, - struct wlr_dmabuf_attributes *attribs) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_gles2_texture_from_dmabuf(renderer->egl, attribs); -} - static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer, struct wl_display *wl_display) { struct wlr_gles2_renderer *renderer = diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 0187a462f..d92eeac3d 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -134,9 +134,12 @@ static const struct wlr_texture_impl texture_impl = { .destroy = gles2_texture_destroy, }; -struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); @@ -175,8 +178,11 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, return &texture->wlr_texture; } -struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { @@ -238,8 +244,11 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, return &texture->wlr_texture; } -struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, +struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_egl *egl = renderer->egl; + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { From e8872d9ed7fce59fde56c3fe33796562ac56a66c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:56:29 +0200 Subject: [PATCH 012/223] render/gles2: keep ref to wlr_gles2_renderer in wlr_gles2_texture --- include/render/gles2.h | 2 +- render/gles2/texture.c | 49 ++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 2853f5b9e..e9c49af9f 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -79,7 +79,7 @@ struct wlr_gles2_renderer { struct wlr_gles2_texture { struct wlr_texture wlr_texture; - struct wlr_egl *egl; + struct wlr_gles2_renderer *renderer; // Basically: // GL_TEXTURE_2D == mutable diff --git a/render/gles2/texture.c b/render/gles2/texture.c index d92eeac3d..72b69204d 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -29,7 +29,7 @@ struct wlr_gles2_texture *gles2_get_texture( static struct wlr_gles2_texture *get_gles2_texture_in_context( struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - wlr_egl_make_current(texture->egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL); return texture; } @@ -47,7 +47,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, if (texture->target != GL_TEXTURE_2D) { wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture"); - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); return false; } @@ -75,7 +75,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, POP_GLES2_DEBUG; - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); return true; } @@ -86,12 +86,12 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture, if (!texture->image) { assert(texture->target == GL_TEXTURE_2D); - if (!texture->egl->exts.image_base_khr) { + if (!texture->renderer->egl->exts.image_base_khr) { return false; } - texture->image = texture->egl->procs.eglCreateImageKHR( - texture->egl->display, texture->egl->context, EGL_GL_TEXTURE_2D_KHR, + texture->image = texture->renderer->egl->procs.eglCreateImageKHR( + texture->renderer->egl->display, texture->renderer->egl->context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(uintptr_t)texture->tex, NULL); if (texture->image == EGL_NO_IMAGE_KHR) { return false; @@ -103,7 +103,7 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture, flags |= WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT; } - return wlr_egl_export_image_to_dmabuf(texture->egl, texture->image, + return wlr_egl_export_image_to_dmabuf(texture->renderer->egl, texture->image, wlr_texture->width, wlr_texture->height, flags, attribs); } @@ -118,11 +118,11 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { PUSH_GLES2_DEBUG; glDeleteTextures(1, &texture->tex); - wlr_egl_destroy_image(texture->egl, texture->image); + wlr_egl_destroy_image(texture->renderer->egl, texture->image); POP_GLES2_DEBUG; - wlr_egl_unset_current(texture->egl); + wlr_egl_unset_current(texture->renderer->egl); free(texture); } @@ -138,9 +138,8 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); if (fmt == NULL) { @@ -155,7 +154,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, return NULL; } wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); - texture->egl = egl; + texture->renderer = renderer; texture->target = GL_TEXTURE_2D; texture->has_alpha = fmt->has_alpha; texture->wl_format = fmt->wl_format; @@ -174,16 +173,15 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { return NULL; @@ -192,7 +190,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, EGLint fmt; int width, height; bool inverted_y; - EGLImageKHR image = wlr_egl_create_image_from_wl_drm(egl, resource, + EGLImageKHR image = wlr_egl_create_image_from_wl_drm(renderer->egl, resource, &fmt, &width, &height, &inverted_y); if (image == EGL_NO_IMAGE_KHR) { wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource"); @@ -203,11 +201,11 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, calloc(1, sizeof(struct wlr_gles2_texture)); if (texture == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); return NULL; } wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); - texture->egl = egl; + texture->renderer = renderer; texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->image = image; @@ -223,7 +221,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, break; default: wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format"); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); free(texture); return NULL; } @@ -240,22 +238,21 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - struct wlr_egl *egl = renderer->egl; - wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); if (!gles2_procs.glEGLImageTargetTexture2DOES) { return NULL; } - if (!egl->exts.image_dmabuf_import_ext) { + if (!renderer->egl->exts.image_dmabuf_import_ext) { wlr_log(WLR_ERROR, "Cannot create DMA-BUF texture: EGL extension " "unavailable"); return NULL; @@ -281,7 +278,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, } wlr_texture_init(&texture->wlr_texture, &texture_impl, attribs->width, attribs->height); - texture->egl = egl; + texture->renderer = renderer; texture->has_alpha = true; texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->inverted_y = @@ -289,7 +286,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, bool external_only; texture->image = - wlr_egl_create_image_from_dmabuf(egl, attribs, &external_only); + wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only); if (texture->image == EGL_NO_IMAGE_KHR) { wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF"); free(texture); @@ -307,7 +304,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, POP_GLES2_DEBUG; - wlr_egl_unset_current(egl); + wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; } From 62da61716f28754a2d3b7151348e1ea40bc6cf66 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 13:58:07 +0200 Subject: [PATCH 013/223] render/gles2: make push/pop debug functions take a wlr_renderer --- include/render/gles2.h | 8 ++--- render/gles2/renderer.c | 80 +++++++++++++++++++++-------------------- render/gles2/texture.c | 20 +++++------ 3 files changed, 56 insertions(+), 52 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index e9c49af9f..a68170bcb 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -115,9 +115,9 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *attribs); -void push_gles2_marker(const char *file, const char *func); -void pop_gles2_marker(void); -#define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__) -#define POP_GLES2_DEBUG pop_gles2_marker() +void push_gles2_debug_(struct wlr_gles2_renderer *renderer, + const char *file, const char *func); +#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__) +void pop_gles2_debug(struct wlr_gles2_renderer *renderer); #endif diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 17a9caccc..395e11bd4 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -43,7 +43,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glViewport(0, 0, width, height); renderer->viewport_width = width; @@ -56,7 +56,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, // XXX: maybe we should save output projection and remove some of the need // for users to sling matricies themselves - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_end(struct wlr_renderer *wlr_renderer) { @@ -66,12 +66,13 @@ static void gles2_end(struct wlr_renderer *wlr_renderer) { static void gles2_clear(struct wlr_renderer *wlr_renderer, const float color[static 4]) { - gles2_get_renderer_in_context(wlr_renderer); + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glClearColor(color[0], color[1], color[2], color[3]); glClear(GL_COLOR_BUFFER_BIT); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_scissor(struct wlr_renderer *wlr_renderer, @@ -79,7 +80,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); if (box != NULL) { struct wlr_box gl_box; wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180, @@ -90,7 +91,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, } else { glDisable(GL_SCISSOR_TEST); } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static bool gles2_render_subtexture_with_matrix( @@ -130,7 +131,7 @@ static bool gles2_render_subtexture_with_matrix( float transposition[9]; wlr_matrix_transpose(transposition, matrix); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex); @@ -168,7 +169,7 @@ static bool gles2_render_subtexture_with_matrix( glBindTexture(texture->target, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return true; } @@ -182,7 +183,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, float transposition[9]; wlr_matrix_transpose(transposition, matrix); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glUseProgram(renderer->shaders.quad.program); glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition); @@ -197,7 +198,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, @@ -217,7 +218,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, 0, 1, // bottom left }; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glUseProgram(renderer->shaders.ellipse.program); glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition); @@ -235,7 +236,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, glDisableVertexAttribArray(renderer->shaders.ellipse.pos_attrib); glDisableVertexAttribArray(renderer->shaders.ellipse.tex_attrib); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); } static const enum wl_shm_format *gles2_renderer_formats( @@ -288,10 +289,10 @@ static enum wl_shm_format gles2_preferred_read_format( gles2_get_renderer_in_context(wlr_renderer); GLint gl_format = -1, gl_type = -1; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); EGLint alpha_size = -1; eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, @@ -328,7 +329,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return false; } - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); // Make sure any pending drawing is finished before we try to read it glFinish(); @@ -355,7 +356,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, } } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return glGetError() == GL_NO_ERROR; } @@ -478,13 +479,13 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glDeleteProgram(renderer->shaders.quad.program); glDeleteProgram(renderer->shaders.ellipse.program); glDeleteProgram(renderer->shaders.tex_rgba.program); glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); @@ -519,7 +520,8 @@ static const struct wlr_renderer_impl renderer_impl = { .blit_dmabuf = gles2_blit_dmabuf, }; -void push_gles2_marker(const char *file, const char *func) { +void push_gles2_debug_(struct wlr_gles2_renderer *renderer, + const char *file, const char *func) { if (!gles2_procs.glPushDebugGroupKHR) { return; } @@ -530,7 +532,7 @@ void push_gles2_marker(const char *file, const char *func) { gles2_procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } -void pop_gles2_marker(void) { +void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { if (gles2_procs.glPopDebugGroupKHR) { gles2_procs.glPopDebugGroupKHR(); } @@ -556,8 +558,9 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, _wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg); } -static GLuint compile_shader(GLuint type, const GLchar *src) { - PUSH_GLES2_DEBUG; +static GLuint compile_shader(struct wlr_gles2_renderer *renderer, + GLuint type, const GLchar *src) { + push_gles2_debug(renderer); GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -570,19 +573,20 @@ static GLuint compile_shader(GLuint type, const GLchar *src) { shader = 0; } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return shader; } -static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { - PUSH_GLES2_DEBUG; +static GLuint link_program(struct wlr_gles2_renderer *renderer, + const GLchar *vert_src, const GLchar *frag_src) { + push_gles2_debug(renderer); - GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); + GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src); if (!vert) { goto error; } - GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); + GLuint frag = compile_shader(renderer, GL_FRAGMENT_SHADER, frag_src); if (!frag) { glDeleteShader(vert); goto error; @@ -605,11 +609,11 @@ static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { goto error; } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return prog; error: - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); return 0; } @@ -715,11 +719,11 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); GLuint prog; renderer->shaders.quad.program = prog = - link_program(quad_vertex_src, quad_fragment_src); + link_program(renderer, quad_vertex_src, quad_fragment_src); if (!renderer->shaders.quad.program) { goto error; } @@ -728,7 +732,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.ellipse.program = prog = - link_program(quad_vertex_src, ellipse_fragment_src); + link_program(renderer, quad_vertex_src, ellipse_fragment_src); if (!renderer->shaders.ellipse.program) { goto error; } @@ -738,7 +742,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.ellipse.tex_attrib = glGetAttribLocation(prog, "texcoord"); renderer->shaders.tex_rgba.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgba); + link_program(renderer, tex_vertex_src, tex_fragment_src_rgba); if (!renderer->shaders.tex_rgba.program) { goto error; } @@ -750,7 +754,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord"); renderer->shaders.tex_rgbx.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgbx); + link_program(renderer, tex_vertex_src, tex_fragment_src_rgbx); if (!renderer->shaders.tex_rgbx.program) { goto error; } @@ -763,7 +767,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { if (renderer->exts.egl_image_external_oes) { renderer->shaders.tex_ext.program = prog = - link_program(tex_vertex_src, tex_fragment_src_external); + link_program(renderer, tex_vertex_src, tex_fragment_src_external); if (!renderer->shaders.tex_ext.program) { goto error; } @@ -775,7 +779,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord"); } - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); @@ -788,7 +792,7 @@ error: glDeleteProgram(renderer->shaders.tex_rgbx.program); glDeleteProgram(renderer->shaders.tex_ext.program); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 72b69204d..5375e7962 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -56,7 +56,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, assert(fmt); // TODO: what if the unpack subimage extension isn't supported? - PUSH_GLES2_DEBUG; + push_gles2_debug(texture->renderer); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -73,7 +73,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, glBindTexture(GL_TEXTURE_2D, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(texture->renderer); wlr_egl_unset_current(texture->renderer->egl); return true; @@ -115,12 +115,12 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = get_gles2_texture_in_context(wlr_texture); - PUSH_GLES2_DEBUG; + push_gles2_debug(texture->renderer); glDeleteTextures(1, &texture->tex); wlr_egl_destroy_image(texture->renderer->egl, texture->image); - POP_GLES2_DEBUG; + pop_gles2_debug(texture->renderer); wlr_egl_unset_current(texture->renderer->egl); @@ -159,7 +159,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, texture->has_alpha = fmt->has_alpha; texture->wl_format = fmt->wl_format; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -171,7 +171,7 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer, glBindTexture(GL_TEXTURE_2D, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; @@ -228,7 +228,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, texture->target = GL_TEXTURE_EXTERNAL_OES; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->tex); @@ -236,7 +236,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, texture->image); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; @@ -295,14 +295,14 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, texture->target = external_only ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; - PUSH_GLES2_DEBUG; + push_gles2_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(texture->target, texture->tex); gles2_procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); glBindTexture(texture->target, 0); - POP_GLES2_DEBUG; + pop_gles2_debug(renderer); wlr_egl_unset_current(renderer->egl); return &texture->wlr_texture; From 1dbcfdaf81778fcd4635c6ecd62b89477f69f0d8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 14:02:08 +0200 Subject: [PATCH 014/223] render/gles2: remove gles2_procs Move the global into wlr_gles2_renderer. This removes global state and allows us to have multiple renderers with different GL loaders. --- include/render/gles2.h | 20 +++++++++----------- render/gles2/renderer.c | 40 +++++++++++++++++++--------------------- render/gles2/texture.c | 8 ++++---- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index a68170bcb..a64aa77ce 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -14,17 +14,6 @@ #include #include -struct wlr_gles2_procs { - PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; - PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; - PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR; - PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR; - PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR; - PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES; -}; - -extern struct wlr_gles2_procs gles2_procs; - struct wlr_gles2_pixel_format { enum wl_shm_format wl_format; GLint gl_format, gl_type; @@ -55,6 +44,15 @@ struct wlr_gles2_renderer { bool egl_image_oes; } exts; + struct { + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; + PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR; + PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR; + PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR; + PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES; + } procs; + struct { struct { GLuint program; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 395e11bd4..9ec87293f 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -21,8 +21,6 @@ static const GLfloat verts[] = { 0, 1, // bottom left }; -struct wlr_gles2_procs gles2_procs = {0}; - static const struct wlr_renderer_impl renderer_impl; struct wlr_gles2_renderer *gles2_get_renderer( @@ -364,7 +362,8 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_dmabuf_attributes *dst_attr, struct wlr_dmabuf_attributes *src_attr) { - if (!gles2_procs.glEGLImageTargetRenderbufferStorageOES) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + if (!renderer->procs.glEGLImageTargetRenderbufferStorageOES) { return false; } @@ -389,15 +388,14 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, // texture. gles2_src_tex->inverted_y = !(src_inverted_y ^ dst_inverted_y); - struct wlr_egl *egl = wlr_gles2_renderer_get_egl(wlr_renderer); - if (!wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL)) { + if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) { goto texture_destroy_out; } // TODO: The imported buffer should be checked with // eglQueryDmaBufModifiersEXT to see if it may be modified. bool external_only = false; - EGLImageKHR image = wlr_egl_create_image_from_dmabuf(egl, dst_attr, + EGLImageKHR image = wlr_egl_create_image_from_dmabuf(renderer->egl, dst_attr, &external_only); if (image == EGL_NO_IMAGE_KHR) { goto texture_destroy_out; @@ -406,7 +404,7 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, GLuint rbo = 0; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); - gles2_procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image); glBindRenderbuffer(GL_RENDERBUFFER, 0); @@ -435,7 +433,7 @@ out: glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffers(1, &rbo); - wlr_egl_destroy_image(egl, image); + wlr_egl_destroy_image(renderer->egl, image); texture_destroy_out: wlr_texture_destroy(src_tex); restore_context_out: @@ -489,7 +487,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); - gles2_procs.glDebugMessageCallbackKHR(NULL, NULL); + renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); } wlr_egl_unset_current(renderer->egl); @@ -522,19 +520,19 @@ static const struct wlr_renderer_impl renderer_impl = { void push_gles2_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func) { - if (!gles2_procs.glPushDebugGroupKHR) { + if (!renderer->procs.glPushDebugGroupKHR) { return; } int len = snprintf(NULL, 0, "%s:%s", file, func) + 1; char str[len]; snprintf(str, len, "%s:%s", file, func); - gles2_procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); + renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { - if (gles2_procs.glPopDebugGroupKHR) { - gles2_procs.glPopDebugGroupKHR(); + if (renderer->procs.glPopDebugGroupKHR) { + renderer->procs.glPopDebugGroupKHR(); } } @@ -689,33 +687,33 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { if (check_gl_ext(exts_str, "GL_KHR_debug")) { renderer->exts.debug_khr = true; - load_gl_proc(&gles2_procs.glDebugMessageCallbackKHR, + load_gl_proc(&renderer->procs.glDebugMessageCallbackKHR, "glDebugMessageCallbackKHR"); - load_gl_proc(&gles2_procs.glDebugMessageControlKHR, + load_gl_proc(&renderer->procs.glDebugMessageControlKHR, "glDebugMessageControlKHR"); } if (check_gl_ext(exts_str, "GL_OES_EGL_image_external")) { renderer->exts.egl_image_external_oes = true; - load_gl_proc(&gles2_procs.glEGLImageTargetTexture2DOES, + load_gl_proc(&renderer->procs.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); } if (check_gl_ext(exts_str, "GL_OES_EGL_image")) { renderer->exts.egl_image_oes = true; - load_gl_proc(&gles2_procs.glEGLImageTargetRenderbufferStorageOES, + load_gl_proc(&renderer->procs.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); } if (renderer->exts.debug_khr) { glEnable(GL_DEBUG_OUTPUT_KHR); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); - gles2_procs.glDebugMessageCallbackKHR(gles2_log, NULL); + renderer->procs.glDebugMessageCallbackKHR(gles2_log, NULL); // Silence unwanted message types - gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, + renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); - gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, + renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } @@ -796,7 +794,7 @@ error: if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); - gles2_procs.glDebugMessageCallbackKHR(NULL, NULL); + renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); } wlr_egl_unset_current(renderer->egl); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 5375e7962..179bfd891 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -183,7 +183,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - if (!gles2_procs.glEGLImageTargetTexture2DOES) { + if (!renderer->procs.glEGLImageTargetTexture2DOES) { return NULL; } @@ -232,7 +232,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer, glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->tex); - gles2_procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, + renderer->procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, texture->image); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); @@ -248,7 +248,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); - if (!gles2_procs.glEGLImageTargetTexture2DOES) { + if (!renderer->procs.glEGLImageTargetTexture2DOES) { return NULL; } @@ -299,7 +299,7 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, glGenTextures(1, &texture->tex); glBindTexture(texture->target, texture->tex); - gles2_procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); + renderer->procs.glEGLImageTargetTexture2DOES(texture->target, texture->image); glBindTexture(texture->target, 0); pop_gles2_debug(renderer); From 74f7be728715e164d5b7f174491797ce31206c8d Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 19 Jul 2020 14:57:10 +0200 Subject: [PATCH 015/223] xwayland: do not allow apps to change focus after wlroots request --- include/xwayland/xwm.h | 1 + xwayland/xwm.c | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index a3e7132d9..362b4cef0 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -128,6 +128,7 @@ struct wlr_xwm { #if WLR_HAS_XCB_ERRORS xcb_errors_context_t *errors_context; #endif + unsigned int last_focus_seq; struct wl_listener compositor_new_surface; struct wl_listener compositor_destroy; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 88f4c3c5f..87b9edc13 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -275,8 +275,9 @@ static void xwm_set_focus_window(struct wlr_xwm *xwm, } else { xwm_send_wm_message(xsurface, &message_data, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT); - xcb_set_input_focus(xwm->xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, - xsurface->window_id, XCB_CURRENT_TIME); + xcb_void_cookie_t cookie = xcb_set_input_focus(xwm->xcb_conn, + XCB_INPUT_FOCUS_POINTER_ROOT, xsurface->window_id, XCB_CURRENT_TIME); + xwm->last_focus_seq = cookie.sequence; } uint32_t values[1]; @@ -1293,6 +1294,16 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, } } +static bool validate_focus_serial(uint16_t last_focus_seq, uint16_t event_seq) { + uint16_t rev_dist = event_seq - last_focus_seq; + if (rev_dist >= UINT16_MAX / 2) { + // Probably overflow or too old + return false; + } + + return true; +} + static void xwm_handle_focus_in(struct wlr_xwm *xwm, xcb_focus_in_event_t *ev) { // Do not interfere with grabs @@ -1311,10 +1322,13 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm, // Note: Some applications rely on being able to change focus, for ex. Steam: // https://github.com/swaywm/sway/issues/1865 // Because of that, we allow changing focus between surfaces belonging to the - // same application. + // same application. We must be careful to ignore requests that are too old + // though, because otherwise it may lead to race conditions: + // https://github.com/swaywm/wlroots/issues/2324 struct wlr_xwayland_surface *requested_focus = lookup_surface(xwm, ev->event); if (xwm->focus_surface && requested_focus && - requested_focus->pid == xwm->focus_surface->pid) { + requested_focus->pid == xwm->focus_surface->pid && + validate_focus_serial(xwm->last_focus_seq, ev->sequence)) { xwm_set_focus_window(xwm, requested_focus); } else { xwm_set_focus_window(xwm, xwm->focus_surface); From aaf490d794bd077330c306face305f4a87de5809 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 30 Jul 2020 23:23:18 -0500 Subject: [PATCH 016/223] drm: fix uninitialized read get_drm_prop_blob does not set path_len if it returns NULL. Check the return value before path_len to avoid reading uninitialized memory. (Granted, this doesn't change the logic at all, but it does make Valgrind a bit happier.) --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7ecc28d39..dafe807b3 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1398,7 +1398,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { bool is_mst = false; char *path = get_drm_prop_blob(drm->fd, wlr_conn->id, wlr_conn->props.path, &path_len); - if (path_len > 4 && path && strncmp(path, "mst:", 4) == 0) { + if (path && path_len > 4 && strncmp(path, "mst:", 4) == 0) { is_mst = true; } free(path); From 0032954c75050276375a151389a25d4717ef1cd5 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Mon, 3 Aug 2020 11:48:27 +0200 Subject: [PATCH 017/223] make sure to fail setting gamma on disabled outputs --- types/wlr_gamma_control_v1.c | 1 + types/wlr_output.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index 591c6aa3a..48356ee11 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -108,6 +108,7 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); if (!wlr_output_test(gamma_control->output)) { gamma_control_send_failed(gamma_control); + wlr_output_rollback(gamma_control->output); goto error_table; } free(table); diff --git a/types/wlr_output.c b/types/wlr_output.c index ce05f97b9..9d02ec3c6 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -551,6 +551,10 @@ static bool output_basic_test(struct wlr_output *output) { wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output"); return false; } + if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) { + wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output"); + return false; + } return true; } From 30226eb1fbf2da0f1d6ff6e0c230541e95dfb46b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 5 Aug 2020 18:00:29 +0200 Subject: [PATCH 018/223] gamma-control-v1: fix use-after-free in gamma_control_handle_set_gamma gamma_control_send_failed destroys gamma_control. --- types/wlr_gamma_control_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index 48356ee11..f96c84aaa 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -107,8 +107,8 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); if (!wlr_output_test(gamma_control->output)) { - gamma_control_send_failed(gamma_control); wlr_output_rollback(gamma_control->output); + gamma_control_send_failed(gamma_control); goto error_table; } free(table); From f0d03fb8921b79c776d0fe9abedced78302c3c06 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Thu, 25 Jun 2020 22:56:56 +1200 Subject: [PATCH 019/223] Implement logind session SetType method to change session type to wayland --- backend/session/logind.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/backend/session/logind.c b/backend/session/logind.c index 00babcae0..317b179f9 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -241,6 +241,24 @@ static bool take_control(struct logind_session *session) { return ret >= 0; } +static bool set_type(struct logind_session *session) { + int ret; + sd_bus_message *msg = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + + ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", + session->path, "org.freedesktop.login1.Session", "SetType", + &error, &msg, "s", "wayland"); + if (ret < 0) { + wlr_log(WLR_ERROR, "Failed to set session type for session: %s", + error.message); + } + + sd_bus_error_free(&error); + sd_bus_message_unref(msg); + return ret >= 0; +} + static void release_control(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; @@ -819,6 +837,11 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } } + if (!set_type(session)) { + // Not fatal + wlr_log(WLR_INFO, "Failed to set logind session type to wayland"); + } + wlr_log(WLR_INFO, "Successfully loaded logind session"); session->base.impl = &session_logind; From e81d2086c055c697e2f3138529deaba112281f93 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Thu, 25 Jun 2020 23:43:28 +1200 Subject: [PATCH 020/223] Also set XDG_SESSION_TYPE --- backend/session/logind.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index 317b179f9..4f03e523c 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -250,12 +250,18 @@ static bool set_type(struct logind_session *session) { session->path, "org.freedesktop.login1.Session", "SetType", &error, &msg, "s", "wayland"); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to set session type for session: %s", + wlr_log(WLR_ERROR, "Failed to set logind session type for session: %s", error.message); } sd_bus_error_free(&error); sd_bus_message_unref(msg); + + ret = setenv("XDG_SESSION_TYPE", "wayland", 1); + if (ret < 0) { + wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); + } + return ret >= 0; } From 7e990a29918968a6f418f3055fefa1d633b3016f Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Fri, 26 Jun 2020 08:55:04 +1200 Subject: [PATCH 021/223] Don't set XDG_SESSION_TYPE unless logind SetType succeeds --- backend/session/logind.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index 4f03e523c..c5d0cb294 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -257,12 +257,16 @@ static bool set_type(struct logind_session *session) { sd_bus_error_free(&error); sd_bus_message_unref(msg); + if (ret < 0) { + return false; + } + ret = setenv("XDG_SESSION_TYPE", "wayland", 1); if (ret < 0) { wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); + return false; } - - return ret >= 0; + return true; } static void release_control(struct logind_session *session) { From c236f60bb6206020396e608d6032c116fe028106 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Sun, 9 Aug 2020 13:31:53 -0400 Subject: [PATCH 022/223] wlr_virtual_keyboard: fix fd leak --- types/wlr_virtual_keyboard_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 7ae030eec..25c94545c 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 199309L #include #include +#include #include #include #include @@ -72,12 +73,14 @@ static void virtual_keyboard_keymap(struct wl_client *client, keyboard->has_keymap = true; xkb_keymap_unref(keymap); xkb_context_unref(context); + close(fd); return; keymap_fail: fd_fail: xkb_context_unref(context); context_fail: wl_client_post_no_memory(client); + close(fd); } static void virtual_keyboard_key(struct wl_client *client, From 801c7670b765aae8dbd72c87e72d0ff9ff8f6cfb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 14 Aug 2020 10:31:27 +0200 Subject: [PATCH 023/223] examples/simple: use wlr_output_preferred_mode --- examples/simple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/simple.c b/examples/simple.c index 8540892d6..965e97be3 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -80,9 +80,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) { wl_container_of(listener, sample, new_output); struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); - if (!wl_list_empty(&output->modes)) { - struct wlr_output_mode *mode = - wl_container_of(output->modes.prev, mode, link); + + struct wlr_output_mode *mode = wlr_output_preferred_mode(output); + if (mode != NULL) { wlr_output_set_mode(output, mode); } sample_output->output = output; From 379835c42f182aa2c8fa814dea20a325361f8bdf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 14 Aug 2020 10:31:44 +0200 Subject: [PATCH 024/223] examples/simple: use wlr_renderer instead of GL --- examples/simple.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/simple.c b/examples/simple.c index 965e97be3..e3af1a118 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -1,5 +1,4 @@ #define _POSIX_C_SOURCE 200112L -#include #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +18,7 @@ struct sample_state { struct wl_listener new_output; struct wl_listener new_input; struct timespec last_frame; - float color[3]; + float color[4]; int dec; }; @@ -40,6 +40,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { struct sample_output *sample_output = wl_container_of(listener, sample_output, frame); struct sample_state *sample = sample_output->sample; + struct wlr_output *wlr_output = sample_output->output; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -56,12 +58,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { sample->dec = inc; } - wlr_output_attach_render(sample_output->output, NULL); + wlr_output_attach_render(wlr_output, NULL); - glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(renderer, sample->color); + wlr_renderer_end(renderer); - wlr_output_commit(sample_output->output); + wlr_output_commit(wlr_output); sample->last_frame = now; } @@ -162,7 +167,7 @@ int main(void) { wlr_log_init(WLR_DEBUG, NULL); struct wl_display *display = wl_display_create(); struct sample_state state = { - .color = { 1.0, 0.0, 0.0 }, + .color = { 1.0, 0.0, 0.0, 1.0 }, .dec = 0, .last_frame = { 0 }, .display = display From 9feeb2738dfc5a2b07a817938cef9d553d0a26ee Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Mon, 17 Aug 2020 11:33:57 +0200 Subject: [PATCH 025/223] backend/wayland: destroy relative pointer when output is disconnected Fixes #2243 Fixes #2106 --- backend/wayland/seat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 1fcb93e5f..d19744d82 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -473,6 +473,9 @@ static void pointer_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_wl_pointer *pointer = wl_container_of(listener, pointer, output_destroy); + if (pointer->relative_pointer) { + zwp_relative_pointer_v1_destroy(pointer->relative_pointer); + } wlr_input_device_destroy(&pointer->input_device->wlr_input_device); } From bad1e9afa8ea7d8927c8b4df83d3f277379dd54e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 25 Jul 2020 21:53:06 +0200 Subject: [PATCH 026/223] session: Add libseat backend --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + backend/session/direct.c | 3 + backend/session/libseat.c | 190 ++++++++++++++++++++++++++++++ backend/session/logind.c | 5 + backend/session/meson.build | 9 ++ backend/session/noop.c | 3 + backend/session/session.c | 24 +++- include/backend/session/session.h | 8 ++ include/wlr/config.h.in | 2 + meson.build | 2 + meson_options.txt | 1 + 13 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 backend/session/libseat.c create mode 100644 include/backend/session/session.h diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 13221d258..402f72f65 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -16,7 +16,7 @@ sources: tasks: - setup: | cd wlroots - meson build -Dauto_features=enabled -Dlogind=disabled -Dxcb-errors=disabled + meson build -Dauto_features=enabled -Dlogind=disabled -Dlibseat=disabled -Dxcb-errors=disabled - build: | cd wlroots ninja -C build diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index b3b1a3c05..9cf2f84fc 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -12,6 +12,7 @@ packages: - xcb-util-errors - xcb-util-image - xcb-util-wm + - seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index a0dfc442e..74553f7b1 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,6 +18,7 @@ packages: - x11/pixman - x11/xcb-util-errors - x11/xcb-util-wm +- sysutils/seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/backend/session/direct.c b/backend/session/direct.c index 4ffd711d7..f9041070b 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -18,6 +18,7 @@ #include #include #include "backend/session/direct-ipc.h" +#include "backend/session/session.h" #include "util/signal.h" enum { DRM_MAJOR = 226 }; @@ -246,6 +247,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; @@ -267,6 +269,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + session->base.active = true; wlr_log(WLR_INFO, "Successfully loaded direct session"); return &session->base; diff --git a/backend/session/libseat.c b/backend/session/libseat.c new file mode 100644 index 000000000..77226204f --- /dev/null +++ b/backend/session/libseat.c @@ -0,0 +1,190 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" +#include "util/signal.h" + +#include + +const struct session_impl session_libseat; + +struct libseat_device { + struct wl_list link; + int fd; + int device_id; +}; + +struct libseat_session { + struct wlr_session base; + + struct libseat *seat; + struct wl_event_source *event; + struct wl_list devices; +}; + +static void handle_enable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = true; + wlr_signal_emit_safe(&session->base.session_signal, session); +} + +static void handle_disable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = false; + wlr_signal_emit_safe(&session->base.session_signal, session); + libseat_disable_seat(session->seat); +} + +static int libseat_event(int fd, uint32_t mask, void *data) { + struct libseat *seat = data; + libseat_dispatch(seat, 0); + return 1; +} + +static struct libseat_seat_listener seat_listener = { + .enable_seat = handle_enable_seat, + .disable_seat = handle_disable_seat, +}; + +static struct libseat_session *libseat_session_from_session( + struct wlr_session *base) { + assert(base->impl == &session_libseat); + return (struct libseat_session *)base; +} + +static struct wlr_session *libseat_session_create(struct wl_display *disp) { + struct libseat_session *session = calloc(1, sizeof(*session)); + if (!session) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + + session_init(&session->base); + wl_list_init(&session->devices); + + session->seat = libseat_open_seat(&seat_listener, session); + if (session->seat == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to create seat"); + goto error; + } + + const char *seat_name = libseat_seat_name(session->seat); + if (seat_name == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to get seat info"); + goto error; + } + snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat_name); + + struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); + session->event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat), + WL_EVENT_READABLE, libseat_event, session->seat); + if (session->event == NULL) { + wlr_log(WLR_ERROR, "Failed to create libseat event source"); + goto error; + } + + // We may have received enable_seat immediately after the open_seat result, + // so, dispatch once without timeout to speed up activation. + if (libseat_dispatch(session->seat, 0) == -1) { + wlr_log_errno(WLR_ERROR, "libseat dispatch failed"); + goto error; + } + + wlr_log(WLR_INFO, "Successfully loaded libseat session"); + session->base.impl = &session_libseat; + return &session->base; + +error: + if (session->seat != NULL) { + libseat_close_seat(session->seat); + } + if (session->event != NULL) { + wl_event_source_remove(session->event); + } + free(session); + return NULL; +} + +static void libseat_session_destroy(struct wlr_session *base) { + struct libseat_session *session = libseat_session_from_session(base); + + libseat_close_seat(session->seat); + wl_event_source_remove(session->event); + free(session); +} + +static struct libseat_device *find_device_by_fd(struct libseat_session *session, int fd) { + struct libseat_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->fd == fd) { + return dev; + } + } + return NULL; +} + +static int libseat_session_open_device(struct wlr_session *base, const char *path) { + struct libseat_session *session = libseat_session_from_session(base); + + int fd; + int device_id = libseat_open_device(session->seat, path, &fd); + if (device_id == -1) { + wlr_log_errno(WLR_ERROR, "Failed to open device '%s'", path); + return -1; + } + + struct libseat_device *dev = calloc(1, sizeof(struct libseat_device)); + if (dev == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + libseat_close_device(session->seat, device_id); + return -1; + } + + dev->fd = fd; + dev->device_id = device_id; + wl_list_insert(&session->devices, &dev->link); + + return fd; +} + +static void libseat_session_close_device(struct wlr_session *base, int fd) { + struct libseat_session *session = libseat_session_from_session(base); + + struct libseat_device *dev = find_device_by_fd(session, fd); + if (dev == NULL) { + wlr_log(WLR_ERROR, "No device with fd %d found", fd); + close(fd); + return; + } + + if (libseat_close_device(session->seat, dev->device_id) == -1) { + wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id); + } + + wl_list_remove(&dev->link); + free(dev); + close(fd); +} + +static bool libseat_change_vt(struct wlr_session *base, unsigned vt) { + struct libseat_session *session = libseat_session_from_session(base); + return libseat_switch_session(session->seat, vt); +} + +const struct session_impl session_libseat = { + .create = libseat_session_create, + .destroy = libseat_session_destroy, + .open = libseat_session_open_device, + .close = libseat_session_close_device, + .change_vt = libseat_change_vt, +}; diff --git a/backend/session/logind.c b/backend/session/logind.c index c5d0cb294..a460cbe26 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -13,6 +13,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" #if WLR_HAS_SYSTEMD @@ -778,6 +779,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); + if (!get_display_session(&session->id)) { goto error; } @@ -855,6 +858,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { wlr_log(WLR_INFO, "Successfully loaded logind session"); session->base.impl = &session_logind; + session->base.active = true; + return &session->base; error_bus: diff --git a/backend/session/meson.build b/backend/session/meson.build index 81ff6d85c..4c83685e9 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -62,3 +62,12 @@ if logind_found wlr_files += files('logind.c') wlr_deps += logind endif + +# libseat + +libseat = dependency('libseat', required: get_option('libseat')) +if libseat.found() + wlr_files += files('libseat.c') + wlr_deps += libseat + conf_data.set10('WLR_HAS_LIBSEAT', true) +endif diff --git a/backend/session/noop.c b/backend/session/noop.c index 0e13a1778..3f293775f 100644 --- a/backend/session/noop.c +++ b/backend/session/noop.c @@ -6,6 +6,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" const struct session_impl session_noop; @@ -33,7 +34,9 @@ static struct wlr_session *noop_session_create(struct wl_display *disp) { return NULL; } + session_init(session); session->impl = &session_noop; + session->active = true; wlr_log(WLR_INFO, "Successfully initialized noop session"); return session; diff --git a/backend/session/session.c b/backend/session/session.c index 01eeffd98..d8e9509d8 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -13,13 +13,18 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" +extern const struct session_impl session_libseat; extern const struct session_impl session_logind; extern const struct session_impl session_direct; extern const struct session_impl session_noop; static const struct session_impl *impls[] = { +#if WLR_HAS_LIBSEAT + &session_libseat, +#endif #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND &session_logind, #endif @@ -65,12 +70,24 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_session_destroy(session); } +void session_init(struct wlr_session *session) { + wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.destroy); + wl_list_init(&session->devices); +} + struct wlr_session *wlr_session_create(struct wl_display *disp) { struct wlr_session *session = NULL; const char *env_wlr_session = getenv("WLR_SESSION"); if (env_wlr_session) { - if (strcmp(env_wlr_session, "logind") == 0 || + if (strcmp(env_wlr_session, "libseat") == 0) { +#if WLR_HAS_LIBSEAT + session = session_libseat.create(disp); +#else + wlr_log(WLR_ERROR, "wlroots is not compiled with libseat support"); +#endif + } else if (strcmp(env_wlr_session, "logind") == 0 || strcmp(env_wlr_session, "systemd") == 0) { #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND session = session_logind.create(disp); @@ -97,11 +114,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return NULL; } - session->active = true; - wl_signal_init(&session->session_signal); - wl_signal_init(&session->events.destroy); - wl_list_init(&session->devices); - session->udev = udev_new(); if (!session->udev) { wlr_log_errno(WLR_ERROR, "Failed to create udev context"); diff --git a/include/backend/session/session.h b/include/backend/session/session.h new file mode 100644 index 000000000..626f470a3 --- /dev/null +++ b/include/backend/session/session.h @@ -0,0 +1,8 @@ +#ifndef BACKEND_SESSION_SESSION_H +#define BACKEND_SESSION_SESSION_H + +struct wlr_session; + +void session_init(struct wlr_session *session); + +#endif diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index a7691ff91..77a155982 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -8,6 +8,8 @@ #mesondefine WLR_HAS_SYSTEMD #mesondefine WLR_HAS_ELOGIND +#mesondefine WLR_HAS_LIBSEAT + #mesondefine WLR_HAS_X11_BACKEND #mesondefine WLR_HAS_XWAYLAND diff --git a/meson.build b/meson.build index 4abe63181..ca26391e7 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,7 @@ endif conf_data = configuration_data() conf_data.set10('WLR_HAS_SYSTEMD', false) conf_data.set10('WLR_HAS_ELOGIND', false) +conf_data.set10('WLR_HAS_LIBSEAT', false) conf_data.set10('WLR_HAS_X11_BACKEND', false) conf_data.set10('WLR_HAS_XWAYLAND', false) conf_data.set10('WLR_HAS_XCB_ERRORS', false) @@ -176,6 +177,7 @@ meson.override_dependency('wlroots', wlroots) summary({ 'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0), 'elogind': conf_data.get('WLR_HAS_ELOGIND', 0), + 'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0), 'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0), 'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0), 'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0), diff --git a/meson_options.txt b/meson_options.txt index 894113e7a..382ef2a66 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,5 +1,6 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support for rootless session via logind') option('logind-provider', type: 'combo', choices: ['auto', 'systemd', 'elogind'], value: 'auto', description: 'Provider of logind support library') +option('libseat', type: 'feature', value: 'auto', description: 'Enable support for rootless session via libseat') option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications') From 297354f8477285231826f6441b943188ec7d7399 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 24 Aug 2020 10:27:03 +0200 Subject: [PATCH 027/223] Remove unnecessary wl_display_dispatch calls wl_display_roundtrip already takes care of dispatching the display. --- backend/wayland/backend.c | 1 - examples/dmabuf-capture.c | 1 - examples/foreign-toplevel.c | 1 - examples/gamma-control.c | 1 - examples/idle-inhibit.c | 1 - examples/idle.c | 1 - examples/input-inhibitor.c | 1 - examples/input-method-keyboard-grab.c | 1 - examples/input-method.c | 1 - examples/keyboard-shortcuts-inhibit.c | 1 - examples/output-power-management.c | 1 - examples/pointer-constraints.c | 1 - examples/relative-pointer-unstable-v1.c | 1 - examples/screencopy-dmabuf.c | 1 - examples/screencopy.c | 1 - examples/text-input.c | 1 - examples/toplevel-decoration.c | 1 - examples/virtual-pointer.c | 2 -- 18 files changed, 19 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 972963e0f..a09126ce2 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -279,7 +279,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl_registry_add_listener(wl->registry, ®istry_listener, wl); - wl_display_dispatch(wl->remote_display); wl_display_roundtrip(wl->remote_display); if (!wl->compositor) { diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c index 203a1ac4a..2a3e195c2 100644 --- a/examples/dmabuf-capture.c +++ b/examples/dmabuf-capture.c @@ -754,7 +754,6 @@ static int init(struct capture_context *ctx) { wl_registry_add_listener(ctx->registry, ®istry_listener, ctx); wl_display_roundtrip(ctx->display); - wl_display_dispatch(ctx->display); if (!ctx->export_manager) { av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n", diff --git a/examples/foreign-toplevel.c b/examples/foreign-toplevel.c index 9184e7374..1d41d01af 100644 --- a/examples/foreign-toplevel.c +++ b/examples/foreign-toplevel.c @@ -332,7 +332,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (toplevel_manager == NULL) { diff --git a/examples/gamma-control.c b/examples/gamma-control.c index a060b8837..9fa00ce36 100644 --- a/examples/gamma-control.c +++ b/examples/gamma-control.c @@ -162,7 +162,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (gamma_control_manager == NULL) { diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index 348892ab3..5de32dbd7 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -177,7 +177,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/idle.c b/examples/idle.c index 6faa1d7d3..254f1c79b 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -125,7 +125,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); wl_registry_destroy(registry); diff --git a/examples/input-inhibitor.c b/examples/input-inhibitor.c index 25e46c735..7192b45b2 100644 --- a/examples/input-inhibitor.c +++ b/examples/input-inhibitor.c @@ -150,7 +150,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); assert(registry); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); assert(compositor && seat && wm_base && input_inhibit_manager); diff --git a/examples/input-method-keyboard-grab.c b/examples/input-method-keyboard-grab.c index 881f91a92..055abeab8 100644 --- a/examples/input-method-keyboard-grab.c +++ b/examples/input-method-keyboard-grab.c @@ -191,7 +191,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (input_method_manager == NULL) { diff --git a/examples/input-method.c b/examples/input-method.c index 9276e1599..479c87613 100644 --- a/examples/input-method.c +++ b/examples/input-method.c @@ -324,7 +324,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/keyboard-shortcuts-inhibit.c b/examples/keyboard-shortcuts-inhibit.c index 3d066c0e0..e9a837b61 100644 --- a/examples/keyboard-shortcuts-inhibit.c +++ b/examples/keyboard-shortcuts-inhibit.c @@ -209,7 +209,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/output-power-management.c b/examples/output-power-management.c index 43e7c53f6..00d4122a3 100644 --- a/examples/output-power-management.c +++ b/examples/output-power-management.c @@ -109,7 +109,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (output_power_manager == NULL) { diff --git a/examples/pointer-constraints.c b/examples/pointer-constraints.c index 1df9f6ce0..f67f1edec 100644 --- a/examples/pointer-constraints.c +++ b/examples/pointer-constraints.c @@ -198,7 +198,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); struct wl_region *disjoint_region = wl_compositor_create_region(compositor); diff --git a/examples/relative-pointer-unstable-v1.c b/examples/relative-pointer-unstable-v1.c index ce671f995..02f9d1c52 100644 --- a/examples/relative-pointer-unstable-v1.c +++ b/examples/relative-pointer-unstable-v1.c @@ -412,7 +412,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); /* Check that all the global interfaces were captured */ diff --git a/examples/screencopy-dmabuf.c b/examples/screencopy-dmabuf.c index 74eb8a75d..2525efc5a 100644 --- a/examples/screencopy-dmabuf.c +++ b/examples/screencopy-dmabuf.c @@ -315,7 +315,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (dmabuf == NULL) { diff --git a/examples/screencopy.c b/examples/screencopy.c index cf4652f49..0e03a2384 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -234,7 +234,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (shm == NULL) { diff --git a/examples/text-input.c b/examples/text-input.c index bfdbc07b4..ec75d3078 100644 --- a/examples/text-input.c +++ b/examples/text-input.c @@ -344,7 +344,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/toplevel-decoration.c b/examples/toplevel-decoration.c index e930c4170..cb8caacec 100644 --- a/examples/toplevel-decoration.c +++ b/examples/toplevel-decoration.c @@ -203,7 +203,6 @@ int main(int argc, char **argv) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (compositor == NULL) { diff --git a/examples/virtual-pointer.c b/examples/virtual-pointer.c index 84af7ffdc..8fd148305 100644 --- a/examples/virtual-pointer.c +++ b/examples/virtual-pointer.c @@ -67,7 +67,6 @@ int main(int argc, char *argv[]) { struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_dispatch(display); wl_display_roundtrip(display); if (pointer_manager == NULL) { @@ -132,7 +131,6 @@ int main(int argc, char *argv[]) { zwlr_virtual_pointer_v1_frame(pointer); zwlr_virtual_pointer_v1_destroy(pointer); - wl_display_dispatch(display); return EXIT_SUCCESS; } From 330c50b48dfe987d7894f5a92c1b084b2cc8c712 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 26 Aug 2020 21:09:56 +0200 Subject: [PATCH 028/223] session: Add missing init to direct-freebsd bad1e9afa8ea ("session: Add libseat backend") introduced a change to to how session backends initialize, but failed to update the FreeBSD specific version of the direct backend accordingly. Closes: https://github.com/swaywm/wlroots/issues/2376 --- backend/session/direct-freebsd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index c6e1f7204..e4b6c7929 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -18,6 +18,7 @@ #include #include #include "backend/session/direct-ipc.h" +#include "backend/session/session.h" #include "util/signal.h" const struct session_impl session_direct; @@ -274,6 +275,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; @@ -297,6 +299,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + session->base.active = true; return &session->base; error_ipc: From 2072d59da54ac772410271ad2219ca107a7fff48 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 20 Jul 2020 23:43:03 +0200 Subject: [PATCH 029/223] xdg-shell: split last-acked and current state These states are distinct in the time period between the ack_configure and the next commit on the surface. Splitting these states avoids the following race for example: - client starts at 1000x1000 - wlr_xdg_toplevel_set_size 500x500 - size is different -> configure sent - client acks the configure - wlr_xdg_toplevel_set_size 1000x1000 - compare_xdg_toplevel_state returns true since there is no pending configure and the currently committed size is still 1000x1000 - no new configure is sent - client commits at the size it last acked, 500x500 --- include/wlr/types/wlr_xdg_shell.h | 1 + include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/xdg_shell/wlr_xdg_toplevel.c | 47 +++++++++--------------- types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 43 ++++++++-------------- 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 4bd286ceb..45c5aee08 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -124,6 +124,7 @@ struct wlr_xdg_toplevel { struct wlr_xdg_toplevel_state client_pending; struct wlr_xdg_toplevel_state server_pending; + struct wlr_xdg_toplevel_state last_acked; struct wlr_xdg_toplevel_state current; char *title; diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 5a6cf72f9..2e870aa5c 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -139,6 +139,7 @@ struct wlr_xdg_toplevel_v6 { struct wlr_xdg_toplevel_v6_state client_pending; struct wlr_xdg_toplevel_v6_state server_pending; + struct wlr_xdg_toplevel_v6_state last_acked; struct wlr_xdg_toplevel_v6_state current; char *title; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 3524bd34c..51d0687b5 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -13,60 +13,44 @@ void handle_xdg_toplevel_ack_configure( assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); assert(configure->toplevel_state != NULL); - surface->toplevel->current.maximized = - configure->toplevel_state->maximized; - surface->toplevel->current.fullscreen = - configure->toplevel_state->fullscreen; - surface->toplevel->current.resizing = - configure->toplevel_state->resizing; - surface->toplevel->current.activated = - configure->toplevel_state->activated; - surface->toplevel->current.tiled = - configure->toplevel_state->tiled; + surface->toplevel->last_acked = *configure->toplevel_state; } bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) { - struct { - struct wlr_xdg_toplevel_state state; - uint32_t width, height; - } configured; - // is pending state different from current state? if (!state->base->configured) { return false; } + struct wlr_xdg_toplevel_state *configured = NULL; if (wl_list_empty(&state->base->configure_list)) { - // last configure is actually the current state, just use it - configured.state = state->current; - configured.width = state->base->surface->current.width; - configured.height = state->base->surface->current.height; + // There are currently no pending configures, so check against the last + // state acked by the client. + configured = &state->last_acked; } else { struct wlr_xdg_surface_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = *configure->toplevel_state; - configured.width = configure->toplevel_state->width; - configured.height = configure->toplevel_state->height; + configured = configure->toplevel_state; } - if (state->server_pending.activated != configured.state.activated) { + if (state->server_pending.activated != configured->activated) { return false; } - if (state->server_pending.fullscreen != configured.state.fullscreen) { + if (state->server_pending.fullscreen != configured->fullscreen) { return false; } - if (state->server_pending.maximized != configured.state.maximized) { + if (state->server_pending.maximized != configured->maximized) { return false; } - if (state->server_pending.resizing != configured.state.resizing) { + if (state->server_pending.resizing != configured->resizing) { return false; } - if (state->server_pending.tiled != configured.state.tiled) { + if (state->server_pending.tiled != configured->tiled) { return false; } - if (state->server_pending.width == configured.width && - state->server_pending.height == configured.height) { + if (state->server_pending.width == configured->width && + state->server_pending.height == configured->height) { return true; } @@ -187,7 +171,10 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) { return; } - // update state that doesn't need compositor approval + // apply state from the last acked configure now that the client committed + surface->toplevel->current = surface->toplevel->last_acked; + + // update state from the client that doesn't need compositor approval surface->toplevel->current.max_width = surface->toplevel->client_pending.max_width; surface->toplevel->current.min_width = diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c index a7a7d12bc..2c626f83d 100644 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c @@ -295,55 +295,41 @@ void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); assert(configure->toplevel_state != NULL); - surface->toplevel->current.maximized = - configure->toplevel_state->maximized; - surface->toplevel->current.fullscreen = - configure->toplevel_state->fullscreen; - surface->toplevel->current.resizing = - configure->toplevel_state->resizing; - surface->toplevel->current.activated = - configure->toplevel_state->activated; + surface->toplevel->last_acked = *configure->toplevel_state; } bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) { - struct { - struct wlr_xdg_toplevel_v6_state state; - uint32_t width, height; - } configured; - // is pending state different from current state? if (!state->base->configured) { return false; } + struct wlr_xdg_toplevel_v6_state *configured = NULL; if (wl_list_empty(&state->base->configure_list)) { - // last configure is actually the current state, just use it - configured.state = state->current; - configured.width = state->base->surface->current.width; - configured.height = state->base->surface->current.height; + // There are currently no pending configures, so check against the last + // state acked by the client. + configured = &state->last_acked; } else { struct wlr_xdg_surface_v6_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = *configure->toplevel_state; - configured.width = configure->toplevel_state->width; - configured.height = configure->toplevel_state->height; + configured = configure->toplevel_state; } - if (state->server_pending.activated != configured.state.activated) { + if (state->server_pending.activated != configured->activated) { return false; } - if (state->server_pending.fullscreen != configured.state.fullscreen) { + if (state->server_pending.fullscreen != configured->fullscreen) { return false; } - if (state->server_pending.maximized != configured.state.maximized) { + if (state->server_pending.maximized != configured->maximized) { return false; } - if (state->server_pending.resizing != configured.state.resizing) { + if (state->server_pending.resizing != configured->resizing) { return false; } - if (state->server_pending.width == configured.width && - state->server_pending.height == configured.height) { + if (state->server_pending.width == configured->width && + state->server_pending.height == configured->height) { return true; } @@ -430,7 +416,10 @@ void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface return; } - // update state that doesn't need compositor approval + // apply state from the last acked configure now that the client committed + surface->toplevel->current = surface->toplevel->last_acked; + + // update state from the client that doesn't need compositor approval surface->toplevel->current.max_width = surface->toplevel->client_pending.max_width; surface->toplevel->current.min_width = From 6949d0fd381dcb5df61d78b34b325473a113f279 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 15:40:15 +0200 Subject: [PATCH 030/223] render: Don't crash on 0 dimensions Don't force compositors to check when an empty shape is being renderered. References #2282. This was motivated by dwl crashing when setting window borders to 0 (djpohly/dwl#51). --- render/wlr_renderer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 593d165f4..8fa11cc97 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -99,6 +99,9 @@ bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r, void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) { + if (box->width == 0 || box->height == 0) { + return; + } assert(box->width > 0 && box->height > 0); float matrix[9]; wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, @@ -115,6 +118,9 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r, void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) { + if (box->width == 0 || box->height == 0) { + return; + } assert(box->width > 0 && box->height > 0); float matrix[9]; wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, From c674241ec0d96a4df42eda00da2894f3e5972710 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Jul 2020 17:22:38 +0200 Subject: [PATCH 031/223] output: introduce wlr_output_event_commit This event contains a `committed` bitfield, which allows callers to know which output fields changed during the commit. This allows users to setup a single atomic commit listener, instead of setting up one listener for each event (mode, scale, transform, and so on). References: https://github.com/swaywm/wlroots/issues/2098 --- include/wlr/types/wlr_output.h | 7 ++++++- types/wlr_output.c | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 075d09a1f..41423b582 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -163,7 +163,7 @@ struct wlr_output { // Emitted right before commit struct wl_signal precommit; // wlr_output_event_precommit // Emitted right after commit - struct wl_signal commit; + struct wl_signal commit; // wlr_output_event_commit // Emitted right after the buffer has been presented to the user struct wl_signal present; // wlr_output_event_present struct wl_signal enable; @@ -198,6 +198,11 @@ struct wlr_output_event_precommit { struct timespec *when; }; +struct wlr_output_event_commit { + struct wlr_output *output; + uint32_t committed; // bitmask of enum wlr_output_state_field +}; + enum wlr_output_present_flag { // The presentation was synchronized to the "vertical retrace" by the // display hardware such that tearing does not happen. diff --git a/types/wlr_output.c b/types/wlr_output.c index 9d02ec3c6..1c40a1470 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -581,11 +581,11 @@ bool wlr_output_commit(struct wlr_output *output) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_output_event_precommit event = { + struct wlr_output_event_precommit pre_event = { .output = output, .when = &now, }; - wlr_signal_emit_safe(&output->events.precommit, &event); + wlr_signal_emit_safe(&output->events.precommit, &pre_event); if (!output->impl->commit(output)) { output_state_clear(&output->pending); @@ -604,7 +604,11 @@ bool wlr_output_commit(struct wlr_output *output) { output->commit_seq++; - wlr_signal_emit_safe(&output->events.commit, output); + struct wlr_output_event_commit event = { + .output = output, + .committed = output->pending.committed, + }; + wlr_signal_emit_safe(&output->events.commit, &event); bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE; if (scale_updated) { From b0144c7ded2b655085eb8e7e9b64908dc9420d60 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Jul 2020 17:29:16 +0200 Subject: [PATCH 032/223] output-power-management-v1: listen to output commit --- .../types/wlr_output_power_management_v1.h | 2 +- types/wlr_output_power_management_v1.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_output_power_management_v1.h b/include/wlr/types/wlr_output_power_management_v1.h index 2ceb86002..23ce814a0 100644 --- a/include/wlr/types/wlr_output_power_management_v1.h +++ b/include/wlr/types/wlr_output_power_management_v1.h @@ -25,7 +25,7 @@ struct wlr_output_power_v1 { struct wl_list link; struct wl_listener output_destroy_listener; - struct wl_listener output_enable_listener; + struct wl_listener output_commit_listener; void *data; }; diff --git a/types/wlr_output_power_management_v1.c b/types/wlr_output_power_management_v1.c index 115c74f74..e607eb161 100644 --- a/types/wlr_output_power_management_v1.c +++ b/types/wlr_output_power_management_v1.c @@ -23,7 +23,7 @@ static void output_power_destroy(struct wlr_output_power_v1 *output_power) { } wl_resource_set_user_data(output_power->resource, NULL); wl_list_remove(&output_power->output_destroy_listener.link); - wl_list_remove(&output_power->output_enable_listener.link); + wl_list_remove(&output_power->output_commit_listener.link); wl_list_remove(&output_power->link); free(output_power); } @@ -58,11 +58,14 @@ static void output_power_v1_send_mode(struct wlr_output_power_v1 *output_power) zwlr_output_power_v1_send_mode(output_power->resource, mode); } -static void output_power_handle_output_enable(struct wl_listener *listener, +static void output_power_handle_output_commit(struct wl_listener *listener, void *data) { struct wlr_output_power_v1 *output_power = - wl_container_of(listener, output_power, output_enable_listener); - output_power_v1_send_mode(output_power); + wl_container_of(listener, output_power, output_commit_listener); + struct wlr_output_event_commit *event = data; + if (event->committed & WLR_OUTPUT_STATE_ENABLED) { + output_power_v1_send_mode(output_power); + } } static void output_power_handle_set_mode(struct wl_client *client, @@ -147,10 +150,10 @@ static void output_power_manager_get_output_power(struct wl_client *client, &output_power->output_destroy_listener); output_power->output_destroy_listener.notify = output_power_handle_output_destroy; - wl_signal_add(&output->events.enable, - &output_power->output_enable_listener); - output_power->output_enable_listener.notify = - output_power_handle_output_enable; + wl_signal_add(&output->events.commit, + &output_power->output_commit_listener); + output_power->output_commit_listener.notify = + output_power_handle_output_commit; struct wlr_output_power_v1 *mgmt; wl_list_for_each(mgmt, &manager->output_powers, link) { From 2b418b4d8857a4eacd719b76dfd36210383db6d6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 31 Aug 2020 16:38:39 +0200 Subject: [PATCH 033/223] examples/dmabuf-capture: add extra roundtrip for wl_output listener This example was relying on wl_display_dispatch being enough to fetch output information. This worked by chance. Add an explicit wl_display_roundtrip. Other examples don't setup wl_output listeners, so they should be fine. Fixes: 297354f84772 ("Remove unnecessary wl_display_dispatch calls") Closes: https://github.com/swaywm/wlroots/issues/2386 --- examples/dmabuf-capture.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/dmabuf-capture.c b/examples/dmabuf-capture.c index 2a3e195c2..60cdb6577 100644 --- a/examples/dmabuf-capture.c +++ b/examples/dmabuf-capture.c @@ -753,6 +753,10 @@ static int init(struct capture_context *ctx) { ctx->registry = wl_display_get_registry(ctx->display); wl_registry_add_listener(ctx->registry, ®istry_listener, ctx); + // First roundtrip to fetch globals + wl_display_roundtrip(ctx->display); + + // Second roundtrip to fetch wl_output information wl_display_roundtrip(ctx->display); if (!ctx->export_manager) { From 8b744412aab11fe4997367adf1a714ef2cb3946e Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 30 Aug 2020 11:08:42 +0200 Subject: [PATCH 034/223] Use fixed size integer type This type is meant to be 4 bytes large as seen in _XcursorReadUInt which always reads 4 bytes. An unsigned int is often 4 bytes large but this isnt' guaranteed so it is cleaner to use the exact type we want. --- include/xcursor/xcursor.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/xcursor/xcursor.h b/include/xcursor/xcursor.h index 62e232202..285f4de66 100644 --- a/include/xcursor/xcursor.h +++ b/include/xcursor/xcursor.h @@ -26,8 +26,10 @@ #ifndef XCURSOR_H #define XCURSOR_H -typedef int XcursorBool; -typedef unsigned int XcursorUInt; +#include + +typedef int XcursorBool; +typedef uint32_t XcursorUInt; typedef XcursorUInt XcursorDim; typedef XcursorUInt XcursorPixel; From 65abd4e92af497bbe1ae1085fa16b1b811a3c652 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 30 Aug 2020 11:13:19 +0200 Subject: [PATCH 035/223] Fix undefined behavior Without the casts the bytes accesses get converted to int. but int is not guaranteed to be 4 bytes large. Even when it is 4 bytes large `bytes[3] << 24` does not fit because int is signed. --- xcursor/xcursor.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/xcursor/xcursor.c b/xcursor/xcursor.c index aabef4837..51ce83237 100644 --- a/xcursor/xcursor.c +++ b/xcursor/xcursor.c @@ -285,11 +285,12 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u) return XcursorFalse; if ((*file->read) (file, bytes, 4) != 4) - return XcursorFalse; - *u = ((bytes[0] << 0) | - (bytes[1] << 8) | - (bytes[2] << 16) | - (bytes[3] << 24)); + return XcursorFalse; + + *u = ((XcursorUInt)(bytes[0]) << 0) | + ((XcursorUInt)(bytes[1]) << 8) | + ((XcursorUInt)(bytes[2]) << 16) | + ((XcursorUInt)(bytes[3]) << 24); return XcursorTrue; } From 971de474f0a423cc8f444c92d2e1a8334db8b55d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 28 Aug 2020 19:19:31 +0200 Subject: [PATCH 036/223] backend/session/libseat: register log handler Route libseat errors through wlroots logging infrastructure. This requires libseat 0.2.0. --- backend/session/libseat.c | 25 +++++++++++++++++++++++++ backend/session/meson.build | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/backend/session/libseat.c b/backend/session/libseat.c index 77226204f..751adcd3e 100644 --- a/backend/session/libseat.c +++ b/backend/session/libseat.c @@ -62,6 +62,28 @@ static struct libseat_session *libseat_session_from_session( return (struct libseat_session *)base; } +static enum wlr_log_importance libseat_log_level_to_wlr( + enum libseat_log_level level) { + switch (level) { + case LIBSEAT_LOG_LEVEL_ERROR: + return WLR_ERROR; + case LIBSEAT_LOG_LEVEL_INFO: + return WLR_INFO; + default: + return WLR_DEBUG; + } +} + +static void log_libseat(enum libseat_log_level level, + const char *fmt, va_list args) { + enum wlr_log_importance importance = libseat_log_level_to_wlr(level); + + static char wlr_fmt[1024]; + snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt); + + _wlr_vlog(importance, wlr_fmt, args); +} + static struct wlr_session *libseat_session_create(struct wl_display *disp) { struct libseat_session *session = calloc(1, sizeof(*session)); if (!session) { @@ -72,6 +94,9 @@ static struct wlr_session *libseat_session_create(struct wl_display *disp) { session_init(&session->base); wl_list_init(&session->devices); + libseat_set_log_handler(log_libseat); + libseat_set_log_level(LIBSEAT_LOG_LEVEL_ERROR); + session->seat = libseat_open_seat(&seat_listener, session); if (session->seat == NULL) { wlr_log_errno(WLR_ERROR, "Unable to create seat"); diff --git a/backend/session/meson.build b/backend/session/meson.build index 4c83685e9..140d41059 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -65,7 +65,7 @@ endif # libseat -libseat = dependency('libseat', required: get_option('libseat')) +libseat = dependency('libseat', required: get_option('libseat'), version: '>=0.2.0') if libseat.found() wlr_files += files('libseat.c') wlr_deps += libseat From 28cedb56237efdf388fed713ddb401a5d8d07434 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Wed, 2 Sep 2020 21:29:12 +1200 Subject: [PATCH 037/223] Quieten failure to set login session type (almost certainly due to systemd version <246) --- backend/session/logind.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index a460cbe26..b9249eced 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -242,7 +242,7 @@ static bool take_control(struct logind_session *session) { return ret >= 0; } -static bool set_type(struct logind_session *session) { +static void set_type(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -251,7 +251,7 @@ static bool set_type(struct logind_session *session) { session->path, "org.freedesktop.login1.Session", "SetType", &error, &msg, "s", "wayland"); if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to set logind session type for session: %s", + wlr_log(WLR_DEBUG, "Failed to set logind session type for session: %s", error.message); } @@ -259,15 +259,13 @@ static bool set_type(struct logind_session *session) { sd_bus_message_unref(msg); if (ret < 0) { - return false; + return; } ret = setenv("XDG_SESSION_TYPE", "wayland", 1); if (ret < 0) { wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session"); - return false; } - return true; } static void release_control(struct logind_session *session) { @@ -850,10 +848,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } } - if (!set_type(session)) { - // Not fatal - wlr_log(WLR_INFO, "Failed to set logind session type to wayland"); - } + set_type(session); wlr_log(WLR_INFO, "Successfully loaded logind session"); From a9cbfd950e83df2053474f50f7d12cf79dd74d74 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 2 Sep 2020 13:06:31 -0400 Subject: [PATCH 038/223] Remove xdg-shell v6 Ding dong the witch is dead Fixes #2381 --- include/types/wlr_xdg_shell_v6.h | 47 -- include/wlr/types/wlr_xdg_shell_v6.h | 375 ------------- protocol/meson.build | 1 - types/meson.build | 5 - types/xdg_shell_v6/wlr_xdg_popup_v6.c | 585 -------------------- types/xdg_shell_v6/wlr_xdg_positioner_v6.c | 230 -------- types/xdg_shell_v6/wlr_xdg_shell_v6.c | 168 ------ types/xdg_shell_v6/wlr_xdg_surface_v6.c | 606 --------------------- types/xdg_shell_v6/wlr_xdg_toplevel_v6.c | 525 ------------------ 9 files changed, 2542 deletions(-) delete mode 100644 include/types/wlr_xdg_shell_v6.h delete mode 100644 include/wlr/types/wlr_xdg_shell_v6.h delete mode 100644 types/xdg_shell_v6/wlr_xdg_popup_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_positioner_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_shell_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_surface_v6.c delete mode 100644 types/xdg_shell_v6/wlr_xdg_toplevel_v6.c diff --git a/include/types/wlr_xdg_shell_v6.h b/include/types/wlr_xdg_shell_v6.h deleted file mode 100644 index 4c9d1fa0e..000000000 --- a/include/types/wlr_xdg_shell_v6.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TYPES_WLR_XDG_SHELL_V6_H -#define TYPES_WLR_XDG_SHELL_V6_H - -#include -#include -#include "xdg-shell-unstable-v6-protocol.h" - -struct wlr_xdg_positioner_v6_resource { - struct wl_resource *resource; - struct wlr_xdg_positioner_v6 attrs; -}; - -extern const struct wlr_surface_role xdg_toplevel_v6_surface_role; -extern const struct wlr_surface_role xdg_popup_v6_surface_role; - -uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface); -struct wlr_xdg_surface_v6 *create_xdg_surface_v6( - struct wlr_xdg_client_v6 *client, struct wlr_surface *surface, - uint32_t id); -void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface); -void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface); -void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface); - -void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id); -struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( - struct wl_resource *resource); - -void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, - struct wlr_xdg_surface_v6 *parent, - struct wlr_xdg_positioner_v6_resource *positioner, int32_t id); -void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface); -struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat( - struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat); -void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface); - -void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, - uint32_t id); -void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface); -void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure); -void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure); -bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state); -void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface); - -#endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h deleted file mode 100644 index 2e870aa5c..000000000 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * This protocol is obsolete and will be removed in a future version. The - * recommended replacement is xdg-shell. - */ - -/* - * 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_TYPES_WLR_XDG_SHELL_V6_H -#define WLR_TYPES_WLR_XDG_SHELL_V6_H - -#include -#include -#include -#include "xdg-shell-unstable-v6-protocol.h" - -/** - * An interface enabling clients to turn their wl_surfaces into windows in a - * desktop environment. - */ -struct wlr_xdg_shell_v6 { - struct wl_global *global; - struct wl_list clients; - struct wl_list popup_grabs; - uint32_t ping_timeout; - - struct wl_listener display_destroy; - - struct { - /** - * The `new_surface` event signals that a client has requested to - * create a new shell surface. At this point, the surface is ready to - * be configured but is not mapped or ready receive input events. The - * surface will be ready to be managed on the `map` event. - */ - struct wl_signal new_surface; - struct wl_signal destroy; - } events; - - void *data; -}; - -struct wlr_xdg_client_v6 { - struct wlr_xdg_shell_v6 *shell; - struct wl_resource *resource; - struct wl_client *client; - struct wl_list surfaces; - - struct wl_list link; // wlr_xdg_shell_v6::clients - - uint32_t ping_serial; - struct wl_event_source *ping_timer; -}; - -struct wlr_xdg_positioner_v6 { - struct wlr_box anchor_rect; - enum zxdg_positioner_v6_anchor anchor; - enum zxdg_positioner_v6_gravity gravity; - enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment; - - struct { - int32_t width, height; - } size; - - struct { - int32_t x, y; - } offset; -}; - -struct wlr_xdg_popup_v6 { - struct wlr_xdg_surface_v6 *base; - struct wl_list link; - - struct wl_resource *resource; - bool committed; - struct wlr_xdg_surface_v6 *parent; - struct wlr_seat *seat; - - // Position of the popup relative to the upper left corner of the window - // geometry of the parent surface - struct wlr_box geometry; - - struct wlr_xdg_positioner_v6 positioner; - - struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups -}; - -// each seat gets a popup grab -struct wlr_xdg_popup_grab_v6 { - struct wl_client *client; - struct wlr_seat_pointer_grab pointer_grab; - struct wlr_seat_keyboard_grab keyboard_grab; - struct wlr_seat_touch_grab touch_grab; - struct wlr_seat *seat; - struct wl_list popups; - struct wl_list link; // wlr_xdg_shell_v6::popup_grabs - struct wl_listener seat_destroy; -}; - -enum wlr_xdg_surface_v6_role { - WLR_XDG_SURFACE_V6_ROLE_NONE, - WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, - WLR_XDG_SURFACE_V6_ROLE_POPUP, -}; - -struct wlr_xdg_toplevel_v6_state { - bool maximized, fullscreen, resizing, activated; - uint32_t width, height; - uint32_t max_width, max_height; - uint32_t min_width, min_height; - - // Since the fullscreen request may be made before the toplevel's surface - // is mapped, this is used to store the requested fullscreen output (if - // any) for wlr_xdg_toplevel_v6::client_pending. - struct wlr_output *fullscreen_output; - struct wl_listener fullscreen_output_destroy; -}; - -/** - * An xdg-surface is a user interface element requiring management by the - * compositor. An xdg-surface alone isn't useful, a role should be assigned to - * it in order to map it. - * - * When a surface has a role and is ready to be displayed, the `map` event is - * emitted. When a surface should no longer be displayed, the `unmap` event is - * emitted. The `unmap` event is guaranteed to be emitted before the `destroy` - * event if the view is destroyed when mapped. - */ -struct wlr_xdg_toplevel_v6 { - struct wl_resource *resource; - struct wlr_xdg_surface_v6 *base; - struct wlr_xdg_surface_v6 *parent; - bool added; - - struct wlr_xdg_toplevel_v6_state client_pending; - struct wlr_xdg_toplevel_v6_state server_pending; - struct wlr_xdg_toplevel_v6_state last_acked; - struct wlr_xdg_toplevel_v6_state current; - - char *title; - char *app_id; - - struct { - struct wl_signal request_maximize; - struct wl_signal request_fullscreen; - struct wl_signal request_minimize; - struct wl_signal request_move; - struct wl_signal request_resize; - struct wl_signal request_show_window_menu; - struct wl_signal set_parent; - struct wl_signal set_title; - struct wl_signal set_app_id; - } events; -}; - -struct wlr_xdg_surface_v6_configure { - struct wl_list link; // wlr_xdg_surface_v6::configure_list - uint32_t serial; - - struct wlr_xdg_toplevel_v6_state *toplevel_state; -}; - -struct wlr_xdg_surface_v6 { - struct wlr_xdg_client_v6 *client; - struct wl_resource *resource; - struct wlr_surface *surface; - struct wl_list link; // wlr_xdg_client_v6::surfaces - enum wlr_xdg_surface_v6_role role; - - union { - struct wlr_xdg_toplevel_v6 *toplevel; - struct wlr_xdg_popup_v6 *popup; - }; - - struct wl_list popups; // wlr_xdg_popup_v6::link - - bool added, configured, mapped; - uint32_t configure_serial; - struct wl_event_source *configure_idle; - uint32_t configure_next_serial; - struct wl_list configure_list; - - bool has_next_geometry; - struct wlr_box next_geometry; - struct wlr_box geometry; - - struct wl_listener surface_destroy; - struct wl_listener surface_commit; - - struct { - struct wl_signal destroy; - struct wl_signal ping_timeout; - struct wl_signal new_popup; - /** - * The `map` event signals that the shell surface is ready to be - * managed by the compositor and rendered on the screen. At this point, - * the surface has configured its properties, has had the opportunity - * to bind to the seat to receive input events, and has a buffer that - * is ready to be rendered. You can now safely add this surface to a - * list of views. - */ - struct wl_signal map; - /** - * The `unmap` event signals that the surface is no longer in a state - * where it should be shown on the screen. This might happen if the - * surface no longer has a displayable buffer because either the - * surface has been hidden or is about to be destroyed. - */ - struct wl_signal unmap; - } events; - - void *data; -}; - -struct wlr_xdg_toplevel_v6_move_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; -}; - -struct wlr_xdg_toplevel_v6_resize_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; - uint32_t edges; -}; - -struct wlr_xdg_toplevel_v6_set_fullscreen_event { - struct wlr_xdg_surface_v6 *surface; - bool fullscreen; - struct wlr_output *output; -}; - -struct wlr_xdg_toplevel_v6_show_window_menu_event { - struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_client *seat; - uint32_t serial; - uint32_t x, y; -}; - -struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); - -/** - * Send a ping to the surface. If the surface does not respond in a reasonable - * amount of time, the ping_timeout event will be emitted. - */ -void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface); - -/** - * Request that this toplevel surface be the given size. Returns the associated - * configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, - uint32_t width, uint32_t height); - -/** - * Request that this toplevel surface show itself in an activated or deactivated - * state. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, - bool activated); - -/** - * Request that this toplevel surface consider itself maximized or not - * maximized. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, - bool maximized); - -/** - * Request that this toplevel surface consider itself fullscreen or not - * fullscreen. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, - bool fullscreen); - -/** - * Request that this toplevel surface consider itself to be resizing or not - * resizing. Returns the associated configure serial. - */ -uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, - bool resizing); - -/** - * Request that this xdg surface closes. - */ -void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface); - -/** - * Find a surface within this xdg-surface tree at the given surface-local - * coordinates. Returns the surface and coordinates in the leaf surface - * coordinate system or NULL if no surface is found at that location. - */ -struct wlr_surface *wlr_xdg_surface_v6_surface_at( - struct wlr_xdg_surface_v6 *surface, double sx, double sy, - double *sub_x, double *sub_y); - -/** - * Get the geometry for this positioner based on the anchor rect, gravity, and - * size of this positioner. - */ -struct wlr_box wlr_xdg_positioner_v6_get_geometry( - struct wlr_xdg_positioner_v6 *positioner); - -/** - * Get the anchor point for this popup in the toplevel parent's coordinate system. - */ -void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, - int *toplevel_sx, int *toplevel_sy); - -/** - * Convert the given coordinates in the popup coordinate system to the toplevel - * surface coordinate system. - */ -void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup, - int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy); - -/** - * Set the geometry of this popup to unconstrain it according to its - * xdg-positioner rules. The box should be in the popup's root toplevel parent - * surface coordinate system. - */ -void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box); - -/** - Invert the right/left anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the x direction. - */ -void wlr_positioner_v6_invert_x( - struct wlr_xdg_positioner_v6 *positioner); - -/** - Invert the top/bottom anchor and gravity for this positioner. This can be - used to "flip" the positioner around the anchor rect in the y direction. - */ -void wlr_positioner_v6_invert_y( - struct wlr_xdg_positioner_v6 *positioner); - -bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface); - -struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( - struct wlr_surface *surface); - -/** - * Get the surface geometry. - * This is either the geometry as set by the client, or defaulted to the bounds - * of the surface + the subsurfaces (as specified by the protocol). - * - * The x and y value can be <0 - */ -void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box); - -/** - * Call `iterator` on each surface and popup in the xdg-surface tree, with the - * surface's position relative to the root xdg-surface. The function is called - * from root to leaves (in rendering order). - */ -void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -/** - * Call `iterator` on each popup in the xdg-surface tree, with the popup's - * position relative to the root xdg-surface. The function is called from root - * to leaves (in rendering order). - */ -void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data); - -#endif diff --git a/protocol/meson.build b/protocol/meson.build index 2369b70e3..b9b74ca57 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -28,7 +28,6 @@ protocols = { 'text-input-unstable-v3': wl_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', 'xdg-decoration-unstable-v1': wl_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', 'xdg-output-unstable-v1': wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', - 'xdg-shell-unstable-v6': wl_protocol_dir / 'unstable/xdg-shell/xdg-shell-unstable-v6.xml', # Other protocols 'gtk-primary-selection': 'gtk-primary-selection.xml', 'kde-idle': 'idle.xml', diff --git a/types/meson.build b/types/meson.build index 998e6b455..80978176e 100644 --- a/types/meson.build +++ b/types/meson.build @@ -11,11 +11,6 @@ wlr_files += files( 'tablet_v2/wlr_tablet_v2_tablet.c', 'tablet_v2/wlr_tablet_v2_tool.c', 'tablet_v2/wlr_tablet_v2.c', - 'xdg_shell_v6/wlr_xdg_popup_v6.c', - 'xdg_shell_v6/wlr_xdg_positioner_v6.c', - 'xdg_shell_v6/wlr_xdg_shell_v6.c', - 'xdg_shell_v6/wlr_xdg_surface_v6.c', - 'xdg_shell_v6/wlr_xdg_toplevel_v6.c', 'xdg_shell/wlr_xdg_popup.c', 'xdg_shell/wlr_xdg_positioner.c', 'xdg_shell/wlr_xdg_shell.c', diff --git a/types/xdg_shell_v6/wlr_xdg_popup_v6.c b/types/xdg_shell_v6/wlr_xdg_popup_v6.c deleted file mode 100644 index bed7e6d90..000000000 --- a/types/xdg_shell_v6/wlr_xdg_popup_v6.c +++ /dev/null @@ -1,585 +0,0 @@ -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -static struct wlr_xdg_surface_v6 *xdg_popup_grab_get_topmost( - struct wlr_xdg_popup_grab_v6 *grab) { - struct wlr_xdg_popup_v6 *popup; - wl_list_for_each(popup, &grab->popups, grab_link) { - return popup->base; - } - - return NULL; -} - -static void xdg_popup_grab_end(struct wlr_xdg_popup_grab_v6 *popup_grab) { - struct wlr_xdg_popup_v6 *popup, *tmp; - wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { - zxdg_popup_v6_send_popup_done(popup->resource); - } - - wlr_seat_pointer_end_grab(popup_grab->seat); - wlr_seat_keyboard_end_grab(popup_grab->seat); - wlr_seat_touch_end_grab(popup_grab->seat); -} - -static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, - struct wlr_surface *surface, double sx, double sy) { - struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; - if (wl_resource_get_client(surface->resource) == popup_grab->client) { - wlr_seat_pointer_enter(grab->seat, surface, sx, sy); - } else { - wlr_seat_pointer_clear_focus(grab->seat); - } -} - -static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) { - wlr_seat_pointer_clear_focus(grab->seat); -} - -static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab, - uint32_t time, double sx, double sy) { - wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); -} - -static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab, - uint32_t time, uint32_t button, uint32_t state) { - uint32_t serial = - wlr_seat_pointer_send_button(grab->seat, time, button, state); - if (serial) { - return serial; - } else { - xdg_popup_grab_end(grab->data); - return 0; - } -} - -static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab, - uint32_t time, enum wlr_axis_orientation orientation, double value, - int32_t value_discrete, enum wlr_axis_source source) { - wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, - value_discrete, source); -} - -static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) { - wlr_seat_pointer_send_frame(grab->seat); -} - -static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) { - xdg_popup_grab_end(grab->data); -} - -static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { - .enter = xdg_pointer_grab_enter, - .clear_focus = xdg_pointer_grab_clear_focus, - .motion = xdg_pointer_grab_motion, - .button = xdg_pointer_grab_button, - .cancel = xdg_pointer_grab_cancel, - .axis = xdg_pointer_grab_axis, - .frame = xdg_pointer_grab_frame, -}; - -static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab, - struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, - struct wlr_keyboard_modifiers *modifiers) { - // keyboard focus should remain on the popup -} - -static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) { - // keyboard focus should remain on the popup -} - -static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, - uint32_t time, uint32_t key, uint32_t state) { - wlr_seat_keyboard_send_key(grab->seat, time, key, state); -} - -static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, - struct wlr_keyboard_modifiers *modifiers) { - wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); -} - -static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { - wlr_seat_pointer_end_grab(grab->seat); -} - -static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { - .enter = xdg_keyboard_grab_enter, - .clear_focus = xdg_keyboard_grab_clear_focus, - .key = xdg_keyboard_grab_key, - .modifiers = xdg_keyboard_grab_modifiers, - .cancel = xdg_keyboard_grab_cancel, -}; - -static uint32_t xdg_touch_grab_down(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; - - if (wl_resource_get_client(point->surface->resource) != popup_grab->client) { - xdg_popup_grab_end(grab->data); - return 0; - } - - return wlr_seat_touch_send_down(grab->seat, point->surface, time, - point->touch_id, point->sx, point->sy); -} - -static void xdg_touch_grab_up(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - wlr_seat_touch_send_up(grab->seat, time, point->touch_id); -} - -static void xdg_touch_grab_motion(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, - point->sy); -} - -static void xdg_touch_grab_enter(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { -} - -static void xdg_touch_grab_cancel(struct wlr_seat_touch_grab *grab) { - wlr_seat_touch_end_grab(grab->seat); -} - -static const struct wlr_touch_grab_interface xdg_touch_grab_impl = { - .down = xdg_touch_grab_down, - .up = xdg_touch_grab_up, - .motion = xdg_touch_grab_motion, - .enter = xdg_touch_grab_enter, - .cancel = xdg_touch_grab_cancel -}; - -static void xdg_popup_grab_handle_seat_destroy( - struct wl_listener *listener, void *data) { - struct wlr_xdg_popup_grab_v6 *xdg_grab = - wl_container_of(listener, xdg_grab, seat_destroy); - - wl_list_remove(&xdg_grab->seat_destroy.link); - - struct wlr_xdg_popup_v6 *popup, *next; - wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { - destroy_xdg_surface_v6(popup->base); - } - - wl_list_remove(&xdg_grab->link); - free(xdg_grab); -} - -struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat( - struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) { - struct wlr_xdg_popup_grab_v6 *xdg_grab; - wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { - if (xdg_grab->seat == seat) { - return xdg_grab; - } - } - - xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab_v6)); - if (!xdg_grab) { - return NULL; - } - - xdg_grab->pointer_grab.data = xdg_grab; - xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; - xdg_grab->keyboard_grab.data = xdg_grab; - xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl; - xdg_grab->touch_grab.data = xdg_grab; - xdg_grab->touch_grab.interface = &xdg_touch_grab_impl; - - wl_list_init(&xdg_grab->popups); - - wl_list_insert(&shell->popup_grabs, &xdg_grab->link); - xdg_grab->seat = seat; - - xdg_grab->seat_destroy.notify = xdg_popup_grab_handle_seat_destroy; - wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); - - return xdg_grab; -} - - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_popup_v6_interface, - &zxdg_popup_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - unmap_xdg_surface_v6(surface); - - wl_resource_set_user_data(surface->popup->resource, NULL); - wl_list_remove(&surface->popup->link); - free(surface->popup); - surface->popup = NULL; - - surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; -} - -static void xdg_popup_handle_grab(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - struct wlr_seat_client *seat_client = - wlr_seat_client_from_resource(seat_resource); - if (!surface) { - return; - } - - if (surface->popup->committed) { - wl_resource_post_error(surface->popup->resource, - ZXDG_POPUP_V6_ERROR_INVALID_GRAB, - "xdg_popup is already mapped"); - return; - } - - struct wlr_xdg_popup_grab_v6 *popup_grab = - get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell, - seat_client->seat); - - struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); - bool parent_is_toplevel = - surface->popup->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - - if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup->parent)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was not created on the topmost popup"); - return; - } - - popup_grab->client = surface->client->client; - surface->popup->seat = seat_client->seat; - - wl_list_insert(&popup_grab->popups, &surface->popup->grab_link); - - wlr_seat_pointer_start_grab(seat_client->seat, - &popup_grab->pointer_grab); - wlr_seat_keyboard_start_grab(seat_client->seat, - &popup_grab->keyboard_grab); - wlr_seat_touch_start_grab(seat_client->seat, - &popup_grab->touch_grab); -} - -static void xdg_popup_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - - if (surface && !wl_list_empty(&surface->popups)) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was destroyed while it was not the topmost popup"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { - .destroy = xdg_popup_handle_destroy, - .grab = xdg_popup_handle_grab, -}; - -static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_popup_resource(resource); - if (surface != NULL) { - destroy_xdg_popup_v6(surface); - } -} - -void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - - if (!surface->popup->committed) { - schedule_xdg_surface_v6_configure(surface); - surface->popup->committed = true; - } -} - -const struct wlr_surface_role xdg_popup_v6_surface_role = { - .name = "xdg_popup_v6", - .commit = handle_xdg_surface_v6_commit, - .precommit = handle_xdg_surface_v6_precommit, -}; - -void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface, - struct wlr_xdg_surface_v6 *parent, - struct wlr_xdg_positioner_v6_resource *positioner, int32_t id) { - if (positioner->attrs.size.width == 0 || - positioner->attrs.anchor_rect.width == 0) { - wl_resource_post_error(xdg_surface->resource, - ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER, - "positioner object is not complete"); - return; - } - - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_popup_v6_surface_role, - xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) { - return; - } - - xdg_surface->popup = calloc(1, sizeof(struct wlr_xdg_popup_v6)); - if (!xdg_surface->popup) { - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - - xdg_surface->popup->resource = - wl_resource_create(xdg_surface->client->client, &zxdg_popup_v6_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (xdg_surface->popup->resource == NULL) { - free(xdg_surface->popup); - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - wl_resource_set_implementation(xdg_surface->popup->resource, - &zxdg_popup_v6_implementation, xdg_surface, - xdg_popup_handle_resource_destroy); - - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP; - xdg_surface->popup->base = xdg_surface; - xdg_surface->popup->parent = parent; - xdg_surface->popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&positioner->attrs); - - // positioner properties - memcpy(&xdg_surface->popup->positioner, &positioner->attrs, - sizeof(struct wlr_xdg_positioner_v6)); - - wl_list_insert(&parent->popups, &xdg_surface->popup->link); - - wlr_signal_emit_safe(&parent->events.new_popup, xdg_surface->popup); -} - -void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, - int *root_sx, int *root_sy) { - struct wlr_box rect = popup->positioner.anchor_rect; - enum zxdg_positioner_v6_anchor anchor = popup->positioner.anchor; - int sx = 0, sy = 0; - - if (anchor == ZXDG_POSITIONER_V6_ANCHOR_NONE) { - sx = (rect.x + rect.width) / 2; - sy = (rect.y + rect.height) / 2; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_TOP) { - sx = (rect.x + rect.width) / 2; - sy = rect.y; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - sx = (rect.x + rect.width) / 2; - sy = rect.y + rect.height; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - sx = rect.x; - sy = (rect.y + rect.height) / 2; - } else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - sx = rect.x + rect.width; - sy = (rect.y + rect.height) / 2; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP | - ZXDG_POSITIONER_V6_ANCHOR_LEFT)) { - sx = rect.x; - sy = rect.y; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP | - ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) { - sx = rect.x + rect.width; - sy = rect.y; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | - ZXDG_POSITIONER_V6_ANCHOR_LEFT)) { - sx = rect.x; - sy = rect.y + rect.height; - } else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | - ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) { - sx = rect.x + rect.width; - sy = rect.y + rect.height; - } - - *root_sx = sx; - *root_sy = sy; -} - -void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup, - int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) { - struct wlr_xdg_surface_v6 *parent = popup->parent; - while (parent != NULL && parent->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - popup_sx += parent->popup->geometry.x; - popup_sy += parent->popup->geometry.y; - parent = parent->popup->parent; - } - assert(parent); - - *toplevel_sx = popup_sx + parent->geometry.x; - *toplevel_sy = popup_sy + parent->geometry.y; -} - -static void xdg_popup_v6_box_constraints(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box, int *offset_x, int *offset_y) { - int popup_width = popup->geometry.width; - int popup_height = popup->geometry.height; - int anchor_sx = 0, anchor_sy = 0; - wlr_xdg_popup_v6_get_anchor_point(popup, &anchor_sx, &anchor_sy); - int popup_sx = 0, popup_sy = 0; - wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &popup_sx, &popup_sy); - *offset_x = 0, *offset_y = 0; - - if (popup_sx < toplevel_sx_box->x) { - *offset_x = toplevel_sx_box->x - popup_sx; - } else if (popup_sx + popup_width > - toplevel_sx_box->x + toplevel_sx_box->width) { - *offset_x = toplevel_sx_box->x + toplevel_sx_box->width - - (popup_sx + popup_width); - } - - if (popup_sy < toplevel_sx_box->y) { - *offset_y = toplevel_sx_box->y - popup_sy; - } else if (popup_sy + popup_height > - toplevel_sx_box->y + toplevel_sx_box->height) { - *offset_y = toplevel_sx_box->y + toplevel_sx_box->height - - (popup_sy + popup_height); - } -} - -static bool xdg_popup_v6_unconstrain_flip(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool flip_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X); - - bool flip_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y); - - if (flip_x) { - wlr_positioner_v6_invert_x(&popup->positioner); - } - if (flip_y) { - wlr_positioner_v6_invert_y(&popup->positioner); - } - - popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&popup->positioner); - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - // no longer constrained - return true; - } - - // revert the positioner back if it didn't fix it and go to the next part - if (offset_x && flip_x) { - wlr_positioner_v6_invert_x(&popup->positioner); - } - if (offset_y && flip_y) { - wlr_positioner_v6_invert_y(&popup->positioner); - } - - popup->geometry = - wlr_xdg_positioner_v6_get_geometry(&popup->positioner); - - return false; -} - -static bool xdg_popup_v6_unconstrain_slide(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x = 0, offset_y = 0; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool slide_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X); - - bool slide_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - - if (slide_x) { - popup->geometry.x += offset_x; - } - - if (slide_y) { - popup->geometry.y += offset_y; - } - - int toplevel_x = 0, toplevel_y = 0; - wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x, - popup->geometry.y, &toplevel_x, &toplevel_y); - - if (slide_x && toplevel_x < toplevel_sx_box->x) { - popup->geometry.x += toplevel_sx_box->x - toplevel_x; - } - if (slide_y && toplevel_y < toplevel_sx_box->y) { - popup->geometry.y += toplevel_sx_box->y - toplevel_y; - } - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - -static bool xdg_popup_v6_unconstrain_resize(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - int offset_x, offset_y; - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - if (!offset_x && !offset_y) { - return true; - } - - bool resize_x = offset_x && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X); - - bool resize_y = offset_y && - (popup->positioner.constraint_adjustment & - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); - - if (resize_x) { - popup->geometry.width -= offset_x; - } - if (resize_y) { - popup->geometry.height -= offset_y; - } - - xdg_popup_v6_box_constraints(popup, toplevel_sx_box, - &offset_x, &offset_y); - - return !offset_x && !offset_y; -} - -void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup, - struct wlr_box *toplevel_sx_box) { - if (xdg_popup_v6_unconstrain_flip(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_v6_unconstrain_slide(popup, toplevel_sx_box)) { - return; - } - if (xdg_popup_v6_unconstrain_resize(popup, toplevel_sx_box)) { - return; - } -} diff --git a/types/xdg_shell_v6/wlr_xdg_positioner_v6.c b/types/xdg_shell_v6/wlr_xdg_positioner_v6.c deleted file mode 100644 index eda19f30c..000000000 --- a/types/xdg_shell_v6/wlr_xdg_positioner_v6.c +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include "types/wlr_xdg_shell_v6.h" - -static const struct zxdg_positioner_v6_interface - zxdg_positioner_v6_implementation; - -struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_positioner_v6_interface, - &zxdg_positioner_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -static void xdg_positioner_destroy(struct wl_resource *resource) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - free(positioner); -} - -static void xdg_positioner_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void xdg_positioner_handle_set_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (width < 1 || height < 1) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positive and non-zero"); - return; - } - - positioner->attrs.size.width = width; - positioner->attrs.size.height = height; -} - -static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y, int32_t width, - int32_t height) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (width < 1 || height < 1) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "width and height must be positive and non-zero"); - return; - } - - positioner->attrs.anchor_rect.x = x; - positioner->attrs.anchor_rect.y = y; - positioner->attrs.anchor_rect.width = width; - positioner->attrs.anchor_rect.height = height; -} - -static void xdg_positioner_handle_set_anchor(struct wl_client *client, - struct wl_resource *resource, uint32_t anchor) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) && - (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) || - ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) && - (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "same-axis values are not allowed"); - return; - } - - positioner->attrs.anchor = anchor; -} - -static void xdg_positioner_handle_set_gravity(struct wl_client *client, - struct wl_resource *resource, uint32_t gravity) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) && - (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) || - ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) && - (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) { - wl_resource_post_error(resource, - ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, - "same-axis values are not allowed"); - return; - } - - positioner->attrs.gravity = gravity; -} - -static void xdg_positioner_handle_set_constraint_adjustment( - struct wl_client *client, struct wl_resource *resource, - uint32_t constraint_adjustment) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - positioner->attrs.constraint_adjustment = constraint_adjustment; -} - -static void xdg_positioner_handle_set_offset(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(resource); - - positioner->attrs.offset.x = x; - positioner->attrs.offset.y = y; -} - -static const struct zxdg_positioner_v6_interface - zxdg_positioner_v6_implementation = { - .destroy = xdg_positioner_handle_destroy, - .set_size = xdg_positioner_handle_set_size, - .set_anchor_rect = xdg_positioner_handle_set_anchor_rect, - .set_anchor = xdg_positioner_handle_set_anchor, - .set_gravity = xdg_positioner_handle_set_gravity, - .set_constraint_adjustment = - xdg_positioner_handle_set_constraint_adjustment, - .set_offset = xdg_positioner_handle_set_offset, -}; - -struct wlr_box wlr_xdg_positioner_v6_get_geometry( - struct wlr_xdg_positioner_v6 *positioner) { - struct wlr_box geometry = { - .x = positioner->offset.x, - .y = positioner->offset.y, - .width = positioner->size.width, - .height = positioner->size.height, - }; - - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { - geometry.y += positioner->anchor_rect.y; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height; - } else { - geometry.y += - positioner->anchor_rect.y + positioner->anchor_rect.height / 2; - } - - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - geometry.x += positioner->anchor_rect.x; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; - } else { - geometry.x += - positioner->anchor_rect.x + positioner->anchor_rect.width / 2; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) { - geometry.y -= geometry.height; - } else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) { - geometry.y -= geometry.height / 2; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) { - geometry.x -= geometry.width; - } else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) { - geometry.x -= geometry.width / 2; - } - - if (positioner->constraint_adjustment == - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE) { - return geometry; - } - - return geometry; -} - -void wlr_positioner_v6_invert_x(struct wlr_xdg_positioner_v6 *positioner) { - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_LEFT; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_RIGHT; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_RIGHT; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; - } else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_LEFT; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT; - } -} - -void wlr_positioner_v6_invert_y( - struct wlr_xdg_positioner_v6 *positioner) { - if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_TOP; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; - } else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { - positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; - positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP; - } - - if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_TOP; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; - } else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) { - positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; - positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP; - } -} - -void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id) { - struct wlr_xdg_positioner_v6_resource *positioner = - calloc(1, sizeof(struct wlr_xdg_positioner_v6_resource)); - if (positioner == NULL) { - wl_client_post_no_memory(client->client); - return; - } - - positioner->resource = wl_resource_create(client->client, - &zxdg_positioner_v6_interface, - wl_resource_get_version(client->resource), id); - if (positioner->resource == NULL) { - free(positioner); - wl_client_post_no_memory(client->client); - return; - } - wl_resource_set_implementation(positioner->resource, - &zxdg_positioner_v6_implementation, positioner, xdg_positioner_destroy); -} diff --git a/types/xdg_shell_v6/wlr_xdg_shell_v6.c b/types/xdg_shell_v6/wlr_xdg_shell_v6.c deleted file mode 100644 index fcaa41e16..000000000 --- a/types/xdg_shell_v6/wlr_xdg_shell_v6.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -#define SHELL_VERSION 1 - -static const struct zxdg_shell_v6_interface xdg_shell_impl; - -static struct wlr_xdg_client_v6 *xdg_client_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_shell_v6_interface, - &xdg_shell_impl)); - return wl_resource_get_user_data(resource); -} - -static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_client_v6 *client = - xdg_client_from_resource(resource); - create_xdg_positioner_v6(client, id); -} - -static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, - struct wl_resource *client_resource, uint32_t id, - struct wl_resource *surface_resource) { - struct wlr_xdg_client_v6 *client = - xdg_client_from_resource(client_resource); - struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); - create_xdg_surface_v6(client, surface, id); -} - -static void xdg_shell_handle_pong(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - if (client->ping_serial != serial) { - return; - } - - wl_event_source_timer_update(client->ping_timer, 0); - client->ping_serial = 0; -} - -static void xdg_shell_handle_destroy(struct wl_client *wl_client, - struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - if (!wl_list_empty(&client->surfaces)) { - wl_resource_post_error(client->resource, - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_wm_base was destroyed before children"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_shell_v6_interface xdg_shell_impl = { - .destroy = xdg_shell_handle_destroy, - .create_positioner = xdg_shell_handle_create_positioner, - .get_xdg_surface = xdg_shell_handle_get_xdg_surface, - .pong = xdg_shell_handle_pong, -}; - -static void xdg_client_v6_handle_resource_destroy( - struct wl_resource *resource) { - struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); - - struct wlr_xdg_surface_v6 *surface, *tmp = NULL; - wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { - wl_resource_destroy(surface->resource); - } - - if (client->ping_timer != NULL) { - wl_event_source_remove(client->ping_timer); - } - - wl_list_remove(&client->link); - free(client); -} - -static int xdg_client_v6_ping_timeout(void *user_data) { - struct wlr_xdg_client_v6 *client = user_data; - - struct wlr_xdg_surface_v6 *surface; - wl_list_for_each(surface, &client->surfaces, link) { - wlr_signal_emit_safe(&surface->events.ping_timeout, surface); - } - - client->ping_serial = 0; - return 1; -} - -static void xdg_shell_bind(struct wl_client *wl_client, void *data, - uint32_t version, uint32_t id) { - struct wlr_xdg_shell_v6 *xdg_shell = data; - assert(wl_client && xdg_shell); - - struct wlr_xdg_client_v6 *client = - calloc(1, sizeof(struct wlr_xdg_client_v6)); - if (client == NULL) { - wl_client_post_no_memory(wl_client); - return; - } - - wl_list_init(&client->surfaces); - - client->resource = - wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id); - if (client->resource == NULL) { - free(client); - wl_client_post_no_memory(wl_client); - return; - } - client->client = wl_client; - client->shell = xdg_shell; - - wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, - xdg_client_v6_handle_resource_destroy); - wl_list_insert(&xdg_shell->clients, &client->link); - - struct wl_display *display = wl_client_get_display(client->client); - struct wl_event_loop *loop = wl_display_get_event_loop(display); - client->ping_timer = wl_event_loop_add_timer(loop, - xdg_client_v6_ping_timeout, client); - if (client->ping_timer == NULL) { - wl_client_post_no_memory(client->client); - } -} - -static void handle_display_destroy(struct wl_listener *listener, void *data) { - struct wlr_xdg_shell_v6 *xdg_shell = - wl_container_of(listener, xdg_shell, display_destroy); - wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell); - wl_list_remove(&xdg_shell->display_destroy.link); - wl_global_destroy(xdg_shell->global); - free(xdg_shell); -} - -struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { - struct wlr_xdg_shell_v6 *xdg_shell = - calloc(1, sizeof(struct wlr_xdg_shell_v6)); - if (!xdg_shell) { - return NULL; - } - - xdg_shell->ping_timeout = 10000; - - wl_list_init(&xdg_shell->clients); - wl_list_init(&xdg_shell->popup_grabs); - - struct wl_global *global = wl_global_create(display, - &zxdg_shell_v6_interface, SHELL_VERSION, xdg_shell, xdg_shell_bind); - if (!global) { - free(xdg_shell); - return NULL; - } - xdg_shell->global = global; - - wl_signal_init(&xdg_shell->events.new_surface); - wl_signal_init(&xdg_shell->events.destroy); - - xdg_shell->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &xdg_shell->display_destroy); - - return xdg_shell; -} diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c deleted file mode 100644 index d9559b988..000000000 --- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c +++ /dev/null @@ -1,606 +0,0 @@ -#include -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface) { - return surface->role == &xdg_toplevel_v6_surface_role || - surface->role == &xdg_popup_v6_surface_role; -} - -struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( - struct wlr_surface *surface) { - assert(wlr_surface_is_xdg_surface_v6(surface)); - return (struct wlr_xdg_surface_v6 *)surface->role_data; -} - -static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface, - &zxdg_surface_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -static void xdg_surface_configure_destroy( - struct wlr_xdg_surface_v6_configure *configure) { - if (configure == NULL) { - return; - } - wl_list_remove(&configure->link); - free(configure->toplevel_state); - free(configure); -} - -void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); - - // TODO: probably need to ungrab before this event - if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, surface); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - free(surface->toplevel->title); - surface->toplevel->title = NULL; - free(surface->toplevel->app_id); - surface->toplevel->app_id = NULL; - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - if (surface->popup->seat != NULL) { - struct wlr_xdg_popup_grab_v6 *grab = - get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell, - surface->popup->seat); - - wl_list_remove(&surface->popup->grab_link); - - if (wl_list_empty(&grab->popups)) { - if (grab->seat->pointer_state.grab == &grab->pointer_grab) { - wlr_seat_pointer_end_grab(grab->seat); - } - if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) { - wlr_seat_keyboard_end_grab(grab->seat); - } - } - - surface->popup->seat = NULL; - } - break; - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(false && "not reached"); - } - - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - xdg_surface_configure_destroy(configure); - } - - surface->configured = surface->mapped = false; - surface->configure_serial = 0; - if (surface->configure_idle) { - wl_event_source_remove(surface->configure_idle); - surface->configure_idle = NULL; - } - surface->configure_next_serial = 0; - - surface->has_next_geometry = false; - memset(&surface->geometry, 0, sizeof(struct wlr_box)); - memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); -} - -void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) { - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { - unmap_xdg_surface_v6(surface); - } - - wlr_signal_emit_safe(&surface->events.destroy, surface); - - struct wlr_xdg_popup_v6 *popup_state, *next; - wl_list_for_each_safe(popup_state, next, &surface->popups, link) { - zxdg_popup_v6_send_popup_done(popup_state->resource); - destroy_xdg_popup_v6(popup_state->base); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - destroy_xdg_toplevel_v6(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - destroy_xdg_popup_v6(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_NONE: - // This space is intentionally left blank - break; - } - - wl_resource_set_user_data(surface->resource, NULL); - surface->surface->role_data = NULL; - wl_list_remove(&surface->link); - wl_list_remove(&surface->surface_destroy.link); - wl_list_remove(&surface->surface_commit.link); - free(surface); -} - -static void xdg_surface_handle_get_toplevel(struct wl_client *client, - struct wl_resource *resource, uint32_t id) { - struct wlr_xdg_surface_v6 *xdg_surface = xdg_surface_from_resource(resource); - create_xdg_toplevel_v6(xdg_surface, id); -} - -static void xdg_surface_handle_get_popup(struct wl_client *wl_client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *parent_resource, - struct wl_resource *positioner_resource) { - struct wlr_xdg_surface_v6 *xdg_surface = - xdg_surface_from_resource(resource); - struct wlr_xdg_surface_v6 *parent = - xdg_surface_from_resource(parent_resource); - struct wlr_xdg_positioner_v6_resource *positioner = - get_xdg_positioner_v6_from_resource(positioner_resource); - - create_xdg_popup_v6(xdg_surface, parent, positioner, id); -} - -static void xdg_surface_handle_ack_configure(struct wl_client *client, - struct wl_resource *resource, uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } - - // First find the ack'ed configure - bool found = false; - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each(configure, &surface->configure_list, link) { - if (configure->serial == serial) { - found = true; - break; - } - } - if (!found) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, - "wrong configure serial: %u", serial); - return; - } - // Then remove old configures from the list - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - if (configure->serial == serial) { - break; - } - xdg_surface_configure_destroy(configure); - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - handle_xdg_toplevel_v6_ack_configure(surface, configure); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - break; - } - - surface->configured = true; - surface->configure_serial = serial; - - xdg_surface_configure_destroy(configure); -} - -static void xdg_surface_handle_set_window_geometry(struct wl_client *client, - struct wl_resource *resource, int32_t x, int32_t y, int32_t width, - int32_t height) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } - - if (width <= 0 || height <= 0) { - wlr_log(WLR_ERROR, "Client tried to set invalid geometry"); - wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry"); - } - - - surface->has_next_geometry = true; - surface->next_geometry.height = height; - surface->next_geometry.width = width; - surface->next_geometry.x = x; - surface->next_geometry.y = y; -} - -static void xdg_surface_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { - wlr_log(WLR_ERROR, "Tried to destroy an xdg_surface before its role " - "object"); - return; - } - - wl_resource_destroy(resource); -} - -static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { - .destroy = xdg_surface_handle_destroy, - .get_toplevel = xdg_surface_handle_get_toplevel, - .get_popup = xdg_surface_handle_get_popup, - .ack_configure = xdg_surface_handle_ack_configure, - .set_window_geometry = xdg_surface_handle_set_window_geometry, -}; - -static void xdg_surface_send_configure(void *user_data) { - struct wlr_xdg_surface_v6 *surface = user_data; - - surface->configure_idle = NULL; - - struct wlr_xdg_surface_v6_configure *configure = - calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); - if (configure == NULL) { - wl_client_post_no_memory(surface->client->client); - return; - } - - wl_list_insert(surface->configure_list.prev, &configure->link); - configure->serial = surface->configure_next_serial; - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - send_xdg_toplevel_v6_configure(surface, configure); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - zxdg_popup_v6_send_configure(surface->popup->resource, - surface->popup->geometry.x, - surface->popup->geometry.y, - surface->popup->geometry.width, - surface->popup->geometry.height); - break; - } - - zxdg_surface_v6_send_configure(surface->resource, configure->serial); -} - -uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface) { - struct wl_display *display = wl_client_get_display(surface->client->client); - struct wl_event_loop *loop = wl_display_get_event_loop(display); - bool pending_same = false; - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - pending_same = - compare_xdg_surface_v6_toplevel_state(surface->toplevel); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - break; - } - - if (surface->configure_idle != NULL) { - if (!pending_same) { - // configure request already scheduled - return surface->configure_next_serial; - } - - // configure request not necessary anymore - wl_event_source_remove(surface->configure_idle); - surface->configure_idle = NULL; - return 0; - } else { - if (pending_same) { - // configure request not necessary - return 0; - } - - surface->configure_next_serial = wl_display_next_serial(display); - surface->configure_idle = wl_event_loop_add_idle(loop, - xdg_surface_send_configure, surface); - return surface->configure_next_serial; - } -} - -void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { - if (surface->client->ping_serial != 0) { - // already pinged - return; - } - - surface->client->ping_serial = - wl_display_next_serial(wl_client_get_display(surface->client->client)); - wl_event_source_timer_update(surface->client->ping_timer, - surface->client->shell->ping_timeout); - zxdg_shell_v6_send_ping(surface->client->resource, - surface->client->ping_serial); -} - -void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface) { - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - if (surface->toplevel) { - zxdg_toplevel_v6_send_close(surface->toplevel->resource); - } - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - if (surface->popup) { - zxdg_popup_v6_send_popup_done(surface->popup->resource); - } - break; - } -} - -static void xdg_surface_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_xdg_surface_v6 *xdg_surface = - wl_container_of(listener, xdg_surface, surface_destroy); - destroy_xdg_surface_v6(xdg_surface); -} - -static void xdg_surface_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct wlr_xdg_surface_v6 *surface = - wl_container_of(listener, surface, surface_commit); - - if (wlr_surface_has_buffer(surface->surface) && !surface->configured) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, - "xdg_surface has never been configured"); - return; - } - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { - wl_resource_post_error(surface->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "xdg_surface must have a role"); - return; - } -} - -void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface) { - struct wlr_xdg_surface_v6 *surface = - wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); - if (surface == NULL) { - return; - } - - if (surface->has_next_geometry) { - surface->has_next_geometry = false; - surface->geometry.x = surface->next_geometry.x; - surface->geometry.y = surface->next_geometry.y; - surface->geometry.width = surface->next_geometry.width; - surface->geometry.height = surface->next_geometry.height; - } - - switch (surface->role) { - case WLR_XDG_SURFACE_V6_ROLE_NONE: - assert(false); - case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: - handle_xdg_surface_v6_toplevel_committed(surface); - break; - case WLR_XDG_SURFACE_V6_ROLE_POPUP: - handle_xdg_surface_v6_popup_committed(surface); - break; - } - - if (!surface->added) { - surface->added = true; - wlr_signal_emit_safe(&surface->client->shell->events.new_surface, - surface); - } - if (surface->configured && wlr_surface_has_buffer(surface->surface) && - !surface->mapped) { - surface->mapped = true; - wlr_signal_emit_safe(&surface->events.map, surface); - } -} - -void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface) { - struct wlr_xdg_surface_v6 *surface = - wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); - if (surface == NULL) { - return; - } - - if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER && - wlr_surface->pending.buffer_resource == NULL) { - // This is a NULL commit - if (surface->configured && surface->mapped) { - unmap_xdg_surface_v6(surface); - } - } -} - -static void xdg_surface_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); - if (surface != NULL) { - destroy_xdg_surface_v6(surface); - } -} - -struct wlr_xdg_surface_v6 *create_xdg_surface_v6( - struct wlr_xdg_client_v6 *client, struct wlr_surface *surface, - uint32_t id) { - if (wlr_surface_has_buffer(surface)) { - wl_resource_post_error(client->resource, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, - "xdg_surface must not have a buffer at creation"); - return NULL; - } - - struct wlr_xdg_surface_v6 *xdg_surface = - calloc(1, sizeof(struct wlr_xdg_surface_v6)); - if (xdg_surface == NULL) { - wl_client_post_no_memory(client->client); - return NULL; - } - - xdg_surface->client = client; - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - xdg_surface->surface = surface; - xdg_surface->resource = wl_resource_create(client->client, - &zxdg_surface_v6_interface, wl_resource_get_version(client->resource), - id); - if (xdg_surface->resource == NULL) { - free(xdg_surface); - wl_client_post_no_memory(client->client); - return NULL; - } - wl_resource_set_implementation(xdg_surface->resource, - &zxdg_surface_v6_implementation, xdg_surface, - xdg_surface_handle_resource_destroy); - - wl_list_init(&xdg_surface->configure_list); - wl_list_init(&xdg_surface->popups); - - wl_signal_init(&xdg_surface->events.destroy); - wl_signal_init(&xdg_surface->events.ping_timeout); - wl_signal_init(&xdg_surface->events.new_popup); - wl_signal_init(&xdg_surface->events.map); - wl_signal_init(&xdg_surface->events.unmap); - - wl_signal_add(&xdg_surface->surface->events.destroy, - &xdg_surface->surface_destroy); - xdg_surface->surface_destroy.notify = xdg_surface_handle_surface_destroy; - - wl_signal_add(&xdg_surface->surface->events.commit, - &xdg_surface->surface_commit); - xdg_surface->surface_commit.notify = xdg_surface_handle_surface_commit; - - wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", xdg_surface, - xdg_surface->resource); - wl_list_insert(&client->surfaces, &xdg_surface->link); - - return xdg_surface; -} - -static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup, - double *popup_sx, double *popup_sy) { - struct wlr_xdg_surface_v6 *parent = popup->parent; - struct wlr_box parent_geo; - wlr_xdg_surface_v6_get_geometry(parent, &parent_geo); - *popup_sx = parent_geo.x + popup->geometry.x - - popup->base->geometry.x; - *popup_sy = parent_geo.y + popup->geometry.y - - popup->base->geometry.y; -} - -struct wlr_surface *wlr_xdg_surface_v6_surface_at( - struct wlr_xdg_surface_v6 *surface, double sx, double sy, - double *sub_x, double *sub_y) { - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - - struct wlr_surface *sub = wlr_xdg_surface_v6_surface_at(popup, - sx - popup_sx, - sy - popup_sy, - sub_x, sub_y); - if (sub != NULL) { - return sub; - } - } - - return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); -} - -struct xdg_surface_v6_iterator_data { - wlr_surface_iterator_func_t user_iterator; - void *user_data; - int x, y; -}; - -static void xdg_surface_v6_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct xdg_surface_v6_iterator_data *iter_data = data; - iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, - iter_data->user_data); -} - -static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct xdg_surface_v6_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .x = x, .y = y, - }; - wlr_surface_for_each_surface(surface->surface, xdg_surface_v6_iterator, - &data); - - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - - xdg_surface_v6_for_each_surface(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); - } -} - -static void xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy); - iterator(popup->surface, x + popup_sx, y + popup_sy, user_data); - - xdg_surface_v6_for_each_popup(popup, - x + popup_sx, - y + popup_sy, - iterator, user_data); - } -} - -void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data); -} - -void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - xdg_surface_v6_for_each_popup(surface, 0, 0, iterator, user_data); -} - -void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box) { - wlr_surface_get_extends(surface->surface, box); - /* The client never set the geometry */ - if (!surface->geometry.width) { - return; - } - - wlr_box_intersection(box, &surface->geometry, box); -} diff --git a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c b/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c deleted file mode 100644 index 2c626f83d..000000000 --- a/types/xdg_shell_v6/wlr_xdg_toplevel_v6.c +++ /dev/null @@ -1,525 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include "types/wlr_xdg_shell_v6.h" -#include "util/signal.h" - -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation; - -static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( - struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &zxdg_toplevel_v6_interface, - &zxdg_toplevel_v6_implementation)); - return wl_resource_get_user_data(resource); -} - -void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - unmap_xdg_surface_v6(surface); - - if (surface->toplevel->client_pending.fullscreen_output) { - struct wlr_xdg_toplevel_v6_state *client_pending = - &surface->toplevel->client_pending; - wl_list_remove(&client_pending->fullscreen_output_destroy.link); - } - wl_resource_set_user_data(surface->toplevel->resource, NULL); - free(surface->toplevel); - surface->toplevel = NULL; - - surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; -} - -static void xdg_toplevel_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void xdg_toplevel_handle_set_parent(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *parent_resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - struct wlr_xdg_surface_v6 *parent = NULL; - if (parent_resource != NULL) { - parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); - } - - surface->toplevel->parent = parent; - wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); -} - -static void xdg_toplevel_handle_set_title(struct wl_client *client, - struct wl_resource *resource, const char *title) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - char *tmp = strdup(title); - if (tmp == NULL) { - return; - } - - free(surface->toplevel->title); - surface->toplevel->title = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface); -} - -static void xdg_toplevel_handle_set_app_id(struct wl_client *client, - struct wl_resource *resource, const char *app_id) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - char *tmp = strdup(app_id); - if (tmp == NULL) { - return; - } - - free(surface->toplevel->app_id); - surface->toplevel->app_id = tmp; - wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface); -} - -static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial, int32_t x, int32_t y) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_show_window_menu_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - .x = x, - .y = y, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu, - &event); -} - -static void xdg_toplevel_handle_move(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_move_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event); -} - -static void xdg_toplevel_handle_resize(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat_resource, - uint32_t serial, uint32_t edges) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - struct wlr_seat_client *seat = - wlr_seat_client_from_resource(seat_resource); - - if (!surface->configured) { - wl_resource_post_error(surface->toplevel->resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, - "surface has not been configured yet"); - return; - } - - if (!wlr_seat_validate_grab_serial(seat->seat, serial)) { - wlr_log(WLR_DEBUG, "invalid serial for grab"); - return; - } - - struct wlr_xdg_toplevel_v6_resize_event event = { - .surface = surface, - .seat = seat, - .serial = serial, - .edges = edges, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event); -} - -static void xdg_toplevel_handle_set_max_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.max_width = width; - surface->toplevel->client_pending.max_height = height; -} - -static void xdg_toplevel_handle_set_min_size(struct wl_client *client, - struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.min_width = width; - surface->toplevel->client_pending.min_height = height; -} - -static void xdg_toplevel_handle_set_maximized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.maximized = true; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); -} - -static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel->client_pending.maximized = false; - wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface); -} - -static void handle_fullscreen_output_destroy(struct wl_listener *listener, - void *data) { - struct wlr_xdg_toplevel_v6_state *state = - wl_container_of(listener, state, fullscreen_output_destroy); - state->fullscreen_output = NULL; - wl_list_remove(&state->fullscreen_output_destroy.link); -} - -static void store_fullscreen_pending(struct wlr_xdg_surface_v6 *surface, - bool fullscreen, struct wlr_output *output) { - struct wlr_xdg_toplevel_v6_state *state = - &surface->toplevel->client_pending; - state->fullscreen = fullscreen; - if (state->fullscreen_output) { - wl_list_remove(&state->fullscreen_output_destroy.link); - } - state->fullscreen_output = output; - if (state->fullscreen_output) { - state->fullscreen_output_destroy.notify = - handle_fullscreen_output_destroy; - wl_signal_add(&state->fullscreen_output->events.destroy, - &state->fullscreen_output_destroy); - } -} - -static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *output_resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - struct wlr_output *output = NULL; - if (output_resource != NULL) { - output = wlr_output_from_resource(output_resource); - } - - store_fullscreen_pending(surface, true, output); - - struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { - .surface = surface, - .fullscreen = true, - .output = output, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); -} - -static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - - store_fullscreen_pending(surface, false, NULL); - - struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { - .surface = surface, - .fullscreen = false, - .output = NULL, - }; - - wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event); -} - -static void xdg_toplevel_handle_set_minimized(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface); -} - -static const struct zxdg_toplevel_v6_interface - zxdg_toplevel_v6_implementation = { - .destroy = xdg_toplevel_handle_destroy, - .set_parent = xdg_toplevel_handle_set_parent, - .set_title = xdg_toplevel_handle_set_title, - .set_app_id = xdg_toplevel_handle_set_app_id, - .show_window_menu = xdg_toplevel_handle_show_window_menu, - .move = xdg_toplevel_handle_move, - .resize = xdg_toplevel_handle_resize, - .set_max_size = xdg_toplevel_handle_set_max_size, - .set_min_size = xdg_toplevel_handle_set_min_size, - .set_maximized = xdg_toplevel_handle_set_maximized, - .unset_maximized = xdg_toplevel_handle_unset_maximized, - .set_fullscreen = xdg_toplevel_handle_set_fullscreen, - .unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, - .set_minimized = xdg_toplevel_handle_set_minimized, -}; - -void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - assert(configure->toplevel_state != NULL); - - surface->toplevel->last_acked = *configure->toplevel_state; -} - -bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) { - // is pending state different from current state? - if (!state->base->configured) { - return false; - } - - struct wlr_xdg_toplevel_v6_state *configured = NULL; - if (wl_list_empty(&state->base->configure_list)) { - // There are currently no pending configures, so check against the last - // state acked by the client. - configured = &state->last_acked; - } else { - struct wlr_xdg_surface_v6_configure *configure = - wl_container_of(state->base->configure_list.prev, configure, link); - configured = configure->toplevel_state; - } - - if (state->server_pending.activated != configured->activated) { - return false; - } - if (state->server_pending.fullscreen != configured->fullscreen) { - return false; - } - if (state->server_pending.maximized != configured->maximized) { - return false; - } - if (state->server_pending.resizing != configured->resizing) { - return false; - } - - if (state->server_pending.width == configured->width && - state->server_pending.height == configured->height) { - return true; - } - - if (state->server_pending.width == 0 && state->server_pending.height == 0) { - return true; - } - - return false; -} - -void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); - if (configure->toplevel_state == NULL) { - wlr_log(WLR_ERROR, "Allocation failed"); - wl_resource_post_no_memory(surface->toplevel->resource); - return; - } - *configure->toplevel_state = surface->toplevel->server_pending; - - uint32_t *s; - struct wl_array states; - wl_array_init(&states); - if (surface->toplevel->server_pending.maximized) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for maximized xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; - } - if (surface->toplevel->server_pending.fullscreen) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for fullscreen xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; - } - if (surface->toplevel->server_pending.resizing) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for resizing xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; - } - if (surface->toplevel->server_pending.activated) { - s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for activated xdg_toplevel"); - goto error_out; - } - *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; - } - - uint32_t width = surface->toplevel->server_pending.width; - uint32_t height = surface->toplevel->server_pending.height; - zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, - height, &states); - - wl_array_release(&states); - return; - -error_out: - wl_array_release(&states); - wl_resource_post_no_memory(surface->toplevel->resource); -} - -void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - if (!surface->toplevel->added) { - // on the first commit, send a configure request to tell the client it - // is added - schedule_xdg_surface_v6_configure(surface); - surface->toplevel->added = true; - return; - } - - // apply state from the last acked configure now that the client committed - surface->toplevel->current = surface->toplevel->last_acked; - - // update state from the client that doesn't need compositor approval - surface->toplevel->current.max_width = - surface->toplevel->client_pending.max_width; - surface->toplevel->current.min_width = - surface->toplevel->client_pending.min_width; - surface->toplevel->current.max_height = - surface->toplevel->client_pending.max_height; - surface->toplevel->current.min_height = - surface->toplevel->client_pending.min_height; -} - -static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = - xdg_surface_from_xdg_toplevel_resource(resource); - if (surface != NULL) { - destroy_xdg_toplevel_v6(surface); - } -} - -const struct wlr_surface_role xdg_toplevel_v6_surface_role = { - .name = "xdg_toplevel_v6", - .commit = handle_xdg_surface_v6_commit, - .precommit = handle_xdg_surface_v6_precommit, -}; - -void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface, - uint32_t id) { - if (!wlr_surface_set_role(xdg_surface->surface, &xdg_toplevel_v6_surface_role, - xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) { - return; - } - - xdg_surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); - if (xdg_surface->toplevel == NULL) { - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - wl_signal_init(&xdg_surface->toplevel->events.request_maximize); - wl_signal_init(&xdg_surface->toplevel->events.request_fullscreen); - wl_signal_init(&xdg_surface->toplevel->events.request_minimize); - wl_signal_init(&xdg_surface->toplevel->events.request_move); - wl_signal_init(&xdg_surface->toplevel->events.request_resize); - wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu); - wl_signal_init(&xdg_surface->toplevel->events.set_parent); - wl_signal_init(&xdg_surface->toplevel->events.set_title); - wl_signal_init(&xdg_surface->toplevel->events.set_app_id); - - xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - xdg_surface->toplevel->base = xdg_surface; - - struct wl_resource *toplevel_resource = wl_resource_create( - xdg_surface->client->client, &zxdg_toplevel_v6_interface, - wl_resource_get_version(xdg_surface->resource), id); - if (toplevel_resource == NULL) { - free(xdg_surface->toplevel); - wl_resource_post_no_memory(xdg_surface->resource); - return; - } - xdg_surface->toplevel->resource = toplevel_resource; - wl_resource_set_implementation(toplevel_resource, - &zxdg_toplevel_v6_implementation, xdg_surface, - xdg_toplevel_handle_resource_destroy); -} - -uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, - uint32_t width, uint32_t height) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.width = width; - surface->toplevel->server_pending.height = height; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, - bool activated) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.activated = activated; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, - bool maximized) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.maximized = maximized; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, - bool fullscreen) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.fullscreen = fullscreen; - - return schedule_xdg_surface_v6_configure(surface); -} - -uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, - bool resizing) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel->server_pending.resizing = resizing; - - return schedule_xdg_surface_v6_configure(surface); -} From efe6414640aa15cfad975dec3db427936c0450a4 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 4 Sep 2020 00:08:45 +0200 Subject: [PATCH 039/223] wayland: emit relative pointer events only for current pointer --- backend/wayland/seat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d19744d82..71e04de6b 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -450,6 +450,9 @@ static void relative_pointer_handle_relative_motion(void *data, wl_fixed_t dy_unaccel) { struct wlr_wl_input_device *input_device = data; struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; + if (pointer_get_wl(wlr_dev->pointer) != input_device->backend->current_pointer) { + return; + } uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo; From fa05d3cde68de73df4cac9762f6623c6001651cc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 3 Sep 2020 21:25:33 +0200 Subject: [PATCH 040/223] session: Don't refuse unprivileged creation of "direct" backend When starting a compositor that's using the "direct" session backend, wlroots needs to handle calls to `drmSetMaster()` and `drmDropMaster()`. As both calls used to require `CAP_SYS_ADMIN`, wlroots thus simply refused starting in case the process doesn't enjoy evelated privileges. Permission rules have changed since linux.git commit 45bc3d26c95a (drm: rework SET_MASTER and DROP_MASTER perm handling, 2020-03-19). As a result, starting with Linux v5.8, both ioctls will now also succeed if the process is currently or has been the DRM master. And as the first process to open render nodes will become the DRM master automatically, this effectively means that process elevation is not strictly required in all setups anymore. So let's drop the `geteuid() != 0` permission check to allow those new rules to do their magic. --- backend/session/direct-ipc.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 94f34a88d..d98d4e669 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -24,16 +24,6 @@ enum { DRM_MAJOR = 226 }; -static bool have_permissions(void) { -#ifdef __linux__ - if (geteuid() != 0) { - wlr_log(WLR_ERROR, "Do not have root privileges; cannot become DRM master"); - return false; - } -#endif - return true; -} - static void send_msg(int sock, int fd, void *buf, size_t buf_len) { char control[CMSG_SPACE(sizeof(fd))] = {0}; struct iovec iovec = { .iov_base = buf, .iov_len = buf_len }; @@ -223,10 +213,6 @@ void direct_ipc_finish(int sock, pid_t pid) { } int direct_ipc_init(pid_t *pid_out) { - if (!have_permissions()) { - return -1; - } - int sock[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock) < 0) { wlr_log_errno(WLR_ERROR, "Failed to create socket pair"); From e44bed0c2b77c944e389efd026948d8ef1230cec Mon Sep 17 00:00:00 2001 From: nerdopolis Date: Tue, 1 Sep 2020 20:00:33 -0400 Subject: [PATCH 041/223] Accommodate for CONFIG_VT=0, all TTYs are in seat0, but not all seat0s have TTYs --- backend/session/logind.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index b9249eced..9c2515a87 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -130,8 +130,8 @@ static void logind_release_device(struct wlr_session *base, int fd) { static bool logind_change_vt(struct wlr_session *base, unsigned vt) { struct logind_session *session = logind_session_from_session(base); - // Only seat0 has VTs associated with it - if (strcmp(session->base.seat, "seat0") != 0) { + // Only if seat has VTs associated with it + if (!sd_seat_can_tty(session->base.seat)) { return true; } @@ -791,7 +791,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { } snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); - if (strcmp(seat, "seat0") == 0) { + if (sd_seat_can_tty(seat)) { ret = sd_session_get_vt(session->id, &session->base.vtnr); if (ret < 0) { wlr_log(WLR_ERROR, "Session not running in virtual terminal"); From 3e03f786ee50f22175db3b7422085df2fa2751d8 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 4 Sep 2020 13:03:21 +0200 Subject: [PATCH 042/223] xwayland: disconnect display destroy listener even if xwayland didn't initialize --- xwayland/server.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/xwayland/server.c b/xwayland/server.c index b257f2451..27e9861a4 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -150,7 +150,13 @@ static void server_finish_process(struct wlr_xwayland_server *server) { } static void server_finish_display(struct wlr_xwayland_server *server) { - if (!server || server->display == -1) { + if (!server) { + return; + } + + wl_list_remove(&server->display_destroy.link); + + if (server->display == -1) { return; } @@ -158,8 +164,6 @@ static void server_finish_display(struct wlr_xwayland_server *server) { safe_close(server->x_fd[1]); server->x_fd[0] = server->x_fd[1] = -1; - wl_list_remove(&server->display_destroy.link); - unlink_display_sockets(server->display); server->display = -1; server->display_name[0] = '\0'; From e4a7075a9e197781526839a258fbfadb7d0f1e19 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 3 Sep 2020 14:20:04 +0200 Subject: [PATCH 043/223] output-management-v1: add head identifying events The following information through separate events are added: - make - model - serial_number This should allow clients to identify a display over different sessions and load configuration data back. A note is added that the description should be preferred when representing a display in UI to users but as a short form for example the model could be used in this case of course too. --- .../wlr-output-management-unstable-v1.xml | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/protocol/wlr-output-management-unstable-v1.xml b/protocol/wlr-output-management-unstable-v1.xml index 35f7ca4e3..cadc45fb2 100644 --- a/protocol/wlr-output-management-unstable-v1.xml +++ b/protocol/wlr-output-management-unstable-v1.xml @@ -39,7 +39,7 @@ interface version number is reset. - + This interface is a manager that allows reading and writing the current output device configuration. @@ -125,7 +125,7 @@ - + A head is an output device. The difference between a wl_output object and a head is that heads are advertised even if they are turned off. A head @@ -257,9 +257,80 @@ resources associated with it. + + + + + This event describes the manufacturer of the head. + + This must report the same make as the wl_output interface does in its + geometry event. + + Together with the model and serial_number events the purpose is to + allow clients to recognize heads from previous sessions and for example + load head-specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the make of + the head or the definition of a make is not sensible in the current + setup, for example in a virtual session. Clients can still try to + identify the head by available information from other events but should + be aware that there is an increased risk of false positives. + + It is not recommended to display the make string in UI to users. For + that the string provided by the description event should be preferred. + + + + + + + This event describes the model of the head. + + This must report the same model as the wl_output interface does in its + geometry event. + + Together with the make and serial_number events the purpose is to + allow clients to recognize heads from previous sessions and for example + load head-specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the model of + the head or the definition of a model is not sensible in the current + setup, for example in a virtual session. Clients can still try to + identify the head by available information from other events but should + be aware that there is an increased risk of false positives. + + It is not recommended to display the model string in UI to users. For + that the string provided by the description event should be preferred. + + + + + + + This event describes the serial number of the head. + + Together with the make and model events the purpose is to allow clients + to recognize heads from previous sessions and for example load head- + specific configurations back. + + It is not guaranteed this event will be ever sent. A reason for that + can be that the compositor does not have information about the serial + number of the head or the definition of a serial number is not sensible + in the current setup. Clients can still try to identify the head by + available information from other events but should be aware that there + is an increased risk of false positives. + + It is not recommended to display the serial_number string in UI to + users. For that the string provided by the description event should be + preferred. + + + - + This object describes an output mode. @@ -305,7 +376,7 @@ - + This object is used by the client to describe a full output configuration. @@ -423,7 +494,7 @@ - + This object is used by the client to update a single head's configuration. From bae8d7593c4ac9d72ddc90bded52e96056330ca2 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 3 Sep 2020 14:42:35 +0200 Subject: [PATCH 044/223] output-management-v1: send head identifying information With version 2 we send make, model and serial number to allow clients the identification of heads. --- types/wlr_output_management_v1.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index 15a971f60..ae20e0d79 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -6,7 +6,7 @@ #include "util/signal.h" #include "wlr-output-management-unstable-v1-protocol.h" -#define OUTPUT_MANAGER_VERSION 1 +#define OUTPUT_MANAGER_VERSION 2 enum { HEAD_STATE_ENABLED = 1 << 0, @@ -761,6 +761,16 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager, output->phys_width, output->phys_height); } + if (version >= ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION && output->make[0] != '\0') { + zwlr_output_head_v1_send_make(head_resource, output->make); + } + if (version >= ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION && output->model[0] != '\0') { + zwlr_output_head_v1_send_model(head_resource, output->model); + } + if (version >= ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION && output->serial[0] != '\0') { + zwlr_output_head_v1_send_serial_number(head_resource, output->serial); + } + struct wlr_output_mode *mode; wl_list_for_each(mode, &output->modes, link) { head_send_mode(head, head_resource, mode); From 8ad2cc39eb420c22dde7e49c01bde916b7bc58cc Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 8 Sep 2020 18:03:33 +0200 Subject: [PATCH 045/223] layer-shell: add for_each_popup This brings the layer-shell api in line with that of xdg-shell and avoids reimplementing this function in every compositor in order to render layer shell popups correctly. --- include/wlr/types/wlr_layer_shell_v1.h | 4 ++++ types/wlr_layer_shell_v1.c | 15 +++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index b6a0a1352..f13eadb7f 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -138,6 +138,10 @@ struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, wlr_surface_iterator_func_t iterator, void *user_data); +/* Calls the iterator function for each popup of this surface */ +void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + /** * Find a surface within this layer-surface tree at the given surface-local * coordinates. Returns the surface and coordinates in the leaf surface diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index db2113e3f..d83b22b86 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -534,16 +534,20 @@ static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, } } -static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface, - int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { +void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { struct layer_surface_iterator_data data = { .user_iterator = iterator, .user_data = user_data, - .x = x, .y = y, + .x = 0, .y = 0, }; wlr_surface_for_each_surface(surface->surface, layer_surface_iterator, &data); + wlr_layer_surface_v1_for_each_popup(surface, iterator, user_data); +} +void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface, + wlr_surface_iterator_func_t iterator, void *user_data){ struct wlr_xdg_popup *popup_state; wl_list_for_each(popup_state, &surface->popups, link) { struct wlr_xdg_surface *popup = popup_state->base; @@ -560,11 +564,6 @@ static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface, } } -void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, - wlr_surface_iterator_func_t iterator, void *user_data) { - layer_surface_for_each_surface(surface, 0, 0, iterator, user_data); -} - struct wlr_surface *wlr_layer_surface_v1_surface_at( struct wlr_layer_surface_v1 *surface, double sx, double sy, double *sub_x, double *sub_y) { From 87836dcb55e15cd1f19f5549d4fcd666135dba15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 16 Sep 2020 12:54:40 +0200 Subject: [PATCH 046/223] backend: remove check for _WAYLAND_DISPLAY I'm not sure what this was used for, but it's not used by libwayland. Setting _WAYLAND_DISPLAY would result in the Wayland backend being picked but would ignore the actual value of the env variable. --- backend/backend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index c71b072f7..aa0d9668d 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -254,8 +254,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, return backend; } - if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") || - getenv("WAYLAND_SOCKET")) { + if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) { struct wlr_backend *wl_backend = attempt_wl_backend(display, create_renderer_func); if (!wl_backend) { From 5012121d331c97bc6af856dd58d68b5be336b573 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 19 Sep 2020 11:36:33 +0200 Subject: [PATCH 047/223] xwm: add loop detection for read_surface_parent Implement a simple loop detection while trying to retrieve the parent for a TRANSIENT_FOR window. Fixes swaywm/sway#4624 --- xwayland/xwm.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 87b9edc13..b3e6c885e 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -467,20 +467,41 @@ static void read_surface_title(struct wlr_xwm *xwm, wlr_signal_emit_safe(&xsurface->events.set_title, xsurface); } +static bool has_parent(struct wlr_xwayland_surface *parent, + struct wlr_xwayland_surface *child) { + while (parent) { + if (child == parent) { + return true; + } + + parent = parent->parent; + } + + return false; +} + static void read_surface_parent(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface, xcb_get_property_reply_t *reply) { + struct wlr_xwayland_surface *found_parent = NULL; if (reply->type != XCB_ATOM_WINDOW) { return; } xcb_window_t *xid = xcb_get_property_value(reply); if (xid != NULL) { - xsurface->parent = lookup_surface(xwm, *xid); + found_parent = lookup_surface(xwm, *xid); + if (!has_parent(found_parent, xsurface)) { + xsurface->parent = found_parent; + } else { + wlr_log(WLR_INFO, "%p with %p would create a loop", xsurface, + found_parent); + } } else { xsurface->parent = NULL; } + wl_list_remove(&xsurface->parent_link); if (xsurface->parent != NULL) { wl_list_insert(&xsurface->parent->children, &xsurface->parent_link); From 8dec751a6d84335fb04288b8efab6dd5c90288d3 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 9 Oct 2020 15:28:07 +0200 Subject: [PATCH 048/223] layer-shell: error on 0 dimension without anchors The protocol requires clients to set opposing anchors when requesting a width or height of 0. The goal of this patch is not to break clients that rely on this behavior but to improve the consistency of the layer shell ecosystem through adherence to the protocol. --- types/wlr_layer_shell_v1.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index d83b22b86..bc6811179 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -307,6 +307,26 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { return; } + const uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + if (surface->client_pending.desired_width == 0 && + (surface->client_pending.anchor & horiz) != horiz) { + wl_resource_post_error(surface->resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE, + "width 0 requested without setting left and right anchors"); + return; + } + + const uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + if (surface->client_pending.desired_height == 0 && + (surface->client_pending.anchor & vert) != vert) { + wl_resource_post_error(surface->resource, + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE, + "height 0 requested without setting top and bottom anchors"); + return; + } + if (surface->closed) { // Ignore commits after the compositor has closed it return; From 86c0b9986b82a477dea7e6029c0fe565dd7af429 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 1 Oct 2020 14:32:57 +0200 Subject: [PATCH 049/223] output-management-v1: send complete head state on enable change The data of a head is only sent when it is enabled. While the head was disabled data might have been changed. In this case clients were not informed about this change. A later enable change that does not also update the other data must still lead to the propagation of this data. Since we do not know what other data was changed while the head was disabled just send together with an enable change all current data. --- types/wlr_output_management_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index ae20e0d79..728abee7c 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -680,6 +680,9 @@ static void head_send_state(struct wlr_output_head_v1 *head, if (state & HEAD_STATE_ENABLED) { zwlr_output_head_v1_send_enabled(head_resource, head->state.enabled); + // On enabling we send all current data since clients have not been + // notified about potential data changes while the head was disabled. + state = HEAD_STATE_ALL; } if (!head->state.enabled) { From 45c1a3621cc6874e5b5d9694015241668980df5d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Oct 2020 16:47:29 +0200 Subject: [PATCH 050/223] backend/libinput: improve logger callback - Add a prefix to make it clear log messages come from libinput - Properly convert libinput log priority to wlroots' --- backend/libinput/backend.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 87497b11d..3c42d7f8f 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -44,9 +44,24 @@ static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) { return 0; } +static enum wlr_log_importance libinput_log_priority_to_wlr( + enum libinput_log_priority priority) { + switch (priority) { + case LIBINPUT_LOG_PRIORITY_ERROR: + return WLR_ERROR; + case LIBINPUT_LOG_PRIORITY_INFO: + return WLR_INFO; + default: + return WLR_DEBUG; + } +} + static void log_libinput(struct libinput *libinput_context, enum libinput_log_priority priority, const char *fmt, va_list args) { - _wlr_vlog(WLR_ERROR, fmt, args); + enum wlr_log_importance importance = libinput_log_priority_to_wlr(priority); + static char wlr_fmt[1024]; + snprintf(wlr_fmt, sizeof(wlr_fmt), "[libinput] %s", fmt); + _wlr_vlog(importance, wlr_fmt, args); } static bool backend_start(struct wlr_backend *wlr_backend) { From ec3f432bbb4cbcb75adc695753353239e017a8bd Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:57:45 -0400 Subject: [PATCH 051/223] examples: use `perror` instead of `fprintf` GNU %m `printf` extension --- examples/screencopy-dmabuf.c | 6 +++--- examples/screencopy.c | 4 ++-- examples/virtual-pointer.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/screencopy-dmabuf.c b/examples/screencopy-dmabuf.c index 2525efc5a..e7657e1a9 100644 --- a/examples/screencopy-dmabuf.c +++ b/examples/screencopy-dmabuf.c @@ -297,7 +297,7 @@ int main(int argc, char *argv[]) { drm_fd = open(render_node, O_RDWR); if (drm_fd < 0) { - fprintf(stderr, "Failed to open drm render node: %m\n"); + perror("Failed to open drm render node"); return EXIT_FAILURE; } @@ -309,7 +309,7 @@ int main(int argc, char *argv[]) { struct wl_display *display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } @@ -343,7 +343,7 @@ int main(int argc, char *argv[]) { void *data = gbm_bo_map(buffer.bo, 0, 0, buffer.width, buffer.height, GBM_BO_TRANSFER_READ, &stride, &map_data); if (!data) { - fprintf(stderr, "Failed to map gbm bo: %m\n"); + perror("Failed to map gbm bo"); return EXIT_FAILURE; } diff --git a/examples/screencopy.c b/examples/screencopy.c index 0e03a2384..42123e55e 100644 --- a/examples/screencopy.c +++ b/examples/screencopy.c @@ -90,7 +90,7 @@ static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt, void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %m\n"); + perror("mmap failed"); close(fd); return NULL; } @@ -228,7 +228,7 @@ static void write_image(char *filename, enum wl_shm_format wl_fmt, int width, int main(int argc, char *argv[]) { struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } diff --git a/examples/virtual-pointer.c b/examples/virtual-pointer.c index 8fd148305..b91768a47 100644 --- a/examples/virtual-pointer.c +++ b/examples/virtual-pointer.c @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) { } struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); + perror("failed to create display"); return EXIT_FAILURE; } From ab80ad902e5914d8b7fbe08f155ac49917acbad0 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:58:57 -0400 Subject: [PATCH 052/223] xwayland: using %m in `wlr_log` is broken, use `wlr_log_errno` instead This one was awful to track down, but calls to `wlr_log` with %m have the errno masked by the `isatty` call in `log_stderr`. Switch them to `wlr_log_errno` instead. Cue quality "how can read(2) POSSIBLY be returning ENOTTY?" moments. --- xwayland/selection/outgoing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 002c0143c..33aa225b4 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -92,7 +92,7 @@ static int xwm_data_source_read(int fd, uint32_t mask, void *data) { size_t available = transfer->source_data.alloc - current; ssize_t len = read(fd, p, available); if (len == -1) { - wlr_log(WLR_ERROR, "read error from data source: %m"); + wlr_log_errno(WLR_ERROR, "read error from data source"); goto error_out; } @@ -289,7 +289,7 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, int p[2]; if (pipe(p) == -1) { - wlr_log(WLR_ERROR, "pipe() failed: %m"); + wlr_log_errno(WLR_ERROR, "pipe() failed"); xwm_selection_send_notify(selection->xwm, req, false); return; } From feb0e1c74d13c44c4c0b8c8db360039846bc9617 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 10 Oct 2020 22:51:50 -0400 Subject: [PATCH 053/223] xwayland: fix use-after-free in selection handling Fixes #2425. wlroots can only handle one outgoing transfer at a time, so it keeps a list of pending selections. The head of the list is the currently-active selection, and when that transfer completes and is destroyed, the next one is started. The trouble is when you have a transfer to some app that is misbehaving. fcitx is one such application. With really large transfers, fcitx will hang and never wake up again. So, you can end up with a transfer list that looks like this: | T1: started | T2: pending | T3: pending | T4: pending | The file descriptor for transfer T1 is registered in libwayland's epoll loop. The rest are waiting in wlroots' list. As a user, you want your clipboard back, so you `pkill fcitx`. Now Xwayland sends `XCB_DESTROY_NOTIFY` to let us know to give up. We clean up T4 first. Due to a bug in wlroots code, we register the (fd, transfer data pointer) pair for T1 with libwayland *again*, despite it already being registered. We do this 2 more times as we remove T3 and T2. Finally, we remove T1 and `free` all the memory associated with it, before `close`-ing its transfer file descriptor. However, we still have 3 copies of T1's file descriptor left in the epoll loop, since we erroneously added them as part of removing T2/3/4. When we `close` the file descriptor as part of T1's teardown, we actually cause the epoll loop to wake up the next time around, saying "this file descriptor has activity!" (it was closed, so `read`-ing would normally return 0 to let us know of EOF). But instead of returning 0, it returns -1 with `EBADF`, because the file descriptor has already been closed. And finally, as part of error-handling this, we access the transfer pointer, which was `free`'d. And we crash. --- xwayland/selection/outgoing.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 33aa225b4..943e4d1a4 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -55,16 +55,27 @@ static int xwm_selection_flush_source_data( static void xwm_selection_transfer_start_outgoing( struct wlr_xwm_selection_transfer *transfer); +static struct wlr_xwm_selection_transfer *xwm_selection_transfer_get_first( + struct wlr_xwm_selection *selection) { + struct wlr_xwm_selection_transfer *first = NULL; + if (!wl_list_empty(&selection->outgoing)) { + first = wl_container_of(selection->outgoing.prev, first, + outgoing_link); + } + + return first; +} + static void xwm_selection_transfer_destroy_outgoing( struct wlr_xwm_selection_transfer *transfer) { + struct wlr_xwm_selection *selection = transfer->selection; + bool was_first = transfer == xwm_selection_transfer_get_first(selection); wl_list_remove(&transfer->outgoing_link); - // Start next queued transfer - struct wlr_xwm_selection_transfer *first = NULL; - if (!wl_list_empty(&transfer->selection->outgoing)) { - first = wl_container_of(transfer->selection->outgoing.prev, first, - outgoing_link); - xwm_selection_transfer_start_outgoing(first); + // Start next queued transfer if we just removed the active one. + if (was_first && !wl_list_empty(&selection->outgoing)) { + xwm_selection_transfer_start_outgoing( + xwm_selection_transfer_get_first(selection)); } xwm_selection_transfer_remove_source(transfer); From 1b0e4c7e6e0bf02b3c41962b669c00280ecc7712 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 3 Oct 2020 14:16:54 -0400 Subject: [PATCH 054/223] xwayland: introduce WLR_XWAYLAND for specifying which Xwayland to use When debugging Xwayland-related issues, a common first step in debugging has been to ask the reporter to move their real Xwayland to /usr/bin/Xwayland.bin, and create a shell script starting Xwayland with extra arguments under the original /usr/bin/Xwayland location. Introducing a `WLR_XWAYLAND` environment variable makes this less invasive, by allowing the user to swap out Xwayland without resorting to global system changes (or source patches). --- docs/env_vars.md | 2 ++ xwayland/server.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/env_vars.md b/docs/env_vars.md index 48f96f7fd..9fca81656 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -9,6 +9,8 @@ wlroots reads these environment variables * *WLR_SESSION*: specifies the wlr\_session to be used (available sessions: logind/systemd, direct) * *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty) +* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead + of following shell search semantics for "Xwayland") ## DRM backend diff --git a/xwayland/server.c b/xwayland/server.c index 27e9861a4..24b435aa6 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -107,8 +107,16 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { dup2(devnull, STDERR_FILENO); } + const char *xwayland_path = getenv("WLR_XWAYLAND"); + if (xwayland_path) { + wlr_log(WLR_INFO, "Using Xwayland binary to '%s' due to WLR_XWAYLAND", + xwayland_path); + } else { + xwayland_path = "Xwayland"; + } + // This returns if and only if the call fails - execvp("Xwayland", argv); + execvp(xwayland_path, argv); wlr_log_errno(WLR_ERROR, "failed to exec Xwayland"); close(devnull); From 7bb9d48dd1383b688c8fefbbb08c552c3cc33c18 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sun, 11 Oct 2020 21:25:26 -0400 Subject: [PATCH 055/223] xwayland: remove stale transfers from the same requestor It seems that if we ever try to reply to a selection request after another has been sent by the same requestor (we reply in FIFO order), the requestor never reads from it, and we end up stalling forever on a transfer that will never complete. It appears that `XCB_SELECTION_REQUEST` has some sort of singleton semantics, and new requests for the same selection are meant to replace outstanding older ones. I couldn't find a reference for this, but empirically this does seem to be the case. Real (contrived) case where we don't currently do this, and things break: * run fcitx * run Slack * wl-copy < <(base64 /opt/firefox/libxul.so) # or some other large file * focus Slack (no need to paste) fcitx will send in an `XCB_SELECTION_REQUEST`, and we'll start processing it. Immediately after, Slack sends its own. fcitx hangs for a long, long time. In the meantime, Slack retries and sends another selection request. We now have two pending requests from Slack. Eventually fcitx gives up (or it can be `pkill`'d), and we start processing the first request Slack gave us (FIFO). Slack (Electron?) isn't listening on the other end anymore, and this transfer never completes. The X11 clipboard becomes unusable until Slack is killed. After this patch, the clipboard is immediately usable again after fcitx bails. Also added a bunch of debug-level logging that makes diagnosing this sort of issue easier. Refs swaywm/sway#4007. --- xwayland/selection/outgoing.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 943e4d1a4..190fb7416 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -71,9 +71,11 @@ static void xwm_selection_transfer_destroy_outgoing( struct wlr_xwm_selection *selection = transfer->selection; bool was_first = transfer == xwm_selection_transfer_get_first(selection); wl_list_remove(&transfer->outgoing_link); + wlr_log(WLR_DEBUG, "Destroying transfer %p", transfer); // Start next queued transfer if we just removed the active one. if (was_first && !wl_list_empty(&selection->outgoing)) { + wlr_log(WLR_DEBUG, "Destroyed transfer was active, starting next"); xwm_selection_transfer_start_outgoing( xwm_selection_transfer_get_first(selection)); } @@ -230,6 +232,8 @@ static void xwm_selection_transfer_start_outgoing( struct wlr_xwm *xwm = transfer->selection->xwm; struct wl_event_loop *loop = wl_display_get_event_loop(xwm->xwayland->wl_display); + wlr_log(WLR_DEBUG, "Starting transfer %p", transfer); + assert(transfer == xwm_selection_transfer_get_first(transfer->selection)); transfer->source = wl_event_loop_add_fd(loop, transfer->source_fd, WL_EVENT_READABLE, xwm_data_source_read, transfer); } @@ -312,14 +316,34 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, transfer->source_fd = p[0]; wlr_log(WLR_DEBUG, "Sending Wayland selection %u to Xwayland window with " - "MIME type %s, target %u", req->target, mime_type, req->target); + "MIME type %s, target %u, transfer %p", req->target, mime_type, + req->target, transfer); xwm_selection_source_send(selection, mime_type, p[1]); + // It seems that if we ever try to reply to a selection request after + // another has been sent by the same requestor, the requestor never reads + // from it. It appears to only ever read from the latest, so purge stale + // transfers to prevent clipboard hangs. + struct wlr_xwm_selection_transfer *outgoing, *tmp; + wl_list_for_each_safe(outgoing, tmp, &selection->outgoing, outgoing_link) { + if (transfer->request.requestor == outgoing->request.requestor) { + wlr_log(WLR_DEBUG, "Destroying stale transfer %p", outgoing); + xwm_selection_send_notify(selection->xwm, &outgoing->request, false); + xwm_selection_transfer_destroy_outgoing(outgoing); + } + } + wl_list_insert(&selection->outgoing, &transfer->outgoing_link); // We can only handle one transfer at a time if (wl_list_length(&selection->outgoing) == 1) { + wlr_log(WLR_DEBUG, "No transfer active, starting %p now", transfer); xwm_selection_transfer_start_outgoing(transfer); + } else { + struct wlr_xwm_selection_transfer *outgoing; + wl_list_for_each(outgoing, &selection->outgoing, outgoing_link) { + wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing); + } } } From afeb941ca027995530d940b81f28421456c77640 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 12 Oct 2020 23:47:29 -0400 Subject: [PATCH 056/223] xwayland: notify requestor when we fail to respond to their request We already mostly did this, but there were a couple of branches (`calloc` failures) where we'd bail without letting the other side know. Refs swaywm/sway#4007. Likely not going to be a real improvement there (if `calloc` fails you're already pretty screwed), but it does address a theoretical possibility. --- xwayland/selection/outgoing.c | 40 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 190fb7416..a5ce2fd26 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -265,15 +265,14 @@ static struct wl_array *xwm_selection_source_get_mime_types( /** * Read the Wayland selection and send it to an Xwayland client. */ -static void xwm_selection_send_data(struct wlr_xwm_selection *selection, +static bool xwm_selection_send_data(struct wlr_xwm_selection *selection, xcb_selection_request_event_t *req, const char *mime_type) { // Check MIME type struct wl_array *mime_types = xwm_selection_source_get_mime_types(selection); if (mime_types == NULL) { wlr_log(WLR_ERROR, "not sending selection: no MIME type list available"); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } bool found = false; @@ -288,16 +287,16 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, if (!found) { wlr_log(WLR_ERROR, "not sending selection: " "requested an unsupported MIME type %s", mime_type); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } struct wlr_xwm_selection_transfer *transfer = calloc(1, sizeof(struct wlr_xwm_selection_transfer)); if (transfer == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); - return; + return false; } + transfer->selection = selection; transfer->request = *req; wl_array_init(&transfer->source_data); @@ -305,9 +304,9 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, int p[2]; if (pipe(p) == -1) { wlr_log_errno(WLR_ERROR, "pipe() failed"); - xwm_selection_send_notify(selection->xwm, req, false); - return; + return false; } + fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[1], F_SETFD, FD_CLOEXEC); @@ -345,6 +344,8 @@ static void xwm_selection_send_data(struct wlr_xwm_selection *selection, wlr_log(WLR_DEBUG, "Transfer %p still queued", outgoing); } } + + return true; } static void xwm_selection_send_targets(struct wlr_xwm_selection *selection, @@ -416,12 +417,12 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, xwm_get_selection(xwm, req->selection); if (selection == NULL) { wlr_log(WLR_DEBUG, "received selection request for unknown selection"); - return; + goto fail_notify_requestor; } if (selection->window != req->owner) { wlr_log(WLR_DEBUG, "received selection request with invalid owner"); - return; + goto fail_notify_requestor; } // No xwayland surface focused, deny access to clipboard @@ -430,8 +431,7 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, wlr_log(WLR_DEBUG, "denying read access to selection %u (%s): " "no xwayland surface focused", selection->atom, selection_name); free(selection_name); - xwm_selection_send_notify(xwm, req, false); - return; + goto fail_notify_requestor; } if (req->target == xwm->atoms[TARGETS]) { @@ -446,12 +446,22 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, if (mime_type == NULL) { wlr_log(WLR_ERROR, "ignoring selection request: unknown atom %u", req->target); - xwm_selection_send_notify(xwm, req, false); - return; + goto fail_notify_requestor; } - xwm_selection_send_data(selection, req, mime_type); + + bool send_success = xwm_selection_send_data(selection, req, mime_type); free(mime_type); + if (!send_success) { + goto fail_notify_requestor; + } } + + return; + +fail_notify_requestor: + // Something went wrong, and there won't be any data being sent to the + // requestor, so let them know. + xwm_selection_send_notify(xwm, req, false); } void xwm_handle_selection_destroy_notify(struct wlr_xwm *xwm, From 99f3c643bf9407c4e0b3eb901b1e44588ae11357 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 14 Oct 2020 11:47:23 +0200 Subject: [PATCH 057/223] xwayland: add set_geometry event This is necessary to react to changes in position of override-redirect views. --- include/wlr/xwayland.h | 1 + xwayland/xwm.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 26a14aea6..b801b5dd4 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -198,6 +198,7 @@ struct wlr_xwayland_surface { struct wl_signal set_hints; struct wl_signal set_decorations; struct wl_signal set_override_redirect; + struct wl_signal set_geometry; struct wl_signal ping_timeout; } events; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index b3e6c885e..b53759da9 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -164,6 +164,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_signal_init(&surface->events.set_decorations); wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.ping_timeout); + wl_signal_init(&surface->events.set_geometry); xcb_get_geometry_reply_t *geometry_reply = xcb_get_geometry_reply(xwm->xcb_conn, geometry_cookie, NULL); @@ -935,15 +936,25 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, return; } - xsurface->x = ev->x; - xsurface->y = ev->y; - xsurface->width = ev->width; - xsurface->height = ev->height; + bool geometry_changed = + (xsurface->x != ev->x || xsurface->y != ev->y || + xsurface->width != ev->width || xsurface->height != ev->height); + + if (geometry_changed) { + xsurface->x = ev->x; + xsurface->y = ev->y; + xsurface->width = ev->width; + xsurface->height = ev->height; + } if (xsurface->override_redirect != ev->override_redirect) { xsurface->override_redirect = ev->override_redirect; wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); } + + if (geometry_changed) { + wlr_signal_emit_safe(&xsurface->events.set_geometry, NULL); + } } #define ICCCM_WITHDRAWN_STATE 0 From 616f06c25c06ec04430c4b8f0ac15a40325cd177 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 16 Oct 2020 12:41:32 +0200 Subject: [PATCH 058/223] xdg_positioner: remove unused field The resource field of wlr_xdg_positioner is never initialized or accessed within wlroots. The wl_resource for this interface is stored in the wlr_xdg_positioner_resource struct. --- include/wlr/types/wlr_xdg_shell.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 45c5aee08..0b9167d2c 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -48,8 +48,6 @@ struct wlr_xdg_client { }; struct wlr_xdg_positioner { - struct wl_resource *resource; - struct wlr_box anchor_rect; enum xdg_positioner_anchor anchor; enum xdg_positioner_gravity gravity; From e410ff8dd4e83ffc6419eb0709693afb25892e47 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 18 Oct 2020 15:13:05 +0200 Subject: [PATCH 059/223] wlr_drag: remove unused point_destroy field --- include/wlr/types/wlr_data_device.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 555eeab01..87c578aed 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -136,7 +136,6 @@ struct wlr_drag { struct wl_signal destroy; } events; - struct wl_listener point_destroy; struct wl_listener source_destroy; struct wl_listener seat_client_destroy; struct wl_listener icon_destroy; From b98522b38fa19c732e0bc420178b76b847460dfe Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 18 Oct 2020 16:33:03 +0300 Subject: [PATCH 060/223] backend/wayland: add touch support to the wayland backend Goal currently is to get support working for a single output, thus there is only one touch device created. Multi-output support is left for later. --- backend/wayland/seat.c | 133 ++++++++++++++++++++++++++++++++++++++ include/backend/wayland.h | 2 + 2 files changed, 135 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 71e04de6b..a23a4c917 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -276,6 +276,95 @@ static struct wl_keyboard_listener keyboard_listener = { .repeat_info = keyboard_handle_repeat_info }; +static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device, + wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) { + // TODO: each output needs its own touch + struct wlr_wl_output *output, *tmp; + wl_list_for_each_safe(output, tmp, &device->backend->outputs, link) { + *sx = wl_fixed_to_double(x) / output->wlr_output.width; + *sy = wl_fixed_to_double(y) / output->wlr_output.height; + return; // Choose the first output in the list + } + + *sx = *sy = 0; +} + +static void touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x, wl_fixed_t y) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + double sx, sy; + touch_coordinates_to_absolute(device, x, y, &sx, &sy); + struct wlr_event_touch_down event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + .x = sx, + .y = sy + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.down, &event); +} + +static void touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + struct wlr_event_touch_up event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.up, &event); +} + +static void touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { + struct wlr_wl_input_device *device = data; + assert(device && device->wlr_input_device.touch); + + double sx, sy; + touch_coordinates_to_absolute(device, x, y, &sx, &sy); + struct wlr_event_touch_motion event = { + .device = &device->wlr_input_device, + .time_msec = time, + .touch_id = id, + .x = sx, + .y = sy + }; + wlr_signal_emit_safe(&device->wlr_input_device.touch->events.motion, &event); +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) { + // no-op +} + +static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) { + // no-op +} + +static void touch_handle_shape(void *data, struct wl_touch *wl_touch, + int32_t id, wl_fixed_t major, wl_fixed_t minor) { + // no-op +} + +static void touch_handle_orientation(void *data, struct wl_touch *wl_touch, + int32_t id, wl_fixed_t orientation) { + // no-op +} + +static struct wl_touch_listener touch_listener = { + .down = touch_handle_down, + .up = touch_handle_up, + .motion = touch_handle_motion, + .frame = touch_handle_frame, + .cancel = touch_handle_cancel, + .shape = touch_handle_shape, + .orientation = touch_handle_orientation, +}; + static struct wlr_wl_input_device *get_wl_input_device_from_input_device( struct wlr_input_device *wlr_dev) { assert(wlr_input_device_is_wl(wlr_dev)); @@ -563,6 +652,28 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); } +void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { + struct wlr_wl_input_device *dev = + create_wl_input_device(wl, WLR_INPUT_DEVICE_TOUCH); + if (!dev) { + return; + } + + struct wlr_input_device *wlr_dev = &dev->wlr_input_device; + + wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); + if (!wlr_dev->touch) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + free(dev); + return; + } + wlr_touch_init(wlr_dev->touch, NULL); + + wl_touch_add_listener(wl_touch, &touch_listener, dev); + wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); +} + + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_backend *backend = data; @@ -614,6 +725,28 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } assert(backend->keyboard == NULL); // free'ed by input_device_destroy } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch == NULL) { + wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat); + + backend->touch = wl_seat_get_touch(wl_seat); + if (backend->started) { + create_wl_touch(backend->touch, backend); + } + } + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch != NULL) { + wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); + + struct wlr_input_device *device, *tmp; + wl_list_for_each_safe(device, tmp, &backend->devices, link) { + if (device->type == WLR_INPUT_DEVICE_TOUCH) { + wlr_input_device_destroy(device); + } + } + + wl_touch_release(backend->touch); + backend->touch = NULL; + } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9a8a404bb..a053adedd 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -39,6 +39,7 @@ struct wlr_wl_backend { struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct wl_seat *seat; + struct wl_touch *touch; struct wl_pointer *pointer; struct wl_keyboard *keyboard; struct wlr_wl_pointer *current_pointer; @@ -112,6 +113,7 @@ void update_wl_output_cursor(struct wlr_wl_output *output); struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output); void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl); +void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); From df417b7e95fce515f85b20e180742bcc289e35d4 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 15:06:05 +0200 Subject: [PATCH 061/223] backend/wayland: manage cursor for current pointer --- backend/wayland/output.c | 5 +++-- backend/wayland/seat.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index bd17fa208..b234c6a0b 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -419,8 +419,9 @@ static void output_destroy(struct wlr_output *wlr_output) { } void update_wl_output_cursor(struct wlr_wl_output *output) { - if (output->backend->pointer && output->enter_serial) { - wl_pointer_set_cursor(output->backend->pointer, output->enter_serial, + struct wlr_wl_pointer *pointer = output->backend->current_pointer; + if (pointer && pointer->output == output && output->enter_serial) { + wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial, output->cursor.surface, output->cursor.hotspot_x, output->cursor.hotspot_y); } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index a23a4c917..cce5c0dce 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -48,6 +48,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_output *output = wl_surface_get_user_data(surface); assert(output); struct wlr_wl_pointer *pointer = output_get_pointer(output); + assert(!backend->current_pointer || backend->current_pointer == pointer); output->enter_serial = serial; backend->current_pointer = pointer; From 1ac5257357fdf51b2864149f4896c51afd2eda09 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 17:34:32 +0200 Subject: [PATCH 062/223] backend/wayland: factor out wlr_wl_seat --- backend/wayland/backend.c | 28 ++++++------- backend/wayland/output.c | 7 +++- backend/wayland/seat.c | 84 +++++++++++++++++++++++++++------------ include/backend/wayland.h | 17 +++++--- 4 files changed, 88 insertions(+), 48 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index a09126ce2..2059b7266 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -103,9 +103,9 @@ static void registry_global(void *data, struct wl_registry *registry, wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); } else if (strcmp(iface, wl_seat_interface.name) == 0) { - wl->seat = wl_registry_bind(registry, name, + struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5); - wl_seat_add_listener(wl->seat, &seat_listener, wl); + create_wl_seat(wl_seat, wl); } else if (strcmp(iface, xdg_wm_base_interface.name) == 0) { wl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); @@ -155,13 +155,16 @@ static bool backend_start(struct wlr_backend *backend) { wl->started = true; - if (wl->keyboard) { - create_wl_keyboard(wl->keyboard, wl); - } + struct wlr_wl_seat *seat = wl->seat; + if (seat != NULL) { + if (seat->keyboard) { + create_wl_keyboard(seat->keyboard, wl); + } - if (wl->tablet_manager && wl->seat) { - wl_add_tablet_seat(wl->tablet_manager, - wl->seat, wl); + if (wl->tablet_manager) { + wl_add_tablet_seat(wl->tablet_manager, + seat->wl_seat, wl); + } } for (size_t i = 0; i < wl->requested_outputs; ++i) { @@ -192,8 +195,6 @@ static void backend_destroy(struct wlr_backend *backend) { wl_list_remove(&wl->local_display_destroy.link); - free(wl->seat_name); - wl_event_source_remove(wl->remote_display_src); wlr_renderer_destroy(wl->renderer); @@ -201,12 +202,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); - if (wl->pointer) { - wl_pointer_destroy(wl->pointer); - } - if (wl->seat) { - wl_seat_destroy(wl->seat); - } + destroy_wl_seats(wl); if (wl->zxdg_decoration_manager_v1) { zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1); } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index b234c6a0b..568d90db6 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -586,8 +586,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); - if (backend->pointer != NULL) { - create_wl_pointer(backend->pointer, output); + struct wlr_wl_seat *seat = backend->seat; + if (seat != NULL) { + if (seat->pointer) { + create_wl_pointer(seat->pointer, output); + } } return wlr_output; diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index cce5c0dce..f20619d51 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -372,12 +372,49 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( return (struct wlr_wl_input_device *)wlr_dev; } +void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { + assert(!wl->seat); // only one seat supported at the moment + struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); + seat->wl_seat = wl_seat; + wl->seat = seat; + wl_seat_add_listener(wl_seat, &seat_listener, wl); +} + +void destroy_wl_seats(struct wlr_wl_backend *wl) { + struct wlr_wl_seat *seat = wl->seat; + if (!seat) { + return; + } + + if (seat->pointer) { + wl_pointer_destroy(seat->pointer); + } + free(seat->name); + if (seat->wl_seat) { + wl_seat_destroy(seat->wl_seat); + } + free(seat); +} + +static struct wlr_wl_seat *backend_get_seat(struct wlr_wl_backend *backend, struct wl_seat *wl_seat) { + assert(backend->seat && backend->seat->wl_seat == wl_seat); + return backend->seat; +} + +static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { + struct wlr_wl_input_device *dev = + get_wl_input_device_from_input_device(wlr_dev); + assert(dev->backend->seat); + return dev->backend->seat; +} + static void input_device_destroy(struct wlr_input_device *wlr_dev) { struct wlr_wl_input_device *dev = get_wl_input_device_from_input_device(wlr_dev); if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) { - wl_keyboard_release(dev->backend->keyboard); - dev->backend->keyboard = NULL; + struct wlr_wl_seat *seat = input_device_get_seat(wlr_dev); + wl_keyboard_release(seat->keyboard); + seat->keyboard = NULL; } wl_list_remove(&dev->wlr_input_device.link); free(dev); @@ -678,20 +715,20 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_backend *backend = data; - assert(backend->seat == wl_seat); + struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); - if ((caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer == NULL) { + if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) { wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat); struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat); - backend->pointer = wl_pointer; + seat->pointer = wl_pointer; struct wlr_wl_output *output; wl_list_for_each(output, &backend->outputs, link) { create_wl_pointer(wl_pointer, output); } } - if (!(caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -701,21 +738,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } } - wl_pointer_release(backend->pointer); - backend->pointer = NULL; + wl_pointer_release(seat->pointer); + seat->pointer = NULL; } - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) { + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard == NULL) { wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat); struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat); - backend->keyboard = wl_keyboard; + seat->keyboard = wl_keyboard; if (backend->started) { create_wl_keyboard(wl_keyboard, backend); } } - if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -724,18 +761,18 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wlr_input_device_destroy(device); } } - assert(backend->keyboard == NULL); // free'ed by input_device_destroy + assert(seat->keyboard == NULL); // free'ed by input_device_destroy } - if ((caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch == NULL) { + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch == NULL) { wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat); - backend->touch = wl_seat_get_touch(wl_seat); + seat->touch = wl_seat_get_touch(wl_seat); if (backend->started) { - create_wl_touch(backend->touch, backend); + create_wl_touch(seat->touch, backend); } } - if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && backend->touch != NULL) { + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); struct wlr_input_device *device, *tmp; @@ -745,18 +782,17 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } } - wl_touch_release(backend->touch); - backend->touch = NULL; + wl_touch_release(seat->touch); + seat->touch = NULL; } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) { struct wlr_wl_backend *backend = data; - assert(backend->seat == wl_seat); - // Do we need to check if seatName was previously set for name change? - free(backend->seat_name); - backend->seat_name = strdup(name); + struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); + free(seat->name); + seat->name = strdup(name); } const struct wl_seat_listener seat_listener = { @@ -765,7 +801,5 @@ const struct wl_seat_listener seat_listener = { }; struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) { - struct wlr_wl_input_device *dev = - get_wl_input_device_from_input_device(wlr_dev); - return dev->backend->seat; + return input_device_get_seat(wlr_dev)->wl_seat; } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index a053adedd..61b349a5e 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -38,13 +38,9 @@ struct wlr_wl_backend { struct wp_presentation *presentation; struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; - struct wl_seat *seat; - struct wl_touch *touch; - struct wl_pointer *pointer; - struct wl_keyboard *keyboard; + struct wlr_wl_seat *seat; struct wlr_wl_pointer *current_pointer; struct zwp_tablet_manager_v2 *tablet_manager; - char *seat_name; struct wlr_drm_format_set linux_dmabuf_v1_formats; }; @@ -108,6 +104,15 @@ struct wlr_wl_pointer { struct wl_listener output_destroy; }; +struct wlr_wl_seat { + struct wl_seat *wl_seat; + + char *name; + struct wl_touch *touch; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; +}; + struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); void update_wl_output_cursor(struct wlr_wl_output *output); struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); @@ -116,6 +121,8 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); +void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); +void destroy_wl_seats(struct wlr_wl_backend *wl); extern const struct wl_seat_listener seat_listener; From 36395e5b1c4107d6945213e0c06eaa58d885f97c Mon Sep 17 00:00:00 2001 From: Daniel Kondor Date: Sun, 18 Oct 2020 23:14:35 +0800 Subject: [PATCH 063/223] foreign-toplevel-management: report parent toplevel Based on the wlr-protocols PR: https://github.com/swaywm/wlr-protocols/pull/52 --- examples/foreign-toplevel.c | 41 +++++++++++-- .../wlr_foreign_toplevel_management_v1.h | 17 ++++++ ...oreign-toplevel-management-unstable-v1.xml | 15 ++++- types/wlr_foreign_toplevel_management_v1.c | 58 ++++++++++++++++++- 4 files changed, 123 insertions(+), 8 deletions(-) diff --git a/examples/foreign-toplevel.c b/examples/foreign-toplevel.c index 1d41d01af..995d4f6cc 100644 --- a/examples/foreign-toplevel.c +++ b/examples/foreign-toplevel.c @@ -7,7 +7,7 @@ #include #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" -#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 2 +#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 3 /** * Usage: @@ -38,11 +38,14 @@ enum toplevel_state_field { TOPLEVEL_STATE_INVALID = (1 << 4), }; +static const uint32_t no_parent = (uint32_t)-1; + struct toplevel_state { char *title; char *app_id; uint32_t state; + uint32_t parent_id; }; static void copy_state(struct toplevel_state *current, @@ -67,6 +70,8 @@ static void copy_state(struct toplevel_state *current, current->state = pending->state; } + current->parent_id = pending->parent_id; + pending->state = TOPLEVEL_STATE_INVALID; } @@ -84,6 +89,12 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) { toplevel->current.title ?: "(nil)", toplevel->current.app_id ?: "(nil)"); + if (toplevel->current.parent_id != no_parent) { + printf(" parent=%u", toplevel->current.parent_id); + } else { + printf(" no parent"); + } + if (print_endl) { printf("\n"); } @@ -172,6 +183,28 @@ static void toplevel_handle_state(void *data, toplevel->pending.state = array_to_state(state); } +static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; +static struct wl_list toplevel_list; + +static void toplevel_handle_parent(void *data, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel, + struct zwlr_foreign_toplevel_handle_v1 *zwlr_parent) { + struct toplevel_v1 *toplevel = data; + toplevel->pending.parent_id = no_parent; + if (zwlr_parent) { + struct toplevel_v1 *toplevel_tmp; + wl_list_for_each(toplevel_tmp, &toplevel_list, link) { + if (toplevel_tmp->zwlr_toplevel == zwlr_parent) { + toplevel->pending.parent_id = toplevel_tmp->id; + break; + } + } + if (toplevel->pending.parent_id == no_parent) { + fprintf(stderr, "Cannot find parent toplevel!\n"); + } + } +} + static void toplevel_handle_done(void *data, struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { struct toplevel_v1 *toplevel = data; @@ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = { .state = toplevel_handle_state, .done = toplevel_handle_done, .closed = toplevel_handle_closed, + .parent = toplevel_handle_parent }; -static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL; -static struct wl_list toplevel_list; - static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) { @@ -218,6 +249,8 @@ static void toplevel_manager_handle_toplevel(void *data, toplevel->id = global_id++; toplevel->zwlr_toplevel = zwlr_toplevel; + toplevel->current.parent_id = no_parent; + toplevel->pending.parent_id = no_parent; wl_list_insert(&toplevel_list, &toplevel->link); zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl, diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index 90d88637c..6ea9d47fd 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 { char *title; char *app_id; + struct wlr_foreign_toplevel_handle_v1 *parent; struct wl_list outputs; // wlr_foreign_toplevel_v1_output uint32_t state; // wlr_foreign_toplevel_v1_state @@ -104,6 +105,12 @@ struct wlr_foreign_toplevel_manager_v1 *wlr_foreign_toplevel_manager_v1_create( struct wlr_foreign_toplevel_handle_v1 *wlr_foreign_toplevel_handle_v1_create( struct wlr_foreign_toplevel_manager_v1 *manager); +/* Destroy the given toplevel handle, sending the closed event to any + * client. Also, if the destroyed toplevel is set as a parent of any + * other valid toplevel, clients still holding a handle to both are + * sent a parent signal with NULL parent. If this is not desired, the + * caller should ensure that any child toplevels are destroyed before + * the parent. */ void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel); @@ -126,4 +133,14 @@ void wlr_foreign_toplevel_handle_v1_set_activated( void wlr_foreign_toplevel_handle_v1_set_fullscreen( struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen); +/* Set the parent of a toplevel. If the parent changed from its previous + * value, also sends a parent event to all clients that hold handles to + * both toplevel and parent (no message is sent to clients that have + * previously destroyed their parent handle). NULL is allowed as the + * parent, meaning no parent exists. */ +void wlr_foreign_toplevel_handle_v1_set_parent( + struct wlr_foreign_toplevel_handle_v1 *toplevel, + struct wlr_foreign_toplevel_handle_v1 *parent); + + #endif diff --git a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml index a97738f8a..206143b4d 100644 --- a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml +++ b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml @@ -25,7 +25,7 @@ THIS SOFTWARE. - + The purpose of this protocol is to enable the creation of taskbars and docks by providing them with a list of opened applications and @@ -68,7 +68,7 @@ - + A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel window. Each app may have multiple opened toplevels. @@ -255,5 +255,16 @@ actually changes, this will be indicated by the state event. + + + + + + This event is emitted whenever the parent of the toplevel changes. + + No event is emitted when the parent handle is destroyed by the client. + + + diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index aed0e203c..5e7b731c6 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -9,7 +9,7 @@ #include "util/signal.h" #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" -#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 2 +#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3 static const struct zwlr_foreign_toplevel_handle_v1_interface toplevel_handle_impl; @@ -405,6 +405,37 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen( toplevel_send_state(toplevel); } +static void toplevel_resource_send_parent( + struct wl_resource *toplevel_resource, + struct wlr_foreign_toplevel_handle_v1 *parent) { + struct wl_client *client = wl_resource_get_client(toplevel_resource); + struct wl_resource *parent_resource = NULL; + if (parent) { + parent_resource = wl_resource_find_for_client(&parent->resources, client); + if (!parent_resource) { + /* don't send an event if this client destroyed the parent handle */ + return; + } + } + zwlr_foreign_toplevel_handle_v1_send_parent(toplevel_resource, + parent_resource); +} + +void wlr_foreign_toplevel_handle_v1_set_parent( + struct wlr_foreign_toplevel_handle_v1 *toplevel, + struct wlr_foreign_toplevel_handle_v1 *parent) { + if (parent == toplevel->parent) { + /* only send parent event to the clients if there was a change */ + return; + } + struct wl_resource *toplevel_resource, *tmp; + wl_resource_for_each_safe(toplevel_resource, tmp, &toplevel->resources) { + toplevel_resource_send_parent(toplevel_resource, parent); + } + toplevel->parent = parent; + toplevel_update_idle_source(toplevel); +} + void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel) { if (!toplevel) { @@ -432,6 +463,19 @@ void wlr_foreign_toplevel_handle_v1_destroy( wl_list_remove(&toplevel->link); + /* need to ensure no other toplevels hold a pointer to this one as + * a parent, so that a later call to foreign_toplevel_manager_bind() + * will not result in a segfault */ + struct wlr_foreign_toplevel_handle_v1 *tl, *tmp3; + wl_list_for_each_safe(tl, tmp3, &toplevel->manager->toplevels, link) { + if (tl->parent == toplevel) { + /* Note: we send a parent signal to all clients in this case; + * the caller should first destroy the child handles if it + * wishes to avoid this behavior. */ + wlr_foreign_toplevel_handle_v1_set_parent(tl, NULL); + } + } + free(toplevel->title); free(toplevel->app_id); free(toplevel); @@ -542,6 +586,8 @@ static void toplevel_send_details_to_toplevel_resource( zwlr_foreign_toplevel_handle_v1_send_state(resource, &states); wl_array_release(&states); + toplevel_resource_send_parent(resource, toplevel->parent); + zwlr_foreign_toplevel_handle_v1_send_done(resource); } @@ -560,9 +606,17 @@ static void foreign_toplevel_manager_bind(struct wl_client *client, void *data, wl_list_insert(&manager->resources, wl_resource_get_link(resource)); struct wlr_foreign_toplevel_handle_v1 *toplevel, *tmp; + /* First loop: create a handle for all toplevels for all clients. + * Separation into two loops avoid the case where a child handle + * is created before a parent handle, so the parent relationship + * could not be sent to a client. */ + wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { + create_toplevel_resource_for_resource(toplevel, resource); + } + /* Second loop: send details about each toplevel. */ wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) { struct wl_resource *toplevel_resource = - create_toplevel_resource_for_resource(toplevel, resource); + wl_resource_find_for_client(&toplevel->resources, client); toplevel_send_details_to_toplevel_resource(toplevel, toplevel_resource); } From 41bf1c6871a2bf9dc91863b9c5b8369ccaaffc61 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 064/223] backend/wayland: add error flow in create_wl_seat --- backend/wayland/backend.c | 4 +++- backend/wayland/seat.c | 7 ++++++- include/backend/wayland.h | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 2059b7266..459baaa6d 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -105,7 +105,9 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, wl_seat_interface.name) == 0) { struct wl_seat *wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5); - create_wl_seat(wl_seat, wl); + if (!create_wl_seat(wl_seat, wl)) { + wl_seat_destroy(wl_seat); + } } else if (strcmp(iface, xdg_wm_base_interface.name) == 0) { wl->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index f20619d51..10a224a10 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -372,12 +372,17 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( return (struct wlr_wl_input_device *)wlr_dev; } -void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { +bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { assert(!wl->seat); // only one seat supported at the moment struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); + if (!seat) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } seat->wl_seat = wl_seat; wl->seat = seat; wl_seat_add_listener(wl_seat, &seat_listener, wl); + return true; } void destroy_wl_seats(struct wlr_wl_backend *wl) { diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 61b349a5e..d782584f6 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -121,7 +121,7 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_backend *backend, enum wlr_input_device_type type); -void create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); +bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); extern const struct wl_seat_listener seat_listener; From 009cd634a2c4d97edf8bdfabe0141923f9e53285 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 065/223] backend/wayland: fix input creation error handling --- backend/wayland/seat.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 10a224a10..133f5403d 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -636,9 +636,6 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp pointer->wl_pointer = wl_pointer; pointer->output = output; - wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); - pointer->output_destroy.notify = pointer_handle_output_destroy; - struct wlr_wl_input_device *dev = create_wl_input_device(backend, WLR_INPUT_DEVICE_POINTER); if (dev == NULL) { @@ -648,6 +645,9 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp } pointer->input_device = dev; + wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); + pointer->output_destroy.notify = pointer_handle_output_destroy; + wlr_dev = &dev->wlr_input_device; wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->output_name = strdup(output->wlr_output.name); @@ -686,7 +686,7 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard)); if (!wlr_dev->keyboard) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - free(dev); + wlr_input_device_destroy(wlr_dev); return; } wlr_keyboard_init(wlr_dev->keyboard, NULL); @@ -707,7 +707,7 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); if (!wlr_dev->touch) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - free(dev); + wlr_input_device_destroy(wlr_dev); return; } wlr_touch_init(wlr_dev->touch, NULL); From 31aa7f4c95ccc8260d5202d6f0d8c6b5c3c80061 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 18 Oct 2020 19:12:01 +0200 Subject: [PATCH 066/223] backend/wayland: fix some keyboard/touch leaks --- backend/wayland/seat.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 133f5403d..1697616c5 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -391,9 +391,16 @@ void destroy_wl_seats(struct wlr_wl_backend *wl) { return; } + if (seat->touch) { + wl_touch_destroy(seat->touch); + } if (seat->pointer) { wl_pointer_destroy(seat->pointer); } + if (seat->keyboard && !wl->started) { + // early termination will not be handled by input_device_destroy + wl_keyboard_destroy(seat->keyboard); + } free(seat->name); if (seat->wl_seat) { wl_seat_destroy(seat->wl_seat); From 5217456b50f707780fce047b9d67b72f74475d3f Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 19 Oct 2020 20:48:41 -0400 Subject: [PATCH 067/223] xwayland: fix minor typo in debug log This accidentally slipped through 1b0e4c7. --- xwayland/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwayland/server.c b/xwayland/server.c index 24b435aa6..d0057c66a 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -109,7 +109,7 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { const char *xwayland_path = getenv("WLR_XWAYLAND"); if (xwayland_path) { - wlr_log(WLR_INFO, "Using Xwayland binary to '%s' due to WLR_XWAYLAND", + wlr_log(WLR_INFO, "Using Xwayland binary '%s' due to WLR_XWAYLAND", xwayland_path); } else { xwayland_path = "Xwayland"; From b4ed8b3d7414ff6280098da811f873e5c5146d27 Mon Sep 17 00:00:00 2001 From: Daniel Kondor Date: Tue, 20 Oct 2020 10:08:24 +0800 Subject: [PATCH 068/223] foreign toplevel: send parent event only to clients that support it --- types/wlr_foreign_toplevel_management_v1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 5e7b731c6..154f790c3 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -408,6 +408,10 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen( static void toplevel_resource_send_parent( struct wl_resource *toplevel_resource, struct wlr_foreign_toplevel_handle_v1 *parent) { + if (wl_resource_get_version(toplevel_resource) < + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_PARENT_SINCE_VERSION) { + return; + } struct wl_client *client = wl_resource_get_client(toplevel_resource); struct wl_resource *parent_resource = NULL; if (parent) { From 79c7591dc196b14dfa857caf2c183276f937ee02 Mon Sep 17 00:00:00 2001 From: Scott Moreau Date: Tue, 20 Oct 2020 10:42:01 -0600 Subject: [PATCH 069/223] foreign toplevel: Fix whitespace error --- protocol/wlr-foreign-toplevel-management-unstable-v1.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml index 206143b4d..108133715 100644 --- a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml +++ b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml @@ -261,7 +261,7 @@ This event is emitted whenever the parent of the toplevel changes. - + No event is emitted when the parent handle is destroyed by the client. From 346188c01511d3a6432f6fdaf43823cf58a8efca Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 27 Oct 2020 18:28:39 +0100 Subject: [PATCH 070/223] xdg_shell: fix a typo --- types/xdg_shell/wlr_xdg_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 7cd12040d..d33cbffed 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -494,7 +494,7 @@ void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) { break; case WLR_XDG_SURFACE_ROLE_POPUP: wl_resource_set_user_data(xdg_surface->popup->resource, NULL); - xdg_surface->toplevel->resource = NULL; + xdg_surface->popup->resource = NULL; wl_list_remove(&xdg_surface->popup->link); From 85757665e6e1393773b36282aa244feb10b7a5fe Mon Sep 17 00:00:00 2001 From: Marten Ringwelski Date: Thu, 29 Oct 2020 12:36:13 +0100 Subject: [PATCH 071/223] backend/drm: Check if output is enabled before sending frame event When an output is disabled one last pageflip will happen to disable it. Currently this pageflip causes a frame event. Since the output is disabled we don't want to send this frame event. --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index dafe807b3..03cd93185 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1523,7 +1523,7 @@ static void page_flip_handler(int fd, unsigned seq, }; wlr_output_send_present(&conn->output, &present_event); - if (drm->session->active) { + if (drm->session->active && conn->output.enabled) { wlr_output_send_frame(&conn->output); } } From 7c6e06fd13ad3b96375da606d1483c4d19df38af Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:05:39 -0400 Subject: [PATCH 072/223] types/wlr_keyboard: use bitmasks for wlr_keyboard_led and wlr_keyboard_modifier enums --- include/wlr/types/wlr_keyboard.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index c3e360548..c1a19a8eb 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -18,22 +18,22 @@ #define WLR_LED_COUNT 3 enum wlr_keyboard_led { - WLR_LED_NUM_LOCK = 1, - WLR_LED_CAPS_LOCK = 2, - WLR_LED_SCROLL_LOCK = 4, + WLR_LED_NUM_LOCK = 1 << 0, + WLR_LED_CAPS_LOCK = 1 << 1, + WLR_LED_SCROLL_LOCK = 1 << 2, }; #define WLR_MODIFIER_COUNT 8 enum wlr_keyboard_modifier { - WLR_MODIFIER_SHIFT = 1, - WLR_MODIFIER_CAPS = 2, - WLR_MODIFIER_CTRL = 4, - WLR_MODIFIER_ALT = 8, - WLR_MODIFIER_MOD2 = 16, - WLR_MODIFIER_MOD3 = 32, - WLR_MODIFIER_LOGO = 64, - WLR_MODIFIER_MOD5 = 128, + WLR_MODIFIER_SHIFT = 1 << 0, + WLR_MODIFIER_CAPS = 1 << 1, + WLR_MODIFIER_CTRL = 1 << 2, + WLR_MODIFIER_ALT = 1 << 3, + WLR_MODIFIER_MOD2 = 1 << 4, + WLR_MODIFIER_MOD3 = 1 << 5, + WLR_MODIFIER_LOGO = 1 << 6, + WLR_MODIFIER_MOD5 = 1 << 7, }; #define WLR_KEYBOARD_KEYS_CAP 32 From 0fdb41fe7c2efeb29206180f076b6a5a7706fdce Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:06:04 -0400 Subject: [PATCH 073/223] types/wlr_output_layout: use bitmask for wlr_direction --- include/wlr/types/wlr_output_layout.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index cdbc446f9..51c1e4cab 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -124,10 +124,10 @@ struct wlr_output *wlr_output_layout_get_center_output( struct wlr_output_layout *layout); enum wlr_direction { - WLR_DIRECTION_UP = 1, - WLR_DIRECTION_DOWN = 2, - WLR_DIRECTION_LEFT = 4, - WLR_DIRECTION_RIGHT = 8, + WLR_DIRECTION_UP = 1 << 0, + WLR_DIRECTION_DOWN = 1 << 1, + WLR_DIRECTION_LEFT = 1 << 2, + WLR_DIRECTION_RIGHT = 1 << 3, }; /** From 368d0146fbda4281b67a65fea3e6eb148655ef8f Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:06:45 -0400 Subject: [PATCH 074/223] util/edges: use bitmask for wlr_edges --- include/wlr/util/edges.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wlr/util/edges.h b/include/wlr/util/edges.h index bf1eb1e72..90a1167ab 100644 --- a/include/wlr/util/edges.h +++ b/include/wlr/util/edges.h @@ -19,10 +19,10 @@ enum wlr_edges { WLR_EDGE_NONE = 0, - WLR_EDGE_TOP = 1, - WLR_EDGE_BOTTOM = 2, - WLR_EDGE_LEFT = 4, - WLR_EDGE_RIGHT = 8, + WLR_EDGE_TOP = 1 << 0, + WLR_EDGE_BOTTOM = 1 << 1, + WLR_EDGE_LEFT = 1 << 2, + WLR_EDGE_RIGHT = 1 << 3, }; #endif From 0f9b2bfa64359eaeb25b73ccae08c9059bfc02e7 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sat, 31 Oct 2020 18:09:17 -0400 Subject: [PATCH 075/223] render/dmabuf: use bitmask for wlr_dmabuf_attributes_flags --- include/wlr/render/dmabuf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 93e50eb30..b9c548967 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -15,9 +15,9 @@ #define WLR_DMABUF_MAX_PLANES 4 enum wlr_dmabuf_attributes_flags { - WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1, - WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 2, - WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 4, + WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0, + WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1, + WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2, }; struct wlr_dmabuf_attributes { From f0ddcd361ea8b20b0a5da8effc30d8c51540f948 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Nov 2020 10:51:52 +0100 Subject: [PATCH 076/223] render: define EGL_NO_PLATFORM_SPECIFIC_TYPES (#2452) This avoids Xlib.h inclusion via EGL headers. See [1] for discussion. This change is based on a Weston commit [2]. [1]: https://github.com/KhronosGroup/EGL-Registry/pull/111 [2]: https://gitlab.freedesktop.org/wayland/weston/commit/526765ddfdfd --- include/wlr/render/egl.h | 3 +++ include/wlr/render/interface.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index d46d95aff..b23931770 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -15,6 +15,9 @@ #ifndef EGL_NO_X11 #define EGL_NO_X11 #endif +#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES +#define EGL_NO_PLATFORM_SPECIFIC_TYPES +#endif #include diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 93c987b7d..998b1cfa7 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -15,6 +15,9 @@ #ifndef EGL_NO_X11 #define EGL_NO_X11 #endif +#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES +#define EGL_NO_PLATFORM_SPECIFIC_TYPES +#endif #include #include From ee43ef3c9d783c832a9b93fbcb9c1fb8c092f196 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Nov 2020 12:11:51 +0100 Subject: [PATCH 077/223] backend/drm: fix "a page-flip is already pending" errors on modeset When performing a modeset, the DRM backend will request a page-flip event. However frame_pending wasn't set to true, so any subsequent wlr_output_schedule_frame calls would imemdiately trigger a synthetic frame event, asking the compositor to submit a new frame. Committing the new frame fails with "a page-flip is already pending" error in the DRM backend. --- backend/drm/drm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 03cd93185..2644014c7 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -373,6 +373,12 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) { } conn->pageflip_pending = true; + + // wlr_output's API guarantees that submitting a buffer will schedule a + // frame event. However the DRM backend will also schedule a frame event + // when performing a modeset. Set frame_pending to true so that + // wlr_output_schedule_frame doesn't trigger a synthetic frame event. + conn->output.frame_pending = true; return true; } From 1fdaaf697a040c0ec7be661ea7d8a84321dbefb7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Nov 2020 15:31:23 +0100 Subject: [PATCH 078/223] xwayland: minor code style fixes --- xwayland/xwm.c | 104 ++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index b53759da9..61d9ad7d9 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1054,49 +1054,49 @@ static void xwm_handle_surface_id_message(struct wlr_xwm *xwm, } } -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 // movement only -#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 // size via keyboard -#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 // move via keyboard -#define _NET_WM_MOVERESIZE_CANCEL 11 // cancel operation +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 // movement only +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 // size via keyboard +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 // move via keyboard +#define _NET_WM_MOVERESIZE_CANCEL 11 // cancel operation static enum wlr_edges net_wm_edges_to_wlr(uint32_t net_wm_edges) { enum wlr_edges edges = WLR_EDGE_NONE; switch(net_wm_edges) { - case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: - edges = WLR_EDGE_TOP | WLR_EDGE_LEFT; - break; - case _NET_WM_MOVERESIZE_SIZE_TOP: - edges = WLR_EDGE_TOP; - break; - case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: - edges = WLR_EDGE_TOP | WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_RIGHT: - edges = WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: - edges = WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOM: - edges = WLR_EDGE_BOTTOM; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: - edges = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; - break; - case _NET_WM_MOVERESIZE_SIZE_LEFT: - edges = WLR_EDGE_LEFT; - break; - default: - break; + case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: + edges = WLR_EDGE_TOP | WLR_EDGE_LEFT; + break; + case _NET_WM_MOVERESIZE_SIZE_TOP: + edges = WLR_EDGE_TOP; + break; + case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: + edges = WLR_EDGE_TOP | WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_RIGHT: + edges = WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: + edges = WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOM: + edges = WLR_EDGE_BOTTOM; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: + edges = WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; + break; + case _NET_WM_MOVERESIZE_SIZE_LEFT: + edges = WLR_EDGE_LEFT; + break; + default: + break; } return edges; @@ -1138,25 +1138,25 @@ static void xwm_handle_net_wm_moveresize_message(struct wlr_xwm *xwm, } } -#define _NET_WM_STATE_REMOVE 0 -#define _NET_WM_STATE_ADD 1 -#define _NET_WM_STATE_TOGGLE 2 +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 static bool update_state(int action, bool *state) { int new_state, changed; switch (action) { - case _NET_WM_STATE_REMOVE: - new_state = false; - break; - case _NET_WM_STATE_ADD: - new_state = true; - break; - case _NET_WM_STATE_TOGGLE: - new_state = !*state; - break; - default: - return false; + case _NET_WM_STATE_REMOVE: + new_state = false; + break; + case _NET_WM_STATE_ADD: + new_state = true; + break; + case _NET_WM_STATE_TOGGLE: + new_state = !*state; + break; + default: + return false; } changed = (*state != new_state); From be1e7647c3250d67041947d77350488ae00bc3e3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Nov 2020 16:48:01 +0100 Subject: [PATCH 079/223] xwayland: log unhandled NET_WM_STATE property changes --- xwayland/xwm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 61d9ad7d9..fefba7fcc 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1187,7 +1187,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, uint32_t action = client_message->data.data32[0]; for (size_t i = 0; i < 2; ++i) { - uint32_t property = client_message->data.data32[1 + i]; + xcb_atom_t property = client_message->data.data32[1 + i]; if (property == xwm->atoms[NET_WM_STATE_MODAL] && update_state(action, &xsurface->modal)) { @@ -1204,6 +1204,11 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, } else if (property == xwm->atoms[NET_WM_STATE_HIDDEN] && update_state(action, &xsurface->minimized)) { xsurface_set_net_wm_state(xsurface); + } else if (property != XCB_ATOM_NONE) { + char *prop_name = xwm_get_atom_name(xwm, property); + wlr_log(WLR_DEBUG, "Unhandled NET_WM_STATE property change " + "%"PRIu32" (%s)", property, prop_name ? prop_name : "(null)"); + free(prop_name); } } // client_message->data.data32[3] is the source indication From c2db691cad17a6228cde6bbbe39b8afff5f01908 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 27 Aug 2020 11:42:58 +0200 Subject: [PATCH 080/223] gamma-control-v1: apply gamma LUT when output gets enabled Closes: https://github.com/swaywm/wlroots/issues/2372 --- include/wlr/types/wlr_gamma_control_v1.h | 4 ++ types/wlr_gamma_control_v1.c | 51 ++++++++++++++++++------ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/include/wlr/types/wlr_gamma_control_v1.h b/include/wlr/types/wlr_gamma_control_v1.h index 290a86e94..b247bae34 100644 --- a/include/wlr/types/wlr_gamma_control_v1.h +++ b/include/wlr/types/wlr_gamma_control_v1.h @@ -21,6 +21,10 @@ struct wlr_gamma_control_v1 { struct wlr_output *output; struct wl_list link; + uint16_t *table; + size_t ramp_size; + + struct wl_listener output_commit_listener; struct wl_listener output_destroy_listener; void *data; diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index f96c84aaa..2fdaaaab9 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -24,7 +24,9 @@ static void gamma_control_destroy(struct wlr_gamma_control_v1 *gamma_control) { wlr_output_set_gamma(gamma_control->output, 0, NULL, NULL, NULL); wl_resource_set_user_data(gamma_control->resource, NULL); wl_list_remove(&gamma_control->output_destroy_listener.link); + wl_list_remove(&gamma_control->output_commit_listener.link); wl_list_remove(&gamma_control->link); + free(gamma_control->table); free(gamma_control); } @@ -34,6 +36,22 @@ static void gamma_control_send_failed( gamma_control_destroy(gamma_control); } +static void gamma_control_apply(struct wlr_gamma_control_v1 *gamma_control) { + uint16_t *r = gamma_control->table; + uint16_t *g = gamma_control->table + gamma_control->ramp_size; + uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size; + + wlr_output_set_gamma(gamma_control->output, gamma_control->ramp_size, r, g, b); + if (!wlr_output_test(gamma_control->output)) { + wlr_output_rollback(gamma_control->output); + gamma_control_send_failed(gamma_control); + return; + } + + // Gamma LUT will be applied on next output commit + wlr_output_schedule_frame(gamma_control->output); +} + static const struct zwlr_gamma_control_v1_interface gamma_control_impl; static struct wlr_gamma_control_v1 *gamma_control_from_resource( @@ -56,6 +74,17 @@ static void gamma_control_handle_output_destroy(struct wl_listener *listener, gamma_control_destroy(gamma_control); } +static void gamma_control_handle_output_commit(struct wl_listener *listener, + void *data) { + struct wlr_gamma_control_v1 *gamma_control = + wl_container_of(listener, gamma_control, output_commit_listener); + struct wlr_output_event_commit *event = data; + if ((event->committed & WLR_OUTPUT_STATE_ENABLED) && + gamma_control->output->enabled) { + gamma_control_apply(gamma_control); + } +} + static void gamma_control_handle_set_gamma(struct wl_client *client, struct wl_resource *gamma_control_resource, int fd) { struct wlr_gamma_control_v1 *gamma_control = @@ -101,20 +130,13 @@ static void gamma_control_handle_set_gamma(struct wl_client *client, close(fd); fd = -1; - uint16_t *r = table; - uint16_t *g = table + ramp_size; - uint16_t *b = table + 2 * ramp_size; + free(gamma_control->table); + gamma_control->table = table; + gamma_control->ramp_size = ramp_size; - wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b); - if (!wlr_output_test(gamma_control->output)) { - wlr_output_rollback(gamma_control->output); - gamma_control_send_failed(gamma_control); - goto error_table; + if (gamma_control->output->enabled) { + gamma_control_apply(gamma_control); } - free(table); - - // Gamma LUT will be applied on next output commit - wlr_output_schedule_frame(gamma_control->output); return; @@ -177,6 +199,11 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client, gamma_control->output_destroy_listener.notify = gamma_control_handle_output_destroy; + wl_signal_add(&output->events.commit, + &gamma_control->output_commit_listener); + gamma_control->output_commit_listener.notify = + gamma_control_handle_output_commit; + wl_list_init(&gamma_control->link); size_t gamma_size = wlr_output_get_gamma_size(output); From 2934a7292083468b3e25b5d9ff7a03398229b17a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 22 Oct 2020 18:19:13 +0200 Subject: [PATCH 081/223] screencopy: stop setting needs_frame flag This is already done by wlr_output_schedule_frame (it calls wlr_output_update_needs_frame). --- types/wlr_screencopy_v1.c | 1 - 1 file changed, 1 deletion(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 702a62b50..19e08a71b 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -374,7 +374,6 @@ static void frame_handle_copy(struct wl_client *wl_client, frame->buffer_destroy.notify = frame_handle_buffer_destroy; // Schedule a buffer commit - output->needs_frame = true; wlr_output_schedule_frame(output); wlr_output_lock_attach_render(output, true); From 1328477a82c50ed4dbed0a42d8624510bf8048f1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:02:15 +0100 Subject: [PATCH 082/223] backend/drm: export pending FB in export_dmabuf, if any This allows callers to grab the current frame right after committing it, without having to incur a full vblank worth of latency. --- backend/drm/drm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 2644014c7..40b73925a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -639,13 +639,15 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output, return false; } - struct wlr_drm_plane *plane = crtc->primary; - - if (plane->current_fb.type == WLR_DRM_FB_TYPE_NONE) { + struct wlr_drm_fb *fb = &crtc->primary->queued_fb; + if (fb->type == WLR_DRM_FB_TYPE_NONE) { + fb = &crtc->primary->current_fb; + } + if (fb->type == WLR_DRM_FB_TYPE_NONE) { return false; } - return export_drm_bo(plane->current_fb.bo, attribs); + return export_drm_bo(fb->bo, attribs); } struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { From ccd313e01ad58beba261ecae78c94f149093ffbb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:08:08 +0100 Subject: [PATCH 083/223] output: update docs to reflect reality The docs were outdated and weren't matching what the DRM backend does (the only implementor of wlr_output_export_dmabuf). --- include/wlr/types/wlr_output.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 41423b582..972343bc4 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -391,8 +391,7 @@ size_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_gamma(struct wlr_output *output, size_t size, const uint16_t *r, const uint16_t *g, const uint16_t *b); /** - * Exports the output's current back-buffer as a DMA-BUF (ie. the buffer that - * will be displayed on next commit). + * Exports the last committed buffer as a DMA-BUF. * * The caller is responsible for cleaning up the DMA-BUF attributes. */ From 8c8164c4a6c926891c5d47f58ad4c3aa6eec8811 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:29:49 +0100 Subject: [PATCH 084/223] output: add when field to wlr_output_event_commit Similar to the one already present in wlr_output_event_precommit. --- include/wlr/types/wlr_output.h | 1 + types/wlr_output.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 972343bc4..cb7427066 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -201,6 +201,7 @@ struct wlr_output_event_precommit { struct wlr_output_event_commit { struct wlr_output *output; uint32_t committed; // bitmask of enum wlr_output_state_field + struct timespec *when; }; enum wlr_output_present_flag { diff --git a/types/wlr_output.c b/types/wlr_output.c index 1c40a1470..4ce7312f0 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -607,6 +607,7 @@ bool wlr_output_commit(struct wlr_output *output) { struct wlr_output_event_commit event = { .output = output, .committed = output->pending.committed, + .when = &now, }; wlr_signal_emit_safe(&output->events.commit, &event); From f0945e112f3f4e50021f55d59572526ff9fee847 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 14:38:56 +0100 Subject: [PATCH 085/223] export-dmabuf: export DMA-BUF on output commit We were previously exporting DMA-BUFs when receiving the capture_output request, and sending a done event on wlr_output.events.precommit. Instead, export and send done on wlr_output.events.commit. --- include/wlr/types/wlr_export_dmabuf_v1.h | 3 +- types/wlr_export_dmabuf_v1.c | 69 ++++++++++++------------ 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index 817bb1a05..344e6cbf9 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -29,12 +29,11 @@ struct wlr_export_dmabuf_frame_v1 { struct wlr_export_dmabuf_manager_v1 *manager; struct wl_list link; // wlr_export_dmabuf_manager_v1::frames - struct wlr_dmabuf_attributes attribs; struct wlr_output *output; bool cursor_locked; - struct wl_listener output_precommit; + struct wl_listener output_commit; }; struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create( diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index c2ec34c89..a8e2a4bde 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -41,8 +41,7 @@ static void frame_destroy(struct wlr_export_dmabuf_frame_v1 *frame) { } } wl_list_remove(&frame->link); - wl_list_remove(&frame->output_precommit.link); - wlr_dmabuf_attributes_finish(&frame->attribs); + wl_list_remove(&frame->output_commit.link); // Make the frame resource inert wl_resource_set_user_data(frame->resource, NULL); free(frame); @@ -53,18 +52,41 @@ static void frame_handle_resource_destroy(struct wl_resource *resource) { frame_destroy(frame); } -static void frame_output_handle_precommit(struct wl_listener *listener, +static void frame_output_handle_commit(struct wl_listener *listener, void *data) { struct wlr_export_dmabuf_frame_v1 *frame = - wl_container_of(listener, frame, output_precommit); - struct wlr_output_event_precommit *event = data; + wl_container_of(listener, frame, output_commit); + struct wlr_output_event_commit *event = data; - if (!(event->output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { + if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { return; } - wl_list_remove(&frame->output_precommit.link); - wl_list_init(&frame->output_precommit.link); + wl_list_remove(&frame->output_commit.link); + wl_list_init(&frame->output_commit.link); + + struct wlr_dmabuf_attributes attribs = {0}; + if (!wlr_output_export_dmabuf(frame->output, &attribs)) { + zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource, + ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY); + frame_destroy(frame); + return; + } + + uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT; + uint32_t mod_high = attribs.modifier >> 32; + uint32_t mod_low = attribs.modifier & 0xFFFFFFFF; + zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, + attribs.width, attribs.height, 0, 0, attribs.flags, frame_flags, + attribs.format, mod_high, mod_low, attribs.n_planes); + + for (int i = 0; i < attribs.n_planes; ++i) { + off_t size = lseek(attribs.fd[i], 0, SEEK_END); + zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i, + attribs.fd[i], size, attribs.offset[i], attribs.stride[i], i); + } + + wlr_dmabuf_attributes_finish(&attribs); time_t tv_sec = event->when->tv_sec; uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; @@ -98,7 +120,7 @@ static void manager_handle_capture_output(struct wl_client *client, return; } frame->manager = manager; - wl_list_init(&frame->output_precommit.link); + wl_list_init(&frame->output_commit.link); uint32_t version = wl_resource_get_version(manager_resource); frame->resource = wl_resource_create(client, @@ -120,14 +142,6 @@ static void manager_handle_capture_output(struct wl_client *client, return; } - struct wlr_dmabuf_attributes *attribs = &frame->attribs; - if (!wlr_output_export_dmabuf(output, attribs)) { - zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource, - ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY); - frame_destroy(frame); - return; - } - frame->output = output; wlr_output_lock_attach_render(frame->output, true); @@ -136,26 +150,11 @@ static void manager_handle_capture_output(struct wl_client *client, frame->cursor_locked = true; } - uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT; - uint32_t mod_high = attribs->modifier >> 32; - uint32_t mod_low = attribs->modifier & 0xFFFFFFFF; - - zwlr_export_dmabuf_frame_v1_send_frame(frame->resource, - output->width, output->height, 0, 0, attribs->flags, frame_flags, - attribs->format, mod_high, mod_low, attribs->n_planes); - - for (int i = 0; i < attribs->n_planes; ++i) { - off_t size = lseek(attribs->fd[i], 0, SEEK_END); - - zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i, - attribs->fd[i], size, attribs->offset[i], attribs->stride[i], i); - } + wl_list_remove(&frame->output_commit.link); + wl_signal_add(&output->events.commit, &frame->output_commit); + frame->output_commit.notify = frame_output_handle_commit; wlr_output_schedule_frame(output); - - wl_list_remove(&frame->output_precommit.link); - wl_signal_add(&output->events.precommit, &frame->output_precommit); - frame->output_precommit.notify = frame_output_handle_precommit; } static void manager_handle_destroy(struct wl_client *client, From 51fc7ddb294895ccfad173afc8f3a920f6aede4a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 16:03:54 +0100 Subject: [PATCH 086/223] screencopy: perform DMA-BUF copy on output commit --- include/wlr/types/wlr_screencopy_v1.h | 1 + types/wlr_screencopy_v1.c | 154 ++++++++++++++++++-------- 2 files changed, 106 insertions(+), 49 deletions(-) diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index b778dd414..1c45f9057 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -53,6 +53,7 @@ struct wlr_screencopy_frame_v1 { struct wlr_output *output; struct wl_listener output_precommit; + struct wl_listener output_commit; struct wl_listener output_destroy; struct wl_listener output_enable; diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 19e08a71b..d1e8336ee 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -143,6 +143,7 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) { } wl_list_remove(&frame->link); wl_list_remove(&frame->output_precommit.link); + wl_list_remove(&frame->output_commit.link); wl_list_remove(&frame->output_destroy.link); wl_list_remove(&frame->output_enable.link); wl_list_remove(&frame->buffer_destroy.link); @@ -152,6 +153,41 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) { free(frame); } +static void frame_send_damage(struct wlr_screencopy_frame_v1 *frame) { + if (!frame->with_damage) { + return; + } + + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, frame->output); + if (damage == NULL) { + return; + } + + // TODO: send fine-grained damage events + struct pixman_box32 *damage_box = + pixman_region32_extents(&damage->damage); + + int damage_x = damage_box->x1; + int damage_y = damage_box->y1; + int damage_width = damage_box->x2 - damage_box->x1; + int damage_height = damage_box->y2 - damage_box->y1; + + zwlr_screencopy_frame_v1_send_damage(frame->resource, + damage_x, damage_y, damage_width, damage_height); + + pixman_region32_clear(&damage->damage); +} + +static void frame_send_ready(struct wlr_screencopy_frame_v1 *frame, + struct timespec *when) { + time_t tv_sec = when->tv_sec; + uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; + uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF; + zwlr_screencopy_frame_v1_send_ready(frame->resource, + tv_sec_hi, tv_sec_lo, when->tv_nsec); +} + static void frame_handle_output_precommit(struct wl_listener *listener, void *_data) { struct wlr_screencopy_frame_v1 *frame = @@ -165,9 +201,14 @@ static void frame_handle_output_precommit(struct wl_listener *listener, return; } - struct screencopy_damage *damage = NULL; + struct wl_shm_buffer *shm_buffer = frame->shm_buffer; + if (shm_buffer == NULL) { + return; + } + if (frame->with_damage) { - damage = screencopy_damage_get_or_create(frame->client, output); + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, output); if (damage) { screencopy_damage_accumulate(damage); if (!pixman_region32_not_empty(&damage->damage)) { @@ -182,36 +223,19 @@ static void frame_handle_output_precommit(struct wl_listener *listener, int x = frame->box.x; int y = frame->box.y; - bool ok = false; - uint32_t flags = 0; + enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer); + int32_t width = wl_shm_buffer_get_width(shm_buffer); + int32_t height = wl_shm_buffer_get_height(shm_buffer); + int32_t stride = wl_shm_buffer_get_stride(shm_buffer); - struct wl_shm_buffer *shm_buffer = frame->shm_buffer; - struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; - assert(shm_buffer || dma_buffer); - - if (shm_buffer) { - enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer); - int32_t width = wl_shm_buffer_get_width(shm_buffer); - int32_t height = wl_shm_buffer_get_height(shm_buffer); - int32_t stride = wl_shm_buffer_get_stride(shm_buffer); - - wl_shm_buffer_begin_access(shm_buffer); - void *data = wl_shm_buffer_get_data(shm_buffer); - uint32_t renderer_flags = 0; - ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags, - stride, width, height, x, y, 0, 0, data); - flags |= renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ? - ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; - wl_shm_buffer_end_access(shm_buffer); - } else if (dma_buffer) { - struct wlr_dmabuf_attributes attr = { 0 }; - ok = wlr_output_export_dmabuf(frame->output, &attr); - ok = ok && wlr_renderer_blit_dmabuf(renderer, - &dma_buffer->attributes, &attr); - flags |= dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ? - ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; - wlr_dmabuf_attributes_finish(&attr); - } + wl_shm_buffer_begin_access(shm_buffer); + void *data = wl_shm_buffer_get_data(shm_buffer); + uint32_t renderer_flags = 0; + bool ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags, + stride, width, height, x, y, 0, 0, data); + uint32_t flags = renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ? + ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; + wl_shm_buffer_end_access(shm_buffer); if (!ok) { zwlr_screencopy_frame_v1_send_failed(frame->resource); @@ -220,29 +244,57 @@ static void frame_handle_output_precommit(struct wl_listener *listener, } zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); + frame_send_damage(frame); + frame_send_ready(frame, event->when); + frame_destroy(frame); +} - // TODO: send fine-grained damage events - if (damage) { - struct pixman_box32 *damage_box = - pixman_region32_extents(&damage->damage); +static void frame_handle_output_commit(struct wl_listener *listener, + void *data) { + struct wlr_screencopy_frame_v1 *frame = + wl_container_of(listener, frame, output_commit); + struct wlr_output_event_commit *event = data; + struct wlr_output *output = frame->output; + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); - int damage_x = damage_box->x1; - int damage_y = damage_box->y1; - int damage_width = damage_box->x2 - damage_box->x1; - int damage_height = damage_box->y2 - damage_box->y1; - - zwlr_screencopy_frame_v1_send_damage(frame->resource, - damage_x, damage_y, damage_width, damage_height); - - pixman_region32_clear(&damage->damage); + if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) { + return; } - time_t tv_sec = event->when->tv_sec; - uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0; - uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF; - zwlr_screencopy_frame_v1_send_ready(frame->resource, - tv_sec_hi, tv_sec_lo, event->when->tv_nsec); + struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer; + if (dma_buffer == NULL) { + return; + } + if (frame->with_damage) { + struct screencopy_damage *damage = + screencopy_damage_get_or_create(frame->client, output); + if (damage && !pixman_region32_not_empty(&damage->damage)) { + return; + } + } + + wl_list_remove(&frame->output_commit.link); + wl_list_init(&frame->output_commit.link); + + struct wlr_dmabuf_attributes attr = { 0 }; + bool ok = wlr_output_export_dmabuf(output, &attr); + ok = ok && wlr_renderer_blit_dmabuf(renderer, + &dma_buffer->attributes, &attr); + uint32_t flags = dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ? + ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0; + wlr_dmabuf_attributes_finish(&attr); + + if (!ok) { + zwlr_screencopy_frame_v1_send_failed(frame->resource); + frame_destroy(frame); + return; + } + + zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); + frame_send_damage(frame); + frame_send_ready(frame, event->when); frame_destroy(frame); } @@ -364,6 +416,9 @@ static void frame_handle_copy(struct wl_client *wl_client, wl_signal_add(&output->events.precommit, &frame->output_precommit); frame->output_precommit.notify = frame_handle_output_precommit; + wl_signal_add(&output->events.commit, &frame->output_commit); + frame->output_commit.notify = frame_handle_output_commit; + wl_signal_add(&output->events.destroy, &frame->output_enable); frame->output_enable.notify = frame_handle_output_enable; @@ -466,6 +521,7 @@ static void capture_output(struct wl_client *wl_client, wl_list_insert(&client->manager->frames, &frame->link); wl_list_init(&frame->output_precommit.link); + wl_list_init(&frame->output_commit.link); wl_list_init(&frame->output_enable.link); wl_list_init(&frame->output_destroy.link); wl_list_init(&frame->buffer_destroy.link); From 4471a83ed0ce3c717d6d59c0a99fbc63614cb248 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 4 Nov 2020 16:06:45 +0100 Subject: [PATCH 087/223] screencopy: send failed when copying a DMA-BUF with a region We don't support that yet. --- types/wlr_screencopy_v1.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index d1e8336ee..2d81ff7be 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -278,6 +278,15 @@ static void frame_handle_output_commit(struct wl_listener *listener, wl_list_remove(&frame->output_commit.link); wl_list_init(&frame->output_commit.link); + // TODO: add support for copying regions with DMA-BUFs + if (frame->box.x != 0 || frame->box.y != 0 || + output->width != frame->box.width || + output->height != frame->box.height) { + zwlr_screencopy_frame_v1_send_failed(frame->resource); + frame_destroy(frame); + return; + } + struct wlr_dmabuf_attributes attr = { 0 }; bool ok = wlr_output_export_dmabuf(output, &attr); ok = ok && wlr_renderer_blit_dmabuf(renderer, From 8348fc3ef8b992fce097bef81111eda3677957f4 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 5 Nov 2020 13:07:45 +0100 Subject: [PATCH 088/223] xwayland: remove unused listener --- include/wlr/xwayland.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index b801b5dd4..8de9ed07e 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -84,7 +84,6 @@ struct wlr_xwayland { struct wl_listener server_ready; struct wl_listener server_destroy; - struct wl_listener client_destroy; struct wl_listener seat_destroy; void *data; From 372a52ecc08aff003b3024e852e848024b699a15 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 19:14:55 +0100 Subject: [PATCH 089/223] input-method: send modifiers in set_keyboard Otherwise the client might have an outdated modifiers state. The same is done in wlr_seat_keyboard [1]. [1]: https://github.com/swaywm/wlroots/blob/8348fc3ef8b992fce097bef81111eda3677957f4/types/seat/wlr_seat_keyboard.c#L163 --- types/wlr_input_method_v2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index cb2482888..29b0d0289 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -259,6 +259,9 @@ void wlr_input_method_keyboard_grab_v2_set_keyboard( handle_keyboard_destroy; wl_signal_add(&keyboard->events.destroy, &keyboard_grab->keyboard_destroy); + + wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, + &keyboard->modifiers); } keyboard_grab->keyboard = keyboard; From 9595f95452a1d7420bbb190dc29c3806c29ca41e Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Tue, 27 Oct 2020 18:28:39 +0100 Subject: [PATCH 090/223] xdg_shell: handle inert popups xdg_popups can be destroyed by the compositor when closed. When this happens, wlroots makes the xdg_popup surface inert and resets the xdg_surface role to NONE. Currently, wlroots sends a protocol error and asserts that an xdg_surface has a role when committed. This is racy if at the same time the client commits an xdg_popup and the compositor closes it. This patch removes the assertion and ignores commits on xdg_surfaces without a role set. --- types/xdg_shell/wlr_xdg_surface.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index d33cbffed..b65490d0a 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -336,7 +336,9 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener, return; } - if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) { + // surface->role might be NONE for inert popups + // So we check surface->surface->role + if (surface->surface->role == NULL) { wl_resource_post_error(surface->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_surface must have a role"); @@ -361,7 +363,8 @@ void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_NONE: - assert(false); + // inert toplevel or popup + return; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: handle_xdg_surface_toplevel_committed(surface); break; From 238d1c078fb03338e9f271d98f7bf6b1fc399285 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 8 Nov 2020 15:01:44 +0100 Subject: [PATCH 091/223] Update version to 0.12.0 --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index ca26391e7..835e01952 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.11.0', + version: '0.12.0', license: 'MIT', meson_version: '>=0.54.0', default_options: [ @@ -15,7 +15,7 @@ project( # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. -soversion = 6 +soversion = 7 add_project_arguments([ '-DWLR_USE_UNSTABLE', From 7693f61d813869f7f8b3c658f610a16f6283b24f Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 21 Oct 2020 17:21:23 +0200 Subject: [PATCH 092/223] Replace wlr_key_state with wl_keyboard_key_state There's no reason to have duplicate enums --- backend/libinput/keyboard.c | 4 ++-- backend/wayland/seat.c | 4 ++-- backend/x11/input_device.c | 8 +++++--- examples/output-layout.c | 2 +- examples/rotation.c | 2 +- include/wlr/types/wlr_keyboard.h | 9 ++------- tinywl/tinywl.c | 4 ++-- types/wlr_keyboard.c | 6 +++--- types/wlr_keyboard_group.c | 15 ++++++++------- 9 files changed, 26 insertions(+), 28 deletions(-) diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c index 93605e778..d5207f542 100644 --- a/backend/libinput/keyboard.c +++ b/backend/libinput/keyboard.c @@ -72,10 +72,10 @@ void handle_keyboard_key(struct libinput_event *event, libinput_event_keyboard_get_key_state(kbevent); switch (state) { case LIBINPUT_KEY_STATE_RELEASED: - wlr_event.state = WLR_KEY_RELEASED; + wlr_event.state = WL_KEYBOARD_KEY_STATE_RELEASED; break; case LIBINPUT_KEY_STATE_PRESSED: - wlr_event.state = WLR_KEY_PRESSED; + wlr_event.state = WL_KEYBOARD_KEY_STATE_PRESSED; break; } wlr_event.update_state = true; diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 1697616c5..c1cd473d9 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -209,7 +209,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, wl_array_for_each(keycode_ptr, keys) { struct wlr_event_keyboard_key event = { .keycode = *keycode_ptr, - .state = WLR_KEY_PRESSED, + .state = WL_KEYBOARD_KEY_STATE_PRESSED, .time_msec = time, .update_state = false, }; @@ -232,7 +232,7 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, struct wlr_event_keyboard_key event = { .keycode = keycode, - .state = WLR_KEY_RELEASED, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, .time_msec = time, .update_state = false, }; diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index ced52baef..1bcd30607 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -4,6 +4,8 @@ #include +#include + #include #include #include @@ -18,7 +20,7 @@ #include "util/signal.h" static void send_key_event(struct wlr_x11_backend *x11, uint32_t key, - enum wlr_key_state st, xcb_timestamp_t time) { + enum wl_keyboard_key_state st, xcb_timestamp_t time) { struct wlr_event_keyboard_key ev = { .time_msec = time, .keycode = key, @@ -123,7 +125,7 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11, wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base, ev->mods.latched, ev->mods.locked, ev->mods.effective); - send_key_event(x11, ev->detail - 8, WLR_KEY_PRESSED, ev->time); + send_key_event(x11, ev->detail - 8, WL_KEYBOARD_KEY_STATE_PRESSED, ev->time); x11->time = ev->time; break; } @@ -133,7 +135,7 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11, wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base, ev->mods.latched, ev->mods.locked, ev->mods.effective); - send_key_event(x11, ev->detail - 8, WLR_KEY_RELEASED, ev->time); + send_key_event(x11, ev->detail - 8, WL_KEYBOARD_KEY_STATE_RELEASED, ev->time); x11->time = ev->time; break; } diff --git a/examples/output-layout.c b/examples/output-layout.c index c9ca53a46..b3fff4196 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -190,7 +190,7 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { // and make this change in pixels/sec^2 // Also, key repeat int delta = 75; - if (event->state == WLR_KEY_PRESSED) { + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { switch (sym) { case XKB_KEY_Left: update_velocities(sample, -delta, 0); diff --git a/examples/rotation.c b/examples/rotation.c index e76cc2a4d..edd100e9b 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -140,7 +140,7 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { if (sym == XKB_KEY_Escape) { wl_display_terminate(sample->display); } - if (event->state == WLR_KEY_PRESSED) { + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { switch (sym) { case XKB_KEY_Left: update_velocities(sample, -16, 0); diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index c1a19a8eb..b51114628 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #define WLR_LED_COUNT 3 @@ -91,16 +91,11 @@ struct wlr_keyboard { void *data; }; -enum wlr_key_state { - WLR_KEY_RELEASED, - WLR_KEY_PRESSED, -}; - struct wlr_event_keyboard_key { uint32_t time_msec; uint32_t keycode; bool update_state; // if backend doesn't update modifiers on its own - enum wlr_key_state state; + enum wl_keyboard_key_state state; }; bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb, diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 84a7636b8..e2cf30a0b 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -197,7 +197,7 @@ static void keyboard_handle_key( bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { /* If alt is held down and this button was _pressed_, we attempt to * process it as a compositor keybinding. */ for (int i = 0; i < nsyms; i++) { @@ -374,7 +374,7 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { int new_left = server->grab_geobox.x; int new_right = server->grab_geobox.x + server->grab_geobox.width; int new_top = server->grab_geobox.y; - int new_bottom = server->grab_geobox.y + server->grab_geobox.height; + int new_bottom = server->grab_geobox.y + server->grab_geobox.height; if (server->resize_edges & WLR_EDGE_TOP) { new_top = border_y; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index 50363fed3..fe94330f6 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -58,11 +58,11 @@ bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { void keyboard_key_update(struct wlr_keyboard *keyboard, struct wlr_event_keyboard_key *event) { - if (event->state == WLR_KEY_PRESSED) { + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { set_add(keyboard->keycodes, &keyboard->num_keycodes, WLR_KEYBOARD_KEYS_CAP, event->keycode); } - if (event->state == WLR_KEY_RELEASED) { + if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { set_remove(keyboard->keycodes, &keyboard->num_keycodes, WLR_KEYBOARD_KEYS_CAP, event->keycode); } @@ -99,7 +99,7 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, if (event->update_state) { uint32_t keycode = event->keycode + 8; xkb_state_update_key(keyboard->xkb_state, keycode, - event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); + event->state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); } bool updated = keyboard_modifier_update(keyboard); diff --git a/types/wlr_keyboard_group.c b/types/wlr_keyboard_group.c index ace1fcd22..d614f58db 100644 --- a/types/wlr_keyboard_group.c +++ b/types/wlr_keyboard_group.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "types/wlr_keyboard.h" #include "util/signal.h" @@ -95,11 +96,11 @@ static bool process_key(struct keyboard_group_device *group_device, if (key->keycode != event->keycode) { continue; } - if (event->state == WLR_KEY_PRESSED) { + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { key->count++; return false; } - if (event->state == WLR_KEY_RELEASED) { + if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { key->count--; if (key->count > 0) { return false; @@ -110,7 +111,7 @@ static bool process_key(struct keyboard_group_device *group_device, break; } - if (event->state == WLR_KEY_PRESSED) { + if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { struct keyboard_group_key *key = calloc(1, sizeof(struct keyboard_group_key)); if (!key) { @@ -199,7 +200,7 @@ static void handle_keyboard_repeat_info(struct wl_listener *listener, } static void refresh_state(struct keyboard_group_device *device, - enum wlr_key_state state) { + enum wl_keyboard_key_state state) { struct wl_array keys; wl_array_init(&keys); @@ -229,7 +230,7 @@ static void refresh_state(struct keyboard_group_device *device, // If there are any unique keys, emit the enter/leave event if (keys.size > 0) { - if (state == WLR_KEY_PRESSED) { + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { wlr_signal_emit_safe(&device->keyboard->group->events.enter, &keys); } else { wlr_signal_emit_safe(&device->keyboard->group->events.leave, &keys); @@ -240,7 +241,7 @@ static void refresh_state(struct keyboard_group_device *device, } static void remove_keyboard_group_device(struct keyboard_group_device *device) { - refresh_state(device, WLR_KEY_RELEASED); + refresh_state(device, WL_KEYBOARD_KEY_STATE_RELEASED); device->keyboard->group = NULL; wl_list_remove(&device->link); wl_list_remove(&device->key.link); @@ -312,7 +313,7 @@ bool wlr_keyboard_group_add_keyboard(struct wlr_keyboard_group *group, group_kb->repeat_info.delay); } - refresh_state(device, WLR_KEY_PRESSED); + refresh_state(device, WL_KEYBOARD_KEY_STATE_PRESSED); return true; } From 0724b3c453e45b59aecdaecd6b654e1febb68dc7 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 11 Oct 2020 16:06:26 +0200 Subject: [PATCH 093/223] Use uint32_t in wlr_renderer_begin signature This matches the signature of wlr_renderer_impl.begin --- include/wlr/render/wlr_renderer.h | 2 +- render/wlr_renderer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 513f412a1..363a12e45 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -35,7 +35,7 @@ struct wlr_renderer { struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, EGLenum platform, void *remote_display, EGLint *config_attribs, EGLint visual_id); -void wlr_renderer_begin(struct wlr_renderer *r, int width, int height); +void wlr_renderer_begin(struct wlr_renderer *r, uint32_t width, uint32_t height); void wlr_renderer_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); /** diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 8fa11cc97..bdcc836f1 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -37,7 +37,7 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { } } -void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { +void wlr_renderer_begin(struct wlr_renderer *r, uint32_t width, uint32_t height) { assert(!r->rendering); r->impl->begin(r, width, height); From e06c9e43afd8d2067c2c28bc25ed0830e43e5c78 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 11 Nov 2020 14:16:41 +0100 Subject: [PATCH 094/223] Remove unneeded includes from wlr_input_device.h This uncovered many places where we were using things without directly including them. --- backend/headless/output.c | 1 + backend/libinput/backend.c | 1 + examples/multi-pointer.c | 1 + examples/pointer.c | 3 +++ examples/simple.c | 1 + examples/tablet.c | 1 + examples/touch.c | 2 ++ include/backend/wayland.h | 1 + include/backend/x11.h | 3 +++ include/wlr/types/wlr_input_device.h | 10 ++-------- include/wlr/types/wlr_pointer.h | 1 + include/wlr/types/wlr_seat.h | 1 + types/tablet_v2/wlr_tablet_v2_pad.c | 1 + types/wlr_cursor.c | 3 +++ 14 files changed, 22 insertions(+), 8 deletions(-) diff --git a/backend/headless/output.c b/backend/headless/output.c index 32c2a7fde..315f5a33c 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 3c42d7f8f..12f76bbff 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index eceeb6d68..a48f58886 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/pointer.c b/examples/pointer.c index 703aa59ea..92a5934e8 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/examples/simple.c b/examples/simple.c index e3af1a118..ce58dfa94 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/examples/tablet.c b/examples/tablet.c index 7721ef720..59bf69798 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/touch.c b/examples/touch.c index 39dd1d457..3d18dfd0c 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include "cat.h" diff --git a/include/backend/wayland.h b/include/backend/wayland.h index d782584f6..9542a75f6 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -12,6 +12,7 @@ #include #include #include +#include #include struct wlr_wl_backend { diff --git a/include/backend/x11.h b/include/backend/x11.h index 549f6a77e..033963616 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -10,7 +10,10 @@ #include #include #include +#include #include +#include +#include #include #include diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index 214620232..8ed9b4659 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -9,6 +9,8 @@ #ifndef WLR_TYPES_WLR_INPUT_DEVICE_H #define WLR_TYPES_WLR_INPUT_DEVICE_H +#include + enum wlr_button_state { WLR_BUTTON_RELEASED, WLR_BUTTON_PRESSED, @@ -23,14 +25,6 @@ enum wlr_input_device_type { WLR_INPUT_DEVICE_SWITCH, }; -/* Note: these are circular dependencies */ -#include -#include -#include -#include -#include -#include - struct wlr_input_device_impl; struct wlr_input_device { diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 696990429..ac168d600 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -11,6 +11,7 @@ #include #include +#include #include struct wlr_pointer_impl; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 332ab0d30..5094874c6 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #define WLR_SERIAL_RINGSET_SIZE 128 diff --git a/types/tablet_v2/wlr_tablet_v2_pad.c b/types/tablet_v2/wlr_tablet_v2_pad.c index fdffd4755..779e24e57 100644 --- a/types/tablet_v2/wlr_tablet_v2_pad.c +++ b/types/tablet_v2/wlr_tablet_v2_pad.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 429acd6db..aff7859de 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include "util/signal.h" From 40bfd9f8f79927b5095166a4b4b5b191288338ef Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 20:48:11 +0200 Subject: [PATCH 095/223] backend/wayland: Bind seat listener to wlr_wl_seat --- backend/wayland/backend.c | 3 +-- backend/wayland/seat.c | 15 +++++---------- backend/wayland/tablet_v2.c | 12 +++++++----- include/backend/wayland.h | 4 +++- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 459baaa6d..4d814cd2f 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -164,8 +164,7 @@ static bool backend_start(struct wlr_backend *backend) { } if (wl->tablet_manager) { - wl_add_tablet_seat(wl->tablet_manager, - seat->wl_seat, wl); + wl_add_tablet_seat(wl->tablet_manager, seat); } } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index c1cd473d9..56e8dc753 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -380,8 +380,9 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { return false; } seat->wl_seat = wl_seat; + seat->backend = wl; wl->seat = seat; - wl_seat_add_listener(wl_seat, &seat_listener, wl); + wl_seat_add_listener(wl_seat, &seat_listener, seat); return true; } @@ -408,11 +409,6 @@ void destroy_wl_seats(struct wlr_wl_backend *wl) { free(seat); } -static struct wlr_wl_seat *backend_get_seat(struct wlr_wl_backend *backend, struct wl_seat *wl_seat) { - assert(backend->seat && backend->seat->wl_seat == wl_seat); - return backend->seat; -} - static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { struct wlr_wl_input_device *dev = get_wl_input_device_from_input_device(wlr_dev); @@ -726,8 +722,8 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); + struct wlr_wl_seat *seat = data; + struct wlr_wl_backend *backend = seat->backend; if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) { wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat); @@ -801,8 +797,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat); + struct wlr_wl_seat *seat = data; free(seat->name); seat->name = strdup(name); } diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index 826c36ba1..cf2ae5323 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -429,7 +429,8 @@ static void handle_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) { wlr_log(WLR_DEBUG, "New tablet pad"); - struct wlr_wl_backend *backend = data; + struct wlr_wl_seat *seat = data; + struct wlr_wl_backend *backend = seat->backend; struct wlr_wl_input_device *dev = create_wl_input_device( backend, WLR_INPUT_DEVICE_TABLET_PAD); if (!dev) { @@ -889,7 +890,8 @@ static void handle_tab_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) { wlr_log(WLR_DEBUG, "New tablet"); - struct wlr_wl_backend *backend = data; + struct wlr_wl_seat *seat = data; + struct wlr_wl_backend *backend = seat->backend; struct wlr_wl_input_device *dev = create_wl_input_device( backend, WLR_INPUT_DEVICE_TABLET_TOOL); @@ -919,18 +921,18 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { struct wlr_wl_tablet_seat *wl_add_tablet_seat( struct zwp_tablet_manager_v2 *manager, - struct wl_seat *seat, struct wlr_wl_backend *backend) { + struct wlr_wl_seat *seat) { struct wlr_wl_tablet_seat *ret = calloc(1, sizeof(struct wlr_wl_tablet_seat)); if (!(ret->tablet_seat = - zwp_tablet_manager_v2_get_tablet_seat(manager, seat))) { + zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat))) { free(ret); return NULL; } zwp_tablet_seat_v2_add_listener(ret->tablet_seat, - &tablet_seat_listener, backend); + &tablet_seat_listener, seat); return ret; } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9542a75f6..c8a0429c8 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -112,6 +112,8 @@ struct wlr_wl_seat { struct wl_touch *touch; struct wl_pointer *pointer; struct wl_keyboard *keyboard; + + struct wlr_wl_backend *backend; }; struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); @@ -129,6 +131,6 @@ extern const struct wl_seat_listener seat_listener; struct wlr_wl_tablet_seat *wl_add_tablet_seat( struct zwp_tablet_manager_v2 *manager, - struct wl_seat *seat, struct wlr_wl_backend *backend); + struct wlr_wl_seat *seat); #endif From 85b08726500c8f297ea78714ac9d636b9ae70987 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 22:11:38 +0200 Subject: [PATCH 096/223] backend/wayland: Link input devices with seats --- backend/wayland/backend.c | 2 +- backend/wayland/output.c | 2 +- backend/wayland/seat.c | 39 ++++++++++++++++++++++--------------- backend/wayland/tablet_v2.c | 6 ++---- include/backend/wayland.h | 9 +++++---- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 4d814cd2f..bd4d6eb66 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -160,7 +160,7 @@ static bool backend_start(struct wlr_backend *backend) { struct wlr_wl_seat *seat = wl->seat; if (seat != NULL) { if (seat->keyboard) { - create_wl_keyboard(seat->keyboard, wl); + create_wl_keyboard(seat); } if (wl->tablet_manager) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 568d90db6..c8149149f 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -589,7 +589,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { struct wlr_wl_seat *seat = backend->seat; if (seat != NULL) { if (seat->pointer) { - create_wl_pointer(seat->pointer, output); + create_wl_pointer(seat, output); } } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 56e8dc753..e038bb526 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -412,8 +412,8 @@ void destroy_wl_seats(struct wlr_wl_backend *wl) { static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { struct wlr_wl_input_device *dev = get_wl_input_device_from_input_device(wlr_dev); - assert(dev->backend->seat); - return dev->backend->seat; + assert(dev->seat); + return dev->seat; } static void input_device_destroy(struct wlr_input_device *wlr_dev) { @@ -437,14 +437,15 @@ bool wlr_input_device_is_wl(struct wlr_input_device *dev) { } struct wlr_wl_input_device *create_wl_input_device( - struct wlr_wl_backend *backend, enum wlr_input_device_type type) { + struct wlr_wl_seat *seat, enum wlr_input_device_type type) { struct wlr_wl_input_device *dev = calloc(1, sizeof(struct wlr_wl_input_device)); if (dev == NULL) { wlr_log_errno(WLR_ERROR, "Allocation failed"); return NULL; } - dev->backend = backend; + dev->backend = seat->backend; + dev->seat = seat; struct wlr_input_device *wlr_dev = &dev->wlr_input_device; @@ -452,7 +453,7 @@ struct wlr_wl_input_device *create_wl_input_device( const char *name = "wayland"; wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, product); - wl_list_insert(&backend->devices, &wlr_dev->link); + wl_list_insert(&seat->backend->devices, &wlr_dev->link); return dev; } @@ -617,7 +618,9 @@ static void pointer_handle_output_destroy(struct wl_listener *listener, wlr_input_device_destroy(&pointer->input_device->wlr_input_device); } -void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output) { +void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { + assert(seat->pointer); + struct wl_pointer *wl_pointer = seat->pointer; struct wlr_wl_backend *backend = output->backend; struct wlr_input_device *wlr_dev; @@ -640,7 +643,7 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp pointer->output = output; struct wlr_wl_input_device *dev = - create_wl_input_device(backend, WLR_INPUT_DEVICE_POINTER); + create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER); if (dev == NULL) { free(pointer); wlr_log(WLR_ERROR, "Allocation failed"); @@ -677,9 +680,11 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); } -void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl) { +void create_wl_keyboard(struct wlr_wl_seat *seat) { + assert(seat->keyboard); + struct wl_keyboard *wl_keyboard = seat->keyboard; struct wlr_wl_input_device *dev = - create_wl_input_device(wl, WLR_INPUT_DEVICE_KEYBOARD); + create_wl_input_device(seat, WLR_INPUT_DEVICE_KEYBOARD); if (!dev) { return; } @@ -695,12 +700,14 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_keyboard_init(wlr_dev->keyboard, NULL); wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); - wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); + wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); } -void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { +void create_wl_touch(struct wlr_wl_seat *seat) { + assert(seat->touch); + struct wl_touch *wl_touch = seat->touch; struct wlr_wl_input_device *dev = - create_wl_input_device(wl, WLR_INPUT_DEVICE_TOUCH); + create_wl_input_device(seat, WLR_INPUT_DEVICE_TOUCH); if (!dev) { return; } @@ -716,7 +723,7 @@ void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) { wlr_touch_init(wlr_dev->touch, NULL); wl_touch_add_listener(wl_touch, &touch_listener, dev); - wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); + wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); } @@ -733,7 +740,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, struct wlr_wl_output *output; wl_list_for_each(output, &backend->outputs, link) { - create_wl_pointer(wl_pointer, output); + create_wl_pointer(seat, output); } } if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { @@ -757,7 +764,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, seat->keyboard = wl_keyboard; if (backend->started) { - create_wl_keyboard(wl_keyboard, backend); + create_wl_keyboard(seat); } } if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) { @@ -777,7 +784,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, seat->touch = wl_seat_get_touch(wl_seat); if (backend->started) { - create_wl_touch(seat->touch, backend); + create_wl_touch(seat); } } if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) { diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index cf2ae5323..b7ad73ea4 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -430,9 +430,8 @@ static void handle_pad_added(void *data, struct zwp_tablet_pad_v2 *id) { wlr_log(WLR_DEBUG, "New tablet pad"); struct wlr_wl_seat *seat = data; - struct wlr_wl_backend *backend = seat->backend; struct wlr_wl_input_device *dev = create_wl_input_device( - backend, WLR_INPUT_DEVICE_TABLET_PAD); + seat, WLR_INPUT_DEVICE_TABLET_PAD); if (!dev) { /* This leaks a couple of server-sent resource ids. iirc this * shouldn't ever be a problem, but it isn't exactly nice @@ -891,9 +890,8 @@ static void handle_tab_added(void *data, struct zwp_tablet_v2 *id) { wlr_log(WLR_DEBUG, "New tablet"); struct wlr_wl_seat *seat = data; - struct wlr_wl_backend *backend = seat->backend; struct wlr_wl_input_device *dev = create_wl_input_device( - backend, WLR_INPUT_DEVICE_TABLET_TOOL); + seat, WLR_INPUT_DEVICE_TABLET_TOOL); if (!dev) { zwp_tablet_v2_destroy(id); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index c8a0429c8..65fe6bbc1 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -87,6 +87,7 @@ struct wlr_wl_input_device { uint32_t fingers; struct wlr_wl_backend *backend; + struct wlr_wl_seat *seat; void *resource; }; @@ -119,11 +120,11 @@ struct wlr_wl_seat { struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); void update_wl_output_cursor(struct wlr_wl_output *output); struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); -void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output); -void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl); -void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl); +void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output); +void create_wl_keyboard(struct wlr_wl_seat *seat); +void create_wl_touch(struct wlr_wl_seat *seat); struct wlr_wl_input_device *create_wl_input_device( - struct wlr_wl_backend *backend, enum wlr_input_device_type type); + struct wlr_wl_seat *seat, enum wlr_input_device_type type); bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); From 70ffda3ea313caace95ad61d647ffb7367af1ae5 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sat, 3 Oct 2020 23:06:10 +0200 Subject: [PATCH 097/223] backend/wayland: Add registering multiple seats --- backend/wayland/backend.c | 5 +++-- backend/wayland/output.c | 4 ++-- backend/wayland/seat.c | 38 ++++++++++++++++++-------------------- include/backend/wayland.h | 3 ++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index bd4d6eb66..314d45cdd 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -157,8 +157,8 @@ static bool backend_start(struct wlr_backend *backend) { wl->started = true; - struct wlr_wl_seat *seat = wl->seat; - if (seat != NULL) { + struct wlr_wl_seat *seat; + wl_list_for_each(seat, &wl->seats, link) { if (seat->keyboard) { create_wl_keyboard(seat); } @@ -262,6 +262,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wl->local_display = display; wl_list_init(&wl->devices); wl_list_init(&wl->outputs); + wl_list_init(&wl->seats); wl->remote_display = wl_display_connect(remote); if (!wl->remote_display) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index c8149149f..3899f7f40 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -586,8 +586,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); - struct wlr_wl_seat *seat = backend->seat; - if (seat != NULL) { + struct wlr_wl_seat *seat; + wl_list_for_each(seat, &backend->seats, link) { if (seat->pointer) { create_wl_pointer(seat, output); } diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index e038bb526..ebb9c84cd 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -373,7 +373,6 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( } bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { - assert(!wl->seat); // only one seat supported at the moment struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); if (!seat) { wlr_log_errno(WLR_ERROR, "Allocation failed"); @@ -381,32 +380,31 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { } seat->wl_seat = wl_seat; seat->backend = wl; - wl->seat = seat; + wl_list_insert(&wl->seats, &seat->link); wl_seat_add_listener(wl_seat, &seat_listener, seat); return true; } void destroy_wl_seats(struct wlr_wl_backend *wl) { - struct wlr_wl_seat *seat = wl->seat; - if (!seat) { - return; - } - - if (seat->touch) { - wl_touch_destroy(seat->touch); - } - if (seat->pointer) { - wl_pointer_destroy(seat->pointer); - } - if (seat->keyboard && !wl->started) { - // early termination will not be handled by input_device_destroy - wl_keyboard_destroy(seat->keyboard); - } - free(seat->name); - if (seat->wl_seat) { + struct wlr_wl_seat *seat, *tmp_seat; + wl_list_for_each_safe(seat, tmp_seat, &wl->seats, link) { + if (seat->touch) { + wl_touch_destroy(seat->touch); + } + if (seat->pointer) { + wl_pointer_destroy(seat->pointer); + } + if (seat->keyboard && !wl->started) { + // early termination will not be handled by input_device_destroy + wl_keyboard_destroy(seat->keyboard); + } + free(seat->name); + assert(seat->wl_seat); wl_seat_destroy(seat->wl_seat); + + wl_list_remove(&seat->link); + free(seat); } - free(seat); } static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 65fe6bbc1..202926254 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -39,7 +39,7 @@ struct wlr_wl_backend { struct wp_presentation *presentation; struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; - struct wlr_wl_seat *seat; + struct wl_list seats; // wlr_wl_seat.link struct wlr_wl_pointer *current_pointer; struct zwp_tablet_manager_v2 *tablet_manager; struct wlr_drm_format_set linux_dmabuf_v1_formats; @@ -109,6 +109,7 @@ struct wlr_wl_pointer { struct wlr_wl_seat { struct wl_seat *wl_seat; + struct wl_list link; // wlr_wl_backend.seats char *name; struct wl_touch *touch; struct wl_pointer *pointer; From 44c4773d58e8d671e3f3e60d7eda86134775e9c9 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 4 Oct 2020 22:45:36 +0200 Subject: [PATCH 098/223] backend/wayland: Use seat name in input names --- backend/wayland/seat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index ebb9c84cd..d61e13707 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -448,7 +448,11 @@ struct wlr_wl_input_device *create_wl_input_device( struct wlr_input_device *wlr_dev = &dev->wlr_input_device; unsigned int vendor = 0, product = 0; - const char *name = "wayland"; + + size_t name_size = 8 + strlen(seat->name) + 1; + char name[name_size]; + (void) snprintf(name, name_size, "wayland-%s", seat->name); + wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor, product); wl_list_insert(&seat->backend->devices, &wlr_dev->link); From 07e2e0f60cc4f743038ea8da2801d598a1b90cb9 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 4 Oct 2020 22:28:25 +0200 Subject: [PATCH 099/223] backend/wayland: Listen to pointers from all seats This effectively gets swaywm/wlroots#1499 to the point where functionality somewhat preserved and no crash happens. We still can have only one cursor, but we can control it from multiple seats in time-sharing manner by entering/leaving output. --- backend/wayland/seat.c | 62 +++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d61e13707..7319c1702 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -22,14 +22,16 @@ #include "util/signal.h" #include "util/time.h" -static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) { +static struct wlr_wl_pointer *output_get_pointer( + struct wlr_wl_output *output, + const struct wl_pointer *wl_pointer) { struct wlr_input_device *wlr_dev; wl_list_for_each(wlr_dev, &output->backend->devices, link) { if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) { continue; } struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer); - if (pointer->output == output) { + if (pointer->output == output && pointer->wl_pointer == wl_pointer) { return pointer; } } @@ -47,8 +49,15 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_output *output = wl_surface_get_user_data(surface); assert(output); - struct wlr_wl_pointer *pointer = output_get_pointer(output); - assert(!backend->current_pointer || backend->current_pointer == pointer); + struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer); + + struct wlr_wl_pointer *current_pointer = backend->current_pointer; + if (current_pointer && current_pointer != pointer) { + wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s", + pointer->input_device->seat->name, + current_pointer->input_device->seat->name); + return; + } output->enter_serial = serial; backend->current_pointer = pointer; @@ -422,6 +431,8 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) { wl_keyboard_release(seat->keyboard); seat->keyboard = NULL; } + // We can't destroy pointer here because we might have multiple devices + // exposing it to compositor. wl_list_remove(&dev->wlr_input_device.link); free(dev); } @@ -625,15 +636,11 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { struct wl_pointer *wl_pointer = seat->pointer; struct wlr_wl_backend *backend = output->backend; - struct wlr_input_device *wlr_dev; - wl_list_for_each(wlr_dev, &output->backend->devices, link) { - if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) { - continue; - } - struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer); - if (pointer->output == output) { - return; - } + if (output_get_pointer(output, wl_pointer)) { + wlr_log(WLR_DEBUG, + "Pointer for seat %s and output %s already exists (ignoring)", + seat->name, output->wlr_output.name); + return; } struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer)); @@ -642,7 +649,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { return; } pointer->wl_pointer = wl_pointer; - pointer->output = output; + pointer->output = output; // we need output to map absolute coordinates onto struct wlr_wl_input_device *dev = create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER); @@ -656,7 +663,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); pointer->output_destroy.notify = pointer_handle_output_destroy; - wlr_dev = &dev->wlr_input_device; + struct wlr_input_device *wlr_dev = &dev->wlr_input_device; wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->output_name = strdup(output->wlr_output.name); wlr_pointer_init(wlr_dev->pointer, &pointer_impl); @@ -748,11 +755,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); + struct wl_pointer *wl_pointer = seat->pointer; + struct wlr_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->type == WLR_INPUT_DEVICE_POINTER) { - wlr_input_device_destroy(device); + if (device->type != WLR_INPUT_DEVICE_POINTER) { + continue; } + struct wlr_wl_pointer *pointer = pointer_get_wl(device->pointer); + if (pointer->wl_pointer != wl_pointer) { + continue; + } + wlr_log(WLR_DEBUG, "dropping pointer %s", + pointer->input_device->wlr_input_device.name); + wlr_input_device_destroy(device); + assert(backend->current_pointer != pointer); } wl_pointer_release(seat->pointer); @@ -774,9 +791,16 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, struct wlr_input_device *device, *tmp; wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->type == WLR_INPUT_DEVICE_KEYBOARD) { - wlr_input_device_destroy(device); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + continue; } + + struct wlr_wl_input_device *input_device = + get_wl_input_device_from_input_device(device); + if (input_device->seat != seat) { + continue; + } + wlr_input_device_destroy(device); } assert(seat->keyboard == NULL); // free'ed by input_device_destroy } From ce8855ca2ab29f93ed7cdfc8348a7a8f5a970328 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Sun, 4 Oct 2020 14:51:52 +0200 Subject: [PATCH 100/223] backend/wayland: Bind pointer listener to seat --- backend/wayland/seat.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 7319c1702..19a1686a3 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -42,7 +42,8 @@ static struct wlr_wl_pointer *output_get_pointer( static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) { - struct wlr_wl_backend *backend = data; + struct wlr_wl_seat *seat = data; + struct wlr_wl_backend *backend = seat->backend; if (surface == NULL) { return; } @@ -54,8 +55,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_pointer *current_pointer = backend->current_pointer; if (current_pointer && current_pointer != pointer) { wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s", - pointer->input_device->seat->name, - current_pointer->input_device->seat->name); + seat->name, current_pointer->input_device->seat->name); return; } @@ -66,7 +66,8 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { - struct wlr_wl_backend *backend = data; + struct wlr_wl_seat *seat = data; + struct wlr_wl_backend *backend = seat->backend; if (surface == NULL) { return; } @@ -85,8 +86,8 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -103,8 +104,8 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -120,8 +121,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -140,8 +141,8 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, } static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -152,8 +153,8 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { static void pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -163,8 +164,8 @@ static void pointer_handle_axis_source(void *data, static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -182,8 +183,8 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { - struct wlr_wl_backend *backend = data; - struct wlr_wl_pointer *pointer = backend->current_pointer; + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->backend->current_pointer; if (pointer == NULL) { return; } @@ -685,7 +686,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { &relative_pointer_listener, dev); } - wl_pointer_add_listener(wl_pointer, &pointer_listener, backend); + wl_pointer_add_listener(wl_pointer, &pointer_listener, seat); wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); } From 44531e16e0edd3dbf6f7abe4afa930bceebcbf92 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Thu, 8 Oct 2020 02:44:38 +0200 Subject: [PATCH 101/223] backend/wayland: Add active pointer per host seat Every host seat with pointer capability propagates events to one of sub-pointer depending which output window we entered. active_pointer tracks reference to sub-pointer on enter/leave events to avoid lookup for it on every move events. Fixes swaywm/wlroots#1499 --- backend/wayland/seat.c | 30 ++++++++++++++++++++++-------- include/backend/wayland.h | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 19a1686a3..cf8412648 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -51,7 +51,9 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_output *output = wl_surface_get_user_data(surface); assert(output); struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer); + seat->active_pointer = pointer; + // Manage cursor icon/rendering on output struct wlr_wl_pointer *current_pointer = backend->current_pointer; if (current_pointer && current_pointer != pointer) { wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s", @@ -74,6 +76,12 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_output *output = wl_surface_get_user_data(surface); assert(output); + + if (seat->active_pointer != NULL && + seat->active_pointer->output == output) { + seat->active_pointer = NULL; + } + output->enter_serial = 0; if (backend->current_pointer == NULL || @@ -87,7 +95,7 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -105,7 +113,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -122,7 +130,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -142,7 +150,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -154,7 +162,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { static void pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -165,7 +173,7 @@ static void pointer_handle_axis_source(void *data, static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -184,7 +192,7 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->backend->current_pointer; + struct wlr_wl_pointer *pointer = seat->active_pointer; if (pointer == NULL) { return; } @@ -485,6 +493,11 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) { pointer->output->backend->current_pointer = NULL; } + struct wlr_wl_seat *seat = pointer->input_device->seat; + if (seat->active_pointer == pointer) { + seat->active_pointer = NULL; + } + wl_list_remove(&pointer->output_destroy.link); free(pointer); } @@ -600,7 +613,7 @@ static void relative_pointer_handle_relative_motion(void *data, wl_fixed_t dy_unaccel) { struct wlr_wl_input_device *input_device = data; struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - if (pointer_get_wl(wlr_dev->pointer) != input_device->backend->current_pointer) { + if (pointer_get_wl(wlr_dev->pointer) != input_device->seat->active_pointer) { return; } @@ -770,6 +783,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wlr_log(WLR_DEBUG, "dropping pointer %s", pointer->input_device->wlr_input_device.name); wlr_input_device_destroy(device); + assert(seat->active_pointer != pointer); assert(backend->current_pointer != pointer); } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 202926254..9f64cdb70 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -116,6 +116,7 @@ struct wlr_wl_seat { struct wl_keyboard *keyboard; struct wlr_wl_backend *backend; + struct wlr_wl_pointer *active_pointer; }; struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); From 2eae9ec7c8b3f972f99cd34ab641bd9bc5e55589 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Fri, 9 Oct 2020 22:17:17 +0200 Subject: [PATCH 102/223] backend/wayland: Set cursor indivdualy per output --- backend/wayland/output.c | 6 ++++-- backend/wayland/seat.c | 23 +++++++++-------------- include/backend/wayland.h | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 3899f7f40..abe8e43ed 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -419,8 +419,10 @@ static void output_destroy(struct wlr_output *wlr_output) { } void update_wl_output_cursor(struct wlr_wl_output *output) { - struct wlr_wl_pointer *pointer = output->backend->current_pointer; - if (pointer && pointer->output == output && output->enter_serial) { + struct wlr_wl_pointer *pointer = output->cursor.pointer; + if (pointer) { + assert(pointer->output == output); + assert(output->enter_serial); wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial, output->cursor.surface, output->cursor.hotspot_x, output->cursor.hotspot_y); diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index cf8412648..4b97bd489 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -43,7 +43,6 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) { struct wlr_wl_seat *seat = data; - struct wlr_wl_backend *backend = seat->backend; if (surface == NULL) { return; } @@ -54,7 +53,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, seat->active_pointer = pointer; // Manage cursor icon/rendering on output - struct wlr_wl_pointer *current_pointer = backend->current_pointer; + struct wlr_wl_pointer *current_pointer = output->cursor.pointer; if (current_pointer && current_pointer != pointer) { wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s", seat->name, current_pointer->input_device->seat->name); @@ -62,14 +61,13 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, } output->enter_serial = serial; - backend->current_pointer = pointer; + output->cursor.pointer = pointer; update_wl_output_cursor(output); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { struct wlr_wl_seat *seat = data; - struct wlr_wl_backend *backend = seat->backend; if (surface == NULL) { return; } @@ -82,14 +80,10 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, seat->active_pointer = NULL; } - output->enter_serial = 0; - - if (backend->current_pointer == NULL || - backend->current_pointer->output != output) { - return; + if (output->cursor.pointer == seat->active_pointer) { + output->enter_serial = 0; + output->cursor.pointer = NULL; } - - backend->current_pointer = NULL; } static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, @@ -489,8 +483,8 @@ struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer) { static void pointer_destroy(struct wlr_pointer *wlr_pointer) { struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_pointer); - if (pointer->output->backend->current_pointer == pointer) { - pointer->output->backend->current_pointer = NULL; + if (pointer->output->cursor.pointer == pointer) { + pointer->output->cursor.pointer = NULL; } struct wlr_wl_seat *seat = pointer->input_device->seat; @@ -782,9 +776,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } wlr_log(WLR_DEBUG, "dropping pointer %s", pointer->input_device->wlr_input_device.name); + struct wlr_wl_output *output = pointer->output; wlr_input_device_destroy(device); assert(seat->active_pointer != pointer); - assert(backend->current_pointer != pointer); + assert(output->cursor.pointer != pointer); } wl_pointer_release(seat->pointer); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9f64cdb70..9596b72ca 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -40,7 +40,6 @@ struct wlr_wl_backend { struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1; struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct wl_list seats; // wlr_wl_seat.link - struct wlr_wl_pointer *current_pointer; struct zwp_tablet_manager_v2 *tablet_manager; struct wlr_drm_format_set linux_dmabuf_v1_formats; }; @@ -75,6 +74,7 @@ struct wlr_wl_output { uint32_t enter_serial; struct { + struct wlr_wl_pointer *pointer; struct wl_surface *surface; struct wl_egl_window *egl_window; int32_t hotspot_x, hotspot_y; From aaa3fcf66fdfd6d23a88a715b33f89c5c89d3edd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 15 Nov 2020 18:57:16 +0100 Subject: [PATCH 103/223] backend/libinput: require libinput 1.14 We have the policy of requiring up-to-date dependencies instead of adding conditionals for older versions. libinput 1.14 was published more than 1 year ago. --- backend/libinput/tablet_tool.c | 2 -- meson.build | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 845ef2209..e07491d1b 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -113,10 +113,8 @@ static enum wlr_tablet_tool_type wlr_type_from_libinput_type( return WLR_TABLET_TOOL_TYPE_MOUSE; case LIBINPUT_TABLET_TOOL_TYPE_LENS: return WLR_TABLET_TOOL_TYPE_LENS; -#if LIBINPUT_MINOR >= 14 case LIBINPUT_TABLET_TOOL_TYPE_TOTEM: return WLR_TABLET_TOOL_TYPE_TOTEM; -#endif } abort(); // unreachable } diff --git a/meson.build b/meson.build index 835e01952..3235dd3fb 100644 --- a/meson.build +++ b/meson.build @@ -104,7 +104,7 @@ egl = dependency('egl') glesv2 = dependency('glesv2') drm = dependency('libdrm', version: '>=2.4.95') gbm = dependency('gbm', version: '>=17.1.0') -libinput = dependency('libinput', version: '>=1.9.0') +libinput = dependency('libinput', version: '>=1.14.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') pixman = dependency('pixman-1') @@ -133,13 +133,6 @@ wlr_deps = [ rt, ] -libinput_ver = libinput.version().split('.') -add_project_arguments([ - '-DLIBINPUT_MAJOR=' + libinput_ver[0], - '-DLIBINPUT_MINOR=' + libinput_ver[1], - '-DLIBINPUT_PATCH=' + libinput_ver[2], -], language: 'c') - subdir('protocol') subdir('render') From f47445f142884dd6b6c3653bfce1a69b5c14b59a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 1 Jun 2020 19:48:39 +0200 Subject: [PATCH 104/223] render: introduce wlr_allocator --- include/render/allocator.h | 42 ++++++++++++++++++++++++++++++++++++++ render/allocator.c | 20 ++++++++++++++++++ render/meson.build | 1 + 3 files changed, 63 insertions(+) create mode 100644 include/render/allocator.h create mode 100644 render/allocator.c diff --git a/include/render/allocator.h b/include/render/allocator.h new file mode 100644 index 000000000..d47184af1 --- /dev/null +++ b/include/render/allocator.h @@ -0,0 +1,42 @@ +#ifndef RENDER_ALLOCATOR +#define RENDER_ALLOCATOR + +#include +#include +#include +#include + +struct wlr_allocator; + +struct wlr_allocator_interface { + struct wlr_buffer *(*create_buffer)(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format); + void (*destroy)(struct wlr_allocator *alloc); +}; + +struct wlr_allocator { + const struct wlr_allocator_interface *impl; + + struct { + struct wl_signal destroy; + } events; +}; + +/** + * Destroy the allocator. + */ +void wlr_allocator_destroy(struct wlr_allocator *alloc); +/** + * Allocate a new buffer. + * + * When the caller is done with it, they must unreference it by calling + * wlr_buffer_drop. + */ +struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format); + +// For wlr_allocator implementors +void wlr_allocator_init(struct wlr_allocator *alloc, + const struct wlr_allocator_interface *impl); + +#endif diff --git a/render/allocator.c b/render/allocator.c new file mode 100644 index 000000000..3638bd62a --- /dev/null +++ b/render/allocator.c @@ -0,0 +1,20 @@ +#include +#include +#include "render/allocator.h" + +void wlr_allocator_init(struct wlr_allocator *alloc, + const struct wlr_allocator_interface *impl) { + assert(impl && impl->destroy && impl->create_buffer); + alloc->impl = impl; + wl_signal_init(&alloc->events.destroy); +} + +void wlr_allocator_destroy(struct wlr_allocator *alloc) { + wl_signal_emit(&alloc->events.destroy, NULL); + alloc->impl->destroy(alloc); +} + +struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc, + int width, int height, const struct wlr_drm_format *format) { + return alloc->impl->create_buffer(alloc, width, height, format); +} diff --git a/render/meson.build b/render/meson.build index 9486c22de..58cc6761e 100644 --- a/render/meson.build +++ b/render/meson.build @@ -1,4 +1,5 @@ wlr_files += files( + 'allocator.c', 'dmabuf.c', 'egl.c', 'drm_format_set.c', From 5913040110bde856fa6dc98d3b844cf7f25f5674 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 1 Jun 2020 19:49:10 +0200 Subject: [PATCH 105/223] render: introduce wlr_gbm_allocator --- include/render/gbm_allocator.h | 29 ++++++ render/gbm_allocator.c | 182 +++++++++++++++++++++++++++++++++ render/meson.build | 1 + 3 files changed, 212 insertions(+) create mode 100644 include/render/gbm_allocator.h create mode 100644 render/gbm_allocator.c diff --git a/include/render/gbm_allocator.h b/include/render/gbm_allocator.h new file mode 100644 index 000000000..f4627b905 --- /dev/null +++ b/include/render/gbm_allocator.h @@ -0,0 +1,29 @@ +#ifndef RENDER_GBM_ALLOCATOR_H +#define RENDER_GBM_ALLOCATOR_H + +#include +#include +#include "render/allocator.h" + +struct wlr_gbm_buffer { + struct wlr_buffer base; + + struct gbm_bo *gbm_bo; + struct wlr_dmabuf_attributes dmabuf; +}; + +struct wlr_gbm_allocator { + struct wlr_allocator base; + + int fd; + struct gbm_device *gbm_device; +}; + +/** + * Creates a new GBM allocator from a render FD. + * + * Takes ownership over the FD. + */ +struct wlr_gbm_allocator *wlr_gbm_allocator_create(int render_fd); + +#endif diff --git a/render/gbm_allocator.c b/render/gbm_allocator.c new file mode 100644 index 000000000..da29501ae --- /dev/null +++ b/render/gbm_allocator.c @@ -0,0 +1,182 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "render/gbm_allocator.h" + +static const struct wlr_buffer_impl buffer_impl; + +static struct wlr_gbm_buffer *get_gbm_buffer_from_buffer( + struct wlr_buffer *buffer) { + assert(buffer->impl == &buffer_impl); + return (struct wlr_gbm_buffer *)buffer; +} + +static struct wlr_gbm_buffer *create_buffer(struct gbm_device *gbm_device, + int width, int height, const struct wlr_drm_format *format) { + struct gbm_bo *bo = NULL; + if (format->len > 0) { + bo = gbm_bo_create_with_modifiers(gbm_device, width, height, + format->format, format->modifiers, format->len); + } + if (bo == NULL) { + uint32_t usage = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; + if (format->len == 1 && + format->modifiers[0] == DRM_FORMAT_MOD_LINEAR) { + usage |= GBM_BO_USE_LINEAR; + } + bo = gbm_bo_create(gbm_device, width, height, format->format, usage); + } + if (bo == NULL) { + wlr_log(WLR_ERROR, "gbm_bo_create failed"); + return NULL; + } + + struct wlr_gbm_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + gbm_bo_destroy(bo); + return NULL; + } + wlr_buffer_init(&buffer->base, &buffer_impl, width, height); + buffer->gbm_bo = bo; + + wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer (format 0x%"PRIX32", " + "modifier 0x%"PRIX64")", buffer->base.width, buffer->base.height, + gbm_bo_get_format(bo), gbm_bo_get_modifier(bo)); + + return buffer; +} + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_gbm_buffer *buffer = + get_gbm_buffer_from_buffer(wlr_buffer); + wlr_dmabuf_attributes_finish(&buffer->dmabuf); + gbm_bo_destroy(buffer->gbm_bo); + free(buffer); +} + +static bool buffer_create_dmabuf(struct wlr_gbm_buffer *buffer) { + assert(buffer->dmabuf.n_planes == 0); + + struct gbm_bo *bo = buffer->gbm_bo; + struct wlr_dmabuf_attributes attribs = {0}; + + attribs.n_planes = gbm_bo_get_plane_count(bo); + if (attribs.n_planes > WLR_DMABUF_MAX_PLANES) { + wlr_log(WLR_ERROR, "GBM BO contains too many planes (%d)", + attribs.n_planes); + return false; + } + + attribs.width = gbm_bo_get_width(bo); + attribs.height = gbm_bo_get_height(bo); + attribs.format = gbm_bo_get_format(bo); + attribs.modifier = gbm_bo_get_modifier(bo); + + int i; + for (i = 0; i < attribs.n_planes; ++i) { + union gbm_bo_handle handle = gbm_bo_get_handle_for_plane(bo, i); + if (handle.s32 < 0) { + wlr_log(WLR_ERROR, "gbm_bo_get_handle_for_plane failed"); + goto error_fd; + } + + int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo)); + int ret = drmPrimeHandleToFD(drm_fd, handle.s32, + DRM_CLOEXEC, &attribs.fd[i]); + if (ret < 0 || attribs.fd[i] < 0) { + wlr_log_errno(WLR_ERROR, "drmPrimeHandleToFD failed"); + goto error_fd; + } + + attribs.offset[i] = gbm_bo_get_offset(bo, i); + attribs.stride[i] = gbm_bo_get_stride_for_plane(bo, i); + } + + memcpy(&buffer->dmabuf, &attribs, sizeof(attribs)); + return true; + +error_fd: + for (int j = 0; j < i; ++j) { + close(attribs.fd[j]); + } + return false; +} + +static bool buffer_get_dmabuf(struct wlr_buffer *wlr_buffer, + struct wlr_dmabuf_attributes *attribs) { + struct wlr_gbm_buffer *buffer = + get_gbm_buffer_from_buffer(wlr_buffer); + + memset(attribs, 0, sizeof(*attribs)); + + // Only export the buffer once + if (buffer->dmabuf.n_planes == 0) { + if (!buffer_create_dmabuf(buffer)) { + return false; + } + } + + memcpy(attribs, &buffer->dmabuf, sizeof(buffer->dmabuf)); + return true; +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .get_dmabuf = buffer_get_dmabuf, +}; + +static const struct wlr_allocator_interface allocator_impl; + +static struct wlr_gbm_allocator *get_gbm_alloc_from_alloc( + struct wlr_allocator *alloc) { + assert(alloc->impl == &allocator_impl); + return (struct wlr_gbm_allocator *)alloc; +} + +struct wlr_gbm_allocator *wlr_gbm_allocator_create(int fd) { + struct wlr_gbm_allocator *alloc = calloc(1, sizeof(*alloc)); + if (alloc == NULL) { + return NULL; + } + wlr_allocator_init(&alloc->base, &allocator_impl); + + alloc->fd = fd; + + alloc->gbm_device = gbm_create_device(fd); + if (alloc->gbm_device == NULL) { + wlr_log(WLR_ERROR, "gbm_create_device failed"); + free(alloc); + return NULL; + } + + return alloc; +} + +static void allocator_destroy(struct wlr_allocator *wlr_alloc) { + struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); + gbm_device_destroy(alloc->gbm_device); + close(alloc->fd); + free(alloc); +} + +static struct wlr_buffer *allocator_create_buffer( + struct wlr_allocator *wlr_alloc, int width, int height, + const struct wlr_drm_format *format) { + struct wlr_gbm_allocator *alloc = get_gbm_alloc_from_alloc(wlr_alloc); + struct wlr_gbm_buffer *buffer = + create_buffer(alloc->gbm_device, width, height, format); + if (buffer == NULL) { + return NULL; + } + return &buffer->base; +} + +static const struct wlr_allocator_interface allocator_impl = { + .destroy = allocator_destroy, + .create_buffer = allocator_create_buffer, +}; diff --git a/render/meson.build b/render/meson.build index 58cc6761e..f68322fea 100644 --- a/render/meson.build +++ b/render/meson.build @@ -3,6 +3,7 @@ wlr_files += files( 'dmabuf.c', 'egl.c', 'drm_format_set.c', + 'gbm_allocator.c', 'gles2/pixel_format.c', 'gles2/renderer.c', 'gles2/shaders.c', From 7c6212a0f71eeab23a4ff4241cb266ec219fad2d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 7 Aug 2020 19:02:49 +0200 Subject: [PATCH 106/223] render/drm_format_set: introduce wlr_drm_format_dup --- include/render/drm_format_set.h | 8 ++++++++ render/drm_format_set.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 include/render/drm_format_set.h diff --git a/include/render/drm_format_set.h b/include/render/drm_format_set.h new file mode 100644 index 000000000..ae1fcc472 --- /dev/null +++ b/include/render/drm_format_set.h @@ -0,0 +1,8 @@ +#ifndef RENDER_DRM_FORMAT_SET_H +#define RENDER_DRM_FORMAT_SET_H + +#include + +struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format); + +#endif diff --git a/render/drm_format_set.c b/render/drm_format_set.c index cbcc0875f..54fc8ae10 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -6,6 +6,7 @@ #include #include #include +#include "render/drm_format_set.h" void wlr_drm_format_set_finish(struct wlr_drm_format_set *set) { for (size_t i = 0; i < set->len; ++i) { @@ -125,3 +126,14 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, set->formats[set->len++] = fmt; return true; } + +struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { + size_t format_size = sizeof(struct wlr_drm_format) + + format->len * sizeof(format->modifiers[0]); + struct wlr_drm_format *duped_format = malloc(format_size); + if (duped_format == NULL) { + return NULL; + } + memcpy(duped_format, format, format_size); + return duped_format; +} From b0a663d39d2de1dcfd9a0381cc822c4713da508e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 1 Jun 2020 19:49:32 +0200 Subject: [PATCH 107/223] render: introduce wlr_swapchain The swapchain maximum capacity is set to 4, so that we have enough room for: - A buffer currently displayed on screen - A buffer queued for display (e.g. to KMS) - A pending buffer that'll be queued next commit - An additional pending buffer in case we want to invalidate the currently pending one --- include/render/swapchain.h | 41 ++++++++++++++ render/meson.build | 1 + render/swapchain.c | 108 +++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 include/render/swapchain.h create mode 100644 render/swapchain.c diff --git a/include/render/swapchain.h b/include/render/swapchain.h new file mode 100644 index 000000000..57a0cd3f0 --- /dev/null +++ b/include/render/swapchain.h @@ -0,0 +1,41 @@ +#ifndef RENDER_SWAPCHAIN_H +#define RENDER_SWAPCHAIN_H + +#include +#include +#include + +#define WLR_SWAPCHAIN_CAP 4 + +struct wlr_swapchain_slot { + struct wlr_buffer *buffer; + bool acquired; // waiting for release + + struct wl_listener release; +}; + +struct wlr_swapchain { + struct wlr_allocator *allocator; // NULL if destroyed + + int width, height; + struct wlr_drm_format *format; + + struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP]; + + struct wl_listener allocator_destroy; +}; + +struct wlr_swapchain *wlr_swapchain_create( + struct wlr_allocator *alloc, int width, int height, + const struct wlr_drm_format *format); +void wlr_swapchain_destroy(struct wlr_swapchain *swapchain); +/** + * Acquire a buffer from the swap chain. + * + * The returned buffer is locked. When the caller is done with it, they must + * unlock it by calling wlr_buffer_unlock. + */ +struct wlr_buffer *wlr_swapchain_acquire( + struct wlr_swapchain *swapchain); + +#endif diff --git a/render/meson.build b/render/meson.build index f68322fea..f8609ef83 100644 --- a/render/meson.build +++ b/render/meson.build @@ -8,6 +8,7 @@ wlr_files += files( 'gles2/renderer.c', 'gles2/shaders.c', 'gles2/texture.c', + 'swapchain.c', 'wlr_renderer.c', 'wlr_texture.c', ) diff --git a/render/swapchain.c b/render/swapchain.c new file mode 100644 index 000000000..4145efd2a --- /dev/null +++ b/render/swapchain.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "render/allocator.h" +#include "render/drm_format_set.h" +#include "render/swapchain.h" + +static void swapchain_handle_allocator_destroy(struct wl_listener *listener, + void *data) { + struct wlr_swapchain *swapchain = + wl_container_of(listener, swapchain, allocator_destroy); + swapchain->allocator = NULL; +} + +struct wlr_swapchain *wlr_swapchain_create( + struct wlr_allocator *alloc, int width, int height, + const struct wlr_drm_format *format) { + struct wlr_swapchain *swapchain = calloc(1, sizeof(*swapchain)); + if (swapchain == NULL) { + return NULL; + } + swapchain->allocator = alloc; + swapchain->width = width; + swapchain->height = height; + + swapchain->format = wlr_drm_format_dup(format); + if (swapchain->format == NULL) { + free(swapchain); + return NULL; + } + + swapchain->allocator_destroy.notify = swapchain_handle_allocator_destroy; + wl_signal_add(&alloc->events.destroy, &swapchain->allocator_destroy); + + return swapchain; +} + +static void slot_reset(struct wlr_swapchain_slot *slot) { + if (slot->acquired) { + wl_list_remove(&slot->release.link); + } + wlr_buffer_drop(slot->buffer); + memset(slot, 0, sizeof(*slot)); +} + +void wlr_swapchain_destroy(struct wlr_swapchain *swapchain) { + if (swapchain == NULL) { + return; + } + for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) { + slot_reset(&swapchain->slots[i]); + } + wl_list_remove(&swapchain->allocator_destroy.link); + free(swapchain->format); + free(swapchain); +} + +static void slot_handle_release(struct wl_listener *listener, void *data) { + struct wlr_swapchain_slot *slot = + wl_container_of(listener, slot, release); + wl_list_remove(&slot->release.link); + slot->acquired = false; +} + +static struct wlr_buffer *slot_acquire(struct wlr_swapchain_slot *slot) { + assert(!slot->acquired); + assert(slot->buffer != NULL); + + slot->acquired = true; + + slot->release.notify = slot_handle_release; + wl_signal_add(&slot->buffer->events.release, &slot->release); + + return wlr_buffer_lock(slot->buffer); +} + +struct wlr_buffer *wlr_swapchain_acquire( + struct wlr_swapchain *swapchain) { + struct wlr_swapchain_slot *free_slot = NULL; + for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) { + struct wlr_swapchain_slot *slot = &swapchain->slots[i]; + if (slot->acquired) { + continue; + } + if (slot->buffer != NULL) { + return slot_acquire(slot); + } + free_slot = slot; + } + if (free_slot == NULL) { + wlr_log(WLR_ERROR, "No free output buffer slot"); + return NULL; + } + + if (swapchain->allocator == NULL) { + return NULL; + } + + wlr_log(WLR_DEBUG, "Allocating new swapchain buffer"); + free_slot->buffer = wlr_allocator_create_buffer(swapchain->allocator, + swapchain->width, swapchain->height, swapchain->format); + if (free_slot->buffer == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate buffer"); + return NULL; + } + return slot_acquire(free_slot); +} From 0b40d09a21eb79896a7e60509a7ff8c69b25b37c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 10:46:46 +0200 Subject: [PATCH 108/223] buffer: add wlr_client_buffer_get --- include/wlr/types/wlr_buffer.h | 5 +++++ types/wlr_buffer.c | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index 14bb2a8da..845558999 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -103,6 +103,11 @@ struct wlr_client_buffer { struct wlr_renderer; +/** + * Get a client buffer from a generic buffer. If the buffer isn't a client + * buffer, returns NULL. + */ +struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer); /** * Check if a resource is a wl_buffer resource. */ diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index 2f914c127..29b264120 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -96,10 +96,18 @@ bool wlr_resource_get_buffer_size(struct wl_resource *resource, static const struct wlr_buffer_impl client_buffer_impl; +struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer) { + if (buffer->impl != &client_buffer_impl) { + return NULL; + } + return (struct wlr_client_buffer *)buffer; +} + static struct wlr_client_buffer *client_buffer_from_buffer( struct wlr_buffer *buffer) { - assert(buffer->impl == &client_buffer_impl); - return (struct wlr_client_buffer *) buffer; + struct wlr_client_buffer *client_buffer = wlr_client_buffer_get(buffer); + assert(client_buffer != NULL); + return client_buffer; } static void client_buffer_destroy(struct wlr_buffer *_buffer) { From c88c54fb385a9fe29f79db2ece3e8ebba0edd0a3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 16:56:18 +0200 Subject: [PATCH 109/223] render: introduce wlr_renderer_bind_buffer --- include/render/wlr_renderer.h | 8 ++++++++ include/wlr/render/interface.h | 2 ++ include/wlr/render/wlr_renderer.h | 1 + render/wlr_renderer.c | 10 ++++++++++ 4 files changed, 21 insertions(+) create mode 100644 include/render/wlr_renderer.h diff --git a/include/render/wlr_renderer.h b/include/render/wlr_renderer.h new file mode 100644 index 000000000..0ef1ef82f --- /dev/null +++ b/include/render/wlr_renderer.h @@ -0,0 +1,8 @@ +#ifndef RENDER_WLR_RENDERER_H +#define RENDER_WLR_RENDERER_H + +#include + +bool wlr_renderer_bind_buffer(struct wlr_renderer *r, struct wlr_buffer *buffer); + +#endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 998b1cfa7..1b57c6603 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -30,6 +30,8 @@ #include struct wlr_renderer_impl { + bool (*bind_buffer)(struct wlr_renderer *renderer, + struct wlr_buffer *buffer); void (*begin)(struct wlr_renderer *renderer, uint32_t width, uint32_t height); void (*end)(struct wlr_renderer *renderer); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 363a12e45..8908d3ce4 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -21,6 +21,7 @@ enum wlr_renderer_read_pixels_flags { struct wlr_renderer_impl; struct wlr_drm_format_set; +struct wlr_buffer; struct wlr_renderer { const struct wlr_renderer_impl *impl; diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index bdcc836f1..311747f10 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -7,6 +7,7 @@ #include #include #include "util/signal.h" +#include "render/wlr_renderer.h" void wlr_renderer_init(struct wlr_renderer *renderer, const struct wlr_renderer_impl *impl) { @@ -37,6 +38,15 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { } } +bool wlr_renderer_bind_buffer(struct wlr_renderer *r, + struct wlr_buffer *buffer) { + assert(!r->rendering); + if (!r->impl->bind_buffer) { + return false; + } + return r->impl->bind_buffer(r, buffer); +} + void wlr_renderer_begin(struct wlr_renderer *r, uint32_t width, uint32_t height) { assert(!r->rendering); From 6136fe87d186dc66503d7acb36b5c7c81e808788 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 16:56:23 +0200 Subject: [PATCH 110/223] render/gles2: implement wlr_renderer_bind_buffer --- include/render/gles2.h | 15 +++++ render/gles2/renderer.c | 141 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/include/render/gles2.h b/include/render/gles2.h index a64aa77ce..2eff0aa52 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -72,9 +72,24 @@ struct wlr_gles2_renderer { struct wlr_gles2_tex_shader tex_ext; } shaders; + struct wl_list buffers; // wlr_gles2_buffer.link + + struct wlr_gles2_buffer *current_buffer; uint32_t viewport_width, viewport_height; }; +struct wlr_gles2_buffer { + struct wlr_buffer *buffer; + struct wlr_gles2_renderer *renderer; + struct wl_list link; // wlr_gles2_renderer.buffers + + EGLImageKHR image; + GLuint rbo; + GLuint fbo; + + struct wl_listener buffer_destroy; +}; + struct wlr_gles2_texture { struct wlr_texture wlr_texture; struct wlr_gles2_renderer *renderer; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 9ec87293f..2ff29c114 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -36,6 +36,139 @@ static struct wlr_gles2_renderer *gles2_get_renderer_in_context( return renderer; } +static void destroy_buffer(struct wlr_gles2_buffer *buffer) { + wl_list_remove(&buffer->link); + wl_list_remove(&buffer->buffer_destroy.link); + + wlr_egl_make_current(buffer->renderer->egl, EGL_NO_SURFACE, NULL); + + push_gles2_debug(buffer->renderer); + + glDeleteFramebuffers(1, &buffer->fbo); + glDeleteRenderbuffers(1, &buffer->rbo); + + pop_gles2_debug(buffer->renderer); + + wlr_egl_destroy_image(buffer->renderer->egl, buffer->image); + wlr_egl_unset_current(buffer->renderer->egl); + free(buffer); +} + +static struct wlr_gles2_buffer *get_buffer(struct wlr_gles2_renderer *renderer, + struct wlr_buffer *wlr_buffer) { + struct wlr_gles2_buffer *buffer; + wl_list_for_each(buffer, &renderer->buffers, link) { + if (buffer->buffer == wlr_buffer) { + return buffer; + } + } + return NULL; +} + +static void handle_buffer_destroy(struct wl_listener *listener, void *data) { + struct wlr_gles2_buffer *buffer = + wl_container_of(listener, buffer, buffer_destroy); + destroy_buffer(buffer); +} + +static struct wlr_gles2_buffer *create_buffer(struct wlr_gles2_renderer *renderer, + struct wlr_buffer *wlr_buffer) { + struct wlr_gles2_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + buffer->buffer = wlr_buffer; + buffer->renderer = renderer; + + struct wlr_dmabuf_attributes dmabuf = {0}; + if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) { + goto error_buffer; + } + + bool external_only; + buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl, + &dmabuf, &external_only); + if (buffer->image == EGL_NO_IMAGE_KHR) { + goto error_buffer; + } + + push_gles2_debug(renderer); + + glGenRenderbuffers(1, &buffer->rbo); + glBindRenderbuffer(GL_RENDERBUFFER, buffer->rbo); + renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + buffer->image); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glGenFramebuffers(1, &buffer->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, buffer->rbo); + GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + pop_gles2_debug(renderer); + + if (fb_status != GL_FRAMEBUFFER_COMPLETE) { + wlr_log(WLR_ERROR, "Failed to create FBO"); + goto error_image; + } + + buffer->buffer_destroy.notify = handle_buffer_destroy; + wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy); + + wl_list_insert(&renderer->buffers, &buffer->link); + + wlr_log(WLR_DEBUG, "Created GL FBO for buffer %dx%d", + wlr_buffer->width, wlr_buffer->height); + + return buffer; + +error_image: + wlr_egl_destroy_image(renderer->egl, buffer->image); +error_buffer: + free(buffer); + return NULL; +} + +static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer, + struct wlr_buffer *wlr_buffer) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + + if (renderer->current_buffer != NULL) { + push_gles2_debug(renderer); + glFlush(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + pop_gles2_debug(renderer); + + wlr_buffer_unlock(renderer->current_buffer->buffer); + renderer->current_buffer = NULL; + } + + if (wlr_buffer == NULL) { + return true; + } + + struct wlr_gles2_buffer *buffer = get_buffer(renderer, wlr_buffer); + if (buffer == NULL) { + buffer = create_buffer(renderer, wlr_buffer); + } + if (buffer == NULL) { + return false; + } + + wlr_buffer_lock(wlr_buffer); + renderer->current_buffer = buffer; + + push_gles2_debug(renderer); + glBindFramebuffer(GL_FRAMEBUFFER, renderer->current_buffer->fbo); + pop_gles2_debug(renderer); + + return true; +} + static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, uint32_t height) { struct wlr_gles2_renderer *renderer = @@ -477,6 +610,11 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + struct wlr_gles2_buffer *buffer, *buffer_tmp; + wl_list_for_each_safe(buffer, buffer_tmp, &renderer->buffers, link) { + destroy_buffer(buffer); + } + push_gles2_debug(renderer); glDeleteProgram(renderer->shaders.quad.program); glDeleteProgram(renderer->shaders.ellipse.program); @@ -497,6 +635,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { static const struct wlr_renderer_impl renderer_impl = { .destroy = gles2_destroy, + .bind_buffer = gles2_bind_buffer, .begin = gles2_begin, .end = gles2_end, .clear = gles2_clear, @@ -668,6 +807,8 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { } wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl); + wl_list_init(&renderer->buffers); + renderer->egl = egl; renderer->exts_str = exts_str; From 1245730ea238942694db3e54d0eaaf8c6bd05818 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 11 Jun 2020 18:40:29 +0200 Subject: [PATCH 111/223] render/gles2: fix y-inverted output when rendering to buffer --- render/gles2/renderer.c | 81 ++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 2ff29c114..faef832f0 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -214,8 +214,12 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, push_gles2_debug(renderer); if (box != NULL) { struct wlr_box gl_box; - wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180, - renderer->viewport_width, renderer->viewport_height); + if (renderer->current_buffer != NULL) { + memcpy(&gl_box, box, sizeof(gl_box)); + } else { + wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180, + renderer->viewport_width, renderer->viewport_height); + } glScissor(gl_box.x, gl_box.y, gl_box.width, gl_box.height); glEnable(GL_SCISSOR_TEST); @@ -225,6 +229,12 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, pop_gles2_debug(renderer); } +static const float flip_180[9] = { + 1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, +}; + static bool gles2_render_subtexture_with_matrix( struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, const struct wlr_fbox *box, const float matrix[static 9], @@ -257,10 +267,15 @@ static bool gles2_render_subtexture_with_matrix( abort(); } + float gl_matrix[9]; + if (renderer->current_buffer != NULL) { + wlr_matrix_multiply(gl_matrix, flip_180, matrix); + } else { + memcpy(gl_matrix, matrix, sizeof(gl_matrix)); + } // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE - float transposition[9]; - wlr_matrix_transpose(transposition, matrix); + wlr_matrix_transpose(gl_matrix, gl_matrix); push_gles2_debug(renderer); @@ -271,7 +286,7 @@ static bool gles2_render_subtexture_with_matrix( glUseProgram(shader->program); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, transposition); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix); glUniform1i(shader->invert_y, texture->inverted_y); glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, alpha); @@ -309,15 +324,20 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); + float gl_matrix[9]; + if (renderer->current_buffer != NULL) { + wlr_matrix_multiply(gl_matrix, flip_180, matrix); + } else { + memcpy(gl_matrix, matrix, sizeof(gl_matrix)); + } // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE - float transposition[9]; - wlr_matrix_transpose(transposition, matrix); + wlr_matrix_transpose(gl_matrix, gl_matrix); push_gles2_debug(renderer); glUseProgram(renderer->shaders.quad.program); - glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition); + glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, gl_matrix); glUniform4f(renderer->shaders.quad.color, color[0], color[1], color[2], color[3]); glVertexAttribPointer(renderer->shaders.quad.pos_attrib, 2, GL_FLOAT, GL_FALSE, @@ -337,10 +357,15 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, struct wlr_gles2_renderer *renderer = gles2_get_renderer_in_context(wlr_renderer); + float gl_matrix[9]; + if (renderer->current_buffer != NULL) { + wlr_matrix_multiply(gl_matrix, flip_180, matrix); + } else { + memcpy(gl_matrix, matrix, sizeof(gl_matrix)); + } // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE - float transposition[9]; - wlr_matrix_transpose(transposition, matrix); + wlr_matrix_transpose(gl_matrix, gl_matrix); static const GLfloat texcoord[] = { 1, 0, // top right @@ -352,7 +377,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, push_gles2_debug(renderer); glUseProgram(renderer->shaders.ellipse.program); - glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition); + glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, gl_matrix); glUniform4f(renderer->shaders.ellipse.color, color[0], color[1], color[2], color[3]); glVertexAttribPointer(renderer->shaders.ellipse.pos_attrib, 2, GL_FLOAT, @@ -472,16 +497,32 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, if (pack_stride == stride && dst_x == 0 && flags != NULL) { // Under these particular conditions, we can read the pixels with only // one glReadPixels call - glReadPixels(src_x, renderer->viewport_height - height - src_y, - width, height, fmt->gl_format, fmt->gl_type, p); - *flags = WLR_RENDERER_READ_PIXELS_Y_INVERT; + + uint32_t y = src_y; + if (renderer->current_buffer == NULL) { + y = renderer->viewport_height - height - src_y; + } + + glReadPixels(src_x, y, width, height, fmt->gl_format, fmt->gl_type, p); + + if (renderer->current_buffer != NULL) { + *flags = 0; + } else { + *flags = WLR_RENDERER_READ_PIXELS_Y_INVERT; + } } else { // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read // the lines out row by row for (size_t i = 0; i < height; ++i) { - glReadPixels(src_x, renderer->viewport_height - src_y - i - 1, width, 1, fmt->gl_format, + uint32_t y = src_y + i; + if (renderer->current_buffer == NULL) { + y = renderer->viewport_height - src_y - i - 1; + } + + glReadPixels(src_x, y, width, 1, fmt->gl_format, fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8); } + if (flags != NULL) { *flags = 0; } @@ -510,6 +551,7 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, goto restore_context_out; } + // TODO: get inverted_y right when current_buffer != NULL // This is to take into account y-inversion on both buffers rather than // just the source buffer. bool src_inverted_y = @@ -517,9 +559,12 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer, bool dst_inverted_y = !!(dst_attr->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT); struct wlr_gles2_texture *gles2_src_tex = gles2_get_texture(src_tex); - // The result is negated because wlr_matrix_projection y-inverts the - // texture. - gles2_src_tex->inverted_y = !(src_inverted_y ^ dst_inverted_y); + gles2_src_tex->inverted_y = src_inverted_y ^ dst_inverted_y; + if (renderer->current_buffer == NULL) { + // The result is negated because wlr_matrix_projection y-inverts the + // texture. + gles2_src_tex->inverted_y = !gles2_src_tex->inverted_y; + } if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) { goto texture_destroy_out; From ef846a883950e59f95507daa6d3f96f0e84da3af Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 1 Jun 2020 19:49:51 +0200 Subject: [PATCH 112/223] backend/drm: use wlr_swapchain --- backend/drm/drm.c | 6 +- backend/drm/renderer.c | 138 ++++++++++++++++++++------------- include/backend/drm/renderer.h | 11 ++- 3 files changed, 93 insertions(+), 62 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 40b73925a..ecd98fdab 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -593,8 +593,8 @@ static bool drm_connector_commit(struct wlr_output *output) { } static void drm_connector_rollback_render(struct wlr_output *output) { - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); - wlr_egl_unset_current(&drm->renderer.egl); + struct wlr_drm_connector *conn = get_drm_connector_from_output(output); + return drm_surface_unset_current(&conn->crtc->primary->surf); } size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, @@ -883,7 +883,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, return false; } - if (!plane->surf.gbm) { + if (!plane->surf.swapchain) { int ret; uint64_t w, h; ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &w); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 4b6e9bf18..b78cf7e28 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -12,9 +12,13 @@ #include #include #include "backend/drm/drm.h" +#include "render/gbm_allocator.h" +#include "render/swapchain.h" +#include "render/wlr_renderer.h" bool init_drm_renderer(struct wlr_drm_backend *drm, struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_renderer_func) { + // TODO: get rid of renderer->gbm renderer->gbm = gbm_create_device(drm->fd); if (!renderer->gbm) { wlr_log(WLR_ERROR, "Failed to create GBM device"); @@ -44,9 +48,17 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, goto error_gbm; } + renderer->allocator = wlr_gbm_allocator_create(drm->fd); + if (renderer->allocator == NULL) { + wlr_log(WLR_ERROR, "Failed to create allocator"); + goto error_wlr_rend; + } + renderer->fd = drm->fd; return true; +error_wlr_rend: + wlr_renderer_destroy(renderer->wlr_rend); error_gbm: gbm_device_destroy(renderer->gbm); return false; @@ -57,6 +69,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) { return; } + wlr_allocator_destroy(&renderer->allocator->base); wlr_renderer_destroy(renderer->wlr_rend); wlr_egl_finish(&renderer->egl); gbm_device_destroy(renderer->gbm); @@ -64,7 +77,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) { static bool init_drm_surface(struct wlr_drm_surface *surf, struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, - uint32_t format, struct wlr_drm_format_set *set, uint32_t flags) { + uint32_t format, const struct wlr_drm_format_set *set, uint32_t flags) { if (surf->width == width && surf->height == height) { return true; } @@ -73,43 +86,41 @@ static bool init_drm_surface(struct wlr_drm_surface *surf, surf->width = width; surf->height = height; - if (surf->gbm) { - gbm_surface_destroy(surf->gbm); - surf->gbm = NULL; - } - wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl); + wlr_buffer_unlock(surf->back_buffer); + surf->back_buffer = NULL; + wlr_swapchain_destroy(surf->swapchain); + surf->swapchain = NULL; - if (!(flags & GBM_BO_USE_LINEAR) && set != NULL) { - const struct wlr_drm_format *drm_format = - wlr_drm_format_set_get(set, format); - if (drm_format != NULL) { - surf->gbm = gbm_surface_create_with_modifiers(renderer->gbm, - width, height, format, drm_format->modifiers, drm_format->len); + const struct wlr_drm_format *drm_format = NULL; + const struct wlr_drm_format format_no_modifiers = { .format = format }; + if (set != NULL) { + drm_format = wlr_drm_format_set_get(set, format); + } else { + drm_format = &format_no_modifiers; + } + + struct wlr_drm_format *format_linear = NULL; + if (flags & GBM_BO_USE_LINEAR) { + format_linear = calloc(1, sizeof(struct wlr_drm_format) + sizeof(uint64_t)); + if (format_linear == NULL) { + return false; } + format_linear->format = format; + format_linear->len = 1; + format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; + drm_format = format_linear; } - if (surf->gbm == NULL) { - surf->gbm = gbm_surface_create(renderer->gbm, width, height, - format, GBM_BO_USE_RENDERING | flags); - } - if (!surf->gbm) { - wlr_log_errno(WLR_ERROR, "Failed to create GBM surface"); - goto error_zero; - } - - surf->egl = wlr_egl_create_surface(&renderer->egl, surf->gbm); - if (surf->egl == EGL_NO_SURFACE) { - wlr_log(WLR_ERROR, "Failed to create EGL surface"); - goto error_gbm; + surf->swapchain = wlr_swapchain_create(&renderer->allocator->base, + width, height, drm_format); + free(format_linear); + if (surf->swapchain == NULL) { + wlr_log(WLR_ERROR, "Failed to create swapchain"); + memset(surf, 0, sizeof(*surf)); + return false; } return true; - -error_gbm: - gbm_surface_destroy(surf->gbm); -error_zero: - memset(surf, 0, sizeof(*surf)); - return false; } static void finish_drm_surface(struct wlr_drm_surface *surf) { @@ -117,17 +128,44 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) { return; } - wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl); - if (surf->gbm) { - gbm_surface_destroy(surf->gbm); - } + wlr_buffer_unlock(surf->back_buffer); + wlr_swapchain_destroy(surf->swapchain); memset(surf, 0, sizeof(*surf)); } bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age) { - return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_age); + wlr_buffer_unlock(surf->back_buffer); + surf->back_buffer = wlr_swapchain_acquire(surf->swapchain); + if (surf->back_buffer == NULL) { + wlr_log(WLR_ERROR, "Failed to acquire swapchain buffer"); + return false; + } + + if (!wlr_egl_make_current(&surf->renderer->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + if (!wlr_renderer_bind_buffer(surf->renderer->wlr_rend, surf->back_buffer)) { + wlr_log(WLR_ERROR, "Failed to attach buffer to renderer"); + return false; + } + + // TODO: damage tracking + if (buffer_age != NULL) { + *buffer_age = -1; + } + return true; +} + +void drm_surface_unset_current(struct wlr_drm_surface *surf) { + assert(surf->back_buffer != NULL); + + wlr_renderer_bind_buffer(surf->renderer->wlr_rend, NULL); + wlr_egl_unset_current(&surf->renderer->egl); + + wlr_buffer_unlock(surf->back_buffer); + surf->back_buffer = NULL; } bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) { @@ -251,7 +289,7 @@ void drm_fb_clear(struct wlr_drm_fb *fb) { assert(!fb->bo); break; case WLR_DRM_FB_TYPE_SURFACE: - gbm_surface_release_buffer(fb->surf->gbm, fb->bo); + abort(); // TODO: remove this case entirely break; case WLR_DRM_FB_TYPE_WLR_BUFFER: gbm_bo_destroy(fb->bo); @@ -264,29 +302,22 @@ void drm_fb_clear(struct wlr_drm_fb *fb) { fb->bo = NULL; if (fb->mgpu_bo) { - assert(fb->mgpu_surf); + // TODO + /*assert(fb->mgpu_surf); gbm_surface_release_buffer(fb->mgpu_surf->gbm, fb->mgpu_bo); fb->mgpu_bo = NULL; - fb->mgpu_surf = NULL; + fb->mgpu_surf = NULL;*/ } } bool drm_fb_lock_surface(struct wlr_drm_fb *fb, struct wlr_drm_surface *surf) { - drm_fb_clear(fb); + assert(surf->back_buffer != NULL); - if (!wlr_egl_swap_buffers(&surf->renderer->egl, surf->egl, NULL)) { - wlr_log(WLR_ERROR, "Failed to swap buffers"); + if (!drm_fb_import_wlr(fb, surf->renderer, surf->back_buffer, NULL)) { return false; } - fb->bo = gbm_surface_lock_front_buffer(surf->gbm); - if (!fb->bo) { - wlr_log(WLR_ERROR, "Failed to lock front buffer"); - return false; - } - - fb->type = WLR_DRM_FB_TYPE_SURFACE; - fb->surf = surf; + drm_surface_unset_current(surf); return true; } @@ -299,7 +330,7 @@ bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer, return false; } - if (!wlr_drm_format_set_has(set, attribs.format, attribs.modifier)) { + if (set && !wlr_drm_format_set_has(set, attribs.format, attribs.modifier)) { // The format isn't supported by the plane. Try stripping the alpha // channel, if any. uint32_t format = strip_alpha_channel(attribs.format); @@ -410,7 +441,8 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); wlr_renderer_end(renderer); - if (!wlr_egl_swap_buffers(&mgpu->renderer->egl, mgpu->egl, NULL)) { + // TODO + /*if (!wlr_egl_swap_buffers(&mgpu->renderer->egl, mgpu->egl, NULL)) { wlr_log(WLR_ERROR, "Failed to swap buffers"); return NULL; } @@ -421,6 +453,6 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm return NULL; } - fb->mgpu_surf = mgpu; + fb->mgpu_surf = mgpu;*/ return fb->mgpu_bo; } diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index bfccf9d5c..8cc4b0de1 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -20,6 +20,7 @@ struct wlr_drm_renderer { uint32_t gbm_format; struct wlr_renderer *wlr_rend; + struct wlr_gbm_allocator *allocator; }; struct wlr_drm_surface { @@ -28,8 +29,8 @@ struct wlr_drm_surface { uint32_t width; uint32_t height; - struct gbm_surface *gbm; - EGLSurface egl; + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer; }; enum wlr_drm_fb_type { @@ -45,10 +46,7 @@ struct wlr_drm_fb { struct wlr_drm_surface *mgpu_surf; struct gbm_bo *mgpu_bo; - union { - struct wlr_drm_surface *surf; - struct wlr_buffer *wlr_buf; - }; + struct wlr_buffer *wlr_buf; }; bool init_drm_renderer(struct wlr_drm_backend *drm, @@ -56,6 +54,7 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, void finish_drm_renderer(struct wlr_drm_renderer *renderer); bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age); +void drm_surface_unset_current(struct wlr_drm_surface *surf); bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs); void drm_fb_clear(struct wlr_drm_fb *fb); From c11c6c45685c96e1b525b2f944bc278be20c119e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 27 Jul 2020 18:36:31 +0200 Subject: [PATCH 113/223] render/swapchain: add support for buffer age --- include/render/swapchain.h | 13 +++++++++-- render/swapchain.c | 46 +++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/include/render/swapchain.h b/include/render/swapchain.h index 57a0cd3f0..243f0404c 100644 --- a/include/render/swapchain.h +++ b/include/render/swapchain.h @@ -10,6 +10,7 @@ struct wlr_swapchain_slot { struct wlr_buffer *buffer; bool acquired; // waiting for release + int age; struct wl_listener release; }; @@ -35,7 +36,15 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain); * The returned buffer is locked. When the caller is done with it, they must * unlock it by calling wlr_buffer_unlock. */ -struct wlr_buffer *wlr_swapchain_acquire( - struct wlr_swapchain *swapchain); +struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain, + int *age); +/** + * Mark the buffer as submitted for presentation. This needs to be called by + * swap chain users on frame boundaries. + * + * If the buffer hasn't been created via the swap chain, the call is ignored. + */ +void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain, + struct wlr_buffer *buffer); #endif diff --git a/render/swapchain.c b/render/swapchain.c index 4145efd2a..fd9f87253 100644 --- a/render/swapchain.c +++ b/render/swapchain.c @@ -63,7 +63,8 @@ static void slot_handle_release(struct wl_listener *listener, void *data) { slot->acquired = false; } -static struct wlr_buffer *slot_acquire(struct wlr_swapchain_slot *slot) { +static struct wlr_buffer *slot_acquire(struct wlr_swapchain *swapchain, + struct wlr_swapchain_slot *slot, int *age) { assert(!slot->acquired); assert(slot->buffer != NULL); @@ -72,11 +73,15 @@ static struct wlr_buffer *slot_acquire(struct wlr_swapchain_slot *slot) { slot->release.notify = slot_handle_release; wl_signal_add(&slot->buffer->events.release, &slot->release); + if (age != NULL) { + *age = slot->age; + } + return wlr_buffer_lock(slot->buffer); } -struct wlr_buffer *wlr_swapchain_acquire( - struct wlr_swapchain *swapchain) { +struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain, + int *age) { struct wlr_swapchain_slot *free_slot = NULL; for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) { struct wlr_swapchain_slot *slot = &swapchain->slots[i]; @@ -84,7 +89,7 @@ struct wlr_buffer *wlr_swapchain_acquire( continue; } if (slot->buffer != NULL) { - return slot_acquire(slot); + return slot_acquire(swapchain, slot, age); } free_slot = slot; } @@ -104,5 +109,36 @@ struct wlr_buffer *wlr_swapchain_acquire( wlr_log(WLR_ERROR, "Failed to allocate buffer"); return NULL; } - return slot_acquire(free_slot); + return slot_acquire(swapchain, free_slot, age); +} + +static bool swapchain_has_buffer(struct wlr_swapchain *swapchain, + struct wlr_buffer *buffer) { + for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) { + struct wlr_swapchain_slot *slot = &swapchain->slots[i]; + if (slot->buffer == buffer) { + return true; + } + } + return false; +} + +void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain, + struct wlr_buffer *buffer) { + assert(buffer != NULL); + + if (!swapchain_has_buffer(swapchain, buffer)) { + return; + } + + // See the algorithm described in: + // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_buffer_age.txt + for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) { + struct wlr_swapchain_slot *slot = &swapchain->slots[i]; + if (slot->buffer == buffer) { + slot->age = 1; + } else if (slot->age > 0) { + slot->age++; + } + } } From 68a8d9905513c0277037cc74325bb2ea507ac012 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 27 Jul 2020 18:37:40 +0200 Subject: [PATCH 114/223] backend/drm: add support for wlr_swapchain buffer age --- backend/drm/drm.c | 14 ++++++++++++-- backend/drm/renderer.c | 6 +----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index ecd98fdab..bd482be3c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -27,6 +27,7 @@ #include "backend/drm/drm.h" #include "backend/drm/iface.h" #include "backend/drm/util.h" +#include "render/swapchain.h" #include "util/signal.h" bool check_drm_features(struct wlr_drm_backend *drm) { @@ -331,6 +332,15 @@ static bool drm_connector_attach_render(struct wlr_output *output, return drm_surface_make_current(&conn->crtc->primary->surf, buffer_age); } +static void drm_plane_set_committed(struct wlr_drm_plane *plane) { + drm_fb_move(&plane->queued_fb, &plane->pending_fb); + + struct wlr_buffer *queued = plane->queued_fb.wlr_buf; + if (queued != NULL) { + wlr_swapchain_set_buffer_submitted(plane->surf.swapchain, queued); + } +} + static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) { struct wlr_drm_backend *drm = get_drm_backend_from_backend(conn->output.backend); @@ -338,9 +348,9 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) { bool ok = drm->iface->crtc_commit(drm, conn, flags); if (ok && !(flags & DRM_MODE_ATOMIC_TEST_ONLY)) { memcpy(&crtc->current, &crtc->pending, sizeof(struct wlr_drm_crtc_state)); - drm_fb_move(&crtc->primary->queued_fb, &crtc->primary->pending_fb); + drm_plane_set_committed(crtc->primary); if (crtc->cursor != NULL) { - drm_fb_move(&crtc->cursor->queued_fb, &crtc->cursor->pending_fb); + drm_plane_set_committed(crtc->cursor); } } else { memcpy(&crtc->pending, &crtc->current, sizeof(struct wlr_drm_crtc_state)); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index b78cf7e28..1d6a32776 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -137,7 +137,7 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) { bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age) { wlr_buffer_unlock(surf->back_buffer); - surf->back_buffer = wlr_swapchain_acquire(surf->swapchain); + surf->back_buffer = wlr_swapchain_acquire(surf->swapchain, buffer_age); if (surf->back_buffer == NULL) { wlr_log(WLR_ERROR, "Failed to acquire swapchain buffer"); return false; @@ -151,10 +151,6 @@ bool drm_surface_make_current(struct wlr_drm_surface *surf, return false; } - // TODO: damage tracking - if (buffer_age != NULL) { - *buffer_age = -1; - } return true; } From 8058e338eaf7c43df25735b0756983ff6b709eae Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 10:47:20 +0200 Subject: [PATCH 115/223] backend/drm: get rid of wlr_drm_fb_type Since all DRM FBs are backed by a wlr_buffer, there's no need for this anymore. --- backend/drm/drm.c | 20 ++++++++++---------- backend/drm/renderer.c | 21 +++++++-------------- include/backend/drm/renderer.h | 10 +--------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index bd482be3c..95f8c3d0a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -377,7 +377,7 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) { } assert(crtc->pending.active); - assert(plane_get_next_fb(crtc->primary)->type != WLR_DRM_FB_TYPE_NONE); + assert(plane_get_next_fb(crtc->primary)->bo); if (!drm_crtc_commit(conn, DRM_MODE_PAGE_FLIP_EVENT)) { return false; } @@ -650,10 +650,10 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output, } struct wlr_drm_fb *fb = &crtc->primary->queued_fb; - if (fb->type == WLR_DRM_FB_TYPE_NONE) { + if (fb->bo == NULL) { fb = &crtc->primary->current_fb; } - if (fb->type == WLR_DRM_FB_TYPE_NONE) { + if (fb->bo == NULL) { return false; } @@ -661,10 +661,10 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output, } struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { - if (plane->pending_fb.type != WLR_DRM_FB_TYPE_NONE) { + if (plane->pending_fb.bo) { return &plane->pending_fb; } - if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { + if (plane->queued_fb.bo) { return &plane->queued_fb; } return &plane->current_fb; @@ -680,7 +680,7 @@ static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) { // drm_crtc_page_flip expects a FB to be available struct wlr_drm_plane *plane = crtc->primary; - if (plane_get_next_fb(plane)->type == WLR_DRM_FB_TYPE_NONE) { + if (!plane_get_next_fb(plane)->bo) { drm_surface_render_black_frame(&plane->surf); if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { return false; @@ -1507,11 +1507,10 @@ static void page_flip_handler(int fd, unsigned seq, } struct wlr_drm_plane *plane = conn->crtc->primary; - if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { + if (plane->queued_fb.bo) { drm_fb_move(&plane->current_fb, &plane->queued_fb); } - if (conn->crtc->cursor && - conn->crtc->cursor->queued_fb.type != WLR_DRM_FB_TYPE_NONE) { + if (conn->crtc->cursor && conn->crtc->cursor->queued_fb.bo) { drm_fb_move(&conn->crtc->cursor->current_fb, &conn->crtc->cursor->queued_fb); } @@ -1522,7 +1521,8 @@ static void page_flip_handler(int fd, unsigned seq, * data between the GPUs, even if we were using the direct scanout * interface. */ - if (!drm->parent && plane->current_fb.type == WLR_DRM_FB_TYPE_WLR_BUFFER) { + if (!drm->parent && plane->current_fb.wlr_buf && + wlr_client_buffer_get(plane->current_fb.wlr_buf)) { present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 1d6a32776..a841aecf6 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -280,21 +280,15 @@ bool drm_plane_init_surface(struct wlr_drm_plane *plane, } void drm_fb_clear(struct wlr_drm_fb *fb) { - switch (fb->type) { - case WLR_DRM_FB_TYPE_NONE: - assert(!fb->bo); - break; - case WLR_DRM_FB_TYPE_SURFACE: - abort(); // TODO: remove this case entirely - break; - case WLR_DRM_FB_TYPE_WLR_BUFFER: - gbm_bo_destroy(fb->bo); - wlr_buffer_unlock(fb->wlr_buf); - fb->wlr_buf = NULL; - break; + if (!fb->bo) { + assert(!fb->wlr_buf); + return; } - fb->type = WLR_DRM_FB_TYPE_NONE; + gbm_bo_destroy(fb->bo); + wlr_buffer_unlock(fb->wlr_buf); + + fb->wlr_buf = NULL; fb->bo = NULL; if (fb->mgpu_bo) { @@ -376,7 +370,6 @@ bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer, return false; } - fb->type = WLR_DRM_FB_TYPE_WLR_BUFFER; fb->wlr_buf = wlr_buffer_lock(buf); return true; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 8cc4b0de1..e3fb6c9eb 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -33,20 +33,12 @@ struct wlr_drm_surface { struct wlr_buffer *back_buffer; }; -enum wlr_drm_fb_type { - WLR_DRM_FB_TYPE_NONE, - WLR_DRM_FB_TYPE_SURFACE, - WLR_DRM_FB_TYPE_WLR_BUFFER -}; - struct wlr_drm_fb { - enum wlr_drm_fb_type type; struct gbm_bo *bo; + struct wlr_buffer *wlr_buf; struct wlr_drm_surface *mgpu_surf; struct gbm_bo *mgpu_bo; - - struct wlr_buffer *wlr_buf; }; bool init_drm_renderer(struct wlr_drm_backend *drm, From c881008e1c73cc75ed32ce034e622092684295e1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 28 Jul 2020 16:42:59 +0200 Subject: [PATCH 116/223] backend/drm: add support for wlr_swapchain multi-GPU --- backend/drm/renderer.c | 30 ++++++++++++++---------------- include/backend/drm/renderer.h | 1 + 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index a841aecf6..c9f0e6f02 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -292,11 +292,12 @@ void drm_fb_clear(struct wlr_drm_fb *fb) { fb->bo = NULL; if (fb->mgpu_bo) { - // TODO - /*assert(fb->mgpu_surf); - gbm_surface_release_buffer(fb->mgpu_surf->gbm, fb->mgpu_bo); + assert(fb->mgpu_surf); + gbm_bo_destroy(fb->mgpu_bo); + wlr_buffer_unlock(fb->mgpu_wlr_buf); fb->mgpu_bo = NULL; - fb->mgpu_surf = NULL;*/ + fb->mgpu_wlr_buf = NULL; + fb->mgpu_surf = NULL; } } @@ -430,18 +431,15 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); wlr_renderer_end(renderer); - // TODO - /*if (!wlr_egl_swap_buffers(&mgpu->renderer->egl, mgpu->egl, NULL)) { - wlr_log(WLR_ERROR, "Failed to swap buffers"); - return NULL; + struct wlr_drm_fb mgpu_fb = { + .bo = fb->mgpu_bo, + .wlr_buf = fb->mgpu_wlr_buf, + }; + if (!drm_fb_lock_surface(&mgpu_fb, mgpu)) { + return false; } - - fb->mgpu_bo = gbm_surface_lock_front_buffer(mgpu->gbm); - if (!fb->mgpu_bo) { - wlr_log(WLR_ERROR, "Failed to lock front buffer"); - return NULL; - } - - fb->mgpu_surf = mgpu;*/ + fb->mgpu_bo = mgpu_fb.bo; + fb->mgpu_wlr_buf = mgpu_fb.wlr_buf; + fb->mgpu_surf = mgpu; return fb->mgpu_bo; } diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index e3fb6c9eb..7202b0ed0 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -39,6 +39,7 @@ struct wlr_drm_fb { struct wlr_drm_surface *mgpu_surf; struct gbm_bo *mgpu_bo; + struct wlr_buffer *mgpu_wlr_buf; }; bool init_drm_renderer(struct wlr_drm_backend *drm, From eef8b3dde8cda28a97ad36a602554e0ecf9819dd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 14 Aug 2020 12:04:29 +0200 Subject: [PATCH 117/223] backend/drm: check drm_surface_render_black_frame return value This avoids hitting an assertion in drm_fb_lock_surface when we failed to render a black frame. --- backend/drm/drm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 95f8c3d0a..dd3e9c716 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -681,7 +681,9 @@ static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) { // drm_crtc_page_flip expects a FB to be available struct wlr_drm_plane *plane = crtc->primary; if (!plane_get_next_fb(plane)->bo) { - drm_surface_render_black_frame(&plane->surf); + if (!drm_surface_render_black_frame(&plane->surf)) { + return false; + } if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { return false; } From c8d95acc37a1f3aa74538e4b9c688c2ed98227c6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 10 Jun 2020 14:26:39 +0200 Subject: [PATCH 118/223] render/egl: introduce wlr_egl_dup_drm_fd --- include/wlr/render/egl.h | 9 ++++++ render/egl.c | 69 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index b23931770..48382f6d9 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -45,8 +45,10 @@ struct wlr_egl { EGLDisplay display; EGLConfig config; EGLContext context; + EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT struct { + // Display extensions bool bind_wayland_display_wl; bool buffer_age_ext; bool image_base_khr; @@ -54,6 +56,9 @@ struct wlr_egl { bool image_dmabuf_import_ext; bool image_dmabuf_import_modifiers_ext; bool swap_buffers_with_damage; + + // Device extensions + bool device_drm_ext; } exts; struct { @@ -70,6 +75,8 @@ struct wlr_egl { PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA; PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA; PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR; + PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT; } procs; struct wl_display *wl_display; @@ -164,4 +171,6 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface); +int wlr_egl_dup_drm_fd(struct wlr_egl *egl); + #endif diff --git a/render/egl.c b/render/egl.c index f99b37f90..c23d81da1 100644 --- a/render/egl.c +++ b/render/egl.c @@ -1,10 +1,14 @@ +#define _POSIX_C_SOURCE 200809L #include #include +#include #include #include +#include #include #include #include +#include static bool egl_get_config(EGLDisplay disp, const EGLint *attribs, EGLConfig *out, EGLint visual_id) { @@ -289,6 +293,32 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, "eglQueryWaylandBufferWL"); } + const char *device_exts_str = NULL; + if (check_egl_ext(client_exts_str, "EGL_EXT_device_query")) { + load_egl_proc(&egl->procs.eglQueryDisplayAttribEXT, + "eglQueryDisplayAttribEXT"); + load_egl_proc(&egl->procs.eglQueryDeviceStringEXT, + "eglQueryDeviceStringEXT"); + + EGLAttrib device_attrib; + if (!egl->procs.eglQueryDisplayAttribEXT(egl->display, + EGL_DEVICE_EXT, &device_attrib)) { + wlr_log(WLR_ERROR, "eglQueryDisplayAttribEXT(EGL_DEVICE_EXT) failed"); + goto error; + } + egl->device = (EGLDeviceEXT)device_attrib; + + device_exts_str = + egl->procs.eglQueryDeviceStringEXT(egl->device, EGL_EXTENSIONS); + if (device_exts_str == NULL) { + wlr_log(WLR_ERROR, "eglQueryDeviceStringEXT(EGL_EXTENSIONS) failed"); + goto error; + } + + egl->exts.device_drm_ext = + check_egl_ext(device_exts_str, "EGL_EXT_device_drm"); + } + if (!egl_get_config(egl->display, config_attribs, &egl->config, visual_id)) { wlr_log(WLR_ERROR, "Failed to get EGL config"); goto error; @@ -297,6 +327,9 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(WLR_INFO, "Supported EGL client extensions: %s", client_exts_str); wlr_log(WLR_INFO, "Supported EGL display extensions: %s", display_exts_str); + if (device_exts_str != NULL) { + wlr_log(WLR_INFO, "Supported EGL device extensions: %s", device_exts_str); + } wlr_log(WLR_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); init_dmabuf_formats(egl); @@ -818,3 +851,39 @@ bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface) { } return eglDestroySurface(egl->display, surface); } + +int wlr_egl_dup_drm_fd(struct wlr_egl *egl) { + if (egl->device == EGL_NO_DEVICE_EXT || !egl->exts.device_drm_ext) { + return -1; + } + + const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device, + EGL_DRM_DEVICE_FILE_EXT); + if (primary_name == NULL) { + wlr_log(WLR_ERROR, + "eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed"); + return -1; + } + + int primary_fd = open(primary_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (primary_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open primary DRM device"); + return -1; + } + + char *render_name = drmGetRenderDeviceNameFromFd(primary_fd); + if (render_name == NULL) { + wlr_log_errno(WLR_ERROR, "drmGetRenderDeviceNameFromFd failed"); + close(primary_fd); + return -1; + } + close(primary_fd); + + int render_fd = open(render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (render_fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open render DRM device"); + return -1; + } + + return render_fd; +} From eb8360bda39bf48e2126e354fe6125c2e487c6b5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 10 Jun 2020 14:47:12 +0200 Subject: [PATCH 119/223] render: introduce wlr_renderer_get_drm_fd --- include/render/gles2.h | 1 + include/wlr/render/interface.h | 1 + include/wlr/render/wlr_renderer.h | 7 +++++++ render/gles2/renderer.c | 18 ++++++++++++++++++ render/wlr_renderer.c | 7 +++++++ 5 files changed, 34 insertions(+) diff --git a/include/render/gles2.h b/include/render/gles2.h index 2eff0aa52..a2173fbb5 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -35,6 +35,7 @@ struct wlr_gles2_renderer { struct wlr_renderer wlr_renderer; struct wlr_egl *egl; + int drm_fd; const char *exts_str; struct { diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 1b57c6603..70e954f8a 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -72,6 +72,7 @@ struct wlr_renderer_impl { bool (*blit_dmabuf)(struct wlr_renderer *renderer, struct wlr_dmabuf_attributes *dst, struct wlr_dmabuf_attributes *src); + int (*get_drm_fd)(struct wlr_renderer *renderer); }; void wlr_renderer_init(struct wlr_renderer *renderer, diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 8908d3ce4..915ec9153 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -131,6 +131,13 @@ bool wlr_renderer_format_supported(struct wlr_renderer *r, bool wlr_renderer_init_wl_display(struct wlr_renderer *r, struct wl_display *wl_display); +/** + * Obtains the FD of the DRM device used for rendering, or -1 if unavailable. + * + * The caller doesn't have ownership of the FD, it must not close it. + */ +int wlr_renderer_get_drm_fd(struct wlr_renderer *r); + /** * Destroys this wlr_renderer. Textures must be destroyed separately. */ diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index faef832f0..b679eb7e4 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -644,6 +645,17 @@ static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer, return true; } +static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer(wlr_renderer); + + if (renderer->drm_fd < 0) { + renderer->drm_fd = wlr_egl_dup_drm_fd(renderer->egl); + } + + return renderer->drm_fd; +} + struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); @@ -675,6 +687,10 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { wlr_egl_unset_current(renderer->egl); + if (renderer->drm_fd >= 0) { + close(renderer->drm_fd); + } + free(renderer); } @@ -700,6 +716,7 @@ static const struct wlr_renderer_impl renderer_impl = { .texture_from_dmabuf = gles2_texture_from_dmabuf, .init_wl_display = gles2_init_wl_display, .blit_dmabuf = gles2_blit_dmabuf, + .get_drm_fd = gles2_get_drm_fd, }; void push_gles2_debug_(struct wlr_gles2_renderer *renderer, @@ -856,6 +873,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->egl = egl; renderer->exts_str = exts_str; + renderer->drm_fd = -1; wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION)); wlr_log(WLR_INFO, "GL vendor: %s", glGetString(GL_VENDOR)); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 311747f10..81b0a5576 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -269,3 +269,10 @@ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, return renderer; } + +int wlr_renderer_get_drm_fd(struct wlr_renderer *r) { + if (!r->impl->get_drm_fd) { + return -1; + } + return r->impl->get_drm_fd(r); +} From 61f8cdfb9ee2f8cc710c4cf947634c0c737e6383 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 22 Aug 2020 17:24:16 +0200 Subject: [PATCH 120/223] backend/headless: switch to wlr_swapchain --- backend/headless/backend.c | 54 ++++++++++++++----- backend/headless/output.c | 106 +++++++++++++------------------------ include/backend/headless.h | 7 +-- 3 files changed, 83 insertions(+), 84 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 7758ece49..49780d889 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -1,12 +1,18 @@ +#define _POSIX_C_SOURCE 200809L #include -#include -#include +#include #include +#include #include #include #include +#include +#include #include +#include #include "backend/headless.h" +#include "render/drm_format_set.h" +#include "render/gbm_allocator.h" #include "util/signal.h" struct wlr_headless_backend *headless_backend_from_backend( @@ -62,6 +68,8 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wlr_signal_emit_safe(&wlr_backend->events.destroy, backend); + free(backend->format); + wlr_allocator_destroy(backend->allocator); if (backend->egl == &backend->priv_egl) { wlr_renderer_destroy(backend->renderer); wlr_egl_finish(&backend->priv_egl); @@ -104,18 +112,40 @@ static bool backend_init(struct wlr_headless_backend *backend, backend->renderer = renderer; backend->egl = wlr_gles2_renderer_get_egl(renderer); - if (wlr_gles2_renderer_check_ext(backend->renderer, "GL_OES_rgb8_rgba8") || - wlr_gles2_renderer_check_ext(backend->renderer, - "GL_OES_required_internalformat") || - wlr_gles2_renderer_check_ext(backend->renderer, "GL_ARM_rgba8")) { - backend->internal_format = GL_RGBA8_OES; - } else { - wlr_log(WLR_INFO, "GL_RGBA8_OES not supported, " - "falling back to GL_RGBA4 internal format " - "(performance may be affected)"); - backend->internal_format = GL_RGBA4; + int fd = wlr_renderer_get_drm_fd(renderer); + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); + return false; } + fd = dup(fd); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "dup failed"); + return false; + } + + struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(fd); + if (alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + return false; + } + backend->allocator = &alloc->base; + + const struct wlr_drm_format_set *formats = + wlr_renderer_get_dmabuf_formats(backend->renderer); + if (formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer"); + return false; + } + // TODO: filter modifiers with external_only=false + const struct wlr_drm_format *format = + wlr_drm_format_set_get(formats, DRM_FORMAT_XRGB8888); + if (format == NULL) { + wlr_log(WLR_ERROR, "Renderer doesn't support XRGB8888"); + return false; + } + backend->format = wlr_drm_format_dup(format); + backend->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &backend->display_destroy); diff --git a/backend/headless/output.c b/backend/headless/output.c index 315f5a33c..d2160987d 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,12 +1,12 @@ #include -#include -#include #include #include #include #include #include #include "backend/headless.h" +#include "render/swapchain.h" +#include "render/wlr_renderer.h" #include "util/signal.h" static struct wlr_headless_output *headless_output_from_output( @@ -15,53 +15,6 @@ static struct wlr_headless_output *headless_output_from_output( return (struct wlr_headless_output *)wlr_output; } -static bool create_fbo(struct wlr_headless_output *output, - unsigned int width, unsigned int height) { - if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) { - return false; - } - - GLuint rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, output->backend->internal_format, - width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, rbo); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - wlr_egl_unset_current(output->backend->egl); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - wlr_log(WLR_ERROR, "Failed to create FBO"); - return false; - } - - output->fbo = fbo; - output->rbo = rbo; - return true; -} - -static void destroy_fbo(struct wlr_headless_output *output) { - if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) { - return; - } - - glDeleteFramebuffers(1, &output->fbo); - glDeleteRenderbuffers(1, &output->rbo); - - wlr_egl_unset_current(output->backend->egl); - - output->fbo = 0; - output->rbo = 0; -} - static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, int32_t height, int32_t refresh) { struct wlr_headless_output *output = @@ -71,8 +24,10 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, refresh = HEADLESS_DEFAULT_REFRESH; } - destroy_fbo(output); - if (!create_fbo(output, width, height)) { + wlr_swapchain_destroy(output->swapchain); + output->swapchain = wlr_swapchain_create(output->backend->allocator, + width, height, output->backend->format); + if (!output->swapchain) { wlr_output_destroy(wlr_output); return false; } @@ -88,15 +43,20 @@ static bool output_attach_render(struct wlr_output *wlr_output, struct wlr_headless_output *output = headless_output_from_output(wlr_output); - if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) { + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age); + if (!output->back_buffer) { return false; } - glBindFramebuffer(GL_FRAMEBUFFER, output->fbo); - - if (buffer_age != NULL) { - *buffer_age = 0; // We only have one buffer + if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; } + if (!wlr_renderer_bind_buffer(output->backend->renderer, + output->back_buffer)) { + return false; + } + return true; } @@ -131,10 +91,18 @@ static bool output_commit(struct wlr_output *wlr_output) { } if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); + assert(output->back_buffer != NULL); + + wlr_renderer_bind_buffer(output->backend->renderer, NULL); wlr_egl_unset_current(output->backend->egl); - // Nothing needs to be done for FBOs + wlr_buffer_unlock(output->front_buffer); + output->front_buffer = output->back_buffer; + output->back_buffer = NULL; + + wlr_swapchain_set_buffer_submitted(output->swapchain, + output->front_buffer); + wlr_output_send_present(wlr_output, NULL); } @@ -145,8 +113,12 @@ static void output_rollback_render(struct wlr_output *wlr_output) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); assert(wlr_egl_is_current(output->backend->egl)); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + + wlr_renderer_bind_buffer(output->backend->renderer, NULL); wlr_egl_unset_current(output->backend->egl); + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = NULL; } static void output_destroy(struct wlr_output *wlr_output) { @@ -154,7 +126,9 @@ static void output_destroy(struct wlr_output *wlr_output) { headless_output_from_output(wlr_output); wl_list_remove(&output->link); wl_event_source_remove(output->frame_timer); - destroy_fbo(output); + wlr_swapchain_destroy(output->swapchain); + wlr_buffer_unlock(output->back_buffer); + wlr_buffer_unlock(output->front_buffer); free(output); } @@ -192,7 +166,9 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, backend->display); struct wlr_output *wlr_output = &output->wlr_output; - if (!create_fbo(output, width, height)) { + output->swapchain = wlr_swapchain_create(backend->allocator, + width, height, backend->format); + if (!output->swapchain) { goto error; } @@ -207,14 +183,6 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, "Headless output %zd", backend->last_output_num); wlr_output_set_description(wlr_output, description); - if (!output_attach_render(wlr_output, NULL)) { - goto error; - } - - wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); - wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); - wlr_renderer_end(backend->renderer); - struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); diff --git a/include/backend/headless.h b/include/backend/headless.h index 5681c2bd2..4a29b0338 100644 --- a/include/backend/headless.h +++ b/include/backend/headless.h @@ -3,7 +3,6 @@ #include #include -#include #define HEADLESS_DEFAULT_REFRESH (60 * 1000) // 60 Hz @@ -12,6 +11,8 @@ struct wlr_headless_backend { struct wlr_egl priv_egl; // may be uninitialized struct wlr_egl *egl; struct wlr_renderer *renderer; + struct wlr_allocator *allocator; + struct wlr_drm_format *format; struct wl_display *display; struct wl_list outputs; size_t last_output_num; @@ -19,7 +20,6 @@ struct wlr_headless_backend { struct wl_listener display_destroy; struct wl_listener renderer_destroy; bool started; - GLenum internal_format; }; struct wlr_headless_output { @@ -28,7 +28,8 @@ struct wlr_headless_output { struct wlr_headless_backend *backend; struct wl_list link; - GLuint fbo, rbo; + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer, *front_buffer; struct wl_event_source *frame_timer; int frame_delay; // ms From 02df7b7ac89696e3a94de3ff66b2bed1c6e5b77a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 25 Aug 2020 12:30:00 +0200 Subject: [PATCH 121/223] backend/headless: implement export_dmabuf --- backend/headless/output.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/headless/output.c b/backend/headless/output.c index d2160987d..8ce7a32bd 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -121,6 +121,23 @@ static void output_rollback_render(struct wlr_output *wlr_output) { output->back_buffer = NULL; } +static bool output_export_dmabuf(struct wlr_output *wlr_output, + struct wlr_dmabuf_attributes *attribs) { + struct wlr_headless_output *output = + headless_output_from_output(wlr_output); + + if (!output->front_buffer) { + return false; + } + + struct wlr_dmabuf_attributes tmp; + if (!wlr_buffer_get_dmabuf(output->front_buffer, &tmp)) { + return false; + } + + return wlr_dmabuf_attributes_copy(attribs, &tmp); +} + static void output_destroy(struct wlr_output *wlr_output) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); @@ -137,6 +154,7 @@ static const struct wlr_output_impl output_impl = { .attach_render = output_attach_render, .commit = output_commit, .rollback_render = output_rollback_render, + .export_dmabuf = output_export_dmabuf, }; bool wlr_output_is_headless(struct wlr_output *wlr_output) { From 526ae5944c5cc97e02f0282c57ce7320ceb2daa5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 15 Nov 2020 23:15:49 +0100 Subject: [PATCH 122/223] build: improve summary via bool_yn Shows YES/NO instead of 1/0, improves readability. --- meson.build | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 3235dd3fb..348fc2a28 100644 --- a/meson.build +++ b/meson.build @@ -168,14 +168,14 @@ wlroots = declare_dependency( meson.override_dependency('wlroots', wlroots) summary({ - 'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0), - 'elogind': conf_data.get('WLR_HAS_ELOGIND', 0), - 'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0), - 'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0), - 'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0), - 'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0), - 'xcb-errors': conf_data.get('WLR_HAS_XCB_ERRORS', 0), -}) + 'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0) == 1, + 'elogind': conf_data.get('WLR_HAS_ELOGIND', 0) == 1, + 'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0) == 1, + 'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0) == 1, + 'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0) == 1, + 'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0) == 1, + 'xcb-errors': conf_data.get('WLR_HAS_XCB_ERRORS', 0) == 1, +}, bool_yn: true) if get_option('examples') subdir('examples') From e18599b05e0f0cbeba11adbd489e801285470eab Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 25 May 2020 17:02:38 +0200 Subject: [PATCH 123/223] render/egl: stop including eglmesaext.h This is a Mesa-specific header that was needed because some Wayland EGL extensions were missing from the Khronos registry. Now that this has been fixed [1] and Mesa [2] & glvnd [3] have sync'ed their headers, we can drop this workaround. [1]: https://github.com/KhronosGroup/EGL-Registry/pull/95 [2]: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4953 [3]: https://gitlab.freedesktop.org/glvnd/libglvnd/-/merge_requests/225 --- include/wlr/config.h.in | 2 -- include/wlr/render/egl.h | 4 ---- meson.build | 5 ----- 3 files changed, 11 deletions(-) diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index 77a155982..cd42987b2 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -1,8 +1,6 @@ #ifndef WLR_CONFIG_H #define WLR_CONFIG_H -#mesondefine WLR_HAS_EGLMESAEXT_H - #mesondefine WLR_HAS_LIBCAP #mesondefine WLR_HAS_SYSTEMD diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 48382f6d9..46af0cf81 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -23,10 +23,6 @@ #include #include -#if WLR_HAS_EGLMESAEXT_H -// TODO: remove eglmesaext.h -#include -#endif #include #include #include diff --git a/meson.build b/meson.build index 348fc2a28..95fdff658 100644 --- a/meson.build +++ b/meson.build @@ -87,7 +87,6 @@ conf_data.set10('WLR_HAS_X11_BACKEND', false) conf_data.set10('WLR_HAS_XWAYLAND', false) conf_data.set10('WLR_HAS_XCB_ERRORS', false) conf_data.set10('WLR_HAS_XCB_ICCCM', false) -conf_data.set10('WLR_HAS_EGLMESAEXT_H', false) # Clang complains about some zeroed initializer lists (= {0}), even though they # are valid @@ -111,10 +110,6 @@ pixman = dependency('pixman-1') math = cc.find_library('m') rt = cc.find_library('rt') -if cc.has_header('EGL/eglmesaext.h', dependencies: egl) - conf_data.set10('WLR_HAS_EGLMESAEXT_H', true) -endif - wlr_files = [] wlr_deps = [ wayland_server, From dc7c6c4860e03193513ca2f0d0adf563318f6b15 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Tue, 17 Nov 2020 13:13:18 -0700 Subject: [PATCH 124/223] render/egl: recognize EGL_BAD_DEVICE_EXT error --- render/egl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/render/egl.c b/render/egl.c index c23d81da1..5b52809ac 100644 --- a/render/egl.c +++ b/render/egl.c @@ -75,6 +75,8 @@ static const char *egl_error_str(EGLint error) { return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_DEVICE_EXT: + return "EGL_BAD_DEVICE_EXT"; case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; case EGL_BAD_MATCH: From 6284af121fd1427eaefb043ea03363c969f2df3f Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Thu, 19 Nov 2020 11:28:32 +0100 Subject: [PATCH 125/223] texture: document that functions should not be called while rendering --- include/wlr/render/wlr_texture.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 71ce5e7c9..3a4840acd 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -24,6 +24,9 @@ struct wlr_texture { /** * Create a new texture from raw pixel data. `stride` is in bytes. The returned * texture is mutable. + * + * Should not be called in a rendering block like renderer_begin()/end() or + * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, @@ -32,12 +35,18 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, /** * Create a new texture from a wl_drm resource. The returned texture is * immutable. + * + * Should not be called in a rendering block like renderer_begin()/end() or + * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer, struct wl_resource *data); /** * Create a new texture from a DMA-BUF. The returned texture is immutable. + * + * Should not be called in a rendering block like renderer_begin()/end() or + * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, struct wlr_dmabuf_attributes *attribs); @@ -58,6 +67,9 @@ bool wlr_texture_is_opaque(struct wlr_texture *texture); /** * Update a texture with raw pixels. The texture must be mutable, and the input * data must have the same pixel format that the texture was created with. + * + * Should not be called in a rendering block like renderer_begin()/end() or + * between attaching a renderer to an output and committing it. */ bool wlr_texture_write_pixels(struct wlr_texture *texture, uint32_t stride, uint32_t width, uint32_t height, From fb3bea80144ea25fb21de8a3eeb0c9249f4cbfd6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 19 Nov 2020 21:34:00 +0100 Subject: [PATCH 126/223] backend/drm: Use legacy gamma size for legacy backend We would always return the GAMMA_LUT_SIZE property if available, and only fall back to legacy gamma size otherwise. This leads to issues if both are available in differs in size while we use the legacy backend. Ensure that we only return the legacy size if we're using the legacy backend. Closes: https://github.com/swaywm/wlroots/issues/2429 --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index dd3e9c716..f797dd5ad 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -609,7 +609,7 @@ static void drm_connector_rollback_render(struct wlr_output *output) { size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc) { - if (crtc->props.gamma_lut_size == 0) { + if (crtc->props.gamma_lut_size == 0 || drm->iface == &legacy_iface) { return (size_t)crtc->legacy_crtc->gamma_size; } From 63df2bcbe656b394b0bd152ab69147194dd74815 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 09:57:03 +0100 Subject: [PATCH 127/223] backend/session: don't return FD on failure in open_file When wlr_session_open_file fails, don't return the FD, otherwise the caller will think the call succeeded. --- backend/session/session.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/session/session.c b/backend/session/session.c index d8e9509d8..e3e108afe 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -195,7 +196,8 @@ int wlr_session_open_file(struct wlr_session *session, const char *path) { error: free(dev); - return fd; + close(fd); + return -1; } static struct wlr_device *find_device(struct wlr_session *session, int fd) { From 44a4792fd80acfeb15e2cf88304f283855689fd0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 10:16:07 +0100 Subject: [PATCH 128/223] backend/session: operate on wlr_device Instead of operating on FDs in {open,close}_device, operate on wlr_devices. This avoids the device lookup in wlr_session and allows callers to have access to wlr_device fields. For now, we use it to remove wlr_session_signal_add and replace it with a more idiomatic wlr_session.events.change field. In the future, other events will be added. --- backend/backend.c | 4 +- backend/drm/backend.c | 18 +++++---- backend/libinput/backend.c | 19 ++++++++- backend/session/session.c | 76 +++++++++++++---------------------- include/backend/drm/drm.h | 1 + include/wlr/backend/drm.h | 3 +- include/wlr/backend/session.h | 16 ++++---- 7 files changed, 69 insertions(+), 68 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index aa0d9668d..7df1cfbdb 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -151,7 +151,7 @@ static struct wlr_backend *attempt_noop_backend(struct wl_display *display) { 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) { - int gpus[8]; + 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); @@ -160,7 +160,7 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, struct wlr_backend *drm = wlr_drm_backend_create(display, session, gpus[i], primary_drm, create_renderer_func); if (!drm) { - wlr_log(WLR_ERROR, "Failed to open DRM device %d", gpus[i]); + wlr_log(WLR_ERROR, "Failed to create DRM backend"); continue; } diff --git a/backend/drm/backend.c b/backend/drm/backend.c index da6e1ebc7..3b7ed93c1 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -50,7 +50,7 @@ static void backend_destroy(struct wlr_backend *backend) { finish_drm_resources(drm); finish_drm_renderer(&drm->renderer); - wlr_session_close_file(drm->session, drm->fd); + wlr_session_close_file(drm->session, drm->dev); wl_event_source_remove(drm->drm_event); free(drm); } @@ -128,13 +128,14 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, - struct wlr_session *session, int gpu_fd, struct wlr_backend *parent, + struct wlr_session *session, struct wlr_device *dev, + struct wlr_backend *parent, wlr_renderer_create_func_t create_renderer_func) { - assert(display && session && gpu_fd >= 0); + assert(display && session && dev); assert(!parent || wlr_backend_is_drm(parent)); - char *name = drmGetDeviceNameFromFd2(gpu_fd); - drmVersion *version = drmGetVersion(gpu_fd); + char *name = drmGetDeviceNameFromFd2(dev->fd); + drmVersion *version = drmGetVersion(dev->fd); wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name); free(name); drmFreeVersion(version); @@ -149,13 +150,14 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, drm->session = session; wl_list_init(&drm->outputs); - drm->fd = gpu_fd; + drm->dev = dev; + drm->fd = dev->fd; if (parent != NULL) { drm->parent = get_drm_backend_from_backend(parent); } drm->drm_invalidated.notify = drm_invalidated; - wlr_session_signal_add(session, gpu_fd, &drm->drm_invalidated); + wl_signal_add(&dev->events.change, &drm->drm_invalidated); drm->display = display; struct wl_event_loop *event_loop = wl_display_get_event_loop(display); @@ -195,7 +197,7 @@ error_event: wl_list_remove(&drm->session_signal.link); wl_event_source_remove(drm->drm_event); error_fd: - wlr_session_close_file(drm->session, drm->fd); + wlr_session_close_file(drm->session, dev); free(drm); return NULL; } diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 12f76bbff..7037084d3 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -17,12 +17,27 @@ static struct wlr_libinput_backend *get_libinput_backend_from_backend( static int libinput_open_restricted(const char *path, int flags, void *_backend) { struct wlr_libinput_backend *backend = _backend; - return wlr_session_open_file(backend->session, path); + struct wlr_device *dev = wlr_session_open_file(backend->session, path); + if (dev == NULL) { + return -1; + } + return dev->fd; } static void libinput_close_restricted(int fd, void *_backend) { struct wlr_libinput_backend *backend = _backend; - wlr_session_close_file(backend->session, fd); + + struct wlr_device *dev; + bool found = false; + wl_list_for_each(dev, &backend->session->devices, link) { + if (dev->fd == fd) { + found = true; + break; + } + } + if (found) { + wlr_session_close_file(backend->session, dev); + } } static const struct libinput_interface libinput_impl = { diff --git a/backend/session/session.c b/backend/session/session.c index e3e108afe..005e4e7e8 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -55,7 +55,7 @@ static int udev_event(int fd, uint32_t mask, void *data) { wl_list_for_each(dev, &session->devices, link) { if (dev->dev == devnum) { - wlr_signal_emit_safe(&dev->signal, session); + wlr_signal_emit_safe(&dev->events.change, NULL); break; } } @@ -169,10 +169,11 @@ void wlr_session_destroy(struct wlr_session *session) { session->impl->destroy(session); } -int wlr_session_open_file(struct wlr_session *session, const char *path) { +struct wlr_device *wlr_session_open_file(struct wlr_session *session, + const char *path) { int fd = session->impl->open(session, path); if (fd < 0) { - return fd; + return NULL; } struct wlr_device *dev = malloc(sizeof(*dev)); @@ -189,46 +190,24 @@ int wlr_session_open_file(struct wlr_session *session, const char *path) { dev->fd = fd; dev->dev = st.st_rdev; - wl_signal_init(&dev->signal); + wl_signal_init(&dev->events.change); wl_list_insert(&session->devices, &dev->link); - return fd; + return dev; error: free(dev); close(fd); - return -1; -} - -static struct wlr_device *find_device(struct wlr_session *session, int fd) { - struct wlr_device *dev; - - wl_list_for_each(dev, &session->devices, link) { - if (dev->fd == fd) { - return dev; - } - } - - wlr_log(WLR_ERROR, "Tried to use fd %d not opened by session", fd); - assert(0); return NULL; } -void wlr_session_close_file(struct wlr_session *session, int fd) { - struct wlr_device *dev = find_device(session, fd); - - session->impl->close(session, fd); +void wlr_session_close_file(struct wlr_session *session, + struct wlr_device *dev) { + session->impl->close(session, dev->fd); wl_list_remove(&dev->link); free(dev); } -void wlr_session_signal_add(struct wlr_session *session, int fd, - struct wl_listener *listener) { - struct wlr_device *dev = find_device(session, fd); - - wl_signal_add(&dev->signal, listener); -} - bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { if (!session) { return false; @@ -240,32 +219,32 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { /* Tests if 'path' is KMS compatible by trying to open it. * It leaves the open device in *fd_out it it succeeds. */ -static int open_if_kms(struct wlr_session *restrict session, +static struct wlr_device *open_if_kms(struct wlr_session *restrict session, const char *restrict path) { if (!path) { - return -1; + return NULL; } - int fd = wlr_session_open_file(session, path); - if (fd < 0) { - return -1; + struct wlr_device *dev = wlr_session_open_file(session, path); + if (!dev) { + return NULL; } - drmVersion *ver = drmGetVersion(fd); + drmVersion *ver = drmGetVersion(dev->fd); if (!ver) { - goto out_fd; + goto out_dev; } drmFreeVersion(ver); - return fd; + return dev; -out_fd: - wlr_session_close_file(session, fd); - return -1; +out_dev: + wlr_session_close_file(session, dev); + return NULL; } static size_t explicit_find_gpus(struct wlr_session *session, - size_t ret_len, int ret[static ret_len], const char *str) { + size_t ret_len, struct wlr_device *ret[static ret_len], const char *str) { char *gpus = strdup(str); if (!gpus) { wlr_log_errno(WLR_ERROR, "Allocation failed"); @@ -281,7 +260,7 @@ static size_t explicit_find_gpus(struct wlr_session *session, } ret[i] = open_if_kms(session, ptr); - if (ret[i] < 0) { + if (!ret[i]) { wlr_log(WLR_ERROR, "Unable to open %s as DRM device", ptr); } else { ++i; @@ -296,7 +275,7 @@ static size_t explicit_find_gpus(struct wlr_session *session, * If it's not found, it returns the first valid GPU it finds. */ size_t wlr_session_find_gpus(struct wlr_session *session, - size_t ret_len, int *ret) { + size_t ret_len, struct wlr_device **ret) { const char *explicit = getenv("WLR_DRM_DEVICES"); if (explicit) { return explicit_find_gpus(session, ret_len, ret, explicit); @@ -348,17 +327,18 @@ size_t wlr_session_find_gpus(struct wlr_session *session, } } - int fd = open_if_kms(session, udev_device_get_devnode(dev)); - if (fd < 0) { + struct wlr_device *wlr_dev = + open_if_kms(session, udev_device_get_devnode(dev)); + if (!wlr_dev) { udev_device_unref(dev); continue; } udev_device_unref(dev); - ret[i] = fd; + ret[i] = wlr_dev; if (is_boot_vga) { - int tmp = ret[0]; + struct wlr_device *tmp = ret[0]; ret[0] = ret[i]; ret[i] = tmp; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 80bc76698..f46d565c9 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -82,6 +82,7 @@ struct wlr_drm_backend { bool addfb2_modifiers; int fd; + struct wlr_device *dev; size_t num_crtcs; struct wlr_drm_crtc *crtcs; diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index c1380323a..cd0f3405d 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -22,7 +22,8 @@ * a DRM backend, other kinds of backends raise SIGABRT). */ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, - struct wlr_session *session, int gpu_fd, struct wlr_backend *parent, + struct wlr_session *session, struct wlr_device *dev, + struct wlr_backend *parent, wlr_renderer_create_func_t create_renderer_func); bool wlr_backend_is_drm(struct wlr_backend *backend); diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 36b80a8d6..82f22a3fe 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -11,9 +11,11 @@ struct session_impl; struct wlr_device { int fd; dev_t dev; - struct wl_signal signal; - struct wl_list link; + + struct { + struct wl_signal change; + } events; }; struct wlr_session { @@ -74,21 +76,21 @@ void wlr_session_destroy(struct wlr_session *session); * * Returns -errno on error. */ -int wlr_session_open_file(struct wlr_session *session, const char *path); +struct wlr_device *wlr_session_open_file(struct wlr_session *session, + const char *path); /* * Closes a file previously opened with wlr_session_open_file. */ -void wlr_session_close_file(struct wlr_session *session, int fd); +void wlr_session_close_file(struct wlr_session *session, + struct wlr_device *device); -void wlr_session_signal_add(struct wlr_session *session, int fd, - struct wl_listener *listener); /* * Changes the virtual terminal. */ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt); size_t wlr_session_find_gpus(struct wlr_session *session, - size_t ret_len, int *ret); + size_t ret_len, struct wlr_device **ret); #endif From 768fbaad54027f8dd027e7e015e8eeb93cb38c52 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 10:42:43 +0100 Subject: [PATCH 129/223] backend/session: filter udev events by sysname We're only interested in card devices. The loop over wlr_session.devices would take care of ignoring non-card events, but a future patch will listen to udev "add" events as well. --- backend/session/session.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/backend/session/session.c b/backend/session/session.c index 005e4e7e8..b96f42941 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -33,6 +33,19 @@ static const struct session_impl *impls[] = { NULL, }; +static bool is_drm_card(const char *sysname) { + const char prefix[] = "card"; + if (strncmp(sysname, prefix, strlen(prefix)) != 0) { + return false; + } + for (size_t i = strlen(prefix); sysname[i] != '\0'; i++) { + if (sysname[i] < '0' || sysname[i] > '9') { + return false; + } + } + return true; +} + static int udev_event(int fd, uint32_t mask, void *data) { struct wlr_session *session = data; @@ -41,18 +54,16 @@ static int udev_event(int fd, uint32_t mask, void *data) { return 1; } + const char *sysname = udev_device_get_sysname(udev_dev); const char *action = udev_device_get_action(udev_dev); + wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action); - wlr_log(WLR_DEBUG, "udev event for %s (%s)", - udev_device_get_sysname(udev_dev), action); - - if (!action || strcmp(action, "change") != 0) { + if (!is_drm_card(sysname) || !action || strcmp(action, "change") != 0) { goto out; } dev_t devnum = udev_device_get_devnum(udev_dev); struct wlr_device *dev; - wl_list_for_each(dev, &session->devices, link) { if (dev->dev == devnum) { wlr_signal_emit_safe(&dev->events.change, NULL); From 76bcddf071454cd373bd09e2619c0cb03a377350 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 10:56:13 +0100 Subject: [PATCH 130/223] backend/session: introduce wlr_session.events.add_drm_card This is triggered when a new DRM card is added. An easy way to test this patch is `modprobe vkms`. --- backend/session/session.c | 33 ++++++++++++++++++++++++++------- include/wlr/backend/session.h | 5 +++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/backend/session/session.c b/backend/session/session.c index b96f42941..a94793c86 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -55,19 +55,37 @@ static int udev_event(int fd, uint32_t mask, void *data) { } const char *sysname = udev_device_get_sysname(udev_dev); + const char *devnode = udev_device_get_devnode(udev_dev); const char *action = udev_device_get_action(udev_dev); wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action); - if (!is_drm_card(sysname) || !action || strcmp(action, "change") != 0) { + if (!is_drm_card(sysname) || !action || !devnode) { goto out; } - dev_t devnum = udev_device_get_devnum(udev_dev); - struct wlr_device *dev; - wl_list_for_each(dev, &session->devices, link) { - if (dev->dev == devnum) { - wlr_signal_emit_safe(&dev->events.change, NULL); - break; + const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT"); + if (!seat) { + seat = "seat0"; + } + if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { + goto out; + } + + if (strcmp(action, "add") == 0) { + wlr_log(WLR_DEBUG, "DRM device %s added", sysname); + struct wlr_session_add_event event = { + .path = devnode, + }; + wlr_signal_emit_safe(&session->events.add_drm_card, &event); + } else if (strcmp(action, "change") == 0) { + dev_t devnum = udev_device_get_devnum(udev_dev); + struct wlr_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->dev == devnum) { + wlr_log(WLR_DEBUG, "DRM device %s changed", sysname); + wlr_signal_emit_safe(&dev->events.change, NULL); + break; + } } } @@ -84,6 +102,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { void session_init(struct wlr_session *session) { wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.add_drm_card); wl_signal_init(&session->events.destroy); wl_list_init(&session->devices); } diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 82f22a3fe..b63c356ce 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -43,10 +43,15 @@ struct wlr_session { struct wl_listener display_destroy; struct { + struct wl_signal add_drm_card; // struct wlr_session_add_event struct wl_signal destroy; } events; }; +struct wlr_session_add_event { + const char *path; +}; + /* * Opens a session, taking control of the current virtual terminal. * This should not be called if another program is already in control From fbf11a41e135c2b380ce51c9c90278dbcfc60c3d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 11:14:49 +0100 Subject: [PATCH 131/223] backend/session: wait for DRM device if none found Wait for a DRM device if none is found in wlr_session_find_gpus. This can happen if the compositor is loaded before the display kernel driver. This supersedes the logind CanGraphical property. To test, e.g. with i915 and sway: rmmod -f i915 sway & modprobe i915 Closes: https://github.com/swaywm/wlroots/issues/2093 --- backend/session/session.c | 65 ++++++++++++++++++++++++++++++++--- include/wlr/backend/session.h | 1 + 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/backend/session/session.c b/backend/session/session.c index a94793c86..c7808212a 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -170,6 +170,8 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { goto error_mon; } + session->display = disp; + session->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(disp, &session->display_destroy); @@ -301,6 +303,36 @@ static size_t explicit_find_gpus(struct wlr_session *session, return i; } +static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { + struct udev_enumerate *en = udev_enumerate_new(udev); + if (!en) { + wlr_log(WLR_ERROR, "udev_enumerate_new failed"); + return NULL; + } + + udev_enumerate_add_match_subsystem(en, "drm"); + udev_enumerate_add_match_sysname(en, "card[0-9]*"); + + if (udev_enumerate_scan_devices(en) != 0) { + wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed"); + udev_enumerate_unref(en); + return NULL; + } + + return en; +} + +struct find_gpus_add_handler { + bool added; + struct wl_listener listener; +}; + +static void find_gpus_handle_add(struct wl_listener *listener, void *data) { + struct find_gpus_add_handler *handler = + wl_container_of(listener, handler, listener); + handler->added = true; +} + /* Tries to find the primary GPU by checking for the "boot_vga" attribute. * If it's not found, it returns the first valid GPU it finds. */ @@ -311,15 +343,38 @@ size_t wlr_session_find_gpus(struct wlr_session *session, return explicit_find_gpus(session, ret_len, ret, explicit); } - struct udev_enumerate *en = udev_enumerate_new(session->udev); + struct udev_enumerate *en = enumerate_drm_cards(session->udev); if (!en) { - wlr_log(WLR_ERROR, "Failed to create udev enumeration"); return -1; } - udev_enumerate_add_match_subsystem(en, "drm"); - udev_enumerate_add_match_sysname(en, "card[0-9]*"); - udev_enumerate_scan_devices(en); + if (udev_enumerate_get_list_entry(en) == NULL) { + udev_enumerate_unref(en); + wlr_log(WLR_INFO, "Waiting for a DRM card device"); + + struct find_gpus_add_handler handler = {0}; + handler.listener.notify = find_gpus_handle_add; + wl_signal_add(&session->events.add_drm_card, &handler.listener); + + struct wl_event_loop *event_loop = + wl_display_get_event_loop(session->display); + while (!handler.added) { + int ret = wl_event_loop_dispatch(event_loop, -1); + if (ret < 0) { + wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: " + "wl_event_loop_dispatch failed"); + udev_enumerate_unref(en); + return -1; + } + } + + wl_list_remove(&handler.listener.link); + + en = enumerate_drm_cards(session->udev); + if (!en) { + return -1; + } + } struct udev_list_entry *entry; size_t i = 0; diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index b63c356ce..692d7be13 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -40,6 +40,7 @@ struct wlr_session { struct wl_list devices; + struct wl_display *display; struct wl_listener display_destroy; struct { From cd95d70df094e59b625073688e5fd3e783183424 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 11:29:41 +0100 Subject: [PATCH 132/223] Revert "session/logind: support CanGraphical property" We now use udev to wait for DRM card devices. This reverts commit 3ebf079a9a120a27fc1008a62e7f99d5d166b745. --- backend/session/logind.c | 150 --------------------------------------- 1 file changed, 150 deletions(-) diff --git a/backend/session/logind.c b/backend/session/logind.c index 9c2515a87..30519a788 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -36,9 +36,7 @@ struct logind_session { char *id; char *path; - char *seat_path; - bool can_graphical; // specifies whether a drm device was taken // if so, the session will be (de)activated with the drm fd, // otherwise with the dbus PropertiesChanged on "active" signal @@ -179,34 +177,6 @@ out: return ret >= 0; } -static bool find_seat_path(struct logind_session *session) { - int ret; - sd_bus_message *msg = NULL; - sd_bus_error error = SD_BUS_ERROR_NULL; - - ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", - "/org/freedesktop/login1", "org.freedesktop.login1.Manager", - "GetSeat", &error, &msg, "s", session->base.seat); - if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to get seat path: %s", error.message); - goto out; - } - - const char *path; - ret = sd_bus_message_read(msg, "o", &path); - if (ret < 0) { - wlr_log(WLR_ERROR, "Could not parse seat path: %s", error.message); - goto out; - } - session->seat_path = strdup(path); - -out: - sd_bus_error_free(&error); - sd_bus_message_unref(msg); - - return ret >= 0; -} - static bool session_activate(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; @@ -294,7 +264,6 @@ static void logind_session_destroy(struct wlr_session *base) { sd_bus_unref(session->bus); free(session->id); free(session->path); - free(session->seat_path); free(session); } @@ -496,95 +465,6 @@ error: return 0; } -static int seat_properties_changed(sd_bus_message *msg, void *userdata, - sd_bus_error *ret_error) { - struct logind_session *session = userdata; - int ret = 0; - - // if we have a drm fd we don't depend on this - if (session->has_drm) { - return 0; - } - - // PropertiesChanged arg 1: interface - const char *interface; - ret = sd_bus_message_read_basic(msg, 's', &interface); // skip path - if (ret < 0) { - goto error; - } - - if (strcmp(interface, "org.freedesktop.login1.Seat") != 0) { - // not interesting for us; ignore - wlr_log(WLR_DEBUG, "ignoring PropertiesChanged from %s", interface); - return 0; - } - - // PropertiesChanged arg 2: changed properties with values - ret = sd_bus_message_enter_container(msg, 'a', "{sv}"); - if (ret < 0) { - goto error; - } - - const char *s; - while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) { - ret = sd_bus_message_read_basic(msg, 's', &s); - if (ret < 0) { - goto error; - } - - if (strcmp(s, "CanGraphical") == 0) { - int ret; - ret = sd_bus_message_enter_container(msg, 'v', "b"); - if (ret < 0) { - goto error; - } - - ret = sd_bus_message_read_basic(msg, 'b', &session->can_graphical); - if (ret < 0) { - goto error; - } - - return 0; - } else { - sd_bus_message_skip(msg, "{sv}"); - } - - ret = sd_bus_message_exit_container(msg); - if (ret < 0) { - goto error; - } - } - - if (ret < 0) { - goto error; - } - - ret = sd_bus_message_exit_container(msg); - if (ret < 0) { - goto error; - } - - // PropertiesChanged arg 3: changed properties without values - sd_bus_message_enter_container(msg, 'a', "s"); - while ((ret = sd_bus_message_read_basic(msg, 's', &s)) > 0) { - if (strcmp(s, "CanGraphical") == 0) { - session->can_graphical = sd_seat_can_graphical(session->base.seat); - return 0; - } - } - - if (ret < 0) { - goto error; - } - - return 0; - -error: - wlr_log(WLR_ERROR, "Failed to parse D-Bus PropertiesChanged: %s", - strerror(-ret)); - return 0; -} - static bool add_signal_matches(struct logind_session *session) { static const char *logind = "org.freedesktop.login1"; static const char *logind_path = "/org/freedesktop/login1"; @@ -622,14 +502,6 @@ static bool add_signal_matches(struct logind_session *session) { return false; } - ret = sd_bus_match_signal(session->bus, NULL, logind, session->seat_path, - property_interface, "PropertiesChanged", - seat_properties_changed, session); - if (ret < 0) { - wlr_log(WLR_ERROR, "Failed to add D-Bus match: %s", strerror(-ret)); - return false; - } - return true; } @@ -811,12 +683,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { goto error; } - if (!find_seat_path(session)) { - sd_bus_unref(session->bus); - free(session->path); - goto error; - } - if (!add_signal_matches(session)) { goto error_bus; } @@ -833,21 +699,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { goto error_bus; } - // Check for CanGraphical first - session->can_graphical = sd_seat_can_graphical(session->base.seat); - if (!session->can_graphical) { - wlr_log(WLR_INFO, "Waiting for 'CanGraphical' on seat %s", session->base.seat); - } - - while (!session->can_graphical) { - ret = wl_event_loop_dispatch(event_loop, -1); - if (ret < 0) { - wlr_log(WLR_ERROR, "Polling error waiting for 'CanGraphical' on seat %s", - session->base.seat); - goto error_bus; - } - } - set_type(session); wlr_log(WLR_INFO, "Successfully loaded logind session"); @@ -860,7 +711,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { error_bus: sd_bus_unref(session->bus); free(session->path); - free(session->seat_path); error: free(session->id); From 0e76f92de7f5ee53a3d35ad3128b5224b9a305aa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 11:34:55 +0100 Subject: [PATCH 133/223] backend/session: replace session_signal with events.active This is more idiomatic wlroots API. The new name makes it clear that the signal is emitted when wlr_session.active changes. --- backend/drm/backend.c | 4 ++-- backend/libinput/backend.c | 4 ++-- backend/session/direct-freebsd.c | 4 ++-- backend/session/direct.c | 4 ++-- backend/session/libseat.c | 4 ++-- backend/session/logind.c | 8 ++++---- backend/session/session.c | 2 +- include/wlr/backend/session.h | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 3b7ed93c1..b2da7cb3d 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -85,7 +85,7 @@ bool wlr_backend_is_drm(struct wlr_backend *b) { static void session_signal(struct wl_listener *listener, void *data) { struct wlr_drm_backend *drm = wl_container_of(listener, drm, session_signal); - struct wlr_session *session = data; + struct wlr_session *session = drm->session; if (session->active) { wlr_log(WLR_INFO, "DRM fd resumed"); @@ -170,7 +170,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, } drm->session_signal.notify = session_signal; - wl_signal_add(&session->session_signal, &drm->session_signal); + wl_signal_add(&session->events.active, &drm->session_signal); if (!check_drm_features(drm)) { goto error_event; diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 7037084d3..e31ecf066 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -175,7 +175,7 @@ bool wlr_backend_is_libinput(struct wlr_backend *b) { static void session_signal(struct wl_listener *listener, void *data) { struct wlr_libinput_backend *backend = wl_container_of(listener, backend, session_signal); - struct wlr_session *session = data; + struct wlr_session *session = backend->session; if (!backend->libinput_context) { return; @@ -219,7 +219,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, backend->display = display; backend->session_signal.notify = session_signal; - wl_signal_add(&session->session_signal, &backend->session_signal); + wl_signal_add(&session->events.active, &backend->session_signal); backend->session_destroy.notify = handle_session_destroy; wl_signal_add(&session->events.destroy, &backend->session_destroy); diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index e4b6c7929..302b0ff42 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -115,7 +115,7 @@ static int vt_handler(int signo, void *data) { if (session->base.active) { session->base.active = false; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); wl_list_for_each(dev, &session->base.devices, link) { if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) { @@ -134,7 +134,7 @@ static int vt_handler(int signo, void *data) { } session->base.active = true; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } return 1; diff --git a/backend/session/direct.c b/backend/session/direct.c index f9041070b..b6d9f06af 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -126,7 +126,7 @@ static int vt_handler(int signo, void *data) { if (session->base.active) { session->base.active = false; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); struct wlr_device *dev; wl_list_for_each(dev, &session->base.devices, link) { @@ -149,7 +149,7 @@ static int vt_handler(int signo, void *data) { } session->base.active = true; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } return 1; diff --git a/backend/session/libseat.c b/backend/session/libseat.c index 751adcd3e..180ce2157 100644 --- a/backend/session/libseat.c +++ b/backend/session/libseat.c @@ -35,13 +35,13 @@ struct libseat_session { static void handle_enable_seat(struct libseat *seat, void *data) { struct libseat_session *session = data; session->base.active = true; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } static void handle_disable_seat(struct libseat *seat, void *data) { struct libseat_session *session = data; session->base.active = false; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); libseat_disable_seat(session->seat); } diff --git a/backend/session/logind.c b/backend/session/logind.c index 30519a788..8859f1a25 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -306,7 +306,7 @@ static int pause_device(sd_bus_message *msg, void *userdata, if (major == DRM_MAJOR && strcmp(type, "gone") != 0) { assert(session->has_drm); session->base.active = false; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } if (strcmp(type, "pause") == 0) { @@ -348,7 +348,7 @@ static int resume_device(sd_bus_message *msg, void *userdata, if (!session->base.active) { session->base.active = true; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } } @@ -407,7 +407,7 @@ static int session_properties_changed(sd_bus_message *msg, void *userdata, if (session->base.active != active) { session->base.active = active; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } return 0; } else { @@ -447,7 +447,7 @@ static int session_properties_changed(sd_bus_message *msg, void *userdata, if (session->base.active != active) { session->base.active = active; - wlr_signal_emit_safe(&session->base.session_signal, session); + wlr_signal_emit_safe(&session->base.events.active, NULL); } return 0; } diff --git a/backend/session/session.c b/backend/session/session.c index c7808212a..a25e78f29 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -101,7 +101,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } void session_init(struct wlr_session *session) { - wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.active); wl_signal_init(&session->events.add_drm_card); wl_signal_init(&session->events.destroy); wl_list_init(&session->devices); diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 692d7be13..06c23d737 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -24,7 +24,6 @@ struct wlr_session { * Signal for when the session becomes active/inactive. * It's called when we swap virtual terminal. */ - struct wl_signal session_signal; bool active; /* @@ -44,6 +43,7 @@ struct wlr_session { struct wl_listener display_destroy; struct { + struct wl_signal active; struct wl_signal add_drm_card; // struct wlr_session_add_event struct wl_signal destroy; } events; From c491a21d2560138817c43899d3cd58e9d28e7e89 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 13:07:29 +0100 Subject: [PATCH 134/223] backend/session/logind: log when using XDG_SESSION_ID This makes it easier to figure out how wlroots selected the session. --- backend/session/logind.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/session/logind.c b/backend/session/logind.c index 8859f1a25..0cef13560 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -569,6 +569,8 @@ static bool get_display_session(char **session_id) { char *xdg_session_id = getenv("XDG_SESSION_ID"); if (xdg_session_id) { + wlr_log(WLR_INFO, "Selecting session from XDG_SESSION_ID: %s", xdg_session_id); + // This just checks whether the supplied session ID is valid if (sd_session_is_active(xdg_session_id) < 0) { wlr_log(WLR_ERROR, "Invalid XDG_SESSION_ID: '%s'", xdg_session_id); From 754179dacd4c8cbd06d6c646cda9c5e23edcb707 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 13:37:26 +0100 Subject: [PATCH 135/223] backend/session: add a timeout waiting for GPUs If a GPU doesn't show up in 10s, bail out and return zero GPUs. --- backend/session/session.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/session/session.c b/backend/session/session.c index a25e78f29..b58bd9679 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,8 @@ #include "backend/session/session.h" #include "util/signal.h" +#define WAIT_GPU_TIMEOUT 10000 // ms + extern const struct session_impl session_libseat; extern const struct session_impl session_logind; extern const struct session_impl session_direct; @@ -322,6 +325,12 @@ static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { return en; } +static uint64_t get_current_time_ms(void) { + struct timespec ts = {0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} + struct find_gpus_add_handler { bool added; struct wl_listener listener; @@ -356,16 +365,24 @@ size_t wlr_session_find_gpus(struct wlr_session *session, handler.listener.notify = find_gpus_handle_add; wl_signal_add(&session->events.add_drm_card, &handler.listener); + uint64_t started_at = get_current_time_ms(); + uint64_t timeout = WAIT_GPU_TIMEOUT; struct wl_event_loop *event_loop = wl_display_get_event_loop(session->display); while (!handler.added) { - int ret = wl_event_loop_dispatch(event_loop, -1); + int ret = wl_event_loop_dispatch(event_loop, (int)timeout); if (ret < 0) { wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: " "wl_event_loop_dispatch failed"); udev_enumerate_unref(en); return -1; } + + uint64_t now = get_current_time_ms(); + if (now >= started_at + WAIT_GPU_TIMEOUT) { + break; + } + timeout = started_at + WAIT_GPU_TIMEOUT - now; } wl_list_remove(&handler.listener.link); From ebecc5404b899b462f4c414663780ba72adbab28 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 7 Nov 2020 22:08:40 +0100 Subject: [PATCH 136/223] surface: Make send_enter store entered outputs wlr_surface_send_enter now stores outputs that have been entered. Combined with a new 'bind' event on wlr_output, this allows us to delay enter events as necessary until the respective wl_output global has been bound. Closes: https://github.com/swaywm/wlroots/issues/2466 --- include/wlr/types/wlr_output.h | 7 ++++ include/wlr/types/wlr_surface.h | 11 +++++ types/wlr_output.c | 8 ++++ types/wlr_surface.c | 72 +++++++++++++++++++++++++++++++-- 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index cb7427066..8cc4afcf8 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -166,6 +166,8 @@ struct wlr_output { struct wl_signal commit; // wlr_output_event_commit // Emitted right after the buffer has been presented to the user struct wl_signal present; // wlr_output_event_present + // Emitted after a client bound the wl_output global + struct wl_signal bind; // wlr_output_event_bind struct wl_signal enable; struct wl_signal mode; struct wl_signal scale; @@ -233,6 +235,11 @@ struct wlr_output_event_present { uint32_t flags; // enum wlr_output_present_flag }; +struct wlr_output_event_bind { + struct wlr_output *output; + struct wl_resource *resource; +}; + struct wlr_surface; /** diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 2cd4ac5db..abb056002 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -67,6 +67,15 @@ struct wlr_surface_role { void (*precommit)(struct wlr_surface *surface); }; +struct wlr_surface_output { + struct wlr_surface *surface; + struct wlr_output *output; + + struct wl_list link; // wlr_surface::current_outputs + struct wl_listener bind; + struct wl_listener destroy; +}; + struct wlr_surface { struct wl_resource *resource; struct wlr_renderer *renderer; @@ -126,6 +135,8 @@ struct wlr_surface { // wlr_subsurface::parent_pending_link struct wl_list subsurface_pending_list; + struct wl_list current_outputs; // wlr_surface_output::link + struct wl_listener renderer_destroy; void *data; diff --git a/types/wlr_output.c b/types/wlr_output.c index 4ce7312f0..15e851544 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -93,6 +93,13 @@ static void output_bind(struct wl_client *wl_client, void *data, send_current_mode(resource); send_scale(resource); send_done(resource); + + struct wlr_output_event_bind evt = { + .output = output, + .resource = resource, + }; + + wlr_signal_emit_safe(&output->events.bind, &evt); } void wlr_output_create_global(struct wlr_output *output) { @@ -333,6 +340,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.precommit); wl_signal_init(&output->events.commit); wl_signal_init(&output->events.present); + wl_signal_init(&output->events.bind); wl_signal_init(&output->events.enable); wl_signal_init(&output->events.mode); wl_signal_init(&output->events.scale); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 1b623504b..c251816e9 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -616,9 +616,16 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { free(subsurface); } +static void surface_output_destroy(struct wlr_surface_output *surface_output); + static void surface_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_surface_output *surface_output, *tmp; struct wlr_surface *surface = wlr_surface_from_resource(resource); + wl_list_for_each_safe(surface_output, tmp, &surface->current_outputs, link) { + surface_output_destroy(surface_output); + } + wlr_signal_emit_safe(&surface->events.destroy, surface); wl_list_remove(wl_resource_get_link(surface->resource)); @@ -676,6 +683,7 @@ struct wlr_surface *wlr_surface_create(struct wl_client *client, wl_signal_init(&surface->events.new_subsurface); wl_list_init(&surface->subsurfaces); wl_list_init(&surface->subsurface_pending_list); + wl_list_init(&surface->current_outputs); pixman_region32_init(&surface->buffer_damage); pixman_region32_init(&surface->opaque_region); pixman_region32_init(&surface->input_region); @@ -1091,10 +1099,59 @@ struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, return NULL; } +static void surface_output_destroy(struct wlr_surface_output *surface_output) { + wl_list_remove(&surface_output->bind.link); + wl_list_remove(&surface_output->destroy.link); + wl_list_remove(&surface_output->link); + + free(surface_output); +} + +static void surface_handle_output_bind(struct wl_listener *listener, + void *data) { + struct wlr_output_event_bind *evt = data; + struct wlr_surface_output *surface_output = + wl_container_of(listener, surface_output, bind); + struct wl_client *client = wl_resource_get_client( + surface_output->surface->resource); + if (client == wl_resource_get_client(evt->resource)) { + wl_surface_send_enter(surface_output->surface->resource, evt->resource); + } +} + +static void surface_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_surface_output *surface_output = + wl_container_of(listener, surface_output, destroy); + surface_output_destroy(surface_output); +} + void wlr_surface_send_enter(struct wlr_surface *surface, struct wlr_output *output) { struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_surface_output *surface_output; struct wl_resource *resource; + + wl_list_for_each(surface_output, &surface->current_outputs, link) { + if (surface_output->output == output) { + return; + } + } + + surface_output = calloc(1, sizeof(struct wlr_surface_output)); + if (surface_output == NULL) { + return; + } + surface_output->bind.notify = surface_handle_output_bind; + surface_output->destroy.notify = surface_handle_output_destroy; + + wl_signal_add(&output->events.bind, &surface_output->bind); + wl_signal_add(&output->events.destroy, &surface_output->destroy); + + surface_output->surface = surface; + surface_output->output = output; + wl_list_insert(&surface->current_outputs, &surface_output->link); + wl_resource_for_each(resource, &output->resources) { if (client == wl_resource_get_client(resource)) { wl_surface_send_enter(surface->resource, resource); @@ -1105,10 +1162,19 @@ void wlr_surface_send_enter(struct wlr_surface *surface, void wlr_surface_send_leave(struct wlr_surface *surface, struct wlr_output *output) { struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_surface_output *surface_output, *tmp; struct wl_resource *resource; - wl_resource_for_each(resource, &output->resources) { - if (client == wl_resource_get_client(resource)) { - wl_surface_send_leave(surface->resource, resource); + + wl_list_for_each_safe(surface_output, tmp, + &surface->current_outputs, link) { + if (surface_output->output == output) { + surface_output_destroy(surface_output); + wl_resource_for_each(resource, &output->resources) { + if (client == wl_resource_get_client(resource)) { + wl_surface_send_leave(surface->resource, resource); + } + } + break; } } } From 262740bc9a282554c8aacb001e06aeb96d0afdce Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 24 Nov 2020 12:56:53 +0100 Subject: [PATCH 137/223] backend/libseat: fix change_vt return value This should return true on success and false on failure not vice-versa. --- backend/session/libseat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/session/libseat.c b/backend/session/libseat.c index 180ce2157..f3ad789cd 100644 --- a/backend/session/libseat.c +++ b/backend/session/libseat.c @@ -203,7 +203,7 @@ static void libseat_session_close_device(struct wlr_session *base, int fd) { static bool libseat_change_vt(struct wlr_session *base, unsigned vt) { struct libseat_session *session = libseat_session_from_session(base); - return libseat_switch_session(session->seat, vt); + return libseat_switch_session(session->seat, vt) == 0; } const struct session_impl session_libseat = { From 52805feae9bd6332c972065c799f4ac3b7ef2275 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 19:06:45 +0100 Subject: [PATCH 138/223] backend/x11: log errors Register an X11 error handler, and optionally use xcb-errors to print a detailed message. --- backend/x11/backend.c | 56 +++++++++++++++++++++++++++++++++++++++++++ include/backend/x11.h | 11 ++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 6dc650ab3..4472396e0 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -38,6 +38,8 @@ struct wlr_x11_output *get_x11_output_from_window_id( return NULL; } +static void handle_x11_error(struct wlr_x11_backend *x11, xcb_value_error_t *ev); + static void handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *event) { switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { @@ -76,6 +78,12 @@ static void handle_x11_event(struct wlr_x11_backend *x11, if (ev->extension == x11->xinput_opcode) { handle_x11_xinput_event(x11, ev); } + break; + } + case 0: { + xcb_value_error_t *ev = (xcb_value_error_t *)event; + handle_x11_error(x11, ev); + break; } } } @@ -140,6 +148,10 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_renderer_destroy(x11->renderer); wlr_egl_finish(&x11->egl); +#if WLR_HAS_XCB_ERRORS + xcb_errors_context_free(x11->errors_context); +#endif + if (x11->xlib_conn) { XCloseDisplay(x11->xlib_conn); } @@ -296,6 +308,13 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, goto error_event; } +#if WLR_HAS_XCB_ERRORS + if (xcb_errors_context_new(x11->xcb, &x11->errors_context) != 0) { + wlr_log(WLR_ERROR, "Failed to create error context"); + return false; + } +#endif + wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "X11 keyboard", 0, 0); wlr_keyboard_init(&x11->keyboard, &keyboard_impl); @@ -314,3 +333,40 @@ error_x11: free(x11); return NULL; } + +static void handle_x11_error(struct wlr_x11_backend *x11, xcb_value_error_t *ev) { +#if WLR_HAS_XCB_ERRORS + const char *major_name = xcb_errors_get_name_for_major_code( + x11->errors_context, ev->major_opcode); + if (!major_name) { + wlr_log(WLR_DEBUG, "X11 error happened, but could not get major name"); + goto log_raw; + } + + const char *minor_name = xcb_errors_get_name_for_minor_code( + x11->errors_context, ev->major_opcode, ev->minor_opcode); + + const char *extension; + const char *error_name = xcb_errors_get_name_for_error(x11->errors_context, + ev->error_code, &extension); + if (!error_name) { + wlr_log(WLR_DEBUG, "X11 error happened, but could not get error name"); + goto log_raw; + } + + wlr_log(WLR_ERROR, "X11 error: op %s (%s), code %s (%s), " + "sequence %"PRIu16", value %"PRIu32, + major_name, minor_name ? minor_name : "no minor", + error_name, extension ? extension : "no extension", + ev->sequence, ev->bad_value); + + return; + +log_raw: +#endif + + wlr_log(WLR_ERROR, "X11 error: op %"PRIu8":%"PRIu16", code %"PRIu8", " + "sequence %"PRIu16", value %"PRIu32, + ev->major_opcode, ev->minor_opcode, ev->error_code, + ev->sequence, ev->bad_value); +} diff --git a/include/backend/x11.h b/include/backend/x11.h index 033963616..7ce3ed98a 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -1,14 +1,19 @@ #ifndef BACKEND_X11_H #define BACKEND_X11_H +#include + #include #include #include #include +#if WLR_HAS_XCB_ERRORS +#include +#endif + #include -#include #include #include #include @@ -81,6 +86,10 @@ struct wlr_x11_backend { // The time we last received an event xcb_timestamp_t time; +#if WLR_HAS_XCB_ERRORS + xcb_errors_context_t *errors_context; +#endif + uint8_t xinput_opcode; struct wl_listener display_destroy; From f6c36f88816dcd6071e5e09ffc1bed88a74dc6d4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 19 Nov 2020 10:18:31 +0100 Subject: [PATCH 139/223] backend/x11: log unhandled X11 events --- backend/x11/backend.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 4472396e0..2c91df71f 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -39,6 +39,8 @@ struct wlr_x11_output *get_x11_output_from_window_id( } static void handle_x11_error(struct wlr_x11_backend *x11, xcb_value_error_t *ev); +static void handle_x11_unknown_event(struct wlr_x11_backend *x11, + xcb_generic_event_t *ev); static void handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *event) { @@ -77,6 +79,8 @@ static void handle_x11_event(struct wlr_x11_backend *x11, xcb_ge_generic_event_t *ev = (xcb_ge_generic_event_t *)event; if (ev->extension == x11->xinput_opcode) { handle_x11_xinput_event(x11, ev); + } else { + handle_x11_unknown_event(x11, event); } break; } @@ -85,6 +89,9 @@ static void handle_x11_event(struct wlr_x11_backend *x11, handle_x11_error(x11, ev); break; } + default: + handle_x11_unknown_event(x11, event); + break; } } @@ -370,3 +377,21 @@ log_raw: ev->major_opcode, ev->minor_opcode, ev->error_code, ev->sequence, ev->bad_value); } + +static void handle_x11_unknown_event(struct wlr_x11_backend *x11, + xcb_generic_event_t *ev) { +#if WLR_HAS_XCB_ERRORS + const char *extension; + const char *event_name = xcb_errors_get_name_for_xcb_event( + x11->errors_context, ev, &extension); + if (!event_name) { + wlr_log(WLR_DEBUG, "No name for unhandled event: %u", + ev->response_type); + return; + } + + wlr_log(WLR_DEBUG, "Unhandled X11 event: %s (%u)", event_name, ev->response_type); +#else + wlr_log(WLR_DEBUG, "Unhandled X11 event: %u", ev->response_type); +#endif +} From 154fe8696f40151dae999cfc69299aef5132dd14 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 19 Nov 2020 10:27:40 +0100 Subject: [PATCH 140/223] backend/x11: log unhandled client messages --- backend/x11/backend.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 2c91df71f..f2b09a257 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -72,6 +72,9 @@ static void handle_x11_event(struct wlr_x11_backend *x11, if (output != NULL) { wlr_output_destroy(&output->wlr_output); } + } else { + wlr_log(WLR_DEBUG, "Unhandled client message %"PRIu32, + ev->data.data32[0]); } break; } From 713c1661b742f93a7d2167321837c0d99541ca87 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 11:57:08 +0100 Subject: [PATCH 141/223] backend/drm: stop force-probing connectors After discussing with Pekka and Daniel on #dri-devel, we concluded [1] that user-space shouldn't need to force-probe connectors. Force-probing can take some time, so using drmModeGetConnectorCurrent can result in faster start-up. Users can manually trigger a force-probe if necessary: echo detect | sudo tee /sys/class/drm/card0-DP-1/status Or just by running a tool like drm_info. A similar change has been submitted to Weston [2]. [1]: https://lists.freedesktop.org/archives/dri-devel/2020-November/287728.html [2]: https://gitlab.freedesktop.org/wayland/weston/-/issues/437 --- backend/drm/drm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index f797dd5ad..de505376e 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1282,8 +1282,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { struct wlr_drm_connector *new_outputs[res->count_connectors + 1]; for (int i = 0; i < res->count_connectors; ++i) { - drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, - res->connectors[i]); + drmModeConnector *drm_conn = + drmModeGetConnectorCurrent(drm->fd, res->connectors[i]); if (!drm_conn) { wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); continue; From 6485fadc16a45ccbcbdcc76b064bcd2ee6256cda Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Nov 2020 13:52:05 +0100 Subject: [PATCH 142/223] backend/wayland: don't set EGL visual The Wayland platform doesn't have visuals. By chance, WL_SHM_FORMAT_ARGB8888 is zero, which means egl_get_config was ignoring it and everything worked fine. --- backend/wayland/backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 314d45cdd..9290e28fd 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -316,7 +316,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT, - wl->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888); + wl->remote_display, config_attribs, 0); if (!wl->renderer) { wlr_log(WLR_ERROR, "Could not create renderer"); From 78e9e692e81d5f4b269d6f125e920011de6bb39e Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 28 Nov 2020 17:41:28 +0100 Subject: [PATCH 143/223] wlr-output-management: add missing NULL check Handle allocation failure in wlr_output_configuration_head_v1_create --- types/wlr_output_management_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index 728abee7c..312057ed3 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -118,6 +118,9 @@ struct wlr_output_configuration_head_v1 * struct wlr_output_configuration_v1 *config, struct wlr_output *output) { struct wlr_output_configuration_head_v1 *config_head = config_head_create(config, output); + if (config_head == NULL) { + return NULL; + } config_head->state.enabled = output->enabled; config_head->state.mode = output->current_mode; config_head->state.custom_mode.width = output->width; From 44cea53e7285fe25a81b3ce2dfb470daec27e6e4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Nov 2020 17:33:30 +0100 Subject: [PATCH 144/223] render/egl: don't rely on being able to open primary node On some setups (e.g. remote access via SSH) the current user won't have the permission to open the primary node at all. It's still possible to use drmGetDevices to match the primary node name returned by EGL. Closes: https://github.com/swaywm/wlroots/issues/2488 --- render/egl.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/render/egl.c b/render/egl.c index 5b52809ac..6382c0c34 100644 --- a/render/egl.c +++ b/render/egl.c @@ -854,6 +854,62 @@ bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface) { return eglDestroySurface(egl->display, surface); } +static bool device_has_name(const drmDevice *device, const char *name) { + for (size_t i = 0; i < DRM_NODE_MAX; i++) { + if (!(device->available_nodes & (1 << i))) { + continue; + } + if (strcmp(device->nodes[i], name) == 0) { + return true; + } + } + return false; +} + +static char *get_render_name(const char *name) { + uint32_t flags = 0; + int devices_len = drmGetDevices2(flags, NULL, 0); + if (devices_len < 0) { + wlr_log(WLR_ERROR, "drmGetDevices2 failed"); + return NULL; + } + drmDevice **devices = calloc(devices_len, sizeof(drmDevice *)); + if (devices == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + devices_len = drmGetDevices2(flags, devices, devices_len); + if (devices_len < 0) { + free(devices); + wlr_log(WLR_ERROR, "drmGetDevices2 failed"); + return NULL; + } + + const drmDevice *match = NULL; + for (int i = 0; i < devices_len; i++) { + if (device_has_name(devices[i], name)) { + match = devices[i]; + break; + } + } + + char *render_name = NULL; + if (match == NULL) { + wlr_log(WLR_ERROR, "Cannot find DRM device %s", name); + } else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) { + wlr_log(WLR_ERROR, "DRM device %s has no render node", name); + } else { + render_name = strdup(match->nodes[DRM_NODE_RENDER]); + } + + for (int i = 0; i < devices_len; i++) { + drmFreeDevice(&devices[i]); + } + free(devices); + + return render_name; +} + int wlr_egl_dup_drm_fd(struct wlr_egl *egl) { if (egl->device == EGL_NO_DEVICE_EXT || !egl->exts.device_drm_ext) { return -1; @@ -867,25 +923,21 @@ int wlr_egl_dup_drm_fd(struct wlr_egl *egl) { return -1; } - int primary_fd = open(primary_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (primary_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open primary DRM device"); - return -1; - } - - char *render_name = drmGetRenderDeviceNameFromFd(primary_fd); + char *render_name = get_render_name(primary_name); if (render_name == NULL) { - wlr_log_errno(WLR_ERROR, "drmGetRenderDeviceNameFromFd failed"); - close(primary_fd); + wlr_log(WLR_ERROR, "Can't find render node name for device %s", + primary_name); return -1; } - close(primary_fd); int render_fd = open(render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); if (render_fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open render DRM device"); + wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s", + render_name); + free(render_name); return -1; } + free(render_name); return render_fd; } From c15ca3793e35ae1cf755dd04d06f6c504b484350 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 13:40:08 +0100 Subject: [PATCH 145/223] render: expand wlr_renderer_get{,_dmabuf}_formats docs Make it clear formats returned are only suitable for import/sampling. These formats can't be used to be rendered to. --- include/wlr/render/egl.h | 2 +- include/wlr/render/wlr_renderer.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 46af0cf81..4ab672d3a 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -123,7 +123,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes, bool *external_only); /** - * Get the available dmabuf formats + * Get DMA-BUF formats suitable for sampling usage. */ const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 915ec9153..1de69e163 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -83,7 +83,8 @@ void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, const float color[static 4], const float matrix[static 9]); /** - * Returns a list of pixel formats supported by this renderer. + * Get the shared-memory formats supporting import usage. Buffers allocated + * with a format from this list may be imported via wlr_texture_from_pixels. */ const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r, size_t *len); @@ -98,7 +99,8 @@ bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer, void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer, struct wl_resource *buffer, int *width, int *height); /** - * Get the available DMA-BUF formats. + * Get the DMA-BUF formats supporting sampling usage. Buffers allocated with + * a format from this list may be imported via wlr_texture_from_dmabuf. */ const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( struct wlr_renderer *renderer); From 61612ecb3688431b85a55d046a49b3700826990d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 13:58:58 +0100 Subject: [PATCH 146/223] render: remove wlr_renderer_format_supported Instead, callers can just use wlr_renderer_get_formats and iterate over the list. This function was unused in wlroots. --- include/wlr/render/interface.h | 2 -- include/wlr/render/wlr_renderer.h | 5 ----- render/gles2/renderer.c | 6 ------ render/wlr_renderer.c | 6 ------ 4 files changed, 19 deletions(-) diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 70e954f8a..625ab1981 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -46,8 +46,6 @@ struct wlr_renderer_impl { const float color[static 4], const float matrix[static 9]); const enum wl_shm_format *(*formats)( struct wlr_renderer *renderer, size_t *len); - bool (*format_supported)(struct wlr_renderer *renderer, - enum wl_shm_format fmt); bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer, struct wl_resource *resource); void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer, diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 1de69e163..c992ded5c 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -120,11 +120,6 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, */ bool wlr_renderer_blit_dmabuf(struct wlr_renderer *r, struct wlr_dmabuf_attributes *dst, struct wlr_dmabuf_attributes *src); -/** - * Checks if a format is supported. - */ -bool wlr_renderer_format_supported(struct wlr_renderer *r, - enum wl_shm_format fmt); /** * Creates necessary shm and invokes the initialization of the implementation. * diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index b679eb7e4..fbf27e498 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -401,11 +401,6 @@ static const enum wl_shm_format *gles2_renderer_formats( return get_gles2_wl_formats(len); } -static bool gles2_format_supported(struct wlr_renderer *wlr_renderer, - enum wl_shm_format wl_fmt) { - return get_gles2_format_from_wl(wl_fmt) != NULL; -} - static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); @@ -705,7 +700,6 @@ static const struct wlr_renderer_impl renderer_impl = { .render_quad_with_matrix = gles2_render_quad_with_matrix, .render_ellipse_with_matrix = gles2_render_ellipse_with_matrix, .formats = gles2_renderer_formats, - .format_supported = gles2_format_supported, .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_formats = gles2_get_dmabuf_formats, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 81b0a5576..0fb7fbda1 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -18,7 +18,6 @@ void wlr_renderer_init(struct wlr_renderer *renderer, assert(impl->render_quad_with_matrix); assert(impl->render_ellipse_with_matrix); assert(impl->formats); - assert(impl->format_supported); assert(impl->texture_from_pixels); renderer->impl = impl; @@ -195,11 +194,6 @@ bool wlr_renderer_blit_dmabuf(struct wlr_renderer *r, return r->impl->blit_dmabuf(r, dst, src); } -bool wlr_renderer_format_supported(struct wlr_renderer *r, - enum wl_shm_format fmt) { - return r->impl->format_supported(r, fmt); -} - bool wlr_renderer_init_wl_display(struct wlr_renderer *r, struct wl_display *wl_display) { if (wl_display_init_shm(wl_display)) { From 5d008d90309defd2ed15f1b9525c551ecb38e21d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 14:16:22 +0100 Subject: [PATCH 147/223] render: introduce wlr_renderer_get_dmabuf_render_formats It describes which DMA-BUF formats can be used to render. --- include/render/wlr_renderer.h | 6 ++++++ include/wlr/render/egl.h | 6 ++++++ include/wlr/render/interface.h | 2 ++ render/egl.c | 12 ++++++++++++ render/gles2/renderer.c | 7 +++++++ render/wlr_renderer.c | 8 ++++++++ 6 files changed, 41 insertions(+) diff --git a/include/render/wlr_renderer.h b/include/render/wlr_renderer.h index 0ef1ef82f..8e113ac8b 100644 --- a/include/render/wlr_renderer.h +++ b/include/render/wlr_renderer.h @@ -4,5 +4,11 @@ #include bool wlr_renderer_bind_buffer(struct wlr_renderer *r, struct wlr_buffer *buffer); +/** + * Get the DMA-BUF formats supporting rendering usage. Buffers allocated with + * a format from this list may be attached via wlr_renderer_bind_buffer. + */ +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_render_formats( + struct wlr_renderer *renderer); #endif diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 4ab672d3a..f2d04049a 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -78,6 +78,7 @@ struct wlr_egl { struct wl_display *wl_display; struct wlr_drm_format_set dmabuf_formats; + struct wlr_drm_format_set dmabuf_render_formats; EGLBoolean **external_only_dmabuf_formats; }; @@ -126,6 +127,11 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, * Get DMA-BUF formats suitable for sampling usage. */ const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl); +/** + * Get DMA-BUF formats suitable for rendering usage. + */ +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats( + struct wlr_egl *egl); bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, int32_t width, int32_t height, uint32_t flags, diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 625ab1981..44b5a48c9 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -52,6 +52,8 @@ struct wlr_renderer_impl { struct wl_resource *buffer, int *width, int *height); const struct wlr_drm_format_set *(*get_dmabuf_formats)( struct wlr_renderer *renderer); + const struct wlr_drm_format_set *(*get_dmabuf_render_formats)( + struct wlr_renderer *renderer); enum wl_shm_format (*preferred_read_format)(struct wlr_renderer *renderer); bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, diff --git a/render/egl.c b/render/egl.c index 6382c0c34..2180c7a13 100644 --- a/render/egl.c +++ b/render/egl.c @@ -158,10 +158,16 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { if (modifiers_len == 0) { wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, DRM_FORMAT_MOD_INVALID); + wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, + DRM_FORMAT_MOD_INVALID); } for (int j = 0; j < modifiers_len; j++) { wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, modifiers[j]); + if (!external_only[j]) { + wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, + modifiers[j]); + } } free(modifiers); @@ -397,6 +403,7 @@ void wlr_egl_finish(struct wlr_egl *egl) { } free(egl->external_only_dmabuf_formats); + wlr_drm_format_set_finish(&egl->dmabuf_render_formats); wlr_drm_format_set_finish(&egl->dmabuf_formats); eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -809,6 +816,11 @@ const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl) return &egl->dmabuf_formats; } +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats( + struct wlr_egl *egl) { + return &egl->dmabuf_render_formats; +} + bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, int32_t width, int32_t height, uint32_t flags, struct wlr_dmabuf_attributes *attribs) { diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index fbf27e498..e5bdcd756 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -435,6 +435,12 @@ static const struct wlr_drm_format_set *gles2_get_dmabuf_formats( return wlr_egl_get_dmabuf_formats(renderer->egl); } +static const struct wlr_drm_format_set *gles2_get_dmabuf_render_formats( + struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + return wlr_egl_get_dmabuf_render_formats(renderer->egl); +} + static enum wl_shm_format gles2_preferred_read_format( struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = @@ -703,6 +709,7 @@ static const struct wlr_renderer_impl renderer_impl = { .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_formats = gles2_get_dmabuf_formats, + .get_dmabuf_render_formats = gles2_get_dmabuf_render_formats, .preferred_read_format = gles2_preferred_read_format, .read_pixels = gles2_read_pixels, .texture_from_pixels = gles2_texture_from_pixels, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 0fb7fbda1..f366f80ff 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -173,6 +173,14 @@ const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( return r->impl->get_dmabuf_formats(r); } +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_render_formats( + struct wlr_renderer *r) { + if (!r->impl->get_dmabuf_render_formats) { + return NULL; + } + return r->impl->get_dmabuf_render_formats(r); +} + bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, From c0452539276983d93cfd8757f9159d726a2d6f3a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 14:30:29 +0100 Subject: [PATCH 148/223] backend/headless: use a format suitable for rendering When allocating buffers, use a format suitable for rendering. This avoids picking a format that won't work. --- backend/headless/backend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 49780d889..e662d6fab 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -13,6 +13,7 @@ #include "backend/headless.h" #include "render/drm_format_set.h" #include "render/gbm_allocator.h" +#include "render/wlr_renderer.h" #include "util/signal.h" struct wlr_headless_backend *headless_backend_from_backend( @@ -132,12 +133,11 @@ static bool backend_init(struct wlr_headless_backend *backend, backend->allocator = &alloc->base; const struct wlr_drm_format_set *formats = - wlr_renderer_get_dmabuf_formats(backend->renderer); + wlr_renderer_get_dmabuf_render_formats(backend->renderer); if (formats == NULL) { wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer"); return false; } - // TODO: filter modifiers with external_only=false const struct wlr_drm_format *format = wlr_drm_format_set_get(formats, DRM_FORMAT_XRGB8888); if (format == NULL) { From 49115e9d5d1c9f9c61c4f05c8e7a16191426b21e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 14:53:13 +0100 Subject: [PATCH 149/223] render: rename wlr_renderer_get_dmabuf_formats Rename wlr_renderer_get_dmabuf_formats to wlr_renderer_get_dmabuf_texture_formats. This makes it clear the formats are only suitable for creating wlr_textures. --- include/wlr/render/egl.h | 5 +++-- include/wlr/render/interface.h | 2 +- include/wlr/render/wlr_renderer.h | 2 +- render/egl.c | 19 +++++++++++-------- render/gles2/renderer.c | 6 +++--- render/wlr_renderer.c | 6 +++--- types/wlr_linux_dmabuf_v1.c | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index f2d04049a..e921201a3 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -77,7 +77,7 @@ struct wlr_egl { struct wl_display *wl_display; - struct wlr_drm_format_set dmabuf_formats; + struct wlr_drm_format_set dmabuf_texture_formats; struct wlr_drm_format_set dmabuf_render_formats; EGLBoolean **external_only_dmabuf_formats; }; @@ -126,7 +126,8 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, /** * Get DMA-BUF formats suitable for sampling usage. */ -const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl); +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats( + struct wlr_egl *egl); /** * Get DMA-BUF formats suitable for rendering usage. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 44b5a48c9..0b364995d 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -50,7 +50,7 @@ struct wlr_renderer_impl { struct wl_resource *resource); void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer, struct wl_resource *buffer, int *width, int *height); - const struct wlr_drm_format_set *(*get_dmabuf_formats)( + const struct wlr_drm_format_set *(*get_dmabuf_texture_formats)( struct wlr_renderer *renderer); const struct wlr_drm_format_set *(*get_dmabuf_render_formats)( struct wlr_renderer *renderer); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index c992ded5c..6c6853cab 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -102,7 +102,7 @@ void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer, * Get the DMA-BUF formats supporting sampling usage. Buffers allocated with * a format from this list may be imported via wlr_texture_from_dmabuf. */ -const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats( struct wlr_renderer *renderer); /** * Reads out of pixels of the currently bound surface into data. `stride` is in diff --git a/render/egl.c b/render/egl.c index 2180c7a13..ff6b916de 100644 --- a/render/egl.c +++ b/render/egl.c @@ -157,13 +157,15 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { } if (modifiers_len == 0) { - wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, DRM_FORMAT_MOD_INVALID); + wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, + DRM_FORMAT_MOD_INVALID); wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, DRM_FORMAT_MOD_INVALID); } for (int j = 0; j < modifiers_len; j++) { - wlr_drm_format_set_add(&egl->dmabuf_formats, fmt, modifiers[j]); + wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, + modifiers[j]); if (!external_only[j]) { wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, modifiers[j]); @@ -398,13 +400,13 @@ void wlr_egl_finish(struct wlr_egl *egl) { return; } - for (size_t i = 0; i < egl->dmabuf_formats.len; i++) { + for (size_t i = 0; i < egl->dmabuf_texture_formats.len; i++) { free(egl->external_only_dmabuf_formats[i]); } free(egl->external_only_dmabuf_formats); wlr_drm_format_set_finish(&egl->dmabuf_render_formats); - wlr_drm_format_set_finish(&egl->dmabuf_formats); + wlr_drm_format_set_finish(&egl->dmabuf_texture_formats); eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display) { @@ -605,8 +607,8 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, static bool dmabuf_format_is_external_only(struct wlr_egl *egl, uint32_t format, uint64_t modifier) { - for (size_t i = 0; i < egl->dmabuf_formats.len; i++) { - struct wlr_drm_format *fmt = egl->dmabuf_formats.formats[i]; + for (size_t i = 0; i < egl->dmabuf_texture_formats.len; i++) { + struct wlr_drm_format *fmt = egl->dmabuf_texture_formats.formats[i]; if (fmt->format == format) { if (egl->external_only_dmabuf_formats[i] == NULL) { break; @@ -812,8 +814,9 @@ static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, return num; } -const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl) { - return &egl->dmabuf_formats; +const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats( + struct wlr_egl *egl) { + return &egl->dmabuf_texture_formats; } const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats( diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index e5bdcd756..28a24087d 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -429,10 +429,10 @@ static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer, buffer, EGL_HEIGHT, height); } -static const struct wlr_drm_format_set *gles2_get_dmabuf_formats( +static const struct wlr_drm_format_set *gles2_get_dmabuf_texture_formats( struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); - return wlr_egl_get_dmabuf_formats(renderer->egl); + return wlr_egl_get_dmabuf_texture_formats(renderer->egl); } static const struct wlr_drm_format_set *gles2_get_dmabuf_render_formats( @@ -708,7 +708,7 @@ static const struct wlr_renderer_impl renderer_impl = { .formats = gles2_renderer_formats, .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, - .get_dmabuf_formats = gles2_get_dmabuf_formats, + .get_dmabuf_texture_formats = gles2_get_dmabuf_texture_formats, .get_dmabuf_render_formats = gles2_get_dmabuf_render_formats, .preferred_read_format = gles2_preferred_read_format, .read_pixels = gles2_read_pixels, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index f366f80ff..18d6c928f 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -165,12 +165,12 @@ void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *r, return r->impl->wl_drm_buffer_get_size(r, buffer, width, height); } -const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats( +const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats( struct wlr_renderer *r) { - if (!r->impl->get_dmabuf_formats) { + if (!r->impl->get_dmabuf_texture_formats) { return NULL; } - return r->impl->get_dmabuf_formats(r); + return r->impl->get_dmabuf_texture_formats(r); } const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_render_formats( diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index acd4cb4c9..87fe3a7c8 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -389,7 +389,7 @@ static void linux_dmabuf_send_formats(struct wlr_linux_dmabuf_v1 *linux_dmabuf, struct wl_resource *resource, uint32_t version) { uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID; const struct wlr_drm_format_set *formats = - wlr_renderer_get_dmabuf_formats(linux_dmabuf->renderer); + wlr_renderer_get_dmabuf_texture_formats(linux_dmabuf->renderer); if (formats == NULL) { return; } From c94ab99ae26f4d5459b061bfb8ac17261afdc6a7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 14:57:53 +0100 Subject: [PATCH 150/223] render: rename wlr_renderer_get_formats Rename wlr_renderer_get_formats to wlr_renderer_get_shm_texture_formats. This makes it clear those formats are only suitable for shm import. --- include/wlr/render/interface.h | 2 +- include/wlr/render/wlr_renderer.h | 4 ++-- render/gles2/renderer.c | 4 ++-- render/wlr_renderer.c | 9 +++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 0b364995d..3ce91d326 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -44,7 +44,7 @@ struct wlr_renderer_impl { const float color[static 4], const float matrix[static 9]); void (*render_ellipse_with_matrix)(struct wlr_renderer *renderer, const float color[static 4], const float matrix[static 9]); - const enum wl_shm_format *(*formats)( + const enum wl_shm_format *(*get_shm_texture_formats)( struct wlr_renderer *renderer, size_t *len); bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer, struct wl_resource *resource); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 6c6853cab..fecc1a13a 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -86,8 +86,8 @@ void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, * Get the shared-memory formats supporting import usage. Buffers allocated * with a format from this list may be imported via wlr_texture_from_pixels. */ -const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r, - size_t *len); +const enum wl_shm_format *wlr_renderer_get_shm_texture_formats( + struct wlr_renderer *r, size_t *len); /** * Returns true if this wl_buffer is a wl_drm buffer. */ diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 28a24087d..c90108fbf 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -396,7 +396,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, pop_gles2_debug(renderer); } -static const enum wl_shm_format *gles2_renderer_formats( +static const enum wl_shm_format *gles2_get_shm_texture_formats( struct wlr_renderer *wlr_renderer, size_t *len) { return get_gles2_wl_formats(len); } @@ -705,7 +705,7 @@ static const struct wlr_renderer_impl renderer_impl = { .render_subtexture_with_matrix = gles2_render_subtexture_with_matrix, .render_quad_with_matrix = gles2_render_quad_with_matrix, .render_ellipse_with_matrix = gles2_render_ellipse_with_matrix, - .formats = gles2_renderer_formats, + .get_shm_texture_formats = gles2_get_shm_texture_formats, .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_texture_formats = gles2_get_dmabuf_texture_formats, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 18d6c928f..62ae94747 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -17,7 +17,7 @@ void wlr_renderer_init(struct wlr_renderer *renderer, assert(impl->render_subtexture_with_matrix); assert(impl->render_quad_with_matrix); assert(impl->render_ellipse_with_matrix); - assert(impl->formats); + assert(impl->get_shm_texture_formats); assert(impl->texture_from_pixels); renderer->impl = impl; @@ -144,9 +144,9 @@ void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, r->impl->render_ellipse_with_matrix(r, color, matrix); } -const enum wl_shm_format *wlr_renderer_get_formats( +const enum wl_shm_format *wlr_renderer_get_shm_texture_formats( struct wlr_renderer *r, size_t *len) { - return r->impl->formats(r, len); + return r->impl->get_shm_texture_formats(r, len); } bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *r, @@ -210,7 +210,8 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, } size_t len; - const enum wl_shm_format *formats = wlr_renderer_get_formats(r, &len); + const enum wl_shm_format *formats = + wlr_renderer_get_shm_texture_formats(r, &len); if (formats == NULL) { wlr_log(WLR_ERROR, "Failed to initialize shm: cannot get formats"); return false; From 1f15dd093d8986c783877bdfb25221f67979cad2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 15:01:13 +0100 Subject: [PATCH 151/223] render: assert {X,A}RGB8888 are supported The Wayland protocol requires those to be supported. --- render/wlr_renderer.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 62ae94747..3703f4191 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -217,13 +217,22 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, return false; } + bool argb8888 = false, xrgb8888 = false; for (size_t i = 0; i < len; ++i) { - // These formats are already added by default - if (formats[i] != WL_SHM_FORMAT_ARGB8888 && - formats[i] != WL_SHM_FORMAT_XRGB8888) { + // ARGB8888 and XRGB8888 must be supported and are implicitly + // advertised by wl_display_init_shm + switch (formats[i]) { + case WL_SHM_FORMAT_ARGB8888: + argb8888 = true; + break; + case WL_SHM_FORMAT_XRGB8888: + xrgb8888 = true; + break; + default: wl_display_add_shm_format(wl_display, formats[i]); } } + assert(argb8888 && xrgb8888); if (r->impl->init_wl_display) { if (!r->impl->init_wl_display(r, wl_display)) { From 83a5d03bf361ab9ffa29fb2b809a8e81c4a75d0f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 30 Nov 2020 10:56:24 +0100 Subject: [PATCH 152/223] render/egl: remove wlr_egl.external_only_dmabuf_formats Replace it with wlr_egl.dmabuf_render_formats. --- include/wlr/render/egl.h | 1 - render/egl.c | 38 +------------------------------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index e921201a3..114dd9c78 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -79,7 +79,6 @@ struct wlr_egl { struct wlr_drm_format_set dmabuf_texture_formats; struct wlr_drm_format_set dmabuf_render_formats; - EGLBoolean **external_only_dmabuf_formats; }; // TODO: Allocate and return a wlr_egl diff --git a/render/egl.c b/render/egl.c index ff6b916de..2b8995937 100644 --- a/render/egl.c +++ b/render/egl.c @@ -138,13 +138,6 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { return; } - egl->external_only_dmabuf_formats = calloc(formats_len, sizeof(EGLBoolean *)); - if (egl->external_only_dmabuf_formats == NULL) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - goto out; - } - - size_t external_formats_len = 0; for (int i = 0; i < formats_len; i++) { uint32_t fmt = formats[i]; @@ -173,9 +166,6 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { } free(modifiers); - - egl->external_only_dmabuf_formats[external_formats_len] = external_only; - external_formats_len++; } char *str_formats = malloc(formats_len * 5 + 1); @@ -400,11 +390,6 @@ void wlr_egl_finish(struct wlr_egl *egl) { return; } - for (size_t i = 0; i < egl->dmabuf_texture_formats.len; i++) { - free(egl->external_only_dmabuf_formats[i]); - } - free(egl->external_only_dmabuf_formats); - wlr_drm_format_set_finish(&egl->dmabuf_render_formats); wlr_drm_format_set_finish(&egl->dmabuf_texture_formats); @@ -605,27 +590,6 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGL_WAYLAND_BUFFER_WL, data, attribs); } -static bool dmabuf_format_is_external_only(struct wlr_egl *egl, - uint32_t format, uint64_t modifier) { - for (size_t i = 0; i < egl->dmabuf_texture_formats.len; i++) { - struct wlr_drm_format *fmt = egl->dmabuf_texture_formats.formats[i]; - if (fmt->format == format) { - if (egl->external_only_dmabuf_formats[i] == NULL) { - break; - } - for (size_t j = 0; j < fmt->len; j++) { - if (fmt->modifiers[j] == modifier) { - return egl->external_only_dmabuf_formats[i][j]; - } - } - break; - } - } - // No info, we're doomed. Choose GL_TEXTURE_EXTERNAL_OES and hope for the - // best. - return true; -} - EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes, bool *external_only) { if (!egl->exts.image_base_khr || !egl->exts.image_dmabuf_import_ext) { @@ -715,7 +679,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, return EGL_NO_IMAGE_KHR; } - *external_only = dmabuf_format_is_external_only(egl, + *external_only = !wlr_drm_format_set_has(&egl->dmabuf_render_formats, attributes->format, attributes->modifier); return image; } From d2329ac07a45c4c3b45c68e24f39456bfc2822fd Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Fri, 27 Nov 2020 14:16:23 +0100 Subject: [PATCH 153/223] xwm: add wlr_xwayland_surface_restack() --- include/wlr/xwayland.h | 8 ++++++++ xwayland/xwm.c | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 8de9ed07e..5488971a5 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -252,6 +252,14 @@ void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland, void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *surface, bool activated); +/** + * Restack surface relative to sibling. + * If sibling is NULL, then the surface is moved to the top or the bottom + * of the stack (depending on the mode). + */ +void wlr_xwayland_surface_restack(struct wlr_xwayland_surface *surface, + struct wlr_xwayland_surface *sibling, enum xcb_stack_mode_t mode); + void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *surface, int16_t x, int16_t y, uint16_t width, uint16_t height); diff --git a/xwayland/xwm.c b/xwayland/xwm.c index fefba7fcc..f258ab008 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1548,6 +1548,23 @@ void wlr_xwayland_surface_activate(struct wlr_xwayland_surface *xsurface, } } +void wlr_xwayland_surface_restack(struct wlr_xwayland_surface *surface, + struct wlr_xwayland_surface *sibling, enum xcb_stack_mode_t mode) { + struct wlr_xwm *xwm = surface->xwm; + uint32_t values[2]; + size_t idx = 0; + uint32_t flags = XCB_CONFIG_WINDOW_STACK_MODE; + + if (sibling != NULL) { + values[idx++] = sibling->window_id; + flags |= XCB_CONFIG_WINDOW_SIBLING; + } + values[idx++] = mode; + + xcb_configure_window(xwm->xcb_conn, surface->window_id, flags, values); + xcb_flush(xwm->xcb_conn); +} + void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface, int16_t x, int16_t y, uint16_t width, uint16_t height) { xsurface->x = x; From 2649600fa11c43c0401a2aaa93472345599de78a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 30 Nov 2020 11:54:56 +0100 Subject: [PATCH 154/223] backend/drm: rotation is a plane property "rotation" is a plane property, it's not a CRTC property. It was also missing from plane_info. --- backend/drm/properties.c | 2 +- include/backend/drm/properties.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 0fafca7b7..8fedac486 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -35,7 +35,6 @@ static const struct prop_info crtc_info[] = { { "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) }, { "MODE_ID", INDEX(mode_id) }, { "VRR_ENABLED", INDEX(vrr_enabled) }, - { "rotation", INDEX(rotation) }, { "scaling mode", INDEX(scaling_mode) }, #undef INDEX }; @@ -53,6 +52,7 @@ static const struct prop_info plane_info[] = { { "SRC_W", INDEX(src_w) }, { "SRC_X", INDEX(src_x) }, { "SRC_Y", INDEX(src_y) }, + { "rotation", INDEX(rotation) }, { "type", INDEX(type) }, #undef INDEX }; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index fba444aa2..914bcefaa 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -28,7 +28,6 @@ union wlr_drm_connector_props { union wlr_drm_crtc_props { struct { // Neither of these are guaranteed to exist - uint32_t rotation; uint32_t scaling_mode; uint32_t vrr_enabled; uint32_t gamma_lut; From de9ff46629fcf3b46252655c5d14ca068c51b46a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 30 Nov 2020 11:56:24 +0100 Subject: [PATCH 155/223] backend/drm: "scaling mode" is a connector property It's not a CRTC property. Remove it altogether since it's unused. --- backend/drm/properties.c | 1 - include/backend/drm/properties.h | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 8fedac486..de51a3dea 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -35,7 +35,6 @@ static const struct prop_info crtc_info[] = { { "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) }, { "MODE_ID", INDEX(mode_id) }, { "VRR_ENABLED", INDEX(vrr_enabled) }, - { "scaling mode", INDEX(scaling_mode) }, #undef INDEX }; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 914bcefaa..c2027c4f3 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -28,7 +28,6 @@ union wlr_drm_connector_props { union wlr_drm_crtc_props { struct { // Neither of these are guaranteed to exist - uint32_t scaling_mode; uint32_t vrr_enabled; uint32_t gamma_lut; uint32_t gamma_lut_size; From 8bc5a92a98ca5b788cd4f426ad2605da265ef422 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 30 Nov 2020 16:19:01 +0100 Subject: [PATCH 156/223] Revert "backend/drm: stop force-probing connectors" This reverts commit 713c1661b742f93a7d2167321837c0d99541ca87. It turns out we do need to force-probe on startup and on hotplug [1]. This is unfortunate, but that's just how the uAPI works. Fixing this would require patching the kernel. [1]: https://lists.freedesktop.org/archives/dri-devel/2020-November/289506.html Closes: https://github.com/swaywm/wlroots/issues/2499 --- backend/drm/drm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index de505376e..f797dd5ad 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1282,8 +1282,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { struct wlr_drm_connector *new_outputs[res->count_connectors + 1]; for (int i = 0; i < res->count_connectors; ++i) { - drmModeConnector *drm_conn = - drmModeGetConnectorCurrent(drm->fd, res->connectors[i]); + drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, + res->connectors[i]); if (!drm_conn) { wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); continue; From 50b5f8558eb1a6b1fb7bc9dc3fbba4f7fb109bc2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Dec 2020 11:46:12 +0100 Subject: [PATCH 157/223] xwayland: add -core to flags Xwayland has its own special handling for signals like SIGSEGV/SIGABRT. Instead of leaving the job to the OS, it tries to walk up the call stack (badly, because a lot of information is missing), print the stack trace to stdout, then exit(1). This is very annoying because it prevents Xwayland crashes from being easily debugged. Xwayland has a flag "-core" that aborts instead of exiting. This allows the OS to generate a coredump. It's far from perfect but better than nothing, I guess. --- xwayland/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwayland/server.c b/xwayland/server.c index d0057c66a..e022f8711 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -61,7 +61,7 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { char *argv[] = { "Xwayland", NULL /* display, e.g. :1 */, - "-rootless", "-terminate", + "-rootless", "-terminate", "-core", "-listen", NULL /* x_fd[0] */, "-listen", NULL /* x_fd[1] */, "-wm", NULL /* wm_fd[1] */, @@ -89,7 +89,7 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { snprintf(wayland_socket_str, sizeof(wayland_socket_str), "%d", server->wl_fd[1]); setenv("WAYLAND_SOCKET", wayland_socket_str, true); - wlr_log(WLR_INFO, "WAYLAND_SOCKET=%d Xwayland :%d -rootless -terminate -listen %d -listen %d -wm %d", + wlr_log(WLR_INFO, "WAYLAND_SOCKET=%d Xwayland :%d -rootless -terminate -core -listen %d -listen %d -wm %d", server->wl_fd[1], server->display, server->x_fd[0], server->x_fd[1], server->wm_fd[1]); From 513eca8dabe1b98f6169a0afa046825daa2c76ea Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 3 Dec 2020 00:05:38 +0100 Subject: [PATCH 158/223] build: add leftover WLR_HAS_LIBCAP We don't support libcap anymore. This was left as a comment by Meson: /* #undef WLR_HAS_LIBCAP */ --- include/wlr/config.h.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index cd42987b2..c139a4d61 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -1,8 +1,6 @@ #ifndef WLR_CONFIG_H #define WLR_CONFIG_H -#mesondefine WLR_HAS_LIBCAP - #mesondefine WLR_HAS_SYSTEMD #mesondefine WLR_HAS_ELOGIND From 237c2cf2fbe6056382077456646916f04140f49b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Nov 2020 15:30:23 +0100 Subject: [PATCH 159/223] backend/drm: take a wlr_drm_format in init_drm_surface Instead of taking a format code and wlr_drm_format_set, simplify the function signature and take a single wlr_drm_format. --- backend/drm/renderer.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index c9f0e6f02..fb915fbe3 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -77,7 +77,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) { static bool init_drm_surface(struct wlr_drm_surface *surf, struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, - uint32_t format, const struct wlr_drm_format_set *set, uint32_t flags) { + const struct wlr_drm_format *drm_format, uint32_t flags) { if (surf->width == width && surf->height == height) { return true; } @@ -91,21 +91,13 @@ static bool init_drm_surface(struct wlr_drm_surface *surf, wlr_swapchain_destroy(surf->swapchain); surf->swapchain = NULL; - const struct wlr_drm_format *drm_format = NULL; - const struct wlr_drm_format format_no_modifiers = { .format = format }; - if (set != NULL) { - drm_format = wlr_drm_format_set_get(set, format); - } else { - drm_format = &format_no_modifiers; - } - struct wlr_drm_format *format_linear = NULL; if (flags & GBM_BO_USE_LINEAR) { format_linear = calloc(1, sizeof(struct wlr_drm_format) + sizeof(uint64_t)); if (format_linear == NULL) { return false; } - format_linear->format = format; + format_linear->format = drm_format->format; format_linear->len = 1; format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; drm_format = format_linear; @@ -253,25 +245,28 @@ bool drm_plane_init_surface(struct wlr_drm_plane *plane, return false; } - struct wlr_drm_format_set *format_set = - with_modifiers ? &plane->formats : NULL; + const struct wlr_drm_format *drm_format = NULL; + const struct wlr_drm_format format_no_modifiers = { .format = format }; + if (with_modifiers) { + drm_format = wlr_drm_format_set_get(&plane->formats, format); + } else { + drm_format = &format_no_modifiers; + } drm_plane_finish_surface(plane); if (!drm->parent) { return init_drm_surface(&plane->surf, &drm->renderer, width, height, - format, format_set, flags | GBM_BO_USE_SCANOUT); + drm_format, flags | GBM_BO_USE_SCANOUT); } if (!init_drm_surface(&plane->surf, &drm->parent->renderer, - width, height, format, NULL, - flags | GBM_BO_USE_LINEAR)) { + width, height, drm_format, flags | GBM_BO_USE_LINEAR)) { return false; } if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer, - width, height, format, format_set, - flags | GBM_BO_USE_SCANOUT)) { + width, height, drm_format, flags | GBM_BO_USE_SCANOUT)) { finish_drm_surface(&plane->surf); return false; } From 82443ea46b32111744aa62a42a24312027e512f8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Nov 2020 15:58:37 +0100 Subject: [PATCH 160/223] render/drm_format_set: introduce wlr_drm_format_intersect Intersects modifiers from two wlr_drm_format structs. If either format doesn't support modifiers, the resulting format won't support modifiers. --- include/render/drm_format_set.h | 9 +++++++++ render/drm_format_set.c | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/render/drm_format_set.h b/include/render/drm_format_set.h index ae1fcc472..78b70e9b6 100644 --- a/include/render/drm_format_set.h +++ b/include/render/drm_format_set.h @@ -4,5 +4,14 @@ #include struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format); +/** + * Intersect modifiers for two DRM formats. + * + * Both arguments must have the same format field. If the formats aren't + * compatible, NULL is returned. If either format doesn't support any modifier, + * a format that doesn't support any modifier is returned. + */ +struct wlr_drm_format *wlr_drm_format_intersect( + const struct wlr_drm_format *a, const struct wlr_drm_format *b); #endif diff --git a/render/drm_format_set.c b/render/drm_format_set.c index 54fc8ae10..d6be706d3 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -137,3 +137,39 @@ struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { memcpy(duped_format, format, format_size); return duped_format; } + +struct wlr_drm_format *wlr_drm_format_intersect( + const struct wlr_drm_format *a, const struct wlr_drm_format *b) { + assert(a->format == b->format); + + size_t format_cap = a->len < b->len ? a->len : b->len; + size_t format_size = sizeof(struct wlr_drm_format) + + format_cap * sizeof(a->modifiers[0]); + struct wlr_drm_format *format = calloc(1, format_size); + if (format == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + format->format = a->format; + format->cap = format_cap; + + for (size_t i = 0; i < a->len; i++) { + for (size_t j = 0; j < b->len; j++) { + if (a->modifiers[i] == b->modifiers[j]) { + assert(format->len < format->cap); + format->modifiers[format->len] = a->modifiers[i]; + format->len++; + break; + } + } + } + + // If both formats support modifiers, but the intersection is empty, then + // the formats aren't compatible with each other + if (format->len == 0 && a->len > 0 && b->len > 0) { + free(format); + return NULL; + } + + return format; +} From 0e927533b007959a13f81107babc00fe5272871b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 25 Nov 2020 16:24:07 +0100 Subject: [PATCH 161/223] backend/drm: query render formats On some platforms it's possible that the display engine supports modifiers not supported by the render engine. Query render formats and intersect them with plane formats to accommodate for this. --- backend/drm/renderer.c | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index fb915fbe3..7f6fe62d5 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -12,6 +12,7 @@ #include #include #include "backend/drm/drm.h" +#include "render/drm_format_set.h" #include "render/gbm_allocator.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" @@ -239,39 +240,61 @@ bool drm_plane_init_surface(struct wlr_drm_plane *plane, if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) { format = strip_alpha_channel(format); } - if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) { + const struct wlr_drm_format *plane_format = + wlr_drm_format_set_get(&plane->formats, format); + if (plane_format == NULL) { wlr_log(WLR_ERROR, "Plane %"PRIu32" doesn't support format 0x%"PRIX32, plane->id, format); return false; } - const struct wlr_drm_format *drm_format = NULL; - const struct wlr_drm_format format_no_modifiers = { .format = format }; + const struct wlr_drm_format_set *render_formats = + wlr_renderer_get_dmabuf_render_formats(drm->renderer.wlr_rend); + if (render_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get render formats"); + return false; + } + const struct wlr_drm_format *render_format = + wlr_drm_format_set_get(render_formats, format); + if (render_format == NULL) { + wlr_log(WLR_ERROR, "Renderer doesn't support format 0x%"PRIX32, + format); + return false; + } + + struct wlr_drm_format *drm_format = NULL; if (with_modifiers) { - drm_format = wlr_drm_format_set_get(&plane->formats, format); + drm_format = wlr_drm_format_intersect(plane_format, render_format); + if (drm_format == NULL) { + wlr_log(WLR_ERROR, + "Failed to intersect plane and render formats 0x%"PRIX32, + format); + return false; + } } else { - drm_format = &format_no_modifiers; + const struct wlr_drm_format format_no_modifiers = { .format = format }; + drm_format = wlr_drm_format_dup(&format_no_modifiers); } drm_plane_finish_surface(plane); + bool ok = true; if (!drm->parent) { - return init_drm_surface(&plane->surf, &drm->renderer, width, height, + ok = init_drm_surface(&plane->surf, &drm->renderer, width, height, drm_format, flags | GBM_BO_USE_SCANOUT); + } else { + ok = init_drm_surface(&plane->surf, &drm->parent->renderer, + width, height, drm_format, flags | GBM_BO_USE_LINEAR); + if (ok && !init_drm_surface(&plane->mgpu_surf, &drm->renderer, + width, height, drm_format, flags | GBM_BO_USE_SCANOUT)) { + finish_drm_surface(&plane->surf); + ok = false; + } } - if (!init_drm_surface(&plane->surf, &drm->parent->renderer, - width, height, drm_format, flags | GBM_BO_USE_LINEAR)) { - return false; - } + free(drm_format); - if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer, - width, height, drm_format, flags | GBM_BO_USE_SCANOUT)) { - finish_drm_surface(&plane->surf); - return false; - } - - return true; + return ok; } void drm_fb_clear(struct wlr_drm_fb *fb) { From 1336ad2a23bfe5a76c161c5985d99e6f4b127931 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 19:34:35 +0100 Subject: [PATCH 162/223] backend/drm: remove unused if in drm_connector_move_cursor We return early if we don't have a plane. --- backend/drm/drm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index f797dd5ad..7c88fd9e4 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1008,10 +1008,8 @@ static bool drm_connector_move_cursor(struct wlr_output *output, wlr_output_transform_invert(output->transform); wlr_box_transform(&box, &box, transform, width, height); - if (plane != NULL) { - box.x -= plane->cursor_hotspot_x; - box.y -= plane->cursor_hotspot_y; - } + box.x -= plane->cursor_hotspot_x; + box.y -= plane->cursor_hotspot_y; conn->cursor_x = box.x; conn->cursor_y = box.y; From 90c8452959470461497c4a83aac0bd93efb0a524 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 20:04:53 +0100 Subject: [PATCH 163/223] backend/session/libseat: set XDG_SESSION_TYPE libseat will call logind's SetType method if necessary. --- backend/session/libseat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/session/libseat.c b/backend/session/libseat.c index f3ad789cd..ccbc77bdd 100644 --- a/backend/session/libseat.c +++ b/backend/session/libseat.c @@ -97,6 +97,9 @@ static struct wlr_session *libseat_session_create(struct wl_display *disp) { libseat_set_log_handler(log_libseat); libseat_set_log_level(LIBSEAT_LOG_LEVEL_ERROR); + // libseat will take care of updating the logind state if necessary + setenv("XDG_SESSION_TYPE", "wayland", 1); + session->seat = libseat_open_seat(&seat_listener, session); if (session->seat == NULL) { wlr_log_errno(WLR_ERROR, "Unable to create seat"); From 1477401acd327ddbe56e412c79a0e666fedb5cc3 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 5 Dec 2020 00:01:29 +0100 Subject: [PATCH 164/223] screencopy: handle compositor not setting damage Damage the full output if the compositor didn't submit damage but did submit a buffer. --- types/wlr_screencopy_v1.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 2d81ff7be..59cd5b9db 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -48,9 +48,20 @@ static void screencopy_damage_accumulate(struct screencopy_damage *damage) { return; } - pixman_region32_union(region, region, &output->pending.damage); - pixman_region32_intersect_rect(region, region, 0, 0, output->width, - output->height); + // If the compositor did not submit damage but did submit a buffer, + if (!(output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) && + (output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { + // damage everything + int width, height; + wlr_output_transformed_resolution(output, &width, &height); + pixman_region32_union_rect(region, region, 0, 0, width, height); + } else { + // otherwise copy over the current damage + pixman_region32_union(region, region, &output->pending.damage); + pixman_region32_intersect_rect(region, region, 0, 0, output->width, + output->height); + } + damage->last_commit_seq = output->commit_seq; } From 1ecc1b5987907f6fc32dcb3da5adf797bd498ef6 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 6 Dec 2020 16:51:40 +0100 Subject: [PATCH 165/223] screencopy: use output transform for damage copy --- types/wlr_screencopy_v1.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 59cd5b9db..4444b8c0a 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -48,18 +48,18 @@ static void screencopy_damage_accumulate(struct screencopy_damage *damage) { return; } + int width, height; + wlr_output_transformed_resolution(output, &width, &height); + // If the compositor did not submit damage but did submit a buffer, if (!(output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) && (output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { // damage everything - int width, height; - wlr_output_transformed_resolution(output, &width, &height); pixman_region32_union_rect(region, region, 0, 0, width, height); } else { // otherwise copy over the current damage pixman_region32_union(region, region, &output->pending.damage); - pixman_region32_intersect_rect(region, region, 0, 0, output->width, - output->height); + pixman_region32_intersect_rect(region, region, 0, 0, width, height); } damage->last_commit_seq = output->commit_seq; From 37cb3eb8ddbc264560757d538fe6710ac8784721 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 6 Dec 2020 16:58:52 +0100 Subject: [PATCH 166/223] screencopy: check if damage committed before copy This check avoids copying stale state from output->pending.damage. --- types/wlr_screencopy_v1.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index 4444b8c0a..b4d47fbdb 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -51,15 +51,14 @@ static void screencopy_damage_accumulate(struct screencopy_damage *damage) { int width, height; wlr_output_transformed_resolution(output, &width, &height); - // If the compositor did not submit damage but did submit a buffer, - if (!(output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) && - (output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { - // damage everything - pixman_region32_union_rect(region, region, 0, 0, width, height); - } else { - // otherwise copy over the current damage + if (output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { + // If the compositor submitted damage, copy it over pixman_region32_union(region, region, &output->pending.damage); pixman_region32_intersect_rect(region, region, 0, 0, width, height); + } else if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + // If the compositor did not submit damage but did submit a buffer + // damage everything + pixman_region32_union_rect(region, region, 0, 0, width, height); } damage->last_commit_seq = output->commit_seq; From 54b7ca56c06c0a9a658b5aea06605b964e66ca81 Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Sun, 6 Dec 2020 21:27:45 +0100 Subject: [PATCH 167/223] drm: do not unset make/model before emitting destroy event --- backend/drm/drm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7c88fd9e4..6c420b100 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1615,10 +1615,6 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { conn->output.enabled = false; conn->output.width = conn->output.height = conn->output.refresh = 0; - memset(&conn->output.make, 0, sizeof(conn->output.make)); - memset(&conn->output.model, 0, sizeof(conn->output.model)); - memset(&conn->output.serial, 0, sizeof(conn->output.serial)); - if (conn->output.idle_frame != NULL) { wl_event_source_remove(conn->output.idle_frame); conn->output.idle_frame = NULL; @@ -1635,6 +1631,10 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { conn->desired_mode = NULL; conn->pageflip_pending = false; wlr_signal_emit_safe(&conn->output.events.destroy, &conn->output); + + memset(&conn->output.make, 0, sizeof(conn->output.make)); + memset(&conn->output.model, 0, sizeof(conn->output.model)); + memset(&conn->output.serial, 0, sizeof(conn->output.serial)); break; case WLR_DRM_CONN_DISCONNECTED: break; From baf2319fd38659a0ab35e4767e267d32e8c9f150 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 7 Dec 2020 11:02:04 +0100 Subject: [PATCH 168/223] screencopy: don't use output transform for damage copy Only wlr_output_damage works in transformed coordinates, wlr_output->damage is in output-buffer-local coordinates. This essentially reverts 1ecc1b5 and fixes 1477401. --- types/wlr_screencopy_v1.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index b4d47fbdb..6feb07427 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -48,17 +48,16 @@ static void screencopy_damage_accumulate(struct screencopy_damage *damage) { return; } - int width, height; - wlr_output_transformed_resolution(output, &width, &height); - if (output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { // If the compositor submitted damage, copy it over pixman_region32_union(region, region, &output->pending.damage); - pixman_region32_intersect_rect(region, region, 0, 0, width, height); + pixman_region32_intersect_rect(region, region, 0, 0, + output->width, output->height); } else if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { // If the compositor did not submit damage but did submit a buffer // damage everything - pixman_region32_union_rect(region, region, 0, 0, width, height); + pixman_region32_union_rect(region, region, 0, 0, + output->width, output->height); } damage->last_commit_seq = output->commit_seq; From 44b1ff16e9bc9d3a0afc86c1afafd1efcdada806 Mon Sep 17 00:00:00 2001 From: Marten Ringwelski Date: Sat, 5 Dec 2020 14:52:58 +0100 Subject: [PATCH 169/223] wlr-output-management: Handle modes added after initializing The DRM backend adds custom modes to wlr_output.modes Currently modes that are added after the first occurence of wlr_output_configuration_head_v1 are not added to wlr_output_head.mode_resources. --- types/wlr_output_management_v1.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index 312057ed3..ed53171f2 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -819,6 +819,26 @@ static bool manager_update_head(struct wlr_output_manager_v1 *manager, state |= HEAD_STATE_SCALE; } + // If a mode was added to wlr_output.modes we need to add the new mode + // to the wlr_output_head + struct wlr_output_mode *mode; + wl_list_for_each(mode, &head->state.output->modes, link) { + bool found = false; + struct wl_resource *mode_resource; + wl_resource_for_each(mode_resource, &head->mode_resources) { + if (mode_from_resource(mode_resource) == mode) { + found = true; + break; + } + } + if (!found) { + struct wl_resource *resource; + wl_resource_for_each(resource, &head->resources) { + head_send_mode(head, resource, mode); + } + } + } + if (state != 0) { *current = *next; From 037710b1d42864ff1e681580e738c82b005bcbfb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 13:37:36 +0100 Subject: [PATCH 170/223] render/egl: support config-less wlr_egl When using wlr_swapchain, there's no need to select an EGLConfig. Add support for creating config-less EGL contexts. --- render/egl.c | 16 +++++++++++++--- render/wlr_renderer.c | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/render/egl.c b/render/egl.c index 2b8995937..8fe733983 100644 --- a/render/egl.c +++ b/render/egl.c @@ -319,9 +319,19 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(device_exts_str, "EGL_EXT_device_drm"); } - if (!egl_get_config(egl->display, config_attribs, &egl->config, visual_id)) { - wlr_log(WLR_ERROR, "Failed to get EGL config"); - goto error; + if (config_attribs != NULL) { + if (!egl_get_config(egl->display, config_attribs, &egl->config, visual_id)) { + wlr_log(WLR_ERROR, "Failed to get EGL config"); + goto error; + } + } else { + if (!check_egl_ext(display_exts_str, "EGL_KHR_no_config_context") && + !check_egl_ext(display_exts_str, "EGL_MESA_configless_context")) { + wlr_log(WLR_ERROR, "EGL_KHR_no_config_context or " + "EGL_MESA_configless_context not supported"); + goto error; + } + egl->config = EGL_NO_CONFIG_KHR; } wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 3703f4191..b8374be9a 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -268,7 +268,11 @@ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, memcpy(&all_config_attribs[config_attribs_len], gles2_config_attribs, sizeof(gles2_config_attribs)); - if (!wlr_egl_init(egl, platform, remote_display, all_config_attribs, + if (config_attribs != NULL) { + config_attribs = all_config_attribs; + } + + if (!wlr_egl_init(egl, platform, remote_display, config_attribs, visual_id)) { wlr_log(WLR_ERROR, "Could not initialize EGL"); return NULL; From bfb59fd4d7bea25a9b6d4d545fd78ea689a5a108 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 13:42:07 +0100 Subject: [PATCH 171/223] backend/headless: create a config-less EGL context --- backend/headless/backend.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index e662d6fab..3995d1eb0 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -165,22 +165,12 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, return NULL; } - static const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, 0, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_BLUE_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_RED_SIZE, 1, - EGL_NONE, - }; - if (!create_renderer_func) { create_renderer_func = wlr_renderer_autocreate; } struct wlr_renderer *renderer = create_renderer_func(&backend->priv_egl, - EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, - (EGLint*)config_attribs, 0); + EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, NULL, 0); if (!renderer) { wlr_log(WLR_ERROR, "Failed to create renderer"); free(backend); From 325cba6414b34359063b7aa2a9f60304da9afef5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 7 Dec 2020 12:06:38 +0100 Subject: [PATCH 172/223] backend/drm: use EGL_PLATFORM_GBM_KHR This is just the vendor-agnostic define for the GBM platform. It has the same value as EGL_PLATFORM_GBM_MESA, so should work with old drivers that only offer the Mesa-vendored extension too. --- backend/drm/renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7f6fe62d5..8091f27b4 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -42,8 +42,8 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, renderer->gbm_format = GBM_FORMAT_ARGB8888; renderer->wlr_rend = create_renderer_func(&renderer->egl, - EGL_PLATFORM_GBM_MESA, renderer->gbm, - config_attribs, renderer->gbm_format); + EGL_PLATFORM_GBM_KHR, renderer->gbm, config_attribs, + renderer->gbm_format); if (!renderer->wlr_rend) { wlr_log(WLR_ERROR, "Failed to create EGL/WLR renderer"); goto error_gbm; From 431ec52b9c20efae7f50ba5b6fa6a2aa56852ac3 Mon Sep 17 00:00:00 2001 From: Dominik Honnef Date: Mon, 30 Nov 2020 20:41:35 +0100 Subject: [PATCH 173/223] xwayland: use pipe instead of SIGUSR1 to signal readiness Closes: https://github.com/swaywm/wlroots/issues/2154 --- include/wlr/xwayland.h | 5 +--- xwayland/server.c | 63 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 5488971a5..fd14ff254 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -22,7 +22,7 @@ struct wlr_xwayland_cursor; struct wlr_xwayland_server { pid_t pid; struct wl_client *client; - struct wl_event_source *sigusr1_source; + struct wl_event_source *pipe_source; int wm_fd[2], wl_fd[2]; time_t server_start; @@ -236,9 +236,6 @@ void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server); * * The server supports a lazy mode in which Xwayland is only started when a * client tries to connect. - * - * Note: wlr_xwayland will setup a global SIGUSR1 handler on the compositor - * process. */ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, struct wlr_compositor *compositor, bool lazy); diff --git a/xwayland/server.c b/xwayland/server.c index e022f8711..f72b668d4 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -57,6 +57,7 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { } /* Make Xwayland signal us when it's ready */ + /* TODO: can we use -displayfd instead? */ signal(SIGUSR1, SIG_IGN); char *argv[] = { @@ -139,8 +140,8 @@ static void server_finish_process(struct wlr_xwayland_server *server) { wl_list_remove(&server->client_destroy.link); wl_client_destroy(server->client); } - if (server->sigusr1_source) { - wl_event_source_remove(server->sigusr1_source); + if (server->pipe_source) { + wl_event_source_remove(server->pipe_source); } safe_close(server->wl_fd[0]); @@ -184,8 +185,8 @@ static void handle_client_destroy(struct wl_listener *listener, void *data) { struct wlr_xwayland_server *server = wl_container_of(listener, server, client_destroy); - if (server->sigusr1_source) { - // Xwayland failed to start, let the sigusr1 handler deal with it + if (server->pipe_source) { + // Xwayland failed to start, let the readiness handler deal with it return; } @@ -219,7 +220,21 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_xwayland_server_destroy(server); } -static int xserver_handle_ready(int signal_number, void *data) { +static int xserver_handle_ready(int fd, uint32_t mask, void *data) { + // There are three ways in which we can end up here, from server_start: + // 1. the second fork failed + // 2. the exec failed + // 3. Xwayland sent a SIGUSR1 + // + // All three cases result in a write to the pipe, which triggers us. + // + // For the first two cases, the first fork will exit with + // EXIT_FAILURE, notifying us that startup failed. + // + // For the third case, the first fork will exit with EXIT_SUCCESS + // and we'll know that Xwayland started successfully. + + close(fd); struct wlr_xwayland_server *server = data; int stat_val = -1; @@ -236,8 +251,8 @@ static int xserver_handle_ready(int signal_number, void *data) { } wlr_log(WLR_DEBUG, "Xserver is ready"); - wl_event_source_remove(server->sigusr1_source); - server->sigusr1_source = NULL; + wl_event_source_remove(server->pipe_source); + server->pipe_source = NULL; struct wlr_xwayland_server_ready_event event = { .server = server, @@ -310,19 +325,33 @@ static bool server_start(struct wlr_xwayland_server *server) { server->client_destroy.notify = handle_client_destroy; wl_client_add_destroy_listener(server->client, &server->client_destroy); + int p[2]; + if (pipe(p) == -1) { + wlr_log_errno(WLR_ERROR, "pipe failed"); + server_finish_process(server); + return false; + } + if (!set_cloexec(p[1], true) || !set_cloexec(p[0], true)) { + wlr_log(WLR_ERROR, "Failed to set CLOEXEC on FD"); + server_finish_process(server); + return false; + } + struct wl_event_loop *loop = wl_display_get_event_loop(server->wl_display); - server->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1, - xserver_handle_ready, server); + server->pipe_source = wl_event_loop_add_fd(loop, p[0], + WL_EVENT_READABLE, xserver_handle_ready, server); server->pid = fork(); if (server->pid < 0) { wlr_log_errno(WLR_ERROR, "fork failed"); + close(p[0]); + close(p[1]); server_finish_process(server); return false; } else if (server->pid == 0) { /* Double-fork, but we need to forward SIGUSR1 once Xserver(1) * is ready, or error if there was one. */ - pid_t ppid = getppid(); + close(p[0]); sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGUSR1); @@ -332,6 +361,7 @@ static bool server_start(struct wlr_xwayland_server *server) { pid_t pid = fork(); if (pid < 0) { wlr_log_errno(WLR_ERROR, "second fork failed"); + (void)!write(p[1], "\n", 1); _exit(EXIT_FAILURE); } else if (pid == 0) { exec_xwayland(server); @@ -339,8 +369,16 @@ static bool server_start(struct wlr_xwayland_server *server) { int sig; sigwait(&sigset, &sig); - kill(ppid, SIGUSR1); - wlr_log(WLR_DEBUG, "sent SIGUSR1 to process %d", ppid); + if (write(p[1], "\n", 1) < 1) { + // Note: if this write failed and we've leaked the write + // end of the pipe (due to a race between another thread + // exec'ing and our call to fcntl), then our handler will + // never wake up and never notice this failure. Hopefully + // that combination of events is extremely unlikely. This + // applies to the other write, too. + wlr_log_errno(WLR_ERROR, "write to pipe failed"); + _exit(EXIT_FAILURE); + } if (sig == SIGCHLD) { waitpid(pid, NULL, 0); _exit(EXIT_FAILURE); @@ -351,6 +389,7 @@ static bool server_start(struct wlr_xwayland_server *server) { /* close child fds */ /* remain managing x sockets for lazy start */ + close(p[1]); close(server->wl_fd[1]); safe_close(server->wm_fd[1]); server->wl_fd[1] = server->wm_fd[1] = -1; From c9760569ae380d99df4fb9c7d1f00d0c70f9e580 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 7 Dec 2020 20:29:17 +0100 Subject: [PATCH 174/223] docs: fix error in wlr_output_set_damage() comment output-buffer-local coordinates are neither scaled nor transformed --- include/wlr/types/wlr_output.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 8cc4afcf8..0af2c4549 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -349,8 +349,7 @@ bool wlr_output_preferred_read_format(struct wlr_output *output, * the screen that has changed since the last frame. * * Compositors implementing damage tracking should call this function with the - * damaged region in output-buffer-local coordinates (ie. scaled and - * transformed). + * damaged region in output-buffer-local coordinates. * * This region is not to be confused with the renderer's buffer damage, ie. the * region compositors need to repaint. Compositors usually need to repaint more From e69bbfd0d6a654a0421793bf10cb3cab15e13273 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 7 Dec 2020 19:57:12 +0100 Subject: [PATCH 175/223] backend/drm: unset current surface before importing drm_fb_import_wlr may need to change the current EGL context. For instance by calling drm_fb_clear, which calls wlr_buffer_unlock, which may destroy a buffer if the cursor swapchain size has changed, which calls gles2's destroy_buffer, which calls glDeleteFramebuffers. Closes: https://github.com/swaywm/wlroots/issues/2479 --- backend/drm/renderer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 8091f27b4..408effd8a 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -322,12 +322,15 @@ void drm_fb_clear(struct wlr_drm_fb *fb) { bool drm_fb_lock_surface(struct wlr_drm_fb *fb, struct wlr_drm_surface *surf) { assert(surf->back_buffer != NULL); - if (!drm_fb_import_wlr(fb, surf->renderer, surf->back_buffer, NULL)) { - return false; - } + struct wlr_buffer *buffer = wlr_buffer_lock(surf->back_buffer); + // Unset the current EGL context ASAP, because other operations may require + // making another context current. drm_surface_unset_current(surf); - return true; + + bool ok = drm_fb_import_wlr(fb, surf->renderer, buffer, NULL); + wlr_buffer_unlock(buffer); + return ok; } bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer, From 29da97c185c60eae5d9eaf743c3895c4dba139f7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 16:02:44 +0100 Subject: [PATCH 176/223] render/drm_format_set: allocate using cap when duplicating In wlr_drm_format_dup, allocate the new wlr_drm_format using cap instead of len. This makes it so the cap field is up-to-date and the chunk of memory isn't too small if we append new modifiers (we don't allow this yet but might in the future). --- render/drm_format_set.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/drm_format_set.c b/render/drm_format_set.c index d6be706d3..b3e8648ec 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -129,7 +129,7 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { size_t format_size = sizeof(struct wlr_drm_format) + - format->len * sizeof(format->modifiers[0]); + format->cap * sizeof(format->modifiers[0]); struct wlr_drm_format *duped_format = malloc(format_size); if (duped_format == NULL) { return NULL; From 863acb26c0326f6e0ccc6140ba86d41d2b3f09ab Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 6 Dec 2020 17:06:48 +0100 Subject: [PATCH 177/223] backend/drm: stop tracking overlay planes We don't do anything with them. Once we do, we can easily add this back. --- backend/drm/drm.c | 24 +++++++----------------- include/backend/drm/drm.h | 7 ------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 6c420b100..c0186f366 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -197,6 +197,13 @@ static bool init_planes(struct wlr_drm_backend *drm) { goto error; } + // We don't really care about overlay planes, as we don't support them + // yet. + if (type == DRM_PLANE_TYPE_OVERLAY) { + drmModeFreePlane(plane); + continue; + } + /* * This is a very naive implementation of the plane matching * logic. Primary and cursor planes should only work on a @@ -204,10 +211,6 @@ static bool init_planes(struct wlr_drm_backend *drm) { * overlay planes can potentially work with multiple CRTCs, * meaning this could return inefficient/skewed results. * - * However, we don't really care about overlay planes, as we - * don't support them yet. We only bother to keep basic - * tracking of them for DRM lease clients. - * * possible_crtcs is a bitmask of crtcs, where each bit is an * index into drmModeRes.crtcs. So if bit 0 is set (ffs starts * counting from 1), crtc 0 is possible. @@ -218,18 +221,6 @@ static bool init_planes(struct wlr_drm_backend *drm) { assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs); struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit]; - - if (type == DRM_PLANE_TYPE_OVERLAY) { - uint32_t *tmp = realloc(crtc->overlays, - sizeof(*crtc->overlays) * (crtc->num_overlays + 1)); - if (tmp) { - crtc->overlays = tmp; - crtc->overlays[crtc->num_overlays++] = id; - } - drmModeFreePlane(plane); - continue; - } - if (!add_plane(drm, crtc, plane, type, &props)) { drmModeFreePlane(plane); goto error; @@ -314,7 +305,6 @@ void finish_drm_resources(struct wlr_drm_backend *drm) { wlr_drm_format_set_finish(&crtc->cursor->formats); free(crtc->cursor); } - free(crtc->overlays); } free(drm->crtcs); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index f46d565c9..7b53f7fc8 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -63,13 +63,6 @@ struct wlr_drm_crtc { struct wlr_drm_plane *primary; struct wlr_drm_plane *cursor; - /* - * We don't support overlay planes yet, but we keep track of them to - * give to DRM lease clients. - */ - size_t num_overlays; - uint32_t *overlays; - union wlr_drm_crtc_props props; }; From b790e5ea3479b0024c5bdd6ad5ad4f6fa46c89db Mon Sep 17 00:00:00 2001 From: Stephane Chauveau Date: Thu, 16 Jul 2020 18:38:35 +0000 Subject: [PATCH 178/223] backend/drm: don't assume possible_crtcs has only one bit set This isn't necessarily the case [1]. This should fix an assertion failure on Raspberry Pi 4 dual screen. [1]: https://lists.freedesktop.org/archives/dri-devel/2020-August/275142.html Closes: https://github.com/swaywm/wlroots/issues/1943 Co-authored-by: Simon Ser --- backend/drm/drm.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index c0186f366..cbc1ae478 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -204,23 +204,26 @@ static bool init_planes(struct wlr_drm_backend *drm) { continue; } - /* - * This is a very naive implementation of the plane matching - * logic. Primary and cursor planes should only work on a - * single CRTC, and this should be perfectly adequate, but - * overlay planes can potentially work with multiple CRTCs, - * meaning this could return inefficient/skewed results. - * - * possible_crtcs is a bitmask of crtcs, where each bit is an - * index into drmModeRes.crtcs. So if bit 0 is set (ffs starts - * counting from 1), crtc 0 is possible. - */ - int crtc_bit = ffs(plane->possible_crtcs) - 1; + assert(drm->num_crtcs <= 32); + struct wlr_drm_crtc *crtc = NULL; + for (size_t j = 0; j < drm->num_crtcs ; j++) { + uint32_t crtc_bit = 1 << j; + if ((plane->possible_crtcs & crtc_bit) == 0) { + continue; + } - // This would be a kernel bug - assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs); + struct wlr_drm_crtc *candidate = &drm->crtcs[j]; + if ((type == DRM_PLANE_TYPE_PRIMARY && !candidate->primary) || + (type == DRM_PLANE_TYPE_CURSOR && !candidate->cursor)) { + crtc = candidate; + break; + } + } + if (!crtc) { + drmModeFreePlane(plane); + continue; + } - struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit]; if (!add_plane(drm, crtc, plane, type, &props)) { drmModeFreePlane(plane); goto error; From eb5886ddbebd5280b36fff7a5f4a356231b3dba1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 00:12:52 +0100 Subject: [PATCH 179/223] backend/headless: add support for direct scan-out I was about to add a check to fail instead of crash when the compositor uses direct scan-out, but with renderer v6 it's so simple to just add support for direct scan-out, why bother? Closes: https://github.com/swaywm/wlroots/issues/2523 --- backend/headless/output.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/backend/headless/output.c b/backend/headless/output.c index 8ce7a32bd..bb15c23d5 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -91,17 +91,27 @@ static bool output_commit(struct wlr_output *wlr_output) { } if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - assert(output->back_buffer != NULL); + struct wlr_buffer *buffer = NULL; + switch (wlr_output->pending.buffer_type) { + case WLR_OUTPUT_STATE_BUFFER_RENDER: + assert(output->back_buffer != NULL); - wlr_renderer_bind_buffer(output->backend->renderer, NULL); - wlr_egl_unset_current(output->backend->egl); + wlr_renderer_bind_buffer(output->backend->renderer, NULL); + wlr_egl_unset_current(output->backend->egl); + + buffer = output->back_buffer; + output->back_buffer = NULL; + break; + case WLR_OUTPUT_STATE_BUFFER_SCANOUT: + buffer = wlr_buffer_lock(wlr_output->pending.buffer); + break; + } + assert(buffer != NULL); wlr_buffer_unlock(output->front_buffer); - output->front_buffer = output->back_buffer; - output->back_buffer = NULL; + output->front_buffer = buffer; - wlr_swapchain_set_buffer_submitted(output->swapchain, - output->front_buffer); + wlr_swapchain_set_buffer_submitted(output->swapchain, buffer); wlr_output_send_present(wlr_output, NULL); } From 06ab41a160ddac970657254ded4258039fe9d317 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 23:32:04 +0100 Subject: [PATCH 180/223] backend/drm: fix missing wlr_drm_format.cap This caused issues with wlr_drm_format_dup. --- backend/drm/renderer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 408effd8a..d8fef035e 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -100,6 +100,7 @@ static bool init_drm_surface(struct wlr_drm_surface *surf, } format_linear->format = drm_format->format; format_linear->len = 1; + format_linear->cap = 1; format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; drm_format = format_linear; } From 8a6930c138807cb04e2ef738cebe907877eaf292 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 23:35:05 +0100 Subject: [PATCH 181/223] render/drm_format_set: assert len <= cap when duplicating --- render/drm_format_set.c | 1 + 1 file changed, 1 insertion(+) diff --git a/render/drm_format_set.c b/render/drm_format_set.c index b3e8648ec..a4c31494e 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -128,6 +128,7 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, } struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { + assert(format->len <= format->cap); size_t format_size = sizeof(struct wlr_drm_format) + format->cap * sizeof(format->modifiers[0]); struct wlr_drm_format *duped_format = malloc(format_size); From 6ff478632a685c64f9977b83d8555b61700f12be Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 11:46:08 +0100 Subject: [PATCH 182/223] backend/drm: remove EGL config Since we're using wlr_swapchain, we don't need to provide an EGL config. --- backend/drm/drm.c | 2 +- backend/drm/renderer.c | 14 +------------- include/backend/drm/renderer.h | 2 -- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index cbc1ae478..f84f3afe0 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -712,7 +712,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, int width = mode->wlr_mode.width; int height = mode->wlr_mode.height; - uint32_t format = drm->renderer.gbm_format; + uint32_t format = DRM_FORMAT_ARGB8888; bool modifiers = true; const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS"); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index d8fef035e..27cd50f1c 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -30,20 +30,8 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, create_renderer_func = wlr_renderer_autocreate; } - static EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 1, - EGL_NONE, - }; - - renderer->gbm_format = GBM_FORMAT_ARGB8888; renderer->wlr_rend = create_renderer_func(&renderer->egl, - EGL_PLATFORM_GBM_KHR, renderer->gbm, config_attribs, - renderer->gbm_format); + EGL_PLATFORM_GBM_KHR, renderer->gbm, NULL, 0); if (!renderer->wlr_rend) { wlr_log(WLR_ERROR, "Failed to create EGL/WLR renderer"); goto error_gbm; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 7202b0ed0..ec855ab9f 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -17,8 +17,6 @@ struct wlr_drm_renderer { struct gbm_device *gbm; struct wlr_egl egl; - uint32_t gbm_format; - struct wlr_renderer *wlr_rend; struct wlr_gbm_allocator *allocator; }; From be8403e73d01acafbe849d92b19dc6d95c05dde0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 19:32:34 +0100 Subject: [PATCH 183/223] render/gles2: don't eglGetConfigAttrib on EGL_NO_CONFIG_KHR If we don't have an EGL config, don't try to query anything from it. --- render/gles2/renderer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index c90108fbf..bb8dab023 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -453,8 +453,10 @@ static enum wl_shm_format gles2_preferred_read_format( pop_gles2_debug(renderer); EGLint alpha_size = -1; - eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, - EGL_ALPHA_SIZE, &alpha_size); + if (renderer->egl->config != EGL_NO_CONFIG_KHR) { + eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, + EGL_ALPHA_SIZE, &alpha_size); + } const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_gl(gl_format, gl_type, alpha_size > 0); From f91e89fd9f701781ff320f643acdb129ab4f4e55 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Dec 2020 19:37:21 +0100 Subject: [PATCH 184/223] render/gles2: query alpha size from render buffer If we're using a render buffer, query the alpha size from it. Closes: https://github.com/swaywm/wlroots/issues/2527 --- render/gles2/renderer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index bb8dab023..db313034a 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -453,7 +453,12 @@ static enum wl_shm_format gles2_preferred_read_format( pop_gles2_debug(renderer); EGLint alpha_size = -1; - if (renderer->egl->config != EGL_NO_CONFIG_KHR) { + if (renderer->current_buffer != NULL) { + glBindRenderbuffer(GL_RENDERBUFFER, renderer->current_buffer->rbo); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, + GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } else if (renderer->egl->config != EGL_NO_CONFIG_KHR) { eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, EGL_ALPHA_SIZE, &alpha_size); } From e9c1f0f7d33ceb5ec36a84ac2b977924562d63af Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 22:20:24 +0100 Subject: [PATCH 185/223] output: improve basic test logging --- types/wlr_output.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index 15e851544..2397985b5 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -518,6 +518,7 @@ static bool output_basic_test(struct wlr_output *output) { if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT) { if (output->attach_render_locks > 0) { + wlr_log(WLR_DEBUG, "Direct scan-out disabled by lock"); return false; } @@ -527,6 +528,8 @@ static bool output_basic_test(struct wlr_output *output) { wl_list_for_each(cursor, &output->cursors, link) { if (cursor->enabled && cursor->visible && cursor != output->hardware_cursor) { + wlr_log(WLR_DEBUG, + "Direct scan-out disabled by software cursor"); return false; } } @@ -537,6 +540,7 @@ static bool output_basic_test(struct wlr_output *output) { output_pending_resolution(output, &pending_width, &pending_height); if (output->pending.buffer->width != pending_width || output->pending.buffer->height != pending_height) { + wlr_log(WLR_DEBUG, "Direct scan-out buffer size mismatch"); return false; } } @@ -576,7 +580,7 @@ bool wlr_output_test(struct wlr_output *output) { bool wlr_output_commit(struct wlr_output *output) { if (!output_basic_test(output)) { - wlr_log(WLR_ERROR, "Basic output test failed"); + wlr_log(WLR_ERROR, "Basic output test failed for %s", output->name); return false; } From 12ede67c62ceab24580d52147354bbc45976129f Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Thu, 10 Dec 2020 23:25:16 +0100 Subject: [PATCH 186/223] egl: fix memory leak I have noticed this with LeakSanitizer, I hope these are all occurrences. --- render/egl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/render/egl.c b/render/egl.c index 8fe733983..8914801bd 100644 --- a/render/egl.c +++ b/render/egl.c @@ -166,6 +166,7 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { } free(modifiers); + free(external_only); } char *str_formats = malloc(formats_len * 5 + 1); @@ -783,6 +784,7 @@ static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, *modifiers, *external_only, &num)) { wlr_log(WLR_ERROR, "Failed to query dmabuf modifiers"); free(*modifiers); + free(*external_only); return -1; } return num; From 4c363a564f7ce1ef722417e8b8a0607c1004c828 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 10 Dec 2020 21:56:49 +0100 Subject: [PATCH 187/223] backend/drm: remove workaround for amdgpu DP MST Closes: https://github.com/swaywm/wlroots/issues/2533 --- backend/drm/drm.c | 41 +++++------------------------------------ 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index f84f3afe0..a454df03c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1209,8 +1209,8 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { } static uint32_t get_possible_crtcs(int fd, drmModeRes *res, - drmModeConnector *conn, bool is_mst) { - uint32_t ret = 0; + drmModeConnector *conn) { + uint32_t possible_crtcs = 0; for (int i = 0; i < conn->count_encoders; ++i) { drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]); @@ -1218,33 +1218,12 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res, continue; } - ret |= enc->possible_crtcs; + possible_crtcs |= enc->possible_crtcs; drmModeFreeEncoder(enc); } - // Sometimes DP MST connectors report no encoders, so we'll loop though - // all of the encoders of the MST type instead. - // TODO: See if there is a better solution. - - if (!is_mst || ret) { - return ret; - } - - for (int i = 0; i < res->count_encoders; ++i) { - drmModeEncoder *enc = drmModeGetEncoder(fd, res->encoders[i]); - if (!enc) { - continue; - } - - if (enc->encoder_type == DRM_MODE_ENCODER_DPMST) { - ret |= enc->possible_crtcs; - } - - drmModeFreeEncoder(enc); - } - - return ret; + return possible_crtcs; } void scan_drm_connectors(struct wlr_drm_backend *drm) { @@ -1405,17 +1384,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link); } - size_t path_len; - bool is_mst = false; - char *path = get_drm_prop_blob(drm->fd, wlr_conn->id, - wlr_conn->props.path, &path_len); - if (path && path_len > 4 && strncmp(path, "mst:", 4) == 0) { - is_mst = true; - } - free(path); - - wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn, - is_mst); + wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn); if (wlr_conn->possible_crtc == 0) { wlr_log(WLR_ERROR, "No CRTC possible for connector '%s'", wlr_conn->output.name); From 768131e4883ed8b04ced6b453721fc28dbf61577 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 11:06:37 +0100 Subject: [PATCH 188/223] output: stop assuming a frame is pending in init - The DRM backend initially doesn't have a frame scheduled initially. However the compositor is expected to set a mode to start the rendering loop (frame_pending is set to true in drm_crtc_pageflip). - The headless and X11 backends have a timer to schedule frames, so they ignore this hint completely. - The Wayland backend renders a fake frame to start the rendering loop. It's the only case where a frame is pending on init, move the assumption there. --- backend/wayland/output.c | 1 + types/wlr_output.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index abe8e43ed..87b06808c 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -582,6 +582,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { NULL)) { goto error; } + wlr_output->frame_pending = true; wl_list_insert(&backend->outputs, &output->link); wlr_output_update_enabled(wlr_output, true); diff --git a/types/wlr_output.c b/types/wlr_output.c index 2397985b5..8dbdfdfba 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -358,8 +358,6 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, output->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &output->display_destroy); - - output->frame_pending = true; } void wlr_output_destroy(struct wlr_output *output) { From 038285d49671a30750ee06fb24b923ccca29cca5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 11:13:52 +0100 Subject: [PATCH 189/223] backend/wayland: stop rendering black frame on init Instead of rendering a black frame, schedule a frame event to ask the compositor to render a proper frame. --- backend/wayland/output.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 87b06808c..77412056e 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -565,25 +565,6 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wl_display_roundtrip(output->backend->remote_display); - // start rendering loop per callbacks by rendering first frame - if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, - NULL)) { - goto error; - } - - wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); - wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); - wlr_renderer_end(backend->renderer); - - output->frame_callback = wl_surface_frame(output->surface); - wl_callback_add_listener(output->frame_callback, &frame_listener, output); - - if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface, - NULL)) { - goto error; - } - wlr_output->frame_pending = true; - wl_list_insert(&backend->outputs, &output->link); wlr_output_update_enabled(wlr_output, true); @@ -596,6 +577,9 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { } } + // Start the rendering loop by requesting the compositor to render a frame + wlr_output_schedule_frame(wlr_output); + return wlr_output; error: From 3923ff005ddc56729d0ed699dbdf47182f3f68c8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 11:40:23 +0100 Subject: [PATCH 190/223] backend/wayland: use wlr_swapchain for main surface The cursor surface still uses a wl_egl_window. References: https://github.com/swaywm/wlroots/issues/1352 --- backend/wayland/backend.c | 39 ++++++++++++- backend/wayland/output.c | 115 +++++++++++++++++++++++++------------- include/backend/wayland.h | 7 ++- 3 files changed, 118 insertions(+), 43 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 9290e28fd..0fc978e98 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -16,7 +17,10 @@ #include #include "backend/wayland.h" +#include "render/drm_format_set.h" +#include "render/gbm_allocator.h" #include "util/signal.h" + #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "pointer-gestures-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" @@ -277,7 +281,8 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl_registry_add_listener(wl->registry, ®istry_listener, wl); - wl_display_roundtrip(wl->remote_display); + wl_display_roundtrip(wl->remote_display); // get globals + wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats if (!wl->compositor) { wlr_log(WLR_ERROR, @@ -317,12 +322,42 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT, wl->remote_display, config_attribs, 0); - if (!wl->renderer) { wlr_log(WLR_ERROR, "Could not create renderer"); goto error_event; } + // TODO: get FD from linux-dmabuf hints instead + int drm_fd = wlr_renderer_get_drm_fd(wl->renderer); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); + goto error_event; + } + + drm_fd = dup(drm_fd); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "dup failed"); + goto error_event; + } + + struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); + if (alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + goto error_event; + } + wl->allocator = &alloc->base; + + uint32_t fmt = DRM_FORMAT_ARGB8888; + const struct wlr_drm_format *remote_format = + wlr_drm_format_set_get(&wl->linux_dmabuf_v1_formats, fmt); + if (remote_format == NULL) { + wlr_log(WLR_ERROR, "Remote compositor doesn't support ARGB8888 " + "via linux-dmabuf-unstable-v1"); + goto error_event; + } + // TODO: intersect with render formats + wl->format = wlr_drm_format_dup(remote_format); + wl->local_display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &wl->local_display_destroy); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 77412056e..540cc1f78 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -15,7 +15,10 @@ #include #include "backend/wayland.h" +#include "render/swapchain.h" +#include "render/wlr_renderer.h" #include "util/signal.h" + #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" @@ -94,17 +97,40 @@ static const struct wp_presentation_feedback_listener static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, int32_t height, int32_t refresh) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); - wl_egl_window_resize(output->egl_window, width, height, 0, 0); + + if (wlr_output->width != width || wlr_output->height != height) { + struct wlr_swapchain *swapchain = wlr_swapchain_create( + output->backend->allocator, width, height, output->backend->format); + if (swapchain == NULL) { + return false; + } + wlr_swapchain_destroy(output->swapchain); + output->swapchain = swapchain; + } + wlr_output_update_custom_mode(&output->wlr_output, width, height, 0); return true; } static bool output_attach_render(struct wlr_output *wlr_output, int *buffer_age) { - struct wlr_wl_output *output = - get_wl_output_from_output(wlr_output); - return wlr_egl_make_current(&output->backend->egl, output->egl_surface, - buffer_age); + struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age); + if (!output->back_buffer) { + return false; + } + + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + if (!wlr_renderer_bind_buffer(output->backend->renderer, + output->back_buffer)) { + return false; + } + + return true; } static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) { @@ -246,39 +272,49 @@ static bool output_commit(struct wlr_output *wlr_output) { output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); + struct wlr_buffer *wlr_buffer = NULL; switch (wlr_output->pending.buffer_type) { case WLR_OUTPUT_STATE_BUFFER_RENDER: - if (!wlr_egl_swap_buffers(&output->backend->egl, - output->egl_surface, damage)) { - return false; - } + assert(output->back_buffer != NULL); + wlr_buffer = output->back_buffer; + + wlr_renderer_bind_buffer(output->backend->renderer, NULL); + wlr_egl_unset_current(&output->backend->egl); break; case WLR_OUTPUT_STATE_BUFFER_SCANOUT:; - struct wlr_wl_buffer *buffer = - create_wl_buffer(output->backend, wlr_output->pending.buffer); - if (buffer == NULL) { - return false; - } - - wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0); - - if (damage == NULL) { - wl_surface_damage_buffer(output->surface, - 0, 0, INT32_MAX, INT32_MAX); - } else { - int rects_len; - pixman_box32_t *rects = - pixman_region32_rectangles(damage, &rects_len); - for (int i = 0; i < rects_len; i++) { - pixman_box32_t *r = &rects[i]; - wl_surface_damage_buffer(output->surface, r->x1, r->y1, - r->x2 - r->x1, r->y2 - r->y1); - } - } - wl_surface_commit(output->surface); + wlr_buffer = wlr_output->pending.buffer; break; } + struct wlr_wl_buffer *buffer = + create_wl_buffer(output->backend, wlr_buffer); + if (buffer == NULL) { + return false; + } + + wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0); + + if (damage == NULL) { + wl_surface_damage_buffer(output->surface, + 0, 0, INT32_MAX, INT32_MAX); + } else { + int rects_len; + pixman_box32_t *rects = + pixman_region32_rectangles(damage, &rects_len); + for (int i = 0; i < rects_len; i++) { + pixman_box32_t *r = &rects[i]; + wl_surface_damage_buffer(output->surface, r->x1, r->y1, + r->x2 - r->x1, r->y2 - r->y1); + } + } + + wl_surface_commit(output->surface); + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = NULL; + + wlr_swapchain_set_buffer_submitted(output->swapchain, wlr_buffer); + if (wp_feedback != NULL) { struct wlr_wl_presentation_feedback *feedback = calloc(1, sizeof(*feedback)); @@ -302,8 +338,8 @@ static bool output_commit(struct wlr_output *wlr_output) { } static void output_rollback_render(struct wlr_output *wlr_output) { - struct wlr_wl_output *output = - get_wl_output_from_output(wlr_output); + struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); + wlr_renderer_bind_buffer(output->backend->renderer, NULL); wlr_egl_unset_current(&output->backend->egl); } @@ -407,8 +443,8 @@ static void output_destroy(struct wlr_output *wlr_output) { presentation_feedback_destroy(feedback); } - wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface); - wl_egl_window_destroy(output->egl_window); + wlr_buffer_unlock(output->back_buffer); + wlr_swapchain_destroy(output->swapchain); if (output->zxdg_toplevel_decoration_v1) { zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1); } @@ -558,10 +594,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { &xdg_toplevel_listener, output); wl_surface_commit(output->surface); - output->egl_window = wl_egl_window_create(output->surface, - wlr_output->width, wlr_output->height); - output->egl_surface = wlr_egl_create_surface(&backend->egl, - output->egl_window); + output->swapchain = wlr_swapchain_create(output->backend->allocator, + wlr_output->width, wlr_output->height, output->backend->format); + if (output->swapchain == NULL) { + goto error; + } wl_display_roundtrip(output->backend->remote_display); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9596b72ca..8189c463e 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -25,6 +25,8 @@ struct wlr_wl_backend { struct wl_list outputs; struct wlr_egl egl; struct wlr_renderer *renderer; + struct wlr_drm_format *format; + struct wlr_allocator *allocator; size_t requested_outputs; size_t last_output_num; struct wl_listener local_display_destroy; @@ -67,10 +69,11 @@ struct wlr_wl_output { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; struct wl_list presentation_feedbacks; + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer; + uint32_t enter_serial; struct { From 441bac139fdfbbe576d3d87a91adeb906f9bd2a7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 13:18:44 +0100 Subject: [PATCH 191/223] backend/wayland: use wlr_swapchain for cursor surface --- backend/wayland/output.c | 54 ++++++++++++++++++++++++++++----------- include/backend/wayland.h | 4 +-- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 540cc1f78..188c22b6c 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -377,19 +377,30 @@ static bool output_set_cursor(struct wlr_output *wlr_output, width = width * wlr_output->scale / scale; height = height * wlr_output->scale / scale; - output->cursor.width = width; - output->cursor.height = height; - - if (output->cursor.egl_window == NULL) { - output->cursor.egl_window = - wl_egl_window_create(surface, width, height); + if (output->cursor.swapchain == NULL || + output->cursor.swapchain->width != width || + output->cursor.swapchain->height != height) { + wlr_swapchain_destroy(output->cursor.swapchain); + output->cursor.swapchain = wlr_swapchain_create( + output->backend->allocator, width, height, + output->backend->format); + if (output->cursor.swapchain == NULL) { + return false; + } } - wl_egl_window_resize(output->cursor.egl_window, width, height, 0, 0); - EGLSurface egl_surface = - wlr_egl_create_surface(&backend->egl, output->cursor.egl_window); + struct wlr_buffer *wlr_buffer = + wlr_swapchain_acquire(output->cursor.swapchain, NULL); + if (wlr_buffer == NULL) { + return false; + } - wlr_egl_make_current(&backend->egl, egl_surface, NULL); + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + if (!wlr_renderer_bind_buffer(output->backend->renderer, wlr_buffer)) { + return false; + } struct wlr_box cursor_box = { .width = width, @@ -407,8 +418,23 @@ static bool output_set_cursor(struct wlr_output *wlr_output, wlr_render_texture_with_matrix(backend->renderer, texture, matrix, 1.0); wlr_renderer_end(backend->renderer); - wlr_egl_swap_buffers(&backend->egl, egl_surface, NULL); - wlr_egl_destroy_surface(&backend->egl, egl_surface); + wlr_renderer_bind_buffer(output->backend->renderer, NULL); + wlr_egl_unset_current(&output->backend->egl); + + struct wlr_wl_buffer *buffer = + create_wl_buffer(output->backend, wlr_buffer); + if (buffer == NULL) { + return false; + } + + wl_surface_attach(surface, buffer->wl_buffer, 0, 0); + wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_commit(surface); + + wlr_buffer_unlock(wlr_buffer); + + output->cursor.width = width; + output->cursor.height = height; } else { wl_surface_attach(surface, NULL, 0, 0); wl_surface_commit(surface); @@ -426,9 +452,7 @@ static void output_destroy(struct wlr_output *wlr_output) { wl_list_remove(&output->link); - if (output->cursor.egl_window != NULL) { - wl_egl_window_destroy(output->cursor.egl_window); - } + wlr_swapchain_destroy(output->cursor.swapchain); if (output->cursor.surface) { wl_surface_destroy(output->cursor.surface); } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 8189c463e..0ff52b515 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -4,9 +4,7 @@ #include #include -#include #include -#include #include #include @@ -79,7 +77,7 @@ struct wlr_wl_output { struct { struct wlr_wl_pointer *pointer; struct wl_surface *surface; - struct wl_egl_window *egl_window; + struct wlr_swapchain *swapchain; int32_t hotspot_x, hotspot_y; int32_t width, height; } cursor; From 858a1940b59e48624b35369541b5ea09e3121606 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 13:23:34 +0100 Subject: [PATCH 192/223] build: move wayland-egl dependency to examples/ Now that the Wayland backend has moved to wlr_swapchain, only client examples use the dependency. Stop linking against wayland-egl in the wlroots library. --- examples/meson.build | 19 ++++++++++--------- meson.build | 2 -- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index c8016d3a0..ede858328 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,4 +1,5 @@ threads = dependency('threads') +wayland_egl = dependency('wayland-egl') wayland_cursor = dependency('wayland-cursor') libpng = dependency('libpng', required: false, disabler: true) # These versions correspond to ffmpeg 4.0 @@ -54,7 +55,7 @@ clients = { }, 'idle-inhibit': { 'src': 'idle-inhibit.c', - 'dep': wlroots, + 'dep': [wayland_egl, wlroots], 'proto': [ 'idle-inhibit-unstable-v1', 'xdg-shell', @@ -62,7 +63,7 @@ clients = { }, 'keyboard-shortcuts-inhibit': { 'src': 'keyboard-shortcuts-inhibit.c', - 'dep': [wayland_cursor, wlroots], + 'dep': [wayland_egl, wayland_cursor, wlroots], 'proto': [ 'keyboard-shortcuts-inhibit-unstable-v1', 'xdg-shell', @@ -70,7 +71,7 @@ clients = { }, 'layer-shell': { 'src': 'layer-shell.c', - 'dep': [wayland_cursor, wlroots], + 'dep': [wayland_egl, wayland_cursor, wlroots], 'proto': [ 'wlr-layer-shell-unstable-v1', 'xdg-shell', @@ -78,7 +79,7 @@ clients = { }, 'input-inhibitor': { 'src': 'input-inhibitor.c', - 'dep': [wayland_cursor, wlroots], + 'dep': [wayland_egl, wayland_cursor, wlroots], 'proto': [ 'wlr-input-inhibitor-unstable-v1', 'xdg-shell', @@ -96,7 +97,7 @@ clients = { }, 'pointer-constraints': { 'src': 'pointer-constraints.c', - 'dep': wlroots, + 'dep': [wayland_egl, wlroots], 'proto': [ 'pointer-constraints-unstable-v1', 'xdg-shell', @@ -104,7 +105,7 @@ clients = { }, 'relative-pointer': { 'src': 'relative-pointer-unstable-v1.c', - 'dep': wlroots, + 'dep': [wayland_egl, wlroots], 'proto': [ 'pointer-constraints-unstable-v1', 'relative-pointer-unstable-v1', @@ -137,7 +138,7 @@ clients = { }, 'toplevel-decoration': { 'src': 'toplevel-decoration.c', - 'dep': wlroots, + 'dep': [wayland_egl, wlroots], 'proto': [ 'xdg-decoration-unstable-v1', 'xdg-shell', @@ -145,7 +146,7 @@ clients = { }, 'input-method': { 'src': 'input-method.c', - 'dep': libepoll, + 'dep': [wayland_egl, libepoll], 'proto': [ 'input-method-unstable-v2', 'text-input-unstable-v3', @@ -154,7 +155,7 @@ clients = { }, 'text-input': { 'src': 'text-input.c', - 'dep': [wayland_cursor, wlroots], + 'dep': [wayland_egl, wayland_cursor, wlroots], 'proto': [ 'text-input-unstable-v3', 'xdg-shell', diff --git a/meson.build b/meson.build index 95fdff658..aa6598bfe 100644 --- a/meson.build +++ b/meson.build @@ -97,7 +97,6 @@ endif wayland_server = dependency('wayland-server', version: '>=1.18') wayland_client = dependency('wayland-client') -wayland_egl = dependency('wayland-egl') wayland_protos = dependency('wayland-protocols', version: '>=1.17') egl = dependency('egl') glesv2 = dependency('glesv2') @@ -114,7 +113,6 @@ wlr_files = [] wlr_deps = [ wayland_server, wayland_client, - wayland_egl, wayland_protos, egl, glesv2, From 16a51bbab27ba5fa9348f21cfabff3085e25fc99 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 16:59:49 +0100 Subject: [PATCH 193/223] backend/wayland: query render formats --- backend/wayland/backend.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 0fc978e98..14b6ca6c3 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -19,6 +19,7 @@ #include "backend/wayland.h" #include "render/drm_format_set.h" #include "render/gbm_allocator.h" +#include "render/wlr_renderer.h" #include "util/signal.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" @@ -351,12 +352,30 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const struct wlr_drm_format *remote_format = wlr_drm_format_set_get(&wl->linux_dmabuf_v1_formats, fmt); if (remote_format == NULL) { - wlr_log(WLR_ERROR, "Remote compositor doesn't support ARGB8888 " - "via linux-dmabuf-unstable-v1"); + wlr_log(WLR_ERROR, "Remote compositor doesn't support format " + "0x%"PRIX32" via linux-dmabuf-unstable-v1", fmt); goto error_event; } - // TODO: intersect with render formats - wl->format = wlr_drm_format_dup(remote_format); + + const struct wlr_drm_format_set *render_formats = + wlr_renderer_get_dmabuf_render_formats(wl->renderer); + if (render_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer"); + return false; + } + const struct wlr_drm_format *render_format = + wlr_drm_format_set_get(render_formats, fmt); + if (render_format == NULL) { + wlr_log(WLR_ERROR, "Renderer doesn't support DRM format 0x%"PRIX32, fmt); + return false; + } + + wl->format = wlr_drm_format_intersect(remote_format, render_format); + if (wl->format == NULL) { + wlr_log(WLR_ERROR, "Failed to intersect remote and render modifiers " + "for format 0x%"PRIX32, fmt); + return false; + } wl->local_display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &wl->local_display_destroy); From d79a00bf020866905ab41f3a3d3b6db667ca11ba Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 18 Nov 2020 19:21:03 +0100 Subject: [PATCH 194/223] backend/x11: switch to wlr_swapchain --- backend/x11/backend.c | 156 +++++++++++++++++++++++- backend/x11/meson.build | 4 +- backend/x11/output.c | 258 +++++++++++++++++++++++++++++++++++----- include/backend/x11.h | 29 ++++- 4 files changed, 413 insertions(+), 34 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index f2b09a257..980bc14c1 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -6,12 +6,16 @@ #include #include #include +#include #include +#include #include #include #include +#include +#include #include #include @@ -25,8 +29,26 @@ #include #include "backend/x11.h" +#include "render/drm_format_set.h" +#include "render/gbm_allocator.h" +#include "render/wlr_renderer.h" #include "util/signal.h" +// See dri2_format_for_depth in mesa +const struct wlr_x11_format formats[] = { + { .drm = DRM_FORMAT_XRGB8888, .depth = 24, .bpp = 32 }, + { .drm = DRM_FORMAT_ARGB8888, .depth = 32, .bpp = 32 }, +}; + +static const struct wlr_x11_format *x11_format_from_depth(uint8_t depth) { + for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { + if (formats[i].depth == depth) { + return &formats[i]; + } + } + return NULL; +} + struct wlr_x11_output *get_x11_output_from_window_id( struct wlr_x11_backend *x11, xcb_window_t window) { struct wlr_x11_output *output; @@ -82,6 +104,8 @@ static void handle_x11_event(struct wlr_x11_backend *x11, xcb_ge_generic_event_t *ev = (xcb_ge_generic_event_t *)event; if (ev->extension == x11->xinput_opcode) { handle_x11_xinput_event(x11, ev); + } else if (ev->extension == x11->present_opcode) { + handle_x11_present_event(x11, ev); } else { handle_x11_unknown_event(x11, event); } @@ -157,6 +181,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_renderer_destroy(x11->renderer); wlr_egl_finish(&x11->egl); + free(x11->drm_format); #if WLR_HAS_XCB_ERRORS xcb_errors_context_free(x11->errors_context); @@ -190,6 +215,27 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { backend_destroy(&x11->backend); } +static xcb_depth_t *get_depth(xcb_screen_t *screen, uint8_t depth) { + xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen); + while (iter.rem > 0) { + if (iter.data->depth == depth) { + return iter.data; + } + xcb_depth_next(&iter); + } + return NULL; +} + +static xcb_visualid_t pick_visualid(xcb_depth_t *depth) { + xcb_visualtype_t *visuals = xcb_depth_visuals(depth); + for (int i = 0; i < xcb_depth_visuals_length(depth); i++) { + if (visuals[i]._class == XCB_VISUAL_CLASS_TRUE_COLOR) { + return visuals[i].visual_id; + } + } + return 0; +} + struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, const char *x11_display, wlr_renderer_create_func_t create_renderer_func) { @@ -247,6 +293,47 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, const xcb_query_extension_reply_t *ext; + // DRI3 extension + + ext = xcb_get_extension_data(x11->xcb, &xcb_dri3_id); + if (!ext || !ext->present) { + wlr_log(WLR_ERROR, "X11 does not support DRI3 extension"); + goto error_display; + } + + xcb_dri3_query_version_cookie_t dri3_cookie = + xcb_dri3_query_version(x11->xcb, 1, 2); + xcb_dri3_query_version_reply_t *dri3_reply = + xcb_dri3_query_version_reply(x11->xcb, dri3_cookie, NULL); + if (!dri3_reply || dri3_reply->major_version < 1 || + dri3_reply->minor_version < 2) { + wlr_log(WLR_ERROR, "X11 does not support required DRI3 version"); + goto error_display; + } + free(dri3_reply); + + // Present extension + + ext = xcb_get_extension_data(x11->xcb, &xcb_present_id); + if (!ext || !ext->present) { + wlr_log(WLR_ERROR, "X11 does not support Present extension"); + goto error_display; + } + x11->present_opcode = ext->major_opcode; + + xcb_present_query_version_cookie_t present_cookie = + xcb_present_query_version(x11->xcb, 1, 2); + xcb_present_query_version_reply_t *present_reply = + xcb_present_query_version_reply(x11->xcb, present_cookie, NULL); + if (!present_reply || present_reply->major_version < 1) { + wlr_log(WLR_ERROR, "X11 does not support required Present version"); + free(present_reply); + goto error_display; + } + free(present_reply); + + // Xfixes extension + ext = xcb_get_extension_data(x11->xcb, &xcb_xfixes_id); if (!ext || !ext->present) { wlr_log(WLR_ERROR, "X11 does not support Xfixes extension"); @@ -265,6 +352,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } free(fixes_reply); + // Xinput extension + ext = xcb_get_extension_data(x11->xcb, &xcb_input_id); if (!ext || !ext->present) { wlr_log(WLR_ERROR, "X11 does not support Xinput extension"); @@ -295,6 +384,32 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, wl_event_source_check(x11->event_source); x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb)).data; + if (!x11->screen) { + wlr_log(WLR_ERROR, "Failed to get X11 screen"); + goto error_display; + } + + x11->depth = get_depth(x11->screen, 32); + if (!x11->depth) { + wlr_log(WLR_ERROR, "Failed to get 32-bit depth for X11 screen"); + goto error_display; + } + + x11->visualid = pick_visualid(x11->depth); + if (!x11->visualid) { + wlr_log(WLR_ERROR, "Failed to pick X11 visual"); + goto error_display; + } + + x11->x11_format = x11_format_from_depth(x11->depth->depth); + if (!x11->x11_format) { + wlr_log(WLR_ERROR, "Unsupported depth %"PRIu8, x11->depth->depth); + goto error_display; + } + + x11->colormap = xcb_generate_id(x11->xcb); + xcb_create_colormap(x11->xcb, XCB_COLORMAP_ALLOC_NONE, x11->colormap, + x11->screen->root, x11->visualid); if (!create_renderer_func) { create_renderer_func = wlr_renderer_autocreate; @@ -306,18 +421,53 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 0, + EGL_ALPHA_SIZE, 1, EGL_NONE, }; x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_X11_KHR, x11->xlib_conn, config_attribs, x11->screen->root_visual); - if (x11->renderer == NULL) { wlr_log(WLR_ERROR, "Failed to create renderer"); goto error_event; } + // TODO: we can use DRI3Open instead + int drm_fd = wlr_renderer_get_drm_fd(x11->renderer); + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); + return false; + } + + drm_fd = dup(drm_fd); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "dup failed"); + return false; + } + + struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); + if (alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + return false; + } + x11->allocator = &alloc->base; + + const struct wlr_drm_format_set *formats = + wlr_renderer_get_dmabuf_render_formats(x11->renderer); + if (formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer"); + return false; + } + const struct wlr_drm_format *format = + wlr_drm_format_set_get(formats, x11->x11_format->drm); + if (format == NULL) { + wlr_log(WLR_ERROR, "Renderer doesn't support DRM format 0x%"PRIX32, + x11->x11_format->drm); + return false; + } + // TODO intersect modifiers with DRI3GetSupportedModifiers + x11->drm_format = wlr_drm_format_dup(format); + #if WLR_HAS_XCB_ERRORS if (xcb_errors_context_new(x11->xcb, &x11->errors_context) != 0) { wlr_log(WLR_ERROR, "Failed to create error context"); @@ -325,6 +475,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } #endif + x11->present_event_id = xcb_generate_id(x11->xcb); + wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "X11 keyboard", 0, 0); wlr_keyboard_init(&x11->keyboard, &keyboard_impl); diff --git a/backend/x11/meson.build b/backend/x11/meson.build index 40530bb0f..51c6dd04e 100644 --- a/backend/x11/meson.build +++ b/backend/x11/meson.build @@ -2,8 +2,10 @@ x11_libs = [] x11_required = [ 'x11-xcb', 'xcb', - 'xcb-xinput', + 'xcb-dri3', + 'xcb-present', 'xcb-xfixes', + 'xcb-xinput', ] msg = [] diff --git a/backend/x11/output.c b/backend/x11/output.c index 07374b614..0e81179d8 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include #include @@ -13,6 +16,8 @@ #include #include "backend/x11.h" +#include "render/swapchain.h" +#include "render/wlr_renderer.h" #include "util/signal.h" static int signal_frame(void *data) { @@ -85,7 +90,8 @@ static void output_destroy(struct wlr_output *wlr_output) { wl_list_remove(&output->link); wl_event_source_remove(output->frame_timer); - wlr_egl_destroy_surface(&x11->egl, output->surf); + wlr_buffer_unlock(output->back_buffer); + wlr_swapchain_destroy(output->swapchain); xcb_destroy_window(x11->xcb, output->win); xcb_flush(x11->xcb); free(output); @@ -96,7 +102,20 @@ static bool output_attach_render(struct wlr_output *wlr_output, struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); struct wlr_x11_backend *x11 = output->x11; - return wlr_egl_make_current(&x11->egl, output->surf, buffer_age); + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age); + if (!output->back_buffer) { + return false; + } + + if (!wlr_egl_make_current(&x11->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + if (!wlr_renderer_bind_buffer(x11->renderer, output->back_buffer)) { + return false; + } + + return true; } static bool output_test(struct wlr_output *wlr_output) { @@ -112,6 +131,125 @@ static bool output_test(struct wlr_output *wlr_output) { return true; } +static struct wlr_x11_buffer *import_x11_buffer(struct wlr_x11_output *output, + struct wlr_buffer *wlr_buffer) { + struct wlr_x11_backend *x11 = output->x11; + + struct wlr_dmabuf_attributes attrs = {0}; + if (!wlr_buffer_get_dmabuf(wlr_buffer, &attrs)) { + return NULL; + } + + if (attrs.format != x11->x11_format->drm) { + // The pixmap's depth must match the window's depth, otherwise Present + // will throw a Match error + return NULL; + } + + // xcb closes the FDs after sending them, so we need to dup them here + struct wlr_dmabuf_attributes dup_attrs = {0}; + if (!wlr_dmabuf_attributes_copy(&dup_attrs, &attrs)) { + return NULL; + } + + const struct wlr_x11_format *x11_fmt = x11->x11_format; + xcb_pixmap_t pixmap = xcb_generate_id(x11->xcb); + xcb_dri3_pixmap_from_buffers(x11->xcb, pixmap, output->win, + attrs.n_planes, attrs.width, attrs.height, attrs.stride[0], + attrs.offset[0], attrs.stride[1], attrs.offset[1], attrs.stride[2], + attrs.offset[2], attrs.stride[3], attrs.offset[3], x11_fmt->depth, + x11_fmt->bpp, attrs.modifier, dup_attrs.fd); + + struct wlr_x11_buffer *buffer = calloc(1, sizeof(struct wlr_x11_buffer)); + if (!buffer) { + xcb_free_pixmap(x11->xcb, pixmap); + return NULL; + } + buffer->buffer = wlr_buffer_lock(wlr_buffer); + buffer->pixmap = pixmap; + buffer->x11 = x11; + wl_list_insert(&output->buffers, &buffer->link); + return buffer; +} + +static void destroy_x11_buffer(struct wlr_x11_buffer *buffer) { + if (!buffer) { + return; + } + wl_list_remove(&buffer->link); + xcb_free_pixmap(buffer->x11->xcb, buffer->pixmap); + wlr_buffer_unlock(buffer->buffer); + free(buffer); +} + +static bool output_commit_buffer(struct wlr_x11_output *output) { + struct wlr_x11_backend *x11 = output->x11; + + assert(output->back_buffer != NULL); + + wlr_renderer_bind_buffer(x11->renderer, NULL); + wlr_egl_unset_current(&x11->egl); + + struct wlr_x11_buffer *x11_buffer = + import_x11_buffer(output, output->back_buffer); + if (!x11_buffer) { + goto error; + } + + xcb_xfixes_region_t region = XCB_NONE; + if (output->wlr_output.pending.committed & WLR_OUTPUT_STATE_DAMAGE) { + pixman_region32_t *damage = &output->wlr_output.pending.damage; + + int rects_len = 0; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len); + + xcb_rectangle_t *xcb_rects = calloc(rects_len, sizeof(xcb_rectangle_t)); + if (!xcb_rects) { + goto error; + } + + for (int i = 0; i < rects_len; i++) { + pixman_box32_t *box = &rects[i]; + xcb_rects[i] = (struct xcb_rectangle_t){ + .x = box->x1, + .y = box->y1, + .width = box->x2 - box->x1, + .height = box->y2 - box->y1, + }; + } + + xcb_xfixes_region_t region = xcb_generate_id(x11->xcb); + xcb_xfixes_create_region(x11->xcb, region, rects_len, xcb_rects); + + free(xcb_rects); + } + + uint32_t serial = output->wlr_output.commit_seq; + uint32_t options = 0; + xcb_present_pixmap(x11->xcb, output->win, x11_buffer->pixmap, serial, + 0, region, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, options, 0, 0, 0, + 0, NULL); + + if (region != XCB_NONE) { + xcb_xfixes_destroy_region(x11->xcb, region); + } + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = NULL; + + wlr_swapchain_set_buffer_submitted(output->swapchain, x11_buffer->buffer); + + wlr_output_send_present(&output->wlr_output, NULL); + + return true; + +error: + destroy_x11_buffer(x11_buffer); + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = NULL; + return false; +} + static bool output_commit(struct wlr_output *wlr_output) { struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); struct wlr_x11_backend *x11 = output->x11; @@ -145,24 +283,21 @@ static bool output_commit(struct wlr_output *wlr_output) { } if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - pixman_region32_t *damage = NULL; - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { - damage = &wlr_output->pending.damage; - } - - if (!wlr_egl_swap_buffers(&x11->egl, output->surf, damage)) { + if (!output_commit_buffer(output)) { return false; } - - wlr_output_send_present(wlr_output, NULL); } + xcb_flush(x11->xcb); + return true; } static void output_rollback_render(struct wlr_output *wlr_output) { struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); - wlr_egl_unset_current(&output->x11->egl); + struct wlr_x11_backend *x11 = output->x11; + wlr_renderer_bind_buffer(x11->renderer, NULL); + wlr_egl_unset_current(&x11->egl); } static const struct wlr_output_impl output_impl = { @@ -186,6 +321,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { return NULL; } output->x11 = x11; + wl_list_init(&output->buffers); struct wlr_output *wlr_output = &output->wlr_output; wlr_output_init(wlr_output, &x11->backend, &output_impl, x11->wl_display); @@ -193,6 +329,14 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output->width = 1024; wlr_output->height = 768; + output->swapchain = wlr_swapchain_create(x11->allocator, + wlr_output->width, wlr_output->height, x11->drm_format); + if (!output->swapchain) { + wlr_log(WLR_ERROR, "Failed to create swapchain"); + free(output); + return NULL; + } + output_set_refresh(&output->wlr_output, 0); snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%zd", @@ -204,14 +348,18 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { "X11 output %zd", x11->last_output_num); wlr_output_set_description(wlr_output, description); - uint32_t mask = XCB_CW_EVENT_MASK; + // The X11 protocol requires us to set a colormap and border pixel if the + // depth doesn't match the root window's + uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; uint32_t values[] = { - XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY + 0, + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY, + x11->colormap, }; output->win = xcb_generate_id(x11->xcb); - xcb_create_window(x11->xcb, XCB_COPY_FROM_PARENT, output->win, - x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual, mask, values); + xcb_create_window(x11->xcb, x11->depth->depth, output->win, + x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->visualid, mask, values); struct { xcb_input_event_mask_t head; @@ -227,16 +375,14 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { XCB_INPUT_XI_EVENT_MASK_LEAVE | XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN | XCB_INPUT_XI_EVENT_MASK_TOUCH_END | - XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE, + XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE | + XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY, }; xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head); - output->surf = wlr_egl_create_surface(&x11->egl, &output->win); - if (!output->surf) { - wlr_log(WLR_ERROR, "Failed to create EGL surface"); - free(output); - return NULL; - } + uint32_t present_mask = XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY; + xcb_present_select_input(x11->xcb, x11->present_event_id, output->win, + present_mask); xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win, x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1, @@ -278,17 +424,30 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { void handle_x11_configure_notify(struct wlr_x11_output *output, xcb_configure_notify_event_t *ev) { // ignore events that set an invalid size: - if (ev->width > 0 && ev->height > 0) { - wlr_output_update_custom_mode(&output->wlr_output, ev->width, - ev->height, output->wlr_output.refresh); - - // Move the pointer to its new location - update_x11_pointer_position(output, output->x11->time); - } else { + if (ev->width == 0 || ev->height == 0) { wlr_log(WLR_DEBUG, "Ignoring X11 configure event for height=%d, width=%d", ev->width, ev->height); + return; } + + if (output->swapchain->width != ev->width || + output->swapchain->height != ev->height) { + struct wlr_swapchain *swapchain = wlr_swapchain_create( + output->x11->allocator, ev->width, ev->height, + output->x11->drm_format); + if (!swapchain) { + return; + } + wlr_swapchain_destroy(output->swapchain); + output->swapchain = swapchain; + } + + wlr_output_update_custom_mode(&output->wlr_output, ev->width, + ev->height, output->wlr_output.refresh); + + // Move the pointer to its new location + update_x11_pointer_position(output, output->x11->time); } bool wlr_output_is_x11(struct wlr_output *wlr_output) { @@ -310,3 +469,42 @@ void wlr_x11_output_set_title(struct wlr_output *output, const char *title) { x11_output->x11->atoms.net_wm_name, x11_output->x11->atoms.utf8_string, 8, strlen(title), title); } + +static struct wlr_x11_buffer *get_x11_buffer(struct wlr_x11_output *output, + xcb_pixmap_t pixmap) { + struct wlr_x11_buffer *buffer; + wl_list_for_each(buffer, &output->buffers, link) { + if (buffer->pixmap == pixmap) { + return buffer; + } + } + return NULL; +} + +void handle_x11_present_event(struct wlr_x11_backend *x11, + xcb_ge_generic_event_t *event) { + switch (event->event_type) { + case XCB_PRESENT_EVENT_IDLE_NOTIFY:; + xcb_present_idle_notify_event_t *idle_notify = + (xcb_present_idle_notify_event_t *)event; + + struct wlr_x11_output *output = + get_x11_output_from_window_id(x11, idle_notify->window); + if (!output) { + wlr_log(WLR_DEBUG, "Got PresentIdleNotify event for unknown window"); + return; + } + + struct wlr_x11_buffer *buffer = + get_x11_buffer(output, idle_notify->pixmap); + if (!buffer) { + wlr_log(WLR_DEBUG, "Got PresentIdleNotify event for unknown buffer"); + return; + } + + destroy_x11_buffer(buffer); + break; + default: + wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type); + } +} diff --git a/include/backend/x11.h b/include/backend/x11.h index 7ce3ed98a..52f50781e 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -8,6 +8,7 @@ #include #include #include +#include #if WLR_HAS_XCB_ERRORS #include @@ -34,7 +35,9 @@ struct wlr_x11_output { struct wl_list link; // wlr_x11_backend::outputs xcb_window_t win; - EGLSurface surf; + + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer; struct wlr_pointer pointer; struct wlr_input_device pointer_dev; @@ -46,6 +49,8 @@ struct wlr_x11_output { struct wl_event_source *frame_timer; int frame_delay; + struct wl_list buffers; // wlr_x11_buffer::link + bool cursor_hidden; }; @@ -63,6 +68,10 @@ struct wlr_x11_backend { Display *xlib_conn; xcb_connection_t *xcb; xcb_screen_t *screen; + xcb_depth_t *depth; + xcb_visualid_t visualid; + xcb_colormap_t colormap; + xcb_present_event_t present_event_id; size_t requested_outputs; size_t last_output_num; @@ -73,6 +82,9 @@ struct wlr_x11_backend { struct wlr_egl egl; struct wlr_renderer *renderer; + const struct wlr_x11_format *x11_format; + struct wlr_drm_format *drm_format; + struct wlr_allocator *allocator; struct wl_event_source *event_source; struct { @@ -90,11 +102,24 @@ struct wlr_x11_backend { xcb_errors_context_t *errors_context; #endif + uint8_t present_opcode; uint8_t xinput_opcode; struct wl_listener display_destroy; }; +struct wlr_x11_buffer { + struct wlr_x11_backend *x11; + struct wlr_buffer *buffer; + xcb_pixmap_t pixmap; + struct wl_list link; // wlr_x11_output::buffers +}; + +struct wlr_x11_format { + uint32_t drm; + uint8_t depth, bpp; +}; + struct wlr_x11_backend *get_x11_backend_from_backend( struct wlr_backend *wlr_backend); struct wlr_x11_output *get_x11_output_from_window_id( @@ -112,5 +137,7 @@ void update_x11_pointer_position(struct wlr_x11_output *output, void handle_x11_configure_notify(struct wlr_x11_output *output, xcb_configure_notify_event_t *event); +void handle_x11_present_event(struct wlr_x11_backend *x11, + xcb_ge_generic_event_t *event); #endif From c59aacf944658d81fb4834f9744186794bea9922 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Nov 2020 16:30:18 +0100 Subject: [PATCH 195/223] backend/x11: query modifiers supported by X11 server --- backend/x11/backend.c | 83 +++++++++++++++++++++++++++++++++++++++---- include/backend/x11.h | 2 ++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 980bc14c1..9482f86d7 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -180,6 +180,7 @@ static void backend_destroy(struct wlr_backend *backend) { wl_list_remove(&x11->display_destroy.link); wlr_renderer_destroy(x11->renderer); + wlr_drm_format_set_finish(&x11->dri3_formats); wlr_egl_finish(&x11->egl); free(x11->drm_format); @@ -236,6 +237,56 @@ static xcb_visualid_t pick_visualid(xcb_depth_t *depth) { return 0; } +static bool query_dri3_modifiers(struct wlr_x11_backend *x11, + const struct wlr_x11_format *format) { + // Query the root window's supported modifiers, because we only care about + // screen_modifiers for now + xcb_dri3_get_supported_modifiers_cookie_t modifiers_cookie = + xcb_dri3_get_supported_modifiers(x11->xcb, x11->screen->root, + format->depth, format->bpp); + xcb_dri3_get_supported_modifiers_reply_t *modifiers_reply = + xcb_dri3_get_supported_modifiers_reply(x11->xcb, modifiers_cookie, + NULL); + if (!modifiers_reply) { + wlr_log(WLR_ERROR, "Failed to get DMA-BUF modifiers supported by " + "the X11 server for the format 0x%"PRIX32, format->drm); + return false; + } + + // If modifiers aren't supported, DRI3 will return an empty list + const uint64_t *modifiers = + xcb_dri3_get_supported_modifiers_screen_modifiers(modifiers_reply); + int modifiers_len = + xcb_dri3_get_supported_modifiers_screen_modifiers_length(modifiers_reply); + for (int i = 0; i < modifiers_len; i++) { + wlr_drm_format_set_add(&x11->dri3_formats, format->drm, modifiers[i]); + } + + free(modifiers_reply); + return true; +} + +static bool query_dri3_formats(struct wlr_x11_backend *x11) { + xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(x11->screen); + while (iter.rem > 0) { + uint8_t depth = iter.data->depth; + + const struct wlr_x11_format *format = x11_format_from_depth(depth); + if (format != NULL) { + wlr_drm_format_set_add(&x11->dri3_formats, format->drm, + DRM_FORMAT_MOD_INVALID); + + if (!query_dri3_modifiers(x11, format)) { + return false; + } + } + + xcb_depth_next(&iter); + } + + return true; +} + struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, const char *x11_display, wlr_renderer_create_func_t create_renderer_func) { @@ -452,21 +503,39 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } x11->allocator = &alloc->base; - const struct wlr_drm_format_set *formats = + const struct wlr_drm_format_set *render_formats = wlr_renderer_get_dmabuf_render_formats(x11->renderer); - if (formats == NULL) { + if (render_formats == NULL) { wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer"); return false; } - const struct wlr_drm_format *format = - wlr_drm_format_set_get(formats, x11->x11_format->drm); - if (format == NULL) { + const struct wlr_drm_format *render_format = + wlr_drm_format_set_get(render_formats, x11->x11_format->drm); + if (render_format == NULL) { wlr_log(WLR_ERROR, "Renderer doesn't support DRM format 0x%"PRIX32, x11->x11_format->drm); return false; } - // TODO intersect modifiers with DRI3GetSupportedModifiers - x11->drm_format = wlr_drm_format_dup(format); + + if (!query_dri3_formats(x11)) { + wlr_log(WLR_ERROR, "Failed to query supported DRI3 formats"); + return false; + } + + const struct wlr_drm_format *dri3_format = + wlr_drm_format_set_get(render_formats, x11->x11_format->drm); + if (dri3_format == NULL) { + wlr_log(WLR_ERROR, "X11 server doesn't support DRM format 0x%"PRIX32, + x11->x11_format->drm); + return false; + } + + x11->drm_format = wlr_drm_format_intersect(dri3_format, render_format); + if (x11->drm_format == NULL) { + wlr_log(WLR_ERROR, "Failed to intersect DRI3 and render modifiers for " + "format 0x%"PRIX32, x11->x11_format->drm); + return false; + } #if WLR_HAS_XCB_ERRORS if (xcb_errors_context_new(x11->xcb, &x11->errors_context) != 0) { diff --git a/include/backend/x11.h b/include/backend/x11.h index 52f50781e..b872385da 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,7 @@ struct wlr_x11_backend { struct wlr_egl egl; struct wlr_renderer *renderer; + struct wlr_drm_format_set dri3_formats; const struct wlr_x11_format *x11_format; struct wlr_drm_format *drm_format; struct wlr_allocator *allocator; From 525fa6ada067084bc63e3002ba12e07499623514 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 13 Dec 2020 12:21:21 +0100 Subject: [PATCH 196/223] backend/x11: fix xinput mask mixed up with present Don't mix xinput and present flags. Fixes: d79a00bf0208 ("backend/x11: switch to wlr_swapchain") --- backend/x11/output.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/x11/output.c b/backend/x11/output.c index 0e81179d8..c7cf1b633 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -375,8 +375,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { XCB_INPUT_XI_EVENT_MASK_LEAVE | XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN | XCB_INPUT_XI_EVENT_MASK_TOUCH_END | - XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE | - XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY, + XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE, }; xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head); From 93cd3a79b26cb3a94094efd28ee55fb6db6e7347 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 12:06:42 +0100 Subject: [PATCH 197/223] backend/drm: stop using GBM flags gbm_bo_create_with_modifiers doesn't take GBM flags, so our wlr_gbm_allocator interface doesn't either. We were still internally using GBM flags in the DRM backend, leading to awkward back-and-forth conversions. The only flag passed to drm_plane_init_surface was GBM_BO_USE_LINEAR, so turn that into a bool to make sure other flags can't be passed in. Move the "force linear" logic out of init_drm_surface, because the supplied wlr_drm_format should already contain that information. --- backend/drm/drm.c | 6 ++--- backend/drm/renderer.c | 43 ++++++++++++++++++---------------- include/backend/drm/renderer.h | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index a454df03c..3f19a7997 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -722,7 +722,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, modifiers = false; } - if (!drm_plane_init_surface(plane, drm, width, height, format, 0, modifiers) || + if (!drm_plane_init_surface(plane, drm, width, height, format, false, modifiers) || !drm_connector_pageflip_renderer(conn)) { if (!modifiers) { wlr_log(WLR_ERROR, "Failed to initialize renderer " @@ -742,7 +742,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, crtc->pending.mode = mode; if (!drm_plane_init_surface(plane, drm, width, height, format, - 0, modifiers)) { + false, modifiers)) { return false; } if (!drm_connector_pageflip_renderer(conn)) { @@ -897,7 +897,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, h = ret ? 64 : h; if (!drm_plane_init_surface(plane, drm, w, h, - DRM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR, false)) { + DRM_FORMAT_ARGB8888, true, false)) { wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); return false; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 27cd50f1c..79add1bab 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -66,7 +66,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) { static bool init_drm_surface(struct wlr_drm_surface *surf, struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, - const struct wlr_drm_format *drm_format, uint32_t flags) { + const struct wlr_drm_format *drm_format) { if (surf->width == width && surf->height == height) { return true; } @@ -80,22 +80,8 @@ static bool init_drm_surface(struct wlr_drm_surface *surf, wlr_swapchain_destroy(surf->swapchain); surf->swapchain = NULL; - struct wlr_drm_format *format_linear = NULL; - if (flags & GBM_BO_USE_LINEAR) { - format_linear = calloc(1, sizeof(struct wlr_drm_format) + sizeof(uint64_t)); - if (format_linear == NULL) { - return false; - } - format_linear->format = drm_format->format; - format_linear->len = 1; - format_linear->cap = 1; - format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; - drm_format = format_linear; - } - surf->swapchain = wlr_swapchain_create(&renderer->allocator->base, width, height, drm_format); - free(format_linear); if (surf->swapchain == NULL) { wlr_log(WLR_ERROR, "Failed to create swapchain"); memset(surf, 0, sizeof(*surf)); @@ -225,7 +211,7 @@ static uint32_t strip_alpha_channel(uint32_t format) { bool drm_plane_init_surface(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, int32_t width, uint32_t height, - uint32_t format, uint32_t flags, bool with_modifiers) { + uint32_t format, bool force_linear, bool with_modifiers) { if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) { format = strip_alpha_channel(format); } @@ -265,22 +251,39 @@ bool drm_plane_init_surface(struct wlr_drm_plane *plane, drm_format = wlr_drm_format_dup(&format_no_modifiers); } + struct wlr_drm_format *drm_format_linear = + calloc(1, sizeof(struct wlr_drm_format) + sizeof(uint64_t)); + if (drm_format_linear == NULL) { + free(drm_format); + return false; + } + drm_format_linear->format = drm_format->format; + drm_format_linear->len = 1; + drm_format_linear->cap = 1; + drm_format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; + + if (force_linear) { + free(drm_format); + drm_format = wlr_drm_format_dup(drm_format_linear); + } + drm_plane_finish_surface(plane); bool ok = true; if (!drm->parent) { - ok = init_drm_surface(&plane->surf, &drm->renderer, width, height, - drm_format, flags | GBM_BO_USE_SCANOUT); + ok = init_drm_surface(&plane->surf, &drm->renderer, + width, height, drm_format); } else { ok = init_drm_surface(&plane->surf, &drm->parent->renderer, - width, height, drm_format, flags | GBM_BO_USE_LINEAR); + width, height, drm_format_linear); if (ok && !init_drm_surface(&plane->mgpu_surf, &drm->renderer, - width, height, drm_format, flags | GBM_BO_USE_SCANOUT)) { + width, height, drm_format)) { finish_drm_surface(&plane->surf); ok = false; } } + free(drm_format_linear); free(drm_format); return ok; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index ec855ab9f..7989fa0bf 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -61,7 +61,7 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm bool drm_plane_init_surface(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, int32_t width, uint32_t height, - uint32_t format, uint32_t flags, bool with_modifiers); + uint32_t format, bool force_linear, bool with_modifiers); void drm_plane_finish_surface(struct wlr_drm_plane *plane); #endif From e57a52e7f793a815f5b635b3751112d4c6f9302b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 13:49:42 +0100 Subject: [PATCH 198/223] Remove inline keyword The compiler is smarter at figuring out whether a function should be inlined or not. --- backend/drm/util.c | 2 +- xwayland/xwm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/util.c b/backend/drm/util.c index 86d66be42..b926e1187 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -221,7 +221,7 @@ uint32_t get_fb_for_bo(struct gbm_bo *bo, bool with_modifiers) { return id; } -static inline bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) { +static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) { for (size_t i = 0; i < n; ++i) { if (arr[i] == key) { return true; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index f258ab008..781bf15dc 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -1165,7 +1165,7 @@ static bool update_state(int action, bool *state) { return changed; } -static inline bool xsurface_is_maximized( +static bool xsurface_is_maximized( struct wlr_xwayland_surface *xsurface) { return xsurface->maximized_horz && xsurface->maximized_vert; } From 3fd809888184c0e629bea2b628e2caca622bab88 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 14:55:18 +0100 Subject: [PATCH 199/223] render/gles2: require GL_EXT_unpack_subimage We implicitly depended on this extension. --- render/gles2/renderer.c | 5 +++++ render/gles2/texture.c | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index db313034a..761142781 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -893,6 +893,11 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { free(renderer); return NULL; } + if (!check_gl_ext(exts_str, "GL_EXT_unpack_subimage")) { + wlr_log(WLR_ERROR, "GL_EXT_unpack_subimage not supported"); + free(renderer); + return NULL; + } renderer->exts.read_format_bgra_ext = check_gl_ext(exts_str, "GL_EXT_read_format_bgra"); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 179bfd891..ea3a11612 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -55,7 +55,6 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, get_gles2_format_from_wl(texture->wl_format); assert(fmt); - // TODO: what if the unpack subimage extension isn't supported? push_gles2_debug(texture->renderer); glBindTexture(GL_TEXTURE_2D, texture->tex); From 1ca4d6b0296ad23a59ad30fbc9063fa93b94b5fe Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 20:49:28 +0100 Subject: [PATCH 200/223] backend/drm: dup FD before wlr_gbm_allocator_create The GBM allocator takes ownership of the DRM FD. --- backend/drm/renderer.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 79add1bab..7599623ac 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -1,5 +1,7 @@ +#define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -37,9 +39,16 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, goto error_gbm; } - renderer->allocator = wlr_gbm_allocator_create(drm->fd); + int alloc_fd = fcntl(drm->fd, F_DUPFD_CLOEXEC, 0); + if (alloc_fd < 0) { + wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); + goto error_wlr_rend; + } + + renderer->allocator = wlr_gbm_allocator_create(alloc_fd); if (renderer->allocator == NULL) { wlr_log(WLR_ERROR, "Failed to create allocator"); + close(alloc_fd); goto error_wlr_rend; } From 87bd718de54ced41544e88200418bc091a1fce50 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 20:52:53 +0100 Subject: [PATCH 201/223] backend: use fcntl(F_DUPFD_CLOEXEC) instead of dup This makes sure the CLOEXEC flag is set on the dup'ed FD. --- backend/headless/backend.c | 13 +++++++------ backend/wayland/backend.c | 6 ++++-- backend/x11/backend.c | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 3995d1eb0..c6c2d0f95 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -113,19 +114,19 @@ static bool backend_init(struct wlr_headless_backend *backend, backend->renderer = renderer; backend->egl = wlr_gles2_renderer_get_egl(renderer); - int fd = wlr_renderer_get_drm_fd(renderer); - if (fd < 0) { + int drm_fd = wlr_renderer_get_drm_fd(renderer); + if (drm_fd < 0) { wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); return false; } - fd = dup(fd); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "dup failed"); + drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); return false; } - struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(fd); + struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); if (alloc == NULL) { wlr_log(WLR_ERROR, "Failed to create GBM allocator"); return false; diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 14b6ca6c3..5b8bce9b1 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -1,4 +1,6 @@ +#define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -335,9 +337,9 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, goto error_event; } - drm_fd = dup(drm_fd); + drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); if (drm_fd < 0) { - wlr_log_errno(WLR_ERROR, "dup failed"); + wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); goto error_event; } diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 9482f86d7..48f1aaee8 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -1,6 +1,6 @@ -#define _POSIX_C_SOURCE 200112L - +#define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -490,9 +490,9 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, return false; } - drm_fd = dup(drm_fd); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "dup failed"); + drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); return false; } From da2a2169344ef2dbe0dc31fd013caf30880d6aff Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 14:31:06 +0100 Subject: [PATCH 202/223] backend/drm: add wlr_drm_connector.backend This allows the DRM code to have direct access to the wlr_drm_backend without having to go through an upcast via get_drm_backend_from_backend. --- backend/drm/atomic.c | 3 +-- backend/drm/drm.c | 29 ++++++++++++----------------- include/backend/drm/drm.h | 1 + 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index cf5367464..f230419fb 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -25,8 +25,7 @@ static void atomic_begin(struct atomic *atom) { static bool atomic_commit(struct atomic *atom, struct wlr_drm_connector *conn, uint32_t flags) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; if (atom->failed) { return false; } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 3f19a7997..7dedddc78 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -335,8 +335,7 @@ static void drm_plane_set_committed(struct wlr_drm_plane *plane) { } static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; bool ok = drm->iface->crtc_commit(drm, conn, flags); if (ok && !(flags & DRM_MODE_ATOMIC_TEST_ONLY)) { @@ -396,8 +395,7 @@ static uint32_t strip_alpha_channel(uint32_t format) { static bool test_buffer(struct wlr_drm_connector *conn, struct wlr_buffer *wlr_buffer) { - struct wlr_output *output = &conn->output; - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; if (!drm->session->active) { return false; @@ -482,7 +480,7 @@ static struct wlr_output_mode *drm_connector_get_pending_mode( static bool drm_connector_commit_buffer(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -518,8 +516,7 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) { } bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -546,7 +543,7 @@ bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { static bool drm_connector_commit(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; if (!drm_connector_test(output)) { return false; @@ -618,7 +615,7 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, static size_t drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; if (crtc == NULL) { @@ -631,7 +628,7 @@ static size_t drm_connector_get_gamma_size(struct wlr_output *output) { static bool drm_connector_export_dmabuf(struct wlr_output *output, struct wlr_dmabuf_attributes *attribs) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; if (!drm->session->active) { @@ -687,8 +684,7 @@ static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) { static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, struct wlr_drm_mode *mode) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; if (conn->state != WLR_DRM_CONN_CONNECTED && conn->state != WLR_DRM_CONN_NEEDS_MODESET) { @@ -777,8 +773,7 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn); bool drm_connector_set_mode(struct wlr_drm_connector *conn, struct wlr_output_mode *wlr_mode) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; conn->desired_enabled = wlr_mode != NULL; conn->desired_mode = wlr_mode; @@ -876,7 +871,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y, bool update_texture) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); + struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -1056,8 +1051,7 @@ static const int32_t subpixel_map[] = { }; static void dealloc_crtc(struct wlr_drm_connector *conn) { - struct wlr_drm_backend *drm = - get_drm_backend_from_backend(conn->output.backend); + struct wlr_drm_backend *drm = conn->backend; if (conn->crtc == NULL) { return; } @@ -1282,6 +1276,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, drm->display); + wlr_conn->backend = drm; wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; wlr_conn->id = drm_conn->connector_id; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 7b53f7fc8..e8b1198f5 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -111,6 +111,7 @@ struct wlr_drm_mode { struct wlr_drm_connector { struct wlr_output output; + struct wlr_drm_backend *backend; enum wlr_drm_connector_state state; struct wlr_output_mode *desired_mode; bool desired_enabled; From 0aa2ba0c0343788accc57c595c914bb611e12ea0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 14:30:13 +0100 Subject: [PATCH 203/223] backend/headless: select the rendering device ourselves Backends will eventually stop creating their renderer. To prepare for this, stop using EGL_PLATFORM_SURFACELESS_MESA in the headless renderer. Pick a render node using libdrm. The new allocator/renderer creation logic looks very much like what will end up in common code. --- backend/headless/backend.c | 137 ++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 34 deletions(-) diff --git a/backend/headless/backend.c b/backend/headless/backend.c index c6c2d0f95..fe893ddf1 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -71,11 +71,11 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wlr_signal_emit_safe(&wlr_backend->events.destroy, backend); free(backend->format); - wlr_allocator_destroy(backend->allocator); if (backend->egl == &backend->priv_egl) { wlr_renderer_destroy(backend->renderer); wlr_egl_finish(&backend->priv_egl); } + wlr_allocator_destroy(backend->allocator); free(backend); } @@ -105,34 +105,17 @@ static void handle_renderer_destroy(struct wl_listener *listener, void *data) { } static bool backend_init(struct wlr_headless_backend *backend, - struct wl_display *display, struct wlr_renderer *renderer) { + struct wl_display *display, struct wlr_allocator *allocator, + struct wlr_renderer *renderer) { wlr_backend_init(&backend->backend, &backend_impl); backend->display = display; wl_list_init(&backend->outputs); wl_list_init(&backend->input_devices); + backend->allocator = allocator; backend->renderer = renderer; backend->egl = wlr_gles2_renderer_get_egl(renderer); - int drm_fd = wlr_renderer_get_drm_fd(renderer); - if (drm_fd < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); - return false; - } - - drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); - if (drm_fd < 0) { - wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); - return false; - } - - struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); - if (alloc == NULL) { - wlr_log(WLR_ERROR, "Failed to create GBM allocator"); - return false; - } - backend->allocator = &alloc->base; - const struct wlr_drm_format_set *formats = wlr_renderer_get_dmabuf_render_formats(backend->renderer); if (formats == NULL) { @@ -155,15 +138,73 @@ static bool backend_init(struct wlr_headless_backend *backend, return true; } +static int open_drm_render_node(void) { + uint32_t flags = 0; + int devices_len = drmGetDevices2(flags, NULL, 0); + if (devices_len < 0) { + wlr_log(WLR_ERROR, "drmGetDevices2 failed"); + return -1; + } + drmDevice **devices = calloc(devices_len, sizeof(drmDevice *)); + if (devices == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + devices_len = drmGetDevices2(flags, devices, devices_len); + if (devices_len < 0) { + free(devices); + wlr_log(WLR_ERROR, "drmGetDevices2 failed"); + return -1; + } + + int fd = -1; + for (int i = 0; i < devices_len; i++) { + drmDevice *dev = devices[i]; + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + const char *name = dev->nodes[DRM_NODE_RENDER]; + wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name); + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + goto out; + } + break; + } + } + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to find any DRM render node"); + } + +out: + for (int i = 0; i < devices_len; i++) { + drmFreeDevice(&devices[i]); + } + free(devices); + + return fd; +} + struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, wlr_renderer_create_func_t create_renderer_func) { wlr_log(WLR_INFO, "Creating headless backend"); + int drm_fd = open_drm_render_node(); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to open DRM render node"); + return NULL; + } + + struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd); + if (gbm_alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + return false; + } + struct wlr_headless_backend *backend = calloc(1, sizeof(struct wlr_headless_backend)); if (!backend) { wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend"); - return NULL; + goto error_backend; } if (!create_renderer_func) { @@ -171,42 +212,70 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, } struct wlr_renderer *renderer = create_renderer_func(&backend->priv_egl, - EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, NULL, 0); + EGL_PLATFORM_GBM_KHR, gbm_alloc->gbm_device, NULL, 0); if (!renderer) { wlr_log(WLR_ERROR, "Failed to create renderer"); - free(backend); - return NULL; + goto error_renderer; } - if (!backend_init(backend, display, renderer)) { - wlr_renderer_destroy(backend->renderer); - free(backend); - return NULL; + if (!backend_init(backend, display, &gbm_alloc->base, renderer)) { + goto error_init; } return &backend->backend; + +error_init: + wlr_renderer_destroy(renderer); +error_renderer: + free(backend); +error_backend: + wlr_allocator_destroy(&gbm_alloc->base); + return NULL; } struct wlr_backend *wlr_headless_backend_create_with_renderer( struct wl_display *display, struct wlr_renderer *renderer) { - wlr_log(WLR_INFO, "Creating headless backend"); + wlr_log(WLR_INFO, "Creating headless backend with parent renderer"); + + int drm_fd = wlr_renderer_get_drm_fd(renderer); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); + return false; + } + + drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); + return false; + } + + struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd); + if (gbm_alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + return false; + } struct wlr_headless_backend *backend = calloc(1, sizeof(struct wlr_headless_backend)); if (!backend) { wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend"); - return NULL; + goto error_backend; } - if (!backend_init(backend, display, renderer)) { - free(backend); - return NULL; + if (!backend_init(backend, display, &gbm_alloc->base, renderer)) { + goto error_init; } backend->renderer_destroy.notify = handle_renderer_destroy; wl_signal_add(&renderer->events.destroy, &backend->renderer_destroy); return &backend->backend; + +error_init: + free(backend); +error_backend: + wlr_allocator_destroy(&gbm_alloc->base); + return NULL; } bool wlr_backend_is_headless(struct wlr_backend *backend) { From 0dcdb5e7a1def069ca31b50cc4c5a84031e4a730 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 17 Dec 2020 16:36:13 +0100 Subject: [PATCH 204/223] backend/x11: fix DRI3 formats not used We queried DRI3 formats, but we weren't using them. Because of a typo, only render formats were used. Fixes: c59aacf94465 ("backend/x11: query modifiers supported by X11 server") Closes: https://github.com/swaywm/wlroots/issues/2552 --- backend/x11/backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 48f1aaee8..6e79129f6 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -523,7 +523,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } const struct wlr_drm_format *dri3_format = - wlr_drm_format_set_get(render_formats, x11->x11_format->drm); + wlr_drm_format_set_get(&x11->dri3_formats, x11->x11_format->drm); if (dri3_format == NULL) { wlr_log(WLR_ERROR, "X11 server doesn't support DRM format 0x%"PRIX32, x11->x11_format->drm); From bdf26f87d548c75f5ef90f21645d2370a6ee34f6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 15:35:59 +0100 Subject: [PATCH 205/223] render/allocator: ignore NULL in wlr_allocator_destroy --- render/allocator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/render/allocator.c b/render/allocator.c index 3638bd62a..ea1712e96 100644 --- a/render/allocator.c +++ b/render/allocator.c @@ -10,6 +10,9 @@ void wlr_allocator_init(struct wlr_allocator *alloc, } void wlr_allocator_destroy(struct wlr_allocator *alloc) { + if (alloc == NULL) { + return; + } wl_signal_emit(&alloc->events.destroy, NULL); alloc->impl->destroy(alloc); } From 60001a75a276f931b02d78a95cedfd0098b88617 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 15 Dec 2020 12:16:26 +0100 Subject: [PATCH 206/223] backend/drm: remove nouveau workaround The workaround is broken because drm_fb_acquire doesn't leave the EGL context current anymore. We'll need to re-introduce it. References: https://github.com/swaywm/wlroots/issues/2525 --- backend/drm/drm.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7dedddc78..0fb7dfc42 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -959,19 +959,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output, plane->cursor_enabled = true; } - if (plane->cursor_enabled) { - drm_fb_acquire(&plane->pending_fb, drm, &plane->mgpu_surf); - /* Workaround for nouveau buffers created with GBM_BO_USER_LINEAR are - * placed in NOUVEAU_GEM_DOMAIN_GART. When the bo is attached to the - * cursor plane it is moved to NOUVEAU_GEM_DOMAIN_VRAM. However, this - * does not wait for the render operations to complete, leaving an - * empty surface. See - * https://gitlab.freedesktop.org/xorg/driver/xf86-video-nouveau/issues/480 - * The render operations can be waited for using: - */ - glFinish(); - } - wlr_output_update_needs_frame(output); return true; } From 9cd3f03f652fc7ee905001e09dafa40b72e1317d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 17 Dec 2020 20:48:47 +0100 Subject: [PATCH 207/223] backend/drm: add wlr_drm_backend.name Save the DRM device name in a wlr_drm_backend field, so that we can easily use it for logging purposes. --- backend/drm/backend.c | 8 ++++---- include/backend/drm/drm.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index b2da7cb3d..44794b511 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -50,6 +50,8 @@ static void backend_destroy(struct wlr_backend *backend) { finish_drm_resources(drm); finish_drm_renderer(&drm->renderer); + + free(drm->name); wlr_session_close_file(drm->session, drm->dev); wl_event_source_remove(drm->drm_event); free(drm); @@ -108,9 +110,7 @@ static void drm_invalidated(struct wl_listener *listener, void *data) { struct wlr_drm_backend *drm = wl_container_of(listener, drm, drm_invalidated); - char *name = drmGetDeviceNameFromFd2(drm->fd); - wlr_log(WLR_DEBUG, "%s invalidated", name); - free(name); + wlr_log(WLR_DEBUG, "%s invalidated", drm->name); scan_drm_connectors(drm); } @@ -137,7 +137,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, char *name = drmGetDeviceNameFromFd2(dev->fd); drmVersion *version = drmGetVersion(dev->fd); wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name); - free(name); drmFreeVersion(version); struct wlr_drm_backend *drm = calloc(1, sizeof(struct wlr_drm_backend)); @@ -152,6 +151,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, drm->dev = dev; drm->fd = dev->fd; + drm->name = name; if (parent != NULL) { drm->parent = get_drm_backend_from_backend(parent); } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index e8b1198f5..ea3cdbd46 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -75,6 +75,7 @@ struct wlr_drm_backend { bool addfb2_modifiers; int fd; + char *name; struct wlr_device *dev; size_t num_crtcs; From 253f447329550bdb97904fababde83d0d8d6ef3e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 17 Dec 2020 20:50:19 +0100 Subject: [PATCH 208/223] backend/drm: print DRM device name when scanning connectors --- backend/drm/drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 0fb7dfc42..017c5c63e 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1216,7 +1216,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { return; } - wlr_log(WLR_INFO, "Scanning DRM connectors"); + wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name); drmModeRes *res = drmModeGetResources(drm->fd); if (!res) { From d37214cb1622458b4d2009a98279b67edcda15b5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 12 Dec 2020 22:26:14 +0100 Subject: [PATCH 209/223] render/drm_format_set: add wlr_drm_format_{create,add} --- include/render/drm_format_set.h | 2 + render/drm_format_set.c | 87 ++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/include/render/drm_format_set.h b/include/render/drm_format_set.h index 78b70e9b6..c438722bc 100644 --- a/include/render/drm_format_set.h +++ b/include/render/drm_format_set.h @@ -3,6 +3,8 @@ #include +struct wlr_drm_format *wlr_drm_format_create(uint32_t format); +bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier); struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format); /** * Intersect modifiers for two DRM formats. diff --git a/render/drm_format_set.c b/render/drm_format_set.c index a4c31494e..634d90707 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -60,52 +60,18 @@ bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, uint64_t modifier) { assert(format != DRM_FORMAT_INVALID); + struct wlr_drm_format **ptr = format_set_get_ref(set, format); - if (ptr) { - struct wlr_drm_format *fmt = *ptr; - - if (modifier == DRM_FORMAT_MOD_INVALID) { - return true; - } - - for (size_t i = 0; i < fmt->len; ++i) { - if (fmt->modifiers[i] == modifier) { - return true; - } - } - - if (fmt->len == fmt->cap) { - size_t cap = fmt->cap ? fmt->cap * 2 : 4; - - fmt = realloc(fmt, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); - if (!fmt) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - return false; - } - - fmt->cap = cap; - *ptr = fmt; - } - - fmt->modifiers[fmt->len++] = modifier; - return true; + return wlr_drm_format_add(ptr, modifier); } - size_t cap = modifier != DRM_FORMAT_MOD_INVALID ? 4 : 0; - - struct wlr_drm_format *fmt = - calloc(1, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + struct wlr_drm_format *fmt = wlr_drm_format_create(format); if (!fmt) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); return false; } - - fmt->format = format; - if (cap) { - fmt->cap = cap; - fmt->len = 1; - fmt->modifiers[0] = modifier; + if (!wlr_drm_format_add(&fmt, modifier)) { + return false; } if (set->len == set->cap) { @@ -127,6 +93,49 @@ bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, return true; } +struct wlr_drm_format *wlr_drm_format_create(uint32_t format) { + size_t cap = 4; + struct wlr_drm_format *fmt = + calloc(1, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + if (!fmt) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + fmt->format = format; + fmt->cap = cap; + return fmt; +} + +bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier) { + struct wlr_drm_format *fmt = *fmt_ptr; + + if (modifier == DRM_FORMAT_MOD_INVALID) { + return true; + } + + for (size_t i = 0; i < fmt->len; ++i) { + if (fmt->modifiers[i] == modifier) { + return true; + } + } + + if (fmt->len == fmt->cap) { + size_t cap = fmt->cap ? fmt->cap * 2 : 4; + + fmt = realloc(fmt, sizeof(*fmt) + sizeof(fmt->modifiers[0]) * cap); + if (!fmt) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } + + fmt->cap = cap; + *fmt_ptr = fmt; + } + + fmt->modifiers[fmt->len++] = modifier; + return true; +} + struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format) { assert(format->len <= format->cap); size_t format_size = sizeof(struct wlr_drm_format) + From 1e2c7fce869c009fdcd91e011cffcfdf229816e7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 12 Dec 2020 22:26:52 +0100 Subject: [PATCH 210/223] backend/drm: use wlr_drm_format_{create,add} Instead of manually allocating and initializing the structs, use the new wlr_drm_format helpers. --- backend/drm/renderer.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7599623ac..61b838bc2 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -256,20 +256,19 @@ bool drm_plane_init_surface(struct wlr_drm_plane *plane, return false; } } else { - const struct wlr_drm_format format_no_modifiers = { .format = format }; - drm_format = wlr_drm_format_dup(&format_no_modifiers); + drm_format = wlr_drm_format_create(format); } - struct wlr_drm_format *drm_format_linear = - calloc(1, sizeof(struct wlr_drm_format) + sizeof(uint64_t)); + struct wlr_drm_format *drm_format_linear = wlr_drm_format_create(format); if (drm_format_linear == NULL) { free(drm_format); return false; } - drm_format_linear->format = drm_format->format; - drm_format_linear->len = 1; - drm_format_linear->cap = 1; - drm_format_linear->modifiers[0] = DRM_FORMAT_MOD_LINEAR; + if (!wlr_drm_format_add(&drm_format_linear, DRM_FORMAT_MOD_LINEAR)) { + free(drm_format_linear); + free(drm_format); + return false; + } if (force_linear) { free(drm_format); From 94fda895accd2538aa61ba4a0aad610750d797d1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 12 Dec 2020 15:48:50 +0100 Subject: [PATCH 211/223] backend/x11: use DRI3Open to get DRM FD Instead of relying on EGL to retrieve the DRM FD, query it from the DRI3 extension. Use the EGL GBM platform, and drop the EGL config. --- backend/x11/backend.c | 94 ++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 6e79129f6..6067c89f4 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -180,8 +180,9 @@ static void backend_destroy(struct wlr_backend *backend) { wl_list_remove(&x11->display_destroy.link); wlr_renderer_destroy(x11->renderer); - wlr_drm_format_set_finish(&x11->dri3_formats); wlr_egl_finish(&x11->egl); + wlr_allocator_destroy(x11->allocator); + wlr_drm_format_set_finish(&x11->dri3_formats); free(x11->drm_format); #if WLR_HAS_XCB_ERRORS @@ -237,6 +238,39 @@ static xcb_visualid_t pick_visualid(xcb_depth_t *depth) { return 0; } +static int query_dri3_drm_fd(struct wlr_x11_backend *x11) { + xcb_dri3_open_cookie_t open_cookie = + xcb_dri3_open(x11->xcb, x11->screen->root, 0); + xcb_dri3_open_reply_t *open_reply = + xcb_dri3_open_reply(x11->xcb, open_cookie, NULL); + if (open_reply == NULL) { + return -1; + } + + int *open_fds = xcb_dri3_open_reply_fds(x11->xcb, open_reply); + if (open_fds == NULL) { + free(open_reply); + return -1; + } + + assert(open_reply->nfd == 1); + int drm_fd = open_fds[0]; + + free(open_reply); + + int flags = fcntl(drm_fd, F_GETFD); + if (flags < 0) { + close(drm_fd); + return -1; + } + if (fcntl(drm_fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + close(drm_fd); + return -1; + } + + return drm_fd; +} + static bool query_dri3_modifiers(struct wlr_x11_backend *x11, const struct wlr_x11_format *format) { // Query the root window's supported modifiers, because we only care about @@ -437,72 +471,58 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb)).data; if (!x11->screen) { wlr_log(WLR_ERROR, "Failed to get X11 screen"); - goto error_display; + goto error_event; } x11->depth = get_depth(x11->screen, 32); if (!x11->depth) { wlr_log(WLR_ERROR, "Failed to get 32-bit depth for X11 screen"); - goto error_display; + goto error_event; } x11->visualid = pick_visualid(x11->depth); if (!x11->visualid) { wlr_log(WLR_ERROR, "Failed to pick X11 visual"); - goto error_display; + goto error_event; } x11->x11_format = x11_format_from_depth(x11->depth->depth); if (!x11->x11_format) { wlr_log(WLR_ERROR, "Unsupported depth %"PRIu8, x11->depth->depth); - goto error_display; + goto error_event; } x11->colormap = xcb_generate_id(x11->xcb); xcb_create_colormap(x11->xcb, XCB_COLORMAP_ALLOC_NONE, x11->colormap, x11->screen->root, x11->visualid); + // DRI3 may return a render node (Xwayland) or an authenticated primary + // node (plain Glamor). + int drm_fd = query_dri3_drm_fd(x11); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to query DRI3 DRM FD"); + goto error_event; + } + + struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd); + if (gbm_alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + close(drm_fd); + goto error_event; + } + x11->allocator = &gbm_alloc->base; + if (!create_renderer_func) { create_renderer_func = wlr_renderer_autocreate; } - static EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 1, - EGL_NONE, - }; - - x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_X11_KHR, - x11->xlib_conn, config_attribs, x11->screen->root_visual); + x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_GBM_KHR, + gbm_alloc->gbm_device, NULL, 0); if (x11->renderer == NULL) { wlr_log(WLR_ERROR, "Failed to create renderer"); goto error_event; } - // TODO: we can use DRI3Open instead - int drm_fd = wlr_renderer_get_drm_fd(x11->renderer); - if (fd < 0) { - wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); - return false; - } - - drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0); - if (drm_fd < 0) { - wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed"); - return false; - } - - struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); - if (alloc == NULL) { - wlr_log(WLR_ERROR, "Failed to create GBM allocator"); - return false; - } - x11->allocator = &alloc->base; - const struct wlr_drm_format_set *render_formats = wlr_renderer_get_dmabuf_render_formats(x11->renderer); if (render_formats == NULL) { From f0c1b32120563e6a9a770a458b397f0021b9e639 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 13 Dec 2020 12:53:43 +0100 Subject: [PATCH 212/223] util/time: add timespec_from_nsec --- include/util/time.h | 5 +++++ util/time.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/util/time.h b/include/util/time.h index 6b35ef5f7..287698dec 100644 --- a/include/util/time.h +++ b/include/util/time.h @@ -13,6 +13,11 @@ uint32_t get_current_time_msec(void); */ int64_t timespec_to_msec(const struct timespec *a); +/** + * Convert nanoseconds to a timespec. + */ +void timespec_from_nsec(struct timespec *r, int64_t nsec); + /** * Subtracts timespec `b` from timespec `a`, and stores the difference in `r`. */ diff --git a/util/time.c b/util/time.c index aed577de4..e1bc2b5c4 100644 --- a/util/time.c +++ b/util/time.c @@ -10,6 +10,11 @@ int64_t timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } +void timespec_from_nsec(struct timespec *r, int64_t nsec) { + r->tv_sec = nsec / NSEC_PER_SEC; + r->tv_nsec = nsec % NSEC_PER_SEC; +} + uint32_t get_current_time_msec(void) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); From 0aefa186906420f2a8f37f2f823a533c9187e7f5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 13 Dec 2020 12:54:05 +0100 Subject: [PATCH 213/223] backend/x11: send more precise output present events Instead of sending dummy output present events, use the X11 Present extension to send more precise events. --- backend/x11/output.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/backend/x11/output.c b/backend/x11/output.c index c7cf1b633..cba9f6001 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -19,6 +19,7 @@ #include "render/swapchain.h" #include "render/wlr_renderer.h" #include "util/signal.h" +#include "util/time.h" static int signal_frame(void *data) { struct wlr_x11_output *output = data; @@ -239,8 +240,6 @@ static bool output_commit_buffer(struct wlr_x11_output *output) { wlr_swapchain_set_buffer_submitted(output->swapchain, x11_buffer->buffer); - wlr_output_send_present(&output->wlr_output, NULL); - return true; error: @@ -379,7 +378,8 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { }; xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head); - uint32_t present_mask = XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY; + uint32_t present_mask = XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY | + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY; xcb_present_select_input(x11->xcb, x11->present_event_id, output->win, present_mask); @@ -482,13 +482,14 @@ static struct wlr_x11_buffer *get_x11_buffer(struct wlr_x11_output *output, void handle_x11_present_event(struct wlr_x11_backend *x11, xcb_ge_generic_event_t *event) { + struct wlr_x11_output *output; + switch (event->event_type) { case XCB_PRESENT_EVENT_IDLE_NOTIFY:; xcb_present_idle_notify_event_t *idle_notify = (xcb_present_idle_notify_event_t *)event; - struct wlr_x11_output *output = - get_x11_output_from_window_id(x11, idle_notify->window); + output = get_x11_output_from_window_id(x11, idle_notify->window); if (!output) { wlr_log(WLR_DEBUG, "Got PresentIdleNotify event for unknown window"); return; @@ -503,6 +504,33 @@ void handle_x11_present_event(struct wlr_x11_backend *x11, destroy_x11_buffer(buffer); break; + case XCB_PRESENT_COMPLETE_NOTIFY:; + xcb_present_complete_notify_event_t *complete_notify = + (xcb_present_complete_notify_event_t *)event; + + output = get_x11_output_from_window_id(x11, complete_notify->window); + if (!output) { + wlr_log(WLR_DEBUG, "Got PresentCompleteNotify event for unknown window"); + return; + } + + struct timespec t; + timespec_from_nsec(&t, complete_notify->ust * 1000); + + uint32_t flags = 0; + if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) { + flags |= WLR_OUTPUT_PRESENT_ZERO_COPY; + } + + struct wlr_output_event_present present_event = { + .output = &output->wlr_output, + .commit_seq = complete_notify->serial, + .when = &t, + .seq = complete_notify->msc, + .flags = flags, + }; + wlr_output_send_present(&output->wlr_output, &present_event); + break; default: wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type); } From c89b131f29343c6c91f24cdb259c5dd6663dd80e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 14:50:39 +0100 Subject: [PATCH 214/223] backend/drm: introduce wlr_drm_conn_log Simplify and unify connector-specific logging with a new wlr_drm_conn_log macro. This makes it easier to understand which connector a failure is about, without having to explicitly integrate the connector name in each log message. --- backend/drm/drm.c | 90 +++++++++++++++++++-------------------- backend/drm/legacy.c | 29 ++++++------- include/backend/drm/drm.h | 8 +++- 3 files changed, 62 insertions(+), 65 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 017c5c63e..d64b8cca6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -363,8 +363,8 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) { // we'll wait for all queued page-flips to complete, so we don't need this // safeguard. if (conn->pageflip_pending && !crtc->pending_modeset) { - wlr_log(WLR_ERROR, "Failed to page-flip output '%s': " - "a page-flip is already pending", conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: " + "a page-flip is already pending"); return false; } @@ -445,7 +445,8 @@ static bool drm_connector_test(struct wlr_output *output) { output->pending.enabled) { if (output->current_mode == NULL && !(output->pending.committed & WLR_OUTPUT_STATE_MODE)) { - wlr_log(WLR_DEBUG, "Can't enable an output without a mode"); + wlr_drm_conn_log(conn, WLR_DEBUG, + "Can't enable an output without a mode"); return false; } } @@ -492,7 +493,7 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) { switch (output->pending.buffer_type) { case WLR_OUTPUT_STATE_BUFFER_RENDER: if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) { - wlr_log(WLR_ERROR, "drm_fb_lock_surface failed"); + wlr_drm_conn_log(conn, WLR_ERROR, "drm_fb_lock_surface failed"); return false; } break; @@ -527,13 +528,13 @@ bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { if (conn->props.vrr_capable == 0 || !get_drm_prop(drm->fd, conn->id, conn->props.vrr_capable, &vrr_capable) || !vrr_capable) { - wlr_log(WLR_DEBUG, "Failed to enable adaptive sync: " - "connector '%s' doesn't support VRR", conn->output.name); + wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " + "connector doesn't support VRR"); return false; } if (crtc->props.vrr_enabled == 0) { - wlr_log(WLR_DEBUG, "Failed to enable adaptive sync: " + wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " "CRTC %"PRIu32" doesn't support VRR", crtc->id); return false; } @@ -663,8 +664,7 @@ struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) { static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) { struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { - wlr_log(WLR_ERROR, "Page-flip failed on connector '%s': no CRTC", - conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, "Page-flip failed: no CRTC"); return false; } @@ -691,13 +691,12 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, return false; } - wlr_log(WLR_DEBUG, "Initializing renderer on connector '%s'", - conn->output.name); + wlr_drm_conn_log(conn, WLR_DEBUG, "Initializing renderer"); struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { - wlr_log(WLR_ERROR, "Failed to initialize renderer on connector '%s': " - "no CRTC", conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, + "Failed to initialize renderer: no CRTC"); return false; } struct wlr_drm_plane *plane = crtc->primary; @@ -713,7 +712,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, bool modifiers = true; const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS"); if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) { - wlr_log(WLR_DEBUG, + wlr_drm_conn_log(conn, WLR_DEBUG, "WLR_DRM_NO_MODIFIERS set, initializing planes without modifiers"); modifiers = false; } @@ -721,15 +720,15 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, if (!drm_plane_init_surface(plane, drm, width, height, format, false, modifiers) || !drm_connector_pageflip_renderer(conn)) { if (!modifiers) { - wlr_log(WLR_ERROR, "Failed to initialize renderer " - "on connector '%s': initial page-flip failed", - conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer:" + "initial page-flip failed"); return false; } // If page-flipping with modifiers enabled doesn't work, retry without // modifiers - wlr_log(WLR_INFO, "Page-flip failed with primary FB modifiers enabled, " + wlr_drm_conn_log(conn, WLR_INFO, + "Page-flip failed with primary FB modifiers enabled, " "retrying without modifiers"); modifiers = false; @@ -742,9 +741,8 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn, return false; } if (!drm_connector_pageflip_renderer(conn)) { - wlr_log(WLR_ERROR, "Failed to initialize renderer " - "on connector '%s': initial page-flip failed", - conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer:" + "initial page-flip failed"); return false; } } @@ -762,8 +760,8 @@ static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) { if (conn->state == WLR_DRM_CONN_NEEDS_MODESET && conn->crtc != NULL && conn->desired_mode != NULL && conn->desired_enabled) { - wlr_log(WLR_DEBUG, "Output %s has a desired mode and a CRTC, " - "attempting a modeset", conn->output.name); + wlr_drm_conn_log(conn, WLR_DEBUG, + "Output has a desired mode and a CRTC, attempting a modeset"); drm_connector_set_mode(conn, conn->desired_mode); } } @@ -794,7 +792,8 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn, if (conn->state != WLR_DRM_CONN_CONNECTED && conn->state != WLR_DRM_CONN_NEEDS_MODESET) { - wlr_log(WLR_ERROR, "Cannot modeset a disconnected output"); + wlr_drm_conn_log(conn, WLR_ERROR, + "Cannot modeset a disconnected output"); return false; } @@ -803,18 +802,19 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn, realloc_crtcs(drm); } if (conn->crtc == NULL) { - wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector", - conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, + "Cannot perform modeset: no CRTC for this connector"); return false; } - wlr_log(WLR_INFO, "Modesetting '%s' with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'", - conn->output.name, wlr_mode->width, wlr_mode->height, - wlr_mode->refresh); + wlr_drm_conn_log(conn, WLR_INFO, + "Modesetting with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'", + wlr_mode->width, wlr_mode->height, wlr_mode->refresh); struct wlr_drm_mode *mode = (struct wlr_drm_mode *)wlr_mode; if (!drm_connector_init_renderer(conn, mode)) { - wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); + wlr_drm_conn_log(conn, WLR_ERROR, + "Failed to initialize renderer for plane"); return false; } @@ -857,7 +857,7 @@ struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output, mode->wlr_mode.height = mode->drm_mode.vdisplay; mode->wlr_mode.refresh = calculate_refresh_rate(modeinfo); - wlr_log(WLR_INFO, "Registered custom mode " + wlr_drm_conn_log(conn, WLR_INFO, "Registered custom mode " "%"PRId32"x%"PRId32"@%"PRId32, mode->wlr_mode.width, mode->wlr_mode.height, mode->wlr_mode.refresh); @@ -893,7 +893,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, if (!drm_plane_init_surface(plane, drm, w, h, DRM_FORMAT_ARGB8888, true, false)) { - wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); + wlr_drm_conn_log(conn, WLR_ERROR, "Cannot allocate cursor resources"); return false; } } @@ -931,7 +931,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, height = height * output->scale / scale; if (width > (int)plane->surf.width || height > (int)plane->surf.height) { - wlr_log(WLR_ERROR, "Cursor too large (max %dx%d)", + wlr_drm_conn_log(conn, WLR_ERROR, "Cursor too large (max %dx%d)", (int)plane->surf.width, (int)plane->surf.height); return false; } @@ -1043,8 +1043,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) { return; } - wlr_log(WLR_DEBUG, "De-allocating CRTC %zu for output '%s'", - conn->crtc - drm->crtcs, conn->output.name); + wlr_drm_conn_log(conn, WLR_DEBUG, "De-allocating CRTC %zu", + conn->crtc - drm->crtcs); conn->crtc->pending_modeset = true; conn->crtc->pending.active = false; @@ -1159,8 +1159,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { if (connector_match[i] == -1) { if (prev_enabled) { - wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", - conn->output.name); + wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC"); conn->state = WLR_DRM_CONN_NEEDS_MODESET; wlr_output_update_enabled(&conn->output, false); conn->desired_mode = conn->output.current_mode; @@ -1179,8 +1178,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { struct wlr_drm_mode *mode = (struct wlr_drm_mode *)conn->output.current_mode; if (!drm_connector_init_renderer(conn, mode)) { - wlr_log(WLR_ERROR, "Failed to initialize renderer on output %s", - conn->output.name); + wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer"); wlr_output_update_enabled(&conn->output, false); continue; } @@ -1298,14 +1296,14 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { uint64_t link_status; if (!get_drm_prop(drm->fd, wlr_conn->id, wlr_conn->props.link_status, &link_status)) { - wlr_log(WLR_ERROR, "Failed to get link status for '%s'", - wlr_conn->output.name); + wlr_drm_conn_log(wlr_conn, WLR_ERROR, + "Failed to get link status prop"); continue; } if (link_status == DRM_MODE_LINK_STATUS_BAD) { // We need to reload our list of modes and force a modeset - wlr_log(WLR_INFO, "Bad link for '%s'", wlr_conn->output.name); + wlr_drm_conn_log(wlr_conn, WLR_INFO, "Bad link detected"); drm_connector_cleanup(wlr_conn); } } @@ -1368,8 +1366,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn); if (wlr_conn->possible_crtc == 0) { - wlr_log(WLR_ERROR, "No CRTC possible for connector '%s'", - wlr_conn->output.name); + wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible"); } // TODO: this results in connectors being enabled without a mode @@ -1414,8 +1411,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { for (size_t i = 0; i < new_outputs_len; ++i) { struct wlr_drm_connector *conn = new_outputs[i]; - wlr_log(WLR_INFO, "Requesting modeset for '%s'", - conn->output.name); + wlr_drm_conn_log(conn, WLR_INFO, "Requesting modeset"); wlr_signal_emit_safe(&drm->backend.events.new_output, &conn->output); } @@ -1440,7 +1436,7 @@ static void page_flip_handler(int fd, unsigned seq, } } if (!conn) { - wlr_log(WLR_DEBUG, "No connector for crtc_id %u", crtc_id); + wlr_log(WLR_DEBUG, "No connector for CRTC %u", crtc_id); return; } diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 3380461ca..fc3158e16 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -42,15 +42,14 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm, DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF; if (drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms, dpms) != 0) { - wlr_log_errno(WLR_ERROR, "%s: failed to set DPMS property", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_ERROR, + "Failed to set DPMS property"); return false; } if (drmModeSetCrtc(drm->fd, crtc->id, fb_id, 0, 0, conns, conns_len, mode)) { - wlr_log_errno(WLR_ERROR, "%s: failed to set CRTC", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_ERROR, "Failed to set CRTC"); return false; } } @@ -67,16 +66,15 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm, if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC, crtc->props.vrr_enabled, output->pending.adaptive_sync_enabled) != 0) { - wlr_log_errno(WLR_ERROR, + wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModeObjectSetProperty(VRR_ENABLED) failed"); return false; } output->adaptive_sync_status = output->pending.adaptive_sync_enabled ? WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; - wlr_log(WLR_DEBUG, "VRR %s on connector '%s'", - output->pending.adaptive_sync_enabled ? "enabled" : "disabled", - output->name); + wlr_drm_conn_log(conn, WLR_DEBUG, "VRR %s", + output->pending.adaptive_sync_enabled ? "enabled" : "disabled"); } if (cursor != NULL && drm_connector_is_cursor_visible(conn)) { @@ -84,29 +82,26 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm, struct gbm_bo *cursor_bo = drm_fb_acquire(cursor_fb, drm, &cursor->mgpu_surf); if (!cursor_bo) { - wlr_log_errno(WLR_DEBUG, "%s: failed to acquire cursor FB", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_DEBUG, + "Failed to acquire cursor FB"); return false; } if (drmModeSetCursor(drm->fd, crtc->id, gbm_bo_get_handle(cursor_bo).u32, cursor->surf.width, cursor->surf.height)) { - wlr_log_errno(WLR_DEBUG, "%s: failed to set hardware cursor", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed"); return false; } if (drmModeMoveCursor(drm->fd, crtc->id, conn->cursor_x, conn->cursor_y) != 0) { - wlr_log_errno(WLR_ERROR, "%s: failed to move cursor", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModeMoveCursor failed"); return false; } } else { if (drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0)) { - wlr_log_errno(WLR_DEBUG, "%s: failed to unset hardware cursor", - conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed"); return false; } } @@ -114,7 +109,7 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm, if (flags & DRM_MODE_PAGE_FLIP_EVENT) { if (drmModePageFlip(drm->fd, crtc->id, fb_id, DRM_MODE_PAGE_FLIP_EVENT, drm)) { - wlr_log_errno(WLR_ERROR, "%s: Failed to page flip", conn->output.name); + wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed"); return false; } } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index ea3cdbd46..9ee62ead1 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -110,9 +110,10 @@ struct wlr_drm_mode { }; struct wlr_drm_connector { - struct wlr_output output; + struct wlr_output output; // only valid if state != DISCONNECTED struct wlr_drm_backend *backend; + char name[24]; enum wlr_drm_connector_state state; struct wlr_output_mode *desired_mode; bool desired_enabled; @@ -155,4 +156,9 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane); +#define wlr_drm_conn_log(conn, verb, fmt, ...) \ + wlr_log(verb, "connector %s: " fmt, conn->output.name, ##__VA_ARGS__) +#define wlr_drm_conn_log_errno(conn, verb, fmt, ...) \ + wlr_log_errno(verb, "connector %s: " fmt, conn->output.name, ##__VA_ARGS__) + #endif From 019ffe8a5ba7f97181c56ad2b9a772c717391feb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 15:11:06 +0100 Subject: [PATCH 215/223] backend/drm: introduce wlr_drm_connector.name The DRM backend is a little special when it comes to wlr_outputs: the wlr_drm_connectors are long-lived and are created even when no screen is connected. A wlr_drm_connector only advertises a wlr_output to the compositor when a screen is connected. As such, most of wlr_output's state is invalid when the connector is disconnected. We want to stop using wlr_output state on disconnected connectors. Introduce wlr_drm_connector.name which is always valid regardless of the connector status to avoid reading wlr_output.name when disconnected. --- backend/drm/atomic.c | 2 +- backend/drm/drm.c | 20 ++++++++++---------- include/backend/drm/drm.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index f230419fb..fe67244f0 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -33,7 +33,7 @@ static bool atomic_commit(struct atomic *atom, int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm); if (ret) { wlr_log_errno(WLR_ERROR, "%s: Atomic %s failed (%s)", - conn->output.name, + conn->name, (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit", (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip"); return false; diff --git a/backend/drm/drm.c b/backend/drm/drm.c index d64b8cca6..82b928b35 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1087,8 +1087,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { connectors[i] = conn; wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d desired_enabled=%d", - conn->output.name, - conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, + conn->name, conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, conn->state, conn->desired_enabled); if (conn->crtc) { @@ -1146,9 +1145,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { bool prev_enabled = conn->crtc; wlr_log(WLR_DEBUG, " '%s' crtc=%zd state=%d desired_enabled=%d", - conn->output.name, - connector_match[i], - conn->state, conn->desired_enabled); + conn->name, connector_match[i], conn->state, conn->desired_enabled); // We don't need to change anything. if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) { @@ -1265,7 +1262,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; wlr_conn->id = drm_conn->connector_id; - snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name), + snprintf(wlr_conn->name, sizeof(wlr_conn->name), "%s-%"PRIu32, conn_get_name(drm_conn->connector_type), drm_conn->connector_type_id); @@ -1274,7 +1271,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } wl_list_insert(drm->outputs.prev, &wlr_conn->link); - wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->output.name); + wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name); } else { seen[index] = true; } @@ -1310,10 +1307,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED && drm_conn->connection == DRM_MODE_CONNECTED) { - wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name); + wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name); wlr_log(WLR_DEBUG, "Current CRTC: %d", wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1); + strncpy(wlr_conn->output.name, wlr_conn->name, + sizeof(wlr_conn->output.name) - 1); + wlr_conn->output.phys_width = drm_conn->mmWidth; wlr_conn->output.phys_height = drm_conn->mmHeight; wlr_log(WLR_INFO, "Physical size: %"PRId32"x%"PRId32, @@ -1379,7 +1379,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } else if ((wlr_conn->state == WLR_DRM_CONN_CONNECTED || wlr_conn->state == WLR_DRM_CONN_NEEDS_MODESET) && drm_conn->connection != DRM_MODE_CONNECTED) { - wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->output.name); + wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name); drm_connector_cleanup(wlr_conn); } @@ -1400,7 +1400,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { continue; } - wlr_log(WLR_INFO, "'%s' disappeared", conn->output.name); + wlr_log(WLR_INFO, "'%s' disappeared", conn->name); drm_connector_cleanup(conn); wlr_output_destroy(&conn->output); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 9ee62ead1..cd534202d 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -157,8 +157,8 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane); #define wlr_drm_conn_log(conn, verb, fmt, ...) \ - wlr_log(verb, "connector %s: " fmt, conn->output.name, ##__VA_ARGS__) + wlr_log(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__) #define wlr_drm_conn_log_errno(conn, verb, fmt, ...) \ - wlr_log_errno(verb, "connector %s: " fmt, conn->output.name, ##__VA_ARGS__) + wlr_log_errno(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__) #endif From 248c7787c7b487ff4157bfef38662776ea7b38d9 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Dec 2020 15:15:17 +0100 Subject: [PATCH 216/223] backend/drm: refactor wlr_output destruction Instead of hand-rolling our own manual wlr_output cleanup function, rely on wlr_output_destroy to remove an output from the compositor's state. --- backend/drm/backend.c | 2 +- backend/drm/drm.c | 105 +++++++++++++++++--------------------- include/backend/drm/drm.h | 1 + 3 files changed, 49 insertions(+), 59 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 44794b511..ea87532f9 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -38,7 +38,7 @@ static void backend_destroy(struct wlr_backend *backend) { struct wlr_drm_connector *conn, *next; wl_list_for_each_safe(conn, next, &drm->outputs, link) { - wlr_output_destroy(&conn->output); + destroy_drm_connector(conn); } wlr_signal_emit_safe(&backend->events.destroy, backend); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 82b928b35..5395e418a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -767,8 +767,6 @@ static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) { } } -static void drm_connector_cleanup(struct wlr_drm_connector *conn); - bool drm_connector_set_mode(struct wlr_drm_connector *conn, struct wlr_output_mode *wlr_mode) { struct wlr_drm_backend *drm = conn->backend; @@ -1004,18 +1002,38 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn) { conn->cursor_y + (int)plane->surf.height >= 0; } -static void drm_connector_destroy(struct wlr_output *output) { +static void dealloc_crtc(struct wlr_drm_connector *conn); + +/** + * Destroy the compositor-facing part of a connector. + * + * The connector isn't destroyed when disconnected. Only the compositor-facing + * wlr_output interface is cleaned up. + */ +static void drm_connector_destroy_output(struct wlr_output *output) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - drm_connector_cleanup(conn); - drmModeFreeCrtc(conn->old_crtc); - wl_list_remove(&conn->link); - free(conn); + + dealloc_crtc(conn); + + conn->state = WLR_DRM_CONN_DISCONNECTED; + conn->desired_enabled = false; + conn->desired_mode = NULL; + conn->possible_crtc = 0; + conn->pageflip_pending = false; + + struct wlr_drm_mode *mode, *mode_tmp; + wl_list_for_each_safe(mode, mode_tmp, &conn->output.modes, wlr_mode.link) { + wl_list_remove(&mode->wlr_mode.link); + free(mode); + } + + memset(&conn->output, 0, sizeof(struct wlr_output)); } static const struct wlr_output_impl output_impl = { .set_cursor = drm_connector_set_cursor, .move_cursor = drm_connector_move_cursor, - .destroy = drm_connector_destroy, + .destroy = drm_connector_destroy_output, .attach_render = drm_connector_attach_render, .test = drm_connector_test, .commit = drm_connector_commit, @@ -1202,6 +1220,8 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res, return possible_crtcs; } +static void disconnect_drm_connector(struct wlr_drm_connector *conn); + void scan_drm_connectors(struct wlr_drm_backend *drm) { /* * This GPU is not really a modesetting device. @@ -1255,8 +1275,6 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { drmModeFreeConnector(drm_conn); continue; } - wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, - drm->display); wlr_conn->backend = drm; wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; @@ -1301,7 +1319,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { if (link_status == DRM_MODE_LINK_STATUS_BAD) { // We need to reload our list of modes and force a modeset wlr_drm_conn_log(wlr_conn, WLR_INFO, "Bad link detected"); - drm_connector_cleanup(wlr_conn); + disconnect_drm_connector(wlr_conn); } } @@ -1311,6 +1329,9 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_log(WLR_DEBUG, "Current CRTC: %d", wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1); + wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, + drm->display); + strncpy(wlr_conn->output.name, wlr_conn->name, sizeof(wlr_conn->output.name) - 1); @@ -1380,8 +1401,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->state == WLR_DRM_CONN_NEEDS_MODESET) && drm_conn->connection != DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name); - - drm_connector_cleanup(wlr_conn); + disconnect_drm_connector(wlr_conn); } drmModeFreeEncoder(curr_enc); @@ -1401,9 +1421,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } wlr_log(WLR_INFO, "'%s' disappeared", conn->name); - drm_connector_cleanup(conn); - - wlr_output_destroy(&conn->output); + disconnect_drm_connector(conn); } realloc_crtcs(drm); @@ -1536,49 +1554,20 @@ void restore_drm_outputs(struct wlr_drm_backend *drm) { } } -static void drm_connector_cleanup(struct wlr_drm_connector *conn) { - if (!conn) { +static void disconnect_drm_connector(struct wlr_drm_connector *conn) { + if (conn->state == WLR_DRM_CONN_DISCONNECTED) { return; } - switch (conn->state) { - case WLR_DRM_CONN_CONNECTED: - case WLR_DRM_CONN_CLEANUP: - conn->output.current_mode = NULL; - conn->desired_mode = NULL; - struct wlr_drm_mode *mode, *tmp; - wl_list_for_each_safe(mode, tmp, &conn->output.modes, wlr_mode.link) { - wl_list_remove(&mode->wlr_mode.link); - free(mode); - } - - conn->output.enabled = false; - conn->output.width = conn->output.height = conn->output.refresh = 0; - - if (conn->output.idle_frame != NULL) { - wl_event_source_remove(conn->output.idle_frame); - conn->output.idle_frame = NULL; - } - conn->output.needs_frame = false; - conn->output.frame_pending = false; - - /* Fallthrough */ - case WLR_DRM_CONN_NEEDS_MODESET: - wlr_log(WLR_INFO, "Emitting destruction signal for '%s'", - conn->output.name); - dealloc_crtc(conn); - conn->possible_crtc = 0; - conn->desired_mode = NULL; - conn->pageflip_pending = false; - wlr_signal_emit_safe(&conn->output.events.destroy, &conn->output); - - memset(&conn->output.make, 0, sizeof(conn->output.make)); - memset(&conn->output.model, 0, sizeof(conn->output.model)); - memset(&conn->output.serial, 0, sizeof(conn->output.serial)); - break; - case WLR_DRM_CONN_DISCONNECTED: - break; - } - - conn->state = WLR_DRM_CONN_DISCONNECTED; + // This will cleanup the compositor-facing wlr_output, but won't destroy + // our wlr_drm_connector. + wlr_output_destroy(&conn->output); +} + +void destroy_drm_connector(struct wlr_drm_connector *conn) { + disconnect_drm_connector(conn); + + drmModeFreeCrtc(conn->old_crtc); + wl_list_remove(&conn->link); + free(conn); } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index cd534202d..6fdfe41a3 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -147,6 +147,7 @@ void finish_drm_resources(struct wlr_drm_backend *drm); void restore_drm_outputs(struct wlr_drm_backend *drm); void scan_drm_connectors(struct wlr_drm_backend *state); int handle_drm_event(int fd, uint32_t mask, void *data); +void destroy_drm_connector(struct wlr_drm_connector *conn); bool drm_connector_set_mode(struct wlr_drm_connector *conn, struct wlr_output_mode *mode); bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn); From 352fdd1bb00a3547591f9360b23c5c2fd22e97e4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 18 Dec 2020 11:44:50 +0100 Subject: [PATCH 217/223] backend/drm: remove unused wlr_drm_plane.drm_format --- backend/drm/drm.c | 15 --------------- include/backend/drm/drm.h | 1 - 2 files changed, 16 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 5395e418a..bdd0b1e45 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -105,21 +105,6 @@ static bool add_plane(struct wlr_drm_backend *drm, DRM_FORMAT_MOD_INVALID); } - // Choose an RGB format for the plane - uint32_t rgb_format = DRM_FORMAT_INVALID; - for (size_t j = 0; j < drm_plane->count_formats; ++j) { - uint32_t fmt = drm_plane->formats[j]; - - if (fmt == DRM_FORMAT_ARGB8888) { - // Prefer formats with alpha channel - rgb_format = fmt; - break; - } else if (fmt == DRM_FORMAT_XRGB8888) { - rgb_format = fmt; - } - } - p->drm_format = rgb_format; - if (p->props.in_formats) { uint64_t blob_id; if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 6fdfe41a3..6c8939e83 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -32,7 +32,6 @@ struct wlr_drm_plane { /* Buffer currently displayed on screen */ struct wlr_drm_fb current_fb; - uint32_t drm_format; // ARGB8888 or XRGB8888 struct wlr_drm_format_set formats; // Only used by cursor From 917ecca58ea8ec88a413982502108903066641f0 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Fri, 18 Dec 2020 14:08:44 -0700 Subject: [PATCH 218/223] backend/drm: avoid gcc stringop-truncation warning --- backend/drm/drm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index bdd0b1e45..50256abd8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1317,8 +1317,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, drm->display); - strncpy(wlr_conn->output.name, wlr_conn->name, - sizeof(wlr_conn->output.name) - 1); + memcpy(wlr_conn->output.name, wlr_conn->name, + sizeof(wlr_conn->output.name)); wlr_conn->output.phys_width = drm_conn->mmWidth; wlr_conn->output.phys_height = drm_conn->mmHeight; From 6c08fe979615ac88648eb91c87ea4c41fa1d7bdf Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 18 Dec 2020 19:53:44 +0100 Subject: [PATCH 219/223] xwayland: avoid crash on repeated server_finish_display() call This function may end up being called more than once if the Xwayland binary does not exist on the system. --- xwayland/server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xwayland/server.c b/xwayland/server.c index f72b668d4..6a0c9fc30 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -164,6 +164,7 @@ static void server_finish_display(struct wlr_xwayland_server *server) { } wl_list_remove(&server->display_destroy.link); + wl_list_init(&server->display_destroy.link); if (server->display == -1) { return; From de896caceb9f6354a99c9435c3a429ff52b6ca4a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 19 Dec 2020 16:23:33 +0100 Subject: [PATCH 220/223] backend/wayland: remove EGL config We don't use EGLSurface anymore, so we don't need to choose an EGL config anymore. --- backend/wayland/backend.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 5b8bce9b1..8e77133dc 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -309,22 +309,12 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl_event_source_check(wl->remote_display_src); - static EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 1, - EGL_NONE, - }; - if (!create_renderer_func) { create_renderer_func = wlr_renderer_autocreate; } wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT, - wl->remote_display, config_attribs, 0); + wl->remote_display, NULL, 0); if (!wl->renderer) { wlr_log(WLR_ERROR, "Could not create renderer"); goto error_event; From defcd9b025c8a6ce844f8b2c772ee763cbc334b5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 11 Dec 2020 18:14:58 +0100 Subject: [PATCH 221/223] backend/wayland: re-use wl_buffers Instead of re-importing a buffer each time we submit a new frame, re-use the wl_buffer objects if possible. --- backend/wayland/backend.c | 6 ++++++ backend/wayland/output.c | 38 ++++++++++++++++++++++++++++++++++---- include/backend/wayland.h | 6 ++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 8e77133dc..11b769bf9 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -210,6 +210,11 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats); + struct wlr_wl_buffer *buffer, *tmp_buffer; + wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) { + destroy_wl_buffer(buffer); + } + destroy_wl_seats(wl); if (wl->zxdg_decoration_manager_v1) { zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1); @@ -270,6 +275,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wl_list_init(&wl->devices); wl_list_init(&wl->outputs); wl_list_init(&wl->seats); + wl_list_init(&wl->buffers); wl->remote_display = wl_display_connect(remote); if (!wl->remote_display) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 188c22b6c..db9056d51 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -133,24 +133,33 @@ static bool output_attach_render(struct wlr_output *wlr_output, return true; } -static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) { +void destroy_wl_buffer(struct wlr_wl_buffer *buffer) { if (buffer == NULL) { return; } + wl_list_remove(&buffer->buffer_destroy.link); + wl_list_remove(&buffer->link); wl_buffer_destroy(buffer->wl_buffer); - wlr_buffer_unlock(buffer->buffer); free(buffer); } static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) { struct wlr_wl_buffer *buffer = data; - destroy_wl_buffer(buffer); + buffer->released = true; + wlr_buffer_unlock(buffer->buffer); // might free buffer } static const struct wl_buffer_listener buffer_listener = { .release = buffer_handle_release, }; +static void buffer_handle_buffer_destroy(struct wl_listener *listener, + void *data) { + struct wlr_wl_buffer *buffer = + wl_container_of(listener, buffer, buffer_destroy); + destroy_wl_buffer(buffer); +} + static bool test_buffer(struct wlr_wl_backend *wl, struct wlr_buffer *wlr_buffer) { struct wlr_dmabuf_attributes attribs; @@ -207,12 +216,33 @@ static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl, } buffer->wl_buffer = wl_buffer; buffer->buffer = wlr_buffer_lock(wlr_buffer); + wl_list_insert(&wl->buffers, &buffer->link); wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer); + buffer->buffer_destroy.notify = buffer_handle_buffer_destroy; + wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy); + return buffer; } +static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl, + struct wlr_buffer *wlr_buffer) { + struct wlr_wl_buffer *buffer; + wl_list_for_each(buffer, &wl->buffers, link) { + // We can only re-use a wlr_wl_buffer if the parent compositor has + // released it, because wl_buffer.release is per-wl_buffer, not per + // wl_surface.commit. + if (buffer->buffer == wlr_buffer && buffer->released) { + buffer->released = false; + wlr_buffer_lock(buffer->buffer); + return buffer; + } + } + + return create_wl_buffer(wl, wlr_buffer); +} + static bool output_test(struct wlr_output *wlr_output) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); @@ -287,7 +317,7 @@ static bool output_commit(struct wlr_output *wlr_output) { } struct wlr_wl_buffer *buffer = - create_wl_buffer(output->backend, wlr_buffer); + get_or_create_wl_buffer(output->backend, wlr_buffer); if (buffer == NULL) { return false; } diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 0ff52b515..1c874b35b 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -25,9 +25,11 @@ struct wlr_wl_backend { struct wlr_renderer *renderer; struct wlr_drm_format *format; struct wlr_allocator *allocator; + struct wl_list buffers; // wlr_wl_buffer.link size_t requested_outputs; size_t last_output_num; struct wl_listener local_display_destroy; + /* remote state */ struct wl_display *remote_display; struct wl_event_source *remote_display_src; @@ -47,6 +49,9 @@ struct wlr_wl_backend { struct wlr_wl_buffer { struct wlr_buffer *buffer; struct wl_buffer *wl_buffer; + bool released; + struct wl_list link; // wlr_wl_backend.buffers + struct wl_listener buffer_destroy; }; struct wlr_wl_presentation_feedback { @@ -130,6 +135,7 @@ struct wlr_wl_input_device *create_wl_input_device( struct wlr_wl_seat *seat, enum wlr_input_device_type type); bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); +void destroy_wl_buffer(struct wlr_wl_buffer *buffer); extern const struct wl_seat_listener seat_listener; From d6dbdd97e90882569899e458f6bbc44bdc6d0a8a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 12 Dec 2020 13:12:06 +0100 Subject: [PATCH 222/223] backend/x11: re-use pixmaps Instead of re-importing a buffer each time we submit a frame, re-use the pixmaps if possible. --- backend/x11/output.c | 44 +++++++++++++++++++++++++++++++++---------- include/backend/x11.h | 1 + 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/backend/x11/output.c b/backend/x11/output.c index cba9f6001..a5d834fce 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -132,7 +132,24 @@ static bool output_test(struct wlr_output *wlr_output) { return true; } -static struct wlr_x11_buffer *import_x11_buffer(struct wlr_x11_output *output, +static void destroy_x11_buffer(struct wlr_x11_buffer *buffer) { + if (!buffer) { + return; + } + wl_list_remove(&buffer->buffer_destroy.link); + wl_list_remove(&buffer->link); + xcb_free_pixmap(buffer->x11->xcb, buffer->pixmap); + free(buffer); +} + +static void buffer_handle_buffer_destroy(struct wl_listener *listener, + void *data) { + struct wlr_x11_buffer *buffer = + wl_container_of(listener, buffer, buffer_destroy); + destroy_x11_buffer(buffer); +} + +static struct wlr_x11_buffer *create_x11_buffer(struct wlr_x11_output *output, struct wlr_buffer *wlr_buffer) { struct wlr_x11_backend *x11 = output->x11; @@ -170,17 +187,24 @@ static struct wlr_x11_buffer *import_x11_buffer(struct wlr_x11_output *output, buffer->pixmap = pixmap; buffer->x11 = x11; wl_list_insert(&output->buffers, &buffer->link); + + buffer->buffer_destroy.notify = buffer_handle_buffer_destroy; + wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy); + return buffer; } -static void destroy_x11_buffer(struct wlr_x11_buffer *buffer) { - if (!buffer) { - return; +static struct wlr_x11_buffer *get_or_create_x11_buffer( + struct wlr_x11_output *output, struct wlr_buffer *wlr_buffer) { + struct wlr_x11_buffer *buffer; + wl_list_for_each(buffer, &output->buffers, link) { + if (buffer->buffer == wlr_buffer) { + wlr_buffer_lock(buffer->buffer); + return buffer; + } } - wl_list_remove(&buffer->link); - xcb_free_pixmap(buffer->x11->xcb, buffer->pixmap); - wlr_buffer_unlock(buffer->buffer); - free(buffer); + + return create_x11_buffer(output, wlr_buffer); } static bool output_commit_buffer(struct wlr_x11_output *output) { @@ -192,7 +216,7 @@ static bool output_commit_buffer(struct wlr_x11_output *output) { wlr_egl_unset_current(&x11->egl); struct wlr_x11_buffer *x11_buffer = - import_x11_buffer(output, output->back_buffer); + get_or_create_x11_buffer(output, output->back_buffer); if (!x11_buffer) { goto error; } @@ -502,7 +526,7 @@ void handle_x11_present_event(struct wlr_x11_backend *x11, return; } - destroy_x11_buffer(buffer); + wlr_buffer_unlock(buffer->buffer); // may destroy buffer break; case XCB_PRESENT_COMPLETE_NOTIFY:; xcb_present_complete_notify_event_t *complete_notify = diff --git a/include/backend/x11.h b/include/backend/x11.h index b872385da..7ffcf465d 100644 --- a/include/backend/x11.h +++ b/include/backend/x11.h @@ -115,6 +115,7 @@ struct wlr_x11_buffer { struct wlr_buffer *buffer; xcb_pixmap_t pixmap; struct wl_list link; // wlr_x11_output::buffers + struct wl_listener buffer_destroy; }; struct wlr_x11_format { From 55b02f753f6bdc004ac2f7af27f89d82946b8701 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 12 Dec 2020 13:15:07 +0100 Subject: [PATCH 223/223] backend/x11: destroy buffers when destroying output --- backend/x11/output.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/x11/output.c b/backend/x11/output.c index a5d834fce..eb35e5842 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -82,6 +82,8 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output, return true; } +static void destroy_x11_buffer(struct wlr_x11_buffer *buffer); + static void output_destroy(struct wlr_output *wlr_output) { struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); struct wlr_x11_backend *x11 = output->x11; @@ -89,6 +91,11 @@ static void output_destroy(struct wlr_output *wlr_output) { wlr_input_device_destroy(&output->pointer_dev); wlr_input_device_destroy(&output->touch_dev); + struct wlr_x11_buffer *buffer, *buffer_tmp; + wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) { + destroy_x11_buffer(buffer); + } + wl_list_remove(&output->link); wl_event_source_remove(output->frame_timer); wlr_buffer_unlock(output->back_buffer);