From ba1a6a7e384bf349e646dfb70bd61287ec82b01c Mon Sep 17 00:00:00 2001 From: Lucas Fryzek Date: Fri, 21 Jun 2024 07:54:18 +0100 Subject: [PATCH] egl/x11/sw: Implement shm support Reviewed-by: Adam Jackson Part-of: --- src/egl/drivers/dri2/platform_x11.c | 175 +++++++++++++++++++++++++++- src/egl/meson.build | 2 +- 2 files changed, 172 insertions(+), 5 deletions(-) diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index 51e9ea12198..7f1c46b2da8 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -37,6 +37,7 @@ #include /* clang-format off */ #include +#include #include #include /* clang-format on */ @@ -46,6 +47,7 @@ #include "util/bitscan.h" #include "util/macros.h" #include "util/u_debug.h" +#include "util/log.h" #include #include @@ -224,8 +226,9 @@ swrastPutImage(__DRIdrawable *draw, int op, int x, int y, int w, int h, } static void -swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data, - void *loaderPrivate) +swrastGetImage2(__DRIdrawable * read, + int x, int y, int w, int h, int stride, + char *data, void *loaderPrivate) { struct dri2_egl_surface *dri2_surf = loaderPrivate; struct dri2_egl_display *dri2_dpy = @@ -247,11 +250,120 @@ swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data, } else { uint32_t bytes = xcb_get_image_data_length(reply); uint8_t *idata = xcb_get_image_data(reply); - memcpy(data, idata, bytes); + int stride_b = w * dri2_surf->bytes_per_pixel; + /* Only copy line by line if we have a different stride */ + if (stride != stride_b) { + for (int i = 0; i < h; i++) { + memcpy(data, idata, stride_b); + data += stride; + idata += stride_b; + } + } else { + memcpy(data, idata, bytes); + } } free(reply); } +static void +swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data, + void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + int stride_b = w * dri2_surf->bytes_per_pixel; + swrastGetImage2(read, x, y, w, h, stride_b, data, loaderPrivate); +} + +static void +swrastPutImageShm(__DRIdrawable * draw, int op, + int x, int y, int w, int h, int stride, + int shmid, char *shmaddr, unsigned offset, + void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + xcb_generic_error_t *error = NULL; + + xcb_shm_seg_t shm_seg = xcb_generate_id(dri2_dpy->conn); + error = xcb_request_check(dri2_dpy->conn, + xcb_shm_attach_checked(dri2_dpy->conn, + shm_seg, shmid, 0)); + if (error) { + mesa_loge("Failed to attach to x11 shm"); + _eglError(EGL_BAD_SURFACE, "xcb_shm_attach_checked"); + free(error); + return; + } + + xcb_gcontext_t gc; + xcb_void_cookie_t cookie; + switch (op) { + case __DRI_SWRAST_IMAGE_OP_DRAW: + gc = dri2_surf->gc; + break; + case __DRI_SWRAST_IMAGE_OP_SWAP: + gc = dri2_surf->swapgc; + break; + default: + return; + } + + cookie = xcb_shm_put_image(dri2_dpy->conn, + dri2_surf->drawable, + gc, + stride / dri2_surf->bytes_per_pixel, h, + x, 0, + w, h, + x, y, + dri2_surf->depth, + XCB_IMAGE_FORMAT_Z_PIXMAP, + 0, shm_seg, stride * y); + xcb_discard_reply(dri2_dpy->conn, cookie.sequence); + + xcb_flush(dri2_dpy->conn); + xcb_shm_detach(dri2_dpy->conn, shm_seg); +} + +static void +swrastGetImageShm(__DRIdrawable * read, + int x, int y, int w, int h, + int shmid, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + xcb_generic_error_t *error = NULL; + + xcb_shm_seg_t shm_seg = xcb_generate_id(dri2_dpy->conn); + error = xcb_request_check(dri2_dpy->conn, + xcb_shm_attach_checked(dri2_dpy->conn, + shm_seg, shmid, 0)); + if (error) { + mesa_loge("Failed to attach to x11 shm"); + _eglError(EGL_BAD_SURFACE, "xcb_shm_attach_checked"); + free(error); + return; + } + + xcb_shm_get_image_cookie_t cookie; + xcb_shm_get_image_reply_t *reply; + + cookie = xcb_shm_get_image(dri2_dpy->conn, + dri2_surf->drawable, + x, y, + w, h, + ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, + shm_seg, 0); + reply = xcb_shm_get_image_reply(dri2_dpy->conn, cookie, NULL); + if (reply == NULL) + _eglLog(_EGL_WARNING, "error in xcb_shm_get_image"); + else + free(reply); + + xcb_shm_detach(dri2_dpy->conn, shm_seg); +} + static xcb_screen_t * get_xcb_screen(xcb_screen_iterator_t iter, int screen) { @@ -1475,6 +1587,18 @@ static const __DRIswrastLoaderExtension swrast_loader_extension = { .getImage = swrastGetImage, }; +static const __DRIswrastLoaderExtension swrast_loader_shm_extension = { + .base = {__DRI_SWRAST_LOADER, 4}, + + .getDrawableInfo = swrastGetDrawableInfo, + .putImage = swrastPutImage, + .putImage2 = swrastPutImage2, + .putImageShm = swrastPutImageShm, + .getImage = swrastGetImage, + .getImage2 = swrastGetImage2, + .getImageShm = swrastGetImageShm, +}; + static_assert(sizeof(struct kopper_vk_surface_create_storage) >= sizeof(VkXcbSurfaceCreateInfoKHR), ""); @@ -1511,6 +1635,13 @@ static const __DRIextension *swrast_loader_extensions[] = { NULL, }; +static const __DRIextension *swrast_loader_shm_extensions[] = { + &swrast_loader_shm_extension.base, + &image_lookup_extension.base, + &kopper_loader_extension.base, + NULL, +}; + static int dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen) { @@ -1595,6 +1726,38 @@ dri2_x11_setup_swap_interval(_EGLDisplay *disp) dri2_setup_swap_interval(disp, arbitrary_max_interval); } +static bool +check_xshm(struct dri2_egl_display *dri2_dpy) +{ + xcb_void_cookie_t cookie; + xcb_generic_error_t *error; + int ret = true; + xcb_query_extension_cookie_t shm_cookie; + xcb_query_extension_reply_t *shm_reply; + bool has_mit_shm; + + shm_cookie = xcb_query_extension(dri2_dpy->conn, 7, "MIT-SHM"); + shm_reply = xcb_query_extension_reply(dri2_dpy->conn, shm_cookie, NULL); + + has_mit_shm = shm_reply->present; + free(shm_reply); + if (!has_mit_shm) + return false; + + cookie = xcb_shm_detach_checked(dri2_dpy->conn, 0); + if ((error = xcb_request_check(dri2_dpy->conn, cookie))) { + /* BadRequest means we're a remote client. If we were local we'd + * expect BadValue since 'info' has an invalid segment name. + */ + if (error->error_code == BadRequest) + ret = false; + free(error); + } + + return ret; +} + + static EGLBoolean dri2_initialize_x11_swrast(_EGLDisplay *disp) { @@ -1619,7 +1782,11 @@ dri2_initialize_x11_swrast(_EGLDisplay *disp) if (!dri2_load_driver_swrast(disp)) goto cleanup; - dri2_dpy->loader_extensions = swrast_loader_extensions; + if (check_xshm(dri2_dpy)) { + dri2_dpy->loader_extensions = swrast_loader_shm_extensions; + } else { + dri2_dpy->loader_extensions = swrast_loader_extensions; + } if (!dri2_create_screen(disp)) goto cleanup; diff --git a/src/egl/meson.build b/src/egl/meson.build index c24fb6f2f19..ee785a3a923 100644 --- a/src/egl/meson.build +++ b/src/egl/meson.build @@ -99,7 +99,7 @@ if with_dri2 files_egl += files('drivers/dri2/platform_x11_dri3.c') link_for_egl += libloader_dri3_helper endif - deps_for_egl += [dep_x11_xcb, dep_xcb_dri2, dep_xcb_xrandr, dep_xcb_xfixes] + deps_for_egl += [dep_x11_xcb, dep_xcb_dri2, dep_xcb_xrandr, dep_xcb_xfixes, dep_xcb_shm] endif if with_gbm and not with_platform_android files_egl += files('drivers/dri2/platform_drm.c')