xserver: Branch 'xwayland-21.1' - 27 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Jun 23 10:44:08 UTC 2021


 glamor/glamor.c                         |    1 
 glx/glxcmds.c                           |   16 
 hw/xwayland/xwayland-cursor.c           |   11 
 hw/xwayland/xwayland-glamor-eglstream.c |  600 +++++++++++++++++++++++++-------
 hw/xwayland/xwayland-glamor-gbm.c       |  186 ---------
 hw/xwayland/xwayland-glamor.c           |  216 ++++++++++-
 hw/xwayland/xwayland-glamor.h           |   24 -
 hw/xwayland/xwayland-glx.c              |    3 
 hw/xwayland/xwayland-present.c          |   12 
 hw/xwayland/xwayland-screen.h           |    4 
 hw/xwayland/xwayland-window.c           |   13 
 11 files changed, 746 insertions(+), 340 deletions(-)

New commits:
commit 763f4fb27849923e7e70f217b1467ef98df1d526
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Jun 3 17:51:01 2021 +0200

    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 <ekurzinger at nvidia.com> for spotting the issue.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    (cherry picked from commit c468d34c7208c9041f9c077b54a00ae9cccad6a3)
    (cherry picked from commit aad61e8e03311eb8bae4f7db59e65634733eadc2)

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;
commit e754b473d1ed35a8d39e0c199efefb65364acbe1
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Thu Dec 10 14:24:32 2020 -0800

    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 <ekurzinger at nvidia.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    (cherry picked from commit b7a85e44da91d1663d5b4eabac06327c92a80f91)

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) {
commit 831426afd1832c6a671cac5d29bda15736dce68e
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu May 20 16:46:33 2021 +0200

    xwayland/eglstream: Log when GL_OES_EGL_image is missing
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 34a58d7714025bc1043bf5282358406eb10e4b8e)

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;
commit 2e1bb50644ce2553451da74506f8f26cb7222a8f
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon May 17 18:20:57 2021 +0200

    xwayland/eglstream: Use "nvidia" for GLVND
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit fae58e9b03696a3890f9c876306c68ffa6f9ff30)

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;
commit 8744ab1b417018888d2d1192a09aae16d06fc20c
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu May 20 12:11:42 2021 +0200

    xwayland: Add preferred GLVND vendor to xwl_screen
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 24fc8aea1e4bbaba780f1a316fba797a0198f603)

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,
commit f4720f1c42cb9fec3edfa8e871f8557b038e2aad
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Tue May 11 17:00:21 2021 -0400

    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 <ekurzinger at nvidia.com>
    (cherry picked from commit 7515c23a416825f0db51f9b445279b12d5918ebf)

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") &&
commit b2963fccc186b384af22891a7f73892c93a7ba39
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Fri May 14 08:26:49 2021 -0400

    xwayland/eglstream: allow commits to dma-buf backed pixmaps
    
    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 <ekurzinger at nvidia.com>
    Acked-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 3d33d885fcd1215a74c1819278cf6f9557c9860b)

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
commit bdb4712da34c743fae3d971590761d6fe3859e3c
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Apr 30 16:23:10 2021 +0200

    xwayland/eglstream: Set ALU to GXCopy for blitting
    
    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 <ofourdan at redhat.com>
    Suggested-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 012350e3db47fef0404346f55968032e62004fcf)

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 <glamor_egl.h>
 #include <glamor.h>
+#include <glamor_priv.h>
 #include <glamor_transform.h>
 #include <glamor_transfer.h>
 
@@ -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 ||
commit 96febe8ba46d7a177f9d26ec69dfbcfd72b0ceae
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue May 4 10:56:38 2021 +0200

    xwayland/eglstream: Do not always increment pixmap refcnt on commit
    
    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 <ofourdan at redhat.com>
    Suggested-by: Michel Dänzer <mdaenzer at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit d85bfa6ab7495281516f3a4b05dc1ff0b2c4bf91)

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 */
commit 7d839b3ed342e89948481e2cc796ef575d412cb5
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Apr 30 09:02:29 2021 +0200

    xwayland/eglstream: Check eglSwapBuffers()
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit b583395cd38ad101c7541bd8b0e91143ced44703)

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 */
commit 8b8a9bf6c7dd6b606ed22878ee7decefe507ba01
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Apr 19 14:52:38 2021 +0200

    xwayland/eglstream: Fix calloc/malloc
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit a45799971083c47082d085d3732a5b12692cf75b)

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);
commit 15e550cc9a5a7fff7f97d74e22cf96bcb0fbf568
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Apr 19 18:11:19 2021 +0200

    xwayland/eglstream: Do not commit without surface
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 098e0f52c088c6eb52c7e54c5a11cefabd480908)

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);
         }
     }
 
