I've found a problem in the server-side swapbuffers code while testing
with the DRI. Here's the function from the ogl-sample glx/server/glxcmds.c
file:
int __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc)
{
ClientPtr client = cl->client;
DrawablePtr pDraw;
xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc;
GLXContextTag tag = req->contextTag;
XID drawId = req->drawable;
__GLXpixmap *pGlxPixmap;
__GLXcontext *glxc = NULL;
int error;
/*
** Check that the GLX drawable is valid.
*/
pDraw = (DrawablePtr) LookupDrawable(drawId, client);
if (pDraw) {
if (pDraw->type == DRAWABLE_WINDOW) {
/*
** Drawable is an X window.
*/
} else {
/*
** Drawable is an X pixmap, which is not allowed.
*/
client->errorValue = drawId;
return __glXBadDrawable;
}
} else {
pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId,
__glXPixmapRes);
if (pGlxPixmap) {
/*
** Drawable is a GLX pixmap.
*/
} else {
/*
** Drawable is neither a X window nor a GLX pixmap.
*/
client->errorValue = drawId;
return __glXBadDrawable;
}
}
if (tag) {
glxc = __glXLookupContextByTag(cl, tag);
if (!glxc) {
return __glXBadContextTag;
}
/*
** The calling thread is swapping its current drawable. In this case,
** glxSwapBuffers is in both GL and X streams, in terms of
** sequentiality.
*/
if (__glXForceCurrent(cl, tag, &error)) {
/*
** Do whatever is needed to make sure that all preceding requests
** in both streams are completed before the swap is executed.
*/
glFinish();
__GLX_NOTE_FLUSHED_CMDS(glxc);
} else {
return error;
}
}
if (pDraw) {
__GLXdrawablePrivate *glxPriv;
glxPriv = __glXGetDrawablePrivate(pDraw, drawId, glxc->modes);
if (glxPriv == NULL) {
return __glXBadDrawable;
}
if ((*glxPriv->swapBuffers)(glxPriv) == GL_FALSE) {
return __glXBadDrawable;
}
}
return Success;
}
If <tag> is 0, then <glxc> will be NULL when we reach the call to
__glXGetDrawablePrivate(). Dereferencing glxc->modes causes a segfault.
<tag> can legally be zero. This happens when the user calls glXSwapBuffers()
for a window which is not currently bound to a rendering context.
The client-side glXSwapBuffers() code explicity sets the context tag to zero
when the user does this.
Replacing the end of the function with this code seems to fix the problem:
[...]
if (pDraw) {
__GLXdrawablePrivate *glxPriv;
if (glxc) {
glxPriv = __glXGetDrawablePrivate(pDraw, drawId, glxc->modes);
if (glxPriv == NULL) {
return __glXBadDrawable;
}
}
else {
glxPriv = __glXFindDrawablePrivate(drawId);
if (glxPriv == NULL) {
/* This is a window we've never seen before, do nothing */
return Success;
}
}
if ((*glxPriv->swapBuffers)(glxPriv) == GL_FALSE) {
return __glXBadDrawable;
}
}
return Success;
}
I'm simply returning Success when attempting to do a swap on a window
which the GLX code has never encountered before. I'm not sure what
else can be done.
I'm checking this change into the XFree86/DRI code. If this looks OK
someone should probably update the ogl-sample code too.
-Brian
|