/*
 * Copyright © 2005 Novell, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of
 * Novell, Inc. not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.
 * Novell, Inc. makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.
 *
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#include "xgl.h"
#include "xglglx.h"
#include "xglglxext.h"

#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/internal/glcore.h>
#include <GL/glxtokens.h>

#include "glxserver.h"
#include "glxdrawable.h"
#include "glxscreens.h"
#include "glxutil.h"
#include "unpack.h"
#include "g_disptab.h"
#include "glapitable.h"
#include "glxext.h"
#include "micmap.h"
#include "compint.h"

#define XGL_MAX_TEXTURE_UNITS      8
#define XGL_MAX_ATTRIB_STACK_DEPTH 16

#define XGL_TEXTURE_1D_BIT	  (1 << 0)
#define XGL_TEXTURE_2D_BIT	  (1 << 1)
#define XGL_TEXTURE_3D_BIT	  (1 << 2)
#define XGL_TEXTURE_RECTANGLE_BIT (1 << 3)
#define XGL_TEXTURE_CUBE_MAP_BIT  (1 << 4)

extern __GLXprovider *__xglMesaProvider;

typedef struct _xglGLScreen {
    __GLXscreen base;
    __GLXscreen *mesaScreen;
    char	*GLXextensions;
} xglGLScreenRec, *xglGLScreenPtr;

typedef struct _xglGLBuffer {
    __GLXdrawable base;
    __GLXdrawable *mesaDrawable;

    ScreenPtr	     pScreen;
    DrawablePtr	     pDrawable;
    xglVisualPtr     pVisual;
    glitz_drawable_t *drawable;
    glitz_surface_t  *backSurface;
    PixmapPtr	     pPixmap;
    GCPtr	     pGC;
    RegionRec	     damage;
    int		     screenX, screenY;
    int		     xOff, yOff;
    int		     yFlip;
} xglGLBufferRec, *xglGLBufferPtr;

typedef int xglGLXVisualConfigRec, *xglGLXVisualConfigPtr;
typedef struct _xglDisplayList *xglDisplayListPtr;

#define XGL_LIST_OP_CALLS 0
#define XGL_LIST_OP_DRAW  1
#define XGL_LIST_OP_GL    2
#define XGL_LIST_OP_LIST  3

typedef struct _xglGLOp {
    void (*glProc) (struct _xglGLOp *pOp);
    union {
	GLenum     enumeration;
	GLbitfield bitfield;
	GLsizei    size;
	struct {
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	} rect;
	struct {
	    GLenum target;
	    GLuint object;
	} bind_object;
	struct {
	    GLenum  target;
	    GLenum  pname;
	    GLfloat params[4];
	} tex_parameter_fv;
	struct {
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	    GLenum  type;
	} copy_pixels;
	struct {
	    GLenum  target;
	    GLint   level;
	    GLenum  internalformat;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLint   border;
	} copy_tex_image_1d;
	struct {
	    GLenum  target;
	    GLint   level;
	    GLenum  internalformat;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	    GLint   border;
	} copy_tex_image_2d;
	struct {
	    GLenum  target;
	    GLint   level;
	    GLint   xoffset;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	} copy_tex_sub_image_1d;
	struct {
	    GLenum  target;
	    GLint   level;
	    GLint   xoffset;
	    GLint   yoffset;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	} copy_tex_sub_image_2d;
	struct {
	    GLenum  target;
	    GLenum  internalformat;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	} copy_color_table;
	struct {
	    GLenum  target;
	    GLsizei start;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	} copy_color_sub_table;
	struct {
	    GLenum  target;
	    GLenum  internalformat;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	} copy_convolution_filter_1d;
	struct {
	    GLenum  target;
	    GLenum  internalformat;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	} copy_convolution_filter_2d;
	struct {
	    GLenum  target;
	    GLint   level;
	    GLint   xoffset;
	    GLint   yoffset;
	    GLint   zoffset;
	    GLint   x;
	    GLint   y;
	    GLsizei width;
	    GLsizei height;
	} copy_tex_sub_image_3d;
	struct {
	    GLfloat x;
	    GLfloat y;
	    GLfloat z;
	} window_pos_3f;
    } u;
} xglGLOpRec, *xglGLOpPtr;

typedef struct _xglListOp {
    int type;
    union {
	GLuint	   list;
	xglGLOpPtr gl;
    } u;
} xglListOpRec, *xglListOpPtr;

typedef struct _xglDisplayList {
    xglListOpPtr pOp;
    int		 nOp;
    int		 size;
} xglDisplayListRec;

typedef struct _xglTexObj {
    GLuint		   key;
    GLuint		   name;
    PixmapPtr		   pPixmap;
    glitz_texture_object_t *object;
    int			   refcnt;
} xglTexObjRec, *xglTexObjPtr;

typedef struct _xglTexUnit {
    GLbitfield   enabled;
    xglTexObjPtr p1D;
    xglTexObjPtr p2D;
    xglTexObjPtr p3D;
    xglTexObjPtr pRect;
    xglTexObjPtr pCubeMap;
} xglTexUnitRec, *xglTexUnitPtr;

typedef struct _xglGLAttributes {
    GLbitfield	  mask;
    GLenum	  drawBuffer;
    GLenum	  readBuffer;
    xRectangle	  viewport;
    xRectangle	  scissor;
    GLboolean	  scissorTest;
    xglTexUnitRec texUnits[XGL_MAX_TEXTURE_UNITS];
} xglGLAttributesRec, *xglGLAttributesPtr;

typedef struct _xglGLContext {
    __GLXcontext base;
    __GLXcontext *mesaContext;

    int			 refcnt;
    struct _xglGLContext *shared;
    glitz_context_t	 *context;
    struct _glapi_table	 glRenderTable;

    PFNGLACTIVETEXTUREARBPROC ActiveTextureARB;
    PFNGLWINDOWPOS3FMESAPROC WindowPos3fMESA;
    PFNGLISPROGRAMARBPROC IsProgramARB;
    PFNGLGENPROGRAMSARBPROC GenProgramsARB;
    PFNGLBINDPROGRAMARBPROC BindProgramARB;
    PFNGLDELETEPROGRAMSARBPROC DeleteProgramsARB;
    PFNGLISRENDERBUFFEREXTPROC IsRenderbufferEXT;
    PFNGLBINDRENDERBUFFEREXTPROC BindRenderbufferEXT;
    PFNGLDELETERENDERBUFFERSEXTPROC DeleteRenderbuffersEXT;
    PFNGLGENRENDERBUFFERSEXTPROC GenRenderbuffersEXT;
    PFNGLISFRAMEBUFFEREXTPROC IsFramebufferEXT;
    PFNGLBINDFRAMEBUFFEREXTPROC BindFramebufferEXT;
    PFNGLDELETEFRAMEBUFFERSEXTPROC DeleteFramebuffersEXT;
    PFNGLGENFRAMEBUFFERSEXTPROC GenFramebuffersEXT;
    PFNGLFRAMEBUFFERTEXTURE1DEXTPROC FramebufferTexture1DEXT;
    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC FramebufferTexture2DEXT;
    PFNGLFRAMEBUFFERTEXTURE3DEXTPROC FramebufferTexture3DEXT;
    PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC FramebufferRenderbufferEXT;
    PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC
    GetFramebufferAttachmentParameterivEXT;
    PFNGLGENERATEMIPMAPEXTPROC GenerateMipmapEXT;

    Bool		 needInit;
    xglGLBufferPtr	 pDrawBuffer;
    xglGLBufferPtr	 pReadBuffer;
    int			 drawXoff, drawYoff;
    int			 readXoff, readYoff;
    char		 *versionString;
    GLenum		 errorValue;
    GLboolean		 doubleBuffer;
    GLint		 depthBits;
    GLint		 stencilBits;
    xglHashTablePtr	 texObjects;
    xglHashTablePtr	 programObjects;
    xglHashTablePtr	 renderbufferObjects;
    xglHashTablePtr	 framebufferObjects;
    GLuint		 framebuffer;
    xglHashTablePtr	 displayLists;
    GLuint		 list;
    GLenum		 listMode;
    GLuint		 beginCnt;
    xglDisplayListPtr	 pList;
    GLuint		 groupList;
    xglGLAttributesRec	 attrib;
    xglGLAttributesRec	 attribStack[XGL_MAX_ATTRIB_STACK_DEPTH];
    int			 nAttribStack;
    int			 activeTexUnit;
    GLint		 maxTexUnits;
    GLint		 maxListNesting;
    GLint		 maxAttribStackDepth;
} xglGLContextRec, *xglGLContextPtr;

static xglGLContextPtr cctx = NULL;

static BoxRec _largeBox = { SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX };

static void
xglSetCurrentContext (xglGLContextPtr pContext);

#define XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES(pBox, nBox, pScissorBox)	      \
    if (cctx->framebuffer)						      \
    {									      \
	(pBox) = &_largeBox;						      \
	(nBox) = 1;							      \
    }									      \
    else								      \
    {									      \
	(pBox) = REGION_RECTS (cctx->pDrawBuffer->pGC->pCompositeClip);	      \
	(nBox) = REGION_NUM_RECTS (cctx->pDrawBuffer->pGC->pCompositeClip);   \
	(pScissorBox)->x1 = cctx->attrib.scissor.x + cctx->pDrawBuffer->xOff; \
	(pScissorBox)->x2 = (pScissorBox)->x1 + cctx->attrib.scissor.width;   \
	(pScissorBox)->y2 = cctx->attrib.scissor.y + cctx->pDrawBuffer->yOff; \
	(pScissorBox)->y2 = cctx->pDrawBuffer->yFlip - (pScissorBox)->y2;     \
	(pScissorBox)->y1 = (pScissorBox)->y2 - cctx->attrib.scissor.height;  \
    }

#define XGL_GLX_DRAW_PROLOGUE(pBox, nBox, pScissorBox)		      \
    XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES (pBox, nBox, pScissorBox); \
    xglSetupTextures ()

#define XGL_GLX_DRAW_BOX(pBox1, pBox2)			    \
    (pBox1)->x1 = cctx->pDrawBuffer->screenX + (pBox2)->x1; \
    (pBox1)->y1 = cctx->pDrawBuffer->screenY + (pBox2)->y1; \
    (pBox1)->x2 = cctx->pDrawBuffer->screenX + (pBox2)->x2; \
    (pBox1)->y2 = cctx->pDrawBuffer->screenY + (pBox2)->y2

#define XGL_GLX_INTERSECT_BOX(pBox1, pBox2) \
    {					    \
	if ((pBox1)->x1 < (pBox2)->x1)	    \
	    (pBox1)->x1 = (pBox2)->x1;	    \
	if ((pBox1)->y1 < (pBox2)->y1)	    \
	    (pBox1)->y1 = (pBox2)->y1;	    \
	if ((pBox1)->x2 > (pBox2)->x2)	    \
	    (pBox1)->x2 = (pBox2)->x2;	    \
	if ((pBox1)->y2 > (pBox2)->y2)	    \
	    (pBox1)->y2 = (pBox2)->y2;	    \
    }

#define XGL_GLX_SET_SCISSOR_BOX(pBox)			  \
    if (cctx->framebuffer)				  \
    {							  \
	if (cctx->attrib.scissorTest)			  \
	    glScissor (cctx->attrib.scissor.x,		  \
		       cctx->attrib.scissor.y,		  \
		       cctx->attrib.scissor.width,	  \
		       cctx->attrib.scissor.height);	  \
	else						  \
	    glScissor (0, 0, SHRT_MAX, SHRT_MAX);	  \
    }							  \
    else						  \
    {							  \
	glScissor ((pBox)->x1,				  \
		   cctx->pDrawBuffer->yFlip - (pBox)->y2, \
		   (pBox)->x2 - (pBox)->x1,		  \
		   (pBox)->y2 - (pBox)->y1);		  \
    }

#define XGL_GLX_DRAW_DAMAGE(pBox, pRegion)				 \
    if (!cctx->framebuffer && cctx->attrib.drawBuffer != GL_BACK)	 \
    {									 \
	(pRegion)->extents.x1 = (pBox)->x1 - cctx->pDrawBuffer->screenX; \
	(pRegion)->extents.y1 = (pBox)->y1 - cctx->pDrawBuffer->screenY; \
	(pRegion)->extents.x2 = (pBox)->x2 - cctx->pDrawBuffer->screenX; \
	(pRegion)->extents.y2 = (pBox)->y2 - cctx->pDrawBuffer->screenY; \
	(pRegion)->data = (RegDataPtr) NULL;				 \
	REGION_UNION (cctx->pDrawBuffer->pGC->pScreen,			 \
		      &cctx->pDrawBuffer->damage,			 \
		      &cctx->pDrawBuffer->damage,			 \
		      pRegion);						 \
	xglAddBitDamage (cctx->pDrawBuffer->pDrawable, pRegion);	 \
    }


static void
xglSetDrawOffset (int xOff,
		  int yOff)
{
    /* update viewport and raster position */
    if (xOff != cctx->drawXoff || yOff != cctx->drawYoff)
    {
	glViewport (cctx->attrib.viewport.x + xOff,
		    cctx->attrib.viewport.y + yOff,
		    cctx->attrib.viewport.width,
		    cctx->attrib.viewport.height);

	glBitmap (0, 0, 0, 0,
		  xOff - cctx->drawXoff,
		  yOff - cctx->drawYoff,
		  NULL);

	cctx->drawXoff = xOff;
	cctx->drawYoff = yOff;
    }
}

static void
xglRecordError (GLenum error)
{
    if (cctx->errorValue == GL_NO_ERROR)
	cctx->errorValue = error;
}

static xglDisplayListPtr
xglCreateList (void)
{
    xglDisplayListPtr pDisplayList;

    pDisplayList = xalloc (sizeof (xglDisplayListRec));
    if (!pDisplayList)
	return NULL;

    pDisplayList->pOp  = NULL;
    pDisplayList->nOp  = 0;
    pDisplayList->size = 0;

    return pDisplayList;
}

static void
xglDestroyList (xglDisplayListPtr pDisplayList)
{
    xglListOpPtr pOp = pDisplayList->pOp;
    int		 nOp = pDisplayList->nOp;

    while (nOp--)
    {
	switch (pOp->type) {
	case XGL_LIST_OP_CALLS:
	case XGL_LIST_OP_DRAW:
	    glDeleteLists (pOp->u.list, 1);
	    break;
	case XGL_LIST_OP_GL:
	    xfree (pOp->u.gl);
	    break;
	case XGL_LIST_OP_LIST:
	    break;
	}

	pOp++;
    }

    if (pDisplayList->pOp)
	xfree (pDisplayList->pOp);

    xfree (pDisplayList);
}

static Bool
xglResizeList (xglDisplayListPtr pDisplayList,
	       int		 nOp)
{
    if (pDisplayList->size < nOp)
    {
	int size = pDisplayList->nOp ? pDisplayList->nOp : 4;

	while (size < nOp)
	    size <<= 1;

	pDisplayList->pOp = xrealloc (pDisplayList->pOp,
				      sizeof (xglListOpRec) * size);
	if (!pDisplayList->pOp)
	    return FALSE;

	pDisplayList->size = size;
    }

    return TRUE;
}

static void
xglStartList (int    type,
	      GLenum mode)
{
    if (!xglResizeList (cctx->pList, cctx->pList->nOp + 1))
    {
	xglRecordError (GL_OUT_OF_MEMORY);
	return;
    }

    cctx->pList->pOp[cctx->pList->nOp].type   = type;
    cctx->pList->pOp[cctx->pList->nOp].u.list = glGenLists (1);

    glNewList (cctx->pList->pOp[cctx->pList->nOp].u.list, mode);

    cctx->pList->nOp++;
}

static void
xglGLOp (xglGLOpPtr pOp)
{
    if (cctx->list)
    {
	xglGLOpPtr pGLOp;

	pGLOp = xalloc (sizeof (xglGLOpRec));
	if (!pGLOp)
	{
	    xglRecordError (GL_OUT_OF_MEMORY);
	    return;
	}

	if (!xglResizeList (cctx->pList, cctx->pList->nOp + 1))
	{
	    xfree (pGLOp);
	    xglRecordError (GL_OUT_OF_MEMORY);
	    return;
	}

	glEndList ();

	*pGLOp = *pOp;

	cctx->pList->pOp[cctx->pList->nOp].type = XGL_LIST_OP_GL;
	cctx->pList->pOp[cctx->pList->nOp].u.gl = pGLOp;
	cctx->pList->nOp++;

	if (cctx->listMode == GL_COMPILE_AND_EXECUTE)
	    (*pOp->glProc) (pOp);

	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
    }
    else
	(*pOp->glProc) (pOp);
}

static void
xglViewportProc (xglGLOpPtr pOp)
{
    cctx->attrib.viewport.x	 = pOp->u.rect.x;
    cctx->attrib.viewport.y	 = pOp->u.rect.y;
    cctx->attrib.viewport.width  = pOp->u.rect.width;
    cctx->attrib.viewport.height = pOp->u.rect.height;

    glViewport (pOp->u.rect.x + cctx->drawXoff,
		pOp->u.rect.y + cctx->drawYoff,
		pOp->u.rect.width,
		pOp->u.rect.height);
}

static void
xglViewport (GLint   x,
	     GLint   y,
	     GLsizei width,
	     GLsizei height)
{
    xglGLOpRec gl;

    gl.glProc = xglViewportProc;

    gl.u.rect.x	     = x;
    gl.u.rect.y	     = y;
    gl.u.rect.width  = width;
    gl.u.rect.height = height;

    xglGLOp (&gl);
}

static void
xglScissorProc (xglGLOpPtr pOp)
{
    cctx->attrib.scissor.x	= pOp->u.rect.x;
    cctx->attrib.scissor.y	= pOp->u.rect.y;
    cctx->attrib.scissor.width  = pOp->u.rect.width;
    cctx->attrib.scissor.height = pOp->u.rect.height;
}

static void
xglScissor (GLint   x,
	    GLint   y,
	    GLsizei width,
	    GLsizei height)
{
    xglGLOpRec gl;

    gl.glProc = xglScissorProc;

    gl.u.rect.x	     = x;
    gl.u.rect.y	     = y;
    gl.u.rect.width  = width;
    gl.u.rect.height = height;

    xglGLOp (&gl);
}

static void
xglDrawBufferProc (xglGLOpPtr pOp)
{
    glitz_drawable_buffer_t buffers[2];

    if (cctx->framebuffer)
    {
	glDrawBuffer (pOp->u.enumeration);
	return;
    }

    switch (pOp->u.enumeration) {
    case GL_FRONT:
	buffers[0] = GLITZ_DRAWABLE_BUFFER_FRONT_COLOR;
	glitz_context_draw_buffers (cctx->context, buffers, 1);
	break;
    case GL_FRONT_AND_BACK:
	buffers[0] = GLITZ_DRAWABLE_BUFFER_FRONT_COLOR;
	if (cctx->doubleBuffer)
	{
	    buffers[1] = GLITZ_DRAWABLE_BUFFER_BACK_COLOR;
	    glitz_context_draw_buffers (cctx->context, buffers, 2);
	}
	else
	    glitz_context_draw_buffers (cctx->context, buffers, 1);
	break;
    case GL_BACK:
	if (!cctx->doubleBuffer)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}
	buffers[0] = GLITZ_DRAWABLE_BUFFER_BACK_COLOR;
	glitz_context_draw_buffers (cctx->context, buffers, 1);
	break;
    default:
	xglRecordError (GL_INVALID_ENUM);
	return;
    }

    cctx->attrib.drawBuffer = pOp->u.enumeration;
}

static void
xglDrawBuffer (GLenum mode)
{
    xglGLOpRec gl;

    gl.glProc = xglDrawBufferProc;

    gl.u.enumeration = mode;

    xglGLOp (&gl);
}

static void
xglReadBufferProc (xglGLOpPtr pOp)
{
    if (cctx->framebuffer)
    {
	glReadBuffer (pOp->u.enumeration);
	return;
    }

    switch (pOp->u.enumeration) {
    case GL_FRONT:
	glitz_context_read_buffer (cctx->context,
				   GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
	break;
    case GL_BACK:
	if (!cctx->doubleBuffer)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}
	glitz_context_read_buffer (cctx->context,
				   GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
	break;
    default:
	xglRecordError (GL_INVALID_ENUM);
	return;
    }

    cctx->attrib.readBuffer = pOp->u.enumeration;
}

static void
xglReadBuffer (GLenum mode)
{
    xglGLOpRec gl;

    gl.glProc = xglReadBufferProc;

    gl.u.enumeration = mode;

    xglGLOp (&gl);
}

static void
xglDisableProc (xglGLOpPtr pOp)
{
    xglTexUnitPtr pTexUnit = &cctx->attrib.texUnits[cctx->activeTexUnit];

    switch (pOp->u.enumeration) {
    case GL_SCISSOR_TEST:
	cctx->attrib.scissorTest = GL_FALSE;
	return;
    case GL_TEXTURE_1D:
	pTexUnit->enabled &= ~XGL_TEXTURE_1D_BIT;
	break;
    case GL_TEXTURE_2D:
	pTexUnit->enabled &= ~XGL_TEXTURE_2D_BIT;
	break;
    case GL_TEXTURE_3D:
	pTexUnit->enabled &= ~XGL_TEXTURE_3D_BIT;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	pTexUnit->enabled &= ~XGL_TEXTURE_RECTANGLE_BIT;
	break;
    case GL_TEXTURE_CUBE_MAP_ARB:
	pTexUnit->enabled &= ~XGL_TEXTURE_CUBE_MAP_BIT;
	break;
    default:
	break;
    }

    glDisable (pOp->u.enumeration);
}

static void
xglDisable (GLenum cap)
{
    xglGLOpRec gl;

    gl.glProc = xglDisableProc;

    gl.u.enumeration = cap;

    xglGLOp (&gl);
}

static void
xglEnableProc (xglGLOpPtr pOp)
{
    xglTexUnitPtr pTexUnit = &cctx->attrib.texUnits[cctx->activeTexUnit];

    switch (pOp->u.enumeration) {
    case GL_SCISSOR_TEST:
	cctx->attrib.scissorTest = GL_TRUE;
	return;
    case GL_DEPTH_TEST:
	if (!cctx->depthBits)
	    return;
    case GL_STENCIL_TEST:
	if (!cctx->stencilBits)
	    return;
    case GL_TEXTURE_1D:
	pTexUnit->enabled |= XGL_TEXTURE_1D_BIT;
	break;
    case GL_TEXTURE_2D:
	pTexUnit->enabled |= XGL_TEXTURE_2D_BIT;
	break;
    case GL_TEXTURE_3D:
	pTexUnit->enabled |= XGL_TEXTURE_3D_BIT;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	pTexUnit->enabled |= XGL_TEXTURE_RECTANGLE_BIT;
	break;
    case GL_TEXTURE_CUBE_MAP_ARB:
	pTexUnit->enabled |= XGL_TEXTURE_CUBE_MAP_BIT;
	break;
    default:
	break;
    }

    glEnable (pOp->u.enumeration);
}

static void
xglEnable (GLenum cap)
{
    xglGLOpRec gl;

    gl.glProc = xglEnableProc;

    gl.u.enumeration = cap;

    xglGLOp (&gl);
}

static void
xglDeleteTexObj (xglTexObjPtr pTexObj)
{
    if (pTexObj->pPixmap)
    {
	ScreenPtr pScreen = pTexObj->pPixmap->drawable.pScreen;

	(*pScreen->DestroyPixmap) (pTexObj->pPixmap);

	glitz_texture_object_destroy (pTexObj->object);
    }

    if (pTexObj->name)
    {
	glDeleteTextures (1, &pTexObj->name);
    }

    pTexObj->key     = 0;
    pTexObj->name    = 0;
    pTexObj->pPixmap = NULL;
    pTexObj->object  = NULL;
}

static void
xglRefTexObj (xglTexObjPtr pTexObj)
{
    if (!pTexObj)
	return;

    pTexObj->refcnt++;
}

static void
xglUnrefTexObj (xglTexObjPtr pTexObj)
{
    if (!pTexObj)
	return;

    pTexObj->refcnt--;
    if (pTexObj->refcnt)
	return;

    xglDeleteTexObj (pTexObj);

    xfree (pTexObj);
}

static void
xglPushAttribProc (xglGLOpPtr pOp)
{
    xglGLAttributesPtr pAttrib;

    if (cctx->nAttribStack == cctx->maxAttribStackDepth)
    {
	xglRecordError (GL_STACK_OVERFLOW);
	return;
    }

    pAttrib = &cctx->attribStack[cctx->nAttribStack];

    *pAttrib = cctx->attrib;
    pAttrib->mask = pOp->u.bitfield;

    if (pOp->u.bitfield & GL_TEXTURE_BIT)
    {
	int i;

	for (i = 0; i < cctx->maxTexUnits; i++)
	{
	    xglRefTexObj (pAttrib->texUnits[i].p1D);
	    xglRefTexObj (pAttrib->texUnits[i].p2D);
	    xglRefTexObj (pAttrib->texUnits[i].p3D);
	    xglRefTexObj (pAttrib->texUnits[i].pRect);
	    xglRefTexObj (pAttrib->texUnits[i].pCubeMap);
	}
    }

    cctx->nAttribStack++;

    glPushAttrib (pOp->u.bitfield);
}

static void
xglPushAttrib (GLbitfield mask)
{
    xglGLOpRec gl;

    gl.glProc = xglPushAttribProc;

    gl.u.bitfield = mask;

    xglGLOp (&gl);
}

static void
xglPopAttribProc (xglGLOpPtr pOp)
{
    xglGLAttributesPtr pAttrib;
    GLbitfield	       mask;

    if (!cctx->nAttribStack)
    {
	xglRecordError (GL_STACK_UNDERFLOW);
	return;
    }

    cctx->nAttribStack--;

    pAttrib = &cctx->attribStack[cctx->nAttribStack];
    mask = pAttrib->mask;

    if (mask & GL_COLOR_BUFFER_BIT)
	xglDrawBuffer (pAttrib->drawBuffer);

    if (mask & GL_PIXEL_MODE_BIT)
	xglReadBuffer (pAttrib->readBuffer);

    if (mask & GL_SCISSOR_BIT)
    {
	xglScissor (pAttrib->scissor.x,
		    pAttrib->scissor.y,
		    pAttrib->scissor.width,
		    pAttrib->scissor.height);

	if (pAttrib->scissorTest)
	    xglEnable (GL_SCISSOR_TEST);
	else
	    xglDisable (GL_SCISSOR_TEST);
    }
    else if (mask & GL_ENABLE_BIT)
    {
	if (pAttrib->scissorTest)
	    xglEnable (GL_SCISSOR_TEST);
	else
	    xglDisable (GL_SCISSOR_TEST);
    }

    if (mask & GL_VIEWPORT_BIT)
	xglViewport (pAttrib->viewport.x,
		     pAttrib->viewport.y,
		     pAttrib->viewport.width,
		     pAttrib->viewport.height);

    if (mask & GL_TEXTURE_BIT)
    {
	int i;

	for (i = 0; i < cctx->maxTexUnits; i++)
	{
	    xglUnrefTexObj (cctx->attrib.texUnits[i].p1D);
	    xglUnrefTexObj (cctx->attrib.texUnits[i].p2D);
	    xglUnrefTexObj (cctx->attrib.texUnits[i].p3D);
	    xglUnrefTexObj (cctx->attrib.texUnits[i].pRect);
	    xglUnrefTexObj (cctx->attrib.texUnits[i].pCubeMap);

	    cctx->attrib.texUnits[i] = pAttrib->texUnits[i];
	}
    }
    else if (mask & GL_ENABLE_BIT)
    {
	int i;

	for (i = 0; i < cctx->maxTexUnits; i++)
	    cctx->attrib.texUnits[i].enabled = pAttrib->texUnits[i].enabled;
    }

    glPopAttrib ();
}

static void
xglPopAttrib (void)
{
    xglGLOpRec gl;

    gl.glProc = xglPopAttribProc;

    xglGLOp (&gl);
}

static GLuint
xglActiveTextureBinding (GLenum target)
{
    xglTexObjPtr pTexObj;

    switch (target) {
    case GL_TEXTURE_BINDING_1D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p1D;
	break;
    case GL_TEXTURE_BINDING_2D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	break;
    case GL_TEXTURE_BINDING_3D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p3D;
	break;
    case GL_TEXTURE_BINDING_RECTANGLE_NV:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	break;
    case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pCubeMap;
	break;
    default:
	return 0;
    }

    if (pTexObj)
	return pTexObj->key;

    return 0;
}

#define DOUBLE_TO_BOOLEAN(X) ((X) ? GL_TRUE : GL_FALSE)
#define INT_TO_BOOLEAN(I)    ((I) ? GL_TRUE : GL_FALSE)
#define ENUM_TO_BOOLEAN(E)   ((E) ? GL_TRUE : GL_FALSE)

static void
xglGetBooleanv (GLenum	  pname,
		GLboolean *params)
{
    switch (pname) {
    case GL_CURRENT_RASTER_POSITION:
    {
	GLdouble v[4];

	glGetDoublev (GL_CURRENT_RASTER_POSITION, v);

	params[0] = DOUBLE_TO_BOOLEAN (v[0] - (GLdouble) cctx->drawXoff);
	params[1] = DOUBLE_TO_BOOLEAN (v[1] - (GLdouble) cctx->drawYoff);
	params[2] = DOUBLE_TO_BOOLEAN (v[2]);
	params[3] = DOUBLE_TO_BOOLEAN (v[3]);
    } break;
    case GL_DOUBLEBUFFER:
	params[0] = cctx->doubleBuffer;
	break;
    case GL_DEPTH_BITS:
	params[0] = INT_TO_BOOLEAN (cctx->depthBits);
	break;
    case GL_STENCIL_BITS:
	params[0] = INT_TO_BOOLEAN (cctx->stencilBits);
	break;
    case GL_DRAW_BUFFER:
	params[0] = ENUM_TO_BOOLEAN (cctx->attrib.drawBuffer);
	break;
    case GL_READ_BUFFER:
	params[0] = ENUM_TO_BOOLEAN (cctx->attrib.readBuffer);
	break;
    case GL_SCISSOR_BOX:
	params[0] = INT_TO_BOOLEAN (cctx->attrib.scissor.x);
	params[1] = INT_TO_BOOLEAN (cctx->attrib.scissor.y);
	params[2] = INT_TO_BOOLEAN (cctx->attrib.scissor.width);
	params[3] = INT_TO_BOOLEAN (cctx->attrib.scissor.height);
	break;
    case GL_SCISSOR_TEST:
	params[0] = cctx->attrib.scissorTest;
	break;
    case GL_VIEWPORT:
	params[0] = INT_TO_BOOLEAN (cctx->attrib.viewport.x);
	params[1] = INT_TO_BOOLEAN (cctx->attrib.viewport.y);
	params[2] = INT_TO_BOOLEAN (cctx->attrib.viewport.width);
	params[3] = INT_TO_BOOLEAN (cctx->attrib.viewport.height);
	break;
    case GL_TEXTURE_BINDING_1D:
    case GL_TEXTURE_BINDING_2D:
    case GL_TEXTURE_BINDING_3D:
    case GL_TEXTURE_BINDING_RECTANGLE_NV:
    case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
	/* should be safe to fall-through here */
    default:
	glGetBooleanv (pname, params);
    }
}

#define INT_TO_DOUBLE(I)     ((GLdouble) (I))
#define ENUM_TO_DOUBLE(E)    ((GLdouble) (E))
#define BOOLEAN_TO_DOUBLE(B) ((B) ? 1.0F : 0.0F)

static void
xglGetDoublev (GLenum	pname,
	       GLdouble *params)
{
    switch (pname) {
    case GL_CURRENT_RASTER_POSITION:
	glGetDoublev (GL_CURRENT_RASTER_POSITION, params);

	params[0] -= (GLdouble) cctx->drawXoff;
	params[1] -= (GLdouble) cctx->drawYoff;
	break;
    case GL_DOUBLEBUFFER:
	params[0] = BOOLEAN_TO_DOUBLE (cctx->doubleBuffer);
	break;
    case GL_DEPTH_BITS:
	params[0] = INT_TO_DOUBLE (cctx->depthBits);
	break;
    case GL_STENCIL_BITS:
	params[0] = INT_TO_DOUBLE (cctx->stencilBits);
	break;
    case GL_DRAW_BUFFER:
	params[0] = ENUM_TO_DOUBLE (cctx->attrib.drawBuffer);
	break;
    case GL_READ_BUFFER:
	params[0] = ENUM_TO_DOUBLE (cctx->attrib.readBuffer);
	break;
    case GL_SCISSOR_BOX:
	params[0] = cctx->attrib.scissor.x;
	params[1] = cctx->attrib.scissor.y;
	params[2] = cctx->attrib.scissor.width;
	params[3] = cctx->attrib.scissor.height;
	break;
    case GL_SCISSOR_TEST:
	params[0] = BOOLEAN_TO_DOUBLE (cctx->attrib.scissorTest);
	break;
    case GL_VIEWPORT:
	params[0] = cctx->attrib.viewport.x;
	params[1] = cctx->attrib.viewport.y;
	params[2] = cctx->attrib.viewport.width;
	params[3] = cctx->attrib.viewport.height;
	break;
    case GL_TEXTURE_BINDING_1D:
    case GL_TEXTURE_BINDING_2D:
    case GL_TEXTURE_BINDING_3D:
    case GL_TEXTURE_BINDING_RECTANGLE_NV:
    case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
	params[0] = xglActiveTextureBinding (pname);
	break;
    case GL_MAX_TEXTURE_UNITS_ARB:
	params[0] = cctx->maxTexUnits;
	break;
    case GL_MAX_ATTRIB_STACK_DEPTH:
	params[0] = cctx->maxAttribStackDepth;
	break;
    default:
	glGetDoublev (pname, params);
    }
}

#define INT_TO_FLOAT(I)     ((GLfloat) (I))
#define ENUM_TO_FLOAT(E)    ((GLfloat) (E))
#define BOOLEAN_TO_FLOAT(B) ((B) ? 1.0F : 0.0F)

static void
xglGetFloatv (GLenum  pname,
	      GLfloat *params)
{
    switch (pname) {
    case GL_CURRENT_RASTER_POSITION:
	glGetFloatv (GL_CURRENT_RASTER_POSITION, params);

	params[0] -= (GLfloat) cctx->drawXoff;
	params[1] -= (GLfloat) cctx->drawYoff;
	break;
    case GL_DOUBLEBUFFER:
	params[0] = BOOLEAN_TO_FLOAT (cctx->doubleBuffer);
	break;
    case GL_DEPTH_BITS:
	params[0] = INT_TO_FLOAT (cctx->depthBits);
	break;
    case GL_STENCIL_BITS:
	params[0] = INT_TO_FLOAT (cctx->stencilBits);
	break;
    case GL_DRAW_BUFFER:
	params[0] = ENUM_TO_FLOAT (cctx->attrib.drawBuffer);
	break;
    case GL_READ_BUFFER:
	params[0] = ENUM_TO_FLOAT (cctx->attrib.readBuffer);
	break;
    case GL_SCISSOR_BOX:
	params[0] = cctx->attrib.scissor.x;
	params[1] = cctx->attrib.scissor.y;
	params[2] = cctx->attrib.scissor.width;
	params[3] = cctx->attrib.scissor.height;
	break;
    case GL_SCISSOR_TEST:
	params[0] = BOOLEAN_TO_FLOAT (cctx->attrib.scissorTest);
	break;
    case GL_VIEWPORT:
	params[0] = cctx->attrib.viewport.x;
	params[1] = cctx->attrib.viewport.y;
	params[2] = cctx->attrib.viewport.width;
	params[3] = cctx->attrib.viewport.height;
	break;
    case GL_TEXTURE_BINDING_1D:
    case GL_TEXTURE_BINDING_2D:
    case GL_TEXTURE_BINDING_3D:
    case GL_TEXTURE_BINDING_RECTANGLE_NV:
    case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
	params[0] = xglActiveTextureBinding (pname);
	break;
    case GL_MAX_TEXTURE_UNITS_ARB:
	params[0] = cctx->maxTexUnits;
	break;
    case GL_MAX_ATTRIB_STACK_DEPTH:
	params[0] = cctx->maxAttribStackDepth;
	break;
    default:
	glGetFloatv (pname, params);
    }
}

#define ENUM_TO_INT(E)    ((GLint) (E))
#define BOOLEAN_TO_INT(B) ((GLint) (B))

static void
xglGetIntegerv (GLenum pname,
		GLint  *params)
{
    switch (pname) {
    case GL_CURRENT_RASTER_POSITION:
	glGetIntegerv (GL_CURRENT_RASTER_POSITION, params);

	params[0] -= (GLint) cctx->drawXoff;
	params[1] -= (GLint) cctx->drawYoff;
	break;
    case GL_DOUBLEBUFFER:
	params[0] = BOOLEAN_TO_INT (cctx->doubleBuffer);
	break;
    case GL_DEPTH_BITS:
	params[0] = cctx->depthBits;
	break;
    case GL_STENCIL_BITS:
	params[0] = cctx->stencilBits;
	break;
    case GL_DRAW_BUFFER:
	params[0] = ENUM_TO_INT (cctx->attrib.drawBuffer);
	break;
    case GL_READ_BUFFER:
	params[0] = ENUM_TO_INT (cctx->attrib.readBuffer);
	break;
    case GL_SCISSOR_BOX:
	params[0] = cctx->attrib.scissor.x;
	params[1] = cctx->attrib.scissor.y;
	params[2] = cctx->attrib.scissor.width;
	params[3] = cctx->attrib.scissor.height;
	break;
    case GL_SCISSOR_TEST:
	params[0] = BOOLEAN_TO_INT (cctx->attrib.scissorTest);
	break;
    case GL_VIEWPORT:
	params[0] = cctx->attrib.viewport.x;
	params[1] = cctx->attrib.viewport.y;
	params[2] = cctx->attrib.viewport.width;
	params[3] = cctx->attrib.viewport.height;
	break;
    case GL_TEXTURE_BINDING_1D:
    case GL_TEXTURE_BINDING_2D:
    case GL_TEXTURE_BINDING_3D:
    case GL_TEXTURE_BINDING_RECTANGLE_NV:
    case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
	params[0] = xglActiveTextureBinding (pname);
	break;
    case GL_MAX_TEXTURE_UNITS_ARB:
	params[0] = cctx->maxTexUnits;
	break;
    case GL_MAX_ATTRIB_STACK_DEPTH:
	params[0] = cctx->maxAttribStackDepth;
	break;
    default:
	glGetIntegerv (pname, params);
    }
}

static GLboolean
xglIsEnabled (GLenum cap)
{
    switch (cap) {
    case GL_SCISSOR_TEST:
	return cctx->attrib.scissorTest;
    default:
	return glIsEnabled (cap);
    }
}

static GLenum
xglGetError (void)
{
    GLenum error = cctx->errorValue;

    if (error != GL_NO_ERROR)
    {
	cctx->errorValue = GL_NO_ERROR;
	return error;
    }

    return glGetError ();
}

static const GLubyte *
xglGetString (GLenum name)
{
    switch (name) {
    case GL_VERSION:
	if (!cctx->versionString)
	{
	    static char *version = "1.2 (%s)";
	    char	*nativeVersion = (char *) glGetString (GL_VERSION);

	    cctx->versionString = xalloc (strlen (version) +
					  strlen (nativeVersion));
	    if (cctx->versionString)
		sprintf (cctx->versionString, version, nativeVersion);
	}
	return (GLubyte *) cctx->versionString;
    default:
	return glGetString (name);
    }
}

static void
xglGenTextures (GLsizei n,
		GLuint  *textures)
{
    xglTexObjPtr pTexObj;
    GLuint	 name;

    name = xglHashFindFreeKeyBlock (cctx->shared->texObjects, n);

    glGenTextures (n, textures);

    while (n--)
    {
	pTexObj = xalloc (sizeof (xglTexObjRec));
	if (pTexObj)
	{
	    pTexObj->key     = name;
	    pTexObj->name    = *textures;
	    pTexObj->pPixmap = NULL;
	    pTexObj->object  = NULL;
	    pTexObj->refcnt  = 1;

	    xglHashInsert (cctx->shared->texObjects, name, pTexObj);
	}
	else
	{
	    xglRecordError (GL_OUT_OF_MEMORY);
	}

	*textures++ = name++;
    }
}

static void
xglBindTextureProc (xglGLOpPtr pOp)
{
    xglTexObjPtr *ppTexObj;

    switch (pOp->u.bind_object.target) {
    case GL_TEXTURE_1D:
	ppTexObj = &cctx->attrib.texUnits[cctx->activeTexUnit].p1D;
	break;
    case GL_TEXTURE_2D:
	ppTexObj = &cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	break;
    case GL_TEXTURE_3D:
	ppTexObj = &cctx->attrib.texUnits[cctx->activeTexUnit].p3D;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	ppTexObj = &cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	break;
    case GL_TEXTURE_CUBE_MAP_ARB:
	ppTexObj = &cctx->attrib.texUnits[cctx->activeTexUnit].pCubeMap;
	break;
    default:
	xglRecordError (GL_INVALID_ENUM);
	return;
    }

    if (pOp->u.bind_object.object)
    {
	if (!*ppTexObj || pOp->u.bind_object.object != (*ppTexObj)->key)
	{
	    xglTexObjPtr pTexObj;

	    pTexObj = (xglTexObjPtr)
		xglHashLookup (cctx->shared->texObjects,
			       pOp->u.bind_object.object);
	    if (!pTexObj)
	    {
		pTexObj = xalloc (sizeof (xglTexObjRec));
		if (!pTexObj)
		{
		    xglRecordError (GL_OUT_OF_MEMORY);
		    return;
		}

		pTexObj->key     = pOp->u.bind_object.object;
		pTexObj->pPixmap = NULL;
		pTexObj->object  = NULL;
		pTexObj->refcnt  = 1;

		glGenTextures (1, &pTexObj->name);

		xglHashInsert (cctx->shared->texObjects,
			       pOp->u.bind_object.object,
			       pTexObj);
	    }

	    xglRefTexObj (pTexObj);
	    xglUnrefTexObj (*ppTexObj);
	    *ppTexObj = pTexObj;

	    glBindTexture (pOp->u.bind_object.target, pTexObj->name);
	}
    }
    else
    {
	xglUnrefTexObj (*ppTexObj);
	*ppTexObj = NULL;

	glBindTexture (pOp->u.bind_object.target, 0);
    }
}

static void
xglBindTexture (GLenum target,
		GLuint texture)
{
    xglGLOpRec gl;

    gl.glProc = xglBindTextureProc;

    gl.u.bind_object.target = target;
    gl.u.bind_object.object = texture;

    xglGLOp (&gl);
}

static void
xglSetupTextures (void)
{
    xglGLContextPtr pContext = cctx;
    xglTexUnitPtr   pTexUnit;
    xglTexObjPtr    pTexObj[XGL_MAX_TEXTURE_UNITS];
    int		    i, activeTexUnit;

    for (i = 0; i < pContext->maxTexUnits; i++)
    {
	pTexObj[i] = NULL;

	pTexUnit = &pContext->attrib.texUnits[i];
	if (pTexUnit->enabled)
	{
	    if (pTexUnit->enabled & XGL_TEXTURE_RECTANGLE_BIT)
		pTexObj[i] = pTexUnit->pRect;
	    else if (pTexUnit->enabled & XGL_TEXTURE_2D_BIT)
		pTexObj[i] = pTexUnit->p2D;

	    if (pTexObj[i] && pTexObj[i]->pPixmap)
	    {
		if (!xglSyncSurface (&pTexObj[i]->pPixmap->drawable))
		    pTexObj[i] = NULL;
	    }
	    else
		pTexObj[i] = NULL;
	}
    }

    if (pContext != cctx)
    {
	XGL_SCREEN_PRIV (pContext->pDrawBuffer->pGC->pScreen);

	glitz_drawable_finish (pScreenPriv->drawable);

	xglSetCurrentContext (pContext);
    }

    activeTexUnit = cctx->activeTexUnit;
    for (i = 0; i < pContext->maxTexUnits; i++)
    {
	if (pTexObj[i])
	{
	    if (i != activeTexUnit)
	    {
		(*cctx->ActiveTextureARB) (GL_TEXTURE0_ARB + i);
		activeTexUnit = i;
	    }
	    glitz_context_bind_texture (cctx->context, pTexObj[i]->object);
	}
    }

    if (activeTexUnit != cctx->activeTexUnit)
	(*cctx->ActiveTextureARB) (cctx->activeTexUnit);
}

static GLboolean
xglAreTexturesResident (GLsizei	     n,
			const GLuint *textures,
			GLboolean    *residences)
{
    GLboolean allResident = GL_TRUE;
    int	      i, j;

    if (n < 0)
    {
	xglRecordError (GL_INVALID_VALUE);
	return GL_FALSE;
    }

    if (!textures || !residences)
	return GL_FALSE;

    for (i = 0; i < n; i++)
    {
	xglTexObjPtr pTexObj;
	GLboolean    resident;

	if (!textures[i])
	{
	    xglRecordError (GL_INVALID_VALUE);
	    return GL_FALSE;
	}

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						textures[i]);
	if (!pTexObj)
	{
	    xglRecordError (GL_INVALID_VALUE);
	    return GL_FALSE;
	}

	if (pTexObj->name == 0 ||
	    glAreTexturesResident (1, &pTexObj->name, &resident))
	{
	    if (!allResident)
		residences[i] = GL_TRUE;
	}
	else
	{
	    if (allResident)
	    {
		allResident = GL_FALSE;

		for (j = 0; j < i; j++)
		    residences[j] = GL_TRUE;
	    }
	    residences[i] = GL_FALSE;
	}
    }

    return allResident;
}

static void
xglDeleteTextures (GLsizei	n,
		   const GLuint *textures)
{
    xglTexObjPtr pTexObj;

    while (n--)
    {
	if (!*textures)
	    continue;

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						*textures);
	if (pTexObj)
	{
	    xglDeleteTexObj (pTexObj);
	    xglUnrefTexObj (pTexObj);
	    xglHashRemove (cctx->shared->texObjects, *textures);
	}
	textures++;
    }
}

static GLboolean
xglIsTexture (GLuint texture)
{
    xglTexObjPtr pTexObj;

    if (!texture)
	return GL_FALSE;

    pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects, texture);
    if (pTexObj)
	return GL_TRUE;

    return GL_FALSE;
}

static void
xglPrioritizeTextures (GLsizei	      n,
		       const GLuint   *textures,
		       const GLclampf *priorities)
{
    xglTexObjPtr pTexObj;
    int		 i;

    if (n < 0)
    {
	xglRecordError (GL_INVALID_VALUE);
	return;
    }

    if (!priorities)
	return;

    for (i = 0; i < n; i++)
    {
	if (!textures[i])
	    continue;

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						textures[i]);
	if (pTexObj && pTexObj->name)
	    glPrioritizeTextures (1, &pTexObj->name, &priorities[i]);
    }
}

static glitz_texture_filter_t
xglTextureMinFilter (GLenum param)
{
    switch (param) {
    case GL_LINEAR:
	return GLITZ_TEXTURE_FILTER_LINEAR;
    case GL_NEAREST_MIPMAP_NEAREST:
	return GLITZ_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST;
    case GL_LINEAR_MIPMAP_NEAREST:
	return GLITZ_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST;
    case GL_NEAREST_MIPMAP_LINEAR:
	return GLITZ_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR;
    case GL_LINEAR_MIPMAP_LINEAR:
	return GLITZ_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR;
    case GL_NEAREST:
    default:
	return GLITZ_TEXTURE_FILTER_NEAREST;
    }
}

static glitz_texture_filter_t
xglTextureMagFilter (GLenum param)
{
    switch (param) {
    case GL_LINEAR:
	return GLITZ_TEXTURE_FILTER_LINEAR;
    case GL_NEAREST:
    default:
	return GLITZ_TEXTURE_FILTER_NEAREST;
    }
}

static glitz_texture_wrap_t
xglTextureWrap (GLenum param)
{
    switch (param) {
    case GL_CLAMP_TO_EDGE:
	return GLITZ_TEXTURE_WRAP_CLAMP_TO_EDGE;
    case GL_CLAMP_TO_BORDER:
	return GLITZ_TEXTURE_WRAP_CLAMP_TO_BORDER;
    case GL_REPEAT:
	return GLITZ_TEXTURE_WRAP_REPEAT;
    case GL_MIRRORED_REPEAT:
	return GLITZ_TEXTURE_WRAP_MIRRORED_REPEAT;
    case GL_CLAMP:
    default:
	return GLITZ_TEXTURE_WRAP_CLAMP;
    }
}

static void
xglTexParameterfvProc (xglGLOpPtr pOp)
{
    xglTexObjPtr pTexObj;

    glTexParameterfv (pOp->u.tex_parameter_fv.target,
		      pOp->u.tex_parameter_fv.pname,
		      pOp->u.tex_parameter_fv.params);

    switch (pOp->u.tex_parameter_fv.target) {
    case GL_TEXTURE_2D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	break;
    default:
	pTexObj = NULL;
	break;
    }

    if (pTexObj && pTexObj->pPixmap)
    {
	GLfloat *params = pOp->u.tex_parameter_fv.params;

	switch (pOp->u.tex_parameter_fv.pname) {
	case GL_TEXTURE_MIN_FILTER:
	    glitz_texture_object_set_filter (pTexObj->object,
					     GLITZ_TEXTURE_FILTER_TYPE_MIN,
					     xglTextureMinFilter (params[0]));
	    break;
	case GL_TEXTURE_MAG_FILTER:
	    glitz_texture_object_set_filter (pTexObj->object,
					     GLITZ_TEXTURE_FILTER_TYPE_MAG,
					     xglTextureMagFilter (params[0]));
	    break;
	case GL_TEXTURE_WRAP_S:
	    glitz_texture_object_set_wrap (pTexObj->object,
					   GLITZ_TEXTURE_WRAP_TYPE_S,
					   xglTextureWrap (params[0]));
	    break;
	case GL_TEXTURE_WRAP_T:
	    glitz_texture_object_set_wrap (pTexObj->object,
					   GLITZ_TEXTURE_WRAP_TYPE_T,
					   xglTextureWrap (params[0]));
	    break;
	case GL_TEXTURE_BORDER_COLOR: {
	    glitz_color_t color;

	    color.red   = params[0] * 0xffff;
	    color.green = params[1] * 0xffff;
	    color.blue  = params[2] * 0xffff;
	    color.alpha = params[3] * 0xffff;

	    glitz_texture_object_set_border_color (pTexObj->object, &color);
	}
	default:
	    break;
	}
    }
}

static void
xglTexParameterfv (GLenum	 target,
		   GLenum	 pname,
		   const GLfloat *params)
{
    xglGLOpRec gl;

    gl.glProc = xglTexParameterfvProc;

    gl.u.tex_parameter_fv.target = target;
    gl.u.tex_parameter_fv.pname  = pname;

    switch (pname) {
    case GL_TEXTURE_BORDER_COLOR:
	gl.u.tex_parameter_fv.params[3] = params[3];
	gl.u.tex_parameter_fv.params[2] = params[2];
	gl.u.tex_parameter_fv.params[1] = params[1];
	/* fall-through */
    default:
	gl.u.tex_parameter_fv.params[0] = params[0];
	break;
    }

    xglGLOp (&gl);
}

static void
xglTexParameteriv (GLenum      target,
		   GLenum      pname,
		   const GLint *params)
{
    xglGLOpRec gl;

    gl.glProc = xglTexParameterfvProc;

    gl.u.tex_parameter_fv.target = target;
    gl.u.tex_parameter_fv.pname  = pname;

    switch (pname) {
    case GL_TEXTURE_BORDER_COLOR:
	gl.u.tex_parameter_fv.params[3] = (GLfloat) params[3] / INT_MAX;
	gl.u.tex_parameter_fv.params[2] = (GLfloat) params[2] / INT_MAX;
	gl.u.tex_parameter_fv.params[1] = (GLfloat) params[1] / INT_MAX;
	gl.u.tex_parameter_fv.params[0] = (GLfloat) params[0] / INT_MAX;
	break;
    default:
	gl.u.tex_parameter_fv.params[0] = params[0];
	break;
    }

    xglGLOp (&gl);
}

static void
xglTexParameterf (GLenum  target,
		  GLenum  pname,
		  GLfloat param)
{
    xglTexParameterfv (target, pname, (const GLfloat *) &param);
}

static void
xglTexParameteri (GLenum target,
		  GLenum pname,
		  GLint  param)
{
    xglTexParameteriv (target, pname, (const GLint *) &param);
}

static void
xglGetTexLevelParameterfv (GLenum  target,
			   GLint   level,
			   GLenum  pname,
			   GLfloat *params)
{
    xglTexObjPtr pTexObj;

    switch (target) {
    case GL_TEXTURE_2D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	break;
    default:
	pTexObj = NULL;
	break;
    }

    if (pTexObj && pTexObj->pPixmap)
    {
	glitz_context_bind_texture (cctx->context, pTexObj->object);

	glGetTexLevelParameterfv (target, level, pname, params);
	glBindTexture (target, pTexObj->name);
    }
    else
	glGetTexLevelParameterfv (target, level, pname, params);
}

static void
xglGetTexLevelParameteriv (GLenum target,
			   GLint  level,
			   GLenum pname,
			   GLint  *params)
{
    xglTexObjPtr pTexObj;

    switch (target) {
    case GL_TEXTURE_2D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	break;
    case GL_TEXTURE_RECTANGLE_NV:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	break;
    default:
	pTexObj = NULL;
	break;
    }

    if (pTexObj && pTexObj->pPixmap)
    {
	glitz_context_bind_texture (cctx->context, pTexObj->object);

	glGetTexLevelParameteriv (target, level, pname, params);
	glBindTexture (target, pTexObj->name);
    }
    else
	glGetTexLevelParameteriv (target, level, pname, params);
}

static GLuint
xglGenLists (GLsizei range)
{
    xglDisplayListPtr pDisplayList;
    GLuint	      first, name;

    first = xglHashFindFreeKeyBlock (cctx->shared->displayLists, range);

    name = first;
    for (name = first; range--; name++)
    {
	pDisplayList = xglCreateList ();
	if (pDisplayList)
	{
	    xglHashInsert (cctx->shared->displayLists, name, pDisplayList);
	}
	else
	{
	    xglRecordError (GL_OUT_OF_MEMORY);
	}
    }

    return first;
}

static void
xglNewList (GLuint list,
	    GLenum mode)
{
    if (!list)
    {
	xglRecordError (GL_INVALID_VALUE);
	return;
    }

    if (cctx->list)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    cctx->pList = xglCreateList ();
    if (!cctx->pList)
    {
	xglRecordError (GL_OUT_OF_MEMORY);
	return;
    }

    cctx->list     = list;
    cctx->listMode = mode;

    xglStartList (XGL_LIST_OP_CALLS, mode);
}

static void
xglEndList (void)
{
    xglDisplayListPtr pDisplayList;

    if (!cctx->list)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    glEndList ();

    pDisplayList = (xglDisplayListPtr)
	xglHashLookup (cctx->shared->displayLists, cctx->list);
    if (pDisplayList)
    {
	xglHashRemove (cctx->shared->displayLists, cctx->list);
	xglDestroyList (pDisplayList);
    }

    xglHashInsert (cctx->shared->displayLists, cctx->list, cctx->pList);

    cctx->list = 0;
}

static void
xglDrawList (GLuint list)
{
    RegionRec region;
    BoxRec    scissor, box;
    BoxPtr    pBox;
    int	      nBox;

    XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

    while (nBox--)
    {
	XGL_GLX_DRAW_BOX (&box, pBox);

	pBox++;

	if (!cctx->framebuffer && cctx->attrib.scissorTest)
	    XGL_GLX_INTERSECT_BOX (&box, &scissor);

	if (box.x1 < box.x2 && box.y1 < box.y2)
	{
	    XGL_GLX_SET_SCISSOR_BOX (&box);

	    glCallList (list);

	    XGL_GLX_DRAW_DAMAGE (&box, &region);
	}
    }
}

static void
xglCallDisplayList (GLuint list,
		    int	   nesting)
{
    if (nesting > cctx->maxListNesting)
	return;

    if (!list)
    {
	xglRecordError (GL_INVALID_VALUE);
	return;
    }

    if (cctx->list)
    {
	if (!xglResizeList (cctx->pList, cctx->pList->nOp + 1))
	{
	    xglRecordError (GL_OUT_OF_MEMORY);
	    return;
	}

	cctx->pList->pOp[cctx->pList->nOp].type   = XGL_LIST_OP_LIST;
	cctx->pList->pOp[cctx->pList->nOp].u.list = list;
	cctx->pList->nOp++;
    }
    else
    {
	xglDisplayListPtr pDisplayList;

	pDisplayList = (xglDisplayListPtr)
	    xglHashLookup (cctx->shared->displayLists, list);
	if (pDisplayList)
	{
	    xglListOpPtr pOp = pDisplayList->pOp;
	    int		 nOp = pDisplayList->nOp;

	    while (nOp--)
	    {
		switch (pOp->type) {
		case XGL_LIST_OP_CALLS:
		    glCallList (pOp->u.list);
		    break;
		case XGL_LIST_OP_DRAW:
		    xglDrawList (pOp->u.list);
		    break;
		case XGL_LIST_OP_GL:
		    (*pOp->u.gl->glProc) (pOp->u.gl);
		    break;
		case XGL_LIST_OP_LIST:
		    xglCallDisplayList (pOp->u.list, nesting + 1);
		    break;
		}

		pOp++;
	    }
	}
    }
}

static void
xglCallList (GLuint list)
{
    xglCallDisplayList (list, 1);
}

static void
xglCallLists (GLsizei	   n,
	      GLenum	   type,
	      const GLvoid *lists)
{
    GLuint list;
    GLint  base, i;

    glGetIntegerv (GL_LIST_BASE, &base);

    for (i = 0; i < n; i++)
    {
	switch (type) {
	case GL_BYTE:
	    list = (GLuint) *(((GLbyte *) lists) + n);
	    break;
	case GL_UNSIGNED_BYTE:
	    list = (GLuint) *(((GLubyte *) lists) + n);
	    break;
	case GL_SHORT:
	    list = (GLuint) *(((GLshort *) lists) + n);
	    break;
	case GL_UNSIGNED_SHORT:
	    list = (GLuint) *(((GLushort *) lists) + n);
	    break;
	case GL_INT:
	    list = (GLuint) *(((GLint *) lists) + n);
	    break;
	case GL_UNSIGNED_INT:
	    list = (GLuint) *(((GLuint *) lists) + n);
	    break;
	case GL_FLOAT:
	    list = (GLuint) *(((GLfloat *) lists) + n);
	    break;
	case GL_2_BYTES:
	{
	    GLubyte *ubptr = ((GLubyte *) lists) + 2 * n;
	    list = (GLuint) *ubptr * 256 + (GLuint) *(ubptr + 1);
	} break;
	case GL_3_BYTES:
	{
	    GLubyte *ubptr = ((GLubyte *) lists) + 3 * n;
	    list = (GLuint) * ubptr * 65536
		+ (GLuint) * (ubptr + 1) * 256
		+ (GLuint) * (ubptr + 2);
	} break;
	case GL_4_BYTES:
	{
	    GLubyte *ubptr = ((GLubyte *) lists) + 4 * n;
	    list = (GLuint) * ubptr * 16777216
		+ (GLuint) * (ubptr + 1) * 65536
		+ (GLuint) * (ubptr + 2) * 256
		+ (GLuint) * (ubptr + 3);
	} break;
	default:
	    xglRecordError (GL_INVALID_ENUM);
	    return;
	}

	xglCallDisplayList (base + list, 1);
    }
}

static void
xglDeleteLists (GLuint  list,
		GLsizei range)
{
    xglDisplayListPtr pDisplayList;
    GLint	      i;

    if (range < 0)
    {
	xglRecordError (GL_INVALID_VALUE);
	return;
    }

    for (i = list; i < list + range; i++)
    {
	if (!i)
	    continue;

	pDisplayList = (xglDisplayListPtr)
	    xglHashLookup (cctx->shared->displayLists, i);
	if (pDisplayList)
	{
	    xglHashRemove (cctx->shared->displayLists, i);
	    xglDestroyList (pDisplayList);
	}
    }
}

static GLboolean
xglIsList (GLuint list)
{
    xglDisplayListPtr pDisplayList;

    if (!list)
	return GL_FALSE;

    pDisplayList = (xglDisplayListPtr)
	xglHashLookup (cctx->shared->displayLists, list);
    if (pDisplayList)
	return GL_TRUE;

    return GL_FALSE;
}

static void
xglFlush (void)
{
    glFlush ();

    if (cctx && cctx->pDrawBuffer->pDrawable)
    {
	xglGLBufferPtr pBuffer = cctx->pDrawBuffer;

	if (REGION_NOTEMPTY (pBuffer->pDrawable->pScreen, &pBuffer->damage))
	{
	    XGL_DRAWABLE_PIXMAP_PRIV (pBuffer->pDrawable);

	    DamageDamageRegion (pBuffer->pDrawable, &pBuffer->damage);
	    REGION_EMPTY (pBuffer->pDrawable->pScreen, &pBuffer->damage);

	    pPixmapPriv->damageBox = miEmptyBox;
	}
    }
}

static void
xglFinish (void)
{
    glFinish ();

    if (cctx && cctx->pDrawBuffer->pDrawable)
    {
	xglGLBufferPtr pBuffer = cctx->pDrawBuffer;

	if (REGION_NOTEMPTY (pBuffer->pDrawable->pScreen, &pBuffer->damage))
	{
	    XGL_DRAWABLE_PIXMAP_PRIV (pBuffer->pDrawable);

	    DamageDamageRegion (pBuffer->pDrawable, &pBuffer->damage);
	    REGION_EMPTY (pBuffer->pDrawable->pScreen, &pBuffer->damage);

	    pPixmapPriv->damageBox = miEmptyBox;
	}
    }
}

static void
xglClear (GLbitfield mask)
{
    GLenum mode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glClear (mask);
	glEndList ();

	mode = cctx->listMode;
    }
    else
	mode = GL_COMPILE_AND_EXECUTE;

    if (mode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glClear (mask);

		if (mask & GL_COLOR_BUFFER_BIT)
		    XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglAccum (GLenum  op,
	  GLfloat value)
{
    if (op == GL_RETURN)
    {
	GLenum listMode;

	if (cctx->list)
	{
	    glEndList ();
	    xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	    glAccum (GL_RETURN, value);
	    glEndList ();

	    listMode = cctx->listMode;
	}
	else
	    listMode = GL_COMPILE_AND_EXECUTE;

	if (listMode == GL_COMPILE_AND_EXECUTE)
	{
	    RegionRec region;
	    BoxRec    scissor, box;
	    BoxPtr    pBox;
	    int	      nBox;

	    XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES (pBox, nBox, &scissor);

	    while (nBox--)
	    {
		XGL_GLX_DRAW_BOX (&box, pBox);

		pBox++;

		if (!cctx->framebuffer && cctx->attrib.scissorTest)
		    XGL_GLX_INTERSECT_BOX (&box, &scissor);

		if (box.x1 < box.x2 && box.y1 < box.y2)
		{
		    XGL_GLX_SET_SCISSOR_BOX (&box);

		    glAccum (GL_RETURN, value);

		    XGL_GLX_DRAW_DAMAGE (&box, &region);
		}
	    }
	}

	if (cctx->list)
	    xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
    }
    else
	glAccum (op, value);
}

static void
xglDrawArrays (GLenum  mode,
	       GLint   first,
	       GLsizei count)
{
    GLenum listMode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glDrawArrays (mode, first, count);
	glEndList ();

	listMode = cctx->listMode;
    }
    else
	listMode = GL_COMPILE_AND_EXECUTE;

    if (listMode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glDrawArrays (mode, first, count);

		XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglDrawElements (GLenum	      mode,
		 GLsizei      count,
		 GLenum	      type,
		 const GLvoid *indices)
{
    GLenum listMode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glDrawElements (mode, count, type, indices);
	glEndList ();

	listMode = cctx->listMode;
    }
    else
	listMode = GL_COMPILE_AND_EXECUTE;

    if (listMode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glDrawElements (mode, count, type, indices);

		XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglDrawPixels (GLsizei	    width,
	       GLsizei	    height,
	       GLenum	    format,
	       GLenum	    type,
	       const GLvoid *pixels)
{
    GLenum listMode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glDrawPixels (width, height, format, type, pixels);
	glEndList ();

	listMode = cctx->listMode;
    }
    else
	listMode = GL_COMPILE_AND_EXECUTE;

    if (listMode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glDrawPixels (width, height, format, type, pixels);

		if (format != GL_STENCIL_INDEX)
		    XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglBitmap (GLsizei	 width,
	   GLsizei	 height,
	   GLfloat	 xorig,
	   GLfloat	 yorig,
	   GLfloat	 xmove,
	   GLfloat	 ymove,
	   const GLubyte *bitmap)
{
    GLenum listMode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glBitmap (width, height, xorig, yorig, 0, 0, bitmap);
	glEndList ();

	listMode = cctx->listMode;
    }
    else
	listMode = GL_COMPILE_AND_EXECUTE;

    if (listMode == GL_COMPILE_AND_EXECUTE && width && height)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glBitmap (width, height, xorig, yorig, 0, 0, bitmap);

		XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);

    glBitmap (0, 0, 0, 0, xmove, ymove, NULL);
}

static void
xglRectdv (const GLdouble *v1,
	   const GLdouble *v2)
{
    GLenum listMode;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
	glRectdv (v1, v2);
	glEndList ();

	listMode = cctx->listMode;
    }
    else
	listMode = GL_COMPILE_AND_EXECUTE;

    if (listMode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;

	XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		XGL_GLX_SET_SCISSOR_BOX (&box);

		glRectdv (v1, v2);

		XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglRectfv (const GLfloat *v1,
	   const GLfloat *v2)
{
    GLdouble dv1[2];
    GLdouble dv2[2];

    dv1[0] = (GLdouble) v1[0];
    dv1[1] = (GLdouble) v1[1];
    dv2[0] = (GLdouble) v2[0];
    dv2[1] = (GLdouble) v2[1];

    xglRectdv (dv1, dv2);
}

static void
xglRectiv (const GLint *v1,
	   const GLint *v2)
{
    GLdouble dv1[2];
    GLdouble dv2[2];

    dv1[0] = (GLdouble) v1[0];
    dv1[1] = (GLdouble) v1[1];
    dv2[0] = (GLdouble) v2[0];
    dv2[1] = (GLdouble) v2[1];

    xglRectdv (dv1, dv2);
}

static void
xglRectsv (const GLshort *v1,
	   const GLshort *v2)
{
    GLdouble dv1[2];
    GLdouble dv2[2];

    dv1[0] = (GLdouble) v1[0];
    dv1[1] = (GLdouble) v1[1];
    dv2[0] = (GLdouble) v2[0];
    dv2[1] = (GLdouble) v2[1];

    xglRectdv (dv1, dv2);
}

static void
xglBegin (GLenum mode)
{
    if (mode > GL_POLYGON)
    {
	xglRecordError (GL_INVALID_ENUM);
	return;
    }

    if (cctx->beginCnt)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    cctx->beginCnt++;

    if (cctx->list)
    {
	glEndList ();
	xglStartList (XGL_LIST_OP_DRAW, GL_COMPILE);
    }
    else
    {
	if (cctx->framebuffer ||
	    REGION_NUM_RECTS (cctx->pDrawBuffer->pGC->pCompositeClip) == 1)
	{
	    BoxRec scissor, box;
	    BoxPtr pBox;
	    int    nBox;

	    XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	    XGL_GLX_DRAW_BOX (&box, pBox);

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    XGL_GLX_SET_SCISSOR_BOX (&box);
	}
	else
	{
	    if (!cctx->groupList)
		cctx->groupList = glGenLists (1);

	    glNewList (cctx->groupList, GL_COMPILE);
	}
    }

    glBegin (mode);
}

static void
xglEnd (void)
{
    if (!cctx->beginCnt)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    cctx->beginCnt--;

    glEnd ();

    if (!cctx->list || cctx->listMode == GL_COMPILE_AND_EXECUTE)
    {
	RegionRec region;
	BoxRec    scissor, box;
	BoxPtr    pBox;
	int	  nBox;
	GLuint	  list = 0;

	if (cctx->list)
	{
	    XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

	    list = cctx->pList->pOp[cctx->pList->nOp - 1].u.list;
	}
	else
	{
	    if (cctx->framebuffer ||
		REGION_NUM_RECTS (cctx->pDrawBuffer->pGC->pCompositeClip) == 1)
	    {
		XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES (pBox, nBox, &scissor);
	    }
	    else
	    {
		XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

		list = cctx->groupList;
	    }
	}

	if (list)
	    glEndList ();

	while (nBox--)
	{
	    XGL_GLX_DRAW_BOX (&box, pBox);

	    pBox++;

	    if (!cctx->framebuffer && cctx->attrib.scissorTest)
		XGL_GLX_INTERSECT_BOX (&box, &scissor);

	    if (box.x1 < box.x2 && box.y1 < box.y2)
	    {
		if (list)
		{
		    XGL_GLX_SET_SCISSOR_BOX (&box);

		    glCallList (list);
		}

		XGL_GLX_DRAW_DAMAGE (&box, &region);
	    }
	}
    }
    else
    {
	glEndList ();
    }

    if (cctx->list)
	xglStartList (XGL_LIST_OP_CALLS, cctx->listMode);
}

static void
xglCopyPixelsProc (xglGLOpPtr pOp)
{
    RegionRec region;
    BoxRec    scissor, box;
    BoxPtr    pBox;
    int	      nBox;

    XGL_GLX_DRAW_PROLOGUE (pBox, nBox, &scissor);

    while (nBox--)
    {
	XGL_GLX_DRAW_BOX (&box, pBox);

	pBox++;

	if (!cctx->framebuffer && cctx->attrib.scissorTest)
	    XGL_GLX_INTERSECT_BOX (&box, &scissor);

	if (box.x1 < box.x2 && box.y1 < box.y2)
	{
	    XGL_GLX_SET_SCISSOR_BOX (&box);

	    glCopyPixels (pOp->u.copy_pixels.x + cctx->pReadBuffer->xOff,
			  pOp->u.copy_pixels.y + cctx->pReadBuffer->yOff,
			  pOp->u.copy_pixels.width,
			  pOp->u.copy_pixels.height,
			  pOp->u.copy_pixels.type);

	    if (pOp->u.copy_pixels.type == GL_COLOR)
		XGL_GLX_DRAW_DAMAGE (&box, &region);
	}
    }
}

static void
xglCopyPixels (GLint   x,
	       GLint   y,
	       GLsizei width,
	       GLsizei height,
	       GLenum  type)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyPixelsProc;

    gl.u.copy_pixels.x	    = x;
    gl.u.copy_pixels.y	    = y;
    gl.u.copy_pixels.width  = width;
    gl.u.copy_pixels.height = height;
    gl.u.copy_pixels.type   = type;

    xglGLOp (&gl);
}

static void
xglReadPixels (GLint   x,
	       GLint   y,
	       GLsizei width,
	       GLsizei height,
	       GLenum  format,
	       GLenum  type,
	       GLvoid  *pixels)
{
    glReadPixels (x + cctx->readXoff,
		  y + cctx->readYoff,
		  width, height, format, type, pixels);
}

static void
xglCopyTexImage1DProc (xglGLOpPtr pOp)
{
    glCopyTexImage1D (pOp->u.copy_tex_image_1d.target,
		      pOp->u.copy_tex_image_1d.level,
		      pOp->u.copy_tex_image_1d.internalformat,
		      pOp->u.copy_tex_image_1d.x + cctx->readXoff,
		      pOp->u.copy_tex_image_1d.y + cctx->readYoff,
		      pOp->u.copy_tex_image_1d.width,
		      pOp->u.copy_tex_image_1d.border);
}

static void
xglCopyTexImage1D (GLenum  target,
		   GLint   level,
		   GLenum  internalformat,
		   GLint   x,
		   GLint   y,
		   GLsizei width,
		   GLint   border)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyTexImage1DProc;

    gl.u.copy_tex_image_1d.target	  = target;
    gl.u.copy_tex_image_1d.level	  = level;
    gl.u.copy_tex_image_1d.internalformat = internalformat;
    gl.u.copy_tex_image_1d.x		  = x;
    gl.u.copy_tex_image_1d.y		  = y;
    gl.u.copy_tex_image_1d.width	  = width;
    gl.u.copy_tex_image_1d.border	  = border;

    xglGLOp (&gl);
}

static void
xglCopyTexImage2DProc (xglGLOpPtr pOp)
{
    glCopyTexImage2D (pOp->u.copy_tex_image_2d.target,
		      pOp->u.copy_tex_image_2d.level,
		      pOp->u.copy_tex_image_2d.internalformat,
		      pOp->u.copy_tex_image_2d.x + cctx->readXoff,
		      pOp->u.copy_tex_image_2d.y + cctx->readYoff,
		      pOp->u.copy_tex_image_2d.width,
		      pOp->u.copy_tex_image_2d.height,
		      pOp->u.copy_tex_image_2d.border);
}

static void
xglCopyTexImage2D (GLenum  target,
		   GLint   level,
		   GLenum  internalformat,
		   GLint   x,
		   GLint   y,
		   GLsizei width,
		   GLsizei height,
		   GLint   border)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyTexImage2DProc;

    gl.u.copy_tex_image_2d.target	  = target;
    gl.u.copy_tex_image_2d.level	  = level;
    gl.u.copy_tex_image_2d.internalformat = internalformat;
    gl.u.copy_tex_image_2d.x		  = x;
    gl.u.copy_tex_image_2d.y		  = y;
    gl.u.copy_tex_image_2d.width	  = width;
    gl.u.copy_tex_image_2d.height	  = height;
    gl.u.copy_tex_image_2d.border	  = border;

    xglGLOp (&gl);
}

static void
xglCopyTexSubImage1DProc (xglGLOpPtr pOp)
{
    glCopyTexSubImage1D (pOp->u.copy_tex_sub_image_1d.target,
			 pOp->u.copy_tex_sub_image_1d.level,
			 pOp->u.copy_tex_sub_image_1d.xoffset,
			 pOp->u.copy_tex_sub_image_1d.x + cctx->readXoff,
			 pOp->u.copy_tex_sub_image_1d.y + cctx->readYoff,
			 pOp->u.copy_tex_sub_image_1d.width);
}

static void
xglCopyTexSubImage1D (GLenum  target,
		      GLint   level,
		      GLint   xoffset,
		      GLint   x,
		      GLint   y,
		      GLsizei width)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyTexSubImage1DProc;

    gl.u.copy_tex_sub_image_1d.target  = target;
    gl.u.copy_tex_sub_image_1d.level   = level;
    gl.u.copy_tex_sub_image_1d.xoffset = xoffset;
    gl.u.copy_tex_sub_image_1d.x       = x;
    gl.u.copy_tex_sub_image_1d.y       = y;
    gl.u.copy_tex_sub_image_1d.width   = width;

    xglGLOp (&gl);
}

static void
xglCopyTexSubImage2DProc (xglGLOpPtr pOp)
{
    glCopyTexSubImage2D (pOp->u.copy_tex_sub_image_2d.target,
			 pOp->u.copy_tex_sub_image_2d.level,
			 pOp->u.copy_tex_sub_image_2d.xoffset,
			 pOp->u.copy_tex_sub_image_2d.yoffset,
			 pOp->u.copy_tex_sub_image_2d.x + cctx->readXoff,
			 pOp->u.copy_tex_sub_image_2d.y + cctx->readYoff,
			 pOp->u.copy_tex_sub_image_2d.width,
			 pOp->u.copy_tex_sub_image_2d.height);
}

static void
xglCopyTexSubImage2D (GLenum  target,
		      GLint   level,
		      GLint   xoffset,
		      GLint   yoffset,
		      GLint   x,
		      GLint   y,
		      GLsizei width,
		      GLsizei height)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyTexSubImage2DProc;

    gl.u.copy_tex_sub_image_2d.target  = target;
    gl.u.copy_tex_sub_image_2d.level   = level;
    gl.u.copy_tex_sub_image_2d.xoffset = xoffset;
    gl.u.copy_tex_sub_image_2d.yoffset = yoffset;
    gl.u.copy_tex_sub_image_2d.x       = x;
    gl.u.copy_tex_sub_image_2d.y       = y;
    gl.u.copy_tex_sub_image_2d.width   = width;
    gl.u.copy_tex_sub_image_2d.height  = height;

    xglGLOp (&gl);
}

static void
xglCopyColorTableProc (xglGLOpPtr pOp)
{
    glCopyColorTable (pOp->u.copy_color_table.target,
		      pOp->u.copy_color_table.internalformat,
		      pOp->u.copy_color_table.x + cctx->readXoff,
		      pOp->u.copy_color_table.y + cctx->readYoff,
		      pOp->u.copy_color_table.width);
}

static void
xglCopyColorTable (GLenum  target,
		   GLenum  internalformat,
		   GLint   x,
		   GLint   y,
		   GLsizei width)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyColorTableProc;

    gl.u.copy_color_table.target	 = target;
    gl.u.copy_color_table.internalformat = internalformat;
    gl.u.copy_color_table.x		 = x;
    gl.u.copy_color_table.y		 = y;
    gl.u.copy_color_table.width		 = width;

    xglGLOp (&gl);
}

static void
xglCopyColorSubTableProc (xglGLOpPtr pOp)
{
    glCopyColorTable (pOp->u.copy_color_sub_table.target,
		      pOp->u.copy_color_sub_table.start,
		      pOp->u.copy_color_sub_table.x + cctx->readXoff,
		      pOp->u.copy_color_sub_table.y + cctx->readYoff,
		      pOp->u.copy_color_sub_table.width);
}

static void
xglCopyColorSubTable (GLenum  target,
		      GLsizei start,
		      GLint   x,
		      GLint   y,
		      GLsizei width)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyColorSubTableProc;

    gl.u.copy_color_sub_table.target = target;
    gl.u.copy_color_sub_table.start  = start;
    gl.u.copy_color_sub_table.x	     = x;
    gl.u.copy_color_sub_table.y	     = y;
    gl.u.copy_color_sub_table.width  = width;

    xglGLOp (&gl);
}

static void
xglCopyConvolutionFilter1DProc (xglGLOpPtr pOp)
{
    GLenum internalformat = pOp->u.copy_convolution_filter_1d.internalformat;

    glCopyConvolutionFilter1D (pOp->u.copy_convolution_filter_1d.target,
			       internalformat,
			       pOp->u.copy_convolution_filter_1d.x +
			       cctx->readXoff,
			       pOp->u.copy_convolution_filter_1d.y +
			       cctx->readYoff,
			       pOp->u.copy_convolution_filter_1d.width);
}

static void
xglCopyConvolutionFilter1D (GLenum  target,
			    GLenum  internalformat,
			    GLint   x,
			    GLint   y,
			    GLsizei width)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyConvolutionFilter1DProc;

    gl.u.copy_convolution_filter_1d.target	   = target;
    gl.u.copy_convolution_filter_1d.internalformat = internalformat;
    gl.u.copy_convolution_filter_1d.x		   = x;
    gl.u.copy_convolution_filter_1d.y		   = y;
    gl.u.copy_convolution_filter_1d.width	   = width;

    xglGLOp (&gl);
}

static void
xglCopyConvolutionFilter2DProc (xglGLOpPtr pOp)
{
    GLenum internalformat = pOp->u.copy_convolution_filter_2d.internalformat;

    glCopyConvolutionFilter2D (pOp->u.copy_convolution_filter_2d.target,
			       internalformat,
			       pOp->u.copy_convolution_filter_2d.x +
			       cctx->readXoff,
			       pOp->u.copy_convolution_filter_2d.y +
			       cctx->readYoff,
			       pOp->u.copy_convolution_filter_2d.width,
			       pOp->u.copy_convolution_filter_2d.height);
}

static void
xglCopyConvolutionFilter2D (GLenum  target,
			    GLenum  internalformat,
			    GLint   x,
			    GLint   y,
			    GLsizei width,
			    GLsizei height)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyConvolutionFilter2DProc;

    gl.u.copy_convolution_filter_2d.target	   = target;
    gl.u.copy_convolution_filter_2d.internalformat = internalformat;
    gl.u.copy_convolution_filter_2d.x		   = x;
    gl.u.copy_convolution_filter_2d.y		   = y;
    gl.u.copy_convolution_filter_2d.width	   = width;
    gl.u.copy_convolution_filter_2d.height	   = height;

    xglGLOp (&gl);
}

static void
xglCopyTexSubImage3DProc (xglGLOpPtr pOp)
{
    glCopyTexSubImage3D (pOp->u.copy_tex_sub_image_3d.target,
			 pOp->u.copy_tex_sub_image_3d.level,
			 pOp->u.copy_tex_sub_image_3d.xoffset,
			 pOp->u.copy_tex_sub_image_3d.yoffset,
			 pOp->u.copy_tex_sub_image_3d.zoffset,
			 pOp->u.copy_tex_sub_image_3d.x + cctx->readXoff,
			 pOp->u.copy_tex_sub_image_3d.y + cctx->readYoff,
			 pOp->u.copy_tex_sub_image_3d.width,
			 pOp->u.copy_tex_sub_image_3d.height);
}

static void
xglCopyTexSubImage3D (GLenum  target,
		      GLint   level,
		      GLint   xoffset,
		      GLint   yoffset,
		      GLint   zoffset,
		      GLint   x,
		      GLint   y,
		      GLsizei width,
		      GLsizei height)
{
    xglGLOpRec gl;

    gl.glProc = xglCopyTexSubImage3DProc;

    gl.u.copy_tex_sub_image_3d.target  = target;
    gl.u.copy_tex_sub_image_3d.level   = level;
    gl.u.copy_tex_sub_image_3d.xoffset = xoffset;
    gl.u.copy_tex_sub_image_3d.yoffset = yoffset;
    gl.u.copy_tex_sub_image_3d.zoffset = zoffset;
    gl.u.copy_tex_sub_image_3d.x       = x;
    gl.u.copy_tex_sub_image_3d.y       = y;
    gl.u.copy_tex_sub_image_3d.width   = width;
    gl.u.copy_tex_sub_image_3d.height  = height;

    xglGLOp (&gl);
}

/* GL_ARB_multitexture */
static void
xglNoOpActiveTextureARB (GLenum texture) {}
static void
xglActiveTextureARBProc (xglGLOpPtr pOp)
{
    GLenum texUnit;

    texUnit = pOp->u.enumeration - GL_TEXTURE0;
    if (texUnit < 0 || texUnit >= cctx->maxTexUnits)
    {
	xglRecordError (GL_INVALID_ENUM);
    }
    else
    {
	cctx->activeTexUnit = texUnit;
	(*cctx->ActiveTextureARB) (pOp->u.enumeration);
    }
}
static void
xglActiveTextureARB (GLenum texture)
{
    xglGLOpRec gl;

    gl.glProc = xglActiveTextureARBProc;

    gl.u.enumeration = texture;

    xglGLOp (&gl);
}
static void
xglNoOpClientActiveTextureARB (GLenum texture) {}
static void
xglNoOpMultiTexCoord1dvARB (GLenum target, const GLdouble *v) {}
static void
xglNoOpMultiTexCoord1fvARB (GLenum target, const GLfloat *v) {}
static void
xglNoOpMultiTexCoord1ivARB (GLenum target, const GLint *v) {}
static void
xglNoOpMultiTexCoord1svARB (GLenum target, const GLshort *v) {}
static void
xglNoOpMultiTexCoord2dvARB (GLenum target, const GLdouble *v) {}
static void
xglNoOpMultiTexCoord2fvARB (GLenum target, const GLfloat *v) {}
static void
xglNoOpMultiTexCoord2ivARB (GLenum target, const GLint *v) {}
static void
xglNoOpMultiTexCoord2svARB (GLenum target, const GLshort *v) {}
static void
xglNoOpMultiTexCoord3dvARB (GLenum target, const GLdouble *v) {}
static void
xglNoOpMultiTexCoord3fvARB (GLenum target, const GLfloat *v) {}
static void
xglNoOpMultiTexCoord3ivARB (GLenum target, const GLint *v) {}
static void
xglNoOpMultiTexCoord3svARB (GLenum target, const GLshort *v) {}
static void
xglNoOpMultiTexCoord4dvARB (GLenum target, const GLdouble *v) {}
static void
xglNoOpMultiTexCoord4fvARB (GLenum target, const GLfloat *v) {}
static void
xglNoOpMultiTexCoord4ivARB (GLenum target, const GLint *v) {}
static void
xglNoOpMultiTexCoord4svARB (GLenum target, const GLshort *v) {}

/* GL_ARB_multisample */
static void
xglNoOpSampleCoverageARB (GLclampf value, GLboolean invert) {}

/* GL_SGIS_multisample */
static void
xglNoOpSampleMaskSGIS (GLclampf value, GLboolean invert) {}
static void
xglNoOpSamplePatternSGIS (GLenum pattern) {}

/* GL_EXT_point_parameters */
static void
xglNoOpPointParameterfEXT (GLenum pname, GLfloat param) {}
static void
xglNoOpPointParameterfvEXT (GLenum pname, const GLfloat *params) {}

/* GL_MESA_window_pos */
static void
xglNoOpWindowPos3fvMESA (const GLfloat *v) {}
static void
xglWindowPos3fMESAProc (xglGLOpPtr pOp)
{
    (*cctx->WindowPos3fMESA) (pOp->u.window_pos_3f.x + cctx->pDrawBuffer->xOff,
			      pOp->u.window_pos_3f.y + cctx->pDrawBuffer->yOff,
			      pOp->u.window_pos_3f.z);
}
static void
xglWindowPos3fvMESA (const GLfloat *v)
{
    xglGLOpRec gl;

    gl.glProc = xglWindowPos3fMESAProc;

    gl.u.window_pos_3f.x = v[0];
    gl.u.window_pos_3f.y = v[1];
    gl.u.window_pos_3f.z = v[2];

    xglGLOp (&gl);
}

/* GL_EXT_blend_func_separate */
static void
xglNoOpBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB,
			     GLenum sfactorAlpha, GLenum dfactorAlpha) {}

/* GL_EXT_fog_coord */
static void
xglNoOpFogCoordfvEXT (const GLfloat *coord) {}
static void
xglNoOpFogCoorddvEXT (const GLdouble *coord) {}
static void
xglNoOpFogCoordPointerEXT (GLenum type, GLsizei stride,
			   const GLvoid *pointer) {}

/* GL_EXT_secondary_color */
static void
xglNoOpSecondaryColor3bvEXT (const GLbyte *v) {}
static void
xglNoOpSecondaryColor3dvEXT (const GLdouble *v) {}
static void
xglNoOpSecondaryColor3fvEXT (const GLfloat *v) {}
static void
xglNoOpSecondaryColor3ivEXT (const GLint *v) {}
static void
xglNoOpSecondaryColor3svEXT (const GLshort *v) {}
static void
xglNoOpSecondaryColor3ubvEXT (const GLubyte *v) {}
static void
xglNoOpSecondaryColor3uivEXT (const GLuint *v) {}
static void
xglNoOpSecondaryColor3usvEXT (const GLushort *v) {}
static void
xglNoOpSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride,
				 const GLvoid *pointer) {}

/* GL_NV_point_sprite */
static void
xglNoOpPointParameteriNV (GLenum pname, GLint params) {}
static void
xglNoOpPointParameterivNV (GLenum pname, const GLint *params) {}

/* GL_EXT_stencil_two_side */
static void
xglNoOpActiveStencilFaceEXT (GLenum face) {}

/* GL_ARB_vertex_program */
static void
xglNoOpVertexAttrib1svARB (GLuint index, const GLshort *v) {}
static void
xglNoOpVertexAttrib1fvARB (GLuint index, const GLfloat *v) {}
static void
xglNoOpVertexAttrib1dvARB (GLuint index, const GLdouble *v) {}
static void
xglNoOpVertexAttrib2svARB (GLuint index, const GLshort *v) {}
static void
xglNoOpVertexAttrib2fvARB (GLuint index, const GLfloat *v) {}
static void
xglNoOpVertexAttrib2dvARB (GLuint index, const GLdouble *v) {}
static void
xglNoOpVertexAttrib3svARB (GLuint index, const GLshort *v) {}
static void
xglNoOpVertexAttrib3fvARB (GLuint index, const GLfloat *v) {}
static void
xglNoOpVertexAttrib3dvARB (GLuint index, const GLdouble *v) {}
static void
xglNoOpVertexAttrib4bvARB (GLuint index, const GLbyte *v) {}
static void
xglNoOpVertexAttrib4svARB (GLuint index, const GLshort *v) {}
static void
xglNoOpVertexAttrib4ivARB (GLuint index, const GLint *v) {}
static void
xglNoOpVertexAttrib4ubvARB (GLuint index, const GLubyte *v) {}
static void
xglNoOpVertexAttrib4usvARB (GLuint index, const GLushort *v) {}
static void
xglNoOpVertexAttrib4uivARB (GLuint index, const GLuint *v) {}
static void
xglNoOpVertexAttrib4fvARB (GLuint index, const GLfloat *v) {}
static void
xglNoOpVertexAttrib4dvARB (GLuint index, const GLdouble *v) {}
static void
xglNoOpVertexAttrib4NbvARB (GLuint index, const GLbyte *v) {}
static void
xglNoOpVertexAttrib4NsvARB (GLuint index, const GLshort *v) {}
static void
xglNoOpVertexAttrib4NivARB (GLuint index, const GLint *v) {}
static void
xglNoOpVertexAttrib4NubvARB (GLuint index, const GLubyte *v) {}
static void
xglNoOpVertexAttrib4NusvARB (GLuint index, const GLushort *v) {}
static void
xglNoOpVertexAttrib4NuivARB (GLuint index, const GLuint *v) {}
static void
xglNoOpProgramStringARB (GLenum target, GLenum format, GLsizei len,
			 const void *string) {}
static void
xglNoOpBindProgramARB (GLenum target, GLuint program) {}
static void
xglBindProgramARBProc (xglGLOpPtr pOp)
{
    if (pOp->u.bind_object.object)
    {
	GLuint po;

	po = (GLuint) xglHashLookup (cctx->shared->programObjects,
				     pOp->u.bind_object.object);
	if (!po)
	{
	    (*cctx->GenProgramsARB) (1, &po);

	    xglHashInsert (cctx->shared->programObjects,
			   pOp->u.bind_object.object,
			   (void *) po);
	}

	(*cctx->BindProgramARB) (pOp->u.bind_object.target, po);
    }
    else
    {
	(*cctx->BindProgramARB) (pOp->u.bind_object.target, 0);
    }
}
static void
xglBindProgramARB (GLenum target, GLuint program)
{
    xglGLOpRec gl;

    gl.glProc = xglBindProgramARBProc;

    gl.u.bind_object.target = target;
    gl.u.bind_object.object = program;

    xglGLOp (&gl);
}
static void
xglNoOpDeleteProgramsARB (GLsizei n, const GLuint *programs) {}
static void
xglDeleteProgramsARB (GLsizei n, const GLuint *programs)
{
    GLuint po;

    while (n--)
    {
	if (!*programs)
	    continue;

	po = (GLuint) xglHashLookup (cctx->shared->programObjects,
				      *programs);
	if (po)
	{
	    (*cctx->DeleteProgramsARB) (1, &po);
	    xglHashRemove (cctx->shared->programObjects, *programs);
	}
	programs++;
    }
}
static void
xglNoOpGenProgramsARB (GLsizei n, GLuint *programs) {}
static void
xglGenProgramsARB (GLsizei n, GLuint *programs)
{
    GLuint name;

    name = xglHashFindFreeKeyBlock (cctx->shared->programObjects, n);

    (cctx->GenProgramsARB) (n, programs);

    while (n--)
    {
	xglHashInsert (cctx->shared->programObjects, name,
		       (void *) *programs);

	*programs++ = name++;
    }
}
static void
xglNoOpProgramEnvParameter4dvARB (GLenum target, GLuint index,
				  const GLdouble *params) {}
static void
xglNoOpProgramEnvParameter4fvARB (GLenum target, GLuint index,
				  const GLfloat *params) {}
static void
xglNoOpProgramLocalParameter4dvARB (GLenum target, GLuint index,
				    const GLdouble *params) {}
static void
xglNoOpProgramLocalParameter4fvARB (GLenum target, GLuint index,
				    const GLfloat *params) {}
static void
xglNoOpGetProgramEnvParameterdvARB (GLenum target, GLuint index,
				    GLdouble *params) {}
static void
xglNoOpGetProgramEnvParameterfvARB (GLenum target, GLuint index,
				    GLfloat *params) {}
static void
xglNoOpGetProgramLocalParameterdvARB (GLenum target, GLuint index,
				      GLdouble *params) {}
static void
xglNoOpGetProgramLocalParameterfvARB (GLenum target, GLuint index,
				      GLfloat *params) {}
static void
xglNoOpGetProgramivARB (GLenum target, GLenum pname, GLint *params) {}
static void
xglNoOpGetProgramStringARB (GLenum target, GLenum pname, void *string) {}
static void
xglNoOpGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params) {}
static void
xglNoOpGetVertexAttribfvARB (GLuint index,GLenum pname, GLfloat *params) {}
static void
xglNoOpGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params) {}
static GLboolean
xglNoOpIsProgramARB (GLuint program)
{
    return GL_FALSE;
}
static GLboolean
xglIsProgramARB (GLuint program)
{
    if (!program)
	return GL_FALSE;

    if (xglHashLookup (cctx->shared->programObjects, program))
	return GL_TRUE;

    return GL_FALSE;
}

/* GL_EXT_framebuffer_object */
static GLboolean
xglNoOpIsRenderbufferEXT (GLuint renderbuffer)
{
    return FALSE;
}
static GLboolean
xglIsRenderbufferEXT (GLuint renderbuffer)
{
    if (!renderbuffer)
	return GL_FALSE;

    if (xglHashLookup (cctx->shared->renderbufferObjects, renderbuffer))
	return GL_TRUE;

    return GL_FALSE;
}
static void
xglNoOpBindRenderbufferEXT (GLenum target, GLuint renderbuffer) {}
static void
xglBindRenderbufferEXTProc (xglGLOpPtr pOp)
{
    if (pOp->u.bind_object.object)
    {
	GLuint rbo;

	rbo = (GLuint) xglHashLookup (cctx->shared->renderbufferObjects,
				      pOp->u.bind_object.object);
	if (!rbo)
	{
	    (*cctx->GenRenderbuffersEXT) (1, &rbo);

	    xglHashInsert (cctx->shared->renderbufferObjects,
			   pOp->u.bind_object.object,
			   (void *) rbo);
	}

	(*cctx->BindRenderbufferEXT) (pOp->u.bind_object.target, rbo);
    }
    else
    {
	(*cctx->BindRenderbufferEXT) (pOp->u.bind_object.target, 0);
    }
}
static void
xglBindRenderbufferEXT (GLenum target,
			GLuint renderbuffer)
{
    xglGLOpRec gl;

    gl.glProc = xglBindRenderbufferEXTProc;

    gl.u.bind_object.target = target;
    gl.u.bind_object.object = renderbuffer;

    xglGLOp (&gl);
}
static void
xglNoOpDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers) {}
static void
xglDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers)
{
    GLuint rbo;

    while (n--)
    {
	if (!*renderbuffers)
	    continue;

	rbo = (GLuint) xglHashLookup (cctx->shared->renderbufferObjects,
				      *renderbuffers);
	if (rbo)
	{
	    (*cctx->DeleteRenderbuffersEXT) (1, &rbo);
	    xglHashRemove (cctx->shared->renderbufferObjects, *renderbuffers);
	}
	renderbuffers++;
    }
}
static void
xglNoOpGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers) {}
static void
xglGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers)
{
    GLuint name;

    name = xglHashFindFreeKeyBlock (cctx->shared->renderbufferObjects, n);

    (cctx->GenRenderbuffersEXT) (n, renderbuffers);

    while (n--)
    {
	xglHashInsert (cctx->shared->renderbufferObjects, name,
		       (void *) *renderbuffers);

	*renderbuffers++ = name++;
    }
}
static void
xglNoOpRenderbufferStorageEXT (GLenum target, GLenum internalformat,
			       GLsizei width, GLsizei height) {}
static void
xglNoOpGetRenderbufferParameterivEXT (GLenum target, GLenum pname,
				      GLint *params) {}
static GLboolean
xglNoOpIsFramebufferEXT (GLuint framebuffer)
{
    return FALSE;
}
static GLboolean
xglIsFramebufferEXT (GLuint framebuffer)
{
    if (!framebuffer)
	return GL_FALSE;

    if (xglHashLookup (cctx->shared->framebufferObjects, framebuffer))
	return GL_TRUE;

    return GL_FALSE;
}
static void
xglNoOpBindFramebufferEXT (GLenum target, GLuint framebuffer) {}
static void
xglBindFramebufferEXTProc (xglGLOpPtr pOp)
{
    GLuint fbo;

    switch (pOp->u.bind_object.target) {
    case GL_FRAMEBUFFER_EXT:
	fbo = cctx->framebuffer;
	break;
    default:
	xglRecordError (GL_INVALID_ENUM);
	return;
    }

    if (pOp->u.bind_object.object)
    {
	if (pOp->u.bind_object.object != fbo)
	{
	    fbo = (GLuint)
		xglHashLookup (cctx->shared->framebufferObjects,
			       pOp->u.bind_object.object);
	    if (!fbo)
	    {
		(*cctx->GenFramebuffersEXT) (1, &fbo);

		xglHashInsert (cctx->shared->framebufferObjects,
			       pOp->u.bind_object.object,
			       (void *) fbo);
	    }

	    if (!cctx->framebuffer)
	    {
		xglSetDrawOffset (0, 0);

		cctx->readXoff = 0;
		cctx->readYoff = 0;
	    }

	    (*cctx->BindFramebufferEXT) (GL_FRAMEBUFFER_EXT, fbo);
	}
    }
    else
    {
	(*cctx->BindFramebufferEXT) (GL_FRAMEBUFFER_EXT, 0);

	/* window-system drawable */
	glitz_context_make_current (cctx->context, cctx->pDrawBuffer->drawable);

	xglSetDrawOffset (cctx->pDrawBuffer->xOff, cctx->pDrawBuffer->yOff);

	cctx->readXoff = cctx->pReadBuffer->xOff;
	cctx->readYoff = cctx->pReadBuffer->yOff;
    }

    cctx->framebuffer = pOp->u.bind_object.object;
}
static void
xglBindFramebufferEXT (GLenum target,
		       GLuint framebuffer)
{
    xglGLOpRec gl;

    gl.glProc = xglBindFramebufferEXTProc;

    gl.u.bind_object.target = target;
    gl.u.bind_object.object = framebuffer;

    xglGLOp (&gl);
}
static void
xglNoOpDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers) {}
static void
xglDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers)
{
    GLuint fbo;

    while (n--)
    {
	if (!*framebuffers)
	    continue;

	fbo = (GLuint) xglHashLookup (cctx->shared->framebufferObjects,
				      *framebuffers);
	if (fbo)
	{
	    (*cctx->DeleteFramebuffersEXT) (1, &fbo);
	    xglHashRemove (cctx->shared->framebufferObjects, *framebuffers);
	}
	framebuffers++;
    }
}
static void
xglNoOpGenFramebuffersEXT (GLsizei n, GLuint *framebuffers) {}
static void
xglGenFramebuffersEXT (GLsizei n, GLuint *framebuffers)
{
    GLuint name;

    name = xglHashFindFreeKeyBlock (cctx->shared->framebufferObjects, n);

    (cctx->GenFramebuffersEXT) (n, framebuffers);

    while (n--)
    {
	xglHashInsert (cctx->shared->framebufferObjects, name,
		       (void *) *framebuffers);

	*framebuffers++ = name++;
    }
}
static GLenum
xglNoOpCheckFramebufferStatusEXT (GLenum target)
{
    return GL_FRAMEBUFFER_UNSUPPORTED_EXT;
}
static void
xglNoOpFramebufferTexture1DEXT (GLenum target,
				GLenum attachment,
				GLenum textarget,
				GLuint texture,
				GLint  level) {}
static void
xglFramebufferTexture1DEXT (GLenum target,
			    GLenum attachment,
			    GLenum textarget,
			    GLuint texture,
			    GLint  level)
{
    if (!cctx->framebuffer)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    if (texture)
    {
	xglTexObjPtr pTexObj;

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						texture);
	if (!pTexObj)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}

	texture = pTexObj->name;
    }

    (*cctx->FramebufferTexture1DEXT) (target,
				      attachment,
				      textarget,
				      texture,
				      level);
}
static void
xglNoOpFramebufferTexture2DEXT (GLenum target,
				GLenum attachment,
				GLenum textarget,
				GLuint texture,
				GLint  level) {}
static void
xglFramebufferTexture2DEXT (GLenum target,
			    GLenum attachment,
			    GLenum textarget,
			    GLuint texture,
			    GLint  level)
{
    if (!cctx->framebuffer)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    if (texture)
    {
	xglTexObjPtr pTexObj;

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						texture);
	if (!pTexObj)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}

	texture = pTexObj->name;
    }

    (*cctx->FramebufferTexture2DEXT) (target,
				      attachment,
				      textarget,
				      texture,
				      level);
}
static void
xglNoOpFramebufferTexture3DEXT (GLenum target,
				GLenum attachment,
				GLenum textarget,
				GLuint texture,
				GLint  level,
				GLint  zoffset) {}
static void
xglFramebufferTexture3DEXT (GLenum target,
			    GLenum attachment,
			    GLenum textarget,
			    GLuint texture,
			    GLint  level,
			    GLint  zoffset)
{
    if (!cctx->framebuffer)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    if (texture)
    {
	xglTexObjPtr pTexObj;

	pTexObj = (xglTexObjPtr) xglHashLookup (cctx->shared->texObjects,
						texture);
	if (!pTexObj)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}

	texture = pTexObj->name;
    }

    (*cctx->FramebufferTexture3DEXT) (target,
				      attachment,
				      textarget,
				      texture,
				      level,
				      zoffset);
}
static void
xglNoOpFramebufferRenderbufferEXT (GLenum target,
				   GLenum attachment,
				   GLenum renderbuffertarget,
				   GLuint renderbuffer) {}
static void
xglFramebufferRenderbufferEXT (GLenum target,
			       GLenum attachment,
			       GLenum renderbuffertarget,
			       GLuint renderbuffer)
{
    if (!cctx->framebuffer)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    if (renderbuffer)
    {
	renderbuffer = (GLuint)
	    xglHashLookup (cctx->shared->renderbufferObjects,
			   renderbuffer);
	if (!renderbuffer)
	{
	    xglRecordError (GL_INVALID_OPERATION);
	    return;
	}
    }

    (*cctx->FramebufferRenderbufferEXT) (target,
					 attachment,
					 renderbuffertarget,
					 renderbuffer);
}
static void
xglNoOpGetFramebufferAttachmentParameterivEXT (GLenum target,
					       GLenum attachment,
					       GLenum pname,
					       GLint *params) {}
static void
xglGetFramebufferAttachmentParameterivEXT (GLenum target,
					   GLenum attachment,
					   GLenum pname,
					   GLint *params)
{
    if (!cctx->framebuffer)
    {
	xglRecordError (GL_INVALID_OPERATION);
	return;
    }

    (*cctx->GetFramebufferAttachmentParameterivEXT) (target,
						     attachment,
						     pname,
						     params);

    if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT)
    {
	GLint type;

	pname = GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT;

	(*cctx->GetFramebufferAttachmentParameterivEXT) (target,
							 attachment,
							 pname,
							 &type);

	switch (type) {
	case GL_RENDERBUFFER_EXT:
	    *params = (GLint) xglHashLookup (cctx->shared->renderbufferObjects,
					     *params);
	    break;
	case GL_TEXTURE:
	    *params = (GLint) xglHashLookup (cctx->shared->texObjects,
					     *params);
	    break;
	}
    }
}
static void
xglNoOpGenerateMipmapEXT (GLenum target) {}

static void
xglGenerateMipmapEXT (GLenum target)
{
    xglTexObjPtr pTexObj = NULL;

    switch (target) {
    case GL_TEXTURE_2D:
	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
    default:
	break;
    }

    if (pTexObj)
    {
	if (pTexObj->pPixmap)
	{
	    xglGLContextPtr pContext = cctx;

	    if (xglSyncSurface (&pTexObj->pPixmap->drawable))
	    {
		if (pContext != cctx)
		{
		    XGL_SCREEN_PRIV (pContext->pDrawBuffer->pGC->pScreen);

		    glitz_drawable_finish (pScreenPriv->drawable);

		    xglSetCurrentContext (pContext);
		}

		glitz_context_bind_texture (cctx->context, pTexObj->object);
	    }
	    else
		pTexObj = NULL;
	}

	if (pTexObj)
	    (*cctx->GenerateMipmapEXT) (target);
    }
}

static struct _glapi_table __glNativeRenderTable = {
    xglNewList,
    xglEndList,
    xglCallList,
    xglCallLists,
    xglDeleteLists,
    xglGenLists,
    glListBase,
    xglBegin,
    xglBitmap,
    0, /* glColor3b */
    glColor3bv,
    0, /* glColor3d */
    glColor3dv,
    0, /* glColor3f */
    glColor3fv,
    0, /* glColor3i */
    glColor3iv,
    0, /* glColor3s */
    glColor3sv,
    0, /* glColor3ub */
    glColor3ubv,
    0, /* glColor3ui */
    glColor3uiv,
    0, /* glColor3us */
    glColor3usv,
    0, /* glColor4b */
    glColor4bv,
    0, /* glColor4d */
    glColor4dv,
    0, /* glColor4f */
    glColor4fv,
    0, /* glColor4i */
    glColor4iv,
    0, /* glColor4s */
    glColor4sv,
    0, /* glColor4ub */
    glColor4ubv,
    0, /* glColor4ui */
    glColor4uiv,
    0, /* glColor4us */
    glColor4usv,
    0, /* glEdgeFlag */
    glEdgeFlagv,
    xglEnd,
    0, /* glIndexd */
    glIndexdv,
    0, /* glIndexf */
    glIndexfv,
    0, /* glIndexi */
    glIndexiv,
    0, /* glIndexs */
    glIndexsv,
    0, /* glNormal3b */
    glNormal3bv,
    0, /* glNormal3d */
    glNormal3dv,
    0, /* glNormal3f */
    glNormal3fv,
    0, /* glNormal3i */
    glNormal3iv,
    0, /* glNormal3s */
    glNormal3sv,
    0, /* glRasterPos2d */
    glRasterPos2dv,
    0, /* glRasterPos2f */
    glRasterPos2fv,
    0, /* glRasterPos2i */
    glRasterPos2iv,
    0, /* glRasterPos2s */
    glRasterPos2sv,
    0, /* glRasterPos3d */
    glRasterPos3dv,
    0, /* glRasterPos3f */
    glRasterPos3fv,
    0, /* glRasterPos3i */
    glRasterPos3iv,
    0, /* glRasterPos3s */
    glRasterPos3sv,
    0, /* glRasterPos4d */
    glRasterPos4dv,
    0, /* glRasterPos4f */
    glRasterPos4fv,
    0, /* glRasterPos4i */
    glRasterPos4iv,
    0, /* glRasterPos4s */
    glRasterPos4sv,
    0, /* glRectd */
    xglRectdv,
    0, /* glRectf */
    xglRectfv,
    0, /* glRecti */
    xglRectiv,
    0, /* glRects */
    xglRectsv,
    0, /* glTexCoord1d */
    glTexCoord1dv,
    0, /* glTexCoord1f */
    glTexCoord1fv,
    0, /* glTexCoord1i */
    glTexCoord1iv,
    0, /* glTexCoord1s */
    glTexCoord1sv,
    0, /* glTexCoord2d */
    glTexCoord2dv,
    0, /* glTexCoord2f */
    glTexCoord2fv,
    0, /* glTexCoord2i */
    glTexCoord2iv,
    0, /* glTexCoord2s */
    glTexCoord2sv,
    0, /* glTexCoord3d */
    glTexCoord3dv,
    0, /* glTexCoord3f */
    glTexCoord3fv,
    0, /* glTexCoord3i */
    glTexCoord3iv,
    0, /* glTexCoord3s */
    glTexCoord3sv,
    0, /* glTexCoord4d */
    glTexCoord4dv,
    0, /* glTexCoord4f */
    glTexCoord4fv,
    0, /* glTexCoord4i */
    glTexCoord4iv,
    0, /* glTexCoord4s */
    glTexCoord4sv,
    0, /* glVertex2d */
    glVertex2dv,
    0, /* glVertex2f */
    glVertex2fv,
    0, /* glVertex2i */
    glVertex2iv,
    0, /* glVertex2s */
    glVertex2sv,
    0, /* glVertex3d */
    glVertex3dv,
    0, /* glVertex3f */
    glVertex3fv,
    0, /* glVertex3i */
    glVertex3iv,
    0, /* glVertex3s */
    glVertex3sv,
    0, /* glVertex4d */
    glVertex4dv,
    0, /* glVertex4f */
    glVertex4fv,
    0, /* glVertex4i */
    glVertex4iv,
    0, /* glVertex4s */
    glVertex4sv,
    glClipPlane,
    glColorMaterial,
    glCullFace,
    glFogf,
    glFogfv,
    glFogi,
    glFogiv,
    glFrontFace,
    glHint,
    glLightf,
    glLightfv,
    glLighti,
    glLightiv,
    glLightModelf,
    glLightModelfv,
    glLightModeli,
    glLightModeliv,
    glLineStipple,
    glLineWidth,
    glMaterialf,
    glMaterialfv,
    glMateriali,
    glMaterialiv,
    glPointSize,
    glPolygonMode,
    glPolygonStipple,
    xglScissor,
    glShadeModel,
    xglTexParameterf,
    xglTexParameterfv,
    xglTexParameteri,
    xglTexParameteriv,
    glTexImage1D,
    glTexImage2D,
    glTexEnvf,
    glTexEnvfv,
    glTexEnvi,
    glTexEnviv,
    glTexGend,
    glTexGendv,
    glTexGenf,
    glTexGenfv,
    glTexGeni,
    glTexGeniv,
    glFeedbackBuffer,
    glSelectBuffer,
    glRenderMode,
    glInitNames,
    glLoadName,
    glPassThrough,
    glPopName,
    glPushName,
    xglDrawBuffer,
    xglClear,
    glClearAccum,
    glClearIndex,
    glClearColor,
    glClearStencil,
    glClearDepth,
    glStencilMask,
    glColorMask,
    glDepthMask,
    glIndexMask,
    xglAccum,
    xglDisable,
    xglEnable,
    xglFinish,
    xglFlush,
    xglPopAttrib,
    xglPushAttrib,
    glMap1d,
    glMap1f,
    glMap2d,
    glMap2f,
    glMapGrid1d,
    glMapGrid1f,
    glMapGrid2d,
    glMapGrid2f,
    0, /* glEvalCoord1d */
    glEvalCoord1dv,
    0, /* glEvalCoord1f */
    glEvalCoord1fv,
    0, /* glEvalCoord2d */
    glEvalCoord2dv,
    0, /* glEvalCoord2f */
    glEvalCoord2fv,
    glEvalMesh1,
    glEvalPoint1,
    glEvalMesh2,
    glEvalPoint2,
    glAlphaFunc,
    glBlendFunc,
    glLogicOp,
    glStencilFunc,
    glStencilOp,
    glDepthFunc,
    glPixelZoom,
    glPixelTransferf,
    glPixelTransferi,
    glPixelStoref,
    glPixelStorei,
    glPixelMapfv,
    glPixelMapuiv,
    glPixelMapusv,
    xglReadBuffer,
    xglCopyPixels,
    xglReadPixels,
    xglDrawPixels,
    xglGetBooleanv,
    glGetClipPlane,
    xglGetDoublev,
    xglGetError,
    xglGetFloatv,
    xglGetIntegerv,
    glGetLightfv,
    glGetLightiv,
    glGetMapdv,
    glGetMapfv,
    glGetMapiv,
    glGetMaterialfv,
    glGetMaterialiv,
    glGetPixelMapfv,
    glGetPixelMapuiv,
    glGetPixelMapusv,
    glGetPolygonStipple,
    xglGetString,
    glGetTexEnvfv,
    glGetTexEnviv,
    glGetTexGendv,
    glGetTexGenfv,
    glGetTexGeniv,
    glGetTexImage,
    glGetTexParameterfv,
    glGetTexParameteriv,
    xglGetTexLevelParameterfv,
    xglGetTexLevelParameteriv,
    xglIsEnabled,
    xglIsList,
    glDepthRange,
    glFrustum,
    glLoadIdentity,
    glLoadMatrixf,
    glLoadMatrixd,
    glMatrixMode,
    glMultMatrixf,
    glMultMatrixd,
    glOrtho,
    glPopMatrix,
    glPushMatrix,
    glRotated,
    glRotatef,
    glScaled,
    glScalef,
    glTranslated,
    glTranslatef,
    xglViewport,
    glArrayElement,
    xglBindTexture,
    glColorPointer,
    glDisableClientState,
    xglDrawArrays,
    xglDrawElements,
    glEdgeFlagPointer,
    glEnableClientState,
    glIndexPointer,
    0, /* glIndexub */
    glIndexubv,
    glInterleavedArrays,
    glNormalPointer,
    glPolygonOffset,
    glTexCoordPointer,
    glVertexPointer,
    xglAreTexturesResident,
    xglCopyTexImage1D,
    xglCopyTexImage2D,
    xglCopyTexSubImage1D,
    xglCopyTexSubImage2D,
    xglDeleteTextures,
    xglGenTextures,
    glGetPointerv,
    xglIsTexture,
    xglPrioritizeTextures,
    glTexSubImage1D,
    glTexSubImage2D,
    glPopClientAttrib,
    glPushClientAttrib,
    glBlendColor,
    glBlendEquation,
    0, /* glDrawRangeElements */
    glColorTable,
    glColorTableParameterfv,
    glColorTableParameteriv,
    xglCopyColorTable,
    glGetColorTable,
    glGetColorTableParameterfv,
    glGetColorTableParameteriv,
    glColorSubTable,
    xglCopyColorSubTable,
    glConvolutionFilter1D,
    glConvolutionFilter2D,
    glConvolutionParameterf,
    glConvolutionParameterfv,
    glConvolutionParameteri,
    glConvolutionParameteriv,
    xglCopyConvolutionFilter1D,
    xglCopyConvolutionFilter2D,
    glGetConvolutionFilter,
    glGetConvolutionParameterfv,
    glGetConvolutionParameteriv,
    glGetSeparableFilter,
    glSeparableFilter2D,
    glGetHistogram,
    glGetHistogramParameterfv,
    glGetHistogramParameteriv,
    glGetMinmax,
    glGetMinmaxParameterfv,
    glGetMinmaxParameteriv,
    glHistogram,
    glMinmax,
    glResetHistogram,
    glResetMinmax,
    glTexImage3D,
    glTexSubImage3D,
    xglCopyTexSubImage3D,
    xglNoOpActiveTextureARB,
    xglNoOpClientActiveTextureARB,
    0, /* glMultiTexCoord1dARB */
    xglNoOpMultiTexCoord1dvARB,
    0, /* glMultiTexCoord1fARB */
    xglNoOpMultiTexCoord1fvARB,
    0, /* glMultiTexCoord1iARB */
    xglNoOpMultiTexCoord1ivARB,
    0, /* glMultiTexCoord1sARB */
    xglNoOpMultiTexCoord1svARB,
    0, /* glMultiTexCoord2dARB */
    xglNoOpMultiTexCoord2dvARB,
    0, /* glMultiTexCoord2fARB */
    xglNoOpMultiTexCoord2fvARB,
    0, /* glMultiTexCoord2iARB */
    xglNoOpMultiTexCoord2ivARB,
    0, /* glMultiTexCoord2sARB */
    xglNoOpMultiTexCoord2svARB,
    0, /* glMultiTexCoord3dARB */
    xglNoOpMultiTexCoord3dvARB,
    0, /* glMultiTexCoord3fARB */
    xglNoOpMultiTexCoord3fvARB,
    0, /* glMultiTexCoord3iARB */
    xglNoOpMultiTexCoord3ivARB,
    0, /* glMultiTexCoord3sARB */
    xglNoOpMultiTexCoord3svARB,
    0, /* glMultiTexCoord4dARB */
    xglNoOpMultiTexCoord4dvARB,
    0, /* glMultiTexCoord4fARB */
    xglNoOpMultiTexCoord4fvARB,
    0, /* glMultiTexCoord4iARB */
    xglNoOpMultiTexCoord4ivARB,
    0, /* glMultiTexCoord4sARB */
    xglNoOpMultiTexCoord4svARB,
    0, /* glStencilFuncSeparate */
    0, /* glStencilOpSeparate */
    0, /* glStencilMaskSeparate */
    0, /* glLoadTransposeMatrixfARB */
    0, /* glLoadTransposeMatrixdARB */
    0, /* glMultTransposeMatrixfARB */
    0, /* glMultTransposeMatrixdARB */
    xglNoOpSampleCoverageARB,
    0, /* glCompressedTexImage1DARB */
    0, /* glCompressedTexImage2DARB */
    0, /* glCompressedTexImage3DARB */
    0, /* glCompressedTexSubImage1DARB */
    0, /* glCompressedTexSubImage2DARB */
    0, /* glCompressedTexSubImage3DARB */
    0, /* glGetCompressedTexImageARB */
    0, /* glDisableVertexAttribArrayARB */
    0, /* glEnableVertexAttribArrayARB */
    xglNoOpGetProgramEnvParameterdvARB,
    xglNoOpGetProgramEnvParameterfvARB,
    xglNoOpGetProgramLocalParameterdvARB,
    xglNoOpGetProgramLocalParameterfvARB,
    xglNoOpGetProgramStringARB,
    xglNoOpGetProgramivARB,
    xglNoOpGetVertexAttribdvARB,
    xglNoOpGetVertexAttribfvARB,
    xglNoOpGetVertexAttribivARB,
    0, /* glProgramEnvParameter4dARB */
    xglNoOpProgramEnvParameter4dvARB,
    0, /* glProgramEnvParameter4fARB */
    xglNoOpProgramEnvParameter4fvARB,
    0, /* glProgramLocalParameter4dARB */
    xglNoOpProgramLocalParameter4dvARB,
    0, /* glProgramLocalParameter4fARB */
    xglNoOpProgramLocalParameter4fvARB,
    xglNoOpProgramStringARB,
    0, /* glVertexAttrib1dARB */
    xglNoOpVertexAttrib1dvARB,
    0, /* glVertexAttrib1fARB */
    xglNoOpVertexAttrib1fvARB,
    0, /* glVertexAttrib1sARB */
    xglNoOpVertexAttrib1svARB,
    0, /* glVertexAttrib2dARB */
    xglNoOpVertexAttrib2dvARB,
    0, /* glVertexAttrib2fARB */
    xglNoOpVertexAttrib2fvARB,
    0, /* glVertexAttrib2sARB */
    xglNoOpVertexAttrib2svARB,
    0, /* glVertexAttrib3dARB */
    xglNoOpVertexAttrib3dvARB,
    0, /* glVertexAttrib3fARB */
    xglNoOpVertexAttrib3fvARB,
    0, /* glVertexAttrib3sARB */
    xglNoOpVertexAttrib3svARB,
    xglNoOpVertexAttrib4NbvARB,
    xglNoOpVertexAttrib4NivARB,
    xglNoOpVertexAttrib4NsvARB,
    0, /* glVertexAttrib4NubARB */
    xglNoOpVertexAttrib4NubvARB,
    xglNoOpVertexAttrib4NuivARB,
    xglNoOpVertexAttrib4NusvARB,
    xglNoOpVertexAttrib4bvARB,
    0, /* glVertexAttrib4dARB */
    xglNoOpVertexAttrib4dvARB,
    0, /* glVertexAttrib4fARB */
    xglNoOpVertexAttrib4fvARB,
    xglNoOpVertexAttrib4ivARB,
    0, /* glVertexAttrib4sARB */
    xglNoOpVertexAttrib4svARB,
    xglNoOpVertexAttrib4ubvARB,
    xglNoOpVertexAttrib4uivARB,
    xglNoOpVertexAttrib4usvARB,
    0, /* glVertexAttribPointerARB */
    0, /* glBindBufferARB */
    0, /* glBufferDataARB */
    0, /* glBufferSubDataARB */
    0, /* glDeleteBuffersARB */
    0, /* glGenBuffersARB */
    0, /* glGetBufferParameterivARB */
    0, /* glGetBufferPointervARB */
    0, /* glGetBufferSubDataARB */
    0, /* glIsBufferARB */
    0, /* glMapBufferARB */
    0, /* glUnmapBufferARB */
    0, /* glBeginQueryARB */
    0, /* glDeleteQueriesARB */
    0, /* glEndQueryARB */
    0, /* glGenQueriesARB */
    0, /* glGetQueryObjectivARB */
    0, /* glGetQueryObjectuivARB */
    0, /* glGetQueryivARB */
    0, /* IsQueryARB */
    0, /* glAttachObjectARB */
    0, /* glCompileShaderARB */
    0, /* CreateProgramObjectARB */
    0, /* CreateShaderObjectARB */
    0, /* glDeleteObjectARB */
    0, /* glDetachObjectARB */
    0, /* glGetActiveUniformARB */
    0, /* glGetAttachedObjectsARB */
    0, /* GetHandleARB */
    0, /* glGetInfoLogARB */
    0, /* glGetObjectParameterfvARB */
    0, /* glGetObjectParameterivARB */
    0, /* glGetShaderSourceARB */
    0, /* GetUniformLocationARB */
    0, /* glGetUniformfvARB */
    0, /* glGetUniformivARB */
    0, /* glLinkProgramARB */
    0, /* glShaderSourceARB */
    0, /* glUniform1fARB */
    0, /* glUniform1fvARB */
    0, /* glUniform1iARB */
    0, /* glUniform1ivARB */
    0, /* glUniform2fARB */
    0, /* glUniform2fvARB */
    0, /* glUniform2iARB */
    0, /* glUniform2ivARB */
    0, /* glUniform3fARB */
    0, /* glUniform3fvARB */
    0, /* glUniform3iARB */
    0, /* glUniform3ivARB */
    0, /* glUniform4fARB */
    0, /* glUniform4fvARB */
    0, /* glUniform4iARB */
    0, /* glUniform4ivARB */
    0, /* glUniformMatrix2fvARB */
    0, /* glUniformMatrix3fvARB */
    0, /* glUniformMatrix4fvARB */
    0, /* glUseProgramObjectARB */
    0, /* glValidateProgramARB */
    0, /* glBindAttribLocationARB */
    0, /* glGetActiveAttribARB */
    0, /* GetAttribLocationARB */
    0, /* glDrawBuffersARB */
    0, /* glPolygonOffsetEXT */
    0, /* glGetPixelTexGenParameterfvSGIS */
    0, /* glGetPixelTexGenParameterivSGIS */
    0, /* glPixelTexGenParameterfSGIS */
    0, /* glPixelTexGenParameterfvSGIS */
    0, /* glPixelTexGenParameteriSGIS */
    0, /* glPixelTexGenParameterivSGIS */
    xglNoOpSampleMaskSGIS,
    xglNoOpSamplePatternSGIS,
    0, /* glColorPointerEXT */
    0, /* glEdgeFlagPointerEXT */
    0, /* glIndexPointerEXT */
    0, /* glNormalPointerEXT */
    0, /* glTexCoordPointerEXT */
    0, /* glVertexPointerEXT */
    xglNoOpPointParameterfEXT,
    xglNoOpPointParameterfvEXT,
    0, /* glLockArraysEXT */
    0, /* glUnlockArraysEXT */
    0, /* glCullParameterdvEXT */
    0, /* glCullParameterfvEXT */
    0, /* glSecondaryColor3bEXT */
    xglNoOpSecondaryColor3bvEXT,
    0, /* glSecondaryColor3dEXT */
    xglNoOpSecondaryColor3dvEXT,
    0, /* glSecondaryColor3fEXT */
    xglNoOpSecondaryColor3fvEXT,
    0, /* glSecondaryColor3iEXT */
    xglNoOpSecondaryColor3ivEXT,
    0, /* glSecondaryColor3sEXT */
    xglNoOpSecondaryColor3svEXT,
    0, /* glSecondaryColor3ubEXT */
    xglNoOpSecondaryColor3ubvEXT,
    0, /* glSecondaryColor3uiEXT */
    xglNoOpSecondaryColor3uivEXT,
    0, /* glSecondaryColor3usEXT */
    xglNoOpSecondaryColor3usvEXT,
    xglNoOpSecondaryColorPointerEXT,
    0, /* glMultiDrawArraysEXT */
    0, /* glMultiDrawElementsEXT */
    xglNoOpFogCoordPointerEXT,
    0, /* glFogCoorddEXT */
    xglNoOpFogCoorddvEXT,
    0, /* glFogCoordfEXT */
    xglNoOpFogCoordfvEXT,
    0, /* glPixelTexGenSGIX */
    xglNoOpBlendFuncSeparateEXT,
    0, /* glFlushVertexArrayRangeNV */
    0, /* glVertexArrayRangeNV */
    0, /* glCombinerInputNV */
    0, /* glCombinerOutputNV */
    0, /* glCombinerParameterfNV */
    0, /* glCombinerParameterfvNV */
    0, /* glCombinerParameteriNV */
    0, /* glCombinerParameterivNV */
    0, /* glFinalCombinerInputNV */
    0, /* glGetCombinerInputParameterfvNV */
    0, /* glGetCombinerInputParameterivNV */
    0, /* glGetCombinerOutputParameterfvNV */
    0, /* glGetCombinerOutputParameterivNV */
    0, /* glGetFinalCombinerInputParameterfvNV */
    0, /* glGetFinalCombinerInputParameterivNV */
    0, /* glResizeBuffersMESA */
    0, /* glWindowPos2dMESA */
    0, /* glWindowPos2dvMESA */
    0, /* glWindowPos2fMESA */
    0, /* glWindowPos2fvMESA */
    0, /* glWindowPos2iMESA */
    0, /* glWindowPos2ivMESA */
    0, /* glWindowPos2sMESA */
    0, /* glWindowPos2svMESA */
    0, /* glWindowPos3dMESA */
    0, /* glWindowPos3dvMESA */
    0, /* glWindowPos3fMESA */
    xglNoOpWindowPos3fvMESA,
    0, /* glWindowPos3iMESA */
    0, /* glWindowPos3ivMESA */
    0, /* glWindowPos3sMESA */
    0, /* glWindowPos3svMESA */
    0, /* glWindowPos4dMESA */
    0, /* glWindowPos4dvMESA */
    0, /* glWindowPos4fMESA */
    0, /* glWindowPos4fvMESA */
    0, /* glWindowPos4iMESA */
    0, /* glWindowPos4ivMESA */
    0, /* glWindowPos4sMESA */
    0, /* glWindowPos4svMESA */
    0, /* glMultiModeDrawArraysIBM */
    0, /* glMultiModeDrawElementsIBM */
    0, /* glDeleteFencesNV */
    0, /* glFinishFenceNV */
    0, /* glGenFencesNV */
    0, /* glGetFenceivNV */
    0, /* glIsFenceNV */
    0, /* glSetFenceNV */
    0, /* glTestFenceNV */
    0, /* glAreProgramsResidentNV */
    xglNoOpBindProgramARB,
    xglNoOpDeleteProgramsARB,
    0, /* glExecuteProgramNV */
    xglNoOpGenProgramsARB,
    0, /* glGetProgramParameterdvNV */
    0, /* glGetProgramParameterfvNV */
    0, /* glGetProgramStringNV */
    0, /* glGetProgramivNV */
    0, /* glGetTrackMatrixivNV */
    0, /* glGetVertexAttribPointervNV */
    0, /* glGetVertexAttribdvNV */
    0, /* glGetVertexAttribfvNV */
    0, /* glGetVertexAttribivNV */
    xglNoOpIsProgramARB,
    0, /* glLoadProgramNV */
    0, /* glProgramParameter4dNV */
    0, /* glProgramParameter4dvNV */
    0, /* glProgramParameter4fNV */
    0, /* glProgramParameter4fvNV */
    0, /* glProgramParameters4dvNV */
    0, /* glProgramParameters4fvNV */
    0, /* glRequestResidentProgramsNV */
    0, /* glTrackMatrixNV */
    0, /* glVertexAttrib1dNV */
    0, /* glVertexAttrib1dvNV */
    0, /* glVertexAttrib1fNV */
    0, /* glVertexAttrib1fvNV */
    0, /* glVertexAttrib1sNV */
    0, /* glVertexAttrib1svNV */
    0, /* glVertexAttrib2dNV */
    0, /* glVertexAttrib2dvNV */
    0, /* glVertexAttrib2fNV */
    0, /* glVertexAttrib2fvNV */
    0, /* glVertexAttrib2sNV */
    0, /* glVertexAttrib2svNV */
    0, /* glVertexAttrib3dNV */
    0, /* glVertexAttrib3dvNV */
    0, /* glVertexAttrib3fNV */
    0, /* glVertexAttrib3fvNV */
    0, /* glVertexAttrib3sNV */
    0, /* glVertexAttrib3svNV */
    0, /* glVertexAttrib4dNV */
    0, /* glVertexAttrib4dvNV */
    0, /* glVertexAttrib4fNV */
    0, /* glVertexAttrib4fvNV */
    0, /* glVertexAttrib4sNV */
    0, /* glVertexAttrib4svNV */
    0, /* glVertexAttrib4ubNV */
    0, /* glVertexAttrib4ubvNV */
    0, /* glVertexAttribPointerNV */
    0, /* glVertexAttribs1dvNV */
    0, /* glVertexAttribs1fvNV */
    0, /* glVertexAttribs1svNV */
    0, /* glVertexAttribs2dvNV */
    0, /* glVertexAttribs2fvNV */
    0, /* glVertexAttribs2svNV */
    0, /* glVertexAttribs3dvNV */
    0, /* glVertexAttribs3fvNV */
    0, /* glVertexAttribs3svNV */
    0, /* glVertexAttribs4dvNV */
    0, /* glVertexAttribs4fvNV */
    0, /* glVertexAttribs4svNV */
    0, /* glVertexAttribs4ubvNV */
    0, /* glAlphaFragmentOp1ATI */
    0, /* glAlphaFragmentOp2ATI */
    0, /* glAlphaFragmentOp3ATI */
    0, /* glBeginFragmentShaderATI */
    0, /* glBindFragmentShaderATI */
    0, /* glColorFragmentOp1ATI */
    0, /* glColorFragmentOp2ATI */
    0, /* glColorFragmentOp3ATI */
    0, /* glDeleteFragmentShaderATI */
    0, /* glEndFragmentShaderATI */
    0, /* glGenFragmentShadersATI */
    0, /* glPassTexCoordATI */
    0, /* glSampleMapATI */
    0, /* glSetFragmentShaderConstantATI */
    xglNoOpPointParameteriNV,
    xglNoOpPointParameterivNV,
    xglNoOpActiveStencilFaceEXT,
    0, /* glBindVertexArrayAPPLE */
    0, /* glDeleteVertexArraysAPPLE */
    0, /* glGenVertexArraysAPPLE */
    0, /* glIsVertexArrayAPPLE */
    0, /* glGetProgramNamedParameterdvNV */
    0, /* glGetProgramNamedParameterfvNV */
    0, /* glProgramNamedParameter4dNV */
    0, /* glProgramNamedParameter4fNV */
    0, /* glProgramNamedParameter4dvNV */
    0, /* glProgramNamedParameter4fvNV */
    0, /* glDepthBoundsEXT */
    0, /* glBlendEquationSeparateEXT */
    xglNoOpBindFramebufferEXT,
    xglNoOpBindRenderbufferEXT,
    xglNoOpCheckFramebufferStatusEXT,
    xglNoOpDeleteFramebuffersEXT,
    xglNoOpDeleteRenderbuffersEXT,
    xglNoOpFramebufferRenderbufferEXT,
    xglNoOpFramebufferTexture1DEXT,
    xglNoOpFramebufferTexture2DEXT,
    xglNoOpFramebufferTexture3DEXT,
    xglNoOpGenFramebuffersEXT,
    xglNoOpGenRenderbuffersEXT,
    xglNoOpGenerateMipmapEXT,
    xglNoOpGetFramebufferAttachmentParameterivEXT,
    xglNoOpGetRenderbufferParameterivEXT,
    xglNoOpIsFramebufferEXT,
    xglNoOpIsRenderbufferEXT,
    xglNoOpRenderbufferStorageEXT,
    0, /* glBlitFramebufferEXT */
    0, /* glProgramEnvParameters4fvEXT */
    0, /* glProgramLocalParameters4fvEXT */
    0, /* glGetQueryObjecti64vEXT */
    0  /* glGetQueryObjectui64vEXT */
};

