diff options
Diffstat (limited to 'backend/x11/backend.c')
-rw-r--r-- | backend/x11/backend.c | 156 |
1 files changed, 154 insertions, 2 deletions
diff --git a/backend/x11/backend.c b/backend/x11/backend.c index f2b09a25..980bc14c 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -6,12 +6,16 @@ #include <stdio.h> #include <stdlib.h> #include <time.h> +#include <unistd.h> #include <wlr/config.h> +#include <drm_fourcc.h> #include <X11/Xlib-xcb.h> #include <wayland-server-core.h> #include <xcb/xcb.h> +#include <xcb/dri3.h> +#include <xcb/present.h> #include <xcb/xfixes.h> #include <xcb/xinput.h> @@ -25,8 +29,26 @@ #include <wlr/util/log.h> #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); |