You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
738 lines
20 KiB
C
738 lines
20 KiB
C
/*
|
|
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
|
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice including the dates of first publication and
|
|
* either this permission notice or a reference to
|
|
* http://oss.sgi.com/projects/FreeB/
|
|
* shall be included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
|
* shall not be used in advertising or otherwise to promote the sale, use or
|
|
* other dealings in this Software without prior written authorization from
|
|
* Silicon Graphics, Inc.
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include "glxserver.h"
|
|
#include <windowstr.h>
|
|
#include <propertyst.h>
|
|
#include <registry.h>
|
|
#include "privates.h"
|
|
#include <os.h>
|
|
#include "extinit.h"
|
|
#include "glx_extinit.h"
|
|
#include "unpack.h"
|
|
#include "glxutil.h"
|
|
#include "glxext.h"
|
|
#include "indirect_table.h"
|
|
#include "indirect_util.h"
|
|
#include "glxvndabi.h"
|
|
|
|
/*
|
|
** X resources.
|
|
*/
|
|
static int glxGeneration;
|
|
RESTYPE __glXContextRes;
|
|
RESTYPE __glXDrawableRes;
|
|
|
|
static DevPrivateKeyRec glxClientPrivateKeyRec;
|
|
static GlxServerVendor *glvnd_vendor = NULL;
|
|
|
|
#define glxClientPrivateKey (&glxClientPrivateKeyRec)
|
|
|
|
/*
|
|
** Forward declarations.
|
|
*/
|
|
static int __glXDispatch(ClientPtr);
|
|
static GLboolean __glXFreeContext(__GLXcontext * cx);
|
|
|
|
/*
|
|
* 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
|
|
* 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)
|
|
{
|
|
if (!cx)
|
|
return TRUE;
|
|
|
|
if (!cx->currentClient)
|
|
__glXFreeContext(cx);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static __GLXcontext *glxPendingDestroyContexts;
|
|
static __GLXcontext *glxAllContexts;
|
|
static int glxBlockClients;
|
|
|
|
/*
|
|
** Destroy routine that gets called when a drawable is freed. A drawable
|
|
** contains the ancillary buffers needed for rendering.
|
|
*/
|
|
static Bool
|
|
DrawableGone(__GLXdrawable * glxPriv, XID xid)
|
|
{
|
|
__GLXcontext *c, *next;
|
|
|
|
if (glxPriv->type == GLX_DRAWABLE_WINDOW) {
|
|
/* If this was created by glXCreateWindow, free the matching resource */
|
|
if (glxPriv->drawId != glxPriv->pDraw->id) {
|
|
if (xid == glxPriv->drawId)
|
|
FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE);
|
|
else
|
|
FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE);
|
|
}
|
|
/* otherwise this window was implicitly created by MakeCurrent */
|
|
}
|
|
|
|
for (c = glxAllContexts; c; c = next) {
|
|
next = c->next;
|
|
if (c->currentClient &&
|
|
(c->drawPriv == glxPriv || c->readPriv == glxPriv)) {
|
|
/* flush the context */
|
|
glFlush();
|
|
/* just force a re-bind the next time through */
|
|
(*c->loseCurrent) (c);
|
|
lastGLContext = NULL;
|
|
}
|
|
if (c->drawPriv == glxPriv)
|
|
c->drawPriv = NULL;
|
|
if (c->readPriv == glxPriv)
|
|
c->readPriv = NULL;
|
|
}
|
|
|
|
/* drop our reference to any backing pixmap */
|
|
if (glxPriv->type == GLX_DRAWABLE_PIXMAP)
|
|
glxPriv->pDraw->pScreen->DestroyPixmap((PixmapPtr) glxPriv->pDraw);
|
|
|
|
glxPriv->destroy(glxPriv);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
__glXAddContext(__GLXcontext * cx)
|
|
{
|
|
/* Register this context as a resource.
|
|
*/
|
|
if (!AddResource(cx->id, __glXContextRes, (void *)cx)) {
|
|
return FALSE;
|
|
}
|
|
|
|
cx->next = glxAllContexts;
|
|
glxAllContexts = cx;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
__glXRemoveFromContextList(__GLXcontext * cx)
|
|
{
|
|
__GLXcontext *c, *prev;
|
|
|
|
if (cx == glxAllContexts)
|
|
glxAllContexts = cx->next;
|
|
else {
|
|
prev = glxAllContexts;
|
|
for (c = glxAllContexts; c; c = c->next) {
|
|
if (c == cx)
|
|
prev->next = c->next;
|
|
prev = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Free a context.
|
|
*/
|
|
static GLboolean
|
|
__glXFreeContext(__GLXcontext * cx)
|
|
{
|
|
if (cx->idExists || cx->currentClient)
|
|
return GL_FALSE;
|
|
|
|
__glXRemoveFromContextList(cx);
|
|
|
|
free(cx->feedbackBuf);
|
|
free(cx->selectBuf);
|
|
free(cx->largeCmdBuf);
|
|
if (cx == lastGLContext) {
|
|
lastGLContext = NULL;
|
|
}
|
|
|
|
/* We can get here through both regular dispatching from
|
|
* __glXDispatch() or as a callback from the resource manager. In
|
|
* the latter case we need to lift the DRI lock manually. */
|
|
|
|
if (!glxBlockClients) {
|
|
cx->destroy(cx);
|
|
}
|
|
else {
|
|
cx->next = glxPendingDestroyContexts;
|
|
glxPendingDestroyContexts = cx;
|
|
}
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
/*
|
|
** These routines can be used to check whether a particular GL command
|
|
** has caused an error. Specifically, we use them to check whether a
|
|
** given query has caused an error, in which case a zero-length data
|
|
** reply is sent to the client.
|
|
*/
|
|
|
|
static GLboolean errorOccured = GL_FALSE;
|
|
|
|
/*
|
|
** The GL was will call this routine if an error occurs.
|
|
*/
|
|
void
|
|
__glXErrorCallBack(GLenum code)
|
|
{
|
|
errorOccured = GL_TRUE;
|
|
}
|
|
|
|
/*
|
|
** Clear the error flag before calling the GL command.
|
|
*/
|
|
void
|
|
__glXClearErrorOccured(void)
|
|
{
|
|
errorOccured = GL_FALSE;
|
|
}
|
|
|
|
/*
|
|
** Check if the GL command caused an error.
|
|
*/
|
|
GLboolean
|
|
__glXErrorOccured(void)
|
|
{
|
|
return errorOccured;
|
|
}
|
|
|
|
static int __glXErrorBase;
|
|
int __glXEventBase;
|
|
|
|
int
|
|
__glXError(int error)
|
|
{
|
|
return __glXErrorBase + error;
|
|
}
|
|
|
|
__GLXclientState *
|
|
glxGetClient(ClientPtr pClient)
|
|
{
|
|
return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
|
|
}
|
|
|
|
static void
|
|
glxClientCallback(CallbackListPtr *list, void *closure, void *data)
|
|
{
|
|
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
|
|
ClientPtr pClient = clientinfo->client;
|
|
__GLXclientState *cl = glxGetClient(pClient);
|
|
|
|
switch (pClient->clientState) {
|
|
case ClientStateGone:
|
|
free(cl->returnBuf);
|
|
free(cl->GLClientextensions);
|
|
cl->returnBuf = NULL;
|
|
cl->GLClientextensions = NULL;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
static __GLXprovider *__glXProviderStack = &__glXDRISWRastProvider;
|
|
|
|
void
|
|
GlxPushProvider(__GLXprovider * provider)
|
|
{
|
|
provider->next = __glXProviderStack;
|
|
__glXProviderStack = provider;
|
|
}
|
|
|
|
static Bool
|
|
checkScreenVisuals(void)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < screenInfo.numScreens; i++) {
|
|
ScreenPtr screen = screenInfo.screens[i];
|
|
for (j = 0; j < screen->numVisuals; j++) {
|
|
if ((screen->visuals[j].class == TrueColor ||
|
|
screen->visuals[j].class == DirectColor) &&
|
|
screen->visuals[j].nplanes > 12)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
GetGLXDrawableBytes(void *value, XID id, ResourceSizePtr size)
|
|
{
|
|
__GLXdrawable *draw = value;
|
|
|
|
size->resourceSize = 0;
|
|
size->pixmapRefSize = 0;
|
|
size->refCnt = 1;
|
|
|
|
if (draw->type == GLX_DRAWABLE_PIXMAP) {
|
|
SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
|
|
ResourceSizeRec pixmapSize = { 0, };
|
|
pixmapSizeFunc((PixmapPtr)draw->pDraw, draw->pDraw->id, &pixmapSize);
|
|
size->pixmapRefSize += pixmapSize.pixmapRefSize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
xorgGlxCloseExtension(const ExtensionEntry *extEntry)
|
|
{
|
|
if (glvnd_vendor != NULL) {
|
|
glxServer.destroyVendor(glvnd_vendor);
|
|
glvnd_vendor = NULL;
|
|
}
|
|
lastGLContext = NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* If we're creating a resource, add the map now */
|
|
if (resource) {
|
|
LEGAL_NEW_RESOURCE(resource, client);
|
|
if (!glxServer.addXIDMap(resource, vendor))
|
|
return BadAlloc;
|
|
}
|
|
|
|
ret = glxServer.forwardRequest(vendor, client);
|
|
|
|
if (ret == Success && vendorCode == X_GLXvop_DestroyGLXPbufferSGIX) {
|
|
xGLXDestroyGLXPbufferSGIXReq *req = (void *)stuff;
|
|
glxServer.removeXIDMap(maybe_swap32(client, req->pbuffer));
|
|
}
|
|
|
|
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 void
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
xorgGlxServerInit(CallbackListPtr *pcbl, void *param, void *ext)
|
|
{
|
|
const ExtensionEntry *extEntry = ext;
|
|
int i;
|
|
|
|
if (!xorgGlxServerPreInit(extEntry)) {
|
|
return;
|
|
}
|
|
|
|
xorgGlxInitGLVNDVendor();
|
|
if (!glvnd_vendor) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < screenInfo.numScreens; 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 = p->screenProbe(pScreen);
|
|
if (glxScreen != NULL) {
|
|
LogMessage(X_INFO,
|
|
"GLX: Initialized %s GL provider for screen %d\n",
|
|
p->name, i);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (p) {
|
|
glxServer.setScreenVendor(pScreen, glvnd_vendor);
|
|
} else {
|
|
LogMessage(X_INFO,
|
|
"GLX: no usable GL providers found for screen %d\n", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool
|
|
xorgGlxCreateVendor(void)
|
|
{
|
|
return AddCallback(glxServer.extensionInitCallback, xorgGlxServerInit, NULL);
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
/*
|
|
** Make a context the current one for the GL (in this implementation, there
|
|
** is only one instance of the GL, and we use it to serve all GL clients by
|
|
** switching it between different contexts). While we are at it, look up
|
|
** a context by its tag and return its (__GLXcontext *).
|
|
*/
|
|
__GLXcontext *
|
|
__glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
|
|
{
|
|
ClientPtr client = cl->client;
|
|
REQUEST(xGLXSingleReq);
|
|
|
|
__GLXcontext *cx;
|
|
|
|
/*
|
|
** See if the context tag is legal; it is managed by the extension,
|
|
** so if it's invalid, we have an implementation error.
|
|
*/
|
|
cx = __glXLookupContextByTag(cl, tag);
|
|
if (!cx) {
|
|
cl->client->errorValue = tag;
|
|
*error = __glXError(GLXBadContextTag);
|
|
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) {
|
|
/*
|
|
** The drawable has vanished. It must be a window, because only
|
|
** windows can be destroyed from under us; GLX pixmaps are
|
|
** refcounted and don't go away until no one is using them.
|
|
*/
|
|
*error = __glXError(GLXBadCurrentWindow);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (cx->wait && (*cx->wait) (cx, cl, error))
|
|
return NULL;
|
|
|
|
if (cx == lastGLContext) {
|
|
/* No need to re-bind */
|
|
return cx;
|
|
}
|
|
|
|
/* Make this context the current one for the GL. */
|
|
if (!cx->isDirect) {
|
|
/*
|
|
* If it is being forced, it means that this context was already made
|
|
* current. So it cannot just be made current again without decrementing
|
|
* refcount's
|
|
*/
|
|
(*cx->loseCurrent) (cx);
|
|
lastGLContext = cx;
|
|
if (!(*cx->makeCurrent) (cx)) {
|
|
/* Bind failed, and set the error code. Bummer */
|
|
lastGLContext = NULL;
|
|
cl->client->errorValue = cx->id;
|
|
*error = __glXError(GLXBadContextState);
|
|
return 0;
|
|
}
|
|
}
|
|
return cx;
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
void
|
|
glxSuspendClients(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (clients[i] && glxGetClient(clients[i])->client)
|
|
IgnoreClient(clients[i]);
|
|
}
|
|
|
|
glxBlockClients = TRUE;
|
|
}
|
|
|
|
void
|
|
glxResumeClients(void)
|
|
{
|
|
__GLXcontext *cx, *next;
|
|
int i;
|
|
|
|
glxBlockClients = FALSE;
|
|
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (clients[i] && glxGetClient(clients[i])->client)
|
|
AttendClient(clients[i]);
|
|
}
|
|
|
|
for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
|
|
next = cx->next;
|
|
|
|
cx->destroy(cx);
|
|
}
|
|
glxPendingDestroyContexts = NULL;
|
|
}
|
|
|
|
static glx_gpa_proc _get_proc_address;
|
|
|
|
void
|
|
__glXsetGetProcAddress(glx_gpa_proc get_proc_address)
|
|
{
|
|
_get_proc_address = get_proc_address;
|
|
}
|
|
|
|
void *__glGetProcAddress(const char *proc)
|
|
{
|
|
void *ret = (void *) _get_proc_address(proc);
|
|
|
|
return ret ? ret : (void *) NoopDDA;
|
|
}
|
|
|
|
/*
|
|
** Top level dispatcher; all commands are executed from here down.
|
|
*/
|
|
static int
|
|
__glXDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xGLXSingleReq);
|
|
CARD8 opcode;
|
|
__GLXdispatchSingleProcPtr proc;
|
|
__GLXclientState *cl;
|
|
int retval = BadRequest;
|
|
|
|
opcode = stuff->glxCode;
|
|
cl = glxGetClient(client);
|
|
|
|
|
|
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) {
|
|
ResetCurrentRequest(client);
|
|
client->sequence--;
|
|
IgnoreClient(client);
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
** Use the opcode to index into the procedure table.
|
|
*/
|
|
proc = __glXGetProtocolDecodeFunction(&Single_dispatch_info, opcode,
|
|
client->swapped);
|
|
if (proc != NULL)
|
|
retval = (*proc) (cl, (GLbyte *) stuff);
|
|
|
|
return retval;
|
|
}
|