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