diff --git a/x11-packages/xwayland/0001-xwayland-support-kgsl-dmabuf-v3-fallback-paths.patch b/x11-packages/xwayland/0001-xwayland-support-kgsl-dmabuf-v3-fallback-paths.patch new file mode 100644 index 00000000000..2acb9774768 --- /dev/null +++ b/x11-packages/xwayland/0001-xwayland-support-kgsl-dmabuf-v3-fallback-paths.patch @@ -0,0 +1,142 @@ +From e910fc1dda09b916e190f5f8645abae5b6ebfda3 Mon Sep 17 00:00:00 2001 +From: superturtlee <160681686+superturtlee@users.noreply.github.com> +Date: Mon, 6 Jul 2026 09:56:24 +0800 +Subject: [PATCH] xwayland: support kgsl dmabuf v3 fallback paths + +Allow glamor to initialize with linux-dmabuf v3 when wl_drm and dmabuf +feedback are unavailable, fall back to a configurable GBM render node, and +handle implicit or bogus linear modifiers used by kgsl/freedreno stacks. + +Based-on-patch: https://github.com/superturtlee/anland/blob/1.11/producers/kde/ubuntu2604/xwayland.patch + +Co-authored-by: lfdevs +--- + hw/xwayland/xwayland-glamor-gbm.c | 65 ++++++++++++++++++++++--------- + hw/xwayland/xwayland-glamor.c | 9 +++++ + 2 files changed, 56 insertions(+), 18 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 05668b8e9..5ce344b3c 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #ifdef DRI3 + #include + #endif /* DRI3 */ +@@ -590,8 +591,17 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + return NULL; + } + ++ /* An implicit-modifier buffer (DRM_FORMAT_MOD_INVALID) is never listed in ++ * the compositor's advertised modifier set, so the regular support check ++ * fails. On the kgsl/turnip stack - where the buffer is allocated on the ++ * display node but composited by turnip - that left both the dmabuf and ++ * the (absent) wl_drm path unusable, so no wl_buffer was created and the ++ * X11 window stayed black. Per the linux-dmabuf protocol, INVALID means ++ * "let the compositor infer the layout", so submit it through the dmabuf ++ * path directly instead of rejecting it. */ + if (xwl_screen->dmabuf && +- xwl_glamor_is_modifier_supported(xwl_screen, format, modifier)) { ++ (modifier == DRM_FORMAT_MOD_INVALID || ++ xwl_glamor_is_modifier_supported(xwl_screen, format, modifier))) { + struct zwp_linux_buffer_params_v1 *params; + + params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf); +@@ -773,6 +783,15 @@ glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds, + strides[0] < width * bpp / 8) + goto error; + ++ /* Some freedreno/kgsl mesa builds (the on-device dev tree) rewrite a ++ * LINEAR modifier (0) to a bogus 1274 (0x4FA) in the loader_dri3 ++ * pixmap_from_buffers path. 1274 is not a valid DRM modifier, so the ++ * gbm_bo_import() below rejects it and the X11 GL client gets BadAlloc ++ * (dri3_alloc_render_buffer -> pixmap_from_buffer[s] failed -> segfault). ++ * The buffer is really linear, so map the bogus value back to LINEAR. */ ++ if (modifier == 1274ULL) ++ modifier = DRM_FORMAT_MOD_LINEAR; ++ + if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { + #ifdef GBM_BO_WITH_MODIFIERS + struct gbm_import_fd_modifier_data data; +@@ -1665,27 +1684,37 @@ static Bool + xwl_glamor_gbm_init_main_dev(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); +- drmDevice *main_dev; +- +- while (!xwl_screen->default_feedback.feedback_done) { +- if (wl_display_dispatch(xwl_screen->display) < 0) { +- ErrorF("Failed to dispatch Wayland display\n"); +- return FALSE; ++ drmDevice *main_dev = NULL; ++ ++ /* linux-dmabuf feedback (and thus a main device) only exists from protocol ++ * version 4. On the kgsl/turnip stack the compositor only speaks v3, so ++ * there is no feedback to wait for - skip the wait and go straight to the ++ * fallback render node below instead of blocking forever on feedback_done. */ ++ if (xwl_screen->dmabuf_protocol_version >= 4) { ++ while (!xwl_screen->default_feedback.feedback_done) { ++ if (wl_display_dispatch(xwl_screen->display) < 0) { ++ ErrorF("Failed to dispatch Wayland display\n"); ++ return FALSE; ++ } + } ++ main_dev = xwl_screen->default_feedback.main_dev; + } + +- main_dev = xwl_screen->default_feedback.main_dev; +- if (!main_dev) { +- ErrorF("No main linux-dmabuf device advertised by compositor\n"); +- return FALSE; +- } +- +- if (!(main_dev->available_nodes & (1 << DRM_NODE_RENDER))) { +- ErrorF("Main linux-dmabuf device has no render node\n"); +- return FALSE; ++ /* On the kgsl-backed turnip stack the compositor advertises no usable DRM ++ * render node (the GPU is exposed through kgsl, not a standard DRM node), ++ * so main_dev is NULL or render-node-less. Rather than dereferencing NULL ++ * (-> crash) or bailing out, fall back to a default render node, which the ++ * patched freedreno mesa redirects to /dev/kgsl-3d0 for native GL. */ ++ if (!main_dev || !(main_dev->available_nodes & (1 << DRM_NODE_RENDER))) { ++ const char *fallback = getenv("XWAYLAND_GBM_DEVICE"); ++ if (!fallback) ++ fallback = "/dev/dri/renderD128"; ++ ErrorF("No usable linux-dmabuf main device, falling back to %s\n", ++ fallback); ++ xwl_gbm->device_name = strdup(fallback); ++ } else { ++ xwl_gbm->device_name = strdup(main_dev->nodes[DRM_NODE_RENDER]); + } +- +- xwl_gbm->device_name = strdup(main_dev->nodes[DRM_NODE_RENDER]); + if (!xwl_gbm->device_name) { + return FALSE; + } +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index 88ced5da0..35d1e0391 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -123,6 +123,15 @@ xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen) + { + if (!xwl_glamor_has_wl_drm(xwl_screen) && + xwl_screen->dmabuf_protocol_version < 4) { ++ /* No wl_drm and no linux-dmabuf feedback (v4). On the kgsl/turnip stack ++ * the compositor exposes neither (the GPU lives behind /dev/kgsl-3d0, ++ * not a DRM render node, so there is no main device to advertise), but ++ * it does speak linux-dmabuf v3. We can still bring glamor up by opening ++ * a fallback render node directly (see xwl_glamor_gbm_init_main_dev) and ++ * submitting buffers over dmabuf v3, so keep glamor available as long as ++ * v3 is present. */ ++ if (xwl_screen->dmabuf_protocol_version >= 3) ++ return TRUE; + LogMessageVerb(X_INFO, 3, "glamor: 'wl_drm' not supported and linux-dmabuf v4 not supported\n"); + return FALSE; + } +-- +2.47.3 + diff --git a/x11-packages/xwayland/0002-xwayland-glamor-add-KGSL-surfaceless-backend-path.patch b/x11-packages/xwayland/0002-xwayland-glamor-add-KGSL-surfaceless-backend-path.patch new file mode 100644 index 00000000000..80618ef3e79 --- /dev/null +++ b/x11-packages/xwayland/0002-xwayland-glamor-add-KGSL-surfaceless-backend-path.patch @@ -0,0 +1,776 @@ +From 6087110e13fc4da98b24b9626b227b9eac9cc81d Mon Sep 17 00:00:00 2001 +From: lfdevs +Date: Wed, 8 Jul 2026 13:59:56 +0800 +Subject: [PATCH] xwayland/glamor: add KGSL surfaceless backend path + +Add an explicit KGSL surfaceless glamor path alongside the existing +GBM/DRM backend. The GBM path remains the default, while +XWAYLAND_FORCE_KGSL_SURFACELESS forces surfaceless EGL and +XWAYLAND_KGSL_SURFACELESS allows falling back to it after GBM setup +fails. + +In KGSL surfaceless mode, Xwayland allocates regular glamor textures, +creates EGLImages from them, exports dma-bufs with +EGL_MESA_image_dma_buf_export, and submits those buffers through +linux-dmabuf. DRI3 direct rendering and DRM syncobj support are disabled +for this backend because there is no usable DRM render node in the PRoot +KGSL environment. + +This keeps the normal DRM/GBM path unchanged for chroot and desktop +setups while allowing PRoot Xwayland to use Mesa KGSL for internal +glamor acceleration. +--- + hw/xwayland/xwayland-glamor-gbm.c | 556 +++++++++++++++++++++++++++--- + 1 file changed, 503 insertions(+), 53 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 5ce344b3c..b70a19fd2 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -32,7 +32,9 @@ + + #include + #include ++#include + #include ++#include + #include + #ifdef DRI3 + #include +@@ -65,7 +67,36 @@ + #include "linux-dmabuf-unstable-v1-client-protocol.h" + #include "linux-drm-syncobj-v1-client-protocol.h" + ++#ifndef EGL_PLATFORM_SURFACELESS_MESA ++#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD ++#endif ++ ++#ifndef EGL_GL_TEXTURE_2D_KHR ++#define EGL_GL_TEXTURE_2D_KHR 0x30B1 ++#endif ++ ++#ifndef EGL_GL_TEXTURE_LEVEL_KHR ++#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC ++#endif ++ ++#ifndef EGL_IMAGE_PRESERVED_KHR ++#define EGL_IMAGE_PRESERVED_KHR 0x30D2 ++#endif ++ ++typedef EGLBoolean (*xwl_egl_export_dmabuf_image_query_mesa_proc) ++ (EGLDisplay dpy, EGLImage image, int *fourcc, int *num_planes, ++ uint64_t *modifiers); ++typedef EGLBoolean (*xwl_egl_export_dmabuf_image_mesa_proc) ++ (EGLDisplay dpy, EGLImage image, int *fds, EGLint *strides, ++ EGLint *offsets); ++ ++enum xwl_glamor_backend { ++ XWL_GLAMOR_BACKEND_GBM, ++ XWL_GLAMOR_BACKEND_KGSL_SURFACELESS, ++}; ++ + struct xwl_gbm_private { ++ enum xwl_glamor_backend backend; + drmDevice *device; + char *device_name; + struct gbm_device *gbm; +@@ -76,6 +107,8 @@ struct xwl_gbm_private { + Bool glamor_gles; + Bool implicit_sync; + Bool supports_syncobjs; ++ xwl_egl_export_dmabuf_image_query_mesa_proc export_dmabuf_image_query; ++ xwl_egl_export_dmabuf_image_mesa_proc export_dmabuf_image; + + /* Set if wl_drm is available */ + struct wl_drm *drm; +@@ -106,6 +139,23 @@ xwl_gbm_get(struct xwl_screen *xwl_screen) + &xwl_gbm_private_key); + } + ++static Bool ++xwl_glamor_env_is_enabled(const char *name) ++{ ++ const char *value = getenv(name); ++ ++ return value && *value && *value != '0'; ++} ++ ++static Bool ++xwl_glamor_is_kgsl_surfaceless(struct xwl_screen *xwl_screen) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ return xwl_gbm && ++ xwl_gbm->backend == XWL_GLAMOR_BACKEND_KGSL_SURFACELESS; ++} ++ + Bool + xwl_glamor_has_wl_drm(struct xwl_screen *xwl_screen) + { +@@ -323,6 +373,95 @@ error: + return NULL; + } + ++static Bool ++xwl_glamor_pixmap_needs_wl_buffer(struct xwl_screen *xwl_screen, ++ int width, int height, int depth, ++ unsigned int hint) ++{ ++ return width > 0 && height > 0 && depth >= 15 && ++ (hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP || ++ hint == CREATE_PIXMAP_USAGE_SHARED || ++ (xwl_screen->rootless && hint == 0)); ++} ++ ++static PixmapPtr ++xwl_glamor_kgsl_create_pixmap(struct xwl_screen *xwl_screen, ++ int width, int height, int depth, ++ unsigned int hint) ++{ ++ PixmapPtr pixmap; ++ struct xwl_pixmap *xwl_pixmap; ++ unsigned int texture; ++ ++ pixmap = glamor_create_pixmap(xwl_screen->screen, width, height, depth, ++ hint); ++ if (!pixmap) ++ return NULL; ++ ++ if (!xwl_glamor_pixmap_needs_wl_buffer(xwl_screen, width, height, depth, ++ hint)) ++ return pixmap; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ texture = glamor_get_pixmap_texture(pixmap); ++ if (!texture) { ++ glamor_destroy_pixmap(pixmap); ++ return NULL; ++ } ++ ++ xwl_pixmap = calloc(1, sizeof(*xwl_pixmap)); ++ if (!xwl_pixmap) { ++ glamor_destroy_pixmap(pixmap); ++ return NULL; ++ } ++ ++ xwl_pixmap->image = EGL_NO_IMAGE_KHR; ++ xwl_pixmap->texture = texture; ++ xwl_pixmap->implicit_modifier = FALSE; ++#if defined(XWL_HAS_GLAMOR) && defined(DRI3) ++ xwl_pixmap->efd = -1; ++#endif /* defined(XWL_HAS_GLAMOR) && defined(DRI3) */ ++ xwl_pixmap_set_private(pixmap, xwl_pixmap); ++ ++ if (xwl_screen->rootless && hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) ++ glamor_clear_pixmap(pixmap); ++ ++ return pixmap; ++} ++ ++static Bool ++xwl_glamor_kgsl_ensure_pixmap_private(PixmapPtr pixmap) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ unsigned int texture; ++ ++ if (xwl_pixmap) ++ return TRUE; ++ ++ if (!xwl_glamor_is_kgsl_surfaceless(xwl_screen)) ++ return FALSE; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ texture = glamor_get_pixmap_texture(pixmap); ++ if (!texture) ++ return FALSE; ++ ++ xwl_pixmap = calloc(1, sizeof(*xwl_pixmap)); ++ if (!xwl_pixmap) ++ return FALSE; ++ ++ xwl_pixmap->image = EGL_NO_IMAGE_KHR; ++ xwl_pixmap->texture = texture; ++ xwl_pixmap->implicit_modifier = FALSE; ++#if defined(XWL_HAS_GLAMOR) && defined(DRI3) ++ xwl_pixmap->efd = -1; ++#endif /* defined(XWL_HAS_GLAMOR) && defined(DRI3) */ ++ xwl_pixmap_set_private(pixmap, xwl_pixmap); ++ ++ return TRUE; ++} ++ + static PixmapPtr + xwl_glamor_gbm_create_pixmap_internal(struct xwl_screen *xwl_screen, + DrawablePtr drawable, +@@ -336,10 +475,12 @@ xwl_glamor_gbm_create_pixmap_internal(struct xwl_screen *xwl_screen, + uint32_t num_modifiers = 0; + uint64_t *modifiers = NULL; + +- if (width > 0 && height > 0 && depth >= 15 && +- (hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP || +- hint == CREATE_PIXMAP_USAGE_SHARED || +- (xwl_screen->rootless && hint == 0))) { ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) ++ return xwl_glamor_kgsl_create_pixmap(xwl_screen, width, height, ++ depth, hint); ++ ++ if (xwl_glamor_pixmap_needs_wl_buffer(xwl_screen, width, height, depth, ++ hint)) { + uint32_t format = gbm_format_for_depth(depth, xwl_gbm->glamor_gles); + Bool implicit = FALSE; + +@@ -457,7 +598,8 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) + if (xwl_pixmap->buffer) + wl_buffer_destroy(xwl_pixmap->buffer); + +- eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); ++ if (xwl_pixmap->image != EGL_NO_IMAGE_KHR) ++ eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); + if (xwl_pixmap->bo) + gbm_bo_destroy(xwl_pixmap->bo); + xwl_glamor_gbm_dispose_syncpts(pixmap); +@@ -541,6 +683,116 @@ init_buffer_params_fallback(struct xwl_pixmap *xwl_pixmap, + return TRUE; + } + ++static Bool ++init_buffer_params_kgsl_surfaceless(struct xwl_screen *xwl_screen, ++ PixmapPtr pixmap, ++ uint32_t *format, ++ uint64_t *modifier, ++ int *num_planes, ++ int *prime_fds, ++ uint32_t *strides, ++ uint32_t *offsets) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ EGLint image_attrs[] = { ++ EGL_GL_TEXTURE_LEVEL_KHR, 0, ++ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, ++ EGL_NONE ++ }; ++ uint64_t modifiers[4] = { ++ DRM_FORMAT_MOD_INVALID, ++ DRM_FORMAT_MOD_INVALID, ++ DRM_FORMAT_MOD_INVALID, ++ DRM_FORMAT_MOD_INVALID ++ }; ++ EGLint egl_strides[4]; ++ EGLint egl_offsets[4]; ++ int fourcc; ++ int i; ++ ++ if (!xwl_pixmap || !xwl_pixmap->texture || ++ !xwl_gbm->export_dmabuf_image_query || ++ !xwl_gbm->export_dmabuf_image) ++ return FALSE; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ ++ if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) { ++ xwl_pixmap->image = ++ eglCreateImageKHR(xwl_screen->egl_display, ++ xwl_screen->egl_context, ++ EGL_GL_TEXTURE_2D_KHR, ++ (EGLClientBuffer)(uintptr_t)xwl_pixmap->texture, ++ image_attrs); ++ if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) { ++ ErrorF("Xwayland glamor: failed to create KGSL EGLImage\n"); ++ return FALSE; ++ } ++ } ++ ++ glFinish(); ++ ++ if (!xwl_gbm->export_dmabuf_image_query(xwl_screen->egl_display, ++ xwl_pixmap->image, ++ &fourcc, num_planes, ++ modifiers)) { ++ ErrorF("Xwayland glamor: failed to query KGSL dma-buf export\n"); ++ return FALSE; ++ } ++ ++ if (*num_planes <= 0 || *num_planes > 4) { ++ ErrorF("Xwayland glamor: unsupported KGSL dma-buf plane count %d\n", ++ *num_planes); ++ return FALSE; ++ } ++ ++ *modifier = modifiers[0]; ++ for (i = 0; i < *num_planes; i++) { ++ if (modifiers[i] != *modifier) { ++ ErrorF("Xwayland glamor: per-plane KGSL modifiers differ\n"); ++ return FALSE; ++ } ++ } ++ ++ if (*modifier != DRM_FORMAT_MOD_LINEAR && ++ *modifier != DRM_FORMAT_MOD_INVALID) { ++ ErrorF("Xwayland glamor: KGSL exported unsupported modifier 0x%" PRIx64 "\n", ++ *modifier); ++ return FALSE; ++ } ++ ++ for (i = 0; i < *num_planes; i++) ++ prime_fds[i] = -1; ++ ++ if (!xwl_gbm->export_dmabuf_image(xwl_screen->egl_display, ++ xwl_pixmap->image, ++ prime_fds, egl_strides, ++ egl_offsets)) { ++ for (i = 0; i < *num_planes; i++) { ++ if (prime_fds[i] >= 0) { ++ close(prime_fds[i]); ++ prime_fds[i] = -1; ++ } ++ } ++ ErrorF("Xwayland glamor: failed to export KGSL dma-buf\n"); ++ return FALSE; ++ } ++ ++ for (i = 0; i < *num_planes; i++) { ++ if (prime_fds[i] < 0) { ++ while (--i >= 0) ++ close(prime_fds[i]); ++ return FALSE; ++ } ++ strides[i] = egl_strides[i]; ++ offsets[i] = egl_offsets[i]; ++ } ++ ++ *format = fourcc; ++ return TRUE; ++} ++ + struct wl_buffer * + xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + { +@@ -556,39 +808,58 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + uint32_t offsets[4]; + uint64_t modifier; + int i; ++ static Bool logged_kgsl_dmabuf_buffer; ++ static Bool logged_kgsl_linear_unadvertised; + +- if (xwl_pixmap == NULL) ++ if (xwl_pixmap == NULL && ++ !xwl_glamor_kgsl_ensure_pixmap_private(pixmap)) + return NULL; ++ xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap->buffer) { ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ xwl_glamor_egl_make_current(xwl_screen); ++ glFinish(); ++ } + /* Buffer already exists. */ + return xwl_pixmap->buffer; + } + +- if (!xwl_pixmap->bo) ++ if (!xwl_pixmap->bo && !xwl_glamor_is_kgsl_surfaceless(xwl_screen)) + return NULL; + +- format = wl_drm_format_for_depth(pixmap->drawable.depth); ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ if (!init_buffer_params_kgsl_surfaceless(xwl_screen, pixmap, ++ &format, ++ &modifier, ++ &num_planes, ++ prime_fds, ++ strides, ++ offsets)) ++ return NULL; ++ } else { ++ format = wl_drm_format_for_depth(pixmap->drawable.depth); + + #ifdef GBM_BO_WITH_MODIFIERS +- if (!xwl_pixmap->implicit_modifier) { +- if (!init_buffer_params_with_modifiers(xwl_pixmap, +- &modifier, +- &num_planes, +- prime_fds, +- strides, +- offsets)) +- return NULL; +- } else ++ if (!xwl_pixmap->implicit_modifier) { ++ if (!init_buffer_params_with_modifiers(xwl_pixmap, ++ &modifier, ++ &num_planes, ++ prime_fds, ++ strides, ++ offsets)) ++ return NULL; ++ } else + #endif +- { +- if (!init_buffer_params_fallback(xwl_pixmap, +- &modifier, +- &num_planes, +- prime_fds, +- strides, +- offsets)) +- return NULL; ++ { ++ if (!init_buffer_params_fallback(xwl_pixmap, ++ &modifier, ++ &num_planes, ++ prime_fds, ++ strides, ++ offsets)) ++ return NULL; ++ } + } + + /* An implicit-modifier buffer (DRM_FORMAT_MOD_INVALID) is never listed in +@@ -601,9 +872,19 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + * path directly instead of rejecting it. */ + if (xwl_screen->dmabuf && + (modifier == DRM_FORMAT_MOD_INVALID || ++ (xwl_glamor_is_kgsl_surfaceless(xwl_screen) && ++ modifier == DRM_FORMAT_MOD_LINEAR) || + xwl_glamor_is_modifier_supported(xwl_screen, format, modifier))) { + struct zwp_linux_buffer_params_v1 *params; + ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen) && ++ modifier == DRM_FORMAT_MOD_LINEAR && ++ !xwl_glamor_is_modifier_supported(xwl_screen, format, modifier) && ++ !logged_kgsl_linear_unadvertised) { ++ ErrorF("linux-dmabuf: submitting KGSL LINEAR dmabuf without advertised modifier\n"); ++ logged_kgsl_linear_unadvertised = TRUE; ++ } ++ + params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf); + for (i = 0; i < num_planes; i++) { + zwp_linux_buffer_params_v1_add(params, prime_fds[i], i, +@@ -629,9 +910,20 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + close(prime_fds[i]); + + /* Add our listener now */ +- if (xwl_pixmap->buffer) ++ if (xwl_pixmap->buffer) { + wl_buffer_add_listener(xwl_pixmap->buffer, + &xwl_glamor_gbm_buffer_listener, pixmap); ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen) && ++ !logged_kgsl_dmabuf_buffer) { ++ ErrorF("linux-dmabuf: created wl_buffer from KGSL dmabuf\n"); ++ logged_kgsl_dmabuf_buffer = TRUE; ++ } ++ } ++ else if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ ErrorF("linux-dmabuf: failed to create wl_buffer from KGSL dmabuf " ++ "(format=0x%" PRIx32 ", modifier=0x%" PRIx64 ")\n", ++ format, modifier); ++ } + + return xwl_pixmap->buffer; + } +@@ -651,7 +943,7 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) + if (xwl_gbm->device_name) + free(xwl_gbm->device_name); + drmFreeDevice(&xwl_gbm->device); +- if (xwl_gbm->drm_fd) ++ if (xwl_gbm->drm_fd >= 0) + close(xwl_gbm->drm_fd); + if (xwl_gbm->drm) + wl_drm_destroy(xwl_gbm->drm); +@@ -783,6 +1075,9 @@ glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds, + strides[0] < width * bpp / 8) + goto error; + ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) ++ goto error; ++ + /* Some freedreno/kgsl mesa builds (the on-device dev tree) rewrite a + * LINEAR modifier (0) to a bogus 1274 (0x4FA) in the loader_dri3 + * pixmap_from_buffers path. 1274 is not a valid DRM modifier, so the +@@ -858,6 +1153,9 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + if (xwl_pixmap == NULL) + return 0; + ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen_get(screen))) ++ return 0; ++ + if (!xwl_pixmap->bo) + return 0; + +@@ -933,6 +1231,9 @@ xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap) + + #ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE + xwl_pixmap = xwl_pixmap_get(pixmap); ++ if (!xwl_pixmap || !xwl_pixmap->bo) ++ return -1; ++ + num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); + + for (p = 0; p < num_planes; ++p) { +@@ -986,6 +1287,11 @@ xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file) + + #ifdef DMA_BUF_IOCTL_IMPORT_SYNC_FILE + xwl_pixmap = xwl_pixmap_get(pixmap); ++ if (!xwl_pixmap || !xwl_pixmap->bo) { ++ close(sync_file); ++ return; ++ } ++ + num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); + + for (p = 0; p < num_planes; ++p) { +@@ -1434,8 +1740,16 @@ xwl_screen_set_syncobj_interface(struct xwl_screen *xwl_screen, + static Bool + xwl_glamor_gbm_has_egl_extension(void) + { +- return (epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") || +- epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm")); ++ Bool has_gbm = epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") || ++ epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm"); ++ ++ if (xwl_glamor_env_is_enabled("XWAYLAND_FORCE_KGSL_SURFACELESS") || ++ xwl_glamor_env_is_enabled("XWAYLAND_KGSL_SURFACELESS")) { ++ return has_gbm || ++ epoxy_has_egl_extension(NULL, "EGL_MESA_platform_surfaceless"); ++ } ++ ++ return has_gbm; + } + + #ifdef DRI3 +@@ -1736,20 +2050,161 @@ xwl_glamor_gbm_init_main_dev(struct xwl_screen *xwl_screen) + return TRUE; + } + ++static void ++xwl_glamor_gbm_reset_egl(struct xwl_screen *xwl_screen) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ if (xwl_screen->egl_display != EGL_NO_DISPLAY) { ++ xwl_glamor_maybe_destroy_context(xwl_screen); ++ eglTerminate(xwl_screen->egl_display); ++ xwl_screen->egl_display = EGL_NO_DISPLAY; ++ } ++ ++ if (xwl_gbm->gbm) { ++ gbm_device_destroy(xwl_gbm->gbm); ++ xwl_gbm->gbm = NULL; ++ } ++ if (xwl_gbm->device_name) { ++ free(xwl_gbm->device_name); ++ xwl_gbm->device_name = NULL; ++ } ++ drmFreeDevice(&xwl_gbm->device); ++ xwl_gbm->device = NULL; ++ if (xwl_gbm->drm_fd >= 0) { ++ close(xwl_gbm->drm_fd); ++ xwl_gbm->drm_fd = -1; ++ } ++ ++ xwl_gbm->fd_render_node = FALSE; ++ xwl_gbm->dmabuf_capable = FALSE; ++ xwl_gbm->supports_syncobjs = FALSE; ++ xwl_gbm->export_dmabuf_image_query = NULL; ++ xwl_gbm->export_dmabuf_image = NULL; ++} ++ ++static Bool ++xwl_glamor_validate_renderer(void) ++{ ++ const GLubyte *renderer = glGetString(GL_RENDERER); ++ ++ if (!renderer) { ++ ErrorF("glGetString() returned NULL, your GL is broken\n"); ++ return FALSE; ++ } ++ if (strstr((const char *)renderer, "softpipe")) { ++ ErrorF("Refusing to try glamor on softpipe\n"); ++ return FALSE; ++ } ++ if (!strncmp("llvmpipe", (const char *)renderer, strlen("llvmpipe"))) { ++ ErrorF("Refusing to try glamor on llvmpipe\n"); ++ return FALSE; ++ } ++ if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { ++ ErrorF("GL_OES_EGL_image not available\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static Bool ++xwl_glamor_kgsl_surfaceless_init_egl(struct xwl_screen *xwl_screen) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ EGLint major, minor; ++ const char *egl_vendor; ++ ++ if (!xwl_screen->dmabuf) { ++ ErrorF("Xwayland glamor: KGSL surfaceless requires linux-dmabuf\n"); ++ return FALSE; ++ } ++ ++ xwl_gbm->backend = XWL_GLAMOR_BACKEND_KGSL_SURFACELESS; ++ xwl_screen->egl_display = ++ glamor_egl_get_display(EGL_PLATFORM_SURFACELESS_MESA, ++ EGL_DEFAULT_DISPLAY); ++ if (xwl_screen->egl_display == EGL_NO_DISPLAY) { ++ ErrorF("Xwayland glamor: surfaceless EGL display setup failed\n"); ++ return FALSE; ++ } ++ ++ if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) { ++ ErrorF("Xwayland glamor: surfaceless eglInitialize() failed\n"); ++ goto error; ++ } ++ ++ if (!xwl_glamor_try_big_gl_api(xwl_screen) && ++ !xwl_glamor_try_gles_api(xwl_screen)) { ++ ErrorF("Cannot use neither GL nor GLES2\n"); ++ goto error; ++ } ++ ++ if (!xwl_glamor_validate_renderer()) ++ goto error; ++ ++ if (!epoxy_has_egl_extension(xwl_screen->egl_display, ++ "EXT_image_dma_buf_import") || ++ !epoxy_has_egl_extension(xwl_screen->egl_display, ++ "MESA_image_dma_buf_export")) { ++ ErrorF("Xwayland glamor: KGSL surfaceless dma-buf export extensions unavailable\n"); ++ goto error; ++ } ++ ++ xwl_gbm->export_dmabuf_image_query = ++ (xwl_egl_export_dmabuf_image_query_mesa_proc) ++ eglGetProcAddress("eglExportDMABUFImageQueryMESA"); ++ xwl_gbm->export_dmabuf_image = ++ (xwl_egl_export_dmabuf_image_mesa_proc) ++ eglGetProcAddress("eglExportDMABUFImageMESA"); ++ if (!xwl_gbm->export_dmabuf_image_query || ++ !xwl_gbm->export_dmabuf_image) { ++ ErrorF("Xwayland glamor: KGSL surfaceless dma-buf export entrypoints unavailable\n"); ++ goto error; ++ } ++ ++ xwl_gbm->dmabuf_capable = TRUE; ++ xwl_gbm->glamor_gles = !epoxy_is_desktop_gl(); ++ xwl_gbm->implicit_sync = TRUE; ++ xwl_gbm->supports_syncobjs = FALSE; ++ xwl_screen->glvnd_vendor = "mesa"; ++ ++ if (xwl_screen->explicit_sync) { ++ wp_linux_drm_syncobj_manager_v1_destroy(xwl_screen->explicit_sync); ++ xwl_screen->explicit_sync = NULL; ++ } ++ ++ egl_vendor = eglQueryString(xwl_screen->egl_display, EGL_VENDOR); ++ ErrorF("Xwayland glamor: using KGSL surfaceless EGL backend (%s)\n", ++ egl_vendor ? egl_vendor : "unknown vendor"); ++ return TRUE; ++ ++error: ++ xwl_glamor_gbm_reset_egl(xwl_screen); ++ xwl_gbm->backend = XWL_GLAMOR_BACKEND_GBM; ++ return FALSE; ++} ++ + Bool + xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + EGLint major, minor; +- const GLubyte *renderer; + const char *gbm_backend_name, *egl_vendor; ++ Bool allow_kgsl_fallback = ++ xwl_glamor_env_is_enabled("XWAYLAND_KGSL_SURFACELESS"); ++ ++ xwl_gbm->backend = XWL_GLAMOR_BACKEND_GBM; ++ ++ if (xwl_glamor_env_is_enabled("XWAYLAND_FORCE_KGSL_SURFACELESS")) ++ return xwl_glamor_kgsl_surfaceless_init_egl(xwl_screen); + + if (!xwl_gbm->drm && !xwl_glamor_gbm_init_main_dev(xwl_screen)) +- return FALSE; ++ goto error; + + if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) { + ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n"); +- return FALSE; ++ goto error; + } + + xwl_gbm->gbm = gbm_create_device(xwl_gbm->drm_fd); +@@ -1776,24 +2231,8 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) + goto error; + } + +- renderer = glGetString(GL_RENDERER); +- if (!renderer) { +- ErrorF("glGetString() returned NULL, your GL is broken\n"); +- goto error; +- } +- if (strstr((const char *)renderer, "softpipe")) { +- ErrorF("Refusing to try glamor on softpipe\n"); +- goto error; +- } +- if (!strncmp("llvmpipe", (const char *)renderer, strlen("llvmpipe"))) { +- ErrorF("Refusing to try glamor on llvmpipe\n"); +- goto error; +- } +- +- if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { +- ErrorF("GL_OES_EGL_image not available\n"); ++ if (!xwl_glamor_validate_renderer()) + goto error; +- } + + if (epoxy_has_egl_extension(xwl_screen->egl_display, + "EXT_image_dma_buf_import") && +@@ -1828,12 +2267,14 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) + #endif /* DRI3 */ + return TRUE; + error: +- if (xwl_screen->egl_display != EGL_NO_DISPLAY) { +- xwl_glamor_maybe_destroy_context(xwl_screen); +- eglTerminate(xwl_screen->egl_display); +- xwl_screen->egl_display = EGL_NO_DISPLAY; ++ if (allow_kgsl_fallback) { ++ ErrorF("Xwayland glamor: GBM EGL setup failed, trying KGSL surfaceless\n"); ++ xwl_glamor_gbm_reset_egl(xwl_screen); ++ if (xwl_glamor_kgsl_surfaceless_init_egl(xwl_screen)) ++ return TRUE; + } + ++ xwl_glamor_gbm_reset_egl(xwl_screen); + xwl_glamor_gbm_cleanup(xwl_screen); + return FALSE; + } +@@ -1842,6 +2283,12 @@ Bool + xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ if (xwl_gbm->backend == XWL_GLAMOR_BACKEND_KGSL_SURFACELESS) { ++ ErrorF("Xwayland glamor: disabling DRI3 for KGSL surfaceless backend\n"); ++ goto skip_drm_auth; ++ } ++ + #ifdef DRI3 + if (xwl_gbm->supports_syncobjs) { + xwl_dri3_info.version = 4; +@@ -1902,6 +2349,9 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) + return FALSE; + } + ++ xwl_gbm->drm_fd = -1; ++ xwl_gbm->backend = XWL_GLAMOR_BACKEND_GBM; ++ + dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key, + xwl_gbm); + +-- +2.47.3 + diff --git a/x11-packages/xwayland/0003-xwayland-dri3-support-KGSL-surfaceless-client-render.patch b/x11-packages/xwayland/0003-xwayland-dri3-support-KGSL-surfaceless-client-render.patch new file mode 100644 index 00000000000..4783b733bdf --- /dev/null +++ b/x11-packages/xwayland/0003-xwayland-dri3-support-KGSL-surfaceless-client-render.patch @@ -0,0 +1,730 @@ +From b2298cba9c243fabdecee768b14eaaebf76daa9e Mon Sep 17 00:00:00 2001 +From: lfdevs +Date: Wed, 8 Jul 2026 22:26:16 +0800 +Subject: [PATCH] xwayland/dri3: support KGSL surfaceless client rendering + +Enable the KGSL surfaceless backend to serve DRI3 clients without relying on a GBM render node. + +Open /dev/kgsl-3d0 for DRI3 clients, advertise linear dma-buf modifiers, and import client dma-bufs directly as EGLImages/textures. Keep duplicated dma-buf fds and plane metadata for KGSL DRI3 pixmaps so Xwayland can recreate the import before Present copies; this avoids stale long-lived EGLImage sampling on the KGSL/proot path and keeps glmark2 visually updating. + +Disable direct Present flips for KGSL surfaceless before probing wl_buffers, since this backend must use the copy path. Also keep KGSL surface commits moving when frame callbacks become stale by occasionally forcing a damage post and refreshing the exported wl_buffer. +--- + hw/xwayland/xwayland-glamor-gbm.c | 406 ++++++++++++++++++++++++++++-- + hw/xwayland/xwayland-glamor-gbm.h | 3 + + hw/xwayland/xwayland-present.c | 19 ++ + hw/xwayland/xwayland-screen.c | 27 +- + hw/xwayland/xwayland-screen.h | 1 + + hw/xwayland/xwayland-window.c | 12 + + hw/xwayland/xwayland-window.h | 1 + + 7 files changed, 452 insertions(+), 17 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index b70a19fd2..fa3d51f26 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #ifdef DRI3 + #include + #endif /* DRI3 */ +@@ -126,6 +127,13 @@ struct xwl_pixmap { + uint64_t timeline_point; + int efd; + struct xwl_window_buffer *xwl_window_buffer; ++ Bool kgsl_dri3_import; ++ CARD8 kgsl_num_fds; ++ int kgsl_fds[4]; ++ uint32_t kgsl_format; ++ CARD32 kgsl_strides[4]; ++ CARD32 kgsl_offsets[4]; ++ uint64_t kgsl_modifier; + #endif /* DRI3 */ + }; + +@@ -147,7 +155,7 @@ xwl_glamor_env_is_enabled(const char *name) + return value && *value && *value != '0'; + } + +-static Bool ++Bool + xwl_glamor_is_kgsl_surfaceless(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); +@@ -156,6 +164,21 @@ xwl_glamor_is_kgsl_surfaceless(struct xwl_screen *xwl_screen) + xwl_gbm->backend == XWL_GLAMOR_BACKEND_KGSL_SURFACELESS; + } + ++void ++xwl_glamor_kgsl_refresh_wl_buffer(PixmapPtr pixmap) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ ++ if (!xwl_glamor_is_kgsl_surfaceless(xwl_screen) || ++ !xwl_pixmap || !xwl_pixmap->buffer) ++ return; ++ ++ xwl_pixmap_del_buffer_release_cb(pixmap); ++ wl_buffer_destroy(xwl_pixmap->buffer); ++ xwl_pixmap->buffer = NULL; ++} ++ + Bool + xwl_glamor_has_wl_drm(struct xwl_screen *xwl_screen) + { +@@ -350,7 +373,7 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image); +- if (eglGetError() != EGL_SUCCESS) ++ if (glGetError() != GL_NO_ERROR) + goto error; + + glBindTexture(GL_TEXTURE_2D, 0); +@@ -429,6 +452,289 @@ xwl_glamor_kgsl_create_pixmap(struct xwl_screen *xwl_screen, + return pixmap; + } + ++#ifdef DRI3 ++static void ++xwl_glamor_kgsl_close_import_fds(struct xwl_pixmap *xwl_pixmap) ++{ ++ int plane; ++ ++ if (!xwl_pixmap->kgsl_dri3_import) ++ return; ++ ++ for (plane = 0; plane < xwl_pixmap->kgsl_num_fds; plane++) { ++ if (xwl_pixmap->kgsl_fds[plane] >= 0) { ++ close(xwl_pixmap->kgsl_fds[plane]); ++ xwl_pixmap->kgsl_fds[plane] = -1; ++ } ++ } ++ ++ xwl_pixmap->kgsl_dri3_import = FALSE; ++ xwl_pixmap->kgsl_num_fds = 0; ++} ++#endif /* DRI3 */ ++ ++static EGLImage ++xwl_glamor_kgsl_create_dma_buf_image(struct xwl_screen *xwl_screen, ++ CARD8 num_fds, const int *fds, ++ CARD16 width, CARD16 height, ++ uint32_t format, ++ const CARD32 *strides, ++ const CARD32 *offsets, ++ uint64_t modifier) ++{ ++ EGLint img_attrs[64] = {0}; ++ int attr_num = 0; ++ int plane; ++ enum PlaneAttrs { ++ PLANE_FD, ++ PLANE_OFFSET, ++ PLANE_PITCH, ++ PLANE_MODIFIER_LO, ++ PLANE_MODIFIER_HI, ++ NUM_PLANE_ATTRS ++ }; ++ static const EGLint plane_attrs[][NUM_PLANE_ATTRS] = { ++ { ++ EGL_DMA_BUF_PLANE0_FD_EXT, ++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE0_PITCH_EXT, ++ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, ++ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, ++ }, ++ { ++ EGL_DMA_BUF_PLANE1_FD_EXT, ++ EGL_DMA_BUF_PLANE1_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE1_PITCH_EXT, ++ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, ++ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, ++ }, ++ { ++ EGL_DMA_BUF_PLANE2_FD_EXT, ++ EGL_DMA_BUF_PLANE2_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE2_PITCH_EXT, ++ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, ++ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, ++ }, ++ { ++ EGL_DMA_BUF_PLANE3_FD_EXT, ++ EGL_DMA_BUF_PLANE3_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE3_PITCH_EXT, ++ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, ++ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT, ++ }, ++ }; ++ ++#define ADD_ATTR(attrs, num, attr) \ ++ do { \ ++ assert(((num) + 1) < (sizeof(attrs) / sizeof((attrs)[0]))); \ ++ (attrs)[(num)++] = (attr); \ ++ } while (0) ++ ADD_ATTR(img_attrs, attr_num, EGL_WIDTH); ++ ADD_ATTR(img_attrs, attr_num, width); ++ ADD_ATTR(img_attrs, attr_num, EGL_HEIGHT); ++ ADD_ATTR(img_attrs, attr_num, height); ++ ADD_ATTR(img_attrs, attr_num, EGL_LINUX_DRM_FOURCC_EXT); ++ ADD_ATTR(img_attrs, attr_num, format); ++ ++ for (plane = 0; plane < num_fds; plane++) { ++ ADD_ATTR(img_attrs, attr_num, plane_attrs[plane][PLANE_FD]); ++ ADD_ATTR(img_attrs, attr_num, fds[plane]); ++ ADD_ATTR(img_attrs, attr_num, plane_attrs[plane][PLANE_OFFSET]); ++ ADD_ATTR(img_attrs, attr_num, offsets[plane]); ++ ADD_ATTR(img_attrs, attr_num, plane_attrs[plane][PLANE_PITCH]); ++ ADD_ATTR(img_attrs, attr_num, strides[plane]); ++ if (modifier != DRM_FORMAT_MOD_INVALID) { ++ ADD_ATTR(img_attrs, attr_num, plane_attrs[plane][PLANE_MODIFIER_LO]); ++ ADD_ATTR(img_attrs, attr_num, (uint32_t)(modifier & 0xffffffffULL)); ++ ADD_ATTR(img_attrs, attr_num, plane_attrs[plane][PLANE_MODIFIER_HI]); ++ ADD_ATTR(img_attrs, attr_num, (uint32_t)(modifier >> 32ULL)); ++ } ++ } ++ ADD_ATTR(img_attrs, attr_num, EGL_NONE); ++#undef ADD_ATTR ++ ++ return eglCreateImageKHR(xwl_screen->egl_display, ++ EGL_NO_CONTEXT, ++ EGL_LINUX_DMA_BUF_EXT, ++ NULL, ++ img_attrs); ++} ++ ++static Bool ++xwl_glamor_kgsl_bind_image_to_texture(EGLImage image, unsigned int *texture) ++{ ++ GLenum gl_error; ++ ++ *texture = 0; ++ ++ glGenTextures(1, texture); ++ glBindTexture(GL_TEXTURE_2D, *texture); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ++ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); ++ gl_error = glGetError(); ++ if (gl_error != GL_NO_ERROR) { ++ ErrorF("Xwayland glamor: failed to bind KGSL DRI3 EGLImage " ++ "(gl_error=0x%x)\n", gl_error); ++ glBindTexture(GL_TEXTURE_2D, 0); ++ if (*texture) { ++ glDeleteTextures(1, texture); ++ *texture = 0; ++ } ++ return FALSE; ++ } ++ ++ glBindTexture(GL_TEXTURE_2D, 0); ++ return TRUE; ++} ++ ++static PixmapPtr ++xwl_glamor_kgsl_create_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, ++ const int *fds, CARD16 width, ++ CARD16 height, ++ const CARD32 *strides, ++ const CARD32 *offsets, ++ CARD8 depth, uint64_t modifier) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ PixmapPtr pixmap = NULL; ++ struct xwl_pixmap *xwl_pixmap = NULL; ++#ifdef DRI3 ++ int plane; ++#endif /* DRI3 */ ++ EGLint egl_error; ++ uint32_t format = gbm_format_for_depth(depth, xwl_gbm->glamor_gles); ++ ++ if (num_fds == 0 || num_fds > 4) ++ return NULL; ++ ++ xwl_pixmap = calloc(1, sizeof(*xwl_pixmap)); ++ if (!xwl_pixmap) ++ return NULL; ++ ++#ifdef DRI3 ++ xwl_pixmap->efd = -1; ++ xwl_pixmap->kgsl_dri3_import = TRUE; ++ xwl_pixmap->kgsl_num_fds = num_fds; ++ xwl_pixmap->kgsl_format = format; ++ xwl_pixmap->kgsl_modifier = modifier; ++ for (plane = 0; plane < 4; plane++) ++ xwl_pixmap->kgsl_fds[plane] = -1; ++ for (plane = 0; plane < num_fds; plane++) { ++ xwl_pixmap->kgsl_fds[plane] = dup(fds[plane]); ++ if (xwl_pixmap->kgsl_fds[plane] < 0) ++ goto error; ++ xwl_pixmap->kgsl_strides[plane] = strides[plane]; ++ xwl_pixmap->kgsl_offsets[plane] = offsets[plane]; ++ } ++#endif /* DRI3 */ ++ ++ pixmap = glamor_create_pixmap(screen, width, height, depth, ++ GLAMOR_CREATE_PIXMAP_NO_TEXTURE); ++ if (!pixmap) ++ goto error; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ xwl_pixmap->image = xwl_glamor_kgsl_create_dma_buf_image(xwl_screen, ++ num_fds, fds, ++ width, height, ++ format, ++ strides, offsets, ++ modifier); ++ if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) { ++ egl_error = eglGetError(); ++ ErrorF("Xwayland glamor: failed to import KGSL DRI3 dma-buf " ++ "(format=0x%" PRIx32 ", modifier=0x%" PRIx64 ++ ", planes=%d, egl_error=0x%x)\n", ++ format, modifier, num_fds, egl_error); ++ goto error; ++ } ++ ++ if (!xwl_glamor_kgsl_bind_image_to_texture(xwl_pixmap->image, ++ &xwl_pixmap->texture)) ++ goto error; ++ ++ if (!glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture)) { ++ ErrorF("Xwayland glamor: failed to attach KGSL DRI3 texture to pixmap\n"); ++ goto error; ++ } ++ ++ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); ++ xwl_pixmap->implicit_modifier = modifier == DRM_FORMAT_MOD_INVALID; ++ xwl_pixmap_set_private(pixmap, xwl_pixmap); ++ ++ return pixmap; ++ ++error: ++#ifdef DRI3 ++ xwl_glamor_kgsl_close_import_fds(xwl_pixmap); ++#endif /* DRI3 */ ++ if (xwl_pixmap->image != EGL_NO_IMAGE_KHR) ++ eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); ++ if (xwl_pixmap->texture) ++ glDeleteTextures(1, &xwl_pixmap->texture); ++ if (pixmap) ++ glamor_destroy_pixmap(pixmap); ++ free(xwl_pixmap); ++ return NULL; ++} ++ ++Bool ++xwl_glamor_kgsl_refresh_dri3_pixmap(PixmapPtr pixmap) ++{ ++#ifdef DRI3 ++ struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ EGLImage image; ++ unsigned int texture; ++ EGLint egl_error; ++ ++ if (!xwl_glamor_is_kgsl_surfaceless(xwl_screen) || ++ !xwl_pixmap || !xwl_pixmap->kgsl_dri3_import) ++ return TRUE; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ image = xwl_glamor_kgsl_create_dma_buf_image(xwl_screen, ++ xwl_pixmap->kgsl_num_fds, ++ xwl_pixmap->kgsl_fds, ++ pixmap->drawable.width, ++ pixmap->drawable.height, ++ xwl_pixmap->kgsl_format, ++ xwl_pixmap->kgsl_strides, ++ xwl_pixmap->kgsl_offsets, ++ xwl_pixmap->kgsl_modifier); ++ if (image == EGL_NO_IMAGE_KHR) { ++ egl_error = eglGetError(); ++ ErrorF("Xwayland glamor: failed to refresh KGSL DRI3 dma-buf " ++ "(pixmap=0x%x, planes=%d, egl_error=0x%x)\n", ++ pixmap->drawable.id, xwl_pixmap->kgsl_num_fds, egl_error); ++ return FALSE; ++ } ++ ++ if (!xwl_glamor_kgsl_bind_image_to_texture(image, &texture)) { ++ eglDestroyImageKHR(xwl_screen->egl_display, image); ++ return FALSE; ++ } ++ ++ if (!glamor_set_pixmap_texture(pixmap, texture)) { ++ ErrorF("Xwayland glamor: failed to refresh KGSL DRI3 pixmap texture\n"); ++ glDeleteTextures(1, &texture); ++ eglDestroyImageKHR(xwl_screen->egl_display, image); ++ return FALSE; ++ } ++ ++ if (xwl_pixmap->image != EGL_NO_IMAGE_KHR) ++ eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); ++ ++ xwl_pixmap->image = image; ++ xwl_pixmap->texture = texture; ++ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); ++#endif /* DRI3 */ ++ ++ return TRUE; ++} ++ + static Bool + xwl_glamor_kgsl_ensure_pixmap_private(PixmapPtr pixmap) + { +@@ -603,6 +909,9 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) + if (xwl_pixmap->bo) + gbm_bo_destroy(xwl_pixmap->bo); + xwl_glamor_gbm_dispose_syncpts(pixmap); ++#ifdef DRI3 ++ xwl_glamor_kgsl_close_import_fds(xwl_pixmap); ++#endif /* DRI3 */ + free(xwl_pixmap); + } + +@@ -1023,6 +1332,15 @@ xwl_dri3_open_client(ClientPtr client, + drm_magic_t magic; + int fd; + ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ fd = open("/dev/kgsl-3d0", O_RDWR | O_CLOEXEC); ++ if (fd < 0) ++ return BadAlloc; ++ ++ *pfd = fd; ++ return Success; ++ } ++ + fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC); + if (fd < 0) + return BadAlloc; +@@ -1075,9 +1393,6 @@ glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds, + strides[0] < width * bpp / 8) + goto error; + +- if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) +- goto error; +- + /* Some freedreno/kgsl mesa builds (the on-device dev tree) rewrite a + * LINEAR modifier (0) to a bogus 1274 (0x4FA) in the loader_dri3 + * pixmap_from_buffers path. 1274 is not a valid DRM modifier, so the +@@ -1087,6 +1402,17 @@ glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds, + if (modifier == 1274ULL) + modifier = DRM_FORMAT_MOD_LINEAR; + ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ if (modifier != DRM_FORMAT_MOD_INVALID && ++ modifier != DRM_FORMAT_MOD_LINEAR) ++ goto error; ++ ++ return xwl_glamor_kgsl_create_pixmap_from_fds(screen, num_fds, fds, ++ width, height, strides, ++ offsets, depth, ++ modifier); ++ } ++ + if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { + #ifdef GBM_BO_WITH_MODIFIERS + struct gbm_import_fd_modifier_data data; +@@ -1140,6 +1466,7 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint64_t *modifier) + { + struct xwl_pixmap *xwl_pixmap; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); + #ifdef GBM_BO_WITH_MODIFIERS + #ifndef GBM_BO_FD_FOR_PLANE + int32_t first_handle; +@@ -1150,11 +1477,26 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + + xwl_pixmap = xwl_pixmap_get(pixmap); + ++ if (xwl_pixmap == NULL && ++ xwl_glamor_is_kgsl_surfaceless(xwl_screen) && ++ xwl_glamor_kgsl_ensure_pixmap_private(pixmap)) ++ xwl_pixmap = xwl_pixmap_get(pixmap); ++ + if (xwl_pixmap == NULL) + return 0; + +- if (xwl_glamor_is_kgsl_surfaceless(xwl_screen_get(screen))) +- return 0; ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ uint32_t format; ++ int num_planes; ++ ++ if (!init_buffer_params_kgsl_surfaceless(xwl_screen, pixmap, ++ &format, modifier, ++ &num_planes, fds, ++ strides, offsets)) ++ return 0; ++ ++ return num_planes; ++ } + + if (!xwl_pixmap->bo) + return 0; +@@ -1544,6 +1886,39 @@ xwl_dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd) + return &syncobj->base; + } + ++static Bool ++xwl_dri3_get_modifiers(ScreenPtr screen, uint32_t format, ++ uint32_t *num_modifiers, uint64_t **modifiers) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ ++ if (!xwl_glamor_is_kgsl_surfaceless(xwl_screen)) ++ return xwl_glamor_get_modifiers(screen, format, num_modifiers, modifiers); ++ ++ *num_modifiers = 0; ++ *modifiers = calloc(1, sizeof(uint64_t)); ++ if (!*modifiers) ++ return FALSE; ++ ++ (*modifiers)[0] = DRM_FORMAT_MOD_LINEAR; ++ *num_modifiers = 1; ++ return TRUE; ++} ++ ++static Bool ++xwl_dri3_get_drawable_modifiers(DrawablePtr drawable, uint32_t format, ++ uint32_t *num_modifiers, uint64_t **modifiers) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(drawable->pScreen); ++ ++ if (!xwl_glamor_is_kgsl_surfaceless(xwl_screen)) ++ return xwl_glamor_get_drawable_modifiers(drawable, format, ++ num_modifiers, modifiers); ++ ++ return xwl_dri3_get_modifiers(drawable->pScreen, format, ++ num_modifiers, modifiers); ++} ++ + static Bool + xwl_gbm_supports_syncobjs(struct xwl_screen *xwl_screen) + { +@@ -1574,8 +1949,8 @@ static dri3_screen_info_rec xwl_dri3_info = { + .fds_from_pixmap = glamor_fds_from_pixmap, + .open_client = xwl_dri3_open_client, + .get_formats = xwl_glamor_get_formats, +- .get_modifiers = xwl_glamor_get_modifiers, +- .get_drawable_modifiers = xwl_glamor_get_drawable_modifiers, ++ .get_modifiers = xwl_dri3_get_modifiers, ++ .get_drawable_modifiers = xwl_dri3_get_drawable_modifiers, + .import_syncobj = NULL, /* need to check for kernel support */ + }; + #endif /* DRI3 */ +@@ -2284,12 +2659,10 @@ xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + +- if (xwl_gbm->backend == XWL_GLAMOR_BACKEND_KGSL_SURFACELESS) { +- ErrorF("Xwayland glamor: disabling DRI3 for KGSL surfaceless backend\n"); +- goto skip_drm_auth; +- } +- + #ifdef DRI3 ++ xwl_dri3_info.version = 2; ++ xwl_dri3_info.import_syncobj = NULL; ++ + if (xwl_gbm->supports_syncobjs) { + xwl_dri3_info.version = 4; + xwl_dri3_info.import_syncobj = xwl_dri3_import_syncobj; +@@ -2299,6 +2672,11 @@ xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) + ErrorF("Failed to initialize dri3\n"); + goto error; + } ++ ++ if (xwl_gbm->backend == XWL_GLAMOR_BACKEND_KGSL_SURFACELESS) { ++ ErrorF("Xwayland glamor: enabling DRI3 without syncobjs for KGSL surfaceless backend\n"); ++ goto skip_drm_auth; ++ } + #endif /* DRI3 */ + if (xwl_gbm->fd_render_node) + goto skip_drm_auth; +diff --git a/hw/xwayland/xwayland-glamor-gbm.h b/hw/xwayland/xwayland-glamor-gbm.h +index b346a0ba6..e40ef4941 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.h ++++ b/hw/xwayland/xwayland-glamor-gbm.h +@@ -41,6 +41,9 @@ Bool xwl_glamor_has_wl_drm(struct xwl_screen *xwl_screen); + Bool xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen); + Bool xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen); + drmDevice *xwl_gbm_get_main_device(struct xwl_screen *xwl_screen); ++Bool xwl_glamor_is_kgsl_surfaceless(struct xwl_screen *xwl_screen); ++void xwl_glamor_kgsl_refresh_wl_buffer(PixmapPtr pixmap); ++Bool xwl_glamor_kgsl_refresh_dri3_pixmap(PixmapPtr pixmap); + + /* Explicit buffer synchronization points */ + Bool xwl_glamor_gbm_set_syncpts(struct xwl_window *xwl_window, PixmapPtr pixmap); +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +index 7b9a4ac32..6b7ec9168 100644 +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -28,6 +28,7 @@ + #include + #ifdef XWL_HAS_GLAMOR + #include ++#include "xwayland-glamor-gbm.h" + #endif + #include + #include +@@ -689,9 +690,15 @@ xwl_present_flush(WindowPtr window) + #ifdef XWL_HAS_GLAMOR + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ static unsigned int kgsl_flush_count; + + if (xwl_screen->glamor) + glamor_block_handler(screen); ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ kgsl_flush_count++; ++ if ((kgsl_flush_count % 256) == 0) ++ xwl_screen_post_damage(xwl_screen); ++ } + #endif + } + +@@ -766,6 +773,11 @@ xwl_present_check_flip(RRCrtcPtr crtc, + present_window->drawable.height != pixmap->drawable.height) + return FALSE; + ++#ifdef XWL_HAS_GLAMOR ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_window->xwl_screen)) ++ return FALSE; ++#endif /* XWL_HAS_GLAMOR */ ++ + if (!xwl_pixmap_get_wl_buffer(pixmap)) + return FALSE; + +@@ -1160,6 +1172,13 @@ retry: + else if (xwl_present_window->flip_active) + xwl_present_flips_stop(window); + ++#ifdef XWL_HAS_GLAMOR ++ if (xwl_glamor_is_kgsl_surfaceless(xwl_screen) && ++ !xwl_glamor_kgsl_refresh_dri3_pixmap(vblank->pixmap)) { ++ ErrorF("Xwayland glamor: failed to refresh KGSL source pixmap before copy\n"); ++ } ++#endif ++ + present_execute_copy(vblank, crtc_msc); + assert(!vblank->queued); + +diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c +index c83adda9f..7825e3fa7 100644 +--- a/hw/xwayland/xwayland-screen.c ++++ b/hw/xwayland/xwayland-screen.c +@@ -32,6 +32,7 @@ + + #ifdef XWL_HAS_GLAMOR + #include ++#include "xwayland-glamor-gbm.h" + #endif + + #include +@@ -433,11 +434,15 @@ xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen) + xwl_window_check_resolution_change_emulation(xwl_window); + } + +-static void ++void + xwl_screen_post_damage(struct xwl_screen *xwl_screen) + { + struct xwl_window *xwl_window, *next_xwl_window; + struct xorg_list commit_window_list; ++#ifdef XWL_HAS_GLAMOR ++ Bool kgsl = xwl_glamor_is_kgsl_surfaceless(xwl_screen); ++ static unsigned int kgsl_frame_block_count; ++#endif + + xorg_list_init(&commit_window_list); + +@@ -445,11 +450,27 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) + &xwl_screen->damage_window_list, link_damage) { + /* If we're waiting on a frame callback from the server, + * don't attach a new buffer. */ +- if (xwl_window->frame_callback) ++ if (xwl_window->frame_callback) { ++#ifdef XWL_HAS_GLAMOR ++ if (kgsl) { ++ kgsl_frame_block_count++; ++ if ((kgsl_frame_block_count % 64) != 0) { ++ continue; ++ } ++ wl_callback_destroy(xwl_window->frame_callback); ++ xwl_window->frame_callback = NULL; ++ xwl_window->force_refresh_wl_buffer = TRUE; ++ } else { ++ continue; ++ } ++#else + continue; ++#endif ++ } + +- if (!xwl_window->allow_commits) ++ if (!xwl_window->allow_commits) { + continue; ++ } + + xwl_window_post_damage(xwl_window); + xorg_list_del(&xwl_window->link_damage); +diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h +index 9751bd25d..259ce7188 100644 +--- a/hw/xwayland/xwayland-screen.h ++++ b/hw/xwayland/xwayland-screen.h +@@ -165,6 +165,7 @@ struct xwl_client *xwl_client_get(ClientPtr client); + struct xwl_screen *xwl_screen_get(ScreenPtr screen); + Bool xwl_screen_has_viewport_support(struct xwl_screen *xwl_screen); + Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen); ++void xwl_screen_post_damage(struct xwl_screen *xwl_screen); + void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen); + struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen); + struct xwl_output *xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen); +diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c +index 4a9a58a2f..d98102cce 100644 +--- a/hw/xwayland/xwayland-window.c ++++ b/hw/xwayland/xwayland-window.c +@@ -48,6 +48,9 @@ + #include "xwayland-window-buffers.h" + #include "xwayland-shm.h" + #include "xwayland-dmabuf.h" ++#ifdef XWL_HAS_GLAMOR ++#include "xwayland-glamor-gbm.h" ++#endif + + #include "linux-dmabuf-unstable-v1-client-protocol.h" + #include "tearing-control-v1-client-protocol.h" +@@ -2041,6 +2044,15 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window) + int i; + + pixmap = xwl_window_swap_pixmap(xwl_window, TRUE); ++#ifdef XWL_HAS_GLAMOR ++ if (xwl_screen->glamor && ++ xwl_glamor_is_kgsl_surfaceless(xwl_screen)) { ++ if (xwl_window->force_refresh_wl_buffer) { ++ xwl_glamor_kgsl_refresh_wl_buffer(pixmap); ++ xwl_window->force_refresh_wl_buffer = FALSE; ++ } ++ } ++#endif + buffer = xwl_pixmap_get_wl_buffer(pixmap); + + if (!buffer) { +diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h +index ac3ce5034..14a721ce1 100644 +--- a/hw/xwayland/xwayland-window.h ++++ b/hw/xwayland/xwayland-window.h +@@ -88,6 +88,7 @@ struct xwl_window { + struct xorg_list link_window; + struct wl_callback *frame_callback; + Bool allow_commits; ++ Bool force_refresh_wl_buffer; + struct xorg_list window_buffers_available; + struct xorg_list window_buffers_unavailable; + OsTimerPtr window_buffers_timer; +-- +2.47.3 + diff --git a/x11-packages/xwayland/0004-xwayland-scope-KGSL-frame-callback-recovery-per-window.patch b/x11-packages/xwayland/0004-xwayland-scope-KGSL-frame-callback-recovery-per-window.patch new file mode 100644 index 00000000000..11c0ad421f0 --- /dev/null +++ b/x11-packages/xwayland/0004-xwayland-scope-KGSL-frame-callback-recovery-per-window.patch @@ -0,0 +1,79 @@ +From 443d7d3603dd6fa4d181364e4dc15a435f8b0d4f Mon Sep 17 00:00:00 2001 +From: lfdevs +Date: Thu, 9 Jul 2026 00:21:05 +0800 +Subject: [PATCH] xwayland: scope KGSL frame callback recovery per window + +Keep the KGSL stale frame callback recovery path, but track blocked frame +callbacks per Xwayland window instead of using a global counter. + +This avoids one busy or stuck window advancing the recovery threshold for +another window during multi-window workloads or rapid resize. Reset the +counter when a frame callback arrives normally, and also after damage is +posted successfully for that window. +--- + hw/xwayland/xwayland-screen.c | 8 ++++---- + hw/xwayland/xwayland-window.c | 1 + + hw/xwayland/xwayland-window.h | 1 + + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c +index 7825e3fa7..34dfd5522 100644 +--- a/hw/xwayland/xwayland-screen.c ++++ b/hw/xwayland/xwayland-screen.c +@@ -441,7 +441,6 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) + struct xorg_list commit_window_list; + #ifdef XWL_HAS_GLAMOR + Bool kgsl = xwl_glamor_is_kgsl_surfaceless(xwl_screen); +- static unsigned int kgsl_frame_block_count; + #endif + + xorg_list_init(&commit_window_list); +@@ -453,10 +452,10 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) + if (xwl_window->frame_callback) { + #ifdef XWL_HAS_GLAMOR + if (kgsl) { +- kgsl_frame_block_count++; +- if ((kgsl_frame_block_count % 64) != 0) { ++ xwl_window->blocked_frame_callback_count++; ++ if (xwl_window->blocked_frame_callback_count < 64) + continue; +- } ++ xwl_window->blocked_frame_callback_count = 0; + wl_callback_destroy(xwl_window->frame_callback); + xwl_window->frame_callback = NULL; + xwl_window->force_refresh_wl_buffer = TRUE; +@@ -473,6 +472,7 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) + } + + xwl_window_post_damage(xwl_window); ++ xwl_window->blocked_frame_callback_count = 0; + xorg_list_del(&xwl_window->link_damage); + xorg_list_append(&xwl_window->link_damage, &commit_window_list); + } +diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c +index d98102cce..9b40dfa65 100644 +--- a/hw/xwayland/xwayland-window.c ++++ b/hw/xwayland/xwayland-window.c +@@ -1973,6 +1973,7 @@ frame_callback(void *data, + + wl_callback_destroy (xwl_window->frame_callback); + xwl_window->frame_callback = NULL; ++ xwl_window->blocked_frame_callback_count = 0; + + if (xwl_window->xwl_screen->present) { + xwl_present_for_each_frame_callback(xwl_window, xwl_present_frame_callback); +diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h +index 14a721ce1..080cea795 100644 +--- a/hw/xwayland/xwayland-window.h ++++ b/hw/xwayland/xwayland-window.h +@@ -89,6 +89,7 @@ struct xwl_window { + struct wl_callback *frame_callback; + Bool allow_commits; + Bool force_refresh_wl_buffer; ++ unsigned int blocked_frame_callback_count; + struct xorg_list window_buffers_available; + struct xorg_list window_buffers_unavailable; + OsTimerPtr window_buffers_timer; +-- +2.47.3 + diff --git a/x11-packages/xwayland/build.sh b/x11-packages/xwayland/build.sh index 534889a7dd6..14cd098ca76 100644 --- a/x11-packages/xwayland/build.sh +++ b/x11-packages/xwayland/build.sh @@ -3,10 +3,11 @@ TERMUX_PKG_DESCRIPTION="Wayland X11 server" TERMUX_PKG_LICENSE="MIT" TERMUX_PKG_MAINTAINER="@termux" TERMUX_PKG_VERSION="24.1.12" +TERMUX_PKG_REVISION=2 TERMUX_PKG_SRCURL=https://xorg.freedesktop.org/releases/individual/xserver/xwayland-${TERMUX_PKG_VERSION}.tar.xz TERMUX_PKG_SHA256=6df02c511b92c1b9848734d9d1b03a4c24f8375ba3cada44e9684a21b5f78e21 -TERMUX_PKG_AUTO_UPDATE=true -TERMUX_PKG_DEPENDS="libandroid-shmem, libdrm, libepoxy, libpciaccess, libpixman, libwayland, libwayland-protocols, libx11, libxau, libxcvt, libxfont2, libxinerama, libxkbfile, libxshmfence, opengl, openssl, xkeyboard-config, xorg-protocol-txt, xorg-xkbcomp" +TERMUX_PKG_AUTO_UPDATE=false +TERMUX_PKG_DEPENDS="libandroid-shmem, libdrm, libepoxy, libpciaccess, libpixman, libwayland, libwayland-protocols, libx11, libxau, libxcvt, libxfont2, libxinerama, libxkbfile, libxshmfence, mesa, opengl, openssl, xkeyboard-config, xorg-protocol-txt, xorg-xkbcomp" TERMUX_PKG_BUILD_DEPENDS="libwayland-cross-scanner" TERMUX_PKG_EXTRA_CONFIGURE_ARGS=" @@ -23,12 +24,15 @@ TERMUX_PKG_EXTRA_CONFIGURE_ARGS=" -Dxcsecurity=true -Dxf86bigfont=true -Ddrm=true --Dglamor=false +-Dglamor=true -Dxvfb=false -Dlibunwind=false -Dipv6=true -Dsha1=libcrypto -Ddefault_font_path=$TERMUX_PREFIX/share/fonts +-Dxkb_dir=$TERMUX_PREFIX/share/xkeyboard-config-2 +-Dxkb_output_dir=$TERMUX_PREFIX/tmp +-Dxkb_bin_dir=$TERMUX_PREFIX/bin " # Remove files conflicting with xorg-server: