Commit 133bd444 authored by Adam Jackson's avatar Adam Jackson 💣

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's avatarAdam Jackson <ajax@redhat.com>
parent 5d87e4f7
......@@ -1948,6 +1948,18 @@ __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc)
** 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.
*/
......@@ -2079,8 +2091,6 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
glxc = __glXForceCurrent(cl, req->contextTag, &error);
if (!glxc) {
/* Reset in case this isn't 1st request. */
__glXResetLargeCommandStatus(cl);
return error;
}
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) {
client->errorValue = req->length;
/* Reset in case this isn't 1st request. */
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return BadLength;
}
pc += sz_xGLXRenderLargeReq;
if (cl->largeCmdRequestsSoFar == 0) {
if (glxc->largeCmdRequestsSoFar == 0) {
__GLXrenderSizeData entry;
int extra = 0;
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.
*/
if (cl->largeCmdBufSize < cmdlen) {
GLbyte *newbuf = cl->largeCmdBuf;
if (glxc->largeCmdBufSize < cmdlen) {
GLbyte *newbuf = glxc->largeCmdBuf;
if (!(newbuf = realloc(newbuf, cmdlen)))
return BadAlloc;
cl->largeCmdBuf = newbuf;
cl->largeCmdBufSize = cmdlen;
glxc->largeCmdBuf = newbuf;
glxc->largeCmdBufSize = cmdlen;
}
memcpy(cl->largeCmdBuf, pc, dataBytes);
memcpy(glxc->largeCmdBuf, pc, dataBytes);
cl->largeCmdBytesSoFar = dataBytes;
cl->largeCmdBytesTotal = cmdlen;
cl->largeCmdRequestsSoFar = 1;
cl->largeCmdRequestsTotal = req->requestTotal;
glxc->largeCmdBytesSoFar = dataBytes;
glxc->largeCmdBytesTotal = cmdlen;
glxc->largeCmdRequestsSoFar = 1;
glxc->largeCmdRequestsTotal = req->requestTotal;
return Success;
}
......@@ -2185,37 +2195,37 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
/*
** 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;
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return __glXError(GLXBadLargeRequest);
}
if (req->requestTotal != cl->largeCmdRequestsTotal) {
if (req->requestTotal != glxc->largeCmdRequestsTotal) {
client->errorValue = req->requestTotal;
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return __glXError(GLXBadLargeRequest);
}
/*
** 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;
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return __glXError(GLXBadLargeRequest);
}
if (bytesSoFar > cl->largeCmdBytesTotal) {
if (bytesSoFar > glxc->largeCmdBytesTotal) {
client->errorValue = dataBytes;
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return __glXError(GLXBadLargeRequest);
}
memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes);
cl->largeCmdBytesSoFar += dataBytes;
cl->largeCmdRequestsSoFar++;
memcpy(glxc->largeCmdBuf + glxc->largeCmdBytesSoFar, pc, dataBytes);
glxc->largeCmdBytesSoFar += dataBytes;
glxc->largeCmdRequestsSoFar++;
if (req->requestNumber == cl->largeCmdRequestsTotal) {
if (req->requestNumber == glxc->largeCmdRequestsTotal) {
__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
** be accepted by the server.
*/
if (safe_pad(cl->largeCmdBytesSoFar) != cl->largeCmdBytesTotal) {
if (safe_pad(glxc->largeCmdBytesSoFar) != glxc->largeCmdBytesTotal) {
client->errorValue = dataBytes;
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
return __glXError(GLXBadLargeRequest);
}
hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf;
hdr = (__GLXrenderLargeHeader *) glxc->largeCmdBuf;
/*
** The opcode and length field in the header had already been
** 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.
*/
(*proc) (cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
(*proc) (glxc->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
/*
** Reset for the next RenderLarge series.
*/
__glXResetLargeCommandStatus(cl);
ResetLargeCommandStatus(glxc);
}
else {
/*
......
......@@ -112,6 +112,16 @@ struct __GLXcontext {
GLuint *selectBuf;
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
*/
......
......@@ -65,18 +65,6 @@ static DevPrivateKeyRec glxClientPrivateKeyRec;
static int __glXDispatch(ClientPtr);
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
* 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->selectBuf);
free(cx->largeCmdBuf);
if (cx == lastGLContext) {
lastGLContext = NULL;
}
......@@ -270,7 +259,6 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
switch (pClient->clientState) {
case ClientStateGone:
free(cl->returnBuf);
free(cl->largeCmdBuf);
free(cl->GLClientextensions);
cl->returnBuf = NULL;
cl->GLClientextensions = NULL;
......@@ -591,6 +579,9 @@ xorgGlxCreateVendor(void)
__GLXcontext *
__glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
{
ClientPtr client = cl->client;
REQUEST(xGLXSingleReq);
__GLXcontext *cx;
/*
......@@ -604,6 +595,13 @@ __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
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->drawPriv == NULL) {
/*
......@@ -710,13 +708,6 @@ __glXDispatch(ClientPtr client)
opcode = stuff->glxCode;
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)
cl->client = client;
......
......@@ -57,7 +57,6 @@ extern Bool __glXAddContext(__GLXcontext * cx);
extern void __glXErrorCallBack(GLenum code);
extern void __glXClearErrorOccured(void);
extern GLboolean __glXErrorOccured(void);
extern void __glXResetLargeCommandStatus(__GLXclientState *);
extern const char GLServerVersion[];
extern int DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap);
......
......@@ -115,16 +115,6 @@ struct __GLXclientStateRec {
GLbyte *returnBuf;
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 */
ClientPtr client;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment