From cf643f9b4fa2fcda764fc0fd1e714b73aa349241 Mon Sep 17 00:00:00 2001 From: Axel Davy Date: Fri, 17 Apr 2015 19:24:52 +0200 Subject: [PATCH] glx/dri3: Use a separate xcb connection for Present events 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 Signed-off-by: Axel Davy 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 v4: add XSync before the xcb_get_geometry call to prevent drawable errors --- src/glx/dri3_glx.c | 59 ++++++++++++++++++++++++++++++++--------------------- src/glx/dri3_priv.h | 2 ++ 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index 1ddc723..921fb3d 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,8 @@ 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; /* First time through, go get the current drawable geometry */ @@ -1064,6 +1068,9 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) priv->eid, priv->stamp); + /* Make sure the drawable creation is done */ + XSync(priv->base.psc->dpy, false); + geom_cookie = xcb_get_geometry(c, priv->base.xDrawable); geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL); @@ -1148,7 +1155,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 +1168,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 +1286,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 +1527,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 +1640,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 +1659,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 +1698,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 +1889,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 +1898,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