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
ContextGone(__GLXcontext * cx,XID id)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
DrawableGone(__GLXdrawable * glxPriv,XID xid)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
__glXAddContext(__GLXcontext * cx)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
__glXRemoveFromContextList(__GLXcontext * cx)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
__glXFreeContext(__GLXcontext * cx)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
__glXErrorCallBack(GLenum code)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
__glXClearErrorOccured(void)224 __glXClearErrorOccured(void)
225 {
226     errorOccured = GL_FALSE;
227 }
228 
229 /*
230 ** Check if the GL command caused an error.
231 */
232 GLboolean
__glXErrorOccured(void)233 __glXErrorOccured(void)
234 {
235     return errorOccured;
236 }
237 
238 static int __glXErrorBase;
239 int __glXEventBase;
240 
241 int
__glXError(int error)242 __glXError(int error)
243 {
244     return __glXErrorBase + error;
245 }
246 
247 __GLXclientState *
glxGetClient(ClientPtr pClient)248 glxGetClient(ClientPtr pClient)
249 {
250     return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
251 }
252 
253 static void
glxClientCallback(CallbackListPtr * list,void * closure,void * data)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
GlxPushProvider(__GLXprovider * provider)278 GlxPushProvider(__GLXprovider * provider)
279 {
280     provider->next = __glXProviderStack;
281     __glXProviderStack = provider;
282 }
283 
284 static Bool
checkScreenVisuals(void)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
GetGLXDrawableBytes(void * value,XID id,ResourceSizePtr size)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
xorgGlxCloseExtension(const ExtensionEntry * extEntry)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
xorgGlxHandleRequest(ClientPtr client)330 xorgGlxHandleRequest(ClientPtr client)
331 {
332     return __glXDispatch(client);
333 }
334 
335 static ScreenPtr
screenNumToScreen(int screen)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
maybe_swap32(ClientPtr client,int x)345 maybe_swap32(ClientPtr client, int x)
346 {
347     return client->swapped ? bswap_32(x) : x;
348 }
349 
350 static GlxServerVendor *
vendorForScreen(ClientPtr client,int screen)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
xorgGlxThunkRequest(ClientPtr client)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
xorgGlxGetDispatchAddress(CARD8 minorOpcode,CARD32 vendorCode)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
xorgGlxServerPreInit(const ExtensionEntry * extEntry)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
xorgGlxInitGLVNDVendor(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
xorgGlxServerInit(CallbackListPtr * pcbl,void * param,void * ext)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
xorgGlxCreateVendor(void)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 *
__glXForceCurrent(__GLXclientState * cl,GLXContextTag tag,int * error)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
glxSuspendClients(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
glxResumeClients(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
__glXsetGetProcAddress(glx_gpa_proc get_proc_address)688 __glXsetGetProcAddress(glx_gpa_proc get_proc_address)
689 {
690     _get_proc_address = get_proc_address;
691 }
692 
__glGetProcAddress(const char * proc)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
__glXDispatch(ClientPtr client)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 }
738