A couple style nits below. At least some of this patch will have to change pending possible changes to patch 3. Aside from that, I think this is ok.
On 11/14/2017 12:13 PM, Adam Jackson wrote: > 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, which is why the > diff is a little uglier than I'd like. > > Signed-off-by: Adam Jackson <a...@redhat.com> > --- > src/glx/glxcurrent.c | 181 > +++++++++++++++++++++++++++++++++++++------------ > src/glx/indirect_glx.c | 125 ++++------------------------------ > 2 files changed, 151 insertions(+), 155 deletions(-) > > diff --git a/src/glx/glxcurrent.c b/src/glx/glxcurrent.c > index 9f8bf7cee1..7ee8a04a60 100644 > --- a/src/glx/glxcurrent.c > +++ b/src/glx/glxcurrent.c > @@ -165,17 +165,85 @@ glXGetCurrentDrawable(void) > return gc->currentDrawable; > } > > -/** > - * Make a particular context current. > - * > - * \note This is in this file so that it can access dummyContext. > - */ > +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 ((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 void > +SetGC(struct glx_context *gc, Display *dpy, GLXDrawable draw, GLXDrawable > read) > +{ > + gc->currentDpy = dpy; > + gc->currentDrawable = draw; > + gc->currentReadable = read; > +} > + > static Bool > MakeContextCurrent(Display * dpy, GLXDrawable draw, > GLXDrawable read, GLXContext gc_user) > { > struct glx_context *gc = (struct glx_context *) gc_user; > struct glx_context *oldGC = __glXGetCurrentContext(); > + Bool ret = GL_FALSE; > > /* Make sure that the new context has a nonzero ID. In the request, > * a zero context ID is used only to mean that we bind to no current > @@ -186,59 +254,86 @@ MakeContextCurrent(Display * dpy, GLXDrawable draw, > } > > _glapi_check_multithread(); > - > __glXLock(); > + > + /* Same context and drawables: no op, just return */ > if (oldGC == gc && > - gc->currentDrawable == draw && gc->currentReadable == read) { > - __glXUnlock(); > - return True; > + gc->currentDrawable == draw && > + gc->currentReadable == read) { > + ret = GL_TRUE; > } > > - if (oldGC != &dummyContext) { > - if (--oldGC->thread_refcount == 0) { > - oldGC->vtable->unbind(oldGC, gc); > - oldGC->currentDpy = 0; > + /* Same context and new drawbles: update drawable bindings */ > + else if (oldGC == gc) { I'm not a fan of if () { ... } /* comment */ else if () { ... } I think the comment should move inside the else and the else should go back with the }. > + if (!SendMakeCurrentRequest(dpy, gc->xid, gc->currentContextTag, > + draw, read, &gc->currentContextTag)) { > + goto out; > } > - } > > - if (gc) { > - /* Attempt to bind the context. We do this before mucking with > - * gc and __glXSetCurrentContext to properly handle our state in > - * case of an error. > - * > - * If an error occurs, set the Null context since we've already > - * blown away our old context. The caller is responsible for > - * figuring out how to handle setting a valid context. > - */ > - if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { > + if (gc->vtable->bind(gc, gc, draw, read) != Success) { > __glXSetCurrentContextNull(); > - __glXUnlock(); > - __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent, > - False); > - return GL_FALSE; > + goto out; > } > + } > > - if (gc->thread_refcount == 0) { > - gc->currentDpy = dpy; > - gc->currentDrawable = draw; > - gc->currentReadable = read; > + /* Different contexts: release the old, bind the new */ > + else { > + if (oldGC != &dummyContext) { > + if (--oldGC->thread_refcount == 0) { > + if (!SendMakeCurrentRequest(dpy, None, oldGC->currentContextTag, > + None, None, > &oldGC->currentContextTag)){ ^ Space before the {. > + goto out; > + } > + > + oldGC->vtable->unbind(oldGC, gc); > + > + if (!oldGC->xid == None) { > + /* destroyed context, free it */ > + oldGC->vtable->destroy(oldGC); > + } else { > + SetGC(oldGC, NULL, None, None); > + } > + } > } > - gc->thread_refcount++; > - __glXSetCurrentContext(gc); > - } else { > __glXSetCurrentContextNull(); > - } > > - if (oldGC->thread_refcount == 0 && oldGC != &dummyContext && oldGC->xid > == None) { > - /* We are switching away from a context that was > - * previously destroyed, so we need to free the memory > - * for the old handle. */ > - oldGC->vtable->destroy(oldGC); > + if (gc) { > + /* > + * MESA_multithread_makecurrent makes this complicated. We need to > send > + * the request if the new context is > + * > + * a) indirect (may be current to another client), or > + * b) (direct and) newly being made current, or > + * c) (direct and) being bound to new drawables > + */ > + Bool new_drawables = (gc->currentReadable != read) || > + (gc->currentDrawable != draw); I know krh would complain about the (not strictly necessary) parens. > + > + if (!gc->isDirect || !gc->thread_refcount || new_drawables) { > + if (!SendMakeCurrentRequest(dpy, gc->xid, > oldGC->currentContextTag, > + draw, read, &gc->currentContextTag)) > { > + goto out; > + } > + } > + > + if (gc->vtable->bind(gc, oldGC, draw, read) != Success) { > + __glXSendError(dpy, GLXBadContext, None, X_GLXMakeContextCurrent, > + False); > + goto out; > + } > + > + if (gc->thread_refcount == 0) { > + SetGC(gc, dpy, draw, read); > + } Since the body and the condition are each only one line, the { and } are optional. This is a fairly recent Mesa style change. > + gc->thread_refcount++; > + __glXSetCurrentContext(gc); > + } > } > + ret = GL_TRUE; > > +out: > __glXUnlock(); > - > - return GL_TRUE; > + return ret; > } > > > diff --git a/src/glx/indirect_glx.c b/src/glx/indirect_glx.c > index b552b5768a..8ac8fd1b47 100644 > --- a/src/glx/indirect_glx.c > +++ b/src/glx/indirect_glx.c > @@ -61,129 +61,30 @@ 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; > - } > - > - 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. > - */ > - __GLXattribute *state = gc->client_state_private; > - if (state && state->array_state == NULL) { > - glGetString(GL_EXTENSIONS); > - glGetString(GL_VERSION); > - __glXInitVertexArrayState(gc); > - } > + 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. > + */ > + __GLXattribute *state = gc->client_state_private; > + if (state && state->array_state == NULL) { > + glGetString(GL_EXTENSIONS); > + glGetString(GL_VERSION); > + __glXInitVertexArrayState(gc); > } > > - return !sent; > + return state != NULL && state->array_state != NULL; > } > > static void > indirect_unbind_context(struct glx_context *gc, struct glx_context *new) > { Mark the parameters UNUSED so that I don't get extra warnings. :) > - 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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev