glx: Large commands are context state, not client state
There's no reason a multithreaded client shouldn't be allowed to interleave other requests (for other contexts) with a RenderLarge. Move the check into __glXForceCurrent, and store the state in the context not the client. Signed-off-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
5d87e4f713
commit
133bd4443b
|
@ -1948,6 +1948,18 @@ __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc)
|
||||||
** client library to send batches of GL rendering commands.
|
** client library to send batches of GL rendering commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Reset state used to keep track of large (multi-request) commands.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ResetLargeCommandStatus(__GLXcontext *cx)
|
||||||
|
{
|
||||||
|
cx->largeCmdBytesSoFar = 0;
|
||||||
|
cx->largeCmdBytesTotal = 0;
|
||||||
|
cx->largeCmdRequestsSoFar = 0;
|
||||||
|
cx->largeCmdRequestsTotal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Execute all the drawing commands in a request.
|
** Execute all the drawing commands in a request.
|
||||||
*/
|
*/
|
||||||
|
@ -2079,8 +2091,6 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
|
|
||||||
glxc = __glXForceCurrent(cl, req->contextTag, &error);
|
glxc = __glXForceCurrent(cl, req->contextTag, &error);
|
||||||
if (!glxc) {
|
if (!glxc) {
|
||||||
/* Reset in case this isn't 1st request. */
|
|
||||||
__glXResetLargeCommandStatus(cl);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
if (safe_pad(req->dataBytes) < 0)
|
if (safe_pad(req->dataBytes) < 0)
|
||||||
|
@ -2093,12 +2103,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
if ((req->length << 2) != safe_pad(dataBytes) + sz_xGLXRenderLargeReq) {
|
if ((req->length << 2) != safe_pad(dataBytes) + sz_xGLXRenderLargeReq) {
|
||||||
client->errorValue = req->length;
|
client->errorValue = req->length;
|
||||||
/* Reset in case this isn't 1st request. */
|
/* Reset in case this isn't 1st request. */
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return BadLength;
|
return BadLength;
|
||||||
}
|
}
|
||||||
pc += sz_xGLXRenderLargeReq;
|
pc += sz_xGLXRenderLargeReq;
|
||||||
|
|
||||||
if (cl->largeCmdRequestsSoFar == 0) {
|
if (glxc->largeCmdRequestsSoFar == 0) {
|
||||||
__GLXrenderSizeData entry;
|
__GLXrenderSizeData entry;
|
||||||
int extra = 0;
|
int extra = 0;
|
||||||
int left = (req->length << 2) - sz_xGLXRenderLargeReq;
|
int left = (req->length << 2) - sz_xGLXRenderLargeReq;
|
||||||
|
@ -2157,21 +2167,21 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
/*
|
/*
|
||||||
** Make enough space in the buffer, then copy the entire request.
|
** Make enough space in the buffer, then copy the entire request.
|
||||||
*/
|
*/
|
||||||
if (cl->largeCmdBufSize < cmdlen) {
|
if (glxc->largeCmdBufSize < cmdlen) {
|
||||||
GLbyte *newbuf = cl->largeCmdBuf;
|
GLbyte *newbuf = glxc->largeCmdBuf;
|
||||||
|
|
||||||
if (!(newbuf = realloc(newbuf, cmdlen)))
|
if (!(newbuf = realloc(newbuf, cmdlen)))
|
||||||
return BadAlloc;
|
return BadAlloc;
|
||||||
|
|
||||||
cl->largeCmdBuf = newbuf;
|
glxc->largeCmdBuf = newbuf;
|
||||||
cl->largeCmdBufSize = cmdlen;
|
glxc->largeCmdBufSize = cmdlen;
|
||||||
}
|
}
|
||||||
memcpy(cl->largeCmdBuf, pc, dataBytes);
|
memcpy(glxc->largeCmdBuf, pc, dataBytes);
|
||||||
|
|
||||||
cl->largeCmdBytesSoFar = dataBytes;
|
glxc->largeCmdBytesSoFar = dataBytes;
|
||||||
cl->largeCmdBytesTotal = cmdlen;
|
glxc->largeCmdBytesTotal = cmdlen;
|
||||||
cl->largeCmdRequestsSoFar = 1;
|
glxc->largeCmdRequestsSoFar = 1;
|
||||||
cl->largeCmdRequestsTotal = req->requestTotal;
|
glxc->largeCmdRequestsTotal = req->requestTotal;
|
||||||
return Success;
|
return Success;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2185,37 +2195,37 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
/*
|
/*
|
||||||
** Check the request number and the total request count.
|
** Check the request number and the total request count.
|
||||||
*/
|
*/
|
||||||
if (req->requestNumber != cl->largeCmdRequestsSoFar + 1) {
|
if (req->requestNumber != glxc->largeCmdRequestsSoFar + 1) {
|
||||||
client->errorValue = req->requestNumber;
|
client->errorValue = req->requestNumber;
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return __glXError(GLXBadLargeRequest);
|
return __glXError(GLXBadLargeRequest);
|
||||||
}
|
}
|
||||||
if (req->requestTotal != cl->largeCmdRequestsTotal) {
|
if (req->requestTotal != glxc->largeCmdRequestsTotal) {
|
||||||
client->errorValue = req->requestTotal;
|
client->errorValue = req->requestTotal;
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return __glXError(GLXBadLargeRequest);
|
return __glXError(GLXBadLargeRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check that we didn't get too much data.
|
** Check that we didn't get too much data.
|
||||||
*/
|
*/
|
||||||
if ((bytesSoFar = safe_add(cl->largeCmdBytesSoFar, dataBytes)) < 0) {
|
if ((bytesSoFar = safe_add(glxc->largeCmdBytesSoFar, dataBytes)) < 0) {
|
||||||
client->errorValue = dataBytes;
|
client->errorValue = dataBytes;
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return __glXError(GLXBadLargeRequest);
|
return __glXError(GLXBadLargeRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesSoFar > cl->largeCmdBytesTotal) {
|
if (bytesSoFar > glxc->largeCmdBytesTotal) {
|
||||||
client->errorValue = dataBytes;
|
client->errorValue = dataBytes;
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return __glXError(GLXBadLargeRequest);
|
return __glXError(GLXBadLargeRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes);
|
memcpy(glxc->largeCmdBuf + glxc->largeCmdBytesSoFar, pc, dataBytes);
|
||||||
cl->largeCmdBytesSoFar += dataBytes;
|
glxc->largeCmdBytesSoFar += dataBytes;
|
||||||
cl->largeCmdRequestsSoFar++;
|
glxc->largeCmdRequestsSoFar++;
|
||||||
|
|
||||||
if (req->requestNumber == cl->largeCmdRequestsTotal) {
|
if (req->requestNumber == glxc->largeCmdRequestsTotal) {
|
||||||
__GLXdispatchRenderProcPtr proc;
|
__GLXdispatchRenderProcPtr proc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2231,12 +2241,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
** fixes a bug that did not allow large commands of odd sizes to
|
** fixes a bug that did not allow large commands of odd sizes to
|
||||||
** be accepted by the server.
|
** be accepted by the server.
|
||||||
*/
|
*/
|
||||||
if (safe_pad(cl->largeCmdBytesSoFar) != cl->largeCmdBytesTotal) {
|
if (safe_pad(glxc->largeCmdBytesSoFar) != glxc->largeCmdBytesTotal) {
|
||||||
client->errorValue = dataBytes;
|
client->errorValue = dataBytes;
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
return __glXError(GLXBadLargeRequest);
|
return __glXError(GLXBadLargeRequest);
|
||||||
}
|
}
|
||||||
hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf;
|
hdr = (__GLXrenderLargeHeader *) glxc->largeCmdBuf;
|
||||||
/*
|
/*
|
||||||
** The opcode and length field in the header had already been
|
** The opcode and length field in the header had already been
|
||||||
** swapped when the first request was received.
|
** swapped when the first request was received.
|
||||||
|
@ -2256,12 +2266,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
|
||||||
/*
|
/*
|
||||||
** Skip over the header and execute the command.
|
** Skip over the header and execute the command.
|
||||||
*/
|
*/
|
||||||
(*proc) (cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
|
(*proc) (glxc->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Reset for the next RenderLarge series.
|
** Reset for the next RenderLarge series.
|
||||||
*/
|
*/
|
||||||
__glXResetLargeCommandStatus(cl);
|
ResetLargeCommandStatus(glxc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -112,6 +112,16 @@ struct __GLXcontext {
|
||||||
GLuint *selectBuf;
|
GLuint *selectBuf;
|
||||||
GLint selectBufSize; /* number of elements allocated */
|
GLint selectBufSize; /* number of elements allocated */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Keep track of large rendering commands, which span multiple requests.
|
||||||
|
*/
|
||||||
|
GLint largeCmdBytesSoFar; /* bytes received so far */
|
||||||
|
GLint largeCmdBytesTotal; /* total bytes expected */
|
||||||
|
GLint largeCmdRequestsSoFar; /* requests received so far */
|
||||||
|
GLint largeCmdRequestsTotal; /* total requests expected */
|
||||||
|
GLbyte *largeCmdBuf;
|
||||||
|
GLint largeCmdBufSize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The drawable private this context is bound to
|
** The drawable private this context is bound to
|
||||||
*/
|
*/
|
||||||
|
|
31
glx/glxext.c
31
glx/glxext.c
|
@ -65,18 +65,6 @@ static DevPrivateKeyRec glxClientPrivateKeyRec;
|
||||||
static int __glXDispatch(ClientPtr);
|
static int __glXDispatch(ClientPtr);
|
||||||
static GLboolean __glXFreeContext(__GLXcontext * cx);
|
static GLboolean __glXFreeContext(__GLXcontext * cx);
|
||||||
|
|
||||||
/*
|
|
||||||
** Reset state used to keep track of large (multi-request) commands.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
__glXResetLargeCommandStatus(__GLXclientState * cl)
|
|
||||||
{
|
|
||||||
cl->largeCmdBytesSoFar = 0;
|
|
||||||
cl->largeCmdBytesTotal = 0;
|
|
||||||
cl->largeCmdRequestsSoFar = 0;
|
|
||||||
cl->largeCmdRequestsTotal = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This procedure is called when the client who created the context goes away
|
* This procedure is called when the client who created the context goes away
|
||||||
* OR when glXDestroyContext is called. If the context is current for a client
|
* OR when glXDestroyContext is called. If the context is current for a client
|
||||||
|
@ -188,6 +176,7 @@ __glXFreeContext(__GLXcontext * cx)
|
||||||
|
|
||||||
free(cx->feedbackBuf);
|
free(cx->feedbackBuf);
|
||||||
free(cx->selectBuf);
|
free(cx->selectBuf);
|
||||||
|
free(cx->largeCmdBuf);
|
||||||
if (cx == lastGLContext) {
|
if (cx == lastGLContext) {
|
||||||
lastGLContext = NULL;
|
lastGLContext = NULL;
|
||||||
}
|
}
|
||||||
|
@ -270,7 +259,6 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
|
||||||
switch (pClient->clientState) {
|
switch (pClient->clientState) {
|
||||||
case ClientStateGone:
|
case ClientStateGone:
|
||||||
free(cl->returnBuf);
|
free(cl->returnBuf);
|
||||||
free(cl->largeCmdBuf);
|
|
||||||
free(cl->GLClientextensions);
|
free(cl->GLClientextensions);
|
||||||
cl->returnBuf = NULL;
|
cl->returnBuf = NULL;
|
||||||
cl->GLClientextensions = NULL;
|
cl->GLClientextensions = NULL;
|
||||||
|
@ -591,6 +579,9 @@ xorgGlxCreateVendor(void)
|
||||||
__GLXcontext *
|
__GLXcontext *
|
||||||
__glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
|
__glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
|
||||||
{
|
{
|
||||||
|
ClientPtr client = cl->client;
|
||||||
|
REQUEST(xGLXSingleReq);
|
||||||
|
|
||||||
__GLXcontext *cx;
|
__GLXcontext *cx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -604,6 +595,13 @@ __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we're expecting a glXRenderLarge request, this better be one. */
|
||||||
|
if (cx->largeCmdRequestsSoFar != 0 && stuff->glxCode != X_GLXRenderLarge) {
|
||||||
|
client->errorValue = stuff->glxCode;
|
||||||
|
*error = __glXError(GLXBadLargeRequest);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cx->isDirect) {
|
if (!cx->isDirect) {
|
||||||
if (cx->drawPriv == NULL) {
|
if (cx->drawPriv == NULL) {
|
||||||
/*
|
/*
|
||||||
|
@ -710,13 +708,6 @@ __glXDispatch(ClientPtr client)
|
||||||
opcode = stuff->glxCode;
|
opcode = stuff->glxCode;
|
||||||
cl = glxGetClient(client);
|
cl = glxGetClient(client);
|
||||||
|
|
||||||
/*
|
|
||||||
** If we're expecting a glXRenderLarge request, this better be one.
|
|
||||||
*/
|
|
||||||
if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) {
|
|
||||||
client->errorValue = stuff->glxCode;
|
|
||||||
return __glXError(GLXBadLargeRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cl->client)
|
if (!cl->client)
|
||||||
cl->client = client;
|
cl->client = client;
|
||||||
|
|
|
@ -57,7 +57,6 @@ extern Bool __glXAddContext(__GLXcontext * cx);
|
||||||
extern void __glXErrorCallBack(GLenum code);
|
extern void __glXErrorCallBack(GLenum code);
|
||||||
extern void __glXClearErrorOccured(void);
|
extern void __glXClearErrorOccured(void);
|
||||||
extern GLboolean __glXErrorOccured(void);
|
extern GLboolean __glXErrorOccured(void);
|
||||||
extern void __glXResetLargeCommandStatus(__GLXclientState *);
|
|
||||||
|
|
||||||
extern const char GLServerVersion[];
|
extern const char GLServerVersion[];
|
||||||
extern int DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap);
|
extern int DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap);
|
||||||
|
|
|
@ -115,16 +115,6 @@ struct __GLXclientStateRec {
|
||||||
GLbyte *returnBuf;
|
GLbyte *returnBuf;
|
||||||
GLint returnBufSize;
|
GLint returnBufSize;
|
||||||
|
|
||||||
/*
|
|
||||||
** Keep track of large rendering commands, which span multiple requests.
|
|
||||||
*/
|
|
||||||
GLint largeCmdBytesSoFar; /* bytes received so far */
|
|
||||||
GLint largeCmdBytesTotal; /* total bytes expected */
|
|
||||||
GLint largeCmdRequestsSoFar; /* requests received so far */
|
|
||||||
GLint largeCmdRequestsTotal; /* total requests expected */
|
|
||||||
GLbyte *largeCmdBuf;
|
|
||||||
GLint largeCmdBufSize;
|
|
||||||
|
|
||||||
/* Back pointer to X client record */
|
/* Back pointer to X client record */
|
||||||
ClientPtr client;
|
ClientPtr client;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue