diff options
32 files changed, 286 insertions, 104 deletions
diff --git a/backend/backend.c b/backend/backend.c index b57fd424..07c171bc 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -72,8 +72,9 @@ static size_t parse_outputs_env(const char *name) { return outputs; } -static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { - struct wlr_backend *backend = wlr_wl_backend_create(display, NULL); +static struct wlr_backend *attempt_wl_backend(struct wl_display *display, + wlr_renderer_create_func_t create_renderer_func) { + struct wlr_backend *backend = wlr_wl_backend_create(display, NULL, create_renderer_func); if (backend == NULL) { return NULL; } @@ -88,8 +89,8 @@ static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { #ifdef WLR_HAS_X11_BACKEND static struct wlr_backend *attempt_x11_backend(struct wl_display *display, - const char *x11_display) { - struct wlr_backend *backend = wlr_x11_backend_create(display, x11_display); + const char *x11_display, wlr_renderer_create_func_t create_renderer_func) { + struct wlr_backend *backend = wlr_x11_backend_create(display, x11_display, create_renderer_func); if (backend == NULL) { return NULL; } @@ -104,8 +105,8 @@ static struct wlr_backend *attempt_x11_backend(struct wl_display *display, #endif static struct wlr_backend *attempt_headless_backend( - struct wl_display *display) { - struct wlr_backend *backend = wlr_headless_backend_create(display); + struct wl_display *display, wlr_renderer_create_func_t create_renderer_func) { + struct wlr_backend *backend = wlr_headless_backend_create(display, create_renderer_func); if (backend == NULL) { return NULL; } @@ -119,7 +120,8 @@ static struct wlr_backend *attempt_headless_backend( } static struct wlr_backend *attempt_drm_backend(struct wl_display *display, - struct wlr_backend *backend, struct wlr_session *session) { + struct wlr_backend *backend, struct wlr_session *session, + wlr_renderer_create_func_t create_renderer_func) { int gpus[8]; size_t num_gpus = wlr_session_find_gpus(session, 8, gpus); struct wlr_backend *primary_drm = NULL; @@ -127,7 +129,7 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, for (size_t i = 0; i < num_gpus; ++i) { struct wlr_backend *drm = wlr_drm_backend_create(display, session, - gpus[i], primary_drm); + gpus[i], primary_drm, create_renderer_func); if (!drm) { wlr_log(L_ERROR, "Failed to open DRM device %d", gpus[i]); continue; @@ -145,15 +147,15 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display, static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, struct wlr_backend *backend, struct wlr_session **session, - const char *name) { + const char *name, wlr_renderer_create_func_t create_renderer_func) { if (strcmp(name, "wayland") == 0) { - return attempt_wl_backend(display); + return attempt_wl_backend(display, create_renderer_func); #ifdef WLR_HAS_X11_BACKEND } else if (strcmp(name, "x11") == 0) { - return attempt_x11_backend(display, NULL); + return attempt_x11_backend(display, NULL, create_renderer_func); #endif } else if (strcmp(name, "headless") == 0) { - return attempt_headless_backend(display); + return attempt_headless_backend(display, create_renderer_func); } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { // DRM and libinput need a session *session = wlr_session_create(display); @@ -165,7 +167,7 @@ static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, if (strcmp(name, "libinput") == 0) { return wlr_libinput_backend_create(display, *session); } else { - return attempt_drm_backend(display, backend, *session); + return attempt_drm_backend(display, backend, *session, create_renderer_func); } } @@ -173,7 +175,8 @@ static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, return NULL; } -struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { +struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, + wlr_renderer_create_func_t create_renderer_func) { struct wlr_backend *backend = wlr_multi_backend_create(display); if (!backend) { wlr_log(L_ERROR, "could not allocate multibackend"); @@ -195,7 +198,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { char *name = strtok_r(names, ",", &saveptr); while (name != NULL) { struct wlr_backend *subbackend = - attempt_backend_by_name(display, backend, &session, name); + attempt_backend_by_name(display, backend, &session, name, create_renderer_func); if (subbackend == NULL) { wlr_log(L_ERROR, "failed to start backend '%s'", name); wlr_backend_destroy(backend); @@ -218,7 +221,8 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) { - struct wlr_backend *wl_backend = attempt_wl_backend(display); + struct wlr_backend *wl_backend = attempt_wl_backend(display, + create_renderer_func); if (wl_backend) { wlr_multi_backend_add(backend, wl_backend); return backend; @@ -229,7 +233,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { const char *x11_display = getenv("DISPLAY"); if (x11_display) { struct wlr_backend *x11_backend = - attempt_x11_backend(display, x11_display); + attempt_x11_backend(display, x11_display, create_renderer_func); if (x11_backend) { wlr_multi_backend_add(backend, x11_backend); return backend; @@ -255,7 +259,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { wlr_multi_backend_add(backend, libinput); struct wlr_backend *primary_drm = - attempt_drm_backend(display, backend, session); + attempt_drm_backend(display, backend, session, create_renderer_func); if (!primary_drm) { wlr_log(L_ERROR, "Failed to open any DRM device"); wlr_backend_destroy(libinput); diff --git a/backend/drm/backend.c b/backend/drm/backend.c index c14b99e3..7bb4dc32 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -114,7 +114,8 @@ 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, int gpu_fd, struct wlr_backend *parent, + wlr_renderer_create_func_t create_renderer_func) { assert(display && session && gpu_fd >= 0); assert(!parent || wlr_backend_is_drm(parent)); @@ -161,15 +162,11 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, goto error_event; } - if (!init_drm_renderer(drm, &drm->renderer)) { + if (!init_drm_renderer(drm, &drm->renderer, create_renderer_func)) { wlr_log(L_ERROR, "Failed to initialize renderer"); goto error_event; } - if (!wlr_egl_bind_display(&drm->renderer.egl, display)) { - wlr_log(L_INFO, "Failed to bind egl/wl display"); - } - drm->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &drm->display_destroy); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7224cb3e..ef8efb9a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -215,7 +215,7 @@ static bool drm_connector_swap_buffers(struct wlr_output *output, uint32_t fb_id = get_fb_for_bo(bo); if (conn->pageflip_pending) { - wlr_log(L_ERROR, "Skipping pageflip"); + wlr_log(L_ERROR, "Skipping pageflip on output '%s'", conn->output.name); return false; } @@ -259,6 +259,8 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { return; } + wlr_log(L_DEBUG, "Starting renderer on output '%s'", conn->output.name); + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)conn->output.backend; struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { @@ -301,8 +303,10 @@ void enable_drm_connector(struct wlr_output *output, bool enable) { static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, bool *changed_outputs) { + wlr_log(L_DEBUG, "Reallocating planes"); + // overlay, primary, cursor - for (int type = 0; type < 3; ++type) { + for (size_t type = 0; type < 3; ++type) { if (drm->num_type_planes[type] == 0) { continue; } @@ -339,6 +343,11 @@ static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]]; if (*old != new) { + wlr_log(L_DEBUG, "Assigning plane %d -> %d to CRTC %d", + *old ? (int)(*old)->id : -1, + new ? (int)new->id : -1, + c->id); + changed_outputs[crtc_res[i]] = true; if (*old) { finish_drm_surface(&(*old)->surf); @@ -363,6 +372,8 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, memset(possible_crtc, 0, sizeof(possible_crtc)); + wlr_log(L_DEBUG, "Reallocating CRTCs for output '%s'", conn->output.name); + ssize_t index = -1, i = -1; struct wlr_drm_connector *c; wl_list_for_each(c, &drm->outputs, link) { @@ -371,6 +382,9 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, index = i; } + wlr_log(L_DEBUG, "output '%s' crtc=%p state=%d", + c->output.name, c->crtc, c->state); + if (c->crtc) { crtc[c->crtc - drm->crtcs] = i; } @@ -378,7 +392,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, if (c->state == WLR_DRM_CONN_CONNECTED) { possible_crtc[i] = c->possible_crtc; } - } assert(index != -1); @@ -396,12 +409,15 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, // There is no point doing anything if this monitor doesn't get activated if (!matched[index]) { + wlr_log(L_DEBUG, "Could not match a CRTC for this output"); return; } for (size_t i = 0; i < drm->num_crtcs; ++i) { // We don't want any of the current monitors to be deactivated. if (crtc[i] != UNMATCHED && !matched[crtc[i]]) { + wlr_log(L_DEBUG, "Could not match a CRTC for other output %d", + crtc[i]); return; } } @@ -424,6 +440,9 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, pos++; } c->crtc = &drm->crtcs[i]; + + wlr_log(L_DEBUG, "Assigning CRTC %d to output '%s'", + drm->crtcs[i].id, c->output.name); } } @@ -481,14 +500,10 @@ static bool drm_connector_set_mode(struct wlr_output *output, memset(changed_outputs, false, sizeof(changed_outputs)); realloc_crtcs(drm, conn, changed_outputs); - if (!conn->crtc) { - wlr_log(L_ERROR, "Unable to match %s with a CRTC", conn->output.name); - goto error_conn; - } - struct wlr_drm_crtc *crtc = conn->crtc; if (!crtc) { - return false; + wlr_log(L_ERROR, "Unable to match %s with a CRTC", conn->output.name); + goto error_conn; } wlr_log(L_DEBUG, "%s: crtc=%td ovr=%td pri=%td cur=%td", conn->output.name, crtc - drm->crtcs, @@ -799,7 +814,6 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->retry_pageflip = wl_event_loop_add_timer(ev, retry_pageflip, wlr_conn); - wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; wlr_conn->id = drm_conn->connector_id; @@ -832,6 +846,8 @@ 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(L_INFO, "'%s' connected", wlr_conn->output.name); + wlr_log(L_DEBUG, "Current CRTC: %d", + wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1); wlr_conn->output.phys_width = drm_conn->mmWidth; wlr_conn->output.phys_height = drm_conn->mmHeight; @@ -860,7 +876,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { mode->wlr_mode.height = mode->drm_mode.vdisplay; mode->wlr_mode.refresh = calculate_refresh_rate(&mode->drm_mode); - wlr_log(L_INFO, " %"PRId32"@%"PRId32"@%"PRId32, + wlr_log(L_INFO, " %"PRId32"x%"PRId32"@%"PRId32, mode->wlr_mode.width, mode->wlr_mode.height, mode->wlr_mode.refresh); @@ -998,8 +1014,8 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { } } - struct wlr_drm_mode *mode; - struct wlr_drm_mode *tmp; + conn->output.current_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); @@ -1011,6 +1027,7 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { conn->crtc = NULL; conn->possible_crtc = 0; + conn->pageflip_pending = false; /* Fallthrough */ case WLR_DRM_CONN_NEEDS_MODESET: wlr_log(L_INFO, "Emitting destruction signal for '%s'", diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7e2b5174..d5bcef2b 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -19,29 +19,28 @@ #endif bool init_drm_renderer(struct wlr_drm_backend *drm, - struct wlr_drm_renderer *renderer) { + struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_renderer_func) { renderer->gbm = gbm_create_device(drm->fd); if (!renderer->gbm) { wlr_log(L_ERROR, "Failed to create GBM device"); return false; } - if (!wlr_egl_init(&renderer->egl, EGL_PLATFORM_GBM_MESA, renderer->gbm, - NULL, GBM_FORMAT_ARGB8888)) { - goto error_gbm; + if (!create_renderer_func) { + create_renderer_func = wlr_renderer_autocreate; } - renderer->wlr_rend = wlr_gles2_renderer_create(&renderer->egl); + renderer->wlr_rend = create_renderer_func(&renderer->egl, + EGL_PLATFORM_GBM_MESA, renderer->gbm, NULL, GBM_FORMAT_ARGB8888); + if (!renderer->wlr_rend) { - wlr_log(L_ERROR, "Failed to create WLR renderer"); - goto error_egl; + wlr_log(L_ERROR, "Failed to create EGL/WLR renderer"); + goto error_gbm; } renderer->fd = drm->fd; return true; -error_egl: - wlr_egl_finish(&renderer->egl); error_gbm: gbm_device_destroy(renderer->gbm); return false; diff --git a/backend/headless/backend.c b/backend/headless/backend.c index 1d29e12a..7015099e 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -78,7 +78,8 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { backend_destroy(&backend->backend); } -struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { +struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, + wlr_renderer_create_func_t create_renderer_func) { wlr_log(L_INFO, "Creating headless backend"); struct wlr_headless_backend *backend = @@ -101,16 +102,18 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; - bool ok = wlr_egl_init(&backend->egl, EGL_PLATFORM_SURFACELESS_MESA, NULL, - (EGLint *)config_attribs, 0); - if (!ok) { - free(backend); - return NULL; + + if (!create_renderer_func) { + create_renderer_func = wlr_renderer_autocreate; } - backend->renderer = wlr_gles2_renderer_create(&backend->egl); - if (backend->renderer == NULL) { + backend->renderer = create_renderer_func(&backend->egl, EGL_PLATFORM_SURFACELESS_MESA, + NULL, (EGLint*)config_attribs, 0); + + if (!backend->renderer) { wlr_log(L_ERROR, "Failed to create renderer"); + free(backend); + return NULL; } backend->display_destroy.notify = handle_display_destroy; diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 4e4ca077..4f3fa2f3 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -139,7 +139,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, - const char *remote) { + const char *remote, wlr_renderer_create_func_t create_renderer_func) { wlr_log(L_INFO, "Creating wayland backend"); struct wlr_wl_backend *backend = calloc(1, sizeof(struct wlr_wl_backend)); @@ -174,14 +174,14 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, EGL_ALPHA_SIZE, 1, EGL_NONE, }; - if (!wlr_egl_init(&backend->egl, EGL_PLATFORM_WAYLAND_EXT, - backend->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888)) { - wlr_log(L_ERROR, "Could not initialize EGL"); - goto error_egl; + + if (!create_renderer_func) { + create_renderer_func = wlr_renderer_autocreate; } - wlr_egl_bind_display(&backend->egl, backend->local_display); - backend->renderer = wlr_gles2_renderer_create(&backend->egl); + backend->renderer = create_renderer_func(&backend->egl, EGL_PLATFORM_WAYLAND_EXT, + backend->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888); + if (backend->renderer == NULL) { wlr_log(L_ERROR, "Could not create renderer"); goto error_renderer; @@ -193,8 +193,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, return &backend->backend; error_renderer: - wlr_egl_finish(&backend->egl); -error_egl: wl_registry_destroy(backend->registry); error_registry: wl_display_disconnect(backend->remote_display); diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 845495e7..d4793b9c 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -232,7 +232,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, - const char *x11_display) { + const char *x11_display, wlr_renderer_create_func_t create_renderer_func) { struct wlr_x11_backend *x11 = calloc(1, sizeof(*x11)); if (!x11) { return NULL; @@ -267,15 +267,16 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb_conn)).data; - if (!wlr_egl_init(&x11->egl, EGL_PLATFORM_X11_KHR, x11->xlib_conn, NULL, - x11->screen->root_visual)) { - goto error_event; + if (!create_renderer_func) { + create_renderer_func = wlr_renderer_autocreate; } - x11->renderer = wlr_gles2_renderer_create(&x11->egl); + x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_X11_KHR, + x11->xlib_conn, NULL, x11->screen->root_visual); + if (x11->renderer == NULL) { wlr_log(L_ERROR, "Failed to create renderer"); - goto error_egl; + goto error_event; } wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD, @@ -288,8 +289,6 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, return &x11->backend; -error_egl: - wlr_egl_finish(&x11->egl); error_event: wl_event_source_remove(x11->event_source); error_x11: diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 83ee253d..c5b2048f 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -284,7 +284,7 @@ int main(int argc, char *argv[]) { .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, .display = display, }; - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/output-layout.c b/examples/output-layout.c index d45100b6..7b847a3b 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -261,7 +261,7 @@ int main(int argc, char *argv[]) { state.layout = wlr_output_layout_create(); clock_gettime(CLOCK_MONOTONIC, &state.ts_last); - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/pointer.c b/examples/pointer.c index 8dba99eb..d6b4ed1c 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -324,7 +324,7 @@ int main(int argc, char *argv[]) { .display = display }; - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/rotation.c b/examples/rotation.c index 0ee9964c..bd39a21e 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) { }; wl_list_init(&state.outputs); - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/simple.c b/examples/simple.c index e64289fb..60acd7db 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -152,7 +152,7 @@ int main() { .last_frame = { 0 }, .display = display }; - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/tablet.c b/examples/tablet.c index d178f2ef..f5c4bbb5 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -349,7 +349,7 @@ int main(int argc, char *argv[]) { }; wl_list_init(&state.tablet_pads); wl_list_init(&state.tablet_tools); - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/examples/touch.c b/examples/touch.c index 069fda74..68f78a0a 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -244,7 +244,7 @@ int main(int argc, char *argv[]) { wl_list_init(&state.touch_points); wl_list_init(&state.touch); - struct wlr_backend *wlr = wlr_backend_autocreate(display); + struct wlr_backend *wlr = wlr_backend_autocreate(display, NULL); if (!wlr) { exit(1); } diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 5e15f3d5..510abe43 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -5,6 +5,7 @@ #include <gbm.h> #include <stdbool.h> #include <stdint.h> +#include <wlr/backend.h> #include <wlr/render/wlr_renderer.h> struct wlr_drm_backend; @@ -32,7 +33,7 @@ struct wlr_drm_surface { }; bool init_drm_renderer(struct wlr_drm_backend *drm, - struct wlr_drm_renderer *renderer); + struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_render); void finish_drm_renderer(struct wlr_drm_renderer *renderer); bool init_drm_surface(struct wlr_drm_surface *surf, diff --git a/include/wlr/backend.h b/include/wlr/backend.h index 2059e3b7..f40f5353 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -20,12 +20,20 @@ struct wlr_backend { } events; }; +typedef struct wlr_renderer *(*wlr_renderer_create_func_t)(struct wlr_egl *egl, EGLenum platform, + void *remote_display, EGLint *config_attribs, EGLint visual_id); /** * Automatically initializes the most suitable backend given the environment. * Will always return a multibackend. The backend is created but not started. * Returns NULL on failure. + * + * The compositor can request to initialize the backend's renderer by setting + * the create_render_func. The callback must initialize the given wlr_egl and + * return a valid wlr_renderer, or NULL if it has failed to initiaze it. + * Pass NULL as create_renderer_func to use the backend's default renderer. */ -struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); +struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, + wlr_renderer_create_func_t create_renderer_func); /** * Start the backend. This may signal new_input or new_output immediately, but * may also wait until the display's event loop begins. Returns false on diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 14fafe10..7f41ca15 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -14,7 +14,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, int gpu_fd, struct wlr_backend *parent, + wlr_renderer_create_func_t create_renderer_func); bool wlr_backend_is_drm(struct wlr_backend *backend); bool wlr_output_is_drm(struct wlr_output *output); diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index ee784a0d..02c7cd11 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -9,7 +9,8 @@ * Creates a headless backend. A headless backend has no outputs or inputs by * default. */ -struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); +struct wlr_backend *wlr_headless_backend_create(struct wl_display *display, + wlr_renderer_create_func_t create_renderer_func); /** * Create a new headless output backed by an in-memory EGL framebuffer. You can * read pixels from this framebuffer via wlr_renderer_read_pixels but it is diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index 31a14c97..119ea247 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -16,7 +16,8 @@ * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 * default) */ -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote); +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote, + wlr_renderer_create_func_t create_renderer_func); /** * Adds a new output to this backend. You may remove outputs by destroying them. diff --git a/include/wlr/backend/x11.h b/include/wlr/backend/x11.h index 7bc1f891..56360bf7 100644 --- a/include/wlr/backend/x11.h +++ b/include/wlr/backend/x11.h @@ -8,7 +8,7 @@ #include <wlr/types/wlr_output.h> struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, - const char *x11_display); + const char *x11_display, wlr_renderer_create_func_t create_renderer_func); struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend); bool wlr_backend_is_x11(struct wlr_backend *backend); diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index e7cdce0a..2267d376 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -49,6 +49,8 @@ struct wlr_renderer_impl { struct wlr_texture *(*texture_from_dmabuf)(struct wlr_renderer *renderer, struct wlr_dmabuf_buffer_attribs *attribs); void (*destroy)(struct wlr_renderer *renderer); + void (*init_wl_display)(struct wlr_renderer *renderer, + struct wl_display *wl_display); }; 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 21f9c16c..039bb66e 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -3,6 +3,7 @@ #include <stdint.h> #include <wayland-server-protocol.h> +#include <wlr/render/egl.h> #include <wlr/render/wlr_texture.h> #include <wlr/types/wlr_box.h> @@ -16,6 +17,9 @@ struct wlr_renderer { } events; }; +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_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); @@ -98,8 +102,8 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, */ bool wlr_renderer_format_supported(struct wlr_renderer *r, enum wl_shm_format fmt); -void wlr_renderer_init_wl_shm(struct wlr_renderer *r, - struct wl_display *display); +void wlr_renderer_init_wl_display(struct wlr_renderer *r, + struct wl_display *wl_display); /** * Destroys this wlr_renderer. Textures must be destroyed separately. */ diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index bfb4e611..97288508 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -59,7 +59,20 @@ struct wlr_keyboard { } repeat_info; struct { + /** + * The `key` event signals with a `wlr_event_keyboard_key` event that a + * key has been pressed or released on the keyboard. This event is + * emitted before the xkb state of the keyboard has been updated + * (including modifiers). + */ struct wl_signal key; + + /** + * The `modifiers` event signals that the modifier state of the + * `wlr_keyboard` has been updated. At this time, you can read the + * modifier state of the `wlr_keyboard` and handle the updated state by + * sending it to clients. + */ struct wl_signal modifiers; struct wl_signal keymap; struct wl_signal repeat_info; diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 22008563..5eb30a16 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -14,6 +14,12 @@ struct wlr_xdg_shell { 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; } events; @@ -86,6 +92,7 @@ enum wlr_xdg_surface_role { struct wlr_xdg_toplevel_state { bool maximized, fullscreen, resizing, activated; + uint32_t tiled; // enum wlr_edges uint32_t width, height; uint32_t max_width, max_height; uint32_t min_width, min_height; @@ -161,7 +168,21 @@ struct wlr_xdg_surface { 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; @@ -247,6 +268,14 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, bool resizing); /** + * Request that this toplevel surface consider itself in a tiled layout and some + * edges are adjacent to another part of the tiling grid. `tiled_edges` is a + * bitfield of `enum wlr_edges`. Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, + uint32_t tiled_edges); + +/** * Request that this xdg surface closes. */ void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface); diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index bce645da..2fdf49e5 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -15,6 +15,12 @@ struct wlr_xdg_shell_v6 { 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; } events; @@ -160,7 +166,21 @@ struct wlr_xdg_surface_v6 { 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; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 8360c5fb..5cea5c3b 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -304,6 +304,15 @@ static struct wlr_texture *gles2_texture_from_dmabuf( return wlr_gles2_texture_from_dmabuf(renderer->egl, attribs); } +static void gles2_init_wl_display(struct wlr_renderer *wlr_renderer, + struct wl_display *wl_display) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + if (!wlr_egl_bind_display(renderer->egl, wl_display)) { + wlr_log(L_INFO, "failed to bind wl_display to EGL"); + } +} + static void gles2_destroy(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); @@ -345,6 +354,7 @@ static const struct wlr_renderer_impl renderer_impl = { .texture_from_pixels = gles2_texture_from_pixels, .texture_from_wl_drm = gles2_texture_from_wl_drm, .texture_from_dmabuf = gles2_texture_from_dmabuf, + .init_wl_display = gles2_init_wl_display, }; void push_gles2_marker(const char *file, const char *func) { diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 8d1bd9ce..aed821c9 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -4,6 +4,7 @@ #include <wlr/render/interface.h> #include <wlr/render/wlr_renderer.h> #include <wlr/types/wlr_matrix.h> +#include <wlr/render/gles2.h> #include <wlr/util/log.h> #include "util/signal.h" @@ -158,9 +159,9 @@ bool wlr_renderer_format_supported(struct wlr_renderer *r, return r->impl->format_supported(r, fmt); } -void wlr_renderer_init_wl_shm(struct wlr_renderer *r, - struct wl_display *display) { - if (wl_display_init_shm(display)) { +void wlr_renderer_init_wl_display(struct wlr_renderer *r, + struct wl_display *wl_display) { + if (wl_display_init_shm(wl_display)) { wlr_log(L_ERROR, "Failed to initialize shm"); return; } @@ -173,9 +174,30 @@ void wlr_renderer_init_wl_shm(struct wlr_renderer *r, } 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) { - wl_display_add_shm_format(display, formats[i]); + wl_display_add_shm_format(wl_display, formats[i]); } } + + if (r->impl->init_wl_display) { + r->impl->init_wl_display(r, wl_display); + } +} + +struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, + EGLenum platform, void *remote_display, EGLint *config_attribs, EGLint visual_id) { + + if (!wlr_egl_init(egl, platform, remote_display, config_attribs, visual_id)) { + wlr_log(L_ERROR, "Could not initialize EGL"); + return NULL; + } + + struct wlr_renderer *renderer = wlr_gles2_renderer_create(egl); + if (!renderer) { + wlr_egl_finish(egl); + } + + return renderer; } diff --git a/rootston/main.c b/rootston/main.c index 18d27a8a..cecdb23d 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -21,7 +21,7 @@ int main(int argc, char **argv) { server.wl_event_loop = wl_display_get_event_loop(server.wl_display); assert(server.config && server.wl_display && server.wl_event_loop); - server.backend = wlr_backend_autocreate(server.wl_display); + server.backend = wlr_backend_autocreate(server.wl_display, NULL); if (server.backend == NULL) { wlr_log(L_ERROR, "could not start backend"); return 1; @@ -31,7 +31,7 @@ int main(int argc, char **argv) { assert(server.renderer); server.data_device_manager = wlr_data_device_manager_create(server.wl_display); - wlr_renderer_init_wl_shm(server.renderer, server.wl_display); + wlr_renderer_init_wl_display(server.renderer, server.wl_display); server.desktop = desktop_create(&server, server.config); server.input = input_create(&server, server.config); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 775f7adf..8a05657e 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -31,7 +31,7 @@ static void surface_handle_buffer_destroy(struct wl_listener *listener, static void surface_state_release_buffer(struct wlr_surface_state *state) { if (state->buffer) { - wl_resource_post_event(state->buffer, WL_BUFFER_RELEASE); + wl_buffer_send_release(state->buffer); surface_state_reset_buffer(state); } } diff --git a/types/xdg_shell/wlr_xdg_shell.c b/types/xdg_shell/wlr_xdg_shell.c index 9d171746..43b28ff0 100644 --- a/types/xdg_shell/wlr_xdg_shell.c +++ b/types/xdg_shell/wlr_xdg_shell.c @@ -3,7 +3,7 @@ #include "types/wlr_xdg_shell.h" #include "util/signal.h" -#define WM_BASE_VERSION 1 +#define WM_BASE_VERSION 2 static const struct xdg_wm_base_interface xdg_shell_impl; diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 387897d9..5968c835 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -3,6 +3,7 @@ #include <stdlib.h> #include <string.h> #include <wlr/util/log.h> +#include <wlr/util/edges.h> #include "types/wlr_xdg_shell.h" #include "util/signal.h" @@ -20,6 +21,8 @@ void handle_xdg_toplevel_ack_configure( configure->toplevel_state->resizing; surface->toplevel->current.activated = configure->toplevel_state->activated; + surface->toplevel->current.tiled = + configure->toplevel_state->tiled; } bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) { @@ -58,6 +61,9 @@ bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) { if (state->server_pending.resizing != configured.state.resizing) { return false; } + if (state->server_pending.tiled != configured.state.tiled) { + return false; + } if (state->server_pending.width == configured.width && state->server_pending.height == configured.height) { @@ -83,11 +89,10 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, } *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)); + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); goto error_out; @@ -95,7 +100,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, *s = XDG_TOPLEVEL_STATE_MAXIMIZED; } if (surface->toplevel->server_pending.fullscreen) { - s = wl_array_add(&states, sizeof(uint32_t)); + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); goto error_out; @@ -103,7 +108,7 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, *s = XDG_TOPLEVEL_STATE_FULLSCREEN; } if (surface->toplevel->server_pending.resizing) { - s = wl_array_add(&states, sizeof(uint32_t)); + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); goto error_out; @@ -111,13 +116,52 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface, *s = XDG_TOPLEVEL_STATE_RESIZING; } if (surface->toplevel->server_pending.activated) { - s = wl_array_add(&states, sizeof(uint32_t)); + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); goto error_out; } *s = XDG_TOPLEVEL_STATE_ACTIVATED; } + if (surface->toplevel->server_pending.tiled) { + if (wl_resource_get_version(surface->resource) >= + XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { + const struct { + enum wlr_edges edge; + enum xdg_toplevel_state state; + } tiled[] = { + { WLR_EDGE_LEFT, XDG_TOPLEVEL_STATE_TILED_LEFT }, + { WLR_EDGE_RIGHT, XDG_TOPLEVEL_STATE_TILED_RIGHT }, + { WLR_EDGE_TOP, XDG_TOPLEVEL_STATE_TILED_TOP }, + { WLR_EDGE_BOTTOM, XDG_TOPLEVEL_STATE_TILED_BOTTOM }, + }; + + for (size_t i = 0; i < sizeof(tiled)/sizeof(tiled[0]); ++i) { + if ((surface->toplevel->server_pending.tiled & + tiled[i].edge) == 0) { + continue; + } + + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, + "Could not allocate state for tiled xdg_toplevel"); + goto error_out; + } + *s = tiled[i].state; + } + } else if (!surface->toplevel->server_pending.maximized) { + // This version doesn't support tiling, best we can do is make the + // toplevel maximized + uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); + if (!s) { + wlr_log(L_ERROR, + "Could not allocate state for maximized xdg_toplevel"); + goto error_out; + } + *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + } + } uint32_t width = surface->toplevel->server_pending.width; uint32_t height = surface->toplevel->server_pending.height; @@ -479,3 +523,11 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, return schedule_xdg_surface_configure(surface); } + +uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, + uint32_t tiled) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + surface->toplevel->server_pending.tiled = tiled; + + return schedule_xdg_surface_configure(surface); +} diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 7c9cd304..b397b1e8 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -187,7 +187,7 @@ static void xwm_set_net_active_window(struct wlr_xwm *xwm, } static void xwm_send_wm_message(struct wlr_xwayland_surface *surface, - xcb_client_message_data_t *data) { + xcb_client_message_data_t *data, uint32_t event_mask) { struct wlr_xwm *xwm = surface->xwm; xcb_client_message_event_t event = { @@ -202,7 +202,7 @@ static void xwm_send_wm_message(struct wlr_xwayland_surface *surface, xcb_send_event(xwm->xcb_conn, 0, // propagate surface->window_id, - XCB_EVENT_MASK_NO_EVENT, + event_mask, (const char *)&event); xcb_flush(xwm->xcb_conn); } @@ -221,7 +221,8 @@ static void xwm_send_focus_window(struct wlr_xwm *xwm, xcb_client_message_data_t message_data = { 0 }; message_data.data32[0] = xwm->atoms[WM_TAKE_FOCUS]; message_data.data32[1] = XCB_TIME_CURRENT_TIME; - xwm_send_wm_message(xsurface, &message_data); + 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); @@ -1266,7 +1267,7 @@ void wlr_xwayland_surface_close(struct wlr_xwayland_surface *xsurface) { xcb_client_message_data_t message_data = {0}; message_data.data32[0] = xwm->atoms[WM_DELETE_WINDOW]; message_data.data32[1] = XCB_CURRENT_TIME; - xwm_send_wm_message(xsurface, &message_data); + xwm_send_wm_message(xsurface, &message_data, XCB_EVENT_MASK_NO_EVENT); } else { xcb_kill_client(xwm->xcb_conn, xsurface->window_id); xcb_flush(xwm->xcb_conn); @@ -1665,7 +1666,7 @@ void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface) { data.data32[1] = XCB_CURRENT_TIME; data.data32[2] = surface->window_id; - xwm_send_wm_message(surface, &data); + xwm_send_wm_message(surface, &data, XCB_EVENT_MASK_NO_EVENT); wl_event_source_timer_update(surface->ping_timer, surface->xwm->ping_timeout); |