diff options
author | Adam Jackson <[email protected]> | 2017-11-14 15:13:04 -0500 |
---|---|---|
committer | Adam Jackson <[email protected]> | 2019-09-23 20:39:01 -0400 |
commit | 999c2aed8826f403b071f52b040ce25b56d35f9d (patch) | |
tree | 09458e714f9954fc30ee54009781a778973e2178 /src/glx/indirect_glx.c | |
parent | 01e437988d7b34065059cc1715aedd09adaf5cdd (diff) |
glx: Lift sending the MakeCurrent request to top-level code
Somewhat terrifyingly, we never sent this for direct contexts, which
means the server never knew the context/drawable bindings. To handle
this sanely, pull the request code up out of the indirect backend, and
rewrite the context switch path to call it as appropriate. This
attempts to preserve the existing behavior of not calling unbind() on
the context if its refcount would not drop to zero.
Of course, you can't just do this indiscriminately, because this is GLX
and extant X servers have bugs and everything is terrible. To wit:
- For 1.20.x prior to 1.20.6, you can bind a direct context once, but
the second time you try to modify the context's binding you will get
GLXBadContextTag. This includes unbinding the context. And "deleting"
the context will leak memory, because it will still appear to be
current.
- For 1.19 and earlier, glXMakeCurrent(dpy, None, ctx) should be legal
for GL 3.0+ contexts, but the server will throw BadMatch.
To guard against this, we only send the request for indirect contexts
unless the server is known good, and only mention one context at a time
in such a request; if switching between contexts, we first unbind the
old, and then bind the new. Note that the second VendorRelease() version
is to catch XFree86 4.x and Xorg [67].x, which almost certainly have the
above bugs. Other servers might report different version numbers here,
but we can't do direct rendering against them, so this should be safe.
Fixes glx-make-context, glx-multi-window-single-context and
glx-query-drawable-glx_fbconfig_id-window. Sufficiently old piglit will
regress on glx-make-glxdrawable-current (throwing BadMatch), which is
fixed by mesa/piglit!116.
Diffstat (limited to 'src/glx/indirect_glx.c')
-rw-r--r-- | src/glx/indirect_glx.c | 140 |
1 files changed, 23 insertions, 117 deletions
diff --git a/src/glx/indirect_glx.c b/src/glx/indirect_glx.c index f370daf8bb6..c23db139165 100644 --- a/src/glx/indirect_glx.c +++ b/src/glx/indirect_glx.c @@ -61,135 +61,41 @@ indirect_destroy_context(struct glx_context *gc) free((char *) gc); } -static Bool -SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id, - GLXContextTag gc_tag, GLXDrawable draw, - GLXDrawable read, GLXContextTag *out_tag) -{ - xGLXMakeCurrentReply reply; - Bool ret; - int opcode = __glXSetupForCommand(dpy); - - LockDisplay(dpy); - - if (draw == read) { - xGLXMakeCurrentReq *req; - - GetReq(GLXMakeCurrent, req); - req->reqType = opcode; - req->glxCode = X_GLXMakeCurrent; - req->drawable = draw; - req->context = gc_id; - req->oldContextTag = gc_tag; - } - else { - struct glx_display *priv = __glXInitialize(dpy); - - /* If the server can support the GLX 1.3 version, we should - * perfer that. Not only that, some servers support GLX 1.3 but - * not the SGI extension. - */ - - if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { - xGLXMakeContextCurrentReq *req; - - GetReq(GLXMakeContextCurrent, req); - req->reqType = opcode; - req->glxCode = X_GLXMakeContextCurrent; - req->drawable = draw; - req->readdrawable = read; - req->context = gc_id; - req->oldContextTag = gc_tag; - } - else { - xGLXVendorPrivateWithReplyReq *vpreq; - xGLXMakeCurrentReadSGIReq *req; - - GetReqExtra(GLXVendorPrivateWithReply, - sz_xGLXMakeCurrentReadSGIReq - - sz_xGLXVendorPrivateWithReplyReq, vpreq); - req = (xGLXMakeCurrentReadSGIReq *) vpreq; - req->reqType = opcode; - req->glxCode = X_GLXVendorPrivateWithReply; - req->vendorCode = X_GLXvop_MakeCurrentReadSGI; - req->drawable = draw; - req->readable = read; - req->context = gc_id; - req->oldContextTag = gc_tag; - } - } - - ret = _XReply(dpy, (xReply *) &reply, 0, False); - - if (out_tag) - *out_tag = reply.contextTag; - - UnlockDisplay(dpy); - SyncHandle(); - - return ret; -} - static int indirect_bind_context(struct glx_context *gc, struct glx_context *old, GLXDrawable draw, GLXDrawable read) { - GLXContextTag tag; - Display *dpy = gc->psc->dpy; - Bool sent; - - if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) { - tag = old->currentContextTag; - old->currentContextTag = 0; - } else { - tag = 0; + __GLXattribute *state = gc->client_state_private; + + if (!IndirectAPI) + IndirectAPI = __glXNewIndirectAPI(); + _glapi_set_dispatch(IndirectAPI); + + /* The indirect vertex array state must to be initialised after we + * have setup the context, as it needs to query server attributes. + * + * At the point this is called gc->currentDpy is not initialized + * nor is the thread's current context actually set. Hence the + * cleverness before the GetString calls. + */ + if (state && state->array_state == NULL) { + gc->currentDpy = gc->psc->dpy; + __glXSetCurrentContext(gc); + __glXSetCurrentContext(gc); + __indirect_glGetString(GL_EXTENSIONS); + __indirect_glGetString(GL_VERSION); + __glXInitVertexArrayState(gc); } - sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read, - &gc->currentContextTag); - - if (sent) { - if (!IndirectAPI) - IndirectAPI = __glXNewIndirectAPI(); - _glapi_set_dispatch(IndirectAPI); - - /* The indirect vertex array state must to be initialised after we - * have setup the context, as it needs to query server attributes. - * - * At the point this is called gc->currentDpy is not initialized - * nor is the thread's current context actually set. Hence the - * cleverness before the GetString calls. - */ - __GLXattribute *state = gc->client_state_private; - if (state && state->array_state == NULL) { - gc->currentDpy = gc->psc->dpy; - __glXSetCurrentContext(gc); - __indirect_glGetString(GL_EXTENSIONS); - __indirect_glGetString(GL_VERSION); - __glXInitVertexArrayState(gc); - } - } + if (state != NULL && state->array_state != NULL) + return Success; - return !sent; + return BadAlloc; } static void indirect_unbind_context(struct glx_context *gc, struct glx_context *new) { - Display *dpy = gc->psc->dpy; - - if (gc == new) - return; - - /* We are either switching to no context, away from an indirect - * context to a direct context or from one dpy to another and have - * to send a request to the dpy to unbind the previous context. - */ - if (!new || new->isDirect || new->psc->dpy != dpy) { - SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None, - NULL); - gc->currentContextTag = 0; - } } static void |