mirror of
https://github.com/X11Libre/xserver.git
synced 2026-11-01 03:03:58 +00:00
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:
parent
8753218bea
commit
d8ec33fe05
23 changed files with 326 additions and 375 deletions
341
glx/glxext.c
341
glx/glxext.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue