glxcmds.c revision 5afdac23
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 <assert.h>
37
38#include "glxserver.h"
39#include <GL/glxtokens.h>
40#include <unpack.h>
41#include <pixmapstr.h>
42#include <windowstr.h>
43#include "glxutil.h"
44#include "glxext.h"
45#include "glapitable.h"
46#include "glapi.h"
47#include "glthread.h"
48#include "dispatch.h"
49#include "indirect_dispatch.h"
50#include "indirect_table.h"
51#include "indirect_util.h"
52
53static int
54validGlxScreen(ClientPtr client, int screen, __GLXscreen **pGlxScreen, int *err)
55{
56    /*
57    ** Check if screen exists.
58    */
59    if (screen < 0 || screen >= screenInfo.numScreens) {
60	client->errorValue = screen;
61	*err = BadValue;
62	return FALSE;
63    }
64    *pGlxScreen = glxGetScreen(screenInfo.screens[screen]);
65
66    return TRUE;
67}
68
69static int
70validGlxFBConfig(ClientPtr client, __GLXscreen *pGlxScreen, XID id,
71		 __GLXconfig **config, int *err)
72{
73    __GLXconfig *m;
74
75    for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next)
76	if (m->fbconfigID == id) {
77	    *config = m;
78	    return TRUE;
79	}
80
81    client->errorValue = id;
82    *err = __glXError(GLXBadFBConfig);
83
84    return FALSE;
85}
86
87static int
88validGlxVisual(ClientPtr client, __GLXscreen *pGlxScreen, XID id,
89	       __GLXconfig **config, int *err)
90{
91    int i;
92
93    for (i = 0; i < pGlxScreen->numVisuals; i++)
94 	if (pGlxScreen->visuals[i]->visualID == id) {
95	    *config = pGlxScreen->visuals[i];
96	    return TRUE;
97	}
98
99    client->errorValue = id;
100    *err = BadValue;
101
102    return FALSE;
103}
104
105static int
106validGlxFBConfigForWindow(ClientPtr client, __GLXconfig *config,
107			  DrawablePtr pDraw, int *err)
108{
109    ScreenPtr pScreen = pDraw->pScreen;
110    VisualPtr pVisual = NULL;
111    XID vid;
112    int i;
113
114    vid = wVisual((WindowPtr)pDraw);
115    for (i = 0; i < pScreen->numVisuals; i++) {
116	if (pScreen->visuals[i].vid == vid) {
117	    pVisual = &pScreen->visuals[i];
118	    break;
119	}
120    }
121
122    /* FIXME: What exactly should we check here... */
123    if (pVisual->class != glxConvertToXVisualType(config->visualType) ||
124	!(config->drawableType & GLX_WINDOW_BIT)) {
125	client->errorValue = pDraw->id;
126	*err = BadMatch;
127	return FALSE;
128    }
129
130    return TRUE;
131}
132
133static int
134validGlxContext(ClientPtr client, XID id, int access_mode,
135		__GLXcontext **context, int *err)
136{
137    *err = dixLookupResourceByType((pointer *) context, id,
138				   __glXContextRes, client, access_mode);
139    if (*err != Success || (*context)->idExists == GL_FALSE) {
140	client->errorValue = id;
141	if (*err == BadValue || *err == Success)
142	    *err = __glXError(GLXBadContext);
143	return FALSE;
144    }
145
146    return TRUE;
147}
148
149static int
150validGlxDrawable(ClientPtr client, XID id, int type, int access_mode,
151		 __GLXdrawable **drawable, int *err)
152{
153    int rc;
154
155    rc = dixLookupResourceByType((pointer *) drawable, id,
156				 __glXDrawableRes, client, access_mode);
157    if (rc != Success && rc != BadValue) {
158	*err = rc;
159	client->errorValue = id;
160	return FALSE;
161    }
162
163    /* If the ID of the glx drawable we looked up doesn't match the id
164     * we looked for, it's because we looked it up under the X
165     * drawable ID (see DoCreateGLXDrawable). */
166    if (rc == BadValue ||
167	(*drawable)->drawId != id ||
168	(type != GLX_DRAWABLE_ANY && type != (*drawable)->type)) {
169	client->errorValue = id;
170	switch (type) {
171	case GLX_DRAWABLE_WINDOW:
172	    *err = __glXError(GLXBadWindow);
173	    return FALSE;
174	case GLX_DRAWABLE_PIXMAP:
175	    *err = __glXError(GLXBadPixmap);
176	    return FALSE;
177	case GLX_DRAWABLE_PBUFFER:
178	    *err = __glXError(GLXBadPbuffer);
179	    return FALSE;
180	case GLX_DRAWABLE_ANY:
181	    *err = __glXError(GLXBadDrawable);
182	    return FALSE;
183	}
184    }
185
186    return TRUE;
187}
188
189void
190__glXContextDestroy(__GLXcontext *context)
191{
192    __glXFlushContextCache();
193}
194
195static void __glXdirectContextDestroy(__GLXcontext *context)
196{
197    __glXContextDestroy(context);
198    free(context);
199}
200
201static __GLXcontext *__glXdirectContextCreate(__GLXscreen *screen,
202					      __GLXconfig *modes,
203					      __GLXcontext *shareContext)
204{
205    __GLXcontext *context;
206
207    context = calloc(1, sizeof (__GLXcontext));
208    if (context == NULL)
209	return NULL;
210
211    context->destroy = __glXdirectContextDestroy;
212
213    return context;
214}
215
216/**
217 * Create a GL context with the given properties.  This routine is used
218 * to implement \c glXCreateContext, \c glXCreateNewContext, and
219 * \c glXCreateContextWithConfigSGIX.  This works becuase of the hack way
220 * that GLXFBConfigs are implemented.  Basically, the FBConfigID is the
221 * same as the VisualID.
222 */
223
224static int
225DoCreateContext(__GLXclientState *cl, GLXContextID gcId,
226		GLXContextID shareList, __GLXconfig *config,
227		__GLXscreen *pGlxScreen, GLboolean isDirect)
228{
229    ClientPtr client = cl->client;
230    __GLXcontext *glxc, *shareglxc;
231    int err;
232
233    LEGAL_NEW_RESOURCE(gcId, client);
234
235    /*
236    ** Find the display list space that we want to share.
237    **
238    ** NOTE: In a multithreaded X server, we would need to keep a reference
239    ** count for each display list so that if one client detroyed a list that
240    ** another client was using, the list would not really be freed until it
241    ** was no longer in use.  Since this sample implementation has no support
242    ** for multithreaded servers, we don't do this.
243    */
244    if (shareList == None) {
245	shareglxc = 0;
246    } else {
247	if (!validGlxContext(client, shareList, DixReadAccess,
248			     &shareglxc, &err))
249	    return err;
250
251	if (shareglxc->isDirect) {
252	    /*
253	    ** NOTE: no support for sharing display lists between direct
254	    ** contexts, even if they are in the same address space.
255	    */
256#if 0
257            /* Disabling this code seems to allow shared display lists
258             * and texture objects to work.  We'll leave it disabled for now.
259             */
260	    client->errorValue = shareList;
261	    return BadMatch;
262#endif
263	} else {
264	    /*
265	    ** Create an indirect context regardless of what the client asked
266	    ** for; this way we can share display list space with shareList.
267	    */
268	    isDirect = GL_FALSE;
269	}
270    }
271
272    /*
273    ** Allocate memory for the new context
274    */
275    if (!isDirect)
276	glxc = pGlxScreen->createContext(pGlxScreen, config, shareglxc);
277    else
278	glxc = __glXdirectContextCreate(pGlxScreen, config, shareglxc);
279    if (!glxc) {
280	return BadAlloc;
281    }
282
283    /*
284    ** Initially, setup the part of the context that could be used by
285    ** a GL core that needs windowing information (e.g., Mesa).
286    */
287    glxc->pGlxScreen = pGlxScreen;
288    glxc->config = config;
289
290    /*
291    ** Register this context as a resource.
292    */
293    if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) {
294	(*glxc->destroy)(glxc);
295	client->errorValue = gcId;
296	return BadAlloc;
297    }
298
299    /*
300    ** Finally, now that everything is working, setup the rest of the
301    ** context.
302    */
303    glxc->id = gcId;
304    glxc->share_id = shareList;
305    glxc->idExists = GL_TRUE;
306    glxc->isCurrent = GL_FALSE;
307    glxc->isDirect = isDirect;
308    glxc->renderMode = GL_RENDER;
309
310    __glXAddToContextList(glxc);
311
312    return Success;
313}
314
315int __glXDisp_CreateContext(__GLXclientState *cl, GLbyte *pc)
316{
317    ClientPtr client = cl->client;
318    xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
319    __GLXconfig *config;
320    __GLXscreen *pGlxScreen;
321    int err;
322
323    REQUEST_SIZE_MATCH(xGLXCreateContextReq);
324
325    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
326	return err;
327    if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
328	return err;
329
330    return DoCreateContext(cl, req->context, req->shareList,
331			   config, pGlxScreen, req->isDirect);
332}
333
334int __glXDisp_CreateNewContext(__GLXclientState *cl, GLbyte *pc)
335{
336    ClientPtr client = cl->client;
337    xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
338    __GLXconfig *config;
339    __GLXscreen *pGlxScreen;
340    int err;
341
342    REQUEST_SIZE_MATCH(xGLXCreateNewContextReq);
343
344    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
345	return err;
346    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
347	return err;
348
349    return DoCreateContext(cl, req->context, req->shareList,
350			   config, pGlxScreen, req->isDirect);
351}
352
353int __glXDisp_CreateContextWithConfigSGIX(__GLXclientState *cl, GLbyte *pc)
354{
355    ClientPtr client = cl->client;
356    xGLXCreateContextWithConfigSGIXReq *req =
357	(xGLXCreateContextWithConfigSGIXReq *) pc;
358    __GLXconfig *config;
359    __GLXscreen *pGlxScreen;
360    int err;
361
362    REQUEST_SIZE_MATCH(xGLXCreateContextWithConfigSGIXReq);
363
364    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
365	return err;
366    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
367	return err;
368
369    return DoCreateContext(cl, req->context, req->shareList,
370			   config, pGlxScreen, req->isDirect);
371}
372
373int __glXDisp_DestroyContext(__GLXclientState *cl, GLbyte *pc)
374{
375    ClientPtr client = cl->client;
376    xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc;
377    __GLXcontext *glxc;
378    int err;
379
380    REQUEST_SIZE_MATCH(xGLXDestroyContextReq);
381
382    if (!validGlxContext(cl->client, req->context, DixDestroyAccess,
383			 &glxc, &err))
384	    return err;
385
386    glxc->idExists = GL_FALSE;
387    if (!glxc->isCurrent)
388        FreeResourceByType(req->context, __glXContextRes, FALSE);
389
390    return Success;
391}
392
393/*
394 * This will return "deleted" contexts, ie, where idExists is GL_FALSE.
395 * Contrast validGlxContext, which will not.  We're cheating here and
396 * using the XID as the context tag, which is fine as long as we defer
397 * actually destroying the context until it's no longer referenced, and
398 * block clients from trying to MakeCurrent on contexts that are on the
399 * way to destruction.  Notice that DoMakeCurrent calls validGlxContext
400 * for new contexts but __glXLookupContextByTag for previous contexts.
401 */
402__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag)
403{
404    __GLXcontext *ret;
405
406    if (dixLookupResourceByType((void **)&ret, tag, __glXContextRes,
407                                cl->client, DixUseAccess) == Success)
408        return ret;
409
410    return NULL;
411}
412
413/*****************************************************************************/
414
415static void StopUsingContext(__GLXcontext *glxc)
416{
417    if (glxc) {
418	if (glxc == __glXLastContext) {
419	    /* Tell server GL library */
420	    __glXLastContext = 0;
421	}
422	glxc->isCurrent = GL_FALSE;
423	if (!glxc->idExists) {
424            FreeResourceByType(glxc->id, __glXContextRes, FALSE);
425	}
426    }
427}
428
429static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc)
430{
431    glxc->isCurrent = GL_TRUE;
432    __glXLastContext = glxc;
433}
434
435/**
436 * This is a helper function to handle the legacy (pre GLX 1.3) cases
437 * where passing an X window to glXMakeCurrent is valid.  Given a
438 * resource ID, look up the GLX drawable if available, otherwise, make
439 * sure it's an X window and create a GLX drawable one the fly.
440 */
441static __GLXdrawable *
442__glXGetDrawable(__GLXcontext *glxc, GLXDrawable drawId, ClientPtr client,
443		 int *error)
444{
445    DrawablePtr pDraw;
446    __GLXdrawable *pGlxDraw;
447    int rc;
448
449    if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
450			 DixWriteAccess, &pGlxDraw, &rc)) {
451	if (glxc != NULL && pGlxDraw->config != glxc->config) {
452	    client->errorValue = drawId;
453	    *error = BadMatch;
454	    return NULL;
455	}
456
457	return pGlxDraw;
458    }
459
460    /* No active context and an unknown drawable, bail. */
461    if (glxc == NULL) {
462	    client->errorValue = drawId;
463	    *error = BadMatch;
464	    return NULL;
465    }
466
467    /* The drawId wasn't a GLX drawable.  Make sure it's a window and
468     * create a GLXWindow for it.  Check that the drawable screen
469     * matches the context screen and that the context fbconfig is
470     * compatible with the window visual. */
471
472    rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess);
473    if (rc != Success || pDraw->type != DRAWABLE_WINDOW) {
474	client->errorValue = drawId;
475	*error = __glXError(GLXBadDrawable);
476	return NULL;
477    }
478
479    if (pDraw->pScreen != glxc->pGlxScreen->pScreen) {
480	client->errorValue = pDraw->pScreen->myNum;
481	*error = BadMatch;
482	return NULL;
483    }
484
485    if (!validGlxFBConfigForWindow(client, glxc->config, pDraw, error))
486	return NULL;
487
488    pGlxDraw = glxc->pGlxScreen->createDrawable(client, glxc->pGlxScreen,
489						pDraw, drawId,
490						GLX_DRAWABLE_WINDOW,
491						drawId, glxc->config);
492
493    /* since we are creating the drawablePrivate, drawId should be new */
494    if (!AddResource(drawId, __glXDrawableRes, pGlxDraw)) {
495	pGlxDraw->destroy (pGlxDraw);
496	*error = BadAlloc;
497	return NULL;
498    }
499
500    return pGlxDraw;
501}
502
503/*****************************************************************************/
504/*
505** Make an OpenGL context and drawable current.
506*/
507
508static int
509DoMakeCurrent(__GLXclientState *cl,
510	      GLXDrawable drawId, GLXDrawable readId,
511	      GLXContextID contextId, GLXContextTag tag)
512{
513    ClientPtr client = cl->client;
514    xGLXMakeCurrentReply reply;
515    __GLXcontext *glxc, *prevglxc;
516    __GLXdrawable *drawPriv = NULL;
517    __GLXdrawable *readPriv = NULL;
518    int error;
519    GLuint  mask;
520
521    /*
522    ** If one is None and the other isn't, it's a bad match.
523    */
524
525    mask  = (drawId == None)    ? (1 << 0) : 0;
526    mask |= (readId == None)    ? (1 << 1) : 0;
527    mask |= (contextId == None) ? (1 << 2) : 0;
528
529    if ( (mask != 0x00) && (mask != 0x07) ) {
530	return BadMatch;
531    }
532
533    /*
534    ** Lookup old context.  If we have one, it must be in a usable state.
535    */
536    if (tag != 0) {
537	prevglxc = __glXLookupContextByTag(cl, tag);
538	if (!prevglxc) {
539	    /*
540	    ** Tag for previous context is invalid.
541	    */
542	    return __glXError(GLXBadContextTag);
543	}
544	if (prevglxc->renderMode != GL_RENDER) {
545	    /* Oops.  Not in render mode render. */
546	    client->errorValue = prevglxc->id;
547	    return __glXError(GLXBadContextState);
548	}
549    } else {
550	prevglxc = 0;
551    }
552
553    /*
554    ** Lookup new context.  It must not be current for someone else.
555    */
556    if (contextId != None) {
557	int  status;
558
559	if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error))
560	    return error;
561	if ((glxc != prevglxc) && glxc->isCurrent) {
562	    /* Context is current to somebody else */
563	    return BadAccess;
564	}
565
566	assert( drawId != None );
567	assert( readId != None );
568
569	drawPriv = __glXGetDrawable(glxc, drawId, client, &status);
570	if (drawPriv == NULL)
571	    return status;
572
573	readPriv = __glXGetDrawable(glxc, readId, client, &status);
574	if (readPriv == NULL)
575	    return status;
576
577    } else {
578	/* Switching to no context.  Ignore new drawable. */
579	glxc = 0;
580	drawPriv = 0;
581	readPriv = 0;
582    }
583
584
585    if (prevglxc) {
586	/*
587	** Flush the previous context if needed.
588	*/
589	if (__GLX_HAS_UNFLUSHED_CMDS(prevglxc)) {
590	    if (__glXForceCurrent(cl, tag, (int *)&error)) {
591		CALL_Flush( GET_DISPATCH(), () );
592		__GLX_NOTE_FLUSHED_CMDS(prevglxc);
593	    } else {
594		return error;
595	    }
596	}
597
598	/*
599	** Make the previous context not current.
600	*/
601	if (!(*prevglxc->loseCurrent)(prevglxc)) {
602	    return __glXError(GLXBadContext);
603	}
604	__glXFlushContextCache();
605	if (!prevglxc->isDirect) {
606	    prevglxc->drawPriv = NULL;
607	    prevglxc->readPriv = NULL;
608	}
609    }
610
611
612    if ((glxc != 0) && !glxc->isDirect) {
613
614	glxc->drawPriv = drawPriv;
615	glxc->readPriv = readPriv;
616
617	/* make the context current */
618	if (!(*glxc->makeCurrent)(glxc)) {
619	    glxc->drawPriv = NULL;
620	    glxc->readPriv = NULL;
621	    return __glXError(GLXBadContext);
622	}
623
624	glxc->isCurrent = GL_TRUE;
625    }
626
627    StopUsingContext(prevglxc);
628
629    if (glxc) {
630	StartUsingContext(cl, glxc);
631	reply.contextTag = glxc->id;
632    } else {
633	reply.contextTag = 0;
634    }
635
636    reply.length = 0;
637    reply.type = X_Reply;
638    reply.sequenceNumber = client->sequence;
639
640    if (client->swapped) {
641	__glXSwapMakeCurrentReply(client, &reply);
642    } else {
643	WriteToClient(client, sz_xGLXMakeCurrentReply, (char *)&reply);
644    }
645    return Success;
646}
647
648int __glXDisp_MakeCurrent(__GLXclientState *cl, GLbyte *pc)
649{
650    ClientPtr client = cl->client;
651    xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc;
652
653    REQUEST_SIZE_MATCH(xGLXMakeCurrentReq);
654
655    return DoMakeCurrent( cl, req->drawable, req->drawable,
656			  req->context, req->oldContextTag );
657}
658
659int __glXDisp_MakeContextCurrent(__GLXclientState *cl, GLbyte *pc)
660{
661    ClientPtr client = cl->client;
662    xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc;
663
664    REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq);
665
666    return DoMakeCurrent( cl, req->drawable, req->readdrawable,
667			  req->context, req->oldContextTag );
668}
669
670int __glXDisp_MakeCurrentReadSGI(__GLXclientState *cl, GLbyte *pc)
671{
672    ClientPtr client = cl->client;
673    xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc;
674
675    REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq);
676
677    return DoMakeCurrent( cl, req->drawable, req->readable,
678			  req->context, req->oldContextTag );
679}
680
681int __glXDisp_IsDirect(__GLXclientState *cl, GLbyte *pc)
682{
683    ClientPtr client = cl->client;
684    xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc;
685    xGLXIsDirectReply reply;
686    __GLXcontext *glxc;
687    int err;
688
689    REQUEST_SIZE_MATCH(xGLXIsDirectReq);
690
691    if (!validGlxContext(cl->client, req->context, DixReadAccess, &glxc, &err))
692	return err;
693
694    reply.isDirect = glxc->isDirect;
695    reply.length = 0;
696    reply.type = X_Reply;
697    reply.sequenceNumber = client->sequence;
698
699    if (client->swapped) {
700	__glXSwapIsDirectReply(client, &reply);
701    } else {
702	WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply);
703    }
704
705    return Success;
706}
707
708int __glXDisp_QueryVersion(__GLXclientState *cl, GLbyte *pc)
709{
710    ClientPtr client = cl->client;
711    xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc;
712    xGLXQueryVersionReply reply;
713    GLuint major, minor;
714
715    REQUEST_SIZE_MATCH(xGLXQueryVersionReq);
716
717    major = req->majorVersion;
718    minor = req->minorVersion;
719    (void)major;
720    (void)minor;
721
722    /*
723    ** Server should take into consideration the version numbers sent by the
724    ** client if it wants to work with older clients; however, in this
725    ** implementation the server just returns its version number.
726    */
727    reply.majorVersion = glxMajorVersion;
728    reply.minorVersion = glxMinorVersion;
729    reply.length = 0;
730    reply.type = X_Reply;
731    reply.sequenceNumber = client->sequence;
732
733    if (client->swapped) {
734	__glXSwapQueryVersionReply(client, &reply);
735    } else {
736	WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply);
737    }
738    return Success;
739}
740
741int __glXDisp_WaitGL(__GLXclientState *cl, GLbyte *pc)
742{
743    ClientPtr client = cl->client;
744    xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc;
745    GLXContextTag tag;
746    __GLXcontext *glxc = NULL;
747    int error;
748
749    REQUEST_SIZE_MATCH(xGLXWaitGLReq);
750
751    tag = req->contextTag;
752    if (tag) {
753	glxc = __glXLookupContextByTag(cl, tag);
754	if (!glxc)
755	    return __glXError(GLXBadContextTag);
756
757	if (!__glXForceCurrent(cl, req->contextTag, &error))
758	    return error;
759
760	CALL_Finish( GET_DISPATCH(), () );
761    }
762
763    if (glxc && glxc->drawPriv->waitGL)
764	(*glxc->drawPriv->waitGL)(glxc->drawPriv);
765
766    return Success;
767}
768
769int __glXDisp_WaitX(__GLXclientState *cl, GLbyte *pc)
770{
771    ClientPtr client = cl->client;
772    xGLXWaitXReq *req = (xGLXWaitXReq *)pc;
773    GLXContextTag tag;
774    __GLXcontext *glxc = NULL;
775    int error;
776
777    REQUEST_SIZE_MATCH(xGLXWaitXReq);
778
779    tag = req->contextTag;
780    if (tag) {
781	glxc = __glXLookupContextByTag(cl, tag);
782	if (!glxc)
783	    return __glXError(GLXBadContextTag);
784
785	if (!__glXForceCurrent(cl, req->contextTag, &error))
786	    return error;
787    }
788
789    if (glxc && glxc->drawPriv->waitX)
790	(*glxc->drawPriv->waitX)(glxc->drawPriv);
791
792    return Success;
793}
794
795int __glXDisp_CopyContext(__GLXclientState *cl, GLbyte *pc)
796{
797    ClientPtr client = cl->client;
798    xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc;
799    GLXContextID source;
800    GLXContextID dest;
801    GLXContextTag tag;
802    unsigned long mask;
803    __GLXcontext *src, *dst;
804    int error;
805
806    REQUEST_SIZE_MATCH(xGLXCopyContextReq);
807
808    source = req->source;
809    dest = req->dest;
810    tag = req->contextTag;
811    mask = req->mask;
812    if (!validGlxContext(cl->client, source, DixReadAccess, &src, &error))
813	return error;
814    if (!validGlxContext(cl->client, dest, DixWriteAccess, &dst, &error))
815	return error;
816
817    /*
818    ** They must be in the same address space, and same screen.
819    ** NOTE: no support for direct rendering contexts here.
820    */
821    if (src->isDirect || dst->isDirect ||
822	(src->pGlxScreen != dst->pGlxScreen)) {
823	client->errorValue = source;
824	return BadMatch;
825    }
826
827    /*
828    ** The destination context must not be current for any client.
829    */
830    if (dst->isCurrent) {
831	client->errorValue = dest;
832	return BadAccess;
833    }
834
835    if (tag) {
836	__GLXcontext *tagcx = __glXLookupContextByTag(cl, tag);
837
838	if (!tagcx) {
839	    return __glXError(GLXBadContextTag);
840	}
841	if (tagcx != src) {
842	    /*
843	    ** This would be caused by a faulty implementation of the client
844	    ** library.
845	    */
846	    return BadMatch;
847	}
848	/*
849	** In this case, glXCopyContext is in both GL and X streams, in terms
850	** of sequentiality.
851	*/
852	if (__glXForceCurrent(cl, tag, &error)) {
853	    /*
854	    ** Do whatever is needed to make sure that all preceding requests
855	    ** in both streams are completed before the copy is executed.
856	    */
857	    CALL_Finish( GET_DISPATCH(), () );
858	    __GLX_NOTE_FLUSHED_CMDS(tagcx);
859	} else {
860	    return error;
861	}
862    }
863    /*
864    ** Issue copy.  The only reason for failure is a bad mask.
865    */
866    if (!(*dst->copy)(dst, src, mask)) {
867	client->errorValue = mask;
868	return BadValue;
869    }
870    return Success;
871}
872
873enum {
874    GLX_VIS_CONFIG_UNPAIRED = 18,
875    GLX_VIS_CONFIG_PAIRED = 20
876};
877
878enum {
879    GLX_VIS_CONFIG_TOTAL = GLX_VIS_CONFIG_UNPAIRED + GLX_VIS_CONFIG_PAIRED
880};
881
882int __glXDisp_GetVisualConfigs(__GLXclientState *cl, GLbyte *pc)
883{
884    xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc;
885    ClientPtr client = cl->client;
886    xGLXGetVisualConfigsReply reply;
887    __GLXscreen *pGlxScreen;
888    __GLXconfig *modes;
889    CARD32 buf[GLX_VIS_CONFIG_TOTAL];
890    int p, i, err;
891    __GLX_DECLARE_SWAP_VARIABLES;
892    __GLX_DECLARE_SWAP_ARRAY_VARIABLES;
893
894    REQUEST_SIZE_MATCH(xGLXGetVisualConfigsReq);
895
896    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
897	return err;
898
899    reply.numVisuals = pGlxScreen->numVisuals;
900    reply.numProps = GLX_VIS_CONFIG_TOTAL;
901    reply.length = (reply.numVisuals * __GLX_SIZE_CARD32 * GLX_VIS_CONFIG_TOTAL) >> 2;
902    reply.type = X_Reply;
903    reply.sequenceNumber = client->sequence;
904
905    if (client->swapped) {
906	__GLX_SWAP_SHORT(&reply.sequenceNumber);
907	__GLX_SWAP_INT(&reply.length);
908	__GLX_SWAP_INT(&reply.numVisuals);
909	__GLX_SWAP_INT(&reply.numProps);
910    }
911
912    WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply);
913
914    for (i = 0; i < pGlxScreen->numVisuals; i++) {
915	modes = pGlxScreen->visuals[i];
916
917	p = 0;
918	buf[p++] = modes->visualID;
919	buf[p++] = glxConvertToXVisualType( modes->visualType );
920	buf[p++] = (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE;
921
922	buf[p++] = modes->redBits;
923	buf[p++] = modes->greenBits;
924	buf[p++] = modes->blueBits;
925	buf[p++] = modes->alphaBits;
926	buf[p++] = modes->accumRedBits;
927	buf[p++] = modes->accumGreenBits;
928	buf[p++] = modes->accumBlueBits;
929	buf[p++] = modes->accumAlphaBits;
930
931	buf[p++] = modes->doubleBufferMode;
932	buf[p++] = modes->stereoMode;
933
934	buf[p++] = modes->rgbBits;
935	buf[p++] = modes->depthBits;
936	buf[p++] = modes->stencilBits;
937	buf[p++] = modes->numAuxBuffers;
938	buf[p++] = modes->level;
939
940	assert(p == GLX_VIS_CONFIG_UNPAIRED);
941	/*
942	** Add token/value pairs for extensions.
943	*/
944	buf[p++] = GLX_VISUAL_CAVEAT_EXT;
945	buf[p++] = modes->visualRating;
946	buf[p++] = GLX_TRANSPARENT_TYPE;
947	buf[p++] = modes->transparentPixel;
948	buf[p++] = GLX_TRANSPARENT_RED_VALUE;
949	buf[p++] = modes->transparentRed;
950	buf[p++] = GLX_TRANSPARENT_GREEN_VALUE;
951	buf[p++] = modes->transparentGreen;
952	buf[p++] = GLX_TRANSPARENT_BLUE_VALUE;
953	buf[p++] = modes->transparentBlue;
954	buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE;
955	buf[p++] = modes->transparentAlpha;
956	buf[p++] = GLX_TRANSPARENT_INDEX_VALUE;
957	buf[p++] = modes->transparentIndex;
958	buf[p++] = GLX_SAMPLES_SGIS;
959	buf[p++] = modes->samples;
960	buf[p++] = GLX_SAMPLE_BUFFERS_SGIS;
961	buf[p++] = modes->sampleBuffers;
962	buf[p++] = 0; /* copy over visualSelectGroup (GLX_VISUAL_SELECT_GROUP_SGIX)? */
963	buf[p++] = 0;
964
965	assert(p == GLX_VIS_CONFIG_TOTAL);
966	if (client->swapped) {
967	    __GLX_SWAP_INT_ARRAY(buf, p);
968	}
969	WriteToClient(client, __GLX_SIZE_CARD32 * p, (char *)buf);
970    }
971    return Success;
972}
973
974#define __GLX_TOTAL_FBCONFIG_ATTRIBS (36)
975#define __GLX_FBCONFIG_ATTRIBS_LENGTH (__GLX_TOTAL_FBCONFIG_ATTRIBS * 2)
976/**
977 * Send the set of GLXFBConfigs to the client.  There is not currently
978 * and interface into the driver on the server-side to get GLXFBConfigs,
979 * so we "invent" some based on the \c __GLXvisualConfig structures that
980 * the driver does supply.
981 *
982 * The reply format for both \c glXGetFBConfigs and \c glXGetFBConfigsSGIX
983 * is the same, so this routine pulls double duty.
984 */
985
986static int
987DoGetFBConfigs(__GLXclientState *cl, unsigned screen)
988{
989    ClientPtr client = cl->client;
990    xGLXGetFBConfigsReply reply;
991    __GLXscreen *pGlxScreen;
992    CARD32 buf[__GLX_FBCONFIG_ATTRIBS_LENGTH];
993    int p, err;
994    __GLXconfig *modes;
995    __GLX_DECLARE_SWAP_VARIABLES;
996    __GLX_DECLARE_SWAP_ARRAY_VARIABLES;
997
998    if (!validGlxScreen(cl->client, screen, &pGlxScreen, &err))
999	return err;
1000
1001    reply.numFBConfigs = pGlxScreen->numFBConfigs;
1002    reply.numAttribs = __GLX_TOTAL_FBCONFIG_ATTRIBS;
1003    reply.length = (__GLX_FBCONFIG_ATTRIBS_LENGTH * reply.numFBConfigs);
1004    reply.type = X_Reply;
1005    reply.sequenceNumber = client->sequence;
1006
1007    if (client->swapped) {
1008	__GLX_SWAP_SHORT(&reply.sequenceNumber);
1009	__GLX_SWAP_INT(&reply.length);
1010	__GLX_SWAP_INT(&reply.numFBConfigs);
1011	__GLX_SWAP_INT(&reply.numAttribs);
1012    }
1013
1014    WriteToClient(client, sz_xGLXGetFBConfigsReply, (char *)&reply);
1015
1016    for (modes = pGlxScreen->fbconfigs; modes != NULL; modes = modes->next) {
1017	p = 0;
1018
1019#define WRITE_PAIR(tag,value) \
1020    do { buf[p++] = tag ; buf[p++] = value ; } while( 0 )
1021
1022	WRITE_PAIR( GLX_VISUAL_ID,        modes->visualID );
1023	WRITE_PAIR( GLX_FBCONFIG_ID,      modes->fbconfigID );
1024	WRITE_PAIR( GLX_X_RENDERABLE,     GL_TRUE );
1025
1026	WRITE_PAIR( GLX_RGBA,
1027		    (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE );
1028	WRITE_PAIR( GLX_RENDER_TYPE,      modes->renderType );
1029	WRITE_PAIR( GLX_DOUBLEBUFFER,     modes->doubleBufferMode );
1030	WRITE_PAIR( GLX_STEREO,           modes->stereoMode );
1031
1032	WRITE_PAIR( GLX_BUFFER_SIZE,      modes->rgbBits );
1033	WRITE_PAIR( GLX_LEVEL,            modes->level );
1034	WRITE_PAIR( GLX_AUX_BUFFERS,      modes->numAuxBuffers );
1035	WRITE_PAIR( GLX_RED_SIZE,         modes->redBits );
1036	WRITE_PAIR( GLX_GREEN_SIZE,       modes->greenBits );
1037	WRITE_PAIR( GLX_BLUE_SIZE,        modes->blueBits );
1038	WRITE_PAIR( GLX_ALPHA_SIZE,       modes->alphaBits );
1039	WRITE_PAIR( GLX_ACCUM_RED_SIZE,   modes->accumRedBits );
1040	WRITE_PAIR( GLX_ACCUM_GREEN_SIZE, modes->accumGreenBits );
1041	WRITE_PAIR( GLX_ACCUM_BLUE_SIZE,  modes->accumBlueBits );
1042	WRITE_PAIR( GLX_ACCUM_ALPHA_SIZE, modes->accumAlphaBits );
1043	WRITE_PAIR( GLX_DEPTH_SIZE,       modes->depthBits );
1044	WRITE_PAIR( GLX_STENCIL_SIZE,     modes->stencilBits );
1045	WRITE_PAIR( GLX_X_VISUAL_TYPE,    modes->visualType );
1046	WRITE_PAIR( GLX_CONFIG_CAVEAT, modes->visualRating );
1047	WRITE_PAIR( GLX_TRANSPARENT_TYPE, modes->transparentPixel );
1048	WRITE_PAIR( GLX_TRANSPARENT_RED_VALUE, modes->transparentRed );
1049	WRITE_PAIR( GLX_TRANSPARENT_GREEN_VALUE, modes->transparentGreen );
1050	WRITE_PAIR( GLX_TRANSPARENT_BLUE_VALUE, modes->transparentBlue );
1051	WRITE_PAIR( GLX_TRANSPARENT_ALPHA_VALUE, modes->transparentAlpha );
1052	WRITE_PAIR( GLX_TRANSPARENT_INDEX_VALUE, modes->transparentIndex );
1053	WRITE_PAIR( GLX_SWAP_METHOD_OML, modes->swapMethod );
1054	WRITE_PAIR( GLX_SAMPLES_SGIS, modes->samples );
1055	WRITE_PAIR( GLX_SAMPLE_BUFFERS_SGIS, modes->sampleBuffers );
1056	/* GLX_VISUAL_SELECT_GROUP_SGIX ? */
1057	WRITE_PAIR( GLX_DRAWABLE_TYPE, modes->drawableType );
1058	WRITE_PAIR( GLX_BIND_TO_TEXTURE_RGB_EXT, modes->bindToTextureRgb );
1059	WRITE_PAIR( GLX_BIND_TO_TEXTURE_RGBA_EXT, modes->bindToTextureRgba );
1060	WRITE_PAIR( GLX_BIND_TO_MIPMAP_TEXTURE_EXT, modes->bindToMipmapTexture );
1061	WRITE_PAIR( GLX_BIND_TO_TEXTURE_TARGETS_EXT, modes->bindToTextureTargets );
1062
1063	if (client->swapped) {
1064	    __GLX_SWAP_INT_ARRAY(buf, __GLX_FBCONFIG_ATTRIBS_LENGTH);
1065	}
1066	WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_FBCONFIG_ATTRIBS_LENGTH,
1067		      (char *)buf);
1068    }
1069    return Success;
1070}
1071
1072
1073int __glXDisp_GetFBConfigs(__GLXclientState *cl, GLbyte *pc)
1074{
1075    ClientPtr client = cl->client;
1076    xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc;
1077    REQUEST_SIZE_MATCH(xGLXGetFBConfigsReq);
1078    return DoGetFBConfigs(cl, req->screen);
1079}
1080
1081int __glXDisp_GetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc)
1082{
1083    ClientPtr client = cl->client;
1084    xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc;
1085    /* work around mesa bug, don't use REQUEST_SIZE_MATCH */
1086    REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq);
1087    return DoGetFBConfigs(cl, req->screen);
1088}
1089
1090GLboolean
1091__glXDrawableInit(__GLXdrawable *drawable,
1092		  __GLXscreen *screen, DrawablePtr pDraw, int type,
1093		  XID drawId, __GLXconfig *config)
1094{
1095    drawable->pDraw = pDraw;
1096    drawable->type = type;
1097    drawable->drawId = drawId;
1098    drawable->otherId = 0;
1099    drawable->config = config;
1100    drawable->eventMask = 0;
1101
1102    return GL_TRUE;
1103}
1104
1105void
1106__glXDrawableRelease(__GLXdrawable *drawable)
1107{
1108}
1109
1110static int
1111DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen,
1112		    __GLXconfig *config, DrawablePtr pDraw, XID drawableId,
1113		    XID glxDrawableId, int type)
1114{
1115    __GLXdrawable *pGlxDraw;
1116
1117    if (pGlxScreen->pScreen != pDraw->pScreen)
1118	return BadMatch;
1119
1120    pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw,
1121					  drawableId, type,
1122					  glxDrawableId, config);
1123    if (pGlxDraw == NULL)
1124	return BadAlloc;
1125
1126    if (!AddResource(glxDrawableId, __glXDrawableRes, pGlxDraw)) {
1127	pGlxDraw->destroy (pGlxDraw);
1128	return BadAlloc;
1129    }
1130
1131    /*
1132     * Windows aren't refcounted, so track both the X and the GLX window
1133     * so we get called regardless of destruction order.
1134     */
1135    if (drawableId != glxDrawableId &&
1136        (type == GLX_DRAWABLE_WINDOW || type == GLX_DRAWABLE_PIXMAP)) {
1137        if (!AddResource(drawableId, __glXDrawableRes, pGlxDraw)) {
1138	    pGlxDraw->destroy (pGlxDraw);
1139	    return BadAlloc;
1140	}
1141	pGlxDraw->otherId = drawableId;
1142    }
1143
1144    return Success;
1145}
1146
1147static int
1148DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config,
1149		  XID drawableId, XID glxDrawableId)
1150{
1151    DrawablePtr pDraw;
1152    int err;
1153
1154    LEGAL_NEW_RESOURCE(glxDrawableId, client);
1155
1156    err = dixLookupDrawable(&pDraw, drawableId, client, 0, DixAddAccess);
1157    if (err != Success) {
1158	client->errorValue = drawableId;
1159	return err;
1160    }
1161    if (pDraw->type != DRAWABLE_PIXMAP) {
1162	client->errorValue = drawableId;
1163	return BadPixmap;
1164    }
1165
1166    err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, drawableId,
1167			      glxDrawableId, GLX_DRAWABLE_PIXMAP);
1168
1169    ((PixmapPtr)pDraw)->refcnt++;
1170
1171    return err;
1172}
1173
1174static void
1175determineTextureTarget(ClientPtr client, XID glxDrawableID,
1176		       CARD32 *attribs, CARD32 numAttribs)
1177{
1178    GLenum target = 0;
1179    GLenum format = 0;
1180    int i, err;
1181    __GLXdrawable *pGlxDraw;
1182
1183    if (!validGlxDrawable(client, glxDrawableID, GLX_DRAWABLE_PIXMAP,
1184			  DixWriteAccess, &pGlxDraw, &err))
1185	/* We just added it in CreatePixmap, so we should never get here. */
1186	return;
1187
1188    for (i = 0; i < numAttribs; i++) {
1189	if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) {
1190	    switch (attribs[2 * i + 1]) {
1191	    case GLX_TEXTURE_2D_EXT:
1192		target = GL_TEXTURE_2D;
1193		break;
1194	    case GLX_TEXTURE_RECTANGLE_EXT:
1195		target = GL_TEXTURE_RECTANGLE_ARB;
1196		break;
1197	    }
1198	}
1199
1200	if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT)
1201		format = attribs[2 * i + 1];
1202    }
1203
1204    if (!target) {
1205	int w = pGlxDraw->pDraw->width, h = pGlxDraw->pDraw->height;
1206
1207	if (h & (h - 1) || w & (w - 1))
1208	    target = GL_TEXTURE_RECTANGLE_ARB;
1209	else
1210	    target = GL_TEXTURE_2D;
1211    }
1212
1213    pGlxDraw->target = target;
1214    pGlxDraw->format = format;
1215}
1216
1217int __glXDisp_CreateGLXPixmap(__GLXclientState *cl, GLbyte *pc)
1218{
1219    ClientPtr client = cl->client;
1220    xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc;
1221    __GLXconfig *config;
1222    __GLXscreen *pGlxScreen;
1223    int err;
1224
1225    REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapReq);
1226
1227    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
1228	return err;
1229    if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
1230	return err;
1231
1232    return DoCreateGLXPixmap(cl->client, pGlxScreen, config,
1233			     req->pixmap, req->glxpixmap);
1234}
1235
1236int __glXDisp_CreatePixmap(__GLXclientState *cl, GLbyte *pc)
1237{
1238    ClientPtr client = cl->client;
1239    xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc;
1240    __GLXconfig *config;
1241    __GLXscreen *pGlxScreen;
1242    int err;
1243
1244    REQUEST_AT_LEAST_SIZE(xGLXCreatePixmapReq);
1245    if (req->numAttribs > (UINT32_MAX >> 3)) {
1246	client->errorValue = req->numAttribs;
1247	return BadValue;
1248    }
1249    REQUEST_FIXED_SIZE(xGLXCreatePixmapReq, req->numAttribs << 3);
1250
1251    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
1252	return err;
1253    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
1254	return err;
1255
1256    err = DoCreateGLXPixmap(cl->client, pGlxScreen, config,
1257			    req->pixmap, req->glxpixmap);
1258    if (err != Success)
1259	return err;
1260
1261    determineTextureTarget(cl->client, req->glxpixmap,
1262			   (CARD32*) (req + 1), req->numAttribs);
1263
1264    return Success;
1265}
1266
1267int __glXDisp_CreateGLXPixmapWithConfigSGIX(__GLXclientState *cl, GLbyte *pc)
1268{
1269    ClientPtr client = cl->client;
1270    xGLXCreateGLXPixmapWithConfigSGIXReq *req =
1271	(xGLXCreateGLXPixmapWithConfigSGIXReq *) pc;
1272    __GLXconfig *config;
1273    __GLXscreen *pGlxScreen;
1274    int err;
1275
1276    REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapWithConfigSGIXReq);
1277
1278    if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
1279	return err;
1280    if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
1281	return err;
1282
1283    return DoCreateGLXPixmap(cl->client, pGlxScreen,
1284			     config, req->pixmap, req->glxpixmap);
1285}
1286
1287
1288static int DoDestroyDrawable(__GLXclientState *cl, XID glxdrawable, int type)
1289{
1290    __GLXdrawable *pGlxDraw;
1291    int err;
1292
1293    if (!validGlxDrawable(cl->client, glxdrawable, type,
1294			  DixDestroyAccess, &pGlxDraw, &err))
1295	return err;
1296
1297    FreeResource(glxdrawable, FALSE);
1298
1299    return Success;
1300}
1301
1302int __glXDisp_DestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc)
1303{
1304    ClientPtr client = cl->client;
1305    xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc;
1306
1307    REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq);
1308
1309    return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP);
1310}
1311
1312int __glXDisp_DestroyPixmap(__GLXclientState *cl, GLbyte *pc)
1313{
1314    ClientPtr client = cl->client;
1315    xGLXDestroyPixmapReq *req = (xGLXDestroyPixmapReq *) pc;
1316
1317    /* should be REQUEST_SIZE_MATCH, but mesa's glXDestroyPixmap used to set
1318     * length to 3 instead of 2 */
1319    REQUEST_AT_LEAST_SIZE(xGLXDestroyPixmapReq);
1320
1321    return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP);
1322}
1323
1324static int
1325DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId,
1326		int width, int height, XID glxDrawableId)
1327{
1328    __GLXconfig	*config;
1329    __GLXscreen		*pGlxScreen;
1330    PixmapPtr		 pPixmap;
1331    int			 err;
1332
1333    LEGAL_NEW_RESOURCE(glxDrawableId, client);
1334
1335    if (!validGlxScreen(client, screenNum, &pGlxScreen, &err))
1336	return err;
1337    if (!validGlxFBConfig(client, pGlxScreen, fbconfigId, &config, &err))
1338	return err;
1339
1340    __glXenterServer(GL_FALSE);
1341    pPixmap = (*pGlxScreen->pScreen->CreatePixmap) (pGlxScreen->pScreen,
1342						    width, height, config->rgbBits, 0);
1343    __glXleaveServer(GL_FALSE);
1344
1345    /* Assign the pixmap the same id as the pbuffer and add it as a
1346     * resource so it and the DRI2 drawable will be reclaimed when the
1347     * pbuffer is destroyed. */
1348    pPixmap->drawable.id = glxDrawableId;
1349    if (!AddResource(pPixmap->drawable.id, RT_PIXMAP, pPixmap))
1350	return BadAlloc;
1351
1352    return DoCreateGLXDrawable(client, pGlxScreen, config, &pPixmap->drawable,
1353			       glxDrawableId, glxDrawableId,
1354			       GLX_DRAWABLE_PBUFFER);
1355}
1356
1357int __glXDisp_CreatePbuffer(__GLXclientState *cl, GLbyte *pc)
1358{
1359    ClientPtr client = cl->client;
1360    xGLXCreatePbufferReq	*req = (xGLXCreatePbufferReq *) pc;
1361    CARD32			*attrs;
1362    int				 width, height, i;
1363
1364    REQUEST_AT_LEAST_SIZE(xGLXCreatePbufferReq);
1365    if (req->numAttribs > (UINT32_MAX >> 3)) {
1366	client->errorValue = req->numAttribs;
1367	return BadValue;
1368    }
1369    REQUEST_FIXED_SIZE(xGLXCreatePbufferReq, req->numAttribs << 3);
1370
1371    attrs = (CARD32 *) (req + 1);
1372    width = 0;
1373    height = 0;
1374
1375    for (i = 0; i < req->numAttribs; i++) {
1376	switch (attrs[i * 2]) {
1377	case GLX_PBUFFER_WIDTH:
1378	    width = attrs[i * 2 + 1];
1379	    break;
1380	case GLX_PBUFFER_HEIGHT:
1381	    height = attrs[i * 2 + 1];
1382	    break;
1383	case GLX_LARGEST_PBUFFER:
1384	case GLX_PRESERVED_CONTENTS:
1385	    /* FIXME: huh... */
1386	    break;
1387	}
1388    }
1389
1390    return DoCreatePbuffer(cl->client, req->screen, req->fbconfig,
1391			   width, height, req->pbuffer);
1392}
1393
1394int __glXDisp_CreateGLXPbufferSGIX(__GLXclientState *cl, GLbyte *pc)
1395{
1396    ClientPtr client = cl->client;
1397    xGLXCreateGLXPbufferSGIXReq *req = (xGLXCreateGLXPbufferSGIXReq *) pc;
1398
1399    REQUEST_AT_LEAST_SIZE(xGLXCreateGLXPbufferSGIXReq);
1400
1401    return DoCreatePbuffer(cl->client, req->screen, req->fbconfig,
1402			   req->width, req->height, req->pbuffer);
1403}
1404
1405int __glXDisp_DestroyPbuffer(__GLXclientState *cl, GLbyte *pc)
1406{
1407    ClientPtr client = cl->client;
1408    xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc;
1409
1410    REQUEST_SIZE_MATCH(xGLXDestroyPbufferReq);
1411
1412    return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER);
1413}
1414
1415int __glXDisp_DestroyGLXPbufferSGIX(__GLXclientState *cl, GLbyte *pc)
1416{
1417    ClientPtr client = cl->client;
1418    xGLXDestroyGLXPbufferSGIXReq *req = (xGLXDestroyGLXPbufferSGIXReq *) pc;
1419
1420    REQUEST_SIZE_MATCH(xGLXDestroyGLXPbufferSGIXReq);
1421
1422    return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER);
1423}
1424
1425static int
1426DoChangeDrawableAttributes(ClientPtr client, XID glxdrawable,
1427			   int numAttribs, CARD32 *attribs)
1428{
1429    __GLXdrawable *pGlxDraw;
1430    int i, err;
1431
1432    if (!validGlxDrawable(client, glxdrawable, GLX_DRAWABLE_ANY,
1433			  DixSetAttrAccess, &pGlxDraw, &err))
1434	return err;
1435
1436    for (i = 0; i < numAttribs; i++) {
1437	switch(attribs[i * 2]) {
1438	case GLX_EVENT_MASK:
1439	    /* All we do is to record the event mask so we can send it
1440	     * back when queried.  We never actually clobber the
1441	     * pbuffers, so we never need to send out the event. */
1442	    pGlxDraw->eventMask = attribs[i * 2 + 1];
1443	    break;
1444	}
1445    }
1446
1447    return Success;
1448}
1449
1450int __glXDisp_ChangeDrawableAttributes(__GLXclientState *cl, GLbyte *pc)
1451{
1452    ClientPtr client = cl->client;
1453    xGLXChangeDrawableAttributesReq *req =
1454	(xGLXChangeDrawableAttributesReq *) pc;
1455
1456    REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesReq);
1457    if (req->numAttribs > (UINT32_MAX >> 3)) {
1458	client->errorValue = req->numAttribs;
1459	return BadValue;
1460    }
1461#if 0
1462    /* mesa sends an additional 8 bytes */
1463    REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3);
1464#else
1465    if (((sizeof(xGLXChangeDrawableAttributesReq) + (req->numAttribs << 3)) >> 2) < client->req_len)
1466	    return BadLength;
1467#endif
1468
1469    return DoChangeDrawableAttributes(cl->client, req->drawable,
1470				      req->numAttribs, (CARD32 *) (req + 1));
1471}
1472
1473int __glXDisp_ChangeDrawableAttributesSGIX(__GLXclientState *cl, GLbyte *pc)
1474{
1475    ClientPtr client = cl->client;
1476    xGLXChangeDrawableAttributesSGIXReq *req =
1477	(xGLXChangeDrawableAttributesSGIXReq *)pc;
1478
1479    REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesSGIXReq);
1480    if (req->numAttribs > (UINT32_MAX >> 3)) {
1481	client->errorValue = req->numAttribs;
1482	return BadValue;
1483    }
1484    REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesSGIXReq, req->numAttribs << 3);
1485
1486    return DoChangeDrawableAttributes(cl->client, req->drawable,
1487				      req->numAttribs, (CARD32 *) (req + 1));
1488}
1489
1490int __glXDisp_CreateWindow(__GLXclientState *cl, GLbyte *pc)
1491{
1492    xGLXCreateWindowReq	*req = (xGLXCreateWindowReq *) pc;
1493    __GLXconfig	*config;
1494    __GLXscreen		*pGlxScreen;
1495    ClientPtr		 client = cl->client;
1496    DrawablePtr		 pDraw;
1497    int			 err;
1498
1499    REQUEST_AT_LEAST_SIZE(xGLXCreateWindowReq);
1500    if (req->numAttribs > (UINT32_MAX >> 3)) {
1501	client->errorValue = req->numAttribs;
1502	return BadValue;
1503    }
1504    REQUEST_FIXED_SIZE(xGLXCreateWindowReq, req->numAttribs << 3);
1505
1506    LEGAL_NEW_RESOURCE(req->glxwindow, client);
1507
1508    if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
1509	return err;
1510    if (!validGlxFBConfig(client, pGlxScreen, req->fbconfig, &config, &err))
1511	return err;
1512
1513    err = dixLookupDrawable(&pDraw, req->window, client, 0, DixAddAccess);
1514    if (err != Success || pDraw->type != DRAWABLE_WINDOW) {
1515	client->errorValue = req->window;
1516	return BadWindow;
1517    }
1518
1519    if (!validGlxFBConfigForWindow(client, config, pDraw, &err))
1520	return err;
1521
1522    return DoCreateGLXDrawable(client, pGlxScreen, config,
1523			       pDraw, req->window,
1524			       req->glxwindow, GLX_DRAWABLE_WINDOW);
1525}
1526
1527int __glXDisp_DestroyWindow(__GLXclientState *cl, GLbyte *pc)
1528{
1529    ClientPtr client = cl->client;
1530    xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc;
1531
1532    /* mesa's glXDestroyWindow used to set length to 3 instead of 2 */
1533    REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq);
1534
1535    return DoDestroyDrawable(cl, req->glxwindow, GLX_DRAWABLE_WINDOW);
1536}
1537
1538
1539/*****************************************************************************/
1540
1541/*
1542** NOTE: There is no portable implementation for swap buffers as of
1543** this time that is of value.  Consequently, this code must be
1544** implemented by somebody other than SGI.
1545*/
1546int __glXDisp_SwapBuffers(__GLXclientState *cl, GLbyte *pc)
1547{
1548    ClientPtr client = cl->client;
1549    xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc;
1550    GLXContextTag tag;
1551    XID drawId;
1552    __GLXcontext *glxc = NULL;
1553    __GLXdrawable *pGlxDraw;
1554    int error;
1555
1556    REQUEST_SIZE_MATCH(xGLXSwapBuffersReq);
1557
1558    tag = req->contextTag;
1559    drawId = req->drawable;
1560    if (tag) {
1561	glxc = __glXLookupContextByTag(cl, tag);
1562	if (!glxc) {
1563	    return __glXError(GLXBadContextTag);
1564	}
1565	/*
1566	** The calling thread is swapping its current drawable.  In this case,
1567	** glxSwapBuffers is in both GL and X streams, in terms of
1568	** sequentiality.
1569	*/
1570	if (__glXForceCurrent(cl, tag, &error)) {
1571	    /*
1572	    ** Do whatever is needed to make sure that all preceding requests
1573	    ** in both streams are completed before the swap is executed.
1574	    */
1575	    CALL_Finish( GET_DISPATCH(), () );
1576	    __GLX_NOTE_FLUSHED_CMDS(glxc);
1577	} else {
1578	    return error;
1579	}
1580    }
1581
1582    pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error);
1583    if (pGlxDraw == NULL)
1584	return error;
1585
1586    if (pGlxDraw->type == DRAWABLE_WINDOW &&
1587	(*pGlxDraw->swapBuffers)(cl->client, pGlxDraw) == GL_FALSE)
1588	return __glXError(GLXBadDrawable);
1589
1590    return Success;
1591}
1592
1593
1594static int
1595DoQueryContext(__GLXclientState *cl, GLXContextID gcId)
1596{
1597    ClientPtr client = cl->client;
1598    __GLXcontext *ctx;
1599    xGLXQueryContextInfoEXTReply reply;
1600    int nProps;
1601    int *sendBuf, *pSendBuf;
1602    int nReplyBytes;
1603    int err;
1604
1605    if (!validGlxContext(cl->client, gcId, DixReadAccess, &ctx, &err))
1606	return err;
1607
1608    nProps = 3;
1609    reply.length = nProps << 1;
1610    reply.type = X_Reply;
1611    reply.sequenceNumber = client->sequence;
1612    reply.n = nProps;
1613
1614    nReplyBytes = reply.length << 2;
1615    sendBuf = (int *)malloc((size_t)nReplyBytes);
1616    if (sendBuf == NULL) {
1617	return __glXError(GLXBadContext);	/* XXX: Is this correct? */
1618    }
1619    pSendBuf = sendBuf;
1620    *pSendBuf++ = GLX_SHARE_CONTEXT_EXT;
1621    *pSendBuf++ = (int)(ctx->share_id);
1622    *pSendBuf++ = GLX_VISUAL_ID_EXT;
1623    *pSendBuf++ = (int)(ctx->config->visualID);
1624    *pSendBuf++ = GLX_SCREEN_EXT;
1625    *pSendBuf++ = (int)(ctx->pGlxScreen->pScreen->myNum);
1626
1627    if (client->swapped) {
1628	__glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf);
1629    } else {
1630	WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply);
1631	WriteToClient(client, nReplyBytes, (char *)sendBuf);
1632    }
1633    free((char *)sendBuf);
1634
1635    return Success;
1636}
1637
1638int __glXDisp_QueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc)
1639{
1640    ClientPtr client = cl->client;
1641    xGLXQueryContextInfoEXTReq *req = (xGLXQueryContextInfoEXTReq *) pc;
1642
1643    REQUEST_SIZE_MATCH(xGLXQueryContextInfoEXTReq);
1644
1645    return DoQueryContext(cl, req->context);
1646}
1647
1648int __glXDisp_QueryContext(__GLXclientState *cl, GLbyte *pc)
1649{
1650    ClientPtr client = cl->client;
1651    xGLXQueryContextReq *req = (xGLXQueryContextReq *) pc;
1652
1653    REQUEST_SIZE_MATCH(xGLXQueryContextReq);
1654
1655    return DoQueryContext(cl, req->context);
1656}
1657
1658int __glXDisp_BindTexImageEXT(__GLXclientState *cl, GLbyte *pc)
1659{
1660    xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc;
1661    ClientPtr		 client = cl->client;
1662    __GLXcontext	*context;
1663    __GLXdrawable	*pGlxDraw;
1664    GLXDrawable		 drawId;
1665    int			 buffer;
1666    int			 error;
1667    CARD32		 num_attribs;
1668
1669    if ((sizeof(xGLXVendorPrivateReq) + 12) >> 2 > client->req_len)
1670	return BadLength;
1671
1672    pc += __GLX_VENDPRIV_HDR_SIZE;
1673
1674    drawId = *((CARD32 *) (pc));
1675    buffer = *((INT32 *)  (pc + 4));
1676    num_attribs = *((CARD32 *) (pc + 8));
1677    if (num_attribs > (UINT32_MAX >> 3)) {
1678	client->errorValue = num_attribs;
1679	return BadValue;
1680    }
1681    REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 12 + (num_attribs << 3));
1682
1683    if (buffer != GLX_FRONT_LEFT_EXT)
1684	return __glXError(GLXBadPixmap);
1685
1686    context = __glXForceCurrent (cl, req->contextTag, &error);
1687    if (!context)
1688	return error;
1689
1690    if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP,
1691			  DixReadAccess, &pGlxDraw, &error))
1692	return error;
1693
1694    if (!context->textureFromPixmap)
1695	return __glXError(GLXUnsupportedPrivateRequest);
1696
1697    return context->textureFromPixmap->bindTexImage(context,
1698						    buffer,
1699						    pGlxDraw);
1700}
1701
1702int __glXDisp_ReleaseTexImageEXT(__GLXclientState *cl, GLbyte *pc)
1703{
1704    xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc;
1705    ClientPtr		 client = cl->client;
1706    __GLXdrawable	*pGlxDraw;
1707    __GLXcontext	*context;
1708    GLXDrawable		 drawId;
1709    int			 buffer;
1710    int			 error;
1711
1712    REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 8);
1713
1714    pc += __GLX_VENDPRIV_HDR_SIZE;
1715
1716    drawId = *((CARD32 *) (pc));
1717    buffer = *((INT32 *)  (pc + 4));
1718
1719    context = __glXForceCurrent (cl, req->contextTag, &error);
1720    if (!context)
1721	return error;
1722
1723    if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP,
1724			  DixReadAccess, &pGlxDraw, &error))
1725	return error;
1726
1727    if (!context->textureFromPixmap)
1728	return __glXError(GLXUnsupportedPrivateRequest);
1729
1730    return context->textureFromPixmap->releaseTexImage(context,
1731						       buffer,
1732						       pGlxDraw);
1733}
1734
1735int __glXDisp_CopySubBufferMESA(__GLXclientState *cl, GLbyte *pc)
1736{
1737    xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc;
1738    GLXContextTag         tag = req->contextTag;
1739    __GLXcontext         *glxc = NULL;
1740    __GLXdrawable        *pGlxDraw;
1741    ClientPtr		  client = cl->client;
1742    GLXDrawable		  drawId;
1743    int                   error;
1744    int                   x, y, width, height;
1745
1746    (void) client;
1747    (void) req;
1748
1749    REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 20);
1750
1751    pc += __GLX_VENDPRIV_HDR_SIZE;
1752
1753    drawId = *((CARD32 *) (pc));
1754    x      = *((INT32 *)  (pc + 4));
1755    y      = *((INT32 *)  (pc + 8));
1756    width  = *((INT32 *)  (pc + 12));
1757    height = *((INT32 *)  (pc + 16));
1758
1759    if (tag) {
1760	glxc = __glXLookupContextByTag(cl, tag);
1761	if (!glxc) {
1762	    return __glXError(GLXBadContextTag);
1763	}
1764	/*
1765	** The calling thread is swapping its current drawable.  In this case,
1766	** glxSwapBuffers is in both GL and X streams, in terms of
1767	** sequentiality.
1768	*/
1769	if (__glXForceCurrent(cl, tag, &error)) {
1770	    /*
1771	    ** Do whatever is needed to make sure that all preceding requests
1772	    ** in both streams are completed before the swap is executed.
1773	    */
1774	    CALL_Finish( GET_DISPATCH(), () );
1775	    __GLX_NOTE_FLUSHED_CMDS(glxc);
1776	} else {
1777	    return error;
1778	}
1779    }
1780
1781    pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error);
1782    if (!pGlxDraw)
1783	return error;
1784
1785    if (pGlxDraw == NULL ||
1786	pGlxDraw->type != GLX_DRAWABLE_WINDOW ||
1787	pGlxDraw->copySubBuffer == NULL)
1788	return __glXError(GLXBadDrawable);
1789
1790    (*pGlxDraw->copySubBuffer)(pGlxDraw, x, y, width, height);
1791
1792    return Success;
1793}
1794
1795/*
1796** Get drawable attributes
1797*/
1798static int
1799DoGetDrawableAttributes(__GLXclientState *cl, XID drawId)
1800{
1801    ClientPtr client = cl->client;
1802    xGLXGetDrawableAttributesReply reply;
1803    __GLXdrawable *pGlxDraw;
1804    CARD32 attributes[6];
1805    int numAttribs, error;
1806
1807    if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY,
1808			  DixGetAttrAccess, &pGlxDraw, &error))
1809	return error;
1810
1811    numAttribs = 3;
1812    reply.length = numAttribs << 1;
1813    reply.type = X_Reply;
1814    reply.sequenceNumber = client->sequence;
1815    reply.numAttribs = numAttribs;
1816
1817    attributes[0] = GLX_TEXTURE_TARGET_EXT;
1818    attributes[1] = pGlxDraw->target == GL_TEXTURE_2D ? GLX_TEXTURE_2D_EXT :
1819	GLX_TEXTURE_RECTANGLE_EXT;
1820    attributes[2] = GLX_Y_INVERTED_EXT;
1821    attributes[3] = GL_FALSE;
1822    attributes[4] = GLX_EVENT_MASK;
1823    attributes[5] = pGlxDraw->eventMask;
1824
1825    if (client->swapped) {
1826	__glXSwapGetDrawableAttributesReply(client, &reply, attributes);
1827    } else {
1828	WriteToClient(client, sz_xGLXGetDrawableAttributesReply,
1829		      (char *)&reply);
1830	WriteToClient(client, reply.length * sizeof (CARD32),
1831		      (char *)attributes);
1832    }
1833
1834    return Success;
1835}
1836
1837int __glXDisp_GetDrawableAttributes(__GLXclientState *cl, GLbyte *pc)
1838{
1839    ClientPtr client = cl->client;
1840    xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *)pc;
1841
1842    /* this should be REQUEST_SIZE_MATCH, but mesa sends an additional 4 bytes */
1843    REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq);
1844
1845    return DoGetDrawableAttributes(cl, req->drawable);
1846}
1847
1848int __glXDisp_GetDrawableAttributesSGIX(__GLXclientState *cl, GLbyte *pc)
1849{
1850    ClientPtr client = cl->client;
1851    xGLXGetDrawableAttributesSGIXReq *req =
1852	(xGLXGetDrawableAttributesSGIXReq *)pc;
1853
1854    REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesSGIXReq);
1855
1856    return DoGetDrawableAttributes(cl, req->drawable);
1857}
1858
1859/************************************************************************/
1860
1861/*
1862** Render and Renderlarge are not in the GLX API.  They are used by the GLX
1863** client library to send batches of GL rendering commands.
1864*/
1865
1866/*
1867** Execute all the drawing commands in a request.
1868*/
1869int __glXDisp_Render(__GLXclientState *cl, GLbyte *pc)
1870{
1871    xGLXRenderReq *req;
1872    ClientPtr client= cl->client;
1873    int left, cmdlen, error;
1874    int commandsDone;
1875    CARD16 opcode;
1876    __GLXrenderHeader *hdr;
1877    __GLXcontext *glxc;
1878    __GLX_DECLARE_SWAP_VARIABLES;
1879
1880    REQUEST_AT_LEAST_SIZE(xGLXRenderReq);
1881
1882    req = (xGLXRenderReq *) pc;
1883    if (client->swapped) {
1884	__GLX_SWAP_SHORT(&req->length);
1885	__GLX_SWAP_INT(&req->contextTag);
1886    }
1887
1888    glxc = __glXForceCurrent(cl, req->contextTag, &error);
1889    if (!glxc) {
1890	return error;
1891    }
1892
1893    commandsDone = 0;
1894    pc += sz_xGLXRenderReq;
1895    left = (req->length << 2) - sz_xGLXRenderReq;
1896    while (left > 0) {
1897        __GLXrenderSizeData entry;
1898        int extra;
1899	__GLXdispatchRenderProcPtr proc;
1900	int err;
1901
1902	if (left < sizeof(__GLXrenderHeader))
1903	    return BadLength;
1904
1905	/*
1906	** Verify that the header length and the overall length agree.
1907	** Also, each command must be word aligned.
1908	*/
1909	hdr = (__GLXrenderHeader *) pc;
1910	if (client->swapped) {
1911	    __GLX_SWAP_SHORT(&hdr->length);
1912	    __GLX_SWAP_SHORT(&hdr->opcode);
1913	}
1914	cmdlen = hdr->length;
1915	opcode = hdr->opcode;
1916
1917	/*
1918	** Check for core opcodes and grab entry data.
1919	*/
1920	err = __glXGetProtocolSizeData(& Render_dispatch_info, opcode, & entry);
1921	proc = (__GLXdispatchRenderProcPtr)
1922	    __glXGetProtocolDecodeFunction(& Render_dispatch_info,
1923					   opcode, client->swapped);
1924
1925	if ((err < 0) || (proc == NULL)) {
1926	    client->errorValue = commandsDone;
1927	    return __glXError(GLXBadRenderRequest);
1928	}
1929
1930        if (entry.varsize) {
1931            /* variable size command */
1932            extra = (*entry.varsize)(pc + __GLX_RENDER_HDR_SIZE,
1933				     client->swapped);
1934            if (extra < 0) {
1935                extra = 0;
1936            }
1937            if (cmdlen != __GLX_PAD(entry.bytes + extra)) {
1938                return BadLength;
1939            }
1940        } else {
1941            /* constant size command */
1942            if (cmdlen != __GLX_PAD(entry.bytes)) {
1943                return BadLength;
1944            }
1945        }
1946	if (left < cmdlen) {
1947	    return BadLength;
1948	}
1949
1950	/*
1951	** Skip over the header and execute the command.  We allow the
1952	** caller to trash the command memory.  This is useful especially
1953	** for things that require double alignment - they can just shift
1954	** the data towards lower memory (trashing the header) by 4 bytes
1955	** and achieve the required alignment.
1956	*/
1957	(*proc)(pc + __GLX_RENDER_HDR_SIZE);
1958	pc += cmdlen;
1959	left -= cmdlen;
1960	commandsDone++;
1961    }
1962    __GLX_NOTE_UNFLUSHED_CMDS(glxc);
1963    return Success;
1964}
1965
1966
1967/*
1968** Execute a large rendering request (one that spans multiple X requests).
1969*/
1970int __glXDisp_RenderLarge(__GLXclientState *cl, GLbyte *pc)
1971{
1972    xGLXRenderLargeReq *req;
1973    ClientPtr client= cl->client;
1974    size_t dataBytes;
1975    __GLXrenderLargeHeader *hdr;
1976    __GLXcontext *glxc;
1977    int error;
1978    CARD16 opcode;
1979    __GLX_DECLARE_SWAP_VARIABLES;
1980
1981    req = (xGLXRenderLargeReq *) pc;
1982    if (client->swapped) {
1983	__GLX_SWAP_SHORT(&req->length);
1984	__GLX_SWAP_INT(&req->contextTag);
1985	__GLX_SWAP_INT(&req->dataBytes);
1986	__GLX_SWAP_SHORT(&req->requestNumber);
1987	__GLX_SWAP_SHORT(&req->requestTotal);
1988    }
1989
1990    glxc = __glXForceCurrent(cl, req->contextTag, &error);
1991    if (!glxc) {
1992	/* Reset in case this isn't 1st request. */
1993	__glXResetLargeCommandStatus(cl);
1994	return error;
1995    }
1996    dataBytes = req->dataBytes;
1997
1998    /*
1999    ** Check the request length.
2000    */
2001    if ((req->length << 2) != __GLX_PAD(dataBytes) + sz_xGLXRenderLargeReq) {
2002	client->errorValue = req->length;
2003	/* Reset in case this isn't 1st request. */
2004	__glXResetLargeCommandStatus(cl);
2005	return BadLength;
2006    }
2007    pc += sz_xGLXRenderLargeReq;
2008
2009    if (cl->largeCmdRequestsSoFar == 0) {
2010	__GLXrenderSizeData entry;
2011	int extra;
2012	size_t cmdlen;
2013	int err;
2014
2015	/*
2016	** This is the first request of a multi request command.
2017	** Make enough space in the buffer, then copy the entire request.
2018	*/
2019	if (req->requestNumber != 1) {
2020	    client->errorValue = req->requestNumber;
2021	    return __glXError(GLXBadLargeRequest);
2022	}
2023
2024	hdr = (__GLXrenderLargeHeader *) pc;
2025	if (client->swapped) {
2026	    __GLX_SWAP_INT(&hdr->length);
2027	    __GLX_SWAP_INT(&hdr->opcode);
2028	}
2029	cmdlen = hdr->length;
2030	opcode = hdr->opcode;
2031
2032	/*
2033	** Check for core opcodes and grab entry data.
2034	*/
2035	err = __glXGetProtocolSizeData(& Render_dispatch_info, opcode, & entry);
2036	if (err < 0) {
2037	    client->errorValue = opcode;
2038	    return __glXError(GLXBadLargeRequest);
2039	}
2040
2041	if (entry.varsize) {
2042	    /*
2043	    ** If it's a variable-size command (a command whose length must
2044	    ** be computed from its parameters), all the parameters needed
2045	    ** will be in the 1st request, so it's okay to do this.
2046	    */
2047	    extra = (*entry.varsize)(pc + __GLX_RENDER_LARGE_HDR_SIZE,
2048				     client->swapped);
2049	    if (extra < 0) {
2050		extra = 0;
2051	    }
2052	    /* large command's header is 4 bytes longer, so add 4 */
2053	    if (cmdlen != __GLX_PAD(entry.bytes + 4 + extra)) {
2054		return BadLength;
2055	    }
2056	} else {
2057	    /* constant size command */
2058	    if (cmdlen != __GLX_PAD(entry.bytes + 4)) {
2059		return BadLength;
2060	    }
2061	}
2062	/*
2063	** Make enough space in the buffer, then copy the entire request.
2064	*/
2065	if (cl->largeCmdBufSize < cmdlen) {
2066	    if (!cl->largeCmdBuf) {
2067		cl->largeCmdBuf = (GLbyte *) malloc(cmdlen);
2068	    } else {
2069		cl->largeCmdBuf = (GLbyte *) realloc(cl->largeCmdBuf, cmdlen);
2070	    }
2071	    if (!cl->largeCmdBuf) {
2072		return BadAlloc;
2073	    }
2074	    cl->largeCmdBufSize = cmdlen;
2075	}
2076	memcpy(cl->largeCmdBuf, pc, dataBytes);
2077
2078	cl->largeCmdBytesSoFar = dataBytes;
2079	cl->largeCmdBytesTotal = cmdlen;
2080	cl->largeCmdRequestsSoFar = 1;
2081	cl->largeCmdRequestsTotal = req->requestTotal;
2082	return Success;
2083
2084    } else {
2085	/*
2086	** We are receiving subsequent (i.e. not the first) requests of a
2087	** multi request command.
2088	*/
2089
2090	/*
2091	** Check the request number and the total request count.
2092	*/
2093	if (req->requestNumber != cl->largeCmdRequestsSoFar + 1) {
2094	    client->errorValue = req->requestNumber;
2095	    __glXResetLargeCommandStatus(cl);
2096	    return __glXError(GLXBadLargeRequest);
2097	}
2098	if (req->requestTotal != cl->largeCmdRequestsTotal) {
2099	    client->errorValue = req->requestTotal;
2100	    __glXResetLargeCommandStatus(cl);
2101	    return __glXError(GLXBadLargeRequest);
2102	}
2103
2104	/*
2105	** Check that we didn't get too much data.
2106	*/
2107	if ((cl->largeCmdBytesSoFar + dataBytes) > cl->largeCmdBytesTotal) {
2108	    client->errorValue = dataBytes;
2109	    __glXResetLargeCommandStatus(cl);
2110	    return __glXError(GLXBadLargeRequest);
2111	}
2112	memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes);
2113	cl->largeCmdBytesSoFar += dataBytes;
2114	cl->largeCmdRequestsSoFar++;
2115
2116	if (req->requestNumber == cl->largeCmdRequestsTotal) {
2117	    __GLXdispatchRenderProcPtr proc;
2118
2119	    /*
2120	    ** This is the last request; it must have enough bytes to complete
2121	    ** the command.
2122	    */
2123	    /* NOTE: the two pad macros have been added below; they are needed
2124	    ** because the client library pads the total byte count, but not
2125	    ** the per-request byte counts.  The Protocol Encoding says the
2126	    ** total byte count should not be padded, so a proposal will be
2127	    ** made to the ARB to relax the padding constraint on the total
2128	    ** byte count, thus preserving backward compatibility.  Meanwhile,
2129	    ** the padding done below fixes a bug that did not allow
2130	    ** large commands of odd sizes to be accepted by the server.
2131	    */
2132	    if (__GLX_PAD(cl->largeCmdBytesSoFar) !=
2133		__GLX_PAD(cl->largeCmdBytesTotal)) {
2134		client->errorValue = dataBytes;
2135		__glXResetLargeCommandStatus(cl);
2136		return __glXError(GLXBadLargeRequest);
2137	    }
2138	    hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf;
2139	    /*
2140	    ** The opcode and length field in the header had already been
2141	    ** swapped when the first request was received.
2142	    **
2143	    ** Use the opcode to index into the procedure table.
2144	    */
2145	    opcode = hdr->opcode;
2146
2147	    proc = (__GLXdispatchRenderProcPtr)
2148	      __glXGetProtocolDecodeFunction(& Render_dispatch_info, opcode,
2149					     client->swapped);
2150	    if (proc == NULL) {
2151		client->errorValue = opcode;
2152		return __glXError(GLXBadLargeRequest);
2153	    }
2154
2155	    /*
2156	    ** Skip over the header and execute the command.
2157	    */
2158	    (*proc)(cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
2159	    __GLX_NOTE_UNFLUSHED_CMDS(glxc);
2160
2161	    /*
2162	    ** Reset for the next RenderLarge series.
2163	    */
2164	    __glXResetLargeCommandStatus(cl);
2165	} else {
2166	    /*
2167	    ** This is neither the first nor the last request.
2168	    */
2169	}
2170	return Success;
2171    }
2172}
2173
2174/************************************************************************/
2175
2176/*
2177** No support is provided for the vendor-private requests other than
2178** allocating the entry points in the dispatch table.
2179*/
2180
2181int __glXDisp_VendorPrivate(__GLXclientState *cl, GLbyte *pc)
2182{
2183    ClientPtr client = cl->client;
2184    xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc;
2185    GLint vendorcode = req->vendorCode;
2186    __GLXdispatchVendorPrivProcPtr proc;
2187
2188    REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq);
2189
2190    proc = (__GLXdispatchVendorPrivProcPtr)
2191      __glXGetProtocolDecodeFunction(& VendorPriv_dispatch_info,
2192				     vendorcode, 0);
2193    if (proc != NULL) {
2194	(*proc)(cl, (GLbyte*)req);
2195	return Success;
2196    }
2197
2198    cl->client->errorValue = req->vendorCode;
2199    return __glXError(GLXUnsupportedPrivateRequest);
2200}
2201
2202int __glXDisp_VendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc)
2203{
2204    ClientPtr client = cl->client;
2205    xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc;
2206    GLint vendorcode = req->vendorCode;
2207    __GLXdispatchVendorPrivProcPtr proc;
2208
2209    REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq);
2210
2211    proc = (__GLXdispatchVendorPrivProcPtr)
2212      __glXGetProtocolDecodeFunction(& VendorPriv_dispatch_info,
2213				     vendorcode, 0);
2214    if (proc != NULL) {
2215	return (*proc)(cl, (GLbyte*)req);
2216    }
2217
2218    cl->client->errorValue = vendorcode;
2219    return __glXError(GLXUnsupportedPrivateRequest);
2220}
2221
2222int __glXDisp_QueryExtensionsString(__GLXclientState *cl, GLbyte *pc)
2223{
2224    ClientPtr client = cl->client;
2225    xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc;
2226    xGLXQueryExtensionsStringReply reply;
2227    __GLXscreen *pGlxScreen;
2228    size_t n, length;
2229    char *buf;
2230    int err;
2231
2232    REQUEST_SIZE_MATCH(xGLXQueryExtensionsStringReq);
2233
2234    if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
2235	return err;
2236
2237    n = strlen(pGlxScreen->GLXextensions) + 1;
2238    length = __GLX_PAD(n) >> 2;
2239    reply.type = X_Reply;
2240    reply.sequenceNumber = client->sequence;
2241    reply.length = length;
2242    reply.n = n;
2243
2244    /* Allocate buffer to make sure it's a multiple of 4 bytes big.*/
2245    buf = (char *) malloc(length << 2);
2246    if (buf == NULL)
2247        return BadAlloc;
2248    memcpy(buf, pGlxScreen->GLXextensions, n);
2249
2250    if (client->swapped) {
2251        glxSwapQueryExtensionsStringReply(client, &reply, buf);
2252    } else {
2253        WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply);
2254        WriteToClient(client, (int)(length << 2), (char *)buf);
2255    }
2256
2257    free(buf);
2258    return Success;
2259}
2260
2261int __glXDisp_QueryServerString(__GLXclientState *cl, GLbyte *pc)
2262{
2263    ClientPtr client = cl->client;
2264    xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc;
2265    xGLXQueryServerStringReply reply;
2266    size_t n, length;
2267    const char *ptr;
2268    char *buf;
2269    __GLXscreen *pGlxScreen;
2270    int err;
2271    char ver_str[16];
2272
2273    REQUEST_SIZE_MATCH(xGLXQueryServerStringReq);
2274
2275    if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
2276	return err;
2277
2278    switch(req->name) {
2279	case GLX_VENDOR:
2280	    ptr = pGlxScreen->GLXvendor;
2281	    break;
2282	case GLX_VERSION:
2283	    /* Return to the server version rather than the screen version
2284	     * to prevent confusion when they do not match.
2285	     */
2286	    snprintf(ver_str, 16, "%d.%d", glxMajorVersion, glxMinorVersion);
2287	    ptr = ver_str;
2288	    break;
2289	case GLX_EXTENSIONS:
2290	    ptr = pGlxScreen->GLXextensions;
2291	    break;
2292	default:
2293	    return BadValue;
2294    }
2295
2296    n = strlen(ptr) + 1;
2297    length = __GLX_PAD(n) >> 2;
2298    reply.type = X_Reply;
2299    reply.sequenceNumber = client->sequence;
2300    reply.length = length;
2301    reply.n = n;
2302
2303    buf = (char *) malloc(length << 2);
2304    if (buf == NULL) {
2305        return BadAlloc;
2306    }
2307    memcpy(buf, ptr, n);
2308
2309    if (client->swapped) {
2310        glxSwapQueryServerStringReply(client, &reply, buf);
2311    } else {
2312        WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply);
2313        WriteToClient(client, (int)(length << 2), buf);
2314    }
2315
2316    free(buf);
2317    return Success;
2318}
2319
2320int __glXDisp_ClientInfo(__GLXclientState *cl, GLbyte *pc)
2321{
2322    ClientPtr client = cl->client;
2323    xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc;
2324    const char *buf;
2325
2326    REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq);
2327
2328    buf = (const char *)(req+1);
2329    if (!memchr(buf, 0, (client->req_len << 2) - sizeof(xGLXClientInfoReq)))
2330	return BadLength;
2331
2332    cl->GLClientmajorVersion = req->major;
2333    cl->GLClientminorVersion = req->minor;
2334    free(cl->GLClientextensions);
2335    cl->GLClientextensions = strdup(buf);
2336
2337    return Success;
2338}
2339