xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

glxext.c (20195B)


      1 /*
      2  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
      3  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice including the dates of first publication and
     13  * either this permission notice or a reference to
     14  * http://oss.sgi.com/projects/FreeB/
     15  * shall be included in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     22  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Except as contained in this notice, the name of Silicon Graphics, Inc.
     26  * shall not be used in advertising or otherwise to promote the sale, use or
     27  * other dealings in this Software without prior written authorization from
     28  * Silicon Graphics, Inc.
     29  */
     30 
     31 #ifdef HAVE_DIX_CONFIG_H
     32 #include <dix-config.h>
     33 #endif
     34 
     35 #include <string.h>
     36 #include "glxserver.h"
     37 #include <windowstr.h>
     38 #include <propertyst.h>
     39 #include <registry.h>
     40 #include "privates.h"
     41 #include <os.h>
     42 #include "extinit.h"
     43 #include "glx_extinit.h"
     44 #include "unpack.h"
     45 #include "glxutil.h"
     46 #include "glxext.h"
     47 #include "indirect_table.h"
     48 #include "indirect_util.h"
     49 #include "glxvndabi.h"
     50 
     51 /*
     52 ** X resources.
     53 */
     54 static int glxGeneration;
     55 RESTYPE __glXContextRes;
     56 RESTYPE __glXDrawableRes;
     57 
     58 static DevPrivateKeyRec glxClientPrivateKeyRec;
     59 static GlxServerVendor *glvnd_vendor = NULL;
     60 
     61 #define glxClientPrivateKey (&glxClientPrivateKeyRec)
     62 
     63 /*
     64 ** Forward declarations.
     65 */
     66 static int __glXDispatch(ClientPtr);
     67 static GLboolean __glXFreeContext(__GLXcontext * cx);
     68 
     69 /*
     70  * This procedure is called when the client who created the context goes away
     71  * OR when glXDestroyContext is called. If the context is current for a client
     72  * the dispatch layer will have moved the context struct to a fake resource ID
     73  * and cx here will be NULL. Otherwise we really free the context.
     74  */
     75 static int
     76 ContextGone(__GLXcontext * cx, XID id)
     77 {
     78     if (!cx)
     79         return TRUE;
     80 
     81     if (!cx->currentClient)
     82         __glXFreeContext(cx);
     83 
     84     return TRUE;
     85 }
     86 
     87 static __GLXcontext *glxPendingDestroyContexts;
     88 static __GLXcontext *glxAllContexts;
     89 static int glxBlockClients;
     90 
     91 /*
     92 ** Destroy routine that gets called when a drawable is freed.  A drawable
     93 ** contains the ancillary buffers needed for rendering.
     94 */
     95 static Bool
     96 DrawableGone(__GLXdrawable * glxPriv, XID xid)
     97 {
     98     __GLXcontext *c, *next;
     99 
    100     if (glxPriv->type == GLX_DRAWABLE_WINDOW) {
    101         /* If this was created by glXCreateWindow, free the matching resource */
    102         if (glxPriv->drawId != glxPriv->pDraw->id) {
    103             if (xid == glxPriv->drawId)
    104                 FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE);
    105             else
    106                 FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE);
    107         }
    108         /* otherwise this window was implicitly created by MakeCurrent */
    109     }
    110 
    111     for (c = glxAllContexts; c; c = next) {
    112         next = c->next;
    113         if (c->currentClient &&
    114 		(c->drawPriv == glxPriv || c->readPriv == glxPriv)) {
    115             /* flush the context */
    116             glFlush();
    117             /* just force a re-bind the next time through */
    118             (*c->loseCurrent) (c);
    119             lastGLContext = NULL;
    120         }
    121         if (c->drawPriv == glxPriv)
    122             c->drawPriv = NULL;
    123         if (c->readPriv == glxPriv)
    124             c->readPriv = NULL;
    125     }
    126 
    127     /* drop our reference to any backing pixmap */
    128     if (glxPriv->type == GLX_DRAWABLE_PIXMAP)
    129         glxPriv->pDraw->pScreen->DestroyPixmap((PixmapPtr) glxPriv->pDraw);
    130 
    131     glxPriv->destroy(glxPriv);
    132 
    133     return TRUE;
    134 }
    135 
    136 Bool
    137 __glXAddContext(__GLXcontext * cx)
    138 {
    139     /* Register this context as a resource.
    140      */
    141     if (!AddResource(cx->id, __glXContextRes, (void *)cx)) {
    142 	return FALSE;
    143     }
    144 
    145     cx->next = glxAllContexts;
    146     glxAllContexts = cx;
    147     return TRUE;
    148 }
    149 
    150 static void
    151 __glXRemoveFromContextList(__GLXcontext * cx)
    152 {
    153     __GLXcontext *c, *prev;
    154 
    155     if (cx == glxAllContexts)
    156         glxAllContexts = cx->next;
    157     else {
    158         prev = glxAllContexts;
    159         for (c = glxAllContexts; c; c = c->next) {
    160             if (c == cx)
    161                 prev->next = c->next;
    162             prev = c;
    163         }
    164     }
    165 }
    166 
    167 /*
    168 ** Free a context.
    169 */
    170 static GLboolean
    171 __glXFreeContext(__GLXcontext * cx)
    172 {
    173     if (cx->idExists || cx->currentClient)
    174         return GL_FALSE;
    175 
    176     __glXRemoveFromContextList(cx);
    177 
    178     free(cx->feedbackBuf);
    179     free(cx->selectBuf);
    180     free(cx->largeCmdBuf);
    181     if (cx == lastGLContext) {
    182         lastGLContext = NULL;
    183     }
    184 
    185     /* We can get here through both regular dispatching from
    186      * __glXDispatch() or as a callback from the resource manager.  In
    187      * the latter case we need to lift the DRI lock manually. */
    188 
    189     if (!glxBlockClients) {
    190         cx->destroy(cx);
    191     }
    192     else {
    193         cx->next = glxPendingDestroyContexts;
    194         glxPendingDestroyContexts = cx;
    195     }
    196 
    197     return GL_TRUE;
    198 }
    199 
    200 /************************************************************************/
    201 
    202 /*
    203 ** These routines can be used to check whether a particular GL command
    204 ** has caused an error.  Specifically, we use them to check whether a
    205 ** given query has caused an error, in which case a zero-length data
    206 ** reply is sent to the client.
    207 */
    208 
    209 static GLboolean errorOccured = GL_FALSE;
    210 
    211 /*
    212 ** The GL was will call this routine if an error occurs.
    213 */
    214 void
    215 __glXErrorCallBack(GLenum code)
    216 {
    217     errorOccured = GL_TRUE;
    218 }
    219 
    220 /*
    221 ** Clear the error flag before calling the GL command.
    222 */
    223 void
    224 __glXClearErrorOccured(void)
    225 {
    226     errorOccured = GL_FALSE;
    227 }
    228 
    229 /*
    230 ** Check if the GL command caused an error.
    231 */
    232 GLboolean
    233 __glXErrorOccured(void)
    234 {
    235     return errorOccured;
    236 }
    237 
    238 static int __glXErrorBase;
    239 int __glXEventBase;
    240 
    241 int
    242 __glXError(int error)
    243 {
    244     return __glXErrorBase + error;
    245 }
    246 
    247 __GLXclientState *
    248 glxGetClient(ClientPtr pClient)
    249 {
    250     return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
    251 }
    252 
    253 static void
    254 glxClientCallback(CallbackListPtr *list, void *closure, void *data)
    255 {
    256     NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
    257     ClientPtr pClient = clientinfo->client;
    258     __GLXclientState *cl = glxGetClient(pClient);
    259 
    260     switch (pClient->clientState) {
    261     case ClientStateGone:
    262         free(cl->returnBuf);
    263         free(cl->GLClientextensions);
    264         cl->returnBuf = NULL;
    265         cl->GLClientextensions = NULL;
    266         break;
    267 
    268     default:
    269         break;
    270     }
    271 }
    272 
    273 /************************************************************************/
    274 
    275 static __GLXprovider *__glXProviderStack = &__glXDRISWRastProvider;
    276 
    277 void
    278 GlxPushProvider(__GLXprovider * provider)
    279 {
    280     provider->next = __glXProviderStack;
    281     __glXProviderStack = provider;
    282 }
    283 
    284 static Bool
    285 checkScreenVisuals(void)
    286 {
    287     int i, j;
    288 
    289     for (i = 0; i < screenInfo.numScreens; i++) {
    290         ScreenPtr screen = screenInfo.screens[i];
    291         for (j = 0; j < screen->numVisuals; j++) {
    292             if ((screen->visuals[j].class == TrueColor ||
    293                  screen->visuals[j].class == DirectColor) &&
    294                 screen->visuals[j].nplanes > 12)
    295                 return TRUE;
    296         }
    297     }
    298 
    299     return FALSE;
    300 }
    301 
    302 static void
    303 GetGLXDrawableBytes(void *value, XID id, ResourceSizePtr size)
    304 {
    305     __GLXdrawable *draw = value;
    306 
    307     size->resourceSize = 0;
    308     size->pixmapRefSize = 0;
    309     size->refCnt = 1;
    310 
    311     if (draw->type == GLX_DRAWABLE_PIXMAP) {
    312         SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
    313         ResourceSizeRec pixmapSize = { 0, };
    314         pixmapSizeFunc((PixmapPtr)draw->pDraw, draw->pDraw->id, &pixmapSize);
    315         size->pixmapRefSize += pixmapSize.pixmapRefSize;
    316     }
    317 }
    318 
    319 static void
    320 xorgGlxCloseExtension(const ExtensionEntry *extEntry)
    321 {
    322     if (glvnd_vendor != NULL) {
    323         glxServer.destroyVendor(glvnd_vendor);
    324         glvnd_vendor = NULL;
    325     }
    326     lastGLContext = NULL;
    327 }
    328 
    329 static int
    330 xorgGlxHandleRequest(ClientPtr client)
    331 {
    332     return __glXDispatch(client);
    333 }
    334 
    335 static ScreenPtr
    336 screenNumToScreen(int screen)
    337 {
    338     if (screen < 0 || screen >= screenInfo.numScreens)
    339         return NULL;
    340 
    341     return screenInfo.screens[screen];
    342 }
    343 
    344 static int
    345 maybe_swap32(ClientPtr client, int x)
    346 {
    347     return client->swapped ? bswap_32(x) : x;
    348 }
    349 
    350 static GlxServerVendor *
    351 vendorForScreen(ClientPtr client, int screen)
    352 {
    353     screen = maybe_swap32(client, screen);
    354 
    355     return glxServer.getVendorForScreen(client, screenNumToScreen(screen));
    356 }
    357 
    358 /* this ought to be generated */
    359 static int
    360 xorgGlxThunkRequest(ClientPtr client)
    361 {
    362     REQUEST(xGLXVendorPrivateReq);
    363     CARD32 vendorCode = maybe_swap32(client, stuff->vendorCode);
    364     GlxServerVendor *vendor = NULL;
    365     XID resource = 0;
    366     int ret;
    367 
    368     switch (vendorCode) {
    369     case X_GLXvop_QueryContextInfoEXT: {
    370         xGLXQueryContextInfoEXTReq *req = (void *)stuff;
    371         REQUEST_AT_LEAST_SIZE(*req);
    372         if (!(vendor = glxServer.getXIDMap(maybe_swap32(client, req->context))))
    373             return __glXError(GLXBadContext);
    374         break;
    375         }
    376 
    377     case X_GLXvop_GetFBConfigsSGIX: {
    378         xGLXGetFBConfigsSGIXReq *req = (void *)stuff;
    379         REQUEST_AT_LEAST_SIZE(*req);
    380         if (!(vendor = vendorForScreen(client, req->screen)))
    381             return BadValue;
    382         break;
    383         }
    384 
    385     case X_GLXvop_CreateContextWithConfigSGIX: {
    386         xGLXCreateContextWithConfigSGIXReq *req = (void *)stuff;
    387         REQUEST_AT_LEAST_SIZE(*req);
    388         resource = maybe_swap32(client, req->context);
    389         if (!(vendor = vendorForScreen(client, req->screen)))
    390             return BadValue;
    391         break;
    392         }
    393 
    394     case X_GLXvop_CreateGLXPixmapWithConfigSGIX: {
    395         xGLXCreateGLXPixmapWithConfigSGIXReq *req = (void *)stuff;
    396         REQUEST_AT_LEAST_SIZE(*req);
    397         resource = maybe_swap32(client, req->glxpixmap);
    398         if (!(vendor = vendorForScreen(client, req->screen)))
    399             return BadValue;
    400         break;
    401         }
    402 
    403     case X_GLXvop_CreateGLXPbufferSGIX: {
    404         xGLXCreateGLXPbufferSGIXReq *req = (void *)stuff;
    405         REQUEST_AT_LEAST_SIZE(*req);
    406         resource = maybe_swap32(client, req->pbuffer);
    407         if (!(vendor = vendorForScreen(client, req->screen)))
    408             return BadValue;
    409         break;
    410         }
    411 
    412     /* same offset for the drawable for these three */
    413     case X_GLXvop_DestroyGLXPbufferSGIX:
    414     case X_GLXvop_ChangeDrawableAttributesSGIX:
    415     case X_GLXvop_GetDrawableAttributesSGIX: {
    416         xGLXGetDrawableAttributesSGIXReq *req = (void *)stuff;
    417         REQUEST_AT_LEAST_SIZE(*req);
    418         if (!(vendor = glxServer.getXIDMap(maybe_swap32(client,
    419                                                         req->drawable))))
    420             return __glXError(GLXBadDrawable);
    421         break;
    422         }
    423 
    424     /* most things just use the standard context tag */
    425     default: {
    426         /* size checked by vnd layer already */
    427         GLXContextTag tag = maybe_swap32(client, stuff->contextTag);
    428         vendor = glxServer.getContextTag(client, tag);
    429         if (!vendor)
    430             return __glXError(GLXBadContextTag);
    431         break;
    432         }
    433     }
    434 
    435     /* If we're creating a resource, add the map now */
    436     if (resource) {
    437         LEGAL_NEW_RESOURCE(resource, client);
    438         if (!glxServer.addXIDMap(resource, vendor))
    439             return BadAlloc;
    440     }
    441 
    442     ret = glxServer.forwardRequest(vendor, client);
    443 
    444     if (ret == Success && vendorCode == X_GLXvop_DestroyGLXPbufferSGIX) {
    445         xGLXDestroyGLXPbufferSGIXReq *req = (void *)stuff;
    446         glxServer.removeXIDMap(maybe_swap32(client, req->pbuffer));
    447     }
    448 
    449     if (ret != Success)
    450         glxServer.removeXIDMap(resource);
    451 
    452     return ret;
    453 }
    454 
    455 static GlxServerDispatchProc
    456 xorgGlxGetDispatchAddress(CARD8 minorOpcode, CARD32 vendorCode)
    457 {
    458     /* we don't support any other GLX opcodes */
    459     if (minorOpcode != X_GLXVendorPrivate &&
    460         minorOpcode != X_GLXVendorPrivateWithReply)
    461         return NULL;
    462 
    463     /* we only support some vendor private requests */
    464     if (!__glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, vendorCode,
    465                                         FALSE))
    466         return NULL;
    467 
    468     return xorgGlxThunkRequest;
    469 }
    470 
    471 static Bool
    472 xorgGlxServerPreInit(const ExtensionEntry *extEntry)
    473 {
    474     if (glxGeneration != serverGeneration) {
    475         /* Mesa requires at least one True/DirectColor visual */
    476         if (!checkScreenVisuals())
    477             return FALSE;
    478 
    479         __glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
    480                                                 "GLXContext");
    481         __glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
    482                                                  "GLXDrawable");
    483         if (!__glXContextRes || !__glXDrawableRes)
    484             return FALSE;
    485 
    486         if (!dixRegisterPrivateKey
    487             (&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
    488             return FALSE;
    489         if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
    490             return FALSE;
    491 
    492         __glXErrorBase = extEntry->errorBase;
    493         __glXEventBase = extEntry->eventBase;
    494 
    495         SetResourceTypeSizeFunc(__glXDrawableRes, GetGLXDrawableBytes);
    496 #if PRESENT
    497         __glXregisterPresentCompleteNotify();
    498 #endif
    499 
    500         glxGeneration = serverGeneration;
    501     }
    502 
    503     return glxGeneration == serverGeneration;
    504 }
    505 
    506 static void
    507 xorgGlxInitGLVNDVendor(void)
    508 {
    509     if (glvnd_vendor == NULL) {
    510         GlxServerImports *imports = NULL;
    511         imports = glxServer.allocateServerImports();
    512 
    513         if (imports != NULL) {
    514             imports->extensionCloseDown = xorgGlxCloseExtension;
    515             imports->handleRequest = xorgGlxHandleRequest;
    516             imports->getDispatchAddress = xorgGlxGetDispatchAddress;
    517             imports->makeCurrent = xorgGlxMakeCurrent;
    518             glvnd_vendor = glxServer.createVendor(imports);
    519             glxServer.freeServerImports(imports);
    520         }
    521     }
    522 }
    523 
    524 static void
    525 xorgGlxServerInit(CallbackListPtr *pcbl, void *param, void *ext)
    526 {
    527     const ExtensionEntry *extEntry = ext;
    528     int i;
    529 
    530     if (!xorgGlxServerPreInit(extEntry)) {
    531         return;
    532     }
    533 
    534     xorgGlxInitGLVNDVendor();
    535     if (!glvnd_vendor) {
    536         return;
    537     }
    538 
    539     for (i = 0; i < screenInfo.numScreens; i++) {
    540         ScreenPtr pScreen = screenInfo.screens[i];
    541         __GLXprovider *p;
    542 
    543         if (glxServer.getVendorForScreen(NULL, pScreen) != NULL) {
    544             // There's already a vendor registered.
    545             LogMessage(X_INFO, "GLX: Another vendor is already registered for screen %d\n", i);
    546             continue;
    547         }
    548 
    549         for (p = __glXProviderStack; p != NULL; p = p->next) {
    550             __GLXscreen *glxScreen = p->screenProbe(pScreen);
    551             if (glxScreen != NULL) {
    552                 LogMessage(X_INFO,
    553                            "GLX: Initialized %s GL provider for screen %d\n",
    554                            p->name, i);
    555                 break;
    556             }
    557 
    558         }
    559 
    560         if (p) {
    561             glxServer.setScreenVendor(pScreen, glvnd_vendor);
    562         } else {
    563             LogMessage(X_INFO,
    564                        "GLX: no usable GL providers found for screen %d\n", i);
    565         }
    566     }
    567 }
    568 
    569 Bool
    570 xorgGlxCreateVendor(void)
    571 {
    572     return AddCallback(glxServer.extensionInitCallback, xorgGlxServerInit, NULL);
    573 }
    574 
    575 /************************************************************************/
    576 
    577 /*
    578 ** Make a context the current one for the GL (in this implementation, there
    579 ** is only one instance of the GL, and we use it to serve all GL clients by
    580 ** switching it between different contexts).  While we are at it, look up
    581 ** a context by its tag and return its (__GLXcontext *).
    582 */
    583 __GLXcontext *
    584 __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
    585 {
    586     ClientPtr client = cl->client;
    587     REQUEST(xGLXSingleReq);
    588 
    589     __GLXcontext *cx;
    590 
    591     /*
    592      ** See if the context tag is legal; it is managed by the extension,
    593      ** so if it's invalid, we have an implementation error.
    594      */
    595     cx = __glXLookupContextByTag(cl, tag);
    596     if (!cx) {
    597         cl->client->errorValue = tag;
    598         *error = __glXError(GLXBadContextTag);
    599         return 0;
    600     }
    601 
    602     /* If we're expecting a glXRenderLarge request, this better be one. */
    603     if (cx->largeCmdRequestsSoFar != 0 && stuff->glxCode != X_GLXRenderLarge) {
    604         client->errorValue = stuff->glxCode;
    605         *error = __glXError(GLXBadLargeRequest);
    606         return 0;
    607     }
    608 
    609     if (!cx->isDirect) {
    610         if (cx->drawPriv == NULL) {
    611             /*
    612              ** The drawable has vanished.  It must be a window, because only
    613              ** windows can be destroyed from under us; GLX pixmaps are
    614              ** refcounted and don't go away until no one is using them.
    615              */
    616             *error = __glXError(GLXBadCurrentWindow);
    617             return 0;
    618         }
    619     }
    620 
    621     if (cx->wait && (*cx->wait) (cx, cl, error))
    622         return NULL;
    623 
    624     if (cx == lastGLContext) {
    625         /* No need to re-bind */
    626         return cx;
    627     }
    628 
    629     /* Make this context the current one for the GL. */
    630     if (!cx->isDirect) {
    631         /*
    632          * If it is being forced, it means that this context was already made
    633          * current. So it cannot just be made current again without decrementing
    634          * refcount's
    635          */
    636         (*cx->loseCurrent) (cx);
    637         lastGLContext = cx;
    638         if (!(*cx->makeCurrent) (cx)) {
    639             /* Bind failed, and set the error code.  Bummer */
    640             lastGLContext = NULL;
    641             cl->client->errorValue = cx->id;
    642             *error = __glXError(GLXBadContextState);
    643             return 0;
    644         }
    645     }
    646     return cx;
    647 }
    648 
    649 /************************************************************************/
    650 
    651 void
    652 glxSuspendClients(void)
    653 {
    654     int i;
    655 
    656     for (i = 1; i < currentMaxClients; i++) {
    657         if (clients[i] && glxGetClient(clients[i])->client)
    658             IgnoreClient(clients[i]);
    659     }
    660 
    661     glxBlockClients = TRUE;
    662 }
    663 
    664 void
    665 glxResumeClients(void)
    666 {
    667     __GLXcontext *cx, *next;
    668     int i;
    669 
    670     glxBlockClients = FALSE;
    671 
    672     for (i = 1; i < currentMaxClients; i++) {
    673         if (clients[i] && glxGetClient(clients[i])->client)
    674             AttendClient(clients[i]);
    675     }
    676 
    677     for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
    678         next = cx->next;
    679 
    680         cx->destroy(cx);
    681     }
    682     glxPendingDestroyContexts = NULL;
    683 }
    684 
    685 static glx_gpa_proc _get_proc_address;
    686 
    687 void
    688 __glXsetGetProcAddress(glx_gpa_proc get_proc_address)
    689 {
    690     _get_proc_address = get_proc_address;
    691 }
    692 
    693 void *__glGetProcAddress(const char *proc)
    694 {
    695     void *ret = (void *) _get_proc_address(proc);
    696 
    697     return ret ? ret : (void *) NoopDDA;
    698 }
    699 
    700 /*
    701 ** Top level dispatcher; all commands are executed from here down.
    702 */
    703 static int
    704 __glXDispatch(ClientPtr client)
    705 {
    706     REQUEST(xGLXSingleReq);
    707     CARD8 opcode;
    708     __GLXdispatchSingleProcPtr proc;
    709     __GLXclientState *cl;
    710     int retval = BadRequest;
    711 
    712     opcode = stuff->glxCode;
    713     cl = glxGetClient(client);
    714 
    715 
    716     if (!cl->client)
    717         cl->client = client;
    718 
    719     /* If we're currently blocking GLX clients, just put this guy to
    720      * sleep, reset the request and return. */
    721     if (glxBlockClients) {
    722         ResetCurrentRequest(client);
    723         client->sequence--;
    724         IgnoreClient(client);
    725         return Success;
    726     }
    727 
    728     /*
    729      ** Use the opcode to index into the procedure table.
    730      */
    731     proc = __glXGetProtocolDecodeFunction(&Single_dispatch_info, opcode,
    732                                           client->swapped);
    733     if (proc != NULL)
    734         retval = (*proc) (cl, (GLbyte *) stuff);
    735 
    736     return retval;
    737 }