[Mesa-dev] [PATCH v3] glx/dri3: Use a separate xcb connection for Present events

Axel Davy axel.davy at ens.fr
Sat Apr 18 14:17:55 PDT 2015


Previously glx was using the xcb connection from Xlib.
It is a problem because there are issues if Xlib is used
in another thread (Present event lost)

This patch creates a per-context xcb connection to solve this issue.

Solves: https://bugs.freedesktop.org/show_bug.cgi?id=84252

Tested-by: Tobias Jakobi <tjakobi at math.uni-bielefeld.de>
Signed-off-by: Axel Davy <axel.davy at ens.fr>

v2: use xcb_connection_has_error to check if connection failed, instead
of comparing to NULL (xcb_connect never returns NULL)
v3: put the xcb_connection in dri3_screen, instead of dri3_context
---
There's a strange issue with xcb_get_geometry: If I use the new xcb connection
it fails and the error is a drawable error. If I use the Xlib xcb connection (what
I did in this patch) it works. If anyone knows why, please tell. We use xcb_get_geometry
with gallium nine with a different xcb connection than Xlib and it works without
problem.

 src/glx/dri3_glx.c  | 61 +++++++++++++++++++++++++++++++----------------------
 src/glx/dri3_priv.h |  2 ++
 2 files changed, 38 insertions(+), 25 deletions(-)

diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index 1ddc723..6f028b8 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -285,7 +285,7 @@ dri3_destroy_drawable(__GLXDRIdrawable *base)
 {
    struct dri3_screen *psc = (struct dri3_screen *) base->psc;
    struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
-   xcb_connection_t     *c = XGetXCBConnection(pdraw->base.psc->dpy);
+   xcb_connection_t *c = psc->xcb_connection;
    int i;
 
    (*psc->core->destroyDrawable) (pdraw->driDrawable);
@@ -455,8 +455,9 @@ dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_
 static bool
 dri3_wait_for_event(__GLXDRIdrawable *pdraw)
 {
-   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+   xcb_connection_t *c = psc->xcb_connection;
    xcb_generic_event_t *ev;
    xcb_present_generic_event_t *ge;
 
@@ -478,8 +479,9 @@ static int
 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
                   int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
 {
-   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+   xcb_connection_t *c = psc->xcb_connection;
    uint32_t msc_serial;
 
    /* Ask for the an event for the target MSC */
@@ -578,7 +580,8 @@ dri3_drawable_gc(struct dri3_drawable *priv)
 {
    if (!priv->gc) {
       uint32_t v;
-      xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+      struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+      xcb_connection_t *c = psc->xcb_connection;
 
       v = 0;
       xcb_create_gc(c,
@@ -637,7 +640,7 @@ dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
    struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
    struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
-   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   xcb_connection_t *c = psc->xcb_connection;
    struct dri3_buffer *back;
 
    unsigned flags = __DRI2_FLUSH_DRAWABLE;
@@ -701,7 +704,7 @@ static void
 dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
 {
    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
-   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   xcb_connection_t *c = psc->xcb_connection;
 
    dri3_flush(psc, priv, __DRI2_FLUSH_DRAWABLE, 0);
 
@@ -838,10 +841,9 @@ dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw,
                          unsigned int format, int width, int height, int depth)
 {
    struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
-   Display *dpy = glx_screen->dpy;
    struct dri3_buffer *buffer;
    __DRIimage *pixmap_buffer;
-   xcb_connection_t *c = XGetXCBConnection(dpy);
+   xcb_connection_t *c = psc->xcb_connection;
    xcb_pixmap_t pixmap;
    xcb_sync_fence_t sync_fence;
    struct xshmfence *shm_fence;
@@ -979,7 +981,7 @@ static void
 dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer)
 {
    struct dri3_screen   *psc = (struct dri3_screen *) pdraw->base.psc;
-   xcb_connection_t     *c = XGetXCBConnection(pdraw->base.psc->dpy);
+   xcb_connection_t *c = psc->xcb_connection;
 
    if (buffer->own_pixmap)
       xcb_free_pixmap(c, buffer->pixmap);
@@ -999,7 +1001,8 @@ dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer)
 static void
 dri3_flush_present_events(struct dri3_drawable *priv)
 {
-   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+   xcb_connection_t *c = psc->xcb_connection;
 
    /* Check to see if any configuration changes have occurred
     * since we were last invoked
@@ -1024,7 +1027,9 @@ static int
 dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
 {
    struct dri3_drawable *priv = loaderPrivate;
-   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+   xcb_connection_t *c = psc->xcb_connection;
+   xcb_connection_t *xlib_c = XGetXCBConnection(priv->base.psc->dpy);
 
    /* First time through, go get the current drawable geometry
     */
@@ -1064,9 +1069,9 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
                                                          priv->eid,
                                                          priv->stamp);
 
-      geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
+      geom_cookie = xcb_get_geometry(xlib_c, priv->base.xDrawable);
 
-      geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
+      geom_reply = xcb_get_geometry_reply(xlib_c, geom_cookie, NULL);
 
       if (!geom_reply)
          return false;
@@ -1148,7 +1153,6 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
    xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
    xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
    int                                  *fds;
-   Display                              *dpy;
    struct dri3_screen                   *psc;
    xcb_connection_t                     *c;
    xcb_sync_fence_t                     sync_fence;
@@ -1162,8 +1166,7 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
 
    pixmap = pdraw->base.xDrawable;
    psc = (struct dri3_screen *) pdraw->base.psc;
-   dpy = psc->base.dpy;
-   c = XGetXCBConnection(dpy);
+   c = psc->xcb_connection;
 
    buffer = calloc(1, sizeof (struct dri3_buffer));
    if (!buffer)
@@ -1281,7 +1284,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
    struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
    struct dri3_drawable *priv = loaderPrivate;
    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
-   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
+   xcb_connection_t *c = psc->xcb_connection;
    struct dri3_buffer      *buffer;
    int                  buf_id;
 
@@ -1522,8 +1525,7 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
    struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
-   Display *dpy = priv->base.psc->dpy;
-   xcb_connection_t *c = XGetXCBConnection(dpy);
+   xcb_connection_t *c = psc->xcb_connection;
    struct dri3_buffer *back;
    int64_t ret = 0;
    uint32_t options = XCB_PRESENT_OPTION_NONE;
@@ -1636,8 +1638,9 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
 static int
 dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
 {
-   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+   xcb_connection_t *c = psc->xcb_connection;
    int back_id = DRI3_BACK_ID(dri3_find_back(c, priv));
 
    if (back_id < 0 || !priv->buffers[back_id])
@@ -1654,13 +1657,12 @@ dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
  * Wrapper around xcb_dri3_open
  */
 static int
-dri3_open(Display *dpy,
+dri3_open(xcb_connection_t *c,
           Window root,
           CARD32 provider)
 {
    xcb_dri3_open_cookie_t       cookie;
    xcb_dri3_open_reply_t        *reply;
-   xcb_connection_t             *c = XGetXCBConnection(dpy);
    int                          fd;
 
    cookie = xcb_dri3_open(c,
@@ -1694,6 +1696,7 @@ dri3_destroy_screen(struct glx_screen *base)
    (*psc->core->destroyScreen) (psc->driScreen);
    driDestroyConfigs(psc->driver_configs);
    close(psc->fd);
+   xcb_disconnect(psc->xcb_connection);
    free(psc);
 }
 
@@ -1884,7 +1887,7 @@ static const struct glx_screen_vtable dri3_screen_vtable = {
 static struct glx_screen *
 dri3_create_screen(int screen, struct glx_display * priv)
 {
-   xcb_connection_t *c = XGetXCBConnection(priv->dpy);
+   xcb_connection_t *c = NULL;
    const __DRIconfig **driver_configs;
    const __DRIextension **extensions;
    const struct dri3_display *const pdp = (struct dri3_display *)
@@ -1893,20 +1896,28 @@ dri3_create_screen(int screen, struct glx_display * priv)
    __GLXDRIscreen *psp;
    struct glx_config *configs = NULL, *visuals = NULL;
    char *driverName, *deviceName, *tmp;
-   int i;
+   int screen_num, i;
+
+   /* Create XCB connection for present calls. Do not use the Xlib one,
+    * to prevent issues if application uses Xlib in another thread */
+   screen_num = screen;
+   c = xcb_connect(DisplayString(priv->dpy), &screen_num);
+   if (xcb_connection_has_error(c))
+      return NULL;
 
    psc = calloc(1, sizeof *psc);
    if (psc == NULL)
       return NULL;
 
    psc->fd = -1;
+   psc->xcb_connection = c;
 
    if (!glx_screen_init(&psc->base, screen, priv)) {
       free(psc);
       return NULL;
    }
 
-   psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
+   psc->fd = dri3_open(c, RootWindow(priv->dpy, screen), None);
    if (psc->fd < 0) {
       int conn_error = xcb_connection_has_error(c);
 
diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
index 1604449..a6f3d00 100644
--- a/src/glx/dri3_priv.h
+++ b/src/glx/dri3_priv.h
@@ -139,6 +139,8 @@ struct dri3_screen {
    int is_different_gpu;
 
    int show_fps_interval;
+
+   xcb_connection_t *xcb_connection;
 };
 
 struct dri3_context
-- 
2.1.0



More information about the mesa-dev mailing list