static void
xglInitExtensions (xglGLContextPtr pContext)
{
    const char *extensions;

    extensions = (const char *) glGetString (GL_EXTENSIONS);

    if (strstr (extensions, "GL_ARB_multitexture"))
    {
	pContext->ActiveTextureARB =
	    (PFNGLACTIVETEXTUREARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glActiveTextureARB");
	pContext->glRenderTable.ClientActiveTextureARB =
	    (PFNGLCLIENTACTIVETEXTUREARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glClientActiveTextureARB");
	pContext->glRenderTable.MultiTexCoord1dvARB =
	    (PFNGLMULTITEXCOORD1DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord1dvARB");
	pContext->glRenderTable.MultiTexCoord1fvARB =
	    (PFNGLMULTITEXCOORD1FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord1fvARB");
	pContext->glRenderTable.MultiTexCoord1ivARB =
	    (PFNGLMULTITEXCOORD1IVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord1ivARB");
	pContext->glRenderTable.MultiTexCoord1svARB =
	    (PFNGLMULTITEXCOORD1SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord1svARB");
	pContext->glRenderTable.MultiTexCoord2dvARB =
	    (PFNGLMULTITEXCOORD2DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord2dvARB");
	pContext->glRenderTable.MultiTexCoord2fvARB =
	    (PFNGLMULTITEXCOORD2FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord2fvARB");
	pContext->glRenderTable.MultiTexCoord2ivARB =
	    (PFNGLMULTITEXCOORD2IVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord2ivARB");
	pContext->glRenderTable.MultiTexCoord2svARB =
	    (PFNGLMULTITEXCOORD2SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord2svARB");
	pContext->glRenderTable.MultiTexCoord3dvARB =
	    (PFNGLMULTITEXCOORD3DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord3dvARB");
	pContext->glRenderTable.MultiTexCoord3fvARB =
	    (PFNGLMULTITEXCOORD3FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord3fvARB");
	pContext->glRenderTable.MultiTexCoord3ivARB =
	    (PFNGLMULTITEXCOORD3IVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord3ivARB");
	pContext->glRenderTable.MultiTexCoord3svARB =
	    (PFNGLMULTITEXCOORD3SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord3svARB");
	pContext->glRenderTable.MultiTexCoord4dvARB =
	    (PFNGLMULTITEXCOORD4DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord4dvARB");
	pContext->glRenderTable.MultiTexCoord4fvARB =
	    (PFNGLMULTITEXCOORD4FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord4fvARB");
	pContext->glRenderTable.MultiTexCoord4ivARB =
	    (PFNGLMULTITEXCOORD4IVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord4ivARB");
	pContext->glRenderTable.MultiTexCoord4svARB =
	    (PFNGLMULTITEXCOORD4SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glMultiTexCoord4svARB");

	glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &pContext->maxTexUnits);
	if (pContext->maxTexUnits > XGL_MAX_TEXTURE_UNITS)
	    pContext->maxTexUnits = XGL_MAX_TEXTURE_UNITS;

	pContext->glRenderTable.ActiveTextureARB = xglActiveTextureARB;
    }
    else
	pContext->maxTexUnits = 1;

    if (strstr (extensions, "GL_ARB_multisample"))
    {
	pContext->glRenderTable.SampleCoverageARB =
	    (PFNGLSAMPLECOVERAGEARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSampleCoverageARB");
    }

    if (strstr (extensions, "GL_SGIS_multisample"))
    {
	pContext->glRenderTable.SampleMaskSGIS =
	    (PFNGLSAMPLEMASKSGISPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSampleMaskSGIS");
	pContext->glRenderTable.SamplePatternSGIS =
	    (PFNGLSAMPLEPATTERNSGISPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSamplePatternSGIS");
    }

    if (strstr (extensions, "GL_EXT_point_parameters"))
    {
	pContext->glRenderTable.PointParameterfEXT =
	    (PFNGLPOINTPARAMETERFEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glPointParameterfEXT");
	pContext->glRenderTable.PointParameterfvEXT =
	    (PFNGLPOINTPARAMETERFVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glPointParameterfvEXT");
    }

    if (strstr (extensions, "GL_ARB_window_pos"))
    {
	pContext->WindowPos3fMESA =
	    (PFNGLWINDOWPOS3FMESAPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glWindowPos3fARB");

	pContext->glRenderTable.WindowPos3fvMESA = xglWindowPos3fvMESA;
    }
    else if (strstr (extensions, "GL_MESA_window_pos"))
    {
	pContext->WindowPos3fMESA =
	    (PFNGLWINDOWPOS3FMESAPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glWindowPos3fMESA");

	pContext->glRenderTable.WindowPos3fvMESA = xglWindowPos3fvMESA;
    }

    if (strstr (extensions, "GL_EXT_blend_func_separate"))
    {
	pContext->glRenderTable.BlendFuncSeparateEXT =
	    (PFNGLBLENDFUNCSEPARATEEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBlendFuncSeparateEXT");
    }

    if (strstr (extensions, "GL_EXT_fog_coord"))
    {
	pContext->glRenderTable.FogCoordfvEXT =
	    (PFNGLFOGCOORDFVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFogCoordfvEXT");
	pContext->glRenderTable.FogCoorddvEXT =
	    (PFNGLFOGCOORDDVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFogCoorddvEXT");
	pContext->glRenderTable.FogCoordPointerEXT =
	    (PFNGLFOGCOORDPOINTEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFogCoordPointerEXT");
    }

    if (strstr (extensions, "GL_EXT_secondary_color"))
    {
	pContext->glRenderTable.SecondaryColor3bvEXT =
	    (PFNGLSECONDARYCOLOR3BVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3bvEXT");
	pContext->glRenderTable.SecondaryColor3dvEXT =
	    (PFNGLSECONDARYCOLOR3DVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3dvEXT");
	pContext->glRenderTable.SecondaryColor3fvEXT =
	    (PFNGLSECONDARYCOLOR3FVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3fvEXT");
	pContext->glRenderTable.SecondaryColor3ivEXT =
	    (PFNGLSECONDARYCOLOR3IVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3ivEXT");
	pContext->glRenderTable.SecondaryColor3svEXT =
	    (PFNGLSECONDARYCOLOR3SVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3svEXT");
	pContext->glRenderTable.SecondaryColor3ubvEXT =
	    (PFNGLSECONDARYCOLOR3UBVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3ubvEXT");
	pContext->glRenderTable.SecondaryColor3uivEXT =
	    (PFNGLSECONDARYCOLOR3UIVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3uivEXT");
	pContext->glRenderTable.SecondaryColor3usvEXT =
	    (PFNGLSECONDARYCOLOR3USVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColor3usvEXT");
	pContext->glRenderTable.SecondaryColorPointerEXT =
	    (PFNGLSECONDARYCOLORPOINTEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glSecondaryColorPointerEXT");
    }

    if (strstr (extensions, "GL_NV_point_sprite"))
    {
	pContext->glRenderTable.PointParameteriNV =
	    (PFNGLPOINTPARAMETERINVPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glPointParameteriNV");
	pContext->glRenderTable.PointParameterivNV =
	    (PFNGLPOINTPARAMETERIVNVPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glPointParameterivNV");
    }

    if (strstr (extensions, "GL_EXT_stencil_two_side"))
    {
	pContext->glRenderTable.ActiveStencilFaceEXT =
	    (PFNGLACTIVESTENCILFACEEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glActiveStencilFaceEXT");
    }

    if (strstr (extensions, "GL_ARB_vertex_program"))
    {
	pContext->BindProgramARB =
	    (PFNGLBINDPROGRAMARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBindProgramARB");
	pContext->DeleteProgramsARB =
	    (PFNGLDELETEPROGRAMSARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glDeleteProgramsARB");
	pContext->GenProgramsARB =
	    (PFNGLGENPROGRAMSARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenProgramsARB");
	pContext->glRenderTable.GetProgramivARB =
	    (PFNGLGETPROGRAMIVPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramivARB");
	pContext->glRenderTable.GetVertexAttribdvARB =
	    (PFNGLGETVERTEXATTRIBDVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetVertexAttribdvARB");
	pContext->glRenderTable.GetVertexAttribfvARB =
	    (PFNGLGETVERTEXATTRIBFVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetVertexAttribfvARB");
	pContext->glRenderTable.GetVertexAttribivARB =
	    (PFNGLGETVERTEXATTRIBIVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetVertexAttribivARB");
	pContext->IsProgramARB =
	    (PFNGLISPROGRAMARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glIsProgramARB");
	pContext->glRenderTable.ProgramEnvParameter4fvARB =
	    (PFNGLPROGRAMENVPARAMETER4FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glProgramEnvParameter4fvARB");
	pContext->glRenderTable.ProgramEnvParameter4dvARB =
	    (PFNGLPROGRAMENVPARAMETER4DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glProgramEnvParameter4dvARB");
	pContext->glRenderTable.VertexAttrib1svARB =
	    (PFNGLVERTEXATTRIB1SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib1svARB");
	pContext->glRenderTable.VertexAttrib2svARB =
	    (PFNGLVERTEXATTRIB2SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib2svARB");
	pContext->glRenderTable.VertexAttrib3svARB =
	    (PFNGLVERTEXATTRIB3SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib3svARB");
	pContext->glRenderTable.VertexAttrib4svARB =
	    (PFNGLVERTEXATTRIB4SVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4svARB");
	pContext->glRenderTable.VertexAttrib1fvARB =
	    (PFNGLVERTEXATTRIB1FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib1fvARB");
	pContext->glRenderTable.VertexAttrib2fvARB =
	    (PFNGLVERTEXATTRIB2FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib2fvARB");
	pContext->glRenderTable.VertexAttrib3fvARB =
	    (PFNGLVERTEXATTRIB3FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib3fvARB");
	pContext->glRenderTable.VertexAttrib4fvARB =
	    (PFNGLVERTEXATTRIB4FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4fvARB");
	pContext->glRenderTable.VertexAttrib1dvARB =
	    (PFNGLVERTEXATTRIB1DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib1dvARB");
	pContext->glRenderTable.VertexAttrib2dvARB =
	    (PFNGLVERTEXATTRIB2DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib2dvARB");
	pContext->glRenderTable.VertexAttrib3dvARB =
	    (PFNGLVERTEXATTRIB3DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib3dvARB");
	pContext->glRenderTable.VertexAttrib4dvARB =
	    (PFNGLVERTEXATTRIB4DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4dvARB");
	pContext->glRenderTable.VertexAttrib4NubvARB =
	    (PFNGLVERTEXATTRIB4NUBVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NubvARB");
	pContext->glRenderTable.ProgramLocalParameter4fvARB =
	    (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glProgramLocalParameter4fvARB");
	pContext->glRenderTable.ProgramLocalParameter4dvARB =
	    (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glProgramLocalParameter4dvARB");
	pContext->glRenderTable.GetProgramEnvParameterdvARB =
	    (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramEnvParameterdvARB");
	pContext->glRenderTable.GetProgramEnvParameterfvARB =
	    (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramEnvParameterfvARB");
	pContext->glRenderTable.GetProgramLocalParameterdvARB =
	    (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramLocalParameterdvARB");
	pContext->glRenderTable.GetProgramLocalParameterfvARB =
	    (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramLocalParameterfvARB");
	pContext->glRenderTable.ProgramStringARB =
	    (PFNGLPROGRAMSTRINGARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glProgramStringARB");
	pContext->glRenderTable.GetProgramStringARB =
	    (PFNGLGETPROGRAMSTRINGARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetProgramStringARB");
	pContext->glRenderTable.VertexAttrib4bvARB =
	    (PFNGLVERTEXATTRIB4BVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4bvARB");
	pContext->glRenderTable.VertexAttrib4ivARB =
	    (PFNGLVERTEXATTRIB4IVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4ivARB");
	pContext->glRenderTable.VertexAttrib4ubvARB =
	    (PFNGLVERTEXATTRIB4UBVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4ubvARB");
	pContext->glRenderTable.VertexAttrib4usvARB =
	    (PFNGLVERTEXATTRIB4USVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4usvARB");
	pContext->glRenderTable.VertexAttrib4uivARB =
	    (PFNGLVERTEXATTRIB4UIVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4uivARB");
	pContext->glRenderTable.VertexAttrib4NbvARB =
	    (PFNGLVERTEXATTRIB4NBVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NbvARB");
	pContext->glRenderTable.VertexAttrib4NsvARB =
	    (PFNGLVERTEXATTRIB4NSVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NsvARB");
	pContext->glRenderTable.VertexAttrib4NivARB =
	    (PFNGLVERTEXATTRIB4NIVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NivARB");
	pContext->glRenderTable.VertexAttrib4NusvARB =
	    (PFNGLVERTEXATTRIB4NUSVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NusvARB");
	pContext->glRenderTable.VertexAttrib4NuivARB =
	    (PFNGLVERTEXATTRIB4NUIVARBPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glVertexAttrib4NuivARB");

	pContext->glRenderTable.IsProgramNV = xglIsProgramARB;
	pContext->glRenderTable.BindProgramNV = xglBindProgramARB;
	pContext->glRenderTable.DeleteProgramsNV = xglDeleteProgramsARB;
	pContext->glRenderTable.GenProgramsNV = xglGenProgramsARB;
    }

    if (strstr (extensions, "GL_EXT_framebuffer_object"))
    {
	pContext->IsRenderbufferEXT =
	    (PFNGLISRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glIsRenderbufferEXT");
	pContext->BindRenderbufferEXT =
	    (PFNGLBINDRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBindRenderbufferEXT");
	pContext->DeleteRenderbuffersEXT =
	    (PFNGLDELETERENDERBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glDeleteRenderbuffersEXT");
	pContext->GenRenderbuffersEXT =
	    (PFNGLGENRENDERBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenRenderbuffersEXT");
	pContext->glRenderTable.RenderbufferStorageEXT =
	    (PFNGLRENDERBUFFERSTORAGEEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glRenderbufferStorageEXT");
	pContext->glRenderTable.GetRenderbufferParameterivEXT =
	    (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetRenderbufferParameterivEXT");
	pContext->IsFramebufferEXT =
	    (PFNGLISFRAMEBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glIsFramebufferEXT");
	pContext->BindFramebufferEXT =
	    (PFNGLBINDFRAMEBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBindFramebufferEXT");
	pContext->DeleteFramebuffersEXT =
	    (PFNGLDELETEFRAMEBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glDeleteFramebuffersEXT");
	pContext->GenFramebuffersEXT =
	    (PFNGLGENFRAMEBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenFramebuffersEXT");
	pContext->glRenderTable.CheckFramebufferStatusEXT =
	    (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glCheckFramebufferStatusEXT");
	pContext->FramebufferTexture1DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture1DEXT");
	pContext->FramebufferTexture2DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture2DEXT");
	pContext->FramebufferTexture3DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture3DEXT");
	pContext->FramebufferRenderbufferEXT =
	    (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferRenderbufferEXT");
	pContext->GetFramebufferAttachmentParameterivEXT =
	    (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetFramebufferAttachment"
					    "ParameterivEXT");
	pContext->GenerateMipmapEXT =
	    (PFNGLGENERATEMIPMAPEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenerateMipmapEXT");

	pContext->glRenderTable.IsRenderbufferEXT = xglIsRenderbufferEXT;
	pContext->glRenderTable.BindRenderbufferEXT = xglBindRenderbufferEXT;
	pContext->glRenderTable.DeleteRenderbuffersEXT =
	    xglDeleteRenderbuffersEXT;
	pContext->glRenderTable.GenRenderbuffersEXT = xglGenRenderbuffersEXT;
	pContext->glRenderTable.IsFramebufferEXT = xglIsFramebufferEXT;
	pContext->glRenderTable.BindFramebufferEXT = xglBindFramebufferEXT;
	pContext->glRenderTable.DeleteFramebuffersEXT = xglDeleteFramebuffersEXT;
	pContext->glRenderTable.GenFramebuffersEXT = xglGenFramebuffersEXT;
	pContext->glRenderTable.FramebufferTexture1DEXT =
	    xglFramebufferTexture1DEXT;
	pContext->glRenderTable.FramebufferTexture2DEXT =
	    xglFramebufferTexture2DEXT;
	pContext->glRenderTable.FramebufferTexture3DEXT =
	    xglFramebufferTexture3DEXT;
	pContext->glRenderTable.FramebufferRenderbufferEXT =
	    xglFramebufferRenderbufferEXT;
	pContext->glRenderTable.GetFramebufferAttachmentParameterivEXT =
	    xglGetFramebufferAttachmentParameterivEXT;
	pContext->glRenderTable.GenerateMipmapEXT = xglGenerateMipmapEXT;
    }
}

static GLboolean
xglResizeBuffer (xglGLBufferPtr pBufferPriv)
{
    DrawablePtr pDrawable = pBufferPriv->pDrawable;

    XGL_SCREEN_PRIV (pDrawable->pScreen);
    XGL_DRAWABLE_PIXMAP (pBufferPriv->pDrawable);

    if (pPixmap != pScreenPriv->pScreenPixmap)
    {
	if (!xglCreatePixmapSurface (pPixmap))
	    return FALSE;

	if (pBufferPriv->drawable == pScreenPriv->drawable)
	{
	    if (pBufferPriv->backSurface)
		glitz_surface_destroy (pBufferPriv->backSurface);

	    glitz_drawable_destroy (pBufferPriv->drawable);

	    pBufferPriv->drawable    = NULL;
	    pBufferPriv->backSurface = NULL;
	}

	if (pBufferPriv->drawable)
	{
	    glitz_drawable_update_size (pBufferPriv->drawable,
					pPixmap->drawable.width,
					pPixmap->drawable.height);
	}
	else
	{
	    glitz_drawable_format_t *format;

	    format = pBufferPriv->pVisual->format.drawable;
	    if (pBufferPriv->pVisual->pbuffer)
	    {
		pBufferPriv->drawable =
		    glitz_create_pbuffer_drawable (pScreenPriv->drawable,
						   format,
						   pPixmap->drawable.width,
						   pPixmap->drawable.height);
	    }
	    else
	    {
		pBufferPriv->drawable =
		    glitz_create_drawable (pScreenPriv->drawable, format,
					   pPixmap->drawable.width,
					   pPixmap->drawable.height);

		if (!pBufferPriv->drawable)
		    return FALSE;

		if (format->doublebuffer)
		{
		    glitz_format_t *backFormat;

		    backFormat = pBufferPriv->pVisual->format.surface;

		    pBufferPriv->backSurface =
			glitz_surface_create (pScreenPriv->drawable, backFormat,
					      pPixmap->drawable.width,
					      pPixmap->drawable.height,
					      0, NULL);
		    if (pBufferPriv->backSurface)
			glitz_surface_attach (pBufferPriv->backSurface,
					      pBufferPriv->drawable,
					      GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
		}
	    }
	}
    }
    else
    {
	glitz_drawable_reference (pScreenPriv->drawable);

	if (pBufferPriv->backSurface)
	    glitz_surface_destroy (pBufferPriv->backSurface);

	if (pBufferPriv->drawable)
	    glitz_drawable_destroy (pBufferPriv->drawable);

	pBufferPriv->drawable    = pScreenPriv->drawable;
	pBufferPriv->backSurface = NULL;
    }

    ValidateGC (pDrawable, pBufferPriv->pGC);

    return TRUE;
}

static GLboolean
xglSwapBuffers (__GLXdrawable *drawable)
{
    xglGLBufferPtr pBufferPriv = (xglGLBufferPtr) drawable;
    __GLXdrawable  *mesaDrawable = pBufferPriv->mesaDrawable;
    DrawablePtr	   pDrawable = pBufferPriv->pDrawable;
    GLboolean	   status = GL_TRUE;

    if (pDrawable)
    {
	glitz_surface_t *surface;
	int		xOff, yOff;
	GCPtr		pGC = pBufferPriv->pGC;
	BoxPtr		pBox = REGION_RECTS (pGC->pCompositeClip);
	int		nBox = REGION_NUM_RECTS (pGC->pCompositeClip);

	XGL_GET_DRAWABLE (pDrawable, surface, xOff, yOff);

	glitz_drawable_swap_buffer_region (pBufferPriv->drawable,
					   xOff, yOff,
					   (glitz_box_t *) pBox, nBox);

	xglAddBitDamage (pDrawable, pGC->pCompositeClip);
	DamageDamageRegion (pDrawable, pGC->pCompositeClip);
	REGION_EMPTY (pGC->pScreen, &pBufferPriv->damage);
    }
    else if (mesaDrawable)
    {
	status = (*mesaDrawable->swapBuffers) (mesaDrawable);
    }

    return status;
}

static GLboolean
xglCopySubBuffer (__GLXdrawable *drawable,
		  int		x,
		  int		y,
		  int		width,
		  int		height)
{
    xglGLBufferPtr pBufferPriv = (xglGLBufferPtr) drawable;
    __GLXdrawable  *mesaDrawable = pBufferPriv->mesaDrawable;
    DrawablePtr	   pDrawable = pBufferPriv->pDrawable;
    GLboolean	   status = GL_TRUE;

    if (pDrawable)
    {
	glitz_surface_t *surface;
	int		xOff, yOff;
	GCPtr		pGC = pBufferPriv->pGC;
	RegionRec	region;
	BoxRec		box;

	XGL_SCREEN_PRIV (pGC->pScreen);

	XGL_GET_DRAWABLE (pDrawable, surface, xOff, yOff);

	box.x1 = pDrawable->x + x;
	box.y2 = pDrawable->height - y;
	box.x2 = box.x1 + width;
	box.y1 = box.y2 - height;

	REGION_INIT (pGC->pScreen, &region, &box, 1);
	REGION_INTERSECT (pDrawable->pScreen, &region,
			  pGC->pCompositeClip, &region);

	glitz_drawable_swap_buffer_region (pBufferPriv->drawable,
					   xOff, yOff, (glitz_box_t *)
					   REGION_RECTS (&region),
					   REGION_NUM_RECTS (&region));

	xglAddBitDamage (pDrawable, &region);
	DamageDamageRegion (pDrawable, &region);
	REGION_SUBTRACT (pGC->pScreen, &pBufferPriv->damage,
			 &pBufferPriv->damage, &region);

	REGION_UNINIT (pGC->pScreen, &region);
    }
    else if (mesaDrawable)
    {
	status = (*mesaDrawable->copySubBuffer) (mesaDrawable,
						 x, y, width, height);
    }

    return status;
}

static GLboolean
xglResizeDrawable (__GLXdrawable *drawable)
{
    xglGLBufferPtr pBufferPriv = (xglGLBufferPtr) drawable;
    __GLXdrawable  *mesaDrawable = pBufferPriv->mesaDrawable;
    DrawablePtr    pDrawable = pBufferPriv->pDrawable;
    GLboolean	   status = GL_TRUE;

    if (pDrawable)
    {
	if (!xglResizeBuffer (pBufferPriv))
	    return GL_FALSE;
    }
    else if (mesaDrawable)
    {
	status = (*mesaDrawable->resize) (mesaDrawable);
    }

    return status;
}

static int
xglBindTexImage (__GLXcontext *context,
		 int	      buffer,
		 __GLXpixmap  *pixmap)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;

    if (cctx)
    {
	xglTexUnitPtr pTexUnit = &cctx->attrib.texUnits[cctx->activeTexUnit];
	ScreenPtr     pScreen = pixmap->pDraw->pScreen;

	XGL_SCREEN_PRIV (pScreen);
	XGL_DRAWABLE_PIXMAP (pixmap->pDraw);

	/* XXX: front left buffer is only supported so far */
	if (buffer != GLX_FRONT_LEFT_EXT)
	    return BadMatch;

	if (xglCreatePixmapSurface (pPixmap))
	{
	    glitz_texture_object_t *texture;

	    XGL_PIXMAP_PRIV (pPixmap);

	    texture = glitz_texture_object_create (pPixmapPriv->surface);
	    if (texture)
	    {
		xglTexObjPtr pTexObj;

		switch (glitz_texture_object_get_target (texture)) {
		case GLITZ_TEXTURE_TARGET_2D:
		    pTexObj = pTexUnit->p2D;
		    break;
		case GLITZ_TEXTURE_TARGET_RECT:
		    pTexObj = pTexUnit->pRect;
		    break;
		default:
		    pTexObj = NULL;
		    break;
		}

		if (pTexObj)
		{
		    pPixmap->refcnt++;

		    if (pTexObj->pPixmap)
			(*pScreen->DestroyPixmap) (pTexObj->pPixmap);

		    if (pTexObj->object)
			glitz_texture_object_destroy (pTexObj->object);

		    pTexObj->pPixmap = pPixmap;
		    pTexObj->object  = texture;
		}
		else
		    glitz_texture_object_destroy (texture);

		return Success;
	    }
	}
    }
    else
    {
	return (*mesaContext->textureFromPixmap->bindTexImage) (mesaContext,
								buffer,
								pixmap);
    }

    return BadDrawable;
}

static int
xglReleaseTexImage (__GLXcontext *context,
		    int		 buffer,
		    __GLXpixmap  *pixmap)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;

    if (cctx)
    {
	DrawablePtr  pDrawable = pixmap->pDraw;
	xglTexObjPtr pTexObj;

	XGL_DRAWABLE_PIXMAP (pDrawable);

	/* XXX: front left buffer is only supported so far */
	if (buffer != GLX_FRONT_LEFT_EXT)
	    return BadMatch;

	pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].p2D;
	if (pTexObj && pTexObj->pPixmap == pPixmap)
	{
	    (*pDrawable->pScreen->DestroyPixmap) (pTexObj->pPixmap);
	    pTexObj->pPixmap = NULL;
	    glitz_texture_object_destroy (pTexObj->object);
	    pTexObj->object = NULL;

	    return Success;
	}
	else
	{
	    pTexObj = cctx->attrib.texUnits[cctx->activeTexUnit].pRect;
	    if (pTexObj && pTexObj->pPixmap == pPixmap)
	    {
		(*pDrawable->pScreen->DestroyPixmap) (pTexObj->pPixmap);
		pTexObj->pPixmap = NULL;
		glitz_texture_object_destroy (pTexObj->object);
		pTexObj->object = NULL;

		return Success;
	    }
	}
    }
    else
    {
	return (*mesaContext->textureFromPixmap->releaseTexImage) (mesaContext,
								   buffer,
								   pixmap);
    }

    return BadDrawable;
}

static __GLXtextureFromPixmapContext __xglTextureFromPixmapContext = {
    xglBindTexImage,
    xglReleaseTexImage
};

static void
xglDestroyDrawable (__GLXdrawable *drawable)
{
    xglGLBufferPtr pBufferPriv = (xglGLBufferPtr) drawable;
    __GLXdrawable *mesaDrawable = pBufferPriv->mesaDrawable;

    if (mesaDrawable)
    {
	mesaDrawable->refCount--;
	if (!mesaDrawable->refCount)
	    (*mesaDrawable->destroy) (mesaDrawable);
    }

    if (pBufferPriv->pGC)
	FreeGC (pBufferPriv->pGC, (GContext) 0);

    if (pBufferPriv->backSurface)
	glitz_surface_destroy (pBufferPriv->backSurface);

    if (pBufferPriv->drawable)
	glitz_drawable_destroy (pBufferPriv->drawable);

    xfree (pBufferPriv);
}

static __GLXdrawable *
xglCreateDrawable (__GLXcontext *context,
		   DrawablePtr  pDrawable,
		   XID	        drawId)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;
    ScreenPtr	    pScreen = pDrawable->pScreen;
    xglGLBufferPtr  pBufferPriv;
    xglVisualPtr    v;
    Bool	    useMesa;

    XGL_SCREEN_PRIV (pScreen);
    XGL_DRAWABLE_PIXMAP (pDrawable);

    pBufferPriv = xalloc (sizeof (xglGLBufferRec));
    if (!pBufferPriv)
	return NULL;

    memset (pBufferPriv, 0, sizeof (xglGLBufferRec));

    if (!GlxDrawableInit (&pBufferPriv->base, context, pDrawable, drawId))
    {
	xfree (pBufferPriv);
	return NULL;
    }

    pBufferPriv->mesaDrawable = NULL;

    pBufferPriv->pScreen   = pScreen;
    pBufferPriv->pDrawable = NULL;
    pBufferPriv->pPixmap   = NULL;
    pBufferPriv->pGC	   = NULL;

    pBufferPriv->base.destroy       = xglDestroyDrawable;
    pBufferPriv->base.resize        = xglResizeDrawable;
    pBufferPriv->base.swapBuffers   = xglSwapBuffers;
    pBufferPriv->base.copySubBuffer = xglCopySubBuffer;

    pBufferPriv->drawable    = NULL;
    pBufferPriv->backSurface = NULL;

    REGION_INIT (pScreen, &pBufferPriv->damage, NullBox, 0);

    pBufferPriv->pVisual = 0;

    /* glx acceleration */
    if (pScreenPriv->accel.glx.enabled &&
	xglCheckPixmapSize (pPixmap, &pScreenPriv->accel.glx.size))
    {
	for (v = pScreenPriv->pGlxVisual; v; v = v->next)
	{
	    glitz_drawable_format_t *format;

	    if (pScreenPriv->accel.glx.pbuffer != v->pbuffer)
		continue;

	    format = v->format.drawable;
	    if (!format)
		continue;

	    if (format->color.red_size   != context->modes->redBits   ||
		format->color.green_size != context->modes->greenBits ||
		format->color.blue_size  != context->modes->blueBits)
		continue;

	    if (format->color.alpha_size < context->modes->alphaBits   ||
		format->depth_size	 < context->modes->depthBits   ||
		format->stencil_size     < context->modes->stencilBits ||
		format->doublebuffer     < context->modes->doubleBufferMode)
		continue;

	    /* this is good enought for pbuffers */
	    if (v->pbuffer)
		break;

	    /* we want an exact match for non-pbuffer formats */
	    if (format->color.alpha_size == context->modes->alphaBits   &&
		format->depth_size	 == context->modes->depthBits   &&
		format->stencil_size     == context->modes->stencilBits &&
		format->doublebuffer     == context->modes->doubleBufferMode)
		break;
	}

	pBufferPriv->pVisual = v;
    }

    useMesa = TRUE;

    if (pDrawable->type == DRAWABLE_WINDOW)
    {

#ifdef COMPOSITE
	if (pBufferPriv->pVisual)
	{
	    useMesa = FALSE;
	}
	else
	{
	    WindowPtr pWin = (WindowPtr) pDrawable;

	    /* this is a root window, can't be redirected */
	    if (!pWin->parent)
	    {
		useMesa = FALSE;
	    }
	    else
	    {
		CompScreenPtr cs = GetCompScreen (pScreen);

		/* allow native GL with overlay windows */
		for (; pWin; pWin = pWin->parent)
		{
		    if (pWin == cs->pOverlayWin)
		    {
			useMesa = FALSE;
			break;
		    }
		}
	    }
	}
#else
	    useMesa = FALSE;
#endif

    }

    if (useMesa)
    {
	pBufferPriv->mesaDrawable = (*mesaContext->createDrawable) (mesaContext,
								    pDrawable,
								    drawId);
    }
    else
    {
	pBufferPriv->pDrawable = pDrawable;
    }

    return &pBufferPriv->base;
}

static void
xglSetCurrentContext (xglGLContextPtr pContext)
{
    cctx = pContext;

    glitz_context_make_current (cctx->context, cctx->pDrawBuffer->drawable);

    GlxSetRenderTables (&cctx->glRenderTable);
}

static void
xglFreeContext (xglGLContextPtr pContext)
{
    int i;

    pContext->refcnt--;
    if (pContext->shared == pContext)
	pContext->refcnt--;

    if (pContext->refcnt)
	return;

    if (pContext->shared != pContext)
	xglFreeContext (pContext->shared);

    if (pContext->context)
    {
	XGL_SCREEN_PRIV (pContext->base.pScreen);

	glitz_context_make_current (pContext->context, pScreenPriv->drawable);
    }

    if (pContext->texObjects)
    {
	xglTexObjPtr pTexObj;
	GLuint	     key;

	do {
	    key = xglHashFirstEntry (pContext->texObjects);
	    if (key)
	    {
		pTexObj = (xglTexObjPtr) xglHashLookup (pContext->texObjects,
							key);
		if (pTexObj)
		    xglUnrefTexObj (pTexObj);

		xglHashRemove (pContext->texObjects, key);
	    }
	} while (key);

	xglDeleteHashTable (pContext->texObjects);
    }

    if (pContext->programObjects)
    {
	GLuint po;
	GLuint key;

	do {
	    key = xglHashFirstEntry (pContext->programObjects);
	    if (key)
	    {
		po = (GLuint) xglHashLookup (pContext->programObjects, key);
		if (po)
		    (*pContext->DeleteProgramsARB) (1, &po);

		xglHashRemove (pContext->programObjects, key);
	    }
	} while (key);

	xglDeleteHashTable (pContext->programObjects);
    }

    if (pContext->renderbufferObjects)
    {
	GLuint rbo;
	GLuint key;

	do {
	    key = xglHashFirstEntry (pContext->renderbufferObjects);
	    if (key)
	    {
		rbo = (GLuint) xglHashLookup (pContext->renderbufferObjects,
					      key);
		if (rbo)
		    (*pContext->DeleteRenderbuffersEXT) (1, &rbo);

		xglHashRemove (pContext->renderbufferObjects, key);
	    }
	} while (key);

	xglDeleteHashTable (pContext->renderbufferObjects);
    }

    if (pContext->framebufferObjects)
    {
	GLuint fbo;
	GLuint key;

	do {
	    key = xglHashFirstEntry (pContext->framebufferObjects);
	    if (key)
	    {
		fbo = (GLuint) xglHashLookup (pContext->framebufferObjects,
					      key);
		if (fbo)
		    (*pContext->DeleteFramebuffersEXT) (1, &fbo);

		xglHashRemove (pContext->framebufferObjects, key);
	    }
	} while (key);

	xglDeleteHashTable (pContext->framebufferObjects);
    }

    if (pContext->displayLists)
    {
	xglDisplayListPtr pDisplayList;
	GLuint		  key;

	do {
	    key = xglHashFirstEntry (pContext->displayLists);
	    if (key)
	    {
		pDisplayList = (xglDisplayListPtr)
		    xglHashLookup (pContext->displayLists, key);
		if (pDisplayList)
		    xglDestroyList (pDisplayList);

		xglHashRemove (pContext->displayLists, key);
	    }
	} while (key);

	xglDeleteHashTable (pContext->displayLists);
    }

    for (i = 0; i < pContext->maxTexUnits; i++)
    {
	xglUnrefTexObj (pContext->attrib.texUnits[i].p1D);
	xglUnrefTexObj (pContext->attrib.texUnits[i].p2D);
	xglUnrefTexObj (pContext->attrib.texUnits[i].p3D);
	xglUnrefTexObj (pContext->attrib.texUnits[i].pRect);
	xglUnrefTexObj (pContext->attrib.texUnits[i].pCubeMap);
    }

    if (pContext->groupList)
	glDeleteLists (pContext->groupList, 1);

    if (pContext->context)
	glitz_context_destroy (pContext->context);

    if (pContext->versionString)
	xfree (pContext->versionString);

    xfree (pContext);
}

static void
xglDestroyContext (__GLXcontext *context)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;

    xglFreeContext (pContext);

    if (mesaContext)
	(*mesaContext->destroy) (mesaContext);
}

static int
xglLoseCurrent (__GLXcontext *context)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;

    GlxFlushContextCache ();
    GlxSetRenderTables (0);

    if (!mesaContext)
	return TRUE;

    return (*mesaContext->loseCurrent) (mesaContext);
}

static int
xglMakeCurrent (__GLXcontext *context)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;
    xglGLBufferPtr  pDrawBufferPriv = (xglGLBufferPtr) context->drawPriv;
    xglGLBufferPtr  pReadBufferPriv = (xglGLBufferPtr) context->readPriv;
    int		    status = TRUE;

    if (pReadBufferPriv->pDrawable && pDrawBufferPriv->pDrawable)
    {
	XID values[2] = { ClipByChildren, 0 };
	int status;

#ifdef COMPOSITE
	/* XXX: temporary hack for root window drawing using
	   IncludeInferiors */
	if (pDrawBufferPriv->pDrawable->type == DRAWABLE_WINDOW &&
	    (!((WindowPtr) (pDrawBufferPriv->pDrawable))->parent))
	    values[0] = IncludeInferiors;
#endif

	/* this happens if client previously used this context with a buffer
	   not supported by the native GL stack */
	if (!pContext->context)
	    return FALSE;

	/* XXX: GLX_SGI_make_current_read disabled for now */
	if (pDrawBufferPriv != pReadBufferPriv)
	    return FALSE;

	if (!pReadBufferPriv->pGC)
	    pReadBufferPriv->pGC =
		CreateGC (pReadBufferPriv->pDrawable,
			  GCSubwindowMode | GCGraphicsExposures, values,
			  &status);

	ValidateGC (pReadBufferPriv->pDrawable, pReadBufferPriv->pGC);

	if (!pDrawBufferPriv->pGC)
	    pDrawBufferPriv->pGC =
		CreateGC (pDrawBufferPriv->pDrawable,
			  GCSubwindowMode | GCGraphicsExposures, values,
			  &status);

	ValidateGC (pDrawBufferPriv->pDrawable, pDrawBufferPriv->pGC);

	pReadBufferPriv->pPixmap = (PixmapPtr) 0;
	pDrawBufferPriv->pPixmap = (PixmapPtr) 0;

	pContext->pReadBuffer = pReadBufferPriv;
	pContext->pDrawBuffer = pDrawBufferPriv;

	/* from now on this context can only be used with native GL stack */
	if (mesaContext)
	{
	    (*mesaContext->destroy) (mesaContext);
	    pContext->mesaContext = NULL;
	}
    }
    else
    {
	/* this happens if client previously used this context with a buffer
	   supported by the native GL stack */
	if (!mesaContext)
	    return GL_FALSE;

	mesaContext->drawPriv = pDrawBufferPriv->mesaDrawable;
	mesaContext->readPriv = pDrawBufferPriv->mesaDrawable;

	status = (*mesaContext->makeCurrent) (mesaContext);

	/* from now on this context can not be used with native GL stack */
	if (status == GL_TRUE && pContext->context)
	{
	    glitz_context_destroy (pContext->context);
	    pContext->context = NULL;
	}
    }

    return status;
}

static int
xglCopyContext (__GLXcontext  *dst,
		__GLXcontext  *src,
		unsigned long mask)
{
    xglGLContextPtr pDst = (xglGLContextPtr) dst;
    xglGLContextPtr pSrc = (xglGLContextPtr) src;
    __GLXcontext    *mesaDst = pDst->mesaContext;
    __GLXcontext    *mesaSrc = pSrc->mesaContext;
    int		    status = TRUE;

    if (pSrc->context && pDst->context)
	glitz_context_copy (pSrc->context, pDst->context, mask);
    else
	status = FALSE;

    if (mesaDst && mesaSrc)
	status = (*mesaDst->copy) (mesaDst, mesaSrc, mask);

    return status;
}

static int
xglForceCurrent (__GLXcontext *context)
{
    xglGLContextPtr pContext = (xglGLContextPtr) context;
    __GLXcontext    *mesaContext = pContext->mesaContext;
    int		    status = TRUE;

    if (pContext && pContext->context)
    {
	cctx = pContext;

	if (cctx->pReadBuffer->pDrawable && cctx->pDrawBuffer->pDrawable)
	{
	    DrawablePtr pDrawable = cctx->pReadBuffer->pDrawable;
	    PixmapPtr   pReadPixmap, pDrawPixmap;

	    XGL_SCREEN_PRIV (pDrawable->pScreen);

	    if (pDrawable->type != DRAWABLE_PIXMAP)
	    {
		pReadPixmap = XGL_GET_WINDOW_PIXMAP (pDrawable);
		cctx->pReadBuffer->screenX = __XGL_OFF_X_WIN (pReadPixmap);
		cctx->pReadBuffer->screenY = __XGL_OFF_Y_WIN (pReadPixmap);
		cctx->pReadBuffer->xOff = pDrawable->x +
		    __XGL_OFF_X_WIN (pReadPixmap);
		cctx->pReadBuffer->yOff = pReadPixmap->drawable.height -
		    ((pDrawable->y + __XGL_OFF_Y_WIN (pReadPixmap)) +
		     pDrawable->height);
		cctx->pReadBuffer->yFlip = pReadPixmap->drawable.height;
	    }
	    else
	    {
		pReadPixmap = (PixmapPtr) pDrawable;
		cctx->pReadBuffer->screenX = cctx->pReadBuffer->screenY = 0;
		cctx->pReadBuffer->xOff = cctx->pReadBuffer->yOff = 0;
		cctx->pReadBuffer->yFlip = pDrawable->height;
	    }

	    pDrawable = cctx->pDrawBuffer->pDrawable;
	    if (pDrawable->type != DRAWABLE_PIXMAP)
	    {
		pDrawPixmap = XGL_GET_WINDOW_PIXMAP (pDrawable);
		cctx->pDrawBuffer->screenX = __XGL_OFF_X_WIN (pDrawPixmap);
		cctx->pDrawBuffer->screenY = __XGL_OFF_Y_WIN (pDrawPixmap);
		cctx->pDrawBuffer->xOff = pDrawable->x +
		    __XGL_OFF_X_WIN (pDrawPixmap);
		cctx->pDrawBuffer->yOff = pDrawPixmap->drawable.height -
		    ((pDrawable->y + __XGL_OFF_Y_WIN (pDrawPixmap)) +
		     pDrawable->height);
		cctx->pDrawBuffer->yFlip = pDrawPixmap->drawable.height;
	    }
	    else
	    {
		pDrawPixmap = (PixmapPtr) pDrawable;
		cctx->pDrawBuffer->screenX = cctx->pDrawBuffer->screenY = 0;
		cctx->pDrawBuffer->xOff = cctx->pDrawBuffer->yOff = 0;
		cctx->pDrawBuffer->yFlip = pDrawable->height;
	    }

	    /* buffer changed */
	    if (cctx->pDrawBuffer->pPixmap != pDrawPixmap ||
		cctx->pReadBuffer->pPixmap != pReadPixmap)
	    {
		if (!xglResizeBuffer (cctx->pDrawBuffer))
		    return FALSE;

		if (!xglResizeBuffer (cctx->pReadBuffer))
		    return FALSE;

		cctx->pReadBuffer->pPixmap = pReadPixmap;
		cctx->pDrawBuffer->pPixmap = pDrawPixmap;
	    }

	    if (!xglSyncSurface (pContext->pDrawBuffer->pDrawable))
		return FALSE;

	    if (pDrawPixmap != pScreenPriv->pScreenPixmap)
	    {
		XGL_PIXMAP_PRIV (pDrawPixmap);

		glitz_surface_attach (pPixmapPriv->surface,
				      pContext->pDrawBuffer->drawable,
				      GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);

		if (pPixmapPriv->target)
		    pPixmapPriv->target = xglPixmapTargetOut;
	    }

	    xglSetCurrentContext (pContext);

	    if (cctx->needInit)
	    {
		int i;

		xglInitExtensions (cctx);

		glGetIntegerv (GL_MAX_LIST_NESTING, &cctx->maxListNesting);
		glGetIntegerv (GL_MAX_ATTRIB_STACK_DEPTH,
			       &cctx->maxAttribStackDepth);
		if (cctx->maxAttribStackDepth > XGL_MAX_ATTRIB_STACK_DEPTH)
		    cctx->maxAttribStackDepth = XGL_MAX_ATTRIB_STACK_DEPTH;

		cctx->attrib.scissorTest = GL_FALSE;
		cctx->attrib.scissor.x = cctx->attrib.scissor.y = 0;
		cctx->attrib.scissor.width =
		    cctx->pDrawBuffer->pDrawable->width;
		cctx->attrib.scissor.height =
		    cctx->pDrawBuffer->pDrawable->height;
		cctx->attrib.viewport = cctx->attrib.scissor;

		cctx->activeTexUnit = 0;

		for (i = 0; i < cctx->maxTexUnits; i++)
		{
		    cctx->attrib.texUnits[i].enabled = 0;

		    cctx->attrib.texUnits[i].p1D      = NULL;
		    cctx->attrib.texUnits[i].p2D      = NULL;
		    cctx->attrib.texUnits[i].p3D      = NULL;
		    cctx->attrib.texUnits[i].pRect    = NULL;
		    cctx->attrib.texUnits[i].pCubeMap = NULL;
		}

		glEnable (GL_SCISSOR_TEST);

		cctx->needInit = FALSE;
	    }

	    if (cctx->framebuffer)
	    {
		GLuint fbo;

		fbo = (GLuint)
		    xglHashLookup (cctx->shared->framebufferObjects,
				   cctx->framebuffer);
		if (fbo)
		    (*cctx->BindFramebufferEXT) (GL_FRAMEBUFFER_EXT, fbo);
	    }
	    else
	    {
		xglSetDrawOffset (cctx->pDrawBuffer->xOff,
				  cctx->pDrawBuffer->yOff);

		cctx->readXoff = cctx->pReadBuffer->xOff;
		cctx->readYoff = cctx->pReadBuffer->yOff;

		xglDrawBuffer (cctx->attrib.drawBuffer);
		xglReadBuffer (cctx->attrib.readBuffer);
	    }
	}
	else
	{
	    xglSetCurrentContext (pContext);
	}
    }
    else
    {
	cctx = NULL;
	status = (*mesaContext->forceCurrent) (mesaContext);
    }

    return status;
}

static void
xglLoseCurrentContext (void *closure)
{
    if (closure == cctx)
    {
	cctx = NULL;

	/* make sure that all preceding drawing commands are finished
	   before switching context */
	glFinish ();

	GlxFlushContextCache ();
	GlxSetRenderTables (0);
    }
}

static __GLXcontext *
xglCreateContext (__GLXscreen	   *screen,
		  __GLcontextModes *modes,
		  __GLXcontext	   *shareContext)
{
    glitz_drawable_format_t *format;
    xglGLScreenPtr	    pGLScreen = (xglGLScreenPtr) screen;
    __GLXscreen		    *mesaScreen = pGLScreen->mesaScreen;
    xglGLContextPtr	    pShareContext = (xglGLContextPtr) shareContext;
    xglGLContextPtr	    pContext;
    __GLXcontext	    *shareMesaContext = NULL;

    XGL_SCREEN_PRIV (screen->pScreen);

    pContext = xalloc (sizeof (xglGLContextRec));
    if (!pContext)
	return NULL;

    memset (pContext, 0, sizeof (xglGLContextRec));

    format = glitz_drawable_get_format (pScreenPriv->drawable);
    pContext->context = glitz_context_create (pScreenPriv->drawable, format);
    glitz_context_set_user_data (pContext->context, pContext,
				 xglLoseCurrentContext);

    pContext->glRenderTable = __glNativeRenderTable;
    pContext->needInit	    = TRUE;
    pContext->versionString = NULL;
    pContext->errorValue    = GL_NO_ERROR;
    pContext->shared	    = NULL;
    pContext->list	    = 0;
    pContext->groupList	    = 0;
    pContext->beginCnt	    = 0;
    pContext->nAttribStack  = 0;
    pContext->refcnt	    = 1;
    pContext->doubleBuffer  = modes->doubleBufferMode;
    pContext->depthBits     = modes->depthBits;
    pContext->stencilBits   = modes->stencilBits;
    pContext->drawXoff	    = 0;
    pContext->drawYoff	    = 0;
    pContext->readXoff	    = 0;
    pContext->readYoff	    = 0;
    pContext->maxTexUnits   = 0;
    pContext->framebuffer   = 0;

    if (pContext->doubleBuffer)
    {
	pContext->attrib.drawBuffer = GL_BACK;
	pContext->attrib.readBuffer = GL_BACK;
    }
    else
    {
	pContext->attrib.drawBuffer = GL_FRONT;
	pContext->attrib.readBuffer = GL_FRONT;
    }

    pContext->attrib.scissorTest = GL_FALSE;

    if (shareContext)
    {
	pContext->texObjects	      = NULL;
	pContext->programObjects      = NULL;
	pContext->renderbufferObjects = NULL;
	pContext->framebufferObjects  = NULL;
	pContext->displayLists	      = NULL;

	pContext->shared = pShareContext->shared;
	shareMesaContext = pShareContext->mesaContext;
    }
    else
    {
	pContext->texObjects = xglNewHashTable ();
	if (!pContext->texObjects)
	{
	    xglFreeContext (pContext);
	    return NULL;
	}

	pContext->programObjects = xglNewHashTable ();
	if (!pContext->programObjects)
	{
	    xglFreeContext (pContext);
	    return NULL;
	}

	pContext->renderbufferObjects = xglNewHashTable ();
	if (!pContext->renderbufferObjects)
	{
	    xglFreeContext (pContext);
	    return NULL;
	}

	pContext->framebufferObjects = xglNewHashTable ();
	if (!pContext->framebufferObjects)
	{
	    xglFreeContext (pContext);
	    return NULL;
	}

	pContext->displayLists = xglNewHashTable ();
	if (!pContext->displayLists)
	{
	    xglFreeContext (pContext);
	    return NULL;
	}

	pContext->shared = pContext;
    }

    pContext->shared->refcnt++;

    pContext->base.destroy        = xglDestroyContext;
    pContext->base.makeCurrent    = xglMakeCurrent;
    pContext->base.loseCurrent    = xglLoseCurrent;
    pContext->base.copy           = xglCopyContext;
    pContext->base.forceCurrent   = xglForceCurrent;
    pContext->base.createDrawable = xglCreateDrawable;

    pContext->base.textureFromPixmap = &__xglTextureFromPixmapContext;

    pContext->mesaContext = (*mesaScreen->createContext) (mesaScreen,
							  modes,
							  shareMesaContext);
    if (!pContext->mesaContext)
    {
	xglFreeContext (pContext);
	return NULL;
    }

    return &pContext->base;
}

static int
xglGetTexTarget (__GLXscreen *screen,
		 __GLXpixmap *pixmap)
{
    int target = GLX_TEXTURE_2D_EXT;

    XGL_DRAWABLE_PIXMAP (pixmap->pDraw);

    if (xglCreatePixmapSurface (pPixmap))
    {
	glitz_texture_object_t *texture;

	XGL_PIXMAP_PRIV (pPixmap);

	texture = glitz_texture_object_create (pPixmapPriv->surface);
	if (texture)
	{
	    switch (glitz_texture_object_get_target (texture)) {
	    case GLITZ_TEXTURE_TARGET_2D:
		target = GLX_TEXTURE_2D_EXT;
		break;
	    case GLITZ_TEXTURE_TARGET_RECT:
		target = GLX_TEXTURE_RECTANGLE_EXT;
		break;
	    }

	    glitz_texture_object_destroy (texture);
	}
    }

    return target;
}

static __GLXtextureFromPixmapScreen __xglTextureFromPixmapScreen = {
    xglGetTexTarget,
};

static void
xglScreenDestroy (__GLXscreen *screen)
{
    xglGLScreenPtr pScreen = (xglGLScreenPtr) screen;
    __GLXscreen    *mesaScreen = pScreen->mesaScreen;

    if (mesaScreen)
	(*mesaScreen->destroy) (mesaScreen);

    if (pScreen->GLXextensions)
	xfree (pScreen->GLXextensions);

    xfree (pScreen);
}

static __GLXscreen *
xglScreenProbe (ScreenPtr pScreen)
{
    xglGLScreenPtr   screen;
    __GLcontextModes *modes;
    xglVisualPtr     pVisual;
    Bool	     status;
    int		     i;

    XGL_SCREEN_PRIV (pScreen);

    screen = (xglGLScreenPtr) xalloc (sizeof (xglGLScreenRec));
    if (!screen)
	return NULL;

    memset (screen, 0, sizeof (xglGLScreenRec));

    screen->base.destroy       = xglScreenDestroy;
    screen->base.createContext = xglCreateContext;
    screen->base.pScreen       = pScreen;

    screen->base.textureFromPixmap = &__xglTextureFromPixmapScreen;

    screen->mesaScreen = (*__xglMesaProvider->screenProbe) (pScreen);

    screen->base.GLextensions  = screen->mesaScreen->GLextensions;
    screen->base.GLXvendor     = screen->mesaScreen->GLXvendor;
    screen->base.GLXversion    = screen->mesaScreen->GLXversion;
    screen->base.GLXextensions = screen->mesaScreen->GLXextensions;

    /* Remove GLX_MESA_copy_sub_buffer from GLX extension string if
       glitz can't efficiently support it */
    if (!(glitz_drawable_get_features (pScreenPriv->drawable) &
	  GLITZ_FEATURE_COPY_SUB_BUFFER_MASK))
    {
	screen->GLXextensions = strdup (screen->mesaScreen->GLXextensions);
	if (screen->GLXextensions)
	{
	    char *s;

	    s = strstr (screen->GLXextensions, "GLX_MESA_copy_sub_buffer ");
	    if (s)
	    {
		int n, n2;

		n  = strlen ("GLX_MESA_copy_sub_buffer ");
		n2 = strlen (s);

		memmove (s, s + n, n2 - n + 1);
	    }

	    screen->base.GLXextensions = screen->GLXextensions;
	}
    }

    screen->base.WrappedPositionWindow =
	screen->mesaScreen->WrappedPositionWindow;

    screen->base.modes		  = screen->mesaScreen->modes;
    screen->base.pVisualPriv	  = screen->mesaScreen->pVisualPriv;
    screen->base.numVisuals	  = screen->mesaScreen->numVisuals;
    screen->base.numUsableVisuals = screen->mesaScreen->numUsableVisuals;

    modes = screen->base.modes;

    /* Create Xgl GLX visuals */
    for (i = 0; i < pScreen->numVisuals; i++)
    {
	pVisual = xglFindVisualWithId (pScreen, pScreen->visuals[i].vid);
	if (pVisual)
	{
	    glitz_drawable_format_t templ, *format, *screenFormat;
	    unsigned long	    mask;

	    templ.color        = pVisual->format.surface->color;
	    templ.depth_size   = modes->depthBits;
	    templ.stencil_size = modes->stencilBits;
	    templ.doublebuffer = modes->doubleBufferMode;
	    templ.samples      = 1;

	    mask =
		GLITZ_FORMAT_FOURCC_MASK       |
		GLITZ_FORMAT_RED_SIZE_MASK     |
		GLITZ_FORMAT_GREEN_SIZE_MASK   |
		GLITZ_FORMAT_BLUE_SIZE_MASK    |
		GLITZ_FORMAT_ALPHA_SIZE_MASK   |
		GLITZ_FORMAT_DEPTH_SIZE_MASK   |
		GLITZ_FORMAT_STENCIL_SIZE_MASK |
		GLITZ_FORMAT_DOUBLEBUFFER_MASK |
		GLITZ_FORMAT_SAMPLES_MASK;

	    format = glitz_find_drawable_format (pScreenPriv->drawable,
						 mask, &templ, 0);
	    if (format)
	    {
		xglVisualPtr v, new, *prev;

		new = xalloc (sizeof (xglVisualRec));
		if (new)
		{
		    new->next    = 0;
		    new->vid     = pVisual->vid;
		    new->pPixel  = pVisual->pPixel;
		    new->pbuffer = FALSE;

		    new->format.surface  = pVisual->format.surface;
		    new->format.drawable = format;

		    prev = &pScreenPriv->pGlxVisual;
		    while ((v = *prev))
			prev = &v->next;

		    *prev = new;
		}
	    }

	    /* use same drawable format as screen for pbuffers */
	    screenFormat = glitz_drawable_get_format (pScreenPriv->drawable);
	    templ.id = screenFormat->id;

	    mask =
		GLITZ_FORMAT_ID_MASK	     |
		GLITZ_FORMAT_FOURCC_MASK     |
		GLITZ_FORMAT_RED_SIZE_MASK   |
		GLITZ_FORMAT_GREEN_SIZE_MASK |
		GLITZ_FORMAT_BLUE_SIZE_MASK  |
		GLITZ_FORMAT_SAMPLES_MASK;

	    format = glitz_find_pbuffer_format (pScreenPriv->drawable,
						mask, &templ, 0);
	    if (format)
	    {
		xglVisualPtr v, new, *prev;

		new = xalloc (sizeof (xglVisualRec));
		if (new)
		{
		    new->next    = 0;
		    new->vid     = pVisual->vid;
		    new->pPixel  = pVisual->pPixel;
		    new->pbuffer = TRUE;

		    new->format.surface  = pVisual->format.surface;
		    new->format.drawable = format;

		    prev = &pScreenPriv->pGlxVisual;
		    while ((v = *prev))
			prev = &v->next;

		    *prev = new;
		}
	    }
	}

	modes = modes->next;
    }

    return &screen->base;
}

__GLXprovider __glXXGLProvider = {
    xglScreenProbe,
    "XGL",
    NULL
};

Bool
xglInitVisualConfigs (ScreenPtr pScreen)
{
    miInitVisualsProcPtr    initVisualsProc = NULL;
    VisualPtr		    visuals;
    int			    nvisuals;
    DepthPtr		    depths;
    int			    ndepths;
    int			    rootDepth;
    VisualID		    defaultVis;
    glitz_drawable_format_t *format;
    xglVisualPtr	    pVisual;
    __GLXvisualConfig	    *pConfig;
    xglGLXVisualConfigPtr   pConfigPriv, *ppConfigPriv;
    XID			    *installedCmaps;
    ColormapPtr		    installedCmap;
    int			    numInstalledCmaps;
    int			    numConfig = 1;
    int			    bpp, i;

    XGL_SCREEN_PRIV (pScreen);

    if (xglScreenInfo.depth != 16 && xglScreenInfo.depth != 24)
	return FALSE;

    for (pVisual = xglVisuals; pVisual; pVisual = pVisual->next)
    {
	if (pVisual->pPixel->depth == xglScreenInfo.depth)
	    break;
    }

    if (!pVisual)
	return FALSE;

    bpp = pVisual->pPixel->masks.bpp;

    format = glitz_drawable_get_format (pScreenPriv->drawable);
    if (format->doublebuffer)
	numConfig *= 2;

    pConfig = xcalloc (sizeof (__GLXvisualConfig), numConfig);
    if (!pConfig)
	return FALSE;

    pConfigPriv = xcalloc (sizeof (xglGLXVisualConfigRec), numConfig);
    if (!pConfigPriv)
    {
	xfree (pConfig);
	return FALSE;
    }

    ppConfigPriv = xcalloc (sizeof (xglGLXVisualConfigPtr), numConfig);
    if (!ppConfigPriv)
    {
	xfree (pConfigPriv);
	xfree (pConfig);
	return FALSE;
    }

    installedCmaps = xalloc (pScreen->maxInstalledCmaps * sizeof (XID));
    if (!installedCmaps)
    {
	xfree (ppConfigPriv);
	xfree (pConfigPriv);
	xfree (pConfig);
	return FALSE;
    }

    for (i = 0; i < numConfig; i++)
    {
	ppConfigPriv[i] = &pConfigPriv[i];

	pConfig[i].vid   = (VisualID) (-1);
	pConfig[i].class = -1;
	pConfig[i].rgba  = TRUE;

	pConfig[i].redSize   = format->color.red_size;
	pConfig[i].greenSize = format->color.green_size;
	pConfig[i].blueSize  = format->color.blue_size;
	pConfig[i].alphaSize = format->color.alpha_size;

	pConfig[i].redMask   = pVisual->pPixel->masks.red_mask;
	pConfig[i].greenMask = pVisual->pPixel->masks.green_mask;
	pConfig[i].blueMask  = pVisual->pPixel->masks.blue_mask;
	pConfig[i].alphaMask = pVisual->pPixel->masks.alpha_mask;

	if (i == 1)
	{
	    pConfig[i].doubleBuffer = FALSE;
	    pConfig[i].depthSize    = 0;
	    pConfig[i].stencilSize  = 0;
	}
	else
	{
	    pConfig[i].doubleBuffer = TRUE;
	    pConfig[i].depthSize    = format->depth_size;
	    pConfig[i].stencilSize  = format->stencil_size;
	}

	pConfig[i].stereo = FALSE;

	if (pScreen->rootDepth == 16)
	    pConfig[i].bufferSize = 16;
	else
	    pConfig[i].bufferSize = 32;

	pConfig[i].auxBuffers = 0;
	pConfig[i].level      = 0;

	pConfig[i].visualRating = GLX_NONE;

	pConfig[i].transparentPixel = GLX_NONE;
	pConfig[i].transparentRed   = 0;
	pConfig[i].transparentGreen = 0;
	pConfig[i].transparentBlue  = 0;
	pConfig[i].transparentAlpha = 0;
	pConfig[i].transparentIndex = 0;
    }

    GlxPushProvider (&__glXXGLProvider);
    GlxSetVisualConfigs (numConfig, pConfig, (void **) ppConfigPriv);

    visuals    = pScreen->visuals;
    nvisuals   = pScreen->numVisuals;
    depths     = pScreen->allowedDepths;
    ndepths    = pScreen->numDepths;
    rootDepth  = pScreen->rootDepth;
    defaultVis = pScreen->rootVisual;

    /* Find installed colormaps */
    numInstalledCmaps = (*pScreen->ListInstalledColormaps) (pScreen,
							    installedCmaps);

    GlxWrapInitVisuals (&initVisualsProc);
    GlxInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &rootDepth,
		    &defaultVis, ((unsigned long) 1 << (bpp - 1)), 8, -1);

    /* Fix up any existing installed colormaps. */
    for (i = 0; i < numInstalledCmaps; i++)
    {
	int j;

	installedCmap = LookupIDByType (installedCmaps[i], RT_COLORMAP);
	if (!installedCmap)
	    continue;

	j = installedCmap->pVisual - pScreen->visuals;
	installedCmap->pVisual = &visuals[j];
    }

    pScreen->visuals       = visuals;
    pScreen->numVisuals    = nvisuals;
    pScreen->allowedDepths = depths;
    pScreen->numDepths     = ndepths;
    pScreen->rootDepth     = rootDepth;
    pScreen->rootVisual    = defaultVis;

#ifndef NGLXLOG
    xglInitGlxLog ();
#endif

    xfree (installedCmaps);
    xfree (pConfigPriv);
    xfree (pConfig);

    return TRUE;
}
