xglglxext.c   [plain text]


/*
 * 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 "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"

#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)

typedef Bool	      (*GLXScreenProbeProc)    (int screen);
typedef __GLinterface *(*GLXCreateContextProc) (__GLimports      *imports,
						__GLcontextModes *modes,
						__GLinterface    *shareGC);
typedef void	      (*GLXCreateBufferProc)   (__GLXdrawablePrivate *glxPriv);
typedef GLboolean     (*GLXSwapBuffersProc)    (__GLXdrawablePrivate *glxPriv);
typedef int	      (*GLXBindBuffersProc)    (__GLXdrawablePrivate *glxPriv,
						int		     buffer);
typedef int	      (*GLXReleaseBuffersProc) (__GLXdrawablePrivate *glxPriv,
						int		     buffer);

typedef struct _xglGLXScreenInfo {
    GLXScreenProbeProc   screenProbe;
    GLXCreateContextProc createContext;
    GLXCreateBufferProc  createBuffer;
} xglGLXScreenInfoRec, *xglGLXScreenInfoPtr;

extern __GLXscreenInfo *__xglScreenInfoPtr;

static xglGLXScreenInfoRec screenInfoPriv;

//extern __GLXscreenInfo __glDDXScreenInfo;

typedef GLboolean (*GLResizeBuffersProc) (__GLdrawableBuffer   *buffer,
					  GLint		       x,
					  GLint		       y,
					  GLuint	       width,
					  GLuint	       height,
					  __GLdrawablePrivate  *glPriv,
					  GLuint	       bufferMask);
typedef void	  (*GLFreeBuffersProc)   (__GLdrawablePrivate  *glPriv);

typedef struct _xglGLBuffer {
    GLXSwapBuffersProc    swapBuffers;
    GLXBindBuffersProc    bindBuffers;
    GLXReleaseBuffersProc releaseBuffers;
    GLResizeBuffersProc   resizeBuffers;
    GLFreeBuffersProc     freeBuffers;
    ScreenPtr		  pScreen;
    DrawablePtr		  pDrawable;
    xglVisualPtr	  pVisual;
    glitz_drawable_t	  *drawable;
    glitz_surface_t	  *backSurface;
    PixmapPtr		  pPixmap;
    GCPtr		  pGC;
    RegionRec		  damage;
    void	          *private;
    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 texture;
	} bind_texture;
	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 {
    __GLinterface	      iface;
    __GLinterface	      *mIface;
    int			      refcnt;
    struct _xglGLContext      *shared;
    glitz_context_t	      *context;
    struct _glapi_table	      glRenderTable;
    PFNGLACTIVETEXTUREARBPROC ActiveTextureARB;
    PFNGLWINDOWPOS3FMESAPROC  WindowPos3fMESA;
    Bool		      needInit;
    xglGLBufferPtr	      pDrawBuffer;
    xglGLBufferPtr	      pReadBuffer;
    int			      drawXoff, drawYoff;
    __GLdrawablePrivate	      *readPriv;
    __GLdrawablePrivate	      *drawPriv;
    char		      *versionString;
    GLenum		      errorValue;
    GLboolean		      doubleBuffer;
    GLint		      depthBits;
    GLint		      stencilBits;
    xglHashTablePtr	      texObjects;
    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 void
xglSetCurrentContext (xglGLContextPtr pContext);

#define XGL_GLX_DRAW_PROLOGUE_WITHOUT_TEXTURES(pBox, nBox, pScissorBox)	  \
    (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)		      \
    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->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
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->pDrawBuffer->xOff,
		pOp->u.rect.y + cctx->pDrawBuffer->yOff,
		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];

    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)
{
    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_texture.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_texture.texture)
    {
	if (!*ppTexObj || pOp->u.bind_texture.texture != (*ppTexObj)->key)
	{
	    xglTexObjPtr pTexObj;

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

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

		glGenTextures (1, &pTexObj->name);

		xglHashInsert (cctx->shared->texObjects,
			       pOp->u.bind_texture.texture,
			       pTexObj);
	    }

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

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

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

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

    gl.glProc = xglBindTextureProc;

    gl.u.bind_texture.target  = target;
    gl.u.bind_texture.texture = 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
xglTextureFilter (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,
					     xglTextureFilter (params[0]));
	    break;
	case GL_TEXTURE_MAG_FILTER:
	    glitz_texture_object_set_filter (pTexObj->object,
					     GLITZ_TEXTURE_FILTER_TYPE_MAG,
					     xglTextureFilter (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->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->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->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->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->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->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->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->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 (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->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 (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->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->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->pReadBuffer->xOff,
		  y + cctx->pReadBuffer->yOff,
		  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->pReadBuffer->xOff,
		      pOp->u.copy_tex_image_1d.y + cctx->pReadBuffer->yOff,
		      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->pReadBuffer->xOff,
		      pOp->u.copy_tex_image_2d.y + cctx->pReadBuffer->yOff,
		      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->pReadBuffer->xOff,
			 pOp->u.copy_tex_sub_image_1d.y +
			 cctx->pReadBuffer->yOff,
			 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->pReadBuffer->xOff,
			 pOp->u.copy_tex_sub_image_2d.y +
			 cctx->pReadBuffer->yOff,
			 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->pReadBuffer->xOff,
		      pOp->u.copy_color_table.y + cctx->pReadBuffer->yOff,
		      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->pReadBuffer->xOff,
		      pOp->u.copy_color_sub_table.y + cctx->pReadBuffer->yOff,
		      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->pReadBuffer->xOff,
			       pOp->u.copy_convolution_filter_1d.y +
			       cctx->pReadBuffer->yOff,
			       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->pReadBuffer->xOff,
			       pOp->u.copy_convolution_filter_2d.y +
			       cctx->pReadBuffer->yOff,
			       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->pReadBuffer->xOff,
			 pOp->u.copy_tex_sub_image_3d.y +
			 cctx->pReadBuffer->yOff,
			 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_EXT_texture_object */