commit 01319a9006d32286b73bdff0417bd7da47d2724d
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Apr 27 14:17:19 2021 +0200

    xwayland/eglstream: Drop the list of pending streams
    
    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 <ofourdan at redhat.com>
    Suggested-by: Michel Dänzer <mdaenzer at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit bee2ebb29f0999862ab39af26c673c00af40b082)

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;
commit 77617490fc9182896e12cc7668f1957178e27eb2
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Apr 14 17:31:08 2021 +0200

    xwayland/eglstream: Keep a reference to the pixmap
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    Fixes: affc47452 xwayland: Drop the separate refcount for the xwl_pixmap
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit e19bf86c17ef9c802fea24410cc6b1f51a19ce7f)

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);
commit b05b19df014bccfc28650ae1ce150b9bb25bcfdd
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Apr 16 10:38:23 2021 +0200

    xwayland/eglstream: Dissociate pending stream from window
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit cb61ecc7291cfbed2f76d4437cd7450b8e4dab00)

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;
 }
 
commit 1cce4bfd684116a8af936ca2ca1756482ed246cb
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Apr 1 08:46:52 2021 +0200

    xwayland/eglstream: Add more error checking
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit cc596bcfb273eeab82ac3d59867668af8bad2abf)

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 =
commit 526cb24826d576c016048fe6e3143efa6d50a176
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Thu Apr 15 10:59:36 2021 +0200

    xwayland/eglstream: Small refactoring
    
    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 <ofourdan at redhat.com>
    Acked-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 823f3254fabd16e5e721da57cd260beac9b8f8bd)

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;
 }
commit 72790f7446996a354d08de6db7a8b35a2d793e68
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Mar 31 09:49:35 2021 +0200

    xwayland/eglstream: Check framebuffer status
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 85244d2a2081d61a2e4a06e847041f638de01e3f)

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
commit 46dc7e8ee355a97fb422f2dcc6f12bbaeb4a1c0c
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Mar 31 13:57:45 2021 +0200

    xwayland/glamor: Add return status to post_damage
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 252cbad316f43edc08aa5c844789398a58ba270c)

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);
commit 673676e759427fd30799e45c12600268c240fc39
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Tue Mar 30 08:48:25 2021 +0200

    glamor: Dump backtrace on GL error
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Martin Peres <martin.peres at mupuf.org>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 3b265c59a6456f6e4abfb9e1694237bc56f1776a)

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();
 }
 
 /**
commit 740f00d44f5b2b6eed22474b1067903c82f1aa8c
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Mar 29 15:01:15 2021 +0200

    xwayland: Check buffer prior to attaching it
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Martin Peres <martin.peres at mupuf.org>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 25d2f4948f0abd39e099b8ac69b7cb1dab38a10a)

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);
commit 8499fc0671666399a906f976fe6c57c5759a1e9e
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Mon Mar 29 14:22:56 2021 +0200

    xwayland/eglstream: Check buffer creation
    
    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 <ofourdan at redhat.com>
    Reviewed-by: Martin Peres <martin.peres at mupuf.org>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
    (cherry picked from commit 4f0889e98306d30a37aba0fadb1fd3790c13205a)

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
commit d60acf6f0b403b8f0f026c3ffcdae0c9b57a60bd
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Tue Apr 27 07:23:44 2021 -0400

    xwayland-eglstream: fix X11 rendering to flipping GL / VK window
    
    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 <ekurzinger at nvidia.com>
    Acked-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
    (cherry picked from commit 4f6fbd5009ae533cf0b3bbe382502254f9276a01)

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
commit 3d10978cb635db46facacf9667d2090e3f90b28c
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Thu Dec 3 14:57:51 2020 -0800

    xwayland: implement pixmap_from_buffers for the eglstream backend
    
    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 <mdaenzer at redhat.com>
    Acked-by: Olivier Fourdan <ofourdan at redhat.com>
    Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
    (cherry picked from commit 38e875904b039ec1889e7c81eb1d577a4f69b26d)

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 <glamor_transfer.h>
 
 #include <xf86drm.h>
+#include <dri3.h>
+#include <drm_fourcc.h>
 
 #include <epoxy/egl.h>
 
@@ -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))
commit f44b22b0c6178736124bd7f6991c04049639f792
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Wed Mar 3 11:56:41 2021 +0100

    xwayland: Add check_flip() glamor backend function
    
    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 <mdaenzer at redhat.com>
    Acked-by: Olivier Fourdan <ofourdan at redhat.com>
    Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
    (cherry picked from commit bc99dd2127f12f1aae55971c09a2792eeaa98444)

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 */
commit 15d3756814755fa9af59166705d957d9d0e4fbb2
Author: Erik Kurzinger <ekurzinger at nvidia.com>
Date:   Fri Feb 12 12:09:27 2021 -0800

    xwayland: move formats and modifiers functions to common glamor code
    
    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 <mdaenzer at redhat.com>
    Acked-by: Olivier Fourdan <ofourdan at redhat.com>
    Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
    (cherry picked from commit 400d4d0fdd55192f394e1a8273dfb2423c895ec0)

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 */
commit 1f65893873cf65e96c90d6001b7bce82f5a55ccc
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Mar 3 09:55:12 2021 +0100

    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 <ofourdan at redhat.com>
    (cherry picked from commit ae225417c0a0828ffb24e11eb4b968c34692e25a)

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 <drm_fourcc.h>
+
 #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;


More information about the xorg-commit mailing list