glx: Use vnd layer for dispatch (v4)

The big change here is MakeCurrent and context tag tracking. We now
delegate context tags entirely to the vnd layer, and simply store a
pointer to the context state as the tag data. If a context is deleted
while it's current, we allocate a fake ID for the context and move the
context state there, so the tag data still points to a real context. As
a result we can stop trying so hard to detach the client from contexts
at disconnect time and just let resource destruction handle it.

Since vnd handles all the MakeCurrent protocol now, our request handlers
for it can just be return BadImplementation. We also remove a bunch of
LEGAL_NEW_RESOURCE, because now by the time we're called vnd has already
allocated its tracking resource on that XID.

v2: Update to match v2 of the vnd import, and remove more redundant work
like request length checks.

v3: Add/remove the XID map from the vendor private thunk, not the
backend. (Kyle Brenneman)

v4: Fix deletion of ghost contexts (Kyle Brenneman)

Signed-off-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Adam Jackson 2018-01-10 13:05:45 -05:00
commit d8ec33fe05
23 changed files with 326 additions and 375 deletions

View file

@ -46,10 +46,12 @@
#include "glxext.h"
#include "indirect_table.h"
#include "indirect_util.h"
#include "glxvndabi.h"
/*
** X resources.
*/
static int glxGeneration;
RESTYPE __glXContextRes;
RESTYPE __glXDrawableRes;
@ -63,15 +65,6 @@ static DevPrivateKeyRec glxClientPrivateKeyRec;
static int __glXDispatch(ClientPtr);
static GLboolean __glXFreeContext(__GLXcontext * cx);
/*
** Called when the extension is reset.
*/
static void
ResetExtension(ExtensionEntry * extEntry)
{
lastGLContext = NULL;
}
/*
** Reset state used to keep track of large (multi-request) commands.
*/
@ -86,16 +79,18 @@ __glXResetLargeCommandStatus(__GLXclientState * cl)
/*
* This procedure is called when the client who created the context goes away
* OR when glXDestroyContext is called. In either case, all we do is flag that
* the ID is no longer valid, and (maybe) free the context.
* OR when glXDestroyContext is called. If the context is current for a client
* the dispatch layer will have moved the context struct to a fake resource ID
* and cx here will be NULL. Otherwise we really free the context.
*/
static int
ContextGone(__GLXcontext * cx, XID id)
{
cx->idExists = GL_FALSE;
if (!cx->currentClient) {
if (!cx)
return TRUE;
if (!cx->currentClient)
__glXFreeContext(cx);
}
return TRUE;
}
@ -271,29 +266,14 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
ClientPtr pClient = clientinfo->client;
__GLXclientState *cl = glxGetClient(pClient);
__GLXcontext *c, *next;
switch (pClient->clientState) {
case ClientStateRunning:
cl->client = pClient;
break;
case ClientStateGone:
/* detach from all current contexts */
for (c = glxAllContexts; c; c = next) {
next = c->next;
if (c->currentClient == pClient) {
c->loseCurrent(c);
lastGLContext = NULL;
c->currentClient = NULL;
FreeResourceByType(c->id, __glXContextRes, FALSE);
}
}
free(cl->returnBuf);
free(cl->largeCmdBuf);
free(cl->GLClientextensions);
memset(cl, 0, sizeof(*cl));
cl->returnBuf = NULL;
cl->GLClientextensions = NULL;
break;
default:
@ -303,7 +283,7 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
/************************************************************************/
static __GLXprovider *__glXProviderStack;
static __GLXprovider *__glXProviderStack = &__glXDRISWRastProvider;
void
GlxPushProvider(__GLXprovider * provider)
@ -346,50 +326,236 @@ GetGLXDrawableBytes(void *value, XID id, ResourceSizePtr size)
}
}
/*
** Initialize the GLX extension.
*/
void
GlxExtensionInit(void)
static void
xorgGlxCloseExtension(const ExtensionEntry *extEntry)
{
ExtensionEntry *extEntry;
ScreenPtr pScreen;
int i;
__GLXprovider *p, **stack;
Bool glx_provided = FALSE;
lastGLContext = NULL;
}
if (serverGeneration == 1) {
for (stack = &__glXProviderStack; *stack; stack = &(*stack)->next)
;
*stack = &__glXDRISWRastProvider;
static int
xorgGlxHandleRequest(ClientPtr client)
{
return __glXDispatch(client);
}
static ScreenPtr
screenNumToScreen(int screen)
{
if (screen < 0 || screen >= screenInfo.numScreens)
return NULL;
return screenInfo.screens[screen];
}
static int
maybe_swap32(ClientPtr client, int x)
{
return client->swapped ? bswap_32(x) : x;
}
static GlxServerVendor *
vendorForScreen(ClientPtr client, int screen)
{
screen = maybe_swap32(client, screen);
return glxServer.getVendorForScreen(client, screenNumToScreen(screen));
}
/* this ought to be generated */
static int
xorgGlxThunkRequest(ClientPtr client)
{
REQUEST(xGLXVendorPrivateReq);
CARD32 vendorCode = maybe_swap32(client, stuff->vendorCode);
GlxServerVendor *vendor = NULL;
XID resource = 0;
int ret;
switch (vendorCode) {
case X_GLXvop_QueryContextInfoEXT: {
xGLXQueryContextInfoEXTReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
if (!(vendor = glxServer.getXIDMap(maybe_swap32(client, req->context))))
return __glXError(GLXBadContext);
break;
}
case X_GLXvop_GetFBConfigsSGIX: {
xGLXGetFBConfigsSGIXReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
if (!(vendor = vendorForScreen(client, req->screen)))
return BadValue;
break;
}
case X_GLXvop_CreateContextWithConfigSGIX: {
xGLXCreateContextWithConfigSGIXReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
resource = maybe_swap32(client, req->context);
if (!(vendor = vendorForScreen(client, req->screen)))
return BadValue;
break;
}
case X_GLXvop_CreateGLXPixmapWithConfigSGIX: {
xGLXCreateGLXPixmapWithConfigSGIXReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
resource = maybe_swap32(client, req->glxpixmap);
if (!(vendor = vendorForScreen(client, req->screen)))
return BadValue;
break;
}
case X_GLXvop_CreateGLXPbufferSGIX: {
xGLXCreateGLXPbufferSGIXReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
resource = maybe_swap32(client, req->pbuffer);
if (!(vendor = vendorForScreen(client, req->screen)))
return BadValue;
break;
}
/* same offset for the drawable for these three */
case X_GLXvop_DestroyGLXPbufferSGIX:
case X_GLXvop_ChangeDrawableAttributesSGIX:
case X_GLXvop_GetDrawableAttributesSGIX: {
xGLXGetDrawableAttributesSGIXReq *req = (void *)stuff;
REQUEST_AT_LEAST_SIZE(*req);
if (!(vendor = glxServer.getXIDMap(maybe_swap32(client,
req->drawable))))
return __glXError(GLXBadDrawable);
break;
}
/* most things just use the standard context tag */
default: {
/* size checked by vnd layer already */
GLXContextTag tag = maybe_swap32(client, stuff->contextTag);
vendor = glxServer.getContextTag(client, tag);
if (!vendor)
return __glXError(GLXBadContextTag);
break;
}
}
/* Mesa requires at least one True/DirectColor visual */
if (!checkScreenVisuals())
return;
/* If we're creating a resource, add the map now */
if (resource) {
LEGAL_NEW_RESOURCE(resource, client);
if (!glxServer.addXIDMap(resource, vendor))
return BadAlloc;
}
__glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
"GLXContext");
__glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
"GLXDrawable");
if (!__glXContextRes || !__glXDrawableRes)
return;
ret = glxServer.forwardRequest(vendor, client);
SetResourceTypeSizeFunc(__glXDrawableRes, GetGLXDrawableBytes);
if (ret == Success && vendorCode == X_GLXvop_DestroyGLXPbufferSGIX) {
xGLXDestroyGLXPbufferSGIXReq *req = (void *)stuff;
glxServer.removeXIDMap(maybe_swap32(client, req->pbuffer));
}
if (!dixRegisterPrivateKey
(&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
if (ret != Success)
glxServer.removeXIDMap(resource);
return ret;
}
static GlxServerDispatchProc
xorgGlxGetDispatchAddress(CARD8 minorOpcode, CARD32 vendorCode)
{
/* we don't support any other GLX opcodes */
if (minorOpcode != X_GLXVendorPrivate &&
minorOpcode != X_GLXVendorPrivateWithReply)
return NULL;
/* we only support some vendor private requests */
if (!__glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, vendorCode,
FALSE))
return NULL;
return xorgGlxThunkRequest;
}
static Bool
xorgGlxServerPreInit(const ExtensionEntry *extEntry)
{
if (glxGeneration != serverGeneration) {
/* Mesa requires at least one True/DirectColor visual */
if (!checkScreenVisuals())
return FALSE;
__glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
"GLXContext");
__glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
"GLXDrawable");
if (!__glXContextRes || !__glXDrawableRes)
return FALSE;
if (!dixRegisterPrivateKey
(&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
return FALSE;
if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
return FALSE;
__glXErrorBase = extEntry->errorBase;
__glXEventBase = extEntry->eventBase;
SetResourceTypeSizeFunc(__glXDrawableRes, GetGLXDrawableBytes);
#if PRESENT
__glXregisterPresentCompleteNotify();
#endif
glxGeneration = serverGeneration;
}
return glxGeneration == serverGeneration;
}
static GlxServerVendor *glvnd_vendor = NULL;
static GlxServerVendor *
xorgGlxInitGLVNDVendor(void)
{
if (glvnd_vendor == NULL) {
GlxServerImports *imports = NULL;
imports = glxServer.allocateServerImports();
if (imports != NULL) {
imports->extensionCloseDown = xorgGlxCloseExtension;
imports->handleRequest = xorgGlxHandleRequest;
imports->getDispatchAddress = xorgGlxGetDispatchAddress;
imports->makeCurrent = xorgGlxMakeCurrent;
glvnd_vendor = glxServer.createVendor(imports);
glxServer.freeServerImports(imports);
}
}
return glvnd_vendor;
}
static void
xorgGlxServerInit(CallbackListPtr *pcbl, void *param, void *ext)
{
const ExtensionEntry *extEntry = ext;
int i;
if (!xorgGlxServerPreInit(extEntry)) {
return;
if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
}
if (!xorgGlxInitGLVNDVendor()) {
return;
}
for (i = 0; i < screenInfo.numScreens; i++) {
pScreen = screenInfo.screens[i];
ScreenPtr pScreen = screenInfo.screens[i];
__GLXprovider *p;
if (glxServer.getVendorForScreen(NULL, pScreen) != NULL) {
// There's already a vendor registered.
LogMessage(X_INFO, "GLX: Another vendor is already registered for screen %d\n", i);
continue;
}
for (p = __glXProviderStack; p != NULL; p = p->next) {
__GLXscreen *glxScreen;
glxScreen = p->screenProbe(pScreen);
__GLXscreen *glxScreen = p->screenProbe(pScreen);
if (glxScreen != NULL) {
LogMessage(X_INFO,
"GLX: Initialized %s GL provider for screen %d\n",
@ -399,33 +565,19 @@ GlxExtensionInit(void)
}
if (!p)
if (p) {
glxServer.setScreenVendor(pScreen, glvnd_vendor);
} else {
LogMessage(X_INFO,
"GLX: no usable GL providers found for screen %d\n", i);
else
glx_provided = TRUE;
}
}
}
/* don't register extension if GL is not provided on any screen */
if (!glx_provided)
return;
/*
** Add extension to server extensions.
*/
extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
__GLX_NUMBER_ERRORS, __glXDispatch,
__glXDispatch, ResetExtension, StandardMinorOpcode);
if (!extEntry) {
FatalError("__glXExtensionInit: AddExtensions failed\n");
return;
}
__glXErrorBase = extEntry->errorBase;
__glXEventBase = extEntry->eventBase;
#if PRESENT
__glXregisterPresentCompleteNotify();
#endif
Bool
xorgGlxCreateVendor(void)
{
return AddCallback(glxServer.extensionInitCallback, xorgGlxServerInit, NULL);
}
/************************************************************************/
@ -500,7 +652,7 @@ glxSuspendClients(void)
int i;
for (i = 1; i < currentMaxClients; i++) {
if (clients[i] && glxGetClient(clients[i])->inUse)
if (glxGetClient(clients[i])->client)
IgnoreClient(clients[i]);
}
@ -516,7 +668,7 @@ glxResumeClients(void)
glxBlockClients = FALSE;
for (i = 1; i < currentMaxClients; i++) {
if (clients[i] && glxGetClient(clients[i])->inUse)
if (glxGetClient(clients[i])->client)
AttendClient(clients[i]);
}
@ -553,12 +705,10 @@ __glXDispatch(ClientPtr client)
CARD8 opcode;
__GLXdispatchSingleProcPtr proc;
__GLXclientState *cl;
int retval;
int retval = BadRequest;
opcode = stuff->glxCode;
cl = glxGetClient(client);
/* Mark it in use so we suspend it on VT switch. */
cl->inUse = TRUE;
/*
** If we're expecting a glXRenderLarge request, this better be one.
@ -568,6 +718,9 @@ __glXDispatch(ClientPtr client)
return __glXError(GLXBadLargeRequest);
}
if (!cl->client)
cl->client = client;
/* If we're currently blocking GLX clients, just put this guy to
* sleep, reset the request and return. */
if (glxBlockClients) {
@ -582,12 +735,8 @@ __glXDispatch(ClientPtr client)
*/
proc = __glXGetProtocolDecodeFunction(&Single_dispatch_info, opcode,
client->swapped);
if (proc != NULL) {
if (proc != NULL)
retval = (*proc) (cl, (GLbyte *) stuff);
}
else {
retval = BadRequest;
}
return retval;
}