static GLboolean
xglNoOpAreTexturesResidentEXT (GLsizei n,
			       const GLuint *textures,
			       GLboolean *residences)
{
    return GL_FALSE;
}
static void
xglNoOpGenTexturesEXT (GLsizei n, GLuint *textures) {}
static GLboolean
xglNoOpIsTextureEXT (GLuint texture)
{
    return GL_FALSE;
}

/* 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
xglNoOpWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z) {}
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
xglWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z)
{
    xglGLOpRec gl;

    gl.glProc = xglWindowPos3fMESAProc;

    gl.u.window_pos_3f.x = x;
    gl.u.window_pos_3f.y = y;
    gl.u.window_pos_3f.z = z;

    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_EXT_framebuffer_object */
static GLboolean
xglNoOpIsRenderbufferEXT (GLuint renderbuffer)
{
    return FALSE;
}
static void
xglNoOpBindRenderbufferEXT (GLenum target, GLuint renderbuffer) {}
static void
xglNoOpDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers) {}
static void
xglNoOpGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers) {}
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 void
xglNoOpBindFramebufferEXT (GLenum target, GLuint framebuffer) {}
static void
xglNoOpDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers) {}
static void
xglNoOpGenFramebuffersEXT (GLsizei n, GLuint *framebuffers) {}
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
xglNoOpFramebufferTexture2DEXT (GLenum target, GLenum attachment,
				GLenum textarget, GLuint texture,
				GLint level) {}
static void
xglNoOpFramebufferTexture3DEXT (GLenum target, GLenum attachment,
				GLenum textarget, GLuint texture,
				GLint level, GLint zoffset) {}
static void
xglNoOpFramebufferRenderbufferEXT (GLenum target, GLenum attachment,
				   GLenum renderbuffertarget,
				   GLuint renderbuffer) {}
static void
xglNoOpGetFramebufferAttachmentParameterivEXT (GLenum target,
					       GLenum attachment,
					       GLenum pname,
					       GLint *params) {}
static void
xglNoOpGenerateMipmapEXT (GLenum 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, /* glLoadTransposeMatrixfARB */
    0, /* glLoadTransposeMatrixdARB */
    0, /* glMultTransposeMatrixfARB */
    0, /* glMultTransposeMatrixdARB */
    xglNoOpSampleCoverageARB,
    0, /* glDrawBuffersARB */
    0, /* glPolygonOffsetEXT */
    0, /* glGetTexFilterFuncSGIS */
    0, /* glTexFilterFuncSGIS */
    0, /* glGetHistogramEXT */
    0, /* glGetHistogramParameterfvEXT */
    0, /* glGetHistogramParameterivEXT */
    0, /* glGetMinmaxEXT */
    0, /* glGetMinmaxParameterfvEXT */
    0, /* glGetMinmaxParameterivEXT */
    0, /* glGetConvolutionFilterEXT */
    0, /* glGetConvolutionParameterfvEXT */
    0, /* glGetConvolutionParameterivEXT */
    0, /* glGetSeparableFilterEXT */
    0, /* glGetColorTableSGI */
    0, /* glGetColorTableParameterfvSGI */
    0, /* glGetColorTableParameterivSGI */
    0, /* glPixelTexGenSGIX */
    0, /* glPixelTexGenParameteriSGIS */
    0, /* glPixelTexGenParameterivSGIS */
    0, /* glPixelTexGenParameterfSGIS */
    0, /* glPixelTexGenParameterfvSGIS */
    0, /* glGetPixelTexGenParameterivSGIS */
    0, /* glGetPixelTexGenParameterfvSGIS */
    0, /* glTexImage4DSGIS */
    0, /* glTexSubImage4DSGIS */
    xglNoOpAreTexturesResidentEXT,
    xglNoOpGenTexturesEXT,
    xglNoOpIsTextureEXT,
    0, /* glDetailTexFuncSGIS */
    0, /* glGetDetailTexFuncSGIS */
    0, /* glSharpenTexFuncSGIS */
    0, /* glGetSharpenTexFuncSGIS */
    xglNoOpSampleMaskSGIS,
    xglNoOpSamplePatternSGIS,
    0, /* glColorPointerEXT */
    0, /* glEdgeFlagPointerEXT */
    0, /* glIndexPointerEXT */
    0, /* glNormalPointerEXT */
    0, /* glTexCoordPointerEXT */
    0, /* glVertexPointerEXT */
    0, /* glSpriteParameterfSGIX */
    0, /* glSpriteParameterfvSGIX */
    0, /* glSpriteParameteriSGIX */
    0, /* glSpriteParameterivSGIX */
    xglNoOpPointParameterfEXT,
    xglNoOpPointParameterfvEXT,
    0, /* glGetInstrumentsSGIX */
    0, /* glInstrumentsBufferSGIX */
    0, /* glPollInstrumentsSGIX */
    0, /* glReadInstrumentsSGIX */
    0, /* glStartInstrumentsSGIX */
    0, /* glStopInstrumentsSGIX */
    0, /* glFrameZoomSGIX */
    0, /* glTagSampleBufferSGIX */
    0, /* glReferencePlaneSGIX */
    0, /* glFlushRasterSGIX */
    0, /* glGetListParameterfvSGIX */
    0, /* glGetListParameterivSGIX */
    0, /* glListParameterfSGIX */
    0, /* glListParameterfvSGIX */
    0, /* glListParameteriSGIX */
    0, /* glListParameterivSGIX */
    0, /* glFragmentColorMaterialSGIX */
    0, /* glFragmentLightfSGIX */
    0, /* glFragmentLightfvSGIX */
    0, /* glFragmentLightiSGIX */
    0, /* glFragmentLightivSGIX */
    0, /* glFragmentLightModelfSGIX */
    0, /* glFragmentLightModelfvSGIX */
    0, /* glFragmentLightModeliSGIX */
    0, /* glFragmentLightModelivSGIX */
    0, /* glFragmentMaterialfSGIX */
    0, /* glFragmentMaterialfvSGIX */
    0, /* glFragmentMaterialiSGIX */
    0, /* glFragmentMaterialivSGIX */
    0, /* glGetFragmentLightfvSGIX */
    0, /* glGetFragmentLightivSGIX */
    0, /* glGetFragmentMaterialfvSGIX */
    0, /* glGetFragmentMaterialivSGIX */
    0, /* glLightEnviSGIX */
    0, /* glVertexWeightfEXT */
    0, /* glVertexWeightfvEXT */
    0, /* glVertexWeightPointerEXT */
    0, /* glFlushVertexArrayRangeNV */
    0, /* glVertexArrayRangeNV */
    0, /* glCombinerParameterfvNV */
    0, /* glCombinerParameterfNV */
    0, /* glCombinerParameterivNV */
    0, /* glCombinerParameteriNV */
    0, /* glCombinerInputNV */
    0, /* glCombinerOutputNV */
    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 */
    xglNoOpWindowPos3fMESA,
    0, /* glWindowPos3fvMESA */
    0, /* glWindowPos3iMESA */
    0, /* glWindowPos3ivMESA */
    0, /* glWindowPos3sMESA */
    0, /* glWindowPos3svMESA */
    0, /* glWindowPos4dMESA */
    0, /* glWindowPos4dvMESA */
    0, /* glWindowPos4fMESA */
    0, /* glWindowPos4fvMESA */
    0, /* glWindowPos4iMESA */
    0, /* glWindowPos4ivMESA */
    0, /* glWindowPos4sMESA */
    0, /* glWindowPos4svMESA */
    xglNoOpBlendFuncSeparateEXT,
    0, /* glIndexMaterialEXT */
    0, /* glIndexFuncEXT */
    0, /* glLockArraysEXT */
    0, /* glUnlockArraysEXT */
    0, /* glCullParameterdvEXT */
    0, /* glCullParameterfvEXT */
    0, /* glHintPGI */
    0, /* glFogCoordfEXT */
    xglNoOpFogCoordfvEXT,
    0, /* glFogCoorddEXT */
    xglNoOpFogCoorddvEXT,
    xglNoOpFogCoordPointerEXT,
    0, /* glGetColorTableEXT */
    0, /* glGetColorTableParameterivEXT */
    0, /* glGetColorTableParameterfvEXT */
    0, /* glTbufferMask3DFX */
    0, /* glCompressedTexImage3DARB */
    0, /* glCompressedTexImage2DARB */
    0, /* glCompressedTexImage1DARB */
    0, /* glCompressedTexSubImage3DARB */
    0, /* glCompressedTexSubImage2DARB */
    0, /* glCompressedTexSubImage1DARB */
    0, /* glGetCompressedTexImageARB */
    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, /* glAreProgramsResidentNV */
    0, /* glBindProgramNV */
    0, /* glDeleteProgramsNV */
    0, /* glExecuteProgramNV */
    0, /* glGenProgramsNV */
    0, /* glGetProgramParameterdvNV */
    0, /* glGetProgramParameterfvNV */
    0, /* glGetProgramivNV */
    0, /* glGetProgramStringNV */
    0, /* glGetTrackMatrixivNV */
    0, /* glGetVertexAttribdvARB */
    0, /* glGetVertexAttribfvARB */
    0, /* glGetVertexAttribivARB */
    0, /* glGetVertexAttribPointervNV */
    0, /* glIsProgramNV */
    0, /* glLoadProgramNV */
    0, /* glProgramParameter4dNV */
    0, /* glProgramParameter4dvNV */
    0, /* glProgramParameter4fNV */
    0, /* glProgramParameter4fvNV */
    0, /* glProgramParameters4dvNV */
    0, /* glProgramParameters4fvNV */
    0, /* glRequestResidentProgramsNV */
    0, /* glTrackMatrixNV */
    0, /* glVertexAttribPointerNV */
    0, /* glVertexAttrib1dARB */
    0, /* glVertexAttrib1dvARB */
    0, /* glVertexAttrib1fARB */
    0, /* glVertexAttrib1fvARB */
    0, /* glVertexAttrib1sARB */
    0, /* glVertexAttrib1svARB */
    0, /* glVertexAttrib2dARB */
    0, /* glVertexAttrib2dvARB */
    0, /* glVertexAttrib2fARB */
    0, /* glVertexAttrib2fvARB */
    0, /* glVertexAttrib2sARB */
    0, /* glVertexAttrib2svARB */
    0, /* glVertexAttrib3dARB */
    0, /* glVertexAttrib3dvARB */
    0, /* glVertexAttrib3fARB */
    0, /* glVertexAttrib3fvARB */
    0, /* glVertexAttrib3sARB */
    0, /* glVertexAttrib3svARB */
    0, /* glVertexAttrib4dARB */
    0, /* glVertexAttrib4dvARB */
    0, /* glVertexAttrib4fARB */
    0, /* glVertexAttrib4fvARB */
    0, /* glVertexAttrib4sARB */
    0, /* glVertexAttrib4svARB */
    0, /* glVertexAttrib4NubARB */
    0, /* glVertexAttrib4NubvARB */
    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 */
    xglNoOpPointParameteriNV,
    xglNoOpPointParameterivNV,
    0, /* glMultiDrawArraysEXT */
    0, /* glMultiDrawElementsEXT */
    xglNoOpActiveStencilFaceEXT,
    0, /* glDeleteFencesNV */
    0, /* glGenFencesNV */
    0, /* glIsFenceNV */
    0, /* glTestFenceNV */
    0, /* glGetFenceivNV */
    0, /* glFinishFenceNV */
    0, /* glSetFenceNV */
    0, /* glVertexAttrib4bvARB */
    0, /* glVertexAttrib4ivARB */
    0, /* glVertexAttrib4ubvARB */
    0, /* glVertexAttrib4usvARB */
    0, /* glVertexAttrib4uivARB */
    0, /* glVertexAttrib4NbvARB */
    0, /* glVertexAttrib4NsvARB */
    0, /* glVertexAttrib4NivARB */
    0, /* glVertexAttrib4NusvARB */
    0, /* glVertexAttrib4NuivARB */
    0, /* glVertexAttribPointerARB */
    0, /* glEnableVertexAttribArrayARB */
    0, /* glDisableVertexAttribArrayARB */
    0, /* glProgramStringARB */
    0, /* glProgramEnvParameter4dARB */
    0, /* glProgramEnvParameter4dvARB */
    0, /* glProgramEnvParameter4fARB */
    0, /* glProgramEnvParameter4fvARB */
    0, /* glProgramLocalParameter4dARB */
    0, /* glProgramLocalParameter4dvARB */
    0, /* glProgramLocalParameter4fARB */
    0, /* glProgramLocalParameter4fvARB */
    0, /* glGetProgramEnvParameterdvARB */
    0, /* glGetProgramEnvParameterfvARB */
    0, /* glGetProgramLocalParameterdvARB */
    0, /* glGetProgramLocalParameterfvARB */
    0, /* glGetProgramivARB */
    0, /* glGetProgramStringARB */
    0, /* glProgramNamedParameter4fNV */
    0, /* glProgramNamedParameter4dNV */
    0, /* glProgramNamedParameter4fvNV */
    0, /* glProgramNamedParameter4dvNV */
    0, /* glGetProgramNamedParameterfvNV */
    0, /* glGetProgramNamedParameterdvNV */
    0, /* glBindBufferARB */
    0, /* glBufferDataARB */
    0, /* glBufferSubDataARB */
    0, /* glDeleteBuffersARB */
    0, /* glGenBuffersARB */
    0, /* glGetBufferParameterivARB */
    0, /* glGetBufferPointervARB */
    0, /* glGetBufferSubDataARB */
    0, /* glIsBufferARB */
    0, /* glMapBufferARB */
    0, /* glUnmapBufferARB */
    0, /* glDepthBoundsEXT */
    0, /* glGenQueriesARB */
    0, /* glDeleteQueriesARB */
    0, /* glIsQueryARB */
    0, /* glBeginQueryARB */
    0, /* glEndQueryARB */
    0, /* glGetQueryivARB */
    0, /* glGetQueryObjectivARB */
    0, /* glGetQueryObjectuivARB */
    0, /* glMultiModeDrawArraysIBM */
    0, /* glMultiModeDrawElementsIBM */
    0, /* glBlendEquationSeparateEXT */
    0, /* glDeleteObjectARB */
    0, /* glGetHandleARB */
    0, /* glDetachObjectARB */
    0, /* glCreateShaderObjectARB */
    0, /* glShaderSourceARB */
    0, /* glCompileShaderARB */
    0, /* glCreateProgramObjectARB */
    0, /* glAttachObjectARB */
    0, /* glLinkProgramARB */
    0, /* glUseProgramObjectARB */
    0, /* glValidateProgramARB */
    0, /* glUniform1fARB */
    0, /* glUniform2fARB */
    0, /* glUniform3fARB */
    0, /* glUniform4fARB */
    0, /* glUniform1iARB */
    0, /* glUniform2iARB */
    0, /* glUniform3iARB */
    0, /* glUniform4iARB */
    0, /* glUniform1fvARB */
    0, /* glUniform2fvARB */
    0, /* glUniform3fvARB */
    0, /* glUniform4fvARB */
    0, /* glUniform1ivARB */
    0, /* glUniform2ivARB */
    0, /* glUniform3ivARB */
    0, /* glUniform4ivARB */
    0, /* glUniformMatrix2fvARB */
    0, /* glUniformMatrix3fvARB */
    0, /* glUniformMatrix4fvARB */
    0, /* glGetObjectParameterfvARB */
    0, /* glGetObjectParameterivARB */
    0, /* glGetInfoLogARB */
    0, /* glGetAttachedObjectsARB */
    0, /* glGetUniformLocationARB */
    0, /* glGetActiveUniformARB */
    0, /* glGetUniformfvARB */
    0, /* glGetUniformivARB */
    0, /* glGetShaderSourceARB */
    0, /* glBindAttribLocationARB */
    0, /* glGetActiveAttribARB */
    0, /* glGetAttribLocationARB */
    0, /* glGetVertexAttribdvNV */
    0, /* glGetVertexAttribfvNV */
    0, /* glGetVertexAttribivNV */
    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, /* glGenFragmentShadersATI */
    0, /* glBindFragmentShaderATI */
    0, /* glDeleteFragmentShaderATI */
    0, /* glBeginFragmentShaderATI */
    0, /* glEndFragmentShaderATI */
    0, /* glPassTexCoordATI */
    0, /* glSampleMapATI */
    0, /* glColorFragmentOp1ATI */
    0, /* glColorFragmentOp2ATI */
    0, /* glColorFragmentOp3ATI */
    0, /* glAlphaFragmentOp1ATI */
    0, /* glAlphaFragmentOp2ATI */
    0, /* glAlphaFragmentOp3ATI */
    0, /* glSetFragmentShaderConstantATI */
    xglNoOpIsRenderbufferEXT,
    xglNoOpBindRenderbufferEXT,
    xglNoOpDeleteRenderbuffersEXT,
    xglNoOpGenRenderbuffersEXT,
    xglNoOpRenderbufferStorageEXT,
    xglNoOpGetRenderbufferParameterivEXT,
    xglNoOpIsFramebufferEXT,
    xglNoOpBindFramebufferEXT,
    xglNoOpDeleteFramebuffersEXT,
    xglNoOpGenFramebuffersEXT,
    xglNoOpCheckFramebufferStatusEXT,
    xglNoOpFramebufferTexture1DEXT,
    xglNoOpFramebufferTexture2DEXT,
    xglNoOpFramebufferTexture3DEXT,
    xglNoOpFramebufferRenderbufferEXT,
    xglNoOpGetFramebufferAttachmentParameterivEXT,
    xglNoOpGenerateMipmapEXT,
    0, /* glStencilFuncSeparate */
    0, /* glStencilOpSeparate */
    0, /* glStencilMaskSeparate */
    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_EXT_texture_object"))
    {
	pContext->glRenderTable.AreTexturesResidentEXT =
	    xglAreTexturesResident;
	pContext->glRenderTable.GenTexturesEXT = xglGenTextures;
	pContext->glRenderTable.IsTextureEXT = xglIsTexture;
    }

    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_MESA_window_pos"))
    {
	pContext->WindowPos3fMESA =
	    (PFNGLWINDOWPOS3FMESAPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glWindowPos3fMESA");

	pContext->glRenderTable.WindowPos3fMESA = xglWindowPos3fMESA;
    }

    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_EXT_framebuffer_object"))
    {
	pContext->glRenderTable.IsRenderbufferEXT =
	    (PFNGLISRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glIsRenderbufferEXT");
	pContext->glRenderTable.BindRenderbufferEXT =
	    (PFNGLBINDRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBindRenderbufferEXT");
	pContext->glRenderTable.DeleteRenderbuffersEXT =
	    (PFNGLDELETERENDERBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glDeleteRenderbuffersEXT");
	pContext->glRenderTable.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->glRenderTable.IsFramebufferEXT =
	    (PFNGLISFRAMEBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glIsFramebufferEXT");
	pContext->glRenderTable.BindFramebufferEXT =
	    (PFNGLBINDFRAMEBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glBindFramebufferEXT");
	pContext->glRenderTable.DeleteFramebuffersEXT =
	    (PFNGLDELETEFRAMEBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glDeleteFramebuffersEXT");
	pContext->glRenderTable.GenFramebuffersEXT =
	    (PFNGLGENFRAMEBUFFERSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenFramebuffersEXT");
	pContext->glRenderTable.CheckFramebufferStatusEXT =
	    (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glCheckFramebufferStatusEXT");
	pContext->glRenderTable.FramebufferTexture1DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture1DEXT");
	pContext->glRenderTable.FramebufferTexture2DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture2DEXT");
	pContext->glRenderTable.FramebufferTexture3DEXT =
	    (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferTexture3DEXT");
	pContext->glRenderTable.FramebufferRenderbufferEXT =
	    (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glFramebufferRenderbufferEXT");
	pContext->glRenderTable.GetFramebufferAttachmentParameterivEXT =
	    (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGetFramebufferAttachment"
					    "ParameterivEXT");
	pContext->glRenderTable.GenerateMipmapEXT =
	    (PFNGLGENERATEMIPMAPEXTPROC)
	    glitz_context_get_proc_address (pContext->context,
					    "glGenerateMipmapEXT");
    }
}

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->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->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 GLboolean
xglDestroyContext (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    xglFreeContext (pContext);

    if (!iface)
	return GL_TRUE;

    return (*iface->exports.destroyContext) ((__GLcontext *) iface);
}

static GLboolean
xglLoseCurrent (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    GlxFlushContextCache ();
    GlxSetRenderTables (0);

    if (!iface)
	return GL_TRUE;

    return (*iface->exports.loseCurrent) ((__GLcontext *) iface);
}

static GLboolean
xglMakeCurrent (__GLcontext *gc)
{
    xglGLContextPtr	pContext = (xglGLContextPtr) gc;
    __GLinterface	*iface = &pContext->iface;
    __GLinterface	*mIface = pContext->mIface;
    __GLdrawablePrivate *drawPriv = iface->imports.getDrawablePrivate (gc);
    __GLdrawablePrivate *readPriv = iface->imports.getReadablePrivate (gc);
    xglGLBufferPtr	pDrawBufferPriv = drawPriv->private;
    xglGLBufferPtr	pReadBufferPriv = readPriv->private;
    GLboolean		status = GL_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 GL_FALSE;

	/* XXX: GLX_SGI_make_current_read disabled for now */
	if (pDrawBufferPriv != pReadBufferPriv)
	    return GL_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;

	pContext->readPriv = readPriv;
	pContext->drawPriv = drawPriv;

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

	drawPriv->private = pDrawBufferPriv->private;
	readPriv->private = pReadBufferPriv->private;

	status = (*mIface->exports.makeCurrent) ((__GLcontext *) mIface);

	drawPriv->private = pDrawBufferPriv;
	readPriv->private = pReadBufferPriv;

	/* 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 GLboolean
xglShareContext (__GLcontext *gc,
		 __GLcontext *gcShare)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    xglGLContextPtr pContextShare = (xglGLContextPtr) gcShare;
    __GLinterface   *iface = pContext->mIface;
    __GLinterface   *ifaceShare = pContextShare->mIface;

    if (!iface || !ifaceShare)
	return GL_TRUE;

    return (*iface->exports.shareContext) ((__GLcontext *) iface,
					   (__GLcontext *) ifaceShare);
}

static GLboolean
xglCopyContext (__GLcontext	  *dst,
		const __GLcontext *src,
		GLuint		  mask)
{
    xglGLContextPtr   pDst = (xglGLContextPtr) dst;
    xglGLContextPtr   pSrc = (xglGLContextPtr) src;
    const __GLcontext *srcCtx = (const __GLcontext *) pSrc->mIface;
    __GLinterface     *dstIface = (__GLinterface *) pDst->mIface;
    GLboolean	      status = GL_TRUE;

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

    if (dstIface && srcCtx)
	status = (*dstIface->exports.copyContext) ((__GLcontext *) dstIface,
						   srcCtx,
						   mask);

    return status;
}

static Bool
xglResizeBuffer (__GLdrawablePrivate *glPriv,
		 int		      x,
		 int		      y,
		 unsigned int	      width,
		 unsigned int	      height)
{
    xglGLBufferPtr pBufferPriv = glPriv->private;
    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
xglForceCurrent (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;
    GLboolean	    status = GL_TRUE;

    if (pContext && pContext->context)
    {
	__GLdrawablePrivate *readPriv, *drawPriv;

	readPriv = pContext->readPriv;
	drawPriv = pContext->drawPriv;

	drawPriv->lockDP (drawPriv, gc);
	if (readPriv != drawPriv)
	    readPriv->lockDP (readPriv, gc);

	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 (drawPriv,
				      pDrawable->x,
				      pDrawable->y,
				      pDrawable->width,
				      pDrawable->height))
		{
		    drawPriv->unlockDP (drawPriv);
		    if (readPriv != drawPriv)
			readPriv->unlockDP (readPriv);

		    return FALSE;
		}

		if (!xglResizeBuffer (readPriv,
				      cctx->pReadBuffer->pDrawable->x,
				      cctx->pReadBuffer->pDrawable->y,
				      cctx->pReadBuffer->pDrawable->width,
				      cctx->pReadBuffer->pDrawable->height))
		{
		    drawPriv->unlockDP (drawPriv);
		    if (readPriv != drawPriv)
			readPriv->unlockDP (readPriv);

		    return FALSE;
		}

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

	    if (!xglSyncSurface (pContext->pDrawBuffer->pDrawable))
	    {
		drawPriv->unlockDP (drawPriv);
		if (readPriv != drawPriv)
		    readPriv->unlockDP (readPriv);

		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;
	    }

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

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

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

	    xglDrawBuffer (cctx->attrib.drawBuffer);
	    xglReadBuffer (cctx->attrib.readBuffer);
	}
	else
	{
	    xglSetCurrentContext (pContext);
	}

	drawPriv->unlockDP (drawPriv);
	if (readPriv != drawPriv)
	    readPriv->unlockDP (readPriv);
    }
    else
    {
	cctx = NULL;
	status = (*iface->exports.forceCurrent) ((__GLcontext *) iface);
    }

    return status;
}

static GLboolean
xglNotifyResize (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    if (!iface)
	return GL_TRUE;

    return (*iface->exports.notifyResize) ((__GLcontext *) iface);
}

static void
xglNotifyDestroy (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    pContext->pReadBuffer->pDrawable = 0;
    pContext->pDrawBuffer->pDrawable = 0;

    if (iface)
	(*iface->exports.notifyDestroy) ((__GLcontext *) iface);
}

static void
xglNotifySwapBuffers (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    if (iface)
	(*iface->exports.notifySwapBuffers) ((__GLcontext *) iface);
}

static struct __GLdispatchStateRec *
xglDispatchExec (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    if (!iface)
	return NULL;

    return (*iface->exports.dispatchExec) ((__GLcontext *) iface);
}

static void
xglBeginDispatchOverride (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    if (iface)
	(*iface->exports.beginDispatchOverride) ((__GLcontext *) iface);
}

static void
xglEndDispatchOverride (__GLcontext *gc)
{
    xglGLContextPtr pContext = (xglGLContextPtr) gc;
    __GLinterface   *iface = pContext->mIface;

    if (iface)
	(*iface->exports.endDispatchOverride) ((__GLcontext *) iface);
}

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

	GlxFlushContextCache ();
	GlxSetRenderTables (0);
    }
}

static __GLinterface *
xglCreateContext (__GLimports      *imports,
		  __GLcontextModes *modes,
		  __GLinterface    *shareGC)
{
    glitz_drawable_format_t *format;
    xglGLContextPtr	    pShareContext = (xglGLContextPtr) shareGC;
    xglGLContextPtr	    pContext;
    __GLinterface	    *shareIface = NULL;
    __GLinterface	    *iface;
    __GLXcontext	    *glxCtx = (__GLXcontext *) imports->other;

    XGL_SCREEN_PRIV (glxCtx->pScreen);

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

    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  = glxCtx->modes->doubleBufferMode;
    pContext->depthBits     = glxCtx->modes->depthBits;
    pContext->stencilBits   = glxCtx->modes->stencilBits;
    pContext->drawXoff	    = 0;
    pContext->drawYoff	    = 0;
    pContext->maxTexUnits   = 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 (shareGC)
    {
	pContext->texObjects   = NULL;
	pContext->displayLists = NULL;

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

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

	pContext->shared = pContext;
    }

    pContext->shared->refcnt++;

    iface = (*screenInfoPriv.createContext) (imports, modes, shareIface);
    if (!iface)
    {
	xglFreeContext (pContext);
	return NULL;
    }

    pContext->mIface = iface;
    pContext->iface.imports = *imports;

    pContext->iface.exports.destroyContext	  = xglDestroyContext;
    pContext->iface.exports.loseCurrent		  = xglLoseCurrent;
    pContext->iface.exports.makeCurrent		  = xglMakeCurrent;
    pContext->iface.exports.shareContext	  = xglShareContext;
    pContext->iface.exports.copyContext		  = xglCopyContext;
    pContext->iface.exports.forceCurrent	  = xglForceCurrent;
    pContext->iface.exports.notifyResize	  = xglNotifyResize;
    pContext->iface.exports.notifyDestroy	  = xglNotifyDestroy;
    pContext->iface.exports.notifySwapBuffers     = xglNotifySwapBuffers;
    pContext->iface.exports.dispatchExec	  = xglDispatchExec;
    pContext->iface.exports.beginDispatchOverride = xglBeginDispatchOverride;
    pContext->iface.exports.endDispatchOverride   = xglEndDispatchOverride;

    return (__GLinterface *) pContext;
}

static GLboolean
xglSwapBuffers (__GLXdrawablePrivate *glxPriv)
{
    __GLdrawablePrivate	*glPriv = &glxPriv->glPriv;
    xglGLBufferPtr	pBufferPriv = glPriv->private;
    DrawablePtr		pDrawable = pBufferPriv->pDrawable;
    GLboolean		status = GL_TRUE;

    if (pDrawable)
    {
	if (glPriv->modes->doubleBufferMode)
	{
	    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 (pBufferPriv->private)
    {
	glPriv->private = pBufferPriv->private;
	status = (*pBufferPriv->swapBuffers) (glxPriv);
	glPriv->private = pBufferPriv;
    }

    return status;
}

static GLboolean
xglResizeBuffers (__GLdrawableBuffer  *buffer,
		  GLint		      x,
		  GLint		      y,
		  GLuint	      width,
		  GLuint	      height,
		  __GLdrawablePrivate *glPriv,
		  GLuint	      bufferMask)
{
    xglGLBufferPtr pBufferPriv = glPriv->private;
    DrawablePtr    pDrawable = pBufferPriv->pDrawable;
    GLboolean	   status = GL_TRUE;

    if (pDrawable)
    {
	if (!xglResizeBuffer (glPriv, x, y, width, height))
	    return GL_FALSE;
    }
    else if (pBufferPriv->private)
    {
	glPriv->private = pBufferPriv->private;
	status = (*pBufferPriv->resizeBuffers) (buffer,
						x, y, width, height,
						glPriv,
						bufferMask);
	glPriv->private = pBufferPriv;
    }

    return status;
}

static int
xglBindBuffers (__GLXdrawablePrivate *glxPriv,
		int		     buffer)
{
    __GLdrawablePrivate	*glPriv = &glxPriv->glPriv;
    xglGLBufferPtr	pBufferPriv = glPriv->private;

    if (cctx)
    {
	xglTexUnitPtr pTexUnit = &cctx->attrib.texUnits[cctx->activeTexUnit];
	xglTexObjPtr  pTexObj = NULL;
	DrawablePtr   pDrawable;

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

	/* Must be a GLXpixmap */
	if (!glxPriv->pGlxPixmap)
	    return BadDrawable;

	pDrawable = glxPriv->pGlxPixmap->pDraw;

	switch (glxPriv->texTarget) {
	case GLX_TEXTURE_RECTANGLE_EXT:
	    pTexObj = pTexUnit->pRect;
	    break;
	case GLX_TEXTURE_2D_EXT:
	    pTexObj = pTexUnit->p2D;
	    break;
	default:
	    break;
	}

	if (pTexObj)
	{
	    glitz_texture_object_t *object;

	    XGL_SCREEN_PRIV (pDrawable->pScreen);
	    XGL_DRAWABLE_PIXMAP (pDrawable);
	    XGL_PIXMAP_PRIV (pPixmap);

	    if (pPixmap == pScreenPriv->pScreenPixmap)
		return BadDrawable;

	    object = glitz_texture_object_create (pPixmapPriv->surface);
	    if (object)
	    {
		pPixmap->refcnt++;

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

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

		pTexObj->pPixmap = pPixmap;
		pTexObj->object  = object;

		return Success;
	    }
	}
    }
    else if (pBufferPriv->private)
    {
	int status;

	glPriv->private = pBufferPriv->private;
	status = (*pBufferPriv->bindBuffers) (glxPriv, buffer);
	glPriv->private = pBufferPriv;

	return status;
    }

    return BadDrawable;
}

static int
xglReleaseBuffers (__GLXdrawablePrivate *glxPriv,
		   int		        buffer)
{
    __GLdrawablePrivate	*glPriv = &glxPriv->glPriv;
    xglGLBufferPtr	pBufferPriv = glPriv->private;

    if (cctx)
    {
	xglTexObjPtr pTexObj;

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

	/* Must be a GLXpixmap */
	if (glxPriv->pGlxPixmap)
	{
	    DrawablePtr pDrawable = glxPriv->pGlxPixmap->pDraw;

	    XGL_DRAWABLE_PIXMAP (pDrawable);

	    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 if (pBufferPriv->private)
    {
	int status;

	glPriv->private = pBufferPriv->private;
	status = (*pBufferPriv->releaseBuffers) (glxPriv, buffer);
	glPriv->private = pBufferPriv;

	return status;
    }

    return BadDrawable;
}
static void
xglFreeBuffers (__GLdrawablePrivate *glPriv)
{
    xglGLBufferPtr pBufferPriv = glPriv->private;

    glPriv->private = pBufferPriv->private;

    if (pBufferPriv->freeBuffers)
	(*pBufferPriv->freeBuffers) (glPriv);

    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 void
xglCreateBuffer (__GLXdrawablePrivate *glxPriv)
{
    __GLdrawablePrivate	*glPriv = &glxPriv->glPriv;
    DrawablePtr	        pDrawable = glxPriv->pDraw;
    ScreenPtr		pScreen = pDrawable->pScreen;
    xglGLBufferPtr	pBufferPriv;
    xglVisualPtr	v;

    XGL_SCREEN_PRIV (pScreen);
    XGL_DRAWABLE_PIXMAP (pDrawable);

    pBufferPriv = xalloc (sizeof (xglGLBufferRec));
    if (!pBufferPriv)
	FatalError ("xglCreateBuffer: No memory\n");

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

    pBufferPriv->swapBuffers = NULL;

    pBufferPriv->bindBuffers    = NULL;
    pBufferPriv->releaseBuffers = NULL;

    pBufferPriv->resizeBuffers = NULL;
    pBufferPriv->private       = NULL;
    pBufferPriv->freeBuffers   = NULL;

    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   != glxPriv->modes->redBits   ||
		format->color.green_size != glxPriv->modes->greenBits ||
		format->color.blue_size  != glxPriv->modes->blueBits)
		continue;

	    if (format->color.alpha_size < glxPriv->modes->alphaBits   ||
		format->depth_size	 < glxPriv->modes->depthBits   ||
		format->stencil_size     < glxPriv->modes->stencilBits ||
		format->doublebuffer     < glxPriv->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 == glxPriv->modes->alphaBits   &&
		format->depth_size	 == glxPriv->modes->depthBits   &&
		format->stencil_size     == glxPriv->modes->stencilBits &&
		format->doublebuffer     == glxPriv->modes->doubleBufferMode)
		break;
	}

	pBufferPriv->pVisual = v;
    }

    if ((pDrawable->type == DRAWABLE_WINDOW)

#ifdef COMPOSITE
	&& (pBufferPriv->pVisual

	    /* this is a root window, can't be redirected */
	    || (!((WindowPtr) pDrawable)->parent))
#endif

	)
    {
	pBufferPriv->pDrawable = pDrawable;
    }
    else
    {
	(*screenInfoPriv.createBuffer) (glxPriv);

	/* Wrap the swap buffers routine */
	pBufferPriv->swapBuffers = glxPriv->swapBuffers;

	/* Wrap the render texture routines */
	pBufferPriv->bindBuffers    = glxPriv->bindBuffers;
	pBufferPriv->releaseBuffers = glxPriv->releaseBuffers;

	/* Wrap the front buffer's resize routine */
	pBufferPriv->resizeBuffers = glPriv->frontBuffer.resize;

	/* Save Xgl's private buffer structure */
	pBufferPriv->freeBuffers = glPriv->freePrivate;
	pBufferPriv->private	 = glPriv->private;
    }

    glxPriv->texTarget = GLX_NO_TEXTURE_EXT;

    /* We enable render texture for all GLXPixmaps right now. Eventually, this
       should only be enabled when fbconfig attribute GLX_RENDER_TEXTURE_RGB or
       GLX_RENDER_TEXTURE_RGBA is set to TRUE. */
    if (pDrawable->type != DRAWABLE_WINDOW)
    {
	XGL_DRAWABLE_PIXMAP (pDrawable);

	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:
		    glxPriv->texTarget = GLX_TEXTURE_2D_EXT;
		    break;
		case GLITZ_TEXTURE_TARGET_RECT:
		    glxPriv->texTarget = GLX_TEXTURE_RECTANGLE_EXT;
		    break;
		}

		glitz_texture_object_destroy (texture);
	    }
	}
    }

    glxPriv->swapBuffers = xglSwapBuffers;

    glxPriv->bindBuffers    = xglBindBuffers;
    glxPriv->releaseBuffers = xglReleaseBuffers;
    glPriv->frontBuffer.resize = xglResizeBuffers;

    glPriv->private	= (void *) pBufferPriv;
    glPriv->freePrivate	= xglFreeBuffers;
}

static Bool
xglScreenProbe (int screen)
{
    ScreenPtr    pScreen = screenInfo.screens[screen];
    xglVisualPtr pVisual;
    Bool         status;
    int          i;

    XGL_SCREEN_PRIV (pScreen);

    status = (*screenInfoPriv.screenProbe) (screen);

    /* Create Xgl GLX visuals */
    for (i = 0; i < __xglScreenInfoPtr->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   = __xglScreenInfoPtr->modes[i].depthBits;
	    templ.stencil_size = __xglScreenInfoPtr->modes[i].stencilBits;
	    templ.doublebuffer = __xglScreenInfoPtr->modes[i].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;
		}
	    }
	}
    }

    /* Wrap createBuffer */
    if (__xglScreenInfoPtr->createBuffer != xglCreateBuffer)
    {
	screenInfoPriv.createBuffer    = __xglScreenInfoPtr->createBuffer;
	__xglScreenInfoPtr->createBuffer = xglCreateBuffer;
    }

    /* Wrap createContext */
    if (__xglScreenInfoPtr->createContext != xglCreateContext)
    {
	screenInfoPriv.createContext    = __xglScreenInfoPtr->createContext;
	__xglScreenInfoPtr->createContext = xglCreateContext;
    }

    return status;
}

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;
    }

    GlxSetVisualConfigs (numConfig, pConfig, (void **) ppConfigPriv);

    /* Wrap screenProbe */
    if (__xglScreenInfoPtr->screenProbe != xglScreenProbe)
    {
	screenInfoPriv.screenProbe    = __xglScreenInfoPtr->screenProbe;
	__xglScreenInfoPtr->screenProbe = xglScreenProbe;
    }

    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;
}