diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bfd71d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/xwayland-21.1.1.tar.xz diff --git a/.xorg-x11-server-Xwayland.metadata b/.xorg-x11-server-Xwayland.metadata new file mode 100644 index 0000000..a73c554 --- /dev/null +++ b/.xorg-x11-server-Xwayland.metadata @@ -0,0 +1 @@ +4eb5e22033c0c80c35480c9466e8041e914cac3a SOURCES/xwayland-21.1.1.tar.xz diff --git a/SOURCES/0001-xwayland-Move-dmabuf-interface-to-common-glamor-code.patch b/SOURCES/0001-xwayland-Move-dmabuf-interface-to-common-glamor-code.patch new file mode 100644 index 0000000..878be4e --- /dev/null +++ b/SOURCES/0001-xwayland-Move-dmabuf-interface-to-common-glamor-code.patch @@ -0,0 +1,257 @@ +From c7853c6de126f6794946c592deed205c0ddad2d9 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Wed, 3 Mar 2021 09:55:12 +0100 +Subject: [PATCH xserver 01/27] xwayland: Move dmabuf interface to common + glamor code + +This is preliminary work for hardware accelerated rendering with the +NVIDIA driver. + +The EGLStream backend can possibly also use the dmabuf interface, so +move the relevant code from the GBM specific source to the common bits. + +Signed-off-by: Olivier Fourdan +(cherry picked from commit ae225417c0a0828ffb24e11eb4b968c34692e25a) +--- + hw/xwayland/xwayland-glamor-gbm.c | 73 ++--------------------------- + hw/xwayland/xwayland-glamor.c | 76 +++++++++++++++++++++++++++++-- + hw/xwayland/xwayland-screen.h | 1 + + 3 files changed, 76 insertions(+), 74 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 221bf268a..73c69727e 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -56,7 +56,6 @@ struct xwl_gbm_private { + char *device_name; + struct gbm_device *gbm; + struct wl_drm *drm; +- struct zwp_linux_dmabuf_v1 *dmabuf; + int drm_fd; + int fd_render_node; + Bool drm_authenticated; +@@ -334,10 +333,10 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + } + } + +- if (xwl_gbm->dmabuf && modifier_supported) { ++ if (xwl_screen->dmabuf && modifier_supported) { + struct zwp_linux_buffer_params_v1 *params; + +- params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf); ++ 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_fd, i, + offsets[i], strides[i], +@@ -604,7 +603,7 @@ glamor_get_formats(ScreenPtr screen, + /* Explicitly zero the count as the caller may ignore the return value */ + *num_formats = 0; + +- if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf) ++ if (!xwl_gbm->dmabuf_capable || !xwl_screen->dmabuf) + return FALSE; + + if (xwl_screen->num_formats == 0) +@@ -633,7 +632,7 @@ glamor_get_modifiers(ScreenPtr screen, uint32_t format, + /* Explicitly zero the count as the caller may ignore the return value */ + *num_modifiers = 0; + +- if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf) ++ if (!xwl_gbm->dmabuf_capable || !xwl_screen->dmabuf) + return FALSE; + + if (xwl_screen->num_formats == 0) +@@ -797,54 +796,6 @@ static const struct wl_drm_listener xwl_drm_listener = { + xwl_drm_handle_capabilities + }; + +-static void +-xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, +- uint32_t format) +-{ +-} +- +-static void +-xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, +- uint32_t format, uint32_t modifier_hi, +- uint32_t modifier_lo) +-{ +- struct xwl_screen *xwl_screen = data; +- struct xwl_format *xwl_format = NULL; +- int i; +- +- for (i = 0; i < xwl_screen->num_formats; i++) { +- if (xwl_screen->formats[i].format == format) { +- xwl_format = &xwl_screen->formats[i]; +- break; +- } +- } +- +- if (xwl_format == NULL) { +- xwl_screen->num_formats++; +- xwl_screen->formats = realloc(xwl_screen->formats, +- xwl_screen->num_formats * sizeof(*xwl_format)); +- if (!xwl_screen->formats) +- return; +- xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1]; +- xwl_format->format = format; +- xwl_format->num_modifiers = 0; +- xwl_format->modifiers = NULL; +- } +- +- xwl_format->num_modifiers++; +- xwl_format->modifiers = realloc(xwl_format->modifiers, +- xwl_format->num_modifiers * sizeof(uint64_t)); +- if (!xwl_format->modifiers) +- return; +- xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo; +- xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32; +-} +- +-static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = { +- .format = xwl_dmabuf_handle_format, +- .modifier = xwl_dmabuf_handle_modifier +-}; +- + Bool + xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +@@ -862,22 +813,6 @@ xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + return TRUE; + } + +-Bool +-xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, +- uint32_t id, uint32_t version) +-{ +- struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); +- +- if (version < 3) +- return FALSE; +- +- xwl_gbm->dmabuf = +- wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3); +- zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen); +- +- return TRUE; +-} +- + static Bool + xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *wl_registry, +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index bcd07a1a5..cce0c911e 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -35,6 +35,10 @@ + #include "glx_extinit.h" + #endif + ++#include "linux-dmabuf-unstable-v1-client-protocol.h" ++#include "drm-client-protocol.h" ++#include ++ + #include "xwayland-glamor.h" + #include "xwayland-glx.h" + #include "xwayland-screen.h" +@@ -75,6 +79,68 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) + xwl_screen->glamor_ctx = glamor_ctx; + } + ++static void ++xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, ++ uint32_t format) ++{ ++} ++ ++static void ++xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, ++ uint32_t format, uint32_t modifier_hi, ++ uint32_t modifier_lo) ++{ ++ struct xwl_screen *xwl_screen = data; ++ struct xwl_format *xwl_format = NULL; ++ int i; ++ ++ for (i = 0; i < xwl_screen->num_formats; i++) { ++ if (xwl_screen->formats[i].format == format) { ++ xwl_format = &xwl_screen->formats[i]; ++ break; ++ } ++ } ++ ++ if (xwl_format == NULL) { ++ xwl_screen->num_formats++; ++ xwl_screen->formats = realloc(xwl_screen->formats, ++ xwl_screen->num_formats * sizeof(*xwl_format)); ++ if (!xwl_screen->formats) ++ return; ++ xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1]; ++ xwl_format->format = format; ++ xwl_format->num_modifiers = 0; ++ xwl_format->modifiers = NULL; ++ } ++ ++ xwl_format->num_modifiers++; ++ xwl_format->modifiers = realloc(xwl_format->modifiers, ++ xwl_format->num_modifiers * sizeof(uint64_t)); ++ if (!xwl_format->modifiers) ++ return; ++ xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo; ++ xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32; ++} ++ ++static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = { ++ .format = xwl_dmabuf_handle_format, ++ .modifier = xwl_dmabuf_handle_modifier ++}; ++ ++Bool ++xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, ++ uint32_t id, uint32_t version) ++{ ++ if (version < 3) ++ return FALSE; ++ ++ xwl_screen->dmabuf = ++ wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3); ++ zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen); ++ ++ return TRUE; ++} ++ + void + xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *registry, +@@ -89,11 +155,11 @@ xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, + version)) { + /* no-op */ + } else if (xwl_screen->eglstream_backend.is_available && +- xwl_screen->eglstream_backend.init_wl_registry(xwl_screen, +- registry, +- id, +- interface, +- version)) { ++ xwl_screen->eglstream_backend.init_wl_registry(xwl_screen, ++ registry, ++ id, ++ interface, ++ version)) { + /* no-op */ + } + } +diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h +index 8d0b12705..5fe4712bd 100644 +--- a/hw/xwayland/xwayland-screen.h ++++ b/hw/xwayland/xwayland-screen.h +@@ -83,6 +83,7 @@ struct xwl_screen { + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; + struct zwp_pointer_constraints_v1 *pointer_constraints; + struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab; ++ struct zwp_linux_dmabuf_v1 *dmabuf; + struct zxdg_output_manager_v1 *xdg_output_manager; + struct wp_viewporter *viewporter; + uint32_t serial; +-- +2.31.1 + diff --git a/SOURCES/0001-xwayland-eglstream-Keep-pending-stream-if-the-pixmap.patch b/SOURCES/0001-xwayland-eglstream-Keep-pending-stream-if-the-pixmap.patch new file mode 100644 index 0000000..5e27cf6 --- /dev/null +++ b/SOURCES/0001-xwayland-eglstream-Keep-pending-stream-if-the-pixmap.patch @@ -0,0 +1,36 @@ +From 8c74023712a9e0d79ec669738b726e7dc821de68 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Wed, 23 Jun 2021 11:35:17 +0200 +Subject: [PATCH xserver 1/2] xwayland/eglstream: Keep pending stream if the + pixmap didn't change +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the pixmap does not actually change in set_window_pixmap(), there is +no need to invalidate the pending stream, if there's one. + +Signed-off-by: Olivier Fourdan +Suggested-by: Michel Dänzer +Reviewed-by: Michel Dänzer +(cherry picked from commit 2be9f795bc15012dc912f595003e01bb6aa66f54) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 0affc954c..2eae9494c 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -377,7 +377,7 @@ xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) + * attached, so the stream would be useless. + */ + old_pixmap = (*screen->GetWindowPixmap) (window); +- if (old_pixmap) ++ if (old_pixmap && old_pixmap != pixmap) + xwl_eglstream_maybe_set_pending_stream_invalid(old_pixmap); + + xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap; +-- +2.31.1 + diff --git a/SOURCES/0002-xwayland-eglstream-Remove-stream-validity.patch b/SOURCES/0002-xwayland-eglstream-Remove-stream-validity.patch new file mode 100644 index 0000000..84f6bfa --- /dev/null +++ b/SOURCES/0002-xwayland-eglstream-Remove-stream-validity.patch @@ -0,0 +1,292 @@ +From d9005a02e9c109e57dcc81b51de3b5778915af26 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Fri, 30 Apr 2021 09:56:05 +0200 +Subject: [PATCH xserver 2/2] xwayland/eglstream: Remove stream validity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To avoid an EGL stream in the wrong state, if the window pixmap changed +before the stream was connected, we would still keep the pending stream +but mark it as invalid. Once the callback is received, the pending would +be simply discarded. + +But all of this is actually to avoid a bug in egl-wayland, there should +not be any problem with Xwayland destroying an EGL stream while the +compositor is still using it. + +With that bug now fixed in egl-wayland 1.1.7, we can safely drop all +that logic from Xwayland EGLstream backend. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1189 +(cherry picked from commit 7d509b6f342d9732b567dc4efa867ea24919853b) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 165 ++++-------------------- + 1 file changed, 28 insertions(+), 137 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 2eae9494c..8d18caaf5 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -52,15 +52,6 @@ + #include "wayland-eglstream-controller-client-protocol.h" + #include "linux-dmabuf-unstable-v1-client-protocol.h" + +-struct xwl_eglstream_pending_stream { +- PixmapPtr pixmap; +- WindowPtr window; +- +- struct wl_callback *cb; +- +- Bool is_valid; +-}; +- + struct xwl_eglstream_private { + EGLDeviceEXT egl_device; + struct wl_eglstream_display *display; +@@ -90,7 +81,7 @@ struct xwl_pixmap { + /* add any new <= 4-byte member here to avoid holes on 64-bit */ + struct xwl_screen *xwl_screen; + struct wl_buffer *buffer; +- struct xwl_eglstream_pending_stream *pending_stream; ++ struct wl_callback *pending_cb; + Bool wait_for_buffer_release; + + /* XWL_PIXMAP_EGLSTREAM. */ +@@ -301,20 +292,12 @@ xwl_eglstream_destroy_pixmap_stream(struct xwl_pixmap *xwl_pixmap) + free(xwl_pixmap); + } + +-static void +-xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream *pending) +-{ +- if (pending->cb) +- wl_callback_destroy(pending->cb); +- free(pending); +-} +- + static void + xwl_glamor_eglstream_remove_pending_stream(struct xwl_pixmap *xwl_pixmap) + { +- if (xwl_pixmap->pending_stream) { +- xwl_glamor_eglstream_destroy_pending_stream(xwl_pixmap->pending_stream); +- xwl_pixmap->pending_stream = NULL; ++ if (xwl_pixmap->pending_cb) { ++ wl_callback_destroy(xwl_pixmap->pending_cb); ++ xwl_pixmap->pending_cb = NULL; + } + } + +@@ -338,27 +321,13 @@ xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + } + + static void +-xwl_eglstream_maybe_set_pending_stream_invalid(PixmapPtr pixmap) ++xwl_eglstream_cancel_pending_stream(PixmapPtr pixmap) + { + struct xwl_pixmap *xwl_pixmap; +- struct xwl_eglstream_pending_stream *pending; + + xwl_pixmap = xwl_pixmap_get(pixmap); +- if (!xwl_pixmap) +- return; +- +- pending = xwl_pixmap->pending_stream; +- if (!pending) +- return; +- +- pending->is_valid = FALSE; +- +- /* The compositor may still be using the stream, so we can't destroy +- * it yet. We'll only have a guarantee that the stream is safe to +- * destroy once we receive the pending wl_display_sync() for this +- * stream +- */ +- pending->pixmap->refcnt++; ++ if (xwl_pixmap) ++ xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); + } + + static void +@@ -378,7 +347,7 @@ xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) + */ + old_pixmap = (*screen->GetWindowPixmap) (window); + if (old_pixmap && old_pixmap != pixmap) +- xwl_eglstream_maybe_set_pending_stream_invalid(old_pixmap); ++ xwl_eglstream_cancel_pending_stream(old_pixmap); + + xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap; + (*xwl_screen->screen->SetWindowPixmap)(window, pixmap); +@@ -464,68 +433,19 @@ xwl_eglstream_print_error(EGLDisplay egl_display, + } + } + +-/* Because we run asynchronously with our wayland compositor, it's possible +- * that an X client event could cause us to begin creating a stream for a +- * pixmap/window combo before the stream for the pixmap this window +- * previously used has been fully initialized. An example: +- * +- * - Start processing X client events. +- * - X window receives resize event, causing us to create a new pixmap and +- * begin creating the corresponding eglstream. This pixmap is known as +- * pixmap A. +- * - X window receives another resize event, and again changes its current +- * pixmap causing us to create another corresponding eglstream for the same +- * window. This pixmap is known as pixmap B. +- * - Start handling events from the wayland compositor. +- * +- * Since both pixmap A and B will have scheduled wl_display_sync events to +- * indicate when their respective streams are connected, we will receive each +- * callback in the original order the pixmaps were created. This means the +- * following would happen: +- * +- * - Receive pixmap A's stream callback, attach its stream to the surface of +- * the window that just orphaned it. +- * - Receive pixmap B's stream callback, fall over and fail because the +- * window's surface now incorrectly has pixmap A's stream attached to it. +- * +- * We work around this problem by keeping a pending stream associated with +- * the xwl_pixmap, which itself is associated with the window pixmap. +- * In the scenario listed above, this should happen: +- * +- * - Begin processing X events... +- * - A window is resized, a new window pixmap is created causing us to +- * add an eglstream (known as eglstream A) waiting for its consumer +- * to finish attachment. +- * - Resize on same window happens. We invalidate the previously pending +- * stream on the old window pixmap. +- * A new window pixmap is attached to the window and another pending +- * stream is created for that new pixmap (known as eglstream B). +- * - Begin processing Wayland events... +- * - Receive invalidated callback from compositor for eglstream A, destroy +- * stream. +- * - Receive callback from compositor for eglstream B, create producer. +- * - Success! +- */ + static void + xwl_eglstream_consumer_ready_callback(void *data, + struct wl_callback *callback, + uint32_t time) + { +- struct xwl_eglstream_pending_stream *pending = data; +- PixmapPtr pixmap = pending->pixmap; ++ PixmapPtr pixmap = data; + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + + wl_callback_destroy(callback); +- pending->cb = NULL; +- +- if (!pending->is_valid) { +- xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); +- dixDestroyPixmap(pixmap, 0); +- return; +- } ++ xwl_pixmap->pending_cb = NULL; + + xwl_glamor_egl_make_current(xwl_screen); + +@@ -541,42 +461,16 @@ xwl_eglstream_consumer_ready_callback(void *data, + ErrorF("eglstream: Failed to create EGLSurface for pixmap\n"); + xwl_eglstream_print_error(xwl_screen->egl_display, + xwl_pixmap->stream, eglGetError()); +- goto out; ++ } else { ++ DebugF("eglstream: completes eglstream for pixmap %p, congrats!\n", ++ pixmap); + } +- +- DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n", +- pending->window->drawable.id, pending->pixmap); +- +-out: +- xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); + } + + static const struct wl_callback_listener consumer_ready_listener = { + xwl_eglstream_consumer_ready_callback + }; + +-static struct xwl_eglstream_pending_stream * +-xwl_eglstream_queue_pending_stream(WindowPtr window, PixmapPtr pixmap) +-{ +- struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); +- struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; +- struct xwl_eglstream_pending_stream *pending_stream; +- +- DebugF("eglstream: win %d queues new pending stream for pixmap %p\n", +- window->drawable.id, pixmap); +- +- pending_stream = calloc(1, sizeof(*pending_stream)); +- pending_stream->window = window; +- pending_stream->pixmap = pixmap; +- pending_stream->is_valid = TRUE; +- +- pending_stream->cb = wl_display_sync(xwl_screen->display); +- wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener, +- pending_stream); +- +- return pending_stream; +-} +- + static void + xwl_eglstream_buffer_release_callback(void *data) + { +@@ -656,9 +550,9 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + wl_eglstream_controller_attach_eglstream_consumer( + xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); + +- xwl_pixmap->pending_stream = +- xwl_eglstream_queue_pending_stream(window, pixmap); +- ++ xwl_pixmap->pending_cb = wl_display_sync(xwl_screen->display); ++ wl_callback_add_listener(xwl_pixmap->pending_cb, &consumer_ready_listener, ++ pixmap); + fail: + if (stream_fd >= 0) + close(stream_fd); +@@ -673,25 +567,22 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap) { +- struct xwl_eglstream_pending_stream *pending = xwl_pixmap->pending_stream; +- +- if (pending) { ++ if (xwl_pixmap->pending_cb) { + /* Wait for the compositor to finish connecting the consumer for + * this eglstream */ +- assert(pending->is_valid); +- + return FALSE; +- } else { +- if (xwl_pixmap->surface != EGL_NO_SURFACE || +- xwl_pixmap->type == XWL_PIXMAP_DMA_BUF) +- return TRUE; +- +- /* The pending stream got removed, we have a xwl_pixmap and +- * yet we do not have a surface. +- * So something went wrong with the surface creation, retry. +- */ +- xwl_eglstream_destroy_pixmap_stream(xwl_pixmap); + } ++ ++ if (xwl_pixmap->surface != EGL_NO_SURFACE || ++ xwl_pixmap->type == XWL_PIXMAP_DMA_BUF) { ++ return TRUE; ++ } ++ ++ /* The pending stream got removed, we have a xwl_pixmap and ++ * yet we do not have a surface. ++ * So something went wrong with the surface creation, retry. ++ */ ++ xwl_eglstream_destroy_pixmap_stream(xwl_pixmap); + } + + /* Glamor pixmap has no backing stream yet; begin making one and disallow +-- +2.31.1 + diff --git a/SOURCES/0002-xwayland-move-formats-and-modifiers-functions-to-com.patch b/SOURCES/0002-xwayland-move-formats-and-modifiers-functions-to-com.patch new file mode 100644 index 0000000..3da295e --- /dev/null +++ b/SOURCES/0002-xwayland-move-formats-and-modifiers-functions-to-com.patch @@ -0,0 +1,330 @@ +From ec91c17a881eaf69c4109f050e7bb9928906c52e Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Fri, 12 Feb 2021 12:09:27 -0800 +Subject: [PATCH xserver 02/27] xwayland: move formats and modifiers functions + to common glamor code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is preliminary work for hardware accelerated rendering with the +NVIDIA driver. + +This moves the modifiers and formats functions previously only available +to the GBM backend to the common glamor code so that it can be used by +both the GBM and EGLStream backends. + +Reviewed-by: Michel Dänzer +Acked-by: Olivier Fourdan +Signed-off-by: Erik Kurzinger +(cherry picked from commit 400d4d0fdd55192f394e1a8273dfb2423c895ec0) +--- + hw/xwayland/xwayland-glamor-gbm.c | 115 ++---------------------------- + hw/xwayland/xwayland-glamor.c | 111 ++++++++++++++++++++++++++++ + hw/xwayland/xwayland-glamor.h | 8 ++- + 3 files changed, 123 insertions(+), 111 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 73c69727e..455b755ca 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -97,25 +97,6 @@ gbm_format_for_depth(int depth) + } + } + +-static uint32_t +-wl_drm_format_for_depth(int depth) +-{ +- switch (depth) { +- case 15: +- return WL_DRM_FORMAT_XRGB1555; +- case 16: +- return WL_DRM_FORMAT_RGB565; +- case 24: +- return WL_DRM_FORMAT_XRGB8888; +- case 30: +- return WL_DRM_FORMAT_ARGB2101010; +- default: +- ErrorF("unexpected depth: %d\n", depth); +- case 32: +- return WL_DRM_FORMAT_ARGB8888; +- } +-} +- + static char + is_device_path_render_node (const char *device_path) + { +@@ -214,7 +195,7 @@ xwl_glamor_gbm_create_pixmap(ScreenPtr screen, + uint32_t num_modifiers; + uint64_t *modifiers = NULL; + +- glamor_get_modifiers(screen, format, &num_modifiers, &modifiers); ++ xwl_glamor_get_modifiers(screen, format, &num_modifiers, &modifiers); + bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height, + format, modifiers, num_modifiers); + free(modifiers); +@@ -277,8 +258,6 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + unsigned short width = pixmap->drawable.width; + unsigned short height = pixmap->drawable.height; + uint32_t format; +- struct xwl_format *xwl_format = NULL; +- Bool modifier_supported = FALSE; + int prime_fd; + int num_planes; + uint32_t strides[4]; +@@ -317,23 +296,8 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + offsets[0] = 0; + #endif + +- for (i = 0; i < xwl_screen->num_formats; i++) { +- if (xwl_screen->formats[i].format == format) { +- xwl_format = &xwl_screen->formats[i]; +- break; +- } +- } +- +- if (xwl_format) { +- for (i = 0; i < xwl_format->num_modifiers; i++) { +- if (xwl_format->modifiers[i] == modifier) { +- modifier_supported = TRUE; +- break; +- } +- } +- } +- +- if (xwl_screen->dmabuf && modifier_supported) { ++ if (xwl_screen->dmabuf && ++ 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); +@@ -592,83 +556,14 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, + return -1; + } + +-_X_EXPORT Bool +-glamor_get_formats(ScreenPtr screen, +- CARD32 *num_formats, CARD32 **formats) +-{ +- struct xwl_screen *xwl_screen = xwl_screen_get(screen); +- struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); +- int i; +- +- /* Explicitly zero the count as the caller may ignore the return value */ +- *num_formats = 0; +- +- if (!xwl_gbm->dmabuf_capable || !xwl_screen->dmabuf) +- return FALSE; +- +- if (xwl_screen->num_formats == 0) +- return TRUE; +- +- *formats = calloc(xwl_screen->num_formats, sizeof(CARD32)); +- if (*formats == NULL) +- return FALSE; +- +- for (i = 0; i < xwl_screen->num_formats; i++) +- (*formats)[i] = xwl_screen->formats[i].format; +- *num_formats = xwl_screen->num_formats; +- +- return TRUE; +-} +- +-_X_EXPORT Bool +-glamor_get_modifiers(ScreenPtr screen, uint32_t format, +- uint32_t *num_modifiers, uint64_t **modifiers) +-{ +- struct xwl_screen *xwl_screen = xwl_screen_get(screen); +- struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); +- struct xwl_format *xwl_format = NULL; +- int i; +- +- /* Explicitly zero the count as the caller may ignore the return value */ +- *num_modifiers = 0; +- +- if (!xwl_gbm->dmabuf_capable || !xwl_screen->dmabuf) +- return FALSE; +- +- if (xwl_screen->num_formats == 0) +- return TRUE; +- +- for (i = 0; i < xwl_screen->num_formats; i++) { +- if (xwl_screen->formats[i].format == format) { +- xwl_format = &xwl_screen->formats[i]; +- break; +- } +- } +- +- if (!xwl_format || +- (xwl_format->num_modifiers == 1 && +- xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID)) +- return FALSE; +- +- *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t)); +- if (*modifiers == NULL) +- return FALSE; +- +- for (i = 0; i < xwl_format->num_modifiers; i++) +- (*modifiers)[i] = xwl_format->modifiers[i]; +- *num_modifiers = xwl_format->num_modifiers; +- +- return TRUE; +-} +- + static const dri3_screen_info_rec xwl_dri3_info = { + .version = 2, + .open = NULL, + .pixmap_from_fds = glamor_pixmap_from_fds, + .fds_from_pixmap = glamor_fds_from_pixmap, + .open_client = xwl_dri3_open_client, +- .get_formats = glamor_get_formats, +- .get_modifiers = glamor_get_modifiers, ++ .get_formats = xwl_glamor_get_formats, ++ .get_modifiers = xwl_glamor_get_modifiers, + .get_drawable_modifiers = glamor_get_drawable_modifiers, + }; + +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index cce0c911e..d8bf1bd5d 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -79,6 +79,117 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) + xwl_screen->glamor_ctx = glamor_ctx; + } + ++Bool ++xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, ++ uint32_t format, uint64_t modifier) ++{ ++ struct xwl_format *xwl_format = NULL; ++ int i; ++ ++ for (i = 0; i < xwl_screen->num_formats; i++) { ++ if (xwl_screen->formats[i].format == format) { ++ xwl_format = &xwl_screen->formats[i]; ++ break; ++ } ++ } ++ ++ if (xwl_format) { ++ for (i = 0; i < xwl_format->num_modifiers; i++) { ++ if (xwl_format->modifiers[i] == modifier) { ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++uint32_t ++wl_drm_format_for_depth(int depth) ++{ ++ switch (depth) { ++ case 15: ++ return WL_DRM_FORMAT_XRGB1555; ++ case 16: ++ return WL_DRM_FORMAT_RGB565; ++ case 24: ++ return WL_DRM_FORMAT_XRGB8888; ++ case 30: ++ return WL_DRM_FORMAT_ARGB2101010; ++ default: ++ ErrorF("unexpected depth: %d\n", depth); ++ case 32: ++ return WL_DRM_FORMAT_ARGB8888; ++ } ++} ++ ++Bool ++xwl_glamor_get_formats(ScreenPtr screen, ++ CARD32 *num_formats, CARD32 **formats) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ int i; ++ ++ /* Explicitly zero the count as the caller may ignore the return value */ ++ *num_formats = 0; ++ ++ if (!xwl_screen->dmabuf) ++ return FALSE; ++ ++ if (xwl_screen->num_formats == 0) ++ return TRUE; ++ ++ *formats = calloc(xwl_screen->num_formats, sizeof(CARD32)); ++ if (*formats == NULL) ++ return FALSE; ++ ++ for (i = 0; i < xwl_screen->num_formats; i++) ++ (*formats)[i] = xwl_screen->formats[i].format; ++ *num_formats = xwl_screen->num_formats; ++ ++ return TRUE; ++} ++ ++Bool ++xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format, ++ uint32_t *num_modifiers, uint64_t **modifiers) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ struct xwl_format *xwl_format = NULL; ++ int i; ++ ++ /* Explicitly zero the count as the caller may ignore the return value */ ++ *num_modifiers = 0; ++ ++ if (!xwl_screen->dmabuf) ++ return FALSE; ++ ++ if (xwl_screen->num_formats == 0) ++ return TRUE; ++ ++ for (i = 0; i < xwl_screen->num_formats; i++) { ++ if (xwl_screen->formats[i].format == format) { ++ xwl_format = &xwl_screen->formats[i]; ++ break; ++ } ++ } ++ ++ if (!xwl_format || ++ (xwl_format->num_modifiers == 1 && ++ xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID)) ++ return FALSE; ++ ++ *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t)); ++ if (*modifiers == NULL) ++ return FALSE; ++ ++ for (i = 0; i < xwl_format->num_modifiers; i++) ++ (*modifiers)[i] = xwl_format->modifiers[i]; ++ *num_modifiers = xwl_format->num_modifiers; ++ ++ return TRUE; ++} ++ + static void + xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + uint32_t format) +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index e017fce80..1637a0733 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -120,7 +120,13 @@ void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); + Bool xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen); +- ++Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, ++ uint32_t format, uint64_t modifier); ++uint32_t wl_drm_format_for_depth(int depth); ++Bool xwl_glamor_get_formats(ScreenPtr screen, ++ CARD32 *num_formats, CARD32 **formats); ++Bool xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format, ++ uint32_t *num_modifiers, uint64_t **modifiers); + + #ifdef XV + /* glamor Xv Adaptor */ +-- +2.31.1 + diff --git a/SOURCES/0003-xwayland-Add-check_flip-glamor-backend-function.patch b/SOURCES/0003-xwayland-Add-check_flip-glamor-backend-function.patch new file mode 100644 index 0000000..db23ae3 --- /dev/null +++ b/SOURCES/0003-xwayland-Add-check_flip-glamor-backend-function.patch @@ -0,0 +1,112 @@ +From c42d3e8edc85856f95c971d5fbc5d59011c23cdc Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Wed, 3 Mar 2021 11:56:41 +0100 +Subject: [PATCH xserver 03/27] xwayland: Add check_flip() glamor backend + function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is preliminary work for hardware accelerated rendering with the +NVIDIA driver. + +This exposes a new glamor backend function, check_flip, which can be +used to control whether flipping is supported for the given pixmap. + +Reviewed-by: Michel Dänzer +Acked-by: Olivier Fourdan +Signed-off-by: Erik Kurzinger +(cherry picked from commit bc99dd2127f12f1aae55971c09a2792eeaa98444) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 7 +++++++ + hw/xwayland/xwayland-glamor-gbm.c | 1 + + hw/xwayland/xwayland-glamor.c | 11 +++++++++++ + hw/xwayland/xwayland-glamor.h | 6 ++++++ + 4 files changed, 25 insertions(+) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 9b2c2c43f..ccaa59cbe 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -633,6 +633,12 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + pixmap->refcnt++; + } + ++static Bool ++xwl_glamor_eglstream_check_flip(PixmapPtr pixmap) ++{ ++ return FALSE; ++} ++ + static void + xwl_eglstream_display_handle_caps(void *data, + struct wl_eglstream_display *disp, +@@ -942,6 +948,7 @@ xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) + xwl_screen->eglstream_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap; + xwl_screen->eglstream_backend.post_damage = xwl_glamor_eglstream_post_damage; + xwl_screen->eglstream_backend.allow_commits = xwl_glamor_eglstream_allow_commits; ++ xwl_screen->eglstream_backend.check_flip = xwl_glamor_eglstream_check_flip; + xwl_screen->eglstream_backend.is_available = TRUE; + xwl_screen->eglstream_backend.backend_flags = XWL_EGL_BACKEND_NO_FLAG; + } +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 455b755ca..1b1d517da 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -967,6 +967,7 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) + xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl; + xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen; + xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; ++ xwl_screen->gbm_backend.check_flip = NULL; + xwl_screen->gbm_backend.is_available = TRUE; + xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_HAS_PRESENT_FLIP | + XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index d8bf1bd5d..060471f01 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -79,6 +79,17 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) + xwl_screen->glamor_ctx = glamor_ctx; + } + ++Bool ++xwl_glamor_check_flip(PixmapPtr pixmap) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); ++ ++ if (xwl_screen->egl_backend->check_flip) ++ return xwl_screen->egl_backend->check_flip(pixmap); ++ ++ return TRUE; ++} ++ + Bool + xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, + uint32_t format, uint64_t modifier) +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index 1637a0733..a86b30b40 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -92,6 +92,11 @@ struct xwl_egl_backend { + * callback is optional. + */ + Bool (*allow_commits)(struct xwl_window *xwl_window); ++ ++ /* Called by Xwayland to check whether the given pixmap can be ++ * presented by xwl_present_flip. If not implemented, assumed TRUE. ++ */ ++ Bool (*check_flip)(PixmapPtr pixmap); + }; + + #ifdef XWL_HAS_GLAMOR +@@ -127,6 +132,7 @@ Bool xwl_glamor_get_formats(ScreenPtr screen, + CARD32 *num_formats, CARD32 **formats); + Bool xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format, + uint32_t *num_modifiers, uint64_t **modifiers); ++Bool xwl_glamor_check_flip(PixmapPtr pixmap); + + #ifdef XV + /* glamor Xv Adaptor */ +-- +2.31.1 + diff --git a/SOURCES/0004-xwayland-implement-pixmap_from_buffers-for-the-eglst.patch b/SOURCES/0004-xwayland-implement-pixmap_from_buffers-for-the-eglst.patch new file mode 100644 index 0000000..21d56c8 --- /dev/null +++ b/SOURCES/0004-xwayland-implement-pixmap_from_buffers-for-the-eglst.patch @@ -0,0 +1,425 @@ +From 6d1529b8d6b3e7c8bf758b670e2122a6af4d5346 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Thu, 3 Dec 2020 14:57:51 -0800 +Subject: [PATCH xserver 04/27] xwayland: implement pixmap_from_buffers for the + eglstream backend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Provides an implementation for the pixmap_from_buffers DRI3 function for +xwayland's eglstream backend. This will be used by the NVIDIA GLX driver +to pass buffers from client applications to the server. These can then +be presented using the PRESENT extension. + +To hopefully make this less error-prone, we also introduce a "type" +field for this struct to distinguish between xwl_pixmaps for the new +DRI3-created pixmaps and those for the existing glamor-created pixmaps. + +Additionally, the patch enables wnmd present mode with the eglstream backend. +This involves creating a wl_buffer for the provided dma-buf before importing it +into EGL and passing this to the compositor so it can be scanned out directly +if possible. + +Since both backends now support this present mode, the HAS_PRESENT_FLIP flag is +no longer needed, so it can be removed. + +Reviewed-by: Michel Dänzer +Acked-by: Olivier Fourdan +Signed-off-by: Erik Kurzinger +(cherry picked from commit 38e875904b039ec1889e7c81eb1d577a4f69b26d) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 202 +++++++++++++++++++++++- + hw/xwayland/xwayland-glamor-gbm.c | 3 +- + hw/xwayland/xwayland-glamor.c | 12 -- + hw/xwayland/xwayland-glamor.h | 6 +- + hw/xwayland/xwayland-present.c | 5 +- + 5 files changed, 204 insertions(+), 24 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index ccaa59cbe..2d8380e1f 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -37,6 +37,8 @@ + #include + + #include ++#include ++#include + + #include + +@@ -47,6 +49,7 @@ + + #include "wayland-eglstream-client-protocol.h" + #include "wayland-eglstream-controller-client-protocol.h" ++#include "linux-dmabuf-unstable-v1-client-protocol.h" + + struct xwl_eglstream_pending_stream { + PixmapPtr pixmap; +@@ -80,12 +83,23 @@ struct xwl_eglstream_private { + GLuint blit_is_rgba_pos; + }; + ++enum xwl_pixmap_type { ++ XWL_PIXMAP_EGLSTREAM, /* Pixmaps created by glamor. */ ++ XWL_PIXMAP_DMA_BUF, /* Pixmaps allocated through DRI3. */ ++}; ++ + struct xwl_pixmap { +- struct wl_buffer *buffer; ++ enum xwl_pixmap_type type; ++ /* add any new <= 4-byte member here to avoid holes on 64-bit */ + struct xwl_screen *xwl_screen; ++ struct wl_buffer *buffer; + ++ /* XWL_PIXMAP_EGLSTREAM. */ + EGLStreamKHR stream; + EGLSurface surface; ++ ++ /* XWL_PIXMAP_DMA_BUF. */ ++ EGLImage image; + }; + + static DevPrivateKeyRec xwl_eglstream_private_key; +@@ -289,12 +303,18 @@ xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap) + xwl_screen->egl_context); + } + +- if (xwl_pixmap->surface) ++ if (xwl_pixmap->surface != EGL_NO_SURFACE) + eglDestroySurface(xwl_screen->egl_display, xwl_pixmap->surface); + +- eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream); ++ if (xwl_pixmap->stream != EGL_NO_STREAM_KHR) ++ eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream); ++ ++ if (xwl_pixmap->buffer) ++ wl_buffer_destroy(xwl_pixmap->buffer); ++ ++ if (xwl_pixmap->image != EGL_NO_IMAGE_KHR) ++ eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); + +- wl_buffer_destroy(xwl_pixmap->buffer); + free(xwl_pixmap); + } + +@@ -509,9 +529,13 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, + FatalError("Not enough memory to create pixmap\n"); + xwl_pixmap_set_private(pixmap, xwl_pixmap); + ++ xwl_pixmap->type = XWL_PIXMAP_EGLSTREAM; ++ xwl_pixmap->image = EGL_NO_IMAGE; ++ + xwl_glamor_egl_make_current(xwl_screen); + + xwl_pixmap->xwl_screen = xwl_screen; ++ xwl_pixmap->surface = EGL_NO_SURFACE; + xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL); + stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display, + xwl_pixmap->stream); +@@ -552,6 +576,7 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap) { ++ assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM); + if (pending) { + /* Wait for the compositor to finish connecting the consumer for + * this eglstream */ +@@ -590,6 +615,8 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + }; + GLint saved_vao; + ++ assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM); ++ + /* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we + * won't actually draw to it + */ +@@ -636,7 +663,7 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + static Bool + xwl_glamor_eglstream_check_flip(PixmapPtr pixmap) + { +- return FALSE; ++ return xwl_pixmap_get(pixmap)->type == XWL_PIXMAP_DMA_BUF; + } + + static void +@@ -681,6 +708,9 @@ xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen, + xwl_eglstream->controller = wl_registry_bind( + wl_registry, id, &wl_eglstream_controller_interface, version); + return TRUE; ++ } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) { ++ xwl_screen_set_dmabuf_interface(xwl_screen, id, version); ++ return TRUE; + } + + /* no match */ +@@ -779,6 +809,163 @@ xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen) + glGetUniformLocation(xwl_eglstream->blit_prog, "is_rgba"); + } + ++static int ++xwl_dri3_open_client(ClientPtr client, ++ ScreenPtr screen, ++ RRProviderPtr provider, ++ int *pfd) ++{ ++ /* Not supported with this backend. */ ++ return BadImplementation; ++} ++ ++static PixmapPtr ++xwl_dri3_pixmap_from_fds(ScreenPtr screen, ++ CARD8 num_fds, const int *fds, ++ CARD16 width, CARD16 height, ++ const CARD32 *strides, const CARD32 *offsets, ++ CARD8 depth, CARD8 bpp, ++ uint64_t modifier) ++{ ++ PixmapPtr pixmap; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ struct xwl_pixmap *xwl_pixmap; ++ unsigned int texture; ++ EGLint image_attribs[48]; ++ uint32_t mod_hi = modifier >> 32, mod_lo = modifier & 0xffffffff, format; ++ int attrib = 0, i; ++ struct zwp_linux_buffer_params_v1 *params; ++ ++ format = wl_drm_format_for_depth(depth); ++ if (!xwl_glamor_is_modifier_supported(xwl_screen, format, modifier)) { ++ ErrorF("glamor: unsupported format modifier\n"); ++ return NULL; ++ } ++ ++ xwl_pixmap = calloc(1, sizeof (*xwl_pixmap)); ++ if (!xwl_pixmap) ++ return NULL; ++ xwl_pixmap->type = XWL_PIXMAP_DMA_BUF; ++ xwl_pixmap->xwl_screen = xwl_screen; ++ ++ xwl_pixmap->buffer = NULL; ++ xwl_pixmap->stream = EGL_NO_STREAM_KHR; ++ xwl_pixmap->surface = EGL_NO_SURFACE; ++ ++ params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf); ++ for (i = 0; i < num_fds; i++) { ++ zwp_linux_buffer_params_v1_add(params, fds[i], i, ++ offsets[i], strides[i], ++ mod_hi, mod_lo); ++ } ++ xwl_pixmap->buffer = ++ zwp_linux_buffer_params_v1_create_immed(params, width, height, ++ format, 0); ++ zwp_linux_buffer_params_v1_destroy(params); ++ ++ ++ image_attribs[attrib++] = EGL_WIDTH; ++ image_attribs[attrib++] = width; ++ image_attribs[attrib++] = EGL_HEIGHT; ++ image_attribs[attrib++] = height; ++ image_attribs[attrib++] = EGL_LINUX_DRM_FOURCC_EXT; ++ image_attribs[attrib++] = drm_format_for_depth(depth, bpp); ++ ++ if (num_fds > 0) { ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_FD_EXT; ++ image_attribs[attrib++] = fds[0]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; ++ image_attribs[attrib++] = offsets[0]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; ++ image_attribs[attrib++] = strides[0]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; ++ image_attribs[attrib++] = mod_hi; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; ++ image_attribs[attrib++] = mod_lo; ++ } ++ if (num_fds > 1) { ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_FD_EXT; ++ image_attribs[attrib++] = fds[1]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; ++ image_attribs[attrib++] = offsets[1]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; ++ image_attribs[attrib++] = strides[1]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; ++ image_attribs[attrib++] = mod_hi; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; ++ image_attribs[attrib++] = mod_lo; ++ } ++ if (num_fds > 2) { ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_FD_EXT; ++ image_attribs[attrib++] = fds[2]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; ++ image_attribs[attrib++] = offsets[2]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; ++ image_attribs[attrib++] = strides[2]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; ++ image_attribs[attrib++] = mod_hi; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT; ++ image_attribs[attrib++] = mod_lo; ++ } ++ if (num_fds > 3) { ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_FD_EXT; ++ image_attribs[attrib++] = fds[3]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT; ++ image_attribs[attrib++] = offsets[3]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_PITCH_EXT; ++ image_attribs[attrib++] = strides[3]; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT; ++ image_attribs[attrib++] = mod_hi; ++ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT; ++ image_attribs[attrib++] = mod_lo; ++ } ++ image_attribs[attrib++] = EGL_NONE; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ ++ /* eglCreateImageKHR will close fds */ ++ xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display, ++ EGL_NO_CONTEXT, ++ EGL_LINUX_DMA_BUF_EXT, ++ NULL, image_attribs); ++ if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) { ++ ErrorF("eglCreateImageKHR failed!\n"); ++ if (xwl_pixmap->buffer) ++ wl_buffer_destroy(xwl_pixmap->buffer); ++ free(xwl_pixmap); ++ return NULL; ++ } ++ ++ 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, xwl_pixmap->image); ++ glBindTexture(GL_TEXTURE_2D, 0); ++ ++ pixmap = glamor_create_pixmap(screen, width, height, depth, ++ GLAMOR_CREATE_PIXMAP_NO_TEXTURE); ++ glamor_set_pixmap_texture(pixmap, texture); ++ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); ++ wl_buffer_add_listener(xwl_pixmap->buffer, ++ &xwl_eglstream_buffer_release_listener, ++ pixmap); ++ xwl_pixmap_set_private(pixmap, xwl_pixmap); ++ ++ return pixmap; ++} ++ ++static const dri3_screen_info_rec xwl_dri3_info = { ++ .version = 2, ++ .open = NULL, ++ .pixmap_from_fds = xwl_dri3_pixmap_from_fds, ++ .fds_from_pixmap = NULL, ++ .open_client = xwl_dri3_open_client, ++ .get_formats = xwl_glamor_get_formats, ++ .get_modifiers = xwl_glamor_get_modifiers, ++ .get_drawable_modifiers = glamor_get_drawable_modifiers, ++}; ++ + static Bool + xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) + { +@@ -858,6 +1045,11 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) + + xwl_eglstream_init_shaders(xwl_screen); + ++ if (epoxy_has_gl_extension("GL_OES_EGL_image") && ++ !dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) { ++ ErrorF("DRI3 initialization failed. Performance will be affected.\n"); ++ } ++ + return TRUE; + error: + xwl_eglstream_cleanup(xwl_screen); +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 1b1d517da..12d820e44 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -969,7 +969,6 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) + xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; + xwl_screen->gbm_backend.check_flip = NULL; + xwl_screen->gbm_backend.is_available = TRUE; +- xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_HAS_PRESENT_FLIP | +- XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | ++ xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | + XWL_EGL_BACKEND_NEEDS_N_BUFFERING; + } +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index 060471f01..9e44d5106 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -362,16 +362,6 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen, + return 0; + } + +-Bool +-xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen) +-{ +- if (!xwl_screen->glamor || !xwl_screen->egl_backend) +- return FALSE; +- +- return (xwl_screen->egl_backend->backend_flags & +- XWL_EGL_BACKEND_HAS_PRESENT_FLIP); +-} +- + Bool + xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen) + { +@@ -430,8 +420,6 @@ xwl_glamor_select_eglstream_backend(struct xwl_screen *xwl_screen) + #ifdef XWL_HAS_EGLSTREAM + if (xwl_screen->eglstream_backend.is_available && + xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->eglstream_backend)) { +- ErrorF("glamor: Using nvidia's EGLStream interface, direct rendering impossible.\n"); +- ErrorF("glamor: Performance may be affected. Ask your vendor to support GBM!\n"); + xwl_screen->egl_backend = &xwl_screen->eglstream_backend; + return TRUE; + } +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index a86b30b40..26ab78f04 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -34,9 +34,8 @@ + + typedef enum _xwl_egl_backend_flags { + XWL_EGL_BACKEND_NO_FLAG = 0, +- XWL_EGL_BACKEND_HAS_PRESENT_FLIP = (1 << 0), +- XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 1), +- XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 2), ++ XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 0), ++ XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 1), + } xwl_egl_backend_flags; + + struct xwl_egl_backend { +@@ -122,7 +121,6 @@ void xwl_glamor_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region); + Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window); + void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); +-Bool xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen); + Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +index 666ea15e7..7ba7efc11 100644 +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -404,6 +404,9 @@ xwl_present_check_flip2(RRCrtcPtr crtc, + if (!xwl_window) + return FALSE; + ++ if (!xwl_glamor_check_flip(pixmap)) ++ return FALSE; ++ + /* Can't flip if the window pixmap doesn't match the xwl_window parent + * window's, e.g. because a client redirected this window or one of its + * parents. +@@ -540,7 +543,7 @@ xwl_present_init(ScreenPtr screen) + { + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + +- if (!xwl_glamor_has_present_flip(xwl_screen)) ++ if (!xwl_screen->glamor || !xwl_screen->egl_backend) + return FALSE; + + if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0)) +-- +2.31.1 + diff --git a/SOURCES/0005-xwayland-eglstream-fix-X11-rendering-to-flipping-GL-.patch b/SOURCES/0005-xwayland-eglstream-fix-X11-rendering-to-flipping-GL-.patch new file mode 100644 index 0000000..8c4640e --- /dev/null +++ b/SOURCES/0005-xwayland-eglstream-fix-X11-rendering-to-flipping-GL-.patch @@ -0,0 +1,61 @@ +From 43d1648dc71d01628a6a65a62364c1a3994a88a8 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 27 Apr 2021 07:23:44 -0400 +Subject: [PATCH xserver 05/27] xwayland-eglstream: fix X11 rendering to + flipping GL / VK window +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a window is being used for direct rendering with OpenGL or Vulkan, and is +using the flipping path for presentation, it's pixmap will be set to a dma-buf +backed pixmap created by the client-side GL driver. However, this means that +xwl_glamor_eglstream_post_damage won't work since it requires that the pixmap +has an EGLSurface that it can render to, which dma-buf backed pixmaps do not. + +In this case, though, xwl_glamor_eglstream_post_damage is not necessary since +glamor will have rendered directly to the pixmap, so we can simply pass it +directly to the compositor. There's no need for the intermediate copy we +normally do in that function. + +Therefore, this change adds an early-return case to post_damage for dma-buf +backed pixmaps, and removes the corresponding asserts from that function and +allow_commits. + +Signed-off-by: Erik Kurzinger +Acked-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit 4f6fbd5009ae533cf0b3bbe382502254f9276a01) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 2d8380e1f..17295f3bd 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -576,7 +576,6 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap) { +- assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM); + if (pending) { + /* Wait for the compositor to finish connecting the consumer for + * this eglstream */ +@@ -615,7 +614,12 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + }; + GLint saved_vao; + +- assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM); ++ if (xwl_pixmap->type != XWL_PIXMAP_EGLSTREAM) ++ /* This can happen if a client does X11 rendering on a ++ * flipping OpenGL or Vulkan window. In that case, we don't ++ * need to do the copy below. ++ */ ++ return; + + /* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we + * won't actually draw to it +-- +2.31.1 + diff --git a/SOURCES/0006-xwayland-eglstream-Check-buffer-creation.patch b/SOURCES/0006-xwayland-eglstream-Check-buffer-creation.patch new file mode 100644 index 0000000..5a35fee --- /dev/null +++ b/SOURCES/0006-xwayland-eglstream-Check-buffer-creation.patch @@ -0,0 +1,53 @@ +From 95224f0f92bc516983038a6326fba041cdef6e75 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 29 Mar 2021 14:22:56 +0200 +Subject: [PATCH xserver 06/27] xwayland/eglstream: Check buffer creation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +EGLStream wl_eglstream_display_create_stream() may fail, yet Xwayland +would try to attach the buffer which may cause a fatal Wayland protocol +error raised by the compositor. + +Check if the buffer creation worked, and fail gracefully otherwise (like +wayland-eglsurface does). + +Signed-off-by: Olivier Fourdan +Reviewed-by: Martin Peres +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 4f0889e98306d30a37aba0fadb1fd3790c13205a) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 17295f3bd..c6e17bf8b 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -548,6 +548,10 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, + stream_fd, + WL_EGLSTREAM_HANDLE_TYPE_FD, + &stream_attribs); ++ if (!xwl_pixmap->buffer) { ++ ErrorF("eglstream: Failed to create buffer\n"); ++ goto fail; ++ } + + wl_buffer_add_listener(xwl_pixmap->buffer, + &xwl_eglstream_buffer_release_listener, +@@ -562,7 +566,9 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, + + xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap); + +- close(stream_fd); ++fail: ++ if (stream_fd >= 0) ++ close(stream_fd); + } + + static Bool +-- +2.31.1 + diff --git a/SOURCES/0007-xwayland-Check-buffer-prior-to-attaching-it.patch b/SOURCES/0007-xwayland-Check-buffer-prior-to-attaching-it.patch new file mode 100644 index 0000000..c194704 --- /dev/null +++ b/SOURCES/0007-xwayland-Check-buffer-prior-to-attaching-it.patch @@ -0,0 +1,88 @@ +From 8a07b3e391bbed0b7d8f2ed37928b362eec3beee Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 29 Mar 2021 15:01:15 +0200 +Subject: [PATCH xserver 07/27] xwayland: Check buffer prior to attaching it +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the buffer is NULL, do not even try to attach it, and risk a Wayland +protocol error which would be fatal to us. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Martin Peres +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 25d2f4948f0abd39e099b8ac69b7cb1dab38a10a) +--- + hw/xwayland/xwayland-cursor.c | 11 +++++++++-- + hw/xwayland/xwayland-present.c | 7 ++++++- + hw/xwayland/xwayland-window.c | 5 +++++ + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c +index fac8840e6..c4457cc2a 100644 +--- a/hw/xwayland/xwayland-cursor.c ++++ b/hw/xwayland/xwayland-cursor.c +@@ -162,8 +162,15 @@ static void + xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat, + struct xwl_cursor *xwl_cursor, PixmapPtr pixmap) + { +- wl_surface_attach(xwl_cursor->surface, +- xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); ++ struct wl_buffer *buffer; ++ ++ buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); ++ if (!buffer) { ++ ErrorF("cursor: Error getting buffer\n"); ++ return; ++ } ++ ++ wl_surface_attach(xwl_cursor->surface, buffer, 0, 0); + xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0, + xwl_seat->x_cursor->bits->width, + xwl_seat->x_cursor->bits->height); +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +index 7ba7efc11..83d67517a 100644 +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -443,6 +443,12 @@ xwl_present_flip(WindowPtr present_window, + if (!xwl_window) + return FALSE; + ++ buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap); ++ if (!buffer) { ++ ErrorF("present: Error getting buffer\n"); ++ return FALSE; ++ } ++ + damage_box = RegionExtents(damage); + + event = malloc(sizeof *event); +@@ -450,7 +456,6 @@ xwl_present_flip(WindowPtr present_window, + return FALSE; + + pixmap->refcnt++; +- buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap); + + event->event_id = event_id; + event->xwl_present_window = xwl_present_window; +diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c +index d0c7c581d..af4290ec7 100644 +--- a/hw/xwayland/xwayland-window.c ++++ b/hw/xwayland/xwayland-window.c +@@ -805,6 +805,11 @@ xwl_window_post_damage(struct xwl_window *xwl_window) + #endif + buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); + ++ if (!buffer) { ++ ErrorF("Error getting buffer\n"); ++ return; ++ } ++ + #ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + xwl_glamor_post_damage(xwl_window, pixmap, region); +-- +2.31.1 + diff --git a/SOURCES/0008-glamor-Dump-backtrace-on-GL-error.patch b/SOURCES/0008-glamor-Dump-backtrace-on-GL-error.patch new file mode 100644 index 0000000..928654d --- /dev/null +++ b/SOURCES/0008-glamor-Dump-backtrace-on-GL-error.patch @@ -0,0 +1,38 @@ +From 85638273f23338d06776cdb7bb422440f690038a Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 30 Mar 2021 08:48:25 +0200 +Subject: [PATCH xserver 08/27] glamor: Dump backtrace on GL error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currrently, when a GL error is triggered, glamor would log the error +which may not be sufficient to trace it back to the cause of the error. + +Also dump the backtrace which may give more information as to where the +error comes from. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Martin Peres +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 3b265c59a6456f6e4abfb9e1694237bc56f1776a) +--- + glamor/glamor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/glamor/glamor.c b/glamor/glamor.c +index 3baef4b9f..b8406f42d 100644 +--- a/glamor/glamor.c ++++ b/glamor/glamor.c +@@ -414,6 +414,7 @@ glamor_debug_output_callback(GLenum source, + + LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n", + screen->myNum, length, message); ++ xorg_backtrace(); + } + + /** +-- +2.31.1 + diff --git a/SOURCES/0009-xwayland-glamor-Add-return-status-to-post_damage.patch b/SOURCES/0009-xwayland-glamor-Add-return-status-to-post_damage.patch new file mode 100644 index 0000000..5c371c6 --- /dev/null +++ b/SOURCES/0009-xwayland-glamor-Add-return-status-to-post_damage.patch @@ -0,0 +1,125 @@ +From c28bb0e879775aec83f5554522724eee592685dc Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Wed, 31 Mar 2021 13:57:45 +0200 +Subject: [PATCH xserver 09/27] xwayland/glamor: Add return status to + post_damage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the glamor backend failed to post damage, the caller should do the +same to avoid a failure to attach the buffer to the Wayland surface. + +Change the API of Xwayland's glamor backend post_damage() to return a +status so that xwl_window_post_damage() can tell whether the callee +failed. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 252cbad316f43edc08aa5c844789398a58ba270c) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 6 ++++-- + hw/xwayland/xwayland-glamor.c | 6 ++++-- + hw/xwayland/xwayland-glamor.h | 4 ++-- + hw/xwayland/xwayland-window.c | 8 ++++++-- + 4 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index c6e17bf8b..f64d05064 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -605,7 +605,7 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + return FALSE; + } + +-static void ++static Bool + xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region) + { +@@ -625,7 +625,7 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + * flipping OpenGL or Vulkan window. In that case, we don't + * need to do the copy below. + */ +- return; ++ return TRUE; + + /* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we + * won't actually draw to it +@@ -668,6 +668,8 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + + /* hang onto the pixmap until the compositor has released it */ + pixmap->refcnt++; ++ ++ return TRUE; + } + + static Bool +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index 9e44d5106..e940f9fd7 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -304,14 +304,16 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) + return NULL; + } + +-void ++Bool + xwl_glamor_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region) + { + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + + if (xwl_screen->egl_backend->post_damage) +- xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region); ++ return xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region); ++ ++ return TRUE; + } + + Bool +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index 26ab78f04..cf3c4fba3 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -83,7 +83,7 @@ struct xwl_egl_backend { + * you should implement blitting from the glamor pixmap to the wayland + * pixmap here. Otherwise, this callback is optional. + */ +- void (*post_damage)(struct xwl_window *xwl_window, ++ Bool (*post_damage)(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region); + + /* Called by Xwayland to confirm with the egl backend that the given +@@ -117,7 +117,7 @@ void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, + uint32_t version); + Bool xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen, + struct xwl_egl_backend *xwl_egl_backend); +-void xwl_glamor_post_damage(struct xwl_window *xwl_window, ++Bool xwl_glamor_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region); + Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window); + void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); +diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c +index af4290ec7..00f161eda 100644 +--- a/hw/xwayland/xwayland-window.c ++++ b/hw/xwayland/xwayland-window.c +@@ -811,8 +811,12 @@ xwl_window_post_damage(struct xwl_window *xwl_window) + } + + #ifdef XWL_HAS_GLAMOR +- if (xwl_screen->glamor) +- xwl_glamor_post_damage(xwl_window, pixmap, region); ++ if (xwl_screen->glamor) { ++ if (!xwl_glamor_post_damage(xwl_window, pixmap, region)) { ++ ErrorF("glamor: Failed to post damage\n"); ++ return; ++ } ++ } + #endif + + wl_surface_attach(xwl_window->surface, buffer, 0, 0); +-- +2.31.1 + diff --git a/SOURCES/0010-xwayland-eglstream-Check-framebuffer-status.patch b/SOURCES/0010-xwayland-eglstream-Check-framebuffer-status.patch new file mode 100644 index 0000000..09c0a46 --- /dev/null +++ b/SOURCES/0010-xwayland-eglstream-Check-framebuffer-status.patch @@ -0,0 +1,74 @@ +From 070abe64b15db831802a842aa1965403eb24679e Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Wed, 31 Mar 2021 09:49:35 +0200 +Subject: [PATCH xserver 10/27] xwayland/eglstream: Check framebuffer status +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The EGLStream backend would sometime generate GL errors trying to draw +to the framebuffer, which gives an invalid buffer, which in turn would +generate a Wayland error from the compositor which is fatal to the +client. + +Check the framebuffer status and bail out early if it's not complete, +to avoid getting into trouble later. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 85244d2a2081d61a2e4a06e847041f638de01e3f) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index f64d05064..64fe93b7c 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -619,6 +619,7 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + box->x2 - box->x1, box->y2 - box->y1 + }; + GLint saved_vao; ++ int status; + + if (xwl_pixmap->type != XWL_PIXMAP_EGLSTREAM) + /* This can happen if a client does X11 rendering on a +@@ -652,6 +653,13 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + glUniform1i(xwl_eglstream->blit_is_rgba_pos, + pixmap->drawable.depth >= 32); + ++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER); ++ if (status != GL_FRAMEBUFFER_COMPLETE) { ++ ErrorF("eglstream: Framebuffer incomplete 0x%X, not posting damage\n", status); ++ status = FALSE; ++ goto out; ++ } ++ + /* Blit rendered image into EGLStream surface */ + glDrawBuffer(GL_BACK); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +@@ -662,14 +670,16 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + else + eglSwapBuffers(xwl_screen->egl_display, xwl_pixmap->surface); + ++ /* hang onto the pixmap until the compositor has released it */ ++ pixmap->refcnt++; ++ status = TRUE; ++ ++out: + /* Restore previous state */ + glBindVertexArray(saved_vao); + glBindTexture(GL_TEXTURE_2D, 0); + +- /* hang onto the pixmap until the compositor has released it */ +- pixmap->refcnt++; +- +- return TRUE; ++ return status; + } + + static Bool +-- +2.31.1 + diff --git a/SOURCES/0011-xwayland-eglstream-Small-refactoring.patch b/SOURCES/0011-xwayland-eglstream-Small-refactoring.patch new file mode 100644 index 0000000..20c7f3a --- /dev/null +++ b/SOURCES/0011-xwayland-eglstream-Small-refactoring.patch @@ -0,0 +1,138 @@ +From 9966356963803db35997f26330fb1245777012a1 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Thu, 15 Apr 2021 10:59:36 +0200 +Subject: [PATCH xserver 11/27] xwayland/eglstream: Small refactoring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some functions are called "callback" whereas they are not longer +callback functions or "unref" while they no longer deal with a reference +counter anymore, which is quite confusing. Rename those functions to be +more explicit. + +Also, the pending streams can be destroyed in different places, move the +common code to separate function to avoid duplicating code and help with +readability of the code. + +Signed-off-by: Olivier Fourdan +Acked-by: Michel Dänzer +(cherry picked from commit 823f3254fabd16e5e721da57cd260beac9b8f8bd) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 42 ++++++++++++++----------- + 1 file changed, 24 insertions(+), 18 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 64fe93b7c..9abb7b779 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -287,7 +287,7 @@ xwl_glamor_egl_device_has_egl_extensions(void *device, + } + + static void +-xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap) ++xwl_eglstream_destroy_pixmap_stream(struct xwl_pixmap *xwl_pixmap) + { + struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; + +@@ -319,7 +319,17 @@ xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap) + } + + static void +-xwl_glamor_eglstream_del_pending_stream_cb(struct xwl_pixmap *xwl_pixmap) ++xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream *pending) ++{ ++ if (pending->cb) ++ wl_callback_destroy(pending->cb); ++ xwl_eglstream_window_set_pending(pending->window, NULL); ++ xorg_list_del(&pending->link); ++ free(pending); ++} ++ ++static void ++xwl_glamor_eglstream_remove_pending_stream(struct xwl_pixmap *xwl_pixmap) + { + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_pixmap->xwl_screen); +@@ -328,10 +338,7 @@ xwl_glamor_eglstream_del_pending_stream_cb(struct xwl_pixmap *xwl_pixmap) + xorg_list_for_each_entry(pending, + &xwl_eglstream->pending_streams, link) { + if (pending->xwl_pixmap == xwl_pixmap) { +- wl_callback_destroy(pending->cb); +- xwl_eglstream_window_set_pending(pending->window, NULL); +- xorg_list_del(&pending->link); +- free(pending); ++ xwl_glamor_eglstream_destroy_pending_stream(pending); + break; + } + } +@@ -343,9 +350,9 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap) + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap && pixmap->refcnt == 1) { +- xwl_glamor_eglstream_del_pending_stream_cb(xwl_pixmap); ++ xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); ++ xwl_eglstream_destroy_pixmap_stream(xwl_pixmap); + xwl_pixmap_del_buffer_release_cb(pixmap); +- xwl_eglstream_unref_pixmap_stream(xwl_pixmap); + } + return glamor_destroy_pixmap(pixmap); + } +@@ -432,8 +439,6 @@ xwl_eglstream_consumer_ready_callback(void *data, + struct xwl_eglstream_pending_stream *pending; + Bool found = FALSE; + +- wl_callback_destroy(callback); +- + xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) { + if (pending->cb == callback) { + found = TRUE; +@@ -442,8 +447,11 @@ xwl_eglstream_consumer_ready_callback(void *data, + } + assert(found); + ++ wl_callback_destroy(callback); ++ pending->cb = NULL; ++ + if (!pending->is_valid) { +- xwl_eglstream_unref_pixmap_stream(pending->xwl_pixmap); ++ xwl_eglstream_destroy_pixmap_stream(pending->xwl_pixmap); + goto out; + } + +@@ -462,9 +470,7 @@ xwl_eglstream_consumer_ready_callback(void *data, + pending->window->drawable.id, pending->pixmap); + + out: +- xwl_eglstream_window_set_pending(pending->window, NULL); +- xorg_list_del(&pending->link); +- free(pending); ++ xwl_glamor_eglstream_destroy_pending_stream(pending); + } + + static const struct wl_callback_listener consumer_ready_listener = { +@@ -514,8 +520,8 @@ static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = { + }; + + static void +-xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, +- WindowPtr window, PixmapPtr pixmap) ++xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, ++ WindowPtr window, PixmapPtr pixmap) + { + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); +@@ -599,8 +605,8 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + /* Glamor pixmap has no backing stream yet; begin making one and disallow + * commits until then + */ +- xwl_eglstream_create_pending_stream(xwl_screen, xwl_window->window, +- pixmap); ++ xwl_eglstream_create_pixmap_and_stream(xwl_screen, xwl_window->window, ++ pixmap); + + return FALSE; + } +-- +2.31.1 + diff --git a/SOURCES/0012-xwayland-eglstream-Add-more-error-checking.patch b/SOURCES/0012-xwayland-eglstream-Add-more-error-checking.patch new file mode 100644 index 0000000..12535e9 --- /dev/null +++ b/SOURCES/0012-xwayland-eglstream-Add-more-error-checking.patch @@ -0,0 +1,150 @@ +From e8f7568016249822bb95c87447ded6abb724c13b Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Thu, 1 Apr 2021 08:46:52 +0200 +Subject: [PATCH xserver 12/27] xwayland/eglstream: Add more error checking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +eglCreateStreamKHR() can fail and return EGL_NO_STREAM_KHR, in which +case there is no point in trying to create a buffer from it. + +Similarly, eglCreateStreamProducerSurfaceKHR() also fail and return +EGL_NO_SURFACE, which in turn will be used in eglMakeCurrent() as +draw/read surface, and therefore would mean no draw/read buffer. + +In those cases, log the error, and bail out early. That won't solve the +issue but will help with investigating the root cause of issues with +EGLStream backend. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit cc596bcfb273eeab82ac3d59867668af8bad2abf) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 93 +++++++++++++++++++++++++ + 1 file changed, 93 insertions(+) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 9abb7b779..77b24a4b4 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -387,6 +387,84 @@ xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) + xwl_screen->screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap; + } + ++static const char * ++xwl_eglstream_get_error_str(EGLint error) ++{ ++ switch (error) { ++ case EGL_BAD_PARAMETER: ++ return "EGL_BAD_PARAMETER"; ++ case EGL_BAD_ATTRIBUTE: ++ return "EGL_BAD_ATTRIBUTE"; ++ case EGL_BAD_MATCH: ++ return "EGL_BAD_MATCH"; ++ case EGL_BAD_ACCESS: ++ return "EGL_BAD_ACCESS"; ++ case EGL_BAD_STATE_KHR: ++ return "EGL_BAD_STATE_KHR"; ++ case EGL_BAD_STREAM_KHR: ++ return "EGL_BAD_STREAM_KHR"; ++ case EGL_BAD_DISPLAY: ++ return "EGL_BAD_DISPLAY"; ++ case EGL_NOT_INITIALIZED: ++ return "EGL_NOT_INITIALIZED"; ++ default: ++ return "Unknown error"; ++ } ++} ++ ++static const char * ++xwl_eglstream_get_stream_state_str(EGLint state) ++{ ++ switch (state) { ++ case EGL_STREAM_STATE_CREATED_KHR: ++ return "EGL_STREAM_STATE_CREATED_KHR"; ++ case EGL_STREAM_STATE_CONNECTING_KHR: ++ return "EGL_STREAM_STATE_CONNECTING_KHR"; ++ case EGL_STREAM_STATE_EMPTY_KHR: ++ return "EGL_STREAM_STATE_EMPTY_KHR"; ++ case EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR: ++ return "EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR"; ++ case EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR: ++ return "EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR"; ++ case EGL_STREAM_STATE_DISCONNECTED_KHR: ++ return "EGL_STREAM_STATE_DISCONNECTED_KHR"; ++ default: ++ return "Unknown state"; ++ } ++} ++ ++static EGLint ++xwl_eglstream_get_state(EGLDisplay egl_display, EGLStreamKHR egl_stream) ++{ ++ EGLint state; ++ ++ eglQueryStreamKHR(egl_display, egl_stream, EGL_STREAM_STATE_KHR, &state); ++ if (!eglQueryStreamKHR(egl_display, egl_stream, ++ EGL_STREAM_STATE_KHR, &state)) { ++ EGLint state_error = eglGetError(); ++ ErrorF("eglstream: Failed to query state - error 0x%X: %s\n", ++ state_error, xwl_eglstream_get_error_str(state_error)); ++ return EGL_FALSE; ++ } ++ ++ return state; ++} ++ ++ ++static void ++xwl_eglstream_print_error(EGLDisplay egl_display, ++ EGLStreamKHR egl_stream, EGLint error) ++{ ++ ErrorF("eglstream: error 0x%X: %s\n", error, ++ xwl_eglstream_get_error_str(error)); ++ ++ if (error == EGL_BAD_STATE_KHR) { ++ EGLint state = xwl_eglstream_get_state(egl_display, egl_stream); ++ ErrorF("eglstream: stream state 0x%X: %s\n", state, ++ xwl_eglstream_get_stream_state_str(state)); ++ } ++} ++ + /* Because we run asynchronously with our wayland compositor, it's possible + * that an X client event could cause us to begin creating a stream for a + * pixmap/window combo before the stream for the pixmap this window +@@ -466,6 +544,13 @@ xwl_eglstream_consumer_ready_callback(void *data, + EGL_NONE + }); + ++ if (xwl_pixmap->surface == EGL_NO_SURFACE) { ++ ErrorF("eglstream: Failed to create EGLSurface for pixmap\n"); ++ xwl_eglstream_print_error(xwl_screen->egl_display, ++ xwl_pixmap->stream, eglGetError()); ++ goto out; ++ } ++ + DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n", + pending->window->drawable.id, pending->pixmap); + +@@ -543,8 +628,16 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + xwl_pixmap->xwl_screen = xwl_screen; + xwl_pixmap->surface = EGL_NO_SURFACE; + xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL); ++ if (xwl_pixmap->stream == EGL_NO_STREAM_KHR) { ++ ErrorF("eglstream: Couldn't create EGL stream.\n"); ++ goto fail; ++ } + stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display, + xwl_pixmap->stream); ++ if (stream_fd == EGL_NO_FILE_DESCRIPTOR_KHR) { ++ ErrorF("eglstream: Couldn't get EGL stream file descriptor.\n"); ++ goto fail; ++ } + + wl_array_init(&stream_attribs); + xwl_pixmap->buffer = +-- +2.31.1 + diff --git a/SOURCES/0013-xwayland-eglstream-Dissociate-pending-stream-from-wi.patch b/SOURCES/0013-xwayland-eglstream-Dissociate-pending-stream-from-wi.patch new file mode 100644 index 0000000..26ff538 --- /dev/null +++ b/SOURCES/0013-xwayland-eglstream-Dissociate-pending-stream-from-wi.patch @@ -0,0 +1,323 @@ +From 90188c2648edb137f3564bdea53012355473f105 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Fri, 16 Apr 2021 10:38:23 +0200 +Subject: [PATCH xserver 13/27] xwayland/eglstream: Dissociate pending stream + from window +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previously, we would have pending streams associated with top level X11 +windows, keeping temporary accounting for the pending streams before +they get fully initialized for the xwl_pixmap which would be associated +with X11 pixmaps. + +If the window content changes before the stream is ready, the +corresponding pending stream would be marked as invalid and the pending +stream would be eventually removed once the stream becomes ready. + +Since commit affc47452 - "xwayland: Drop the separate refcount for the +xwl_pixmap", we no longer keep a separate reference counter for the +xwl_pixmap, but rather tie it to the X11 pixmap lifespan. Yet, the +pending stream would still be associated with the X11 toplevel window. + +Dissociate the pending streams from the X11 toplevel window, to keep it +tied only to the xwl_pixmap so that we can have: + + - pixmap <-> xwl_pixmap + - xwl_pixmap <-> pending stream + +Of course, the pending streams remain temporary and get removed as soon +as the ready callback is triggered, but the pending streams are not +linked to the X11 window anymore which can change their content, and +therefore their X11 pixmap at any time. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit cb61ecc7291cfbed2f76d4437cd7450b8e4dab00) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 131 +++++++++++------------- + 1 file changed, 60 insertions(+), 71 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 77b24a4b4..32f9a326f 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -93,6 +93,7 @@ struct xwl_pixmap { + /* add any new <= 4-byte member here to avoid holes on 64-bit */ + struct xwl_screen *xwl_screen; + struct wl_buffer *buffer; ++ struct xwl_eglstream_pending_stream *pending_stream; + + /* XWL_PIXMAP_EGLSTREAM. */ + EGLStreamKHR stream; +@@ -103,7 +104,6 @@ struct xwl_pixmap { + }; + + static DevPrivateKeyRec xwl_eglstream_private_key; +-static DevPrivateKeyRec xwl_eglstream_window_private_key; + + static inline struct xwl_eglstream_private * + xwl_eglstream_get(struct xwl_screen *xwl_screen) +@@ -112,21 +112,6 @@ xwl_eglstream_get(struct xwl_screen *xwl_screen) + &xwl_eglstream_private_key); + } + +-static inline struct xwl_eglstream_pending_stream * +-xwl_eglstream_window_get_pending(WindowPtr window) +-{ +- return dixLookupPrivate(&window->devPrivates, +- &xwl_eglstream_window_private_key); +-} +- +-static inline void +-xwl_eglstream_window_set_pending(WindowPtr window, +- struct xwl_eglstream_pending_stream *stream) +-{ +- dixSetPrivate(&window->devPrivates, +- &xwl_eglstream_window_private_key, stream); +-} +- + static GLint + xwl_eglstream_compile_glsl_prog(GLenum type, const char *source) + { +@@ -323,7 +308,6 @@ xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream + { + if (pending->cb) + wl_callback_destroy(pending->cb); +- xwl_eglstream_window_set_pending(pending->window, NULL); + xorg_list_del(&pending->link); + free(pending); + } +@@ -331,16 +315,9 @@ xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream + static void + xwl_glamor_eglstream_remove_pending_stream(struct xwl_pixmap *xwl_pixmap) + { +- struct xwl_eglstream_private *xwl_eglstream = +- xwl_eglstream_get(xwl_pixmap->xwl_screen); +- struct xwl_eglstream_pending_stream *pending; +- +- xorg_list_for_each_entry(pending, +- &xwl_eglstream->pending_streams, link) { +- if (pending->xwl_pixmap == xwl_pixmap) { +- xwl_glamor_eglstream_destroy_pending_stream(pending); +- break; +- } ++ if (xwl_pixmap->pending_stream) { ++ xwl_glamor_eglstream_destroy_pending_stream(xwl_pixmap->pending_stream); ++ xwl_pixmap->pending_stream = NULL; + } + } + +@@ -363,23 +340,41 @@ xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + return xwl_pixmap_get(pixmap)->buffer; + } + ++static void ++xwl_eglstream_maybe_set_pending_stream_invalid(PixmapPtr pixmap) ++{ ++ struct xwl_pixmap *xwl_pixmap; ++ struct xwl_eglstream_pending_stream *pending; ++ ++ xwl_pixmap = xwl_pixmap_get(pixmap); ++ if (!xwl_pixmap) ++ return; ++ ++ pending = xwl_pixmap->pending_stream; ++ if (!pending) ++ return; ++ ++ pending->is_valid = FALSE; ++} ++ + static void + xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) + { +- struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); ++ ScreenPtr screen = window->drawable.pScreen; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); +- struct xwl_eglstream_pending_stream *pending; ++ PixmapPtr old_pixmap; + +- pending = xwl_eglstream_window_get_pending(window); +- if (pending) { +- /* The pixmap for this window has changed before the compositor +- * finished attaching the consumer for the window's pixmap's original +- * eglstream. A producer can no longer be attached, so the stream's +- * useless +- */ +- pending->is_valid = FALSE; +- } ++ /* The pixmap for this window has changed. ++ * If that occurs while there is a stream pending, i.e. before the ++ * compositor has finished attaching the consumer for the window's ++ * pixmap's original eglstream, then a producer could no longer be ++ * attached, so the stream would be useless. ++ */ ++ old_pixmap = (*screen->GetWindowPixmap) (window); ++ if (old_pixmap) ++ xwl_eglstream_maybe_set_pending_stream_invalid(old_pixmap); + + xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap; + (*xwl_screen->screen->SetWindowPixmap)(window, pixmap); +@@ -489,16 +484,18 @@ xwl_eglstream_print_error(EGLDisplay egl_display, + * - Receive pixmap B's stream callback, fall over and fail because the + * window's surface now incorrectly has pixmap A's stream attached to it. + * +- * We work around this problem by keeping a queue of pending streams, and +- * only allowing one queue entry to exist for each window. In the scenario +- * listed above, this should happen: ++ * We work around this problem by keeping a pending stream associated with ++ * the xwl_pixmap, which itself is associated with the window pixmap. ++ * In the scenario listed above, this should happen: + * + * - Begin processing X events... +- * - A window is resized, causing us to add an eglstream (known as eglstream +- * A) waiting for its consumer to finish attachment to be added to the +- * queue. ++ * - A window is resized, a new window pixmap is created causing us to ++ * add an eglstream (known as eglstream A) waiting for its consumer ++ * to finish attachment. + * - Resize on same window happens. We invalidate the previously pending +- * stream and add another one to the pending queue (known as eglstream B). ++ * stream on the old window pixmap. ++ * A new window pixmap is attached to the window and another pending ++ * stream is created for that new pixmap (known as eglstream B). + * - Begin processing Wayland events... + * - Receive invalidated callback from compositor for eglstream A, destroy + * stream. +@@ -515,6 +512,7 @@ xwl_eglstream_consumer_ready_callback(void *data, + xwl_eglstream_get(xwl_screen); + struct xwl_pixmap *xwl_pixmap; + struct xwl_eglstream_pending_stream *pending; ++ PixmapPtr pixmap; + Bool found = FALSE; + + xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) { +@@ -528,6 +526,9 @@ xwl_eglstream_consumer_ready_callback(void *data, + wl_callback_destroy(callback); + pending->cb = NULL; + ++ xwl_pixmap = pending->xwl_pixmap; ++ pixmap = pending->pixmap; ++ + if (!pending->is_valid) { + xwl_eglstream_destroy_pixmap_stream(pending->xwl_pixmap); + goto out; +@@ -535,12 +536,11 @@ xwl_eglstream_consumer_ready_callback(void *data, + + xwl_glamor_egl_make_current(xwl_screen); + +- xwl_pixmap = pending->xwl_pixmap; + xwl_pixmap->surface = eglCreateStreamProducerSurfaceKHR( + xwl_screen->egl_display, xwl_eglstream->config, + xwl_pixmap->stream, (int[]) { +- EGL_WIDTH, pending->pixmap->drawable.width, +- EGL_HEIGHT, pending->pixmap->drawable.height, ++ EGL_WIDTH, pixmap->drawable.width, ++ EGL_HEIGHT, pixmap->drawable.height, + EGL_NONE + }); + +@@ -555,14 +555,14 @@ xwl_eglstream_consumer_ready_callback(void *data, + pending->window->drawable.id, pending->pixmap); + + out: +- xwl_glamor_eglstream_destroy_pending_stream(pending); ++ xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); + } + + static const struct wl_callback_listener consumer_ready_listener = { + xwl_eglstream_consumer_ready_callback + }; + +-static void ++static struct xwl_eglstream_pending_stream * + xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, + WindowPtr window, PixmapPtr pixmap) + { +@@ -570,14 +570,8 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, + xwl_eglstream_get(xwl_screen); + struct xwl_eglstream_pending_stream *pending_stream; + +-#ifdef DEBUG +- if (!xwl_eglstream_window_get_pending(window)) +- DebugF("eglstream: win %d begins new eglstream for pixmap %p\n", +- window->drawable.id, pixmap); +- else +- DebugF("eglstream: win %d interrupts and replaces pending eglstream for pixmap %p\n", +- window->drawable.id, pixmap); +-#endif ++ DebugF("eglstream: win %d queues new pending stream for pixmap %p\n", ++ window->drawable.id, pixmap); + + pending_stream = malloc(sizeof(*pending_stream)); + pending_stream->window = window; +@@ -586,11 +580,12 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, + pending_stream->is_valid = TRUE; + xorg_list_init(&pending_stream->link); + xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams); +- xwl_eglstream_window_set_pending(window, pending_stream); + + pending_stream->cb = wl_display_sync(xwl_screen->display); + wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener, + xwl_screen); ++ ++ return pending_stream; + } + + static void +@@ -663,7 +658,8 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + wl_eglstream_controller_attach_eglstream_consumer( + xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); + +- xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap); ++ xwl_pixmap->pending_stream = ++ xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap); + + fail: + if (stream_fd >= 0) +@@ -674,22 +670,19 @@ static Bool + xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + { + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; +- struct xwl_eglstream_pending_stream *pending = +- xwl_eglstream_window_get_pending(xwl_window->window); + PixmapPtr pixmap = + (*xwl_screen->screen->GetWindowPixmap)(xwl_window->window); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap) { ++ struct xwl_eglstream_pending_stream *pending = xwl_pixmap->pending_stream; ++ + if (pending) { + /* Wait for the compositor to finish connecting the consumer for + * this eglstream */ +- if (pending->is_valid) +- return FALSE; ++ assert(pending->is_valid); + +- /* The pixmap for this window was changed before the compositor +- * finished connecting the eglstream for the window's previous +- * pixmap. Begin creating a new eglstream. */ ++ return FALSE; + } else { + return TRUE; + } +@@ -1190,10 +1183,6 @@ xwl_glamor_eglstream_init_screen(struct xwl_screen *xwl_screen) + xwl_eglstream->SetWindowPixmap = screen->SetWindowPixmap; + screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap; + +- if (!dixRegisterPrivateKey(&xwl_eglstream_window_private_key, +- PRIVATE_WINDOW, 0)) +- return FALSE; +- + return TRUE; + } + +-- +2.31.1 + diff --git a/SOURCES/0014-xwayland-eglstream-Keep-a-reference-to-the-pixmap.patch b/SOURCES/0014-xwayland-eglstream-Keep-a-reference-to-the-pixmap.patch new file mode 100644 index 0000000..a635eca --- /dev/null +++ b/SOURCES/0014-xwayland-eglstream-Keep-a-reference-to-the-pixmap.patch @@ -0,0 +1,73 @@ +From f76dd86f5bbdccb3655ac58365e4604d03de65f5 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Wed, 14 Apr 2021 17:31:08 +0200 +Subject: [PATCH xserver 14/27] xwayland/eglstream: Keep a reference to the + pixmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit affc47452 - "xwayland: Drop the separate refcount for the +xwl_pixmap" removed the separate reference counter for the xwl_pixmap +which holds the EGLStream. + +While that works fine for the common case, if the window's pixmap is +changed before the stream is ready, the older pixmap will be destroyed +and the xwl_pixmap along with it, even if the compositor is still using +the stream. + +The code that was removed with commit affc47452 was taking care of that +by increasing the separate reference counter for the xwl_pixmap, but it +no longer the case. + +As a result, we may end up with the EGL stream in the wrong state when +trying to use it, which will cascade down into all sort of issues. + +To avoid the problem, increase the reference count on the pixmap when it +is marked as invalid in EGLStream's SetWindowPixmap(). + +This way, the xwl_pixmap and the EGLStream are kept until released by +the compositor, even when the pixmap changes before stream is ready. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +Fixes: affc47452 xwayland: Drop the separate refcount for the xwl_pixmap +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit e19bf86c17ef9c802fea24410cc6b1f51a19ce7f) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 32f9a326f..807bfcb1d 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -355,6 +355,13 @@ xwl_eglstream_maybe_set_pending_stream_invalid(PixmapPtr pixmap) + return; + + pending->is_valid = FALSE; ++ ++ /* The compositor may still be using the stream, so we can't destroy ++ * it yet. We'll only have a guarantee that the stream is safe to ++ * destroy once we receive the pending wl_display_sync() for this ++ * stream ++ */ ++ pending->pixmap->refcnt++; + } + + static void +@@ -530,8 +537,9 @@ xwl_eglstream_consumer_ready_callback(void *data, + pixmap = pending->pixmap; + + if (!pending->is_valid) { +- xwl_eglstream_destroy_pixmap_stream(pending->xwl_pixmap); +- goto out; ++ xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); ++ dixDestroyPixmap(pixmap, 0); ++ return; + } + + xwl_glamor_egl_make_current(xwl_screen); +-- +2.31.1 + diff --git a/SOURCES/0015-xwayland-eglstream-Drop-the-list-of-pending-streams.patch b/SOURCES/0015-xwayland-eglstream-Drop-the-list-of-pending-streams.patch new file mode 100644 index 0000000..06c1250 --- /dev/null +++ b/SOURCES/0015-xwayland-eglstream-Drop-the-list-of-pending-streams.patch @@ -0,0 +1,146 @@ +From a68e939342aed0ea11c737d166e506442e048e90 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 27 Apr 2021 14:17:19 +0200 +Subject: [PATCH xserver 15/27] xwayland/eglstream: Drop the list of pending + streams +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that the pending stream is associated with the xwl_pixmap for +EGLStream and the xwl_pixmap itself is associated to the pixmap, we have +a reliable way to get to those data from any pending stream. + +As a result, the list of pending streams that we keep in the EGLStream +global structure becomes useless. + +So we can drop the pending stream's xwl_pixmap and also the list of +pending streams altogether, and save us a walk though that list for each +callback. + +Signed-off-by: Olivier Fourdan +Suggested-by: Michel Dänzer +Reviewed-by: Michel Dänzer +(cherry picked from commit bee2ebb29f0999862ab39af26c673c00af40b082) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 41 ++++++------------------- + 1 file changed, 9 insertions(+), 32 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 807bfcb1d..399a691d3 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -55,12 +55,9 @@ struct xwl_eglstream_pending_stream { + PixmapPtr pixmap; + WindowPtr window; + +- struct xwl_pixmap *xwl_pixmap; + struct wl_callback *cb; + + Bool is_valid; +- +- struct xorg_list link; + }; + + struct xwl_eglstream_private { +@@ -73,8 +70,6 @@ struct xwl_eglstream_private { + + SetWindowPixmapProcPtr SetWindowPixmap; + +- struct xorg_list pending_streams; +- + Bool have_egl_damage; + + GLint blit_prog; +@@ -308,7 +303,6 @@ xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream + { + if (pending->cb) + wl_callback_destroy(pending->cb); +- xorg_list_del(&pending->link); + free(pending); + } + +@@ -514,28 +508,16 @@ xwl_eglstream_consumer_ready_callback(void *data, + struct wl_callback *callback, + uint32_t time) + { +- struct xwl_screen *xwl_screen = data; ++ struct xwl_eglstream_pending_stream *pending = data; ++ PixmapPtr pixmap = pending->pixmap; ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); +- struct xwl_pixmap *xwl_pixmap; +- struct xwl_eglstream_pending_stream *pending; +- PixmapPtr pixmap; +- Bool found = FALSE; +- +- xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) { +- if (pending->cb == callback) { +- found = TRUE; +- break; +- } +- } +- assert(found); + + wl_callback_destroy(callback); + pending->cb = NULL; + +- xwl_pixmap = pending->xwl_pixmap; +- pixmap = pending->pixmap; +- + if (!pending->is_valid) { + xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap); + dixDestroyPixmap(pixmap, 0); +@@ -571,11 +553,10 @@ static const struct wl_callback_listener consumer_ready_listener = { + }; + + static struct xwl_eglstream_pending_stream * +-xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, +- WindowPtr window, PixmapPtr pixmap) ++xwl_eglstream_queue_pending_stream(WindowPtr window, PixmapPtr pixmap) + { +- struct xwl_eglstream_private *xwl_eglstream = +- xwl_eglstream_get(xwl_screen); ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; + struct xwl_eglstream_pending_stream *pending_stream; + + DebugF("eglstream: win %d queues new pending stream for pixmap %p\n", +@@ -584,14 +565,11 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, + pending_stream = malloc(sizeof(*pending_stream)); + pending_stream->window = window; + pending_stream->pixmap = pixmap; +- pending_stream->xwl_pixmap = xwl_pixmap_get(pixmap); + pending_stream->is_valid = TRUE; +- xorg_list_init(&pending_stream->link); +- xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams); + + pending_stream->cb = wl_display_sync(xwl_screen->display); + wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener, +- xwl_screen); ++ pending_stream); + + return pending_stream; + } +@@ -667,7 +645,7 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); + + xwl_pixmap->pending_stream = +- xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap); ++ xwl_eglstream_queue_pending_stream(window, pixmap); + + fail: + if (stream_fd >= 0) +@@ -1249,7 +1227,6 @@ xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) + &xwl_eglstream_private_key, xwl_eglstream); + + xwl_eglstream->egl_device = egl_device; +- xorg_list_init(&xwl_eglstream->pending_streams); + + xwl_screen->eglstream_backend.init_egl = xwl_glamor_eglstream_init_egl; + xwl_screen->eglstream_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry; +-- +2.31.1 + diff --git a/SOURCES/0016-xwayland-eglstream-Do-not-commit-without-surface.patch b/SOURCES/0016-xwayland-eglstream-Do-not-commit-without-surface.patch new file mode 100644 index 0000000..4bf1d39 --- /dev/null +++ b/SOURCES/0016-xwayland-eglstream-Do-not-commit-without-surface.patch @@ -0,0 +1,49 @@ +From 9601f2cc5c94b9db4c7f8da404dae53b9609c995 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 19 Apr 2021 18:11:19 +0200 +Subject: [PATCH xserver 16/27] xwayland/eglstream: Do not commit without + surface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The EGL surface for the xwl_pixmap is created once the stream is ready +and valid. + +If the pixmap's EGL surface fails, for whatever reason, the xwl_pixmap +will be unusable and will end up as an invalid wl_buffer. + +Make sure we do not allow commits in that case and recreate the +xwl_pixmap/stream. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156 +(cherry picked from commit 098e0f52c088c6eb52c7e54c5a11cefabd480908) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 399a691d3..ce066cd9e 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -670,7 +670,14 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + + return FALSE; + } else { +- return TRUE; ++ if (xwl_pixmap->surface != EGL_NO_SURFACE) ++ return TRUE; ++ ++ /* The pending stream got removed, we have a xwl_pixmap and ++ * yet we do not have a surface. ++ * So something went wrong with the surface creation, retry. ++ */ ++ xwl_eglstream_destroy_pixmap_stream(xwl_pixmap); + } + } + +-- +2.31.1 + diff --git a/SOURCES/0017-xwayland-eglstream-Fix-calloc-malloc.patch b/SOURCES/0017-xwayland-eglstream-Fix-calloc-malloc.patch new file mode 100644 index 0000000..11801c2 --- /dev/null +++ b/SOURCES/0017-xwayland-eglstream-Fix-calloc-malloc.patch @@ -0,0 +1,47 @@ +From 39df6934d5a9a132c2e87456e35094b7e81a238e Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 19 Apr 2021 14:52:38 +0200 +Subject: [PATCH xserver 17/27] xwayland/eglstream: Fix calloc/malloc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use calloc() instead of malloc() like the rest of the code. + +Also fix the arguments of calloc() calls to match the definition which +is calloc(size_t nmemb, size_t size). + +This is a cleanup patch, no functional change. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit a45799971083c47082d085d3732a5b12692cf75b) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index ce066cd9e..3a3caa976 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -562,7 +562,7 @@ xwl_eglstream_queue_pending_stream(WindowPtr window, PixmapPtr pixmap) + DebugF("eglstream: win %d queues new pending stream for pixmap %p\n", + window->drawable.id, pixmap); + +- pending_stream = malloc(sizeof(*pending_stream)); ++ pending_stream = calloc(1, sizeof(*pending_stream)); + pending_stream->window = window; + pending_stream->pixmap = pixmap; + pending_stream->is_valid = TRUE; +@@ -596,7 +596,7 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + struct wl_array stream_attribs; + int stream_fd = -1; + +- xwl_pixmap = calloc(sizeof(*xwl_pixmap), 1); ++ xwl_pixmap = calloc(1, sizeof(*xwl_pixmap)); + if (!xwl_pixmap) + FatalError("Not enough memory to create pixmap\n"); + xwl_pixmap_set_private(pixmap, xwl_pixmap); +-- +2.31.1 + diff --git a/SOURCES/0018-xwayland-eglstream-Check-eglSwapBuffers.patch b/SOURCES/0018-xwayland-eglstream-Check-eglSwapBuffers.patch new file mode 100644 index 0000000..4655b8e --- /dev/null +++ b/SOURCES/0018-xwayland-eglstream-Check-eglSwapBuffers.patch @@ -0,0 +1,56 @@ +From a964ccdadf351d90482df00c272dee3634f7a8ee Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Fri, 30 Apr 2021 09:02:29 +0200 +Subject: [PATCH xserver 18/27] xwayland/eglstream: Check eglSwapBuffers() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +EGLstream's post_damage() would unconditionally return success +regardless of the actual status of the eglSwapBuffers(). + +Yet, if eglSwapBuffers() fails, we should not post the corresponding +damage as they wouldn't match the actual content of the buffer. + +Use the eglSwapBuffers() return value as the return value for +post_damage() and do not take a refrence on the pixmap if it fails. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit b583395cd38ad101c7541bd8b0e91143ced44703) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 3a3caa976..6721acfe8 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -750,14 +750,20 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if (xwl_eglstream->have_egl_damage) +- eglSwapBuffersWithDamageKHR(xwl_screen->egl_display, +- xwl_pixmap->surface, egl_damage, 1); ++ status = eglSwapBuffersWithDamageKHR(xwl_screen->egl_display, ++ xwl_pixmap->surface, ++ egl_damage, 1); + else +- eglSwapBuffers(xwl_screen->egl_display, xwl_pixmap->surface); ++ status = eglSwapBuffers(xwl_screen->egl_display, ++ xwl_pixmap->surface); ++ ++ if (!status) { ++ ErrorF("eglstream: buffer swap failed, not posting damage\n"); ++ goto out; ++ } + + /* hang onto the pixmap until the compositor has released it */ + pixmap->refcnt++; +- status = TRUE; + + out: + /* Restore previous state */ +-- +2.31.1 + diff --git a/SOURCES/0019-xwayland-eglstream-Do-not-always-increment-pixmap-re.patch b/SOURCES/0019-xwayland-eglstream-Do-not-always-increment-pixmap-re.patch new file mode 100644 index 0000000..3407d14 --- /dev/null +++ b/SOURCES/0019-xwayland-eglstream-Do-not-always-increment-pixmap-re.patch @@ -0,0 +1,89 @@ +From 7b06e468b37164eeaa18fc32cba801de0eee4eb1 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Tue, 4 May 2021 10:56:38 +0200 +Subject: [PATCH xserver 19/27] xwayland/eglstream: Do not always increment + pixmap refcnt on commit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, the EGLstream backend would increment the pixmap refcount for +each commit, and decrease that refcount on the wl_buffer release +callback. + +But that's relying on the compositor sending us a release callback for +each commit, otherwise the pixmap refcount will keep increasing and the +pixmap will be leaked. + +So instead, increment the refcount on the pixmap only when we have not +received a release notification for the wl_buffer, to avoid increasing +the pixmap refcount more than once without a corresponding release +event. + +This way, if the pixmap is still in use when released on the X11 side, +the EGL stream will be kept until the compositor releases it. + +Signed-off-by: Olivier Fourdan +Suggested-by: Michel Dänzer +Reviewed-by: Michel Dänzer +(cherry picked from commit d85bfa6ab7495281516f3a4b05dc1ff0b2c4bf91) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 6721acfe8..64f4e31f5 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -89,6 +89,7 @@ struct xwl_pixmap { + struct xwl_screen *xwl_screen; + struct wl_buffer *buffer; + struct xwl_eglstream_pending_stream *pending_stream; ++ Bool wait_for_buffer_release; + + /* XWL_PIXMAP_EGLSTREAM. */ + EGLStreamKHR stream; +@@ -577,8 +578,16 @@ xwl_eglstream_queue_pending_stream(WindowPtr window, PixmapPtr pixmap) + static void + xwl_eglstream_buffer_release_callback(void *data) + { +- /* drop the reference we took in post_damage, freeing if necessary */ +- dixDestroyPixmap(data, 0); ++ PixmapPtr pixmap = data; ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ ++ assert(xwl_pixmap); ++ ++ if (xwl_pixmap->wait_for_buffer_release) { ++ xwl_pixmap->wait_for_buffer_release = FALSE; ++ /* drop the reference we took in the ready callback, freeing if necessary */ ++ dixDestroyPixmap(pixmap, 0); ++ } + } + + static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = { +@@ -606,6 +615,7 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen, + + xwl_glamor_egl_make_current(xwl_screen); + ++ xwl_pixmap->wait_for_buffer_release = FALSE; + xwl_pixmap->xwl_screen = xwl_screen; + xwl_pixmap->surface = EGL_NO_SURFACE; + xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL); +@@ -762,8 +772,11 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + goto out; + } + +- /* hang onto the pixmap until the compositor has released it */ +- pixmap->refcnt++; ++ if (!xwl_pixmap->wait_for_buffer_release) { ++ /* hang onto the pixmap until the compositor has released it */ ++ pixmap->refcnt++; ++ xwl_pixmap->wait_for_buffer_release = TRUE; ++ } + + out: + /* Restore previous state */ +-- +2.31.1 + diff --git a/SOURCES/0020-xwayland-eglstream-Set-ALU-to-GXCopy-for-blitting.patch b/SOURCES/0020-xwayland-eglstream-Set-ALU-to-GXCopy-for-blitting.patch new file mode 100644 index 0000000..7236283 --- /dev/null +++ b/SOURCES/0020-xwayland-eglstream-Set-ALU-to-GXCopy-for-blitting.patch @@ -0,0 +1,51 @@ +From 9519ebe96344ec64e8f18eae2420df101c446a1a Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Fri, 30 Apr 2021 16:23:10 +0200 +Subject: [PATCH xserver 20/27] xwayland/eglstream: Set ALU to GXCopy for + blitting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The EGLstream backend's post damage function uses a shader and +glDrawArrays() to copy the data from the glamor's pixmap texture prior +to do the eglSwapBuffers(). + +However, glDrawArrays() can be affected by the GL state, and therefore +not reliably produce the expected copy, causing the content of the +buffer to be corrupted. + +Make sure to set the ALU to GXCopy prior to call glDrawArrays() to get +the expected result. + +Signed-off-by: Olivier Fourdan +Suggested-by: Michel Dänzer +(cherry picked from commit 012350e3db47fef0404346f55968032e62004fcf) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 64f4e31f5..2094d293a 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -33,6 +33,7 @@ + #define EGL_NO_X11 + #include + #include ++#include + #include + #include + +@@ -727,6 +728,8 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + * won't actually draw to it + */ + xwl_glamor_egl_make_current(xwl_screen); ++ glamor_set_alu(xwl_screen->screen, GXcopy); ++ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (eglGetCurrentSurface(EGL_READ) != xwl_pixmap->surface || +-- +2.31.1 + diff --git a/SOURCES/0021-xwayland-eglstream-allow-commits-to-dma-buf-backed-p.patch b/SOURCES/0021-xwayland-eglstream-allow-commits-to-dma-buf-backed-p.patch new file mode 100644 index 0000000..d4d9b27 --- /dev/null +++ b/SOURCES/0021-xwayland-eglstream-allow-commits-to-dma-buf-backed-p.patch @@ -0,0 +1,43 @@ +From 64deb9471c7d9cad4c2ec1de1fba6a35c9af8e68 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Fri, 14 May 2021 08:26:49 -0400 +Subject: [PATCH xserver 21/27] xwayland/eglstream: allow commits to dma-buf + backed pixmaps +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As of commit 098e0f52 xwl_glamor_eglstream_allow_commits will not allow commits +if the xwl_pixmap does not have an EGLSurface. This is valid for pixmaps backed +by an EGLStream, however pixmaps backed by a dma-buf for OpenGL or Vulkan +rendering will never have an EGLSurface. Unlike EGLStream backed pixmaps, +though, glamor will render directly to the buffer that Xwayland passes to the +compositor. Hence, they don't require the intermediate copy in +xwl_glamor_eglstream_post_damage that EGLStream backed pixmaps do, so there is +no need for an EGLSurface. + +Signed-off-by: Erik Kurzinger +Acked-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit 3d33d885fcd1215a74c1819278cf6f9557c9860b) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 2094d293a..2d0827709 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -681,7 +681,8 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) + + return FALSE; + } else { +- if (xwl_pixmap->surface != EGL_NO_SURFACE) ++ if (xwl_pixmap->surface != EGL_NO_SURFACE || ++ xwl_pixmap->type == XWL_PIXMAP_DMA_BUF) + return TRUE; + + /* The pending stream got removed, we have a xwl_pixmap and +-- +2.31.1 + diff --git a/SOURCES/0022-xwayland-eglstream-flush-stream-after-eglSwapBuffers.patch b/SOURCES/0022-xwayland-eglstream-flush-stream-after-eglSwapBuffers.patch new file mode 100644 index 0000000..65a5d77 --- /dev/null +++ b/SOURCES/0022-xwayland-eglstream-flush-stream-after-eglSwapBuffers.patch @@ -0,0 +1,76 @@ +From 29cba30948cda34e744314343109964ff9ed515c Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 11 May 2021 17:00:21 -0400 +Subject: [PATCH xserver 22/27] xwayland/eglstream: flush stream after + eglSwapBuffers + +When eglSwapBuffers inserts a new frame into a window's stream, there may be a +delay before the state of the consumer end of the stream is updated to reflect +this. If the subsequent wl_surface_attach, wl_surface_damage, wl_surface_commit +calls are received by the compositor before then, it will (typically) re-use +the previous frame acquired from the stream instead of the latest one. + +This can leave the window displaying out-of-date contents, which might never be +updated thereafter. + +To fix this, after calling eglSwapBuffers, xwl_glamor_eglstream_post_damage +should call eglStreamFlushNV. This call will block until it can be guaranteed +that the state of the consumer end of the stream has been updated to reflect +that a new frame is available. + +Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1171 + +Signed-off-by: Erik Kurzinger +(cherry picked from commit 7515c23a416825f0db51f9b445279b12d5918ebf) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 2d0827709..c583a1390 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -72,6 +72,7 @@ struct xwl_eglstream_private { + SetWindowPixmapProcPtr SetWindowPixmap; + + Bool have_egl_damage; ++ Bool have_egl_stream_flush; + + GLint blit_prog; + GLuint blit_vao; +@@ -776,6 +777,13 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + goto out; + } + ++#ifdef EGL_NV_stream_flush ++ if (xwl_eglstream->have_egl_stream_flush) ++ /* block until stream state is updated on the compositor's side */ ++ eglStreamFlushNV(xwl_screen->egl_display, ++ xwl_pixmap->stream); ++#endif ++ + if (!xwl_pixmap->wait_for_buffer_release) { + /* hang onto the pixmap until the compositor has released it */ + pixmap->refcnt++; +@@ -1173,6 +1181,18 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) + ErrorF("Driver lacks EGL_KHR_swap_buffers_with_damage, performance " + "will be affected\n"); + ++#ifdef EGL_NV_stream_flush ++ xwl_eglstream->have_egl_stream_flush = ++ epoxy_has_egl_extension(xwl_screen->egl_display, ++ "EGL_NV_stream_flush"); ++#else ++ xwl_eglstream->have_egl_stream_flush = FALSE; ++#endif /* EGL_NV_stream_flush */ ++ ++ if (!xwl_eglstream->have_egl_stream_flush) ++ ErrorF("EGL_NV_stream_flush not available, " ++ "this may cause visible corruption.\n"); ++ + xwl_eglstream_init_shaders(xwl_screen); + + if (epoxy_has_gl_extension("GL_OES_EGL_image") && +-- +2.31.1 + diff --git a/SOURCES/0023-xwayland-Add-preferred-GLVND-vendor-to-xwl_screen.patch b/SOURCES/0023-xwayland-Add-preferred-GLVND-vendor-to-xwl_screen.patch new file mode 100644 index 0000000..ffb2c6f --- /dev/null +++ b/SOURCES/0023-xwayland-Add-preferred-GLVND-vendor-to-xwl_screen.patch @@ -0,0 +1,57 @@ +From 4c01758cbe7db02d84ac0cba0c626e855bf927d6 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Thu, 20 May 2021 12:11:42 +0200 +Subject: [PATCH xserver 23/27] xwayland: Add preferred GLVND vendor to + xwl_screen +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If Xwayland's EGLstream backend supports hardware acceleration with the +NVIDIA closed-source driver, the GLX library also needs to be one +shipped by NVIDIA, that's what GLVND is for. + +Add a new member to the xwl_screen that the backend can optionally set +to the preferred GLVND vendor to use. + +If not set, "mesa" is assumed. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit 24fc8aea1e4bbaba780f1a316fba797a0198f603) +--- + hw/xwayland/xwayland-glx.c | 3 +++ + hw/xwayland/xwayland-screen.h | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/xwayland/xwayland-glx.c b/hw/xwayland/xwayland-glx.c +index 7e2a87fc1..eba8946ab 100644 +--- a/hw/xwayland/xwayland-glx.c ++++ b/hw/xwayland/xwayland-glx.c +@@ -378,6 +378,9 @@ egl_screen_probe(ScreenPtr pScreen) + return NULL; + } + ++ if (!screen->base.glvnd && xwl_screen->glvnd_vendor) ++ screen->base.glvnd = strdup(xwl_screen->glvnd_vendor); ++ + if (!screen->base.glvnd) + screen->base.glvnd = strdup("mesa"); + +diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h +index 5fe4712bd..b965dddd7 100644 +--- a/hw/xwayland/xwayland-screen.h ++++ b/hw/xwayland/xwayland-screen.h +@@ -107,6 +107,9 @@ struct xwl_screen { + struct glamor_context *glamor_ctx; + + Atom allow_commits_prop; ++ ++ /* The preferred GLVND vendor. If NULL, "mesa" is assumed. */ ++ const char *glvnd_vendor; + }; + + /* Apps which use randr/vidmode to change the mode when going fullscreen, +-- +2.31.1 + diff --git a/SOURCES/0024-xwayland-eglstream-Use-nvidia-for-GLVND.patch b/SOURCES/0024-xwayland-eglstream-Use-nvidia-for-GLVND.patch new file mode 100644 index 0000000..efe46c9 --- /dev/null +++ b/SOURCES/0024-xwayland-eglstream-Use-nvidia-for-GLVND.patch @@ -0,0 +1,42 @@ +From 430eb872784c04e825126e0d7454f3a5bbefff70 Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 17 May 2021 18:20:57 +0200 +Subject: [PATCH xserver 24/27] xwayland/eglstream: Use "nvidia" for GLVND +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the EGLStream backend is able to use hardware acceleration with the +NVIDIA closed source driver, we should use the "nvidia" GLX +implementation instead of the one from Mesa to take advantage of the +NVIDIA hardware accelerated rendering. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit fae58e9b03696a3890f9c876306c68ffa6f9ff30) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index c583a1390..5e89849ff 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -1195,9 +1195,11 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) + + xwl_eglstream_init_shaders(xwl_screen); + +- if (epoxy_has_gl_extension("GL_OES_EGL_image") && +- !dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) { +- ErrorF("DRI3 initialization failed. Performance will be affected.\n"); ++ if (epoxy_has_gl_extension("GL_OES_EGL_image")) { ++ if (dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) ++ xwl_screen->glvnd_vendor = "nvidia"; ++ else ++ ErrorF("DRI3 initialization failed. Performance will be affected.\n"); + } + + return TRUE; +-- +2.31.1 + diff --git a/SOURCES/0025-xwayland-eglstream-Log-when-GL_OES_EGL_image-is-miss.patch b/SOURCES/0025-xwayland-eglstream-Log-when-GL_OES_EGL_image-is-miss.patch new file mode 100644 index 0000000..ffca409 --- /dev/null +++ b/SOURCES/0025-xwayland-eglstream-Log-when-GL_OES_EGL_image-is-miss.patch @@ -0,0 +1,35 @@ +From 0cb42b7de629e74afed9b19d47672cebfe08f12e Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Thu, 20 May 2021 16:46:33 +0200 +Subject: [PATCH xserver 25/27] xwayland/eglstream: Log when GL_OES_EGL_image + is missing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +That will dramatically affect performance, might as well log when we +cannot use GL_OES_EGL_image with the NVIDIA closed-source driver. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Michel Dänzer +(cherry picked from commit 34a58d7714025bc1043bf5282358406eb10e4b8e) +--- + hw/xwayland/xwayland-glamor-eglstream.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c +index 5e89849ff..0affc954c 100644 +--- a/hw/xwayland/xwayland-glamor-eglstream.c ++++ b/hw/xwayland/xwayland-glamor-eglstream.c +@@ -1200,6 +1200,8 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) + xwl_screen->glvnd_vendor = "nvidia"; + else + ErrorF("DRI3 initialization failed. Performance will be affected.\n"); ++ } else { ++ ErrorF("Driver lacks GL_OES_EGL_image, performance will be affected.\n"); + } + + return TRUE; +-- +2.31.1 + diff --git a/SOURCES/0026-glx-don-t-create-implicit-GLXWindow-if-one-already-e.patch b/SOURCES/0026-glx-don-t-create-implicit-GLXWindow-if-one-already-e.patch new file mode 100644 index 0000000..cb3aa7f --- /dev/null +++ b/SOURCES/0026-glx-don-t-create-implicit-GLXWindow-if-one-already-e.patch @@ -0,0 +1,60 @@ +From a604a0a26791e9f352aad27232127d729bca4334 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Thu, 10 Dec 2020 14:24:32 -0800 +Subject: [PATCH xserver 26/27] glx: don't create implicit GLXWindow if one + already exists + +If a GLXMakeCurrent request specifies an X window as its drawable, +__glXGetDrawable will implicitly create a GLXWindow for it. However, +the client may have already explicitly created a GLXWindow for that X +window. If that happens, two __glXDrawableRes resources will be added +to the window. + +If the explicitly-created GLXWindow is later destroyed by the client, +DrawableGone will call FreeResourceByType on the X window, but this +will actually free the resource for the implicitly-created GLXWindow, +since that one would be at the head of the list. + +Then if the X window is destroyed after that, the resource for the +explicitly-created GLXWindow will be freed. But that GLXWindow was +already destroyed above. This crashes the server when it tries to call +the destroyed GLXWindow's destructor. It also means the +implicitly-created GLXWindow would have been leaked since the +FreeResourceByType call mentioned above skips calling the destructor. + +To fix this, if __glXGetDrawable is given an X window, it should check +if there is already a GLXWindow associated with it, and only create an +implicit one if there is not. + +Signed-off-by: Erik Kurzinger +Reviewed-by: Adam Jackson +(cherry picked from commit b7a85e44da91d1663d5b4eabac06327c92a80f91) +--- + glx/glxcmds.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/glx/glxcmds.c b/glx/glxcmds.c +index 37576b6ef..1b9ad6d14 100644 +--- a/glx/glxcmds.c ++++ b/glx/glxcmds.c +@@ -487,8 +487,15 @@ __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client, + __GLXscreen *pGlxScreen; + int rc; + +- if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, +- DixWriteAccess, &pGlxDraw, &rc)) { ++ rc = dixLookupResourceByType((void **)&pGlxDraw, drawId, ++ __glXDrawableRes, client, DixWriteAccess); ++ if (rc == Success && ++ /* If pGlxDraw->drawId == drawId, drawId is a valid GLX drawable. ++ * Otherwise, if pGlxDraw->type == GLX_DRAWABLE_WINDOW, drawId is ++ * an X window, but the client has already created a GLXWindow ++ * associated with it, so we don't want to create another one. */ ++ (pGlxDraw->drawId == drawId || ++ pGlxDraw->type == GLX_DRAWABLE_WINDOW)) { + if (glxc != NULL && + glxc->config != NULL && + glxc->config != pGlxDraw->config) { +-- +2.31.1 + diff --git a/SOURCES/0027-glx-Set-ContextTag-for-all-contexts.patch b/SOURCES/0027-glx-Set-ContextTag-for-all-contexts.patch new file mode 100644 index 0000000..1bedd5c --- /dev/null +++ b/SOURCES/0027-glx-Set-ContextTag-for-all-contexts.patch @@ -0,0 +1,45 @@ +From 1607ac6870f7cf67c30b96529ea5ca389c771a3d Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Thu, 3 Jun 2021 17:51:01 +0200 +Subject: [PATCH xserver 27/27] glx: Set ContextTag for all contexts + +Currently, xorgGlxMakeCurrent() would set the context tag only for +indirect GLX contexts. + +However, several other places expect to find a context for the tag or +they would raise a GLXBadContextTag error, such as WaitGL() or WaitX(). + +Set the context tag for direct contexts as well, to avoid raising an +error and possibly killing the client and set currentClient. + +Thanks to Erik Kurzinger for spotting the issue. + +Signed-off-by: Olivier Fourdan +Reviewed-by: Adam Jackson +(cherry picked from commit c468d34c7208c9041f9c077b54a00ae9cccad6a3) +(cherry picked from commit aad61e8e03311eb8bae4f7db59e65634733eadc2) +--- + glx/glxcmds.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/glx/glxcmds.c b/glx/glxcmds.c +index 1b9ad6d14..8b2170306 100644 +--- a/glx/glxcmds.c ++++ b/glx/glxcmds.c +@@ -662,10 +662,11 @@ xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId, + glxc->readPriv = NULL; + return __glXError(GLXBadContext); + } ++ } + ++ glxServer.setContextTagPrivate(client, newContextTag, glxc); ++ if (glxc) + glxc->currentClient = client; +- glxServer.setContextTagPrivate(client, newContextTag, glxc); +- } + + if (prevglxc) { + prevglxc->currentClient = NULL; +-- +2.31.1 + diff --git a/SPECS/xorg-x11-server-Xwayland.spec b/SPECS/xorg-x11-server-Xwayland.spec new file mode 100644 index 0000000..7b7e8bd --- /dev/null +++ b/SPECS/xorg-x11-server-Xwayland.spec @@ -0,0 +1,192 @@ +%global commit 280aac5a0ee09c45b17ec4be0681397f7c34c12e +%global shortcommit %(c=%{commit}; echo ${c:0:7}) + +#global gitdate 20210201 +%global pkgname %{?gitdate:xserver}%{!?gitdate:xwayland} + +%global default_font_path "catalogue:/etc/X11/fontpath.d,built-ins" + +Summary: Xwayland +Name: xorg-x11-server-Xwayland +Version: 21.1.1 +Release: 6%{?gitdate:.%{gitdate}git%{shortcommit}}%{?dist} + +URL: http://www.x.org +%if 0%{?gitdate} +Source0: https://gitlab.freedesktop.org/xorg/%{pkgname}/-/archive/%{commit}/%{pkgname}-%{shortcommit}.tar.gz +%else +Source0: https://www.x.org/pub/individual/xserver/%{pkgname}-%{version}.tar.xz +%endif + +Patch1: 0001-xwayland-Move-dmabuf-interface-to-common-glamor-code.patch +Patch2: 0002-xwayland-move-formats-and-modifiers-functions-to-com.patch +Patch3: 0003-xwayland-Add-check_flip-glamor-backend-function.patch +Patch4: 0004-xwayland-implement-pixmap_from_buffers-for-the-eglst.patch +Patch5: 0005-xwayland-eglstream-fix-X11-rendering-to-flipping-GL-.patch +Patch6: 0006-xwayland-eglstream-Check-buffer-creation.patch +Patch7: 0007-xwayland-Check-buffer-prior-to-attaching-it.patch +Patch8: 0008-glamor-Dump-backtrace-on-GL-error.patch +Patch9: 0009-xwayland-glamor-Add-return-status-to-post_damage.patch +Patch10: 0010-xwayland-eglstream-Check-framebuffer-status.patch +Patch11: 0011-xwayland-eglstream-Small-refactoring.patch +Patch12: 0012-xwayland-eglstream-Add-more-error-checking.patch +Patch13: 0013-xwayland-eglstream-Dissociate-pending-stream-from-wi.patch +Patch14: 0014-xwayland-eglstream-Keep-a-reference-to-the-pixmap.patch +Patch15: 0015-xwayland-eglstream-Drop-the-list-of-pending-streams.patch +Patch16: 0016-xwayland-eglstream-Do-not-commit-without-surface.patch +Patch17: 0017-xwayland-eglstream-Fix-calloc-malloc.patch +Patch18: 0018-xwayland-eglstream-Check-eglSwapBuffers.patch +Patch19: 0019-xwayland-eglstream-Do-not-always-increment-pixmap-re.patch +Patch20: 0020-xwayland-eglstream-Set-ALU-to-GXCopy-for-blitting.patch +Patch21: 0021-xwayland-eglstream-allow-commits-to-dma-buf-backed-p.patch +Patch22: 0022-xwayland-eglstream-flush-stream-after-eglSwapBuffers.patch +Patch23: 0023-xwayland-Add-preferred-GLVND-vendor-to-xwl_screen.patch +Patch24: 0024-xwayland-eglstream-Use-nvidia-for-GLVND.patch +Patch25: 0025-xwayland-eglstream-Log-when-GL_OES_EGL_image-is-miss.patch +Patch26: 0026-glx-don-t-create-implicit-GLXWindow-if-one-already-e.patch +Patch27: 0027-glx-Set-ContextTag-for-all-contexts.patch +# https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/704 +Patch28: 0001-xwayland-eglstream-Keep-pending-stream-if-the-pixmap.patch +Patch29: 0002-xwayland-eglstream-Remove-stream-validity.patch + +License: MIT + +Requires: xorg-x11-server-common +Requires: libEGL + +BuildRequires: gcc +BuildRequires: git-core +BuildRequires: meson + +BuildRequires: wayland-devel +BuildRequires: pkgconfig(wayland-client) >= 1.3.0 +BuildRequires: pkgconfig(wayland-protocols) +BuildRequires: pkgconfig(wayland-eglstream-protocols) + +BuildRequires: pkgconfig(dmx) +BuildRequires: pkgconfig(epoxy) +BuildRequires: pkgconfig(fontenc) +BuildRequires: pkgconfig(libdrm) >= 2.4.0 +BuildRequires: pkgconfig(libssl) +BuildRequires: pkgconfig(libtirpc) +BuildRequires: pkgconfig(pixman-1) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xau) +BuildRequires: pkgconfig(xdmcp) +BuildRequires: pkgconfig(xext) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(xfont2) +BuildRequires: pkgconfig(xi) +BuildRequires: pkgconfig(xinerama) +BuildRequires: pkgconfig(xkbfile) +BuildRequires: pkgconfig(xmu) +BuildRequires: pkgconfig(xorg-macros) >= 1.17 +BuildRequires: pkgconfig(xpm) +BuildRequires: pkgconfig(xrender) +BuildRequires: pkgconfig(xres) +BuildRequires: pkgconfig(xshmfence) >= 1.1 +BuildRequires: pkgconfig(xtrans) >= 1.3.2 +BuildRequires: pkgconfig(xtst) +BuildRequires: pkgconfig(xv) +BuildRequires: xorg-x11-proto-devel >= 7.7-10 + +BuildRequires: mesa-libGL-devel >= 9.2 +BuildRequires: mesa-libEGL-devel +BuildRequires: mesa-libgbm-devel + +BuildRequires: audit-libs-devel +BuildRequires: libselinux-devel >= 2.0.86-1 + +# libunwind is Exclusive for the following arches +%ifarch aarch64 %{arm} hppa ia64 mips ppc ppc64 %{ix86} x86_64 +%if !0%{?rhel} +BuildRequires: libunwind-devel +%endif +%endif + +BuildRequires: pkgconfig(xcb-aux) +BuildRequires: pkgconfig(xcb-image) +BuildRequires: pkgconfig(xcb-icccm) +BuildRequires: pkgconfig(xcb-keysyms) +BuildRequires: pkgconfig(xcb-renderutil) + +%description +Xwayland is an X server for running X clients under Wayland. + +%package devel +Summary: Development package +Requires: pkgconfig + +%description devel +The development package provides the developmental files which are +necessary for developing Wayland compositors using Xwayland. + +%prep +%autosetup -S git_am -n %{pkgname}-%{?gitdate:%{commit}}%{!?gitdate:%{version}} + +%build +%meson \ + -Dxwayland_eglstream=true \ + -Ddefault_font_path=%{default_font_path} \ + -Dbuilder_string="Build ID: %{name} %{version}-%{release}" \ + -Dxkb_output_dir=%{_localstatedir}/lib/xkb \ + -Dxcsecurity=true \ + -Dglamor=true \ + -Ddri3=true + +%meson_build + +%install +%meson_install + +# Remove unwanted files/dirs +rm $RPM_BUILD_ROOT%{_mandir}/man1/Xserver.1* +rm -Rf $RPM_BUILD_ROOT%{_libdir}/xorg +rm -Rf $RPM_BUILD_ROOT%{_includedir}/xorg +rm -Rf $RPM_BUILD_ROOT%{_datadir}/aclocal +rm -Rf $RPM_BUILD_ROOT%{_localstatedir}/lib/xkb + +%files +%{_bindir}/Xwayland +%{_mandir}/man1/Xwayland.1* + +%files devel +%{_libdir}/pkgconfig/xwayland.pc + +%changelog +* Tue Aug 10 2021 Mohan Boddu - 21.1.1-6 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Mon Aug 9 2021 Olivier Fourdan - 21.1.1-5 +- Backport the latest fixes from Xwayland for EGLstream (rhbz#1977742) + +* Tue Jun 22 2021 Mohan Boddu - 21.1.1-4 +- Rebuilt for RHEL 9 BETA for openssl 3.0 + Related: rhbz#1971065 + +* Mon Jun 21 2021 Olivier Fourdan - 21.1.1-3 +- Fix a use-after-free in the previous changes for GLX + +* Thu Jun 17 2021 Olivier Fourdan - 21.1.1-2 +- Backport fixes for GLX and EGLstream (#1969486) + +* Thu Jun 17 2021 Olivier Fourdan - 21.1.1-1 +- xwayland 21.1.1 (#1952897) + +* Fri Apr 16 2021 Mohan Boddu - 21.1.0-2 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Thu Mar 18 2021 Olivier Fourdan - 21.1.0-1 +- xwayland 21.1.0 + +* Thu Mar 4 2021 Olivier Fourdan - 21.0.99.902-1 +- xwayland 21.0.99.902 +- Remove xdmcp, udev, udev_kms build options +- Stop overriding the vendor name, same as xorg-x11-server + +* Thu Feb 18 2021 Olivier Fourdan - 21.0.99.901-1 +- xwayland 21.0.99.901 + +* Mon Feb 1 2021 Olivier Fourdan - 1.20.99.1-0.1.20210201git5429791 +- Initial import (#1912335).