glxcmds.c   [plain text]


/* $XFree86: xc/lib/GL/glx/glxcmds.c,v 1.31 2004/02/09 23:46:31 alanh Exp $ */
/*
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
** 
** http://oss.sgi.com/projects/FreeB
** 
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
** 
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
** 
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
**
*/

#include "packsingle.h"
#include "glxclient.h"
#include <extensions/extutil.h>
#include <extensions/Xext.h>
#include <assert.h>
#include <string.h>
#include "glapi.h"
#ifdef GLX_DIRECT_RENDERING
#include "indirect_init.h"
#include <extensions/xf86vmode.h>
#endif
#include "glxextensions.h"
#include "glcontextmodes.h"
#include <sys/time.h>


//#define DEBUG 1

const char __glXGLClientExtensions[] = 
			"GL_ARB_depth_texture "
			"GL_ARB_imaging "
			"GL_ARB_multisample "
			"GL_ARB_multitexture "
			"GL_ARB_point_parameters "
			"GL_ARB_point_sprite "
			"GL_ARB_shadow "
			"GL_ARB_shadow_ambient "
			"GL_ARB_texture_border_clamp "
			"GL_ARB_texture_cube_map "
			"GL_ARB_texture_env_add "
			"GL_ARB_texture_env_combine "
			"GL_ARB_texture_env_crossbar "
			"GL_ARB_texture_env_dot3 "
			"GL_ARB_texture_mirrored_repeat "
			"GL_ARB_texture_non_power_of_two "
			"GL_ARB_transpose_matrix "
			"GL_ARB_window_pos "
			"GL_EXT_abgr "
			"GL_EXT_bgra "
 			"GL_EXT_blend_color "
			"GL_EXT_blend_func_separate "
			"GL_EXT_blend_logic_op "
 			"GL_EXT_blend_minmax "
 			"GL_EXT_blend_subtract "
			"GL_EXT_clip_volume_hint "
			"GL_EXT_copy_texture "
			"GL_EXT_draw_range_elements "
			"GL_EXT_fog_coord "
			"GL_EXT_multi_draw_arrays "
			"GL_EXT_packed_pixels "
			"GL_EXT_polygon_offset "
			"GL_EXT_rescale_normal "
			"GL_EXT_secondary_color "
			"GL_EXT_separate_specular_color "
			"GL_EXT_shadow_funcs "
 			"GL_EXT_stencil_two_side "
			"GL_EXT_stencil_wrap "
			"GL_EXT_subtexture "
			"GL_EXT_texture "
			"GL_EXT_texture3D "
			"GL_EXT_texture_edge_clamp "
 			"GL_EXT_texture_env_add "
 			"GL_EXT_texture_env_combine "
 			"GL_EXT_texture_env_dot3 "
			"GL_EXT_texture_filter_anisotropic "
 			"GL_EXT_texture_lod "
 			"GL_EXT_texture_lod_bias "
			"GL_EXT_texture_object "
			"GL_EXT_texture_rectangle "
			"GL_EXT_vertex_array "
 			"GL_APPLE_packed_pixels "
 			"GL_APPLE_ycbcr_422 "
 			"GL_ATI_texture_env_combine3 "
 			"GL_ATI_texture_float "
 			"GL_ATI_texture_mirror_once "
 			"GL_ATIX_texture_env_combine3 "
			"GL_HP_convolution_border_modes "
#if 0
    /* This is currently removed because there seem to be some problems with
     * it and the software-only indirect rendering path.  At this point, I'm
     * not sure which side (client or server) has the problem. - idr
     */
 			"GL_HP_occlusion_test "
#endif
			"GL_IBM_cull_vertex "
			"GL_IBM_pixel_filter_hint "
			"GL_IBM_rasterpos_clip "
			"GL_IBM_texture_clamp_nodraw "
			"GL_IBM_texture_mirrored_repeat "
			"GL_INGR_interlace_read "
 			"GL_MESA_pack_invert "
 			"GL_MESA_ycbcr_texture "
			"GL_NV_blend_square "
			"GL_NV_copy_depth_to_color "
			"GL_NV_depth_clamp "
			"GL_NV_fog_distance "
			"GL_NV_light_max_exponent "
			"GL_NV_multisample_filter_hint "
			"GL_NV_point_sprite "
			"GL_NV_texgen_reflection "
			"GL_NV_texture_rectangle "
			"GL_SGIS_generate_mipmap "
			"GL_SGIS_multisample "
			"GL_SGIS_texture_border_clamp "
			"GL_SGIS_texture_edge_clamp "
			"GL_SGIS_texture_lod "
			"GL_SGIX_blend_alpha_minmax "
			"GL_SGIX_clipmap "
			"GL_SGIX_depth_texture "
			"GL_SGIX_fog_offset "
			"GL_SGIX_shadow "
			"GL_SGIX_shadow_ambient "
			"GL_SGIX_texture_coordinate_clamp "
			"GL_SGIX_texture_lod_bias "
			"GL_SGIX_texture_range "
			"GL_SGIX_texture_scale_bias "
			"GL_SGIX_vertex_preclip "
			"GL_SGIX_vertex_preclip_hint "
			"GL_SGIX_ycrcb "
			"GL_SUN_convolution_border_modes "
			"GL_SUN_slice_accum "
			;

static const char __glXGLXClientVendorName[] = "SGI";
static const char __glXGLXClientVersion[] = "1.2";

/**
 * Textual version of the client-side GL core version.  This version is
 * primarilly determined by what functionality has implemented protocol.
 */
const char __glXGLClientVersion[] = "1.2";

#ifdef GLX_DIRECT_RENDERING
static void * DriverCreateContextWrapper( __GLXscreenConfigs *psc,
    Display *dpy, XVisualInfo *vis, void *shared, __DRIcontext *ctx,
    __GLcontextModes *fbconfig );

static Bool dummyBindContext2( Display *dpy, int scrn,
    GLXDrawable draw, GLXDrawable read, GLXContext gc );

static Bool dummyUnbindContext2( Display *dpy, int scrn,
    GLXDrawable draw, GLXDrawable read, GLXContext gc );

/****************************************************************************/

static Bool dummyBindContext2( Display *dpy, int scrn,
			       GLXDrawable draw, GLXDrawable read,
			       GLXContext gc )
{
    assert( draw == read );
    return (*gc->driContext.bindContext)( dpy, scrn, draw, gc );
}

static Bool dummyUnbindContext2( Display *dpy, int scrn,
				 GLXDrawable draw, GLXDrawable read,
				 GLXContext gc )
{
    assert( draw == read );
    return (*gc->driContext.unbindContext)( dpy, scrn, draw, gc, GL_FALSE );
}


/****************************************************************************/
/**
 * Wrap the call to the driver's \c createContext function.
 *
 * The \c createContext function is wrapped because not all drivers support
 * the "new" \c unbindContext2 and \c bindContext2 interfaces.  libGL should
 * not have to check to see which functions the driver supports.  Instead,
 * if either function is not supported it is wrapped.  The wrappers test to
 * make sure that both drawables are the same and pass control to the old
 * interface.
 */

static void * DriverCreateContextWrapper( __GLXscreenConfigs *psc,
					  Display *dpy, XVisualInfo *vis,
					  void *shared,
					  __DRIcontext *ctx,
					  __GLcontextModes *fbconfig )
{
    void * ctx_priv;

    (void) fbconfig;
    ctx_priv = (*psc->driScreen.createContext)(dpy, vis, shared, ctx);
    if ( ctx_priv != NULL ) {
	if ( ctx->unbindContext2 == NULL ) {
	    ctx->unbindContext2 = dummyUnbindContext2;
	}

	if ( ctx->bindContext2 == NULL ) {
	    ctx->bindContext2 = dummyBindContext2;
	}
    }
    
    return ctx_priv;
}
#endif


/****************************************************************************/
/**
 * Get the __DRIdrawable for the drawable associated with a GLXContext
 * 
 * \param dpy       The display associated with \c drawable.
 * \param drawable  GLXDrawable whose __DRIdrawable part is to be retrieved.
 * \returns  A pointer to the context's __DRIdrawable on success, or NULL if
 *           the drawable is not associated with a direct-rendering context.
 */

#ifdef GLX_DIRECT_RENDERING
static __DRIdrawable *
GetDRIDrawable( Display *dpy, GLXDrawable drawable, int * const scrn_num )
{
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);

    if ( (priv != NULL) && (priv->driDisplay.private != NULL) ) {
	const unsigned  screen_count = ScreenCount(dpy);
	unsigned   i;

	for ( i = 0 ; i < screen_count ; i++ ) {
	    __DRIscreen * const psc = &priv->screenConfigs[i].driScreen;
	    __DRIdrawable * const pdraw = (psc->private != NULL)
	       ? (*psc->getDrawable)(dpy, drawable, psc->private) : NULL;

	    if ( pdraw != NULL ) {
		if ( scrn_num != NULL ) {
		    *scrn_num = i;
		}
		return pdraw;
	    }
	}
    }

    return NULL;
}
#endif


/**
 * Get the GLX per-screen data structure associated with a GLX context.
 * 
 * \param dpy   Display for which the GLX per-screen information is to be
 *              retrieved.
 * \param scrn  Screen on \c dpy for which the GLX per-screen information is
 *              to be retrieved.
 * \returns A pointer to the GLX per-screen data if \c dpy and \c scrn
 *          specify a valid GLX screen, or NULL otherwise.
 * 
 * \todo Should this function validate that \c scrn is within the screen
 *       number range for \c dpy?
 */

static __GLXscreenConfigs *
GetGLXScreenConfigs(Display *dpy, int scrn)
{
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);

    return (priv->screenConfigs != NULL) ? &priv->screenConfigs[scrn] : NULL;
}


static int
GetGLXPrivScreenConfig( Display *dpy, int scrn, __GLXdisplayPrivate ** ppriv,
			__GLXscreenConfigs ** ppsc )
{
    /* Initialize the extension, if needed .  This has the added value
     * of initializing/allocating the display private 
     */
    
    if ( dpy == NULL ) {
	return GLX_NO_EXTENSION;
    }

    *ppriv = __glXInitialize(dpy);
    if ( *ppriv == NULL ) {
	return GLX_NO_EXTENSION;
    }

    /* Check screen number to see if its valid */
    if ((scrn < 0) || (scrn >= ScreenCount(dpy))) {
	return GLX_BAD_SCREEN;
    }

    /* Check to see if the GL is supported on this screen */
    *ppsc = &((*ppriv)->screenConfigs[scrn]);
    if ( ((*ppsc)->configs == NULL) || ((*ppsc)->numConfigs <= 0) ) {
	/* No support for GL on this screen regardless of visual */
	return GLX_BAD_VISUAL;
    }

    return Success;
}


/**
 * \todo It should be possible to move the allocate of \c client_state_private
 * later in the function for direct-rendering contexts.  Direct-rendering
 * contexts don't need to track client state, so they don't need that memory
 * at all.
 * 
 * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
 * function called \c __glXAllocateClientState that allocates the memory and
 * does all the initialization (including the pixel pack / unpack).
 */
static
GLXContext AllocateGLXContext( Display *dpy )
{
     GLXContext gc;
     int bufSize;
     CARD8 opcode;
    __GLXattribute *state;

    if (!dpy)
        return NULL;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return NULL;
    }

    /* Allocate our context record */
    gc = (GLXContext) Xmalloc(sizeof(struct __GLXcontextRec));
    if (!gc) {
	/* Out of memory */
	return NULL;
    }
    memset(gc, 0, sizeof(struct __GLXcontextRec));

    state = Xmalloc(sizeof(struct __GLXattributeRec));
    if (state == NULL) {
	/* Out of memory */
	Xfree(gc);
	return NULL;
    }
    gc->client_state_private = state;
    memset(gc->client_state_private, 0, sizeof(struct __GLXattributeRec));

    /*
    ** Create a temporary buffer to hold GLX rendering commands.  The size
    ** of the buffer is selected so that the maximum number of GLX rendering
    ** commands can fit in a single X packet and still have room in the X
    ** packet for the GLXRenderReq header.
    */

    bufSize = (XMaxRequestSize(dpy) * 4) - sz_xGLXRenderReq;
    gc->buf = (GLubyte *) Xmalloc(bufSize);
    if (!gc->buf) {
	Xfree(gc->client_state_private);
	Xfree(gc);
	return NULL;
    }
    gc->bufSize = bufSize;

    /* Fill in the new context */
    gc->renderMode = GL_RENDER;

    state->storePack.alignment = 4;
    state->storeUnpack.alignment = 4;

    __glXInitVertexArrayState(gc);

    gc->attributes.stackPointer = &gc->attributes.stack[0];

    /*
    ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
    ** Other code uses the fastImageUnpack bit, but it is never set
    ** to GL_TRUE.
    */
    gc->fastImageUnpack = GL_FALSE;
    gc->fillImage = __glFillImage;
    gc->isDirect = GL_FALSE;
    gc->pc = gc->buf;
    gc->bufEnd = gc->buf + bufSize;
    if (__glXDebug) {
	/*
	** Set limit register so that there will be one command per packet
	*/
	gc->limit = gc->buf;
    } else {
	gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
    }
    gc->createDpy = dpy;
    gc->majorOpcode = opcode;

    /*
    ** Constrain the maximum drawing command size allowed to be
    ** transfered using the X_GLXRender protocol request.  First
    ** constrain by a software limit, then constrain by the protocl
    ** limit.
    */
    if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
        bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
    }
    if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
        bufSize = __GLX_MAX_RENDER_CMD_SIZE;
    }
    gc->maxSmallRenderCommandSize = bufSize;
    return gc;
}


/**
 * Create a new context.  Exactly one of \c vis and \c fbconfig should be
 * non-NULL.
 * 
 * \param use_glx_1_3  For FBConfigs, should GLX 1.3 protocol or
 *                     SGIX_fbconfig protocol be used?
 * \param renderType   For FBConfigs, what is the rendering type?
 */

static
GLXContext CreateContext(Display *dpy, XVisualInfo *vis,
			 __GLcontextModes * fbconfig, GLXContext shareList,
			 Bool allowDirect, GLXContextID contextID,
			 Bool use_glx_1_3, int renderType)
{
    GLXContext gc;

    if ( dpy == NULL )
       return NULL;

    gc = AllocateGLXContext(dpy);
    if (!gc)
	return NULL;

    if (None == contextID) {
	if ( (vis == NULL) && (fbconfig == NULL) )
	    return NULL;

#ifdef GLX_DIRECT_RENDERING
	if (allowDirect) {
	    int screen = (fbconfig == NULL) ? vis->screen : fbconfig->screen;
	    __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);

	    if (psc && psc->driScreen.private) {
		void * const shared = (shareList != NULL)
		    ? shareList->driContext.private : NULL;
		gc->driContext.private =
		    DriverCreateContextWrapper( psc, dpy, vis, shared,
						&gc->driContext, fbconfig );
		if (gc->driContext.private) {
		    gc->isDirect = GL_TRUE;
		    gc->screen = screen;
		    if ( fbconfig == NULL ) {
			gc->vid = vis->visualid;
			gc->fbconfigID = None;
		    }
		    else {
			gc->vid = fbconfig->visualID;
			gc->fbconfigID = fbconfig->fbconfigID;
		    }
		}
	    }
	}
#endif

	LockDisplay(dpy);
	if ( fbconfig == NULL ) {
	    xGLXCreateContextReq *req;

	    /* Send the glXCreateContext request */
	    GetReq(GLXCreateContext,req);
	    req->reqType = gc->majorOpcode;
	    req->glxCode = X_GLXCreateContext;
	    req->context = gc->xid = XAllocID(dpy);
	    req->visual = vis->visualid;
	    req->screen = vis->screen;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}
	else if ( use_glx_1_3 ) {
	    xGLXCreateNewContextReq *req;

	    /* Send the glXCreateNewContext request */
	    GetReq(GLXCreateNewContext,req);
	    req->reqType = gc->majorOpcode;
	    req->glxCode = X_GLXCreateNewContext;
	    req->context = gc->xid = XAllocID(dpy);
	    req->fbconfig = fbconfig->fbconfigID;
	    req->screen = fbconfig->screen;
	    req->renderType = renderType;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}
	else {
	    xGLXVendorPrivateReq *vpreq;
	    xGLXCreateContextWithConfigSGIXReq *req;

	    /* Send the glXCreateNewContext request */
	    GetReqExtra(GLXVendorPrivate,
			sz_xGLXCreateContextWithConfigSGIXReq-sz_xGLXVendorPrivateReq,vpreq);
	    req = (xGLXCreateContextWithConfigSGIXReq *)vpreq;
	    req->reqType = gc->majorOpcode;
	    req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX;
	    req->context = gc->xid = XAllocID(dpy);
	    req->fbconfig = fbconfig->fbconfigID;
	    req->screen = fbconfig->screen;
	    req->renderType = renderType;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}

	UnlockDisplay(dpy);
	SyncHandle();
	gc->imported = GL_FALSE;
    }
    else {
	gc->xid = contextID;
	gc->imported = GL_TRUE;
    }


    return gc;
}


GLXContext GLX_PREFIX(glXCreateContext)(Display *dpy, XVisualInfo *vis,
			    GLXContext shareList, Bool allowDirect)
{
   return CreateContext(dpy, vis, NULL, shareList, allowDirect, None,
			False, 0);
}

void __glXFreeContext(__GLXcontext *gc)
{
    if (gc->vendor) XFree((char *) gc->vendor);
    if (gc->renderer) XFree((char *) gc->renderer);
    if (gc->version) XFree((char *) gc->version);
    if (gc->extensions) XFree((char *) gc->extensions);
    __glFreeAttributeState(gc);
    XFree((char *) gc->buf);
    XFree((char *) gc->client_state_private);
    XFree((char *) gc);
    
}

/*
** Destroy the named context
*/
static void 
DestroyContext(Display *dpy, GLXContext gc)
{
    xGLXDestroyContextReq *req;
    GLXContextID xid;
    CARD8 opcode;
    GLboolean imported;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode || !gc) {
	return;
    }

    __glXLock();
    xid = gc->xid;
    imported = gc->imported;
    gc->xid = None;

#ifdef GLX_DIRECT_RENDERING
    /* Destroy the direct rendering context */
    if (gc->isDirect) {
	if (gc->driContext.private) {
	    (*gc->driContext.destroyContext)(dpy, gc->screen,
					     gc->driContext.private);
	    gc->driContext.private = NULL;
	}
    }
#endif

    if (gc->currentDpy) {
	/* Have to free later cuz it's in use now */
	__glXUnlock();
    } else {
	/* Destroy the handle if not current to anybody */
	__glXUnlock();
	__glXFreeContext(gc);
    }

    if (!imported) {
	/* 
	** This dpy also created the server side part of the context.
	** Send the glXDestroyContext request.
	*/
	LockDisplay(dpy);
	GetReq(GLXDestroyContext,req);
	req->reqType = opcode;
	req->glxCode = X_GLXDestroyContext;
	req->context = xid;
	UnlockDisplay(dpy);
	SyncHandle();
    }
}
void GLX_PREFIX(glXDestroyContext)(Display *dpy, GLXContext gc)
{
    DestroyContext(dpy, gc);
}

/*
** Return the major and minor version #s for the GLX extension
*/
Bool GLX_PREFIX(glXQueryVersion)(Display *dpy, int *major, int *minor)
{
    __GLXdisplayPrivate *priv;

    /* Init the extension.  This fetches the major and minor version. */
    priv = __glXInitialize(dpy);
    if (!priv) return GL_FALSE;

    if (major) *major = priv->majorVersion;
    if (minor) *minor = priv->minorVersion;
    return GL_TRUE;
}

/*
** Query the existance of the GLX extension
*/
Bool GLX_PREFIX(glXQueryExtension)(Display *dpy, int *errorBase, int *eventBase)
{
    int major_op, erb, evb;
    Bool rv;

    rv = XQueryExtension(dpy, GLX_EXTENSION_NAME, &major_op, &evb, &erb);
    if (rv) {
	if (errorBase) *errorBase = erb;
	if (eventBase) *eventBase = evb;
    }
    return rv;
}

/*
** Put a barrier in the token stream that forces the GL to finish its
** work before X can proceed.
*/
void GLX_PREFIX(glXWaitGL)(void)
{
    xGLXWaitGLReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
/* This bit of ugliness unwraps the glFinish function */
#ifdef glFinish
#undef glFinish
#endif
	glFinish();
	return;
    }
#endif

    /* Send the glXWaitGL request */
    LockDisplay(dpy);
    GetReq(GLXWaitGL,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitGL;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

/*
** Put a barrier in the token stream that forces X to finish its
** work before GL can proceed.
*/
void GLX_PREFIX(glXWaitX)(void)
{
    xGLXWaitXReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	XSync(dpy, False);
	return;
    }
#endif

    /*
    ** Send the glXWaitX request.
    */
    LockDisplay(dpy);
    GetReq(GLXWaitX,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitX;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

void GLX_PREFIX(glXUseXFont)(Font font, int first, int count, int listBase)
{
    xGLXUseXFontReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    (void) __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
      DRI_glXUseXFont(font, first, count, listBase);
      return;
    }
#endif

    /* Send the glXUseFont request */
    LockDisplay(dpy);
    GetReq(GLXUseXFont,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXUseXFont;
    req->contextTag = gc->currentContextTag;
    req->font = font;
    req->first = first;
    req->count = count;
    req->listBase = listBase;
    UnlockDisplay(dpy);
    SyncHandle();
}

/************************************************************************/

/*
** Copy the source context to the destination context using the
** attribute "mask".
*/
void GLX_PREFIX(glXCopyContext)(Display *dpy, GLXContext source, GLXContext dest,
		    unsigned long mask)
{
    xGLXCopyContextReq *req;
    GLXContext gc = __glXGetCurrentContext();
    GLXContextTag tag;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	/* NOT_DONE: This does not work yet */
    }
#endif

    /*
    ** If the source is the current context, send its tag so that the context
    ** can be flushed before the copy.
    */
    if (source == gc && dpy == gc->currentDpy) {
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXCopyContext request */
    LockDisplay(dpy);
    GetReq(GLXCopyContext,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCopyContext;
    req->source = source ? source->xid : None;
    req->dest = dest ? dest->xid : None;
    req->mask = mask;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
}


/*
** Return GL_TRUE if the context is direct rendering or not.
*/
static Bool __glXIsDirect(Display *dpy, GLXContextID contextID)
{
    xGLXIsDirectReq *req;
    xGLXIsDirectReply reply;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return GL_FALSE;
    }

    /* Send the glXIsDirect request */
    LockDisplay(dpy);
    GetReq(GLXIsDirect,req);
    req->reqType = opcode;
    req->glxCode = X_GLXIsDirect;
    req->context = contextID;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);
    SyncHandle();

    return reply.isDirect;
}

Bool GLX_PREFIX(glXIsDirect)(Display *dpy, GLXContext gc)
{
    if (!gc) {
	return GL_FALSE;
#ifdef GLX_DIRECT_RENDERING
    } else if (gc->isDirect) {
	return GL_TRUE;
#endif
    }
    return __glXIsDirect(dpy, gc->xid);
}

GLXPixmap GLX_PREFIX(glXCreateGLXPixmap)(Display *dpy, XVisualInfo *vis, Pixmap pixmap)
{
    xGLXCreateGLXPixmapReq *req;
    GLXPixmap xid;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return None;
    }

    /* Send the glXCreateGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXCreateGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCreateGLXPixmap;
    req->screen = vis->screen;
    req->visual = vis->visualid;
    req->pixmap = pixmap;
    req->glxpixmap = xid = XAllocID(dpy);
    UnlockDisplay(dpy);
    SyncHandle();
    return xid;
}

/*
** Destroy the named pixmap
*/
void GLX_PREFIX(glXDestroyGLXPixmap)(Display *dpy, GLXPixmap glxpixmap)
{
    xGLXDestroyGLXPixmapReq *req;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }
    
    /* Send the glXDestroyGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXDestroyGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXDestroyGLXPixmap;
    req->glxpixmap = glxpixmap;
    UnlockDisplay(dpy);
    SyncHandle();
}

void GLX_PREFIX(glXSwapBuffers)(Display *dpy, GLXDrawable drawable)
{
    xGLXSwapBuffersReq *req;
    GLXContext gc;
    GLXContextTag tag;
    CARD8 opcode;
#ifdef GLX_DIRECT_RENDERING
    __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, NULL );

    if ( pdraw != NULL ) {
	(*pdraw->swapBuffers)(dpy, pdraw->private);
	return;
    }
#endif

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }

    /*
    ** The calling thread may or may not have a current context.  If it
    ** does, send the context tag so the server can do a flush.
    */
    gc = __glXGetCurrentContext();
    if ((gc != NULL) && (dpy == gc->currentDpy) && 
 	((drawable == gc->currentDrawable) || (drawable == gc->currentReadable)) ) {
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXSwapBuffers request */
    LockDisplay(dpy);
    GetReq(GLXSwapBuffers,req);
    req->reqType = opcode;
    req->glxCode = X_GLXSwapBuffers;
    req->drawable = drawable;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
    XFlush(dpy);
}


/*
** Return configuration information for the given display, screen and
** visual combination.
*/
int GLX_PREFIX(glXGetConfig)(Display *dpy, XVisualInfo *vis, int attribute,
		 int *value_return)
{
    __GLXdisplayPrivate *priv;
    __GLXscreenConfigs *psc;
    int   status;

    status = GetGLXPrivScreenConfig( dpy, vis->screen, & priv, & psc );
    if ( status == Success ) {
	unsigned  i;

	/* Lookup attribute after first finding a match on the visual */
	for ( i = 0 ; i < psc->numConfigs ; i++ ) {
	    if (psc->configs[i].visualID == vis->visualid) {
		return _gl_get_context_mode_data( & psc->configs[i], 
						  attribute,
						  value_return );
	    }
	}
	
	status = GLX_BAD_VISUAL;
    }

    /*
    ** If we can't find the config for this visual, this visual is not
    ** supported by the OpenGL implementation on the server.
    */
    if ( (status == GLX_BAD_VISUAL) && (attribute == GLX_USE_GL) ) {
	*value_return = GL_FALSE;
	status = Success;
    }

    return status;
}

/************************************************************************/

#define MATCH_DONT_CARE( param ) \
	do { \
	    if ( (a-> param != GLX_DONT_CARE) \
		 && (a-> param != b-> param) ) { \
		return False; \
	    } \
	} while ( 0 )

#define MATCH_MINIMUM( param ) \
	do { \
	    if ( (a-> param != GLX_DONT_CARE) \
		 && (a-> param > b-> param) ) { \
		return False; \
	    } \
	} while ( 0 )

#define MATCH_EXACT( param ) \
	do { \
	    if ( a-> param != b-> param) { \
		return False; \
	    } \
	} while ( 0 )

/* According to the manual here: 
 http://www.opengl.org/sdk/docs/man/xhtml/glXChooseVisual.xml
*/
/* Colors may be 0 to request the smallest color size. */
/* Colors that are > 0 request >= visual->colorSize. */
#define MATCH_COLOR(param) do { \
	if(0 == a->param || GLX_DONT_CARE == a->param) { \
	    /* Accept b whatever it is. */ \
	} else if(b->param < a->param) { \
	    /* The user's specified value is greater than this \
	     * server (b) visual. \
	     */		  \
	    return False; \
	} \
    } while(0)
 

/**
 * Determine if two GLXFBConfigs are compatible.
 *
 * \param a  Application specified config to test.
 * \param b  Server specified config to test against \c a.
 */
static Bool
fbconfigs_compatible( const __GLcontextModes * const a,
		      const __GLcontextModes * const b )
{

#ifdef DEBUG
    printf("app config doubleBufferMode %d\n", a->doubleBufferMode);
    printf("server specified config doubleBufferMode %d\n",
	   b->doubleBufferMode);

    printf("samples\tapp %d\tserver %d\n", a->samples, b->samples);
    printf("sampleBuffers\tapp %d\tserver %d\n", a->sampleBuffers, 
	   b->sampleBuffers);
#endif

    if(a->doubleBufferMode != b->doubleBufferMode) {
	return False;
    }

    MATCH_DONT_CARE( visualType );
    MATCH_DONT_CARE( visualRating );
    MATCH_DONT_CARE( xRenderable );
    MATCH_DONT_CARE( fbconfigID );
    MATCH_DONT_CARE( swapMethod );

    /*
     * The GLX_BUFFER_SIZE (rgbBits) should only be used if the application
     * has not requested GLX_RGBA when choosing a visual, thus a color indexed
     * mode.
     */
    if(a->renderType == GLX_COLOR_INDEX_BIT) {
	MATCH_MINIMUM( rgbBits );
    }

    /* 
     * Try to find an AUX buffer request at least equal to the request.
     */
    if(GLX_DONT_CARE == a->numAuxBuffers) {
	/* We don't care how many aux buffers the visual has. */
    } else if(a->numAuxBuffers > b->numAuxBuffers) {
	/* 
	 * The program/user requested more aux buffers -- try to  
	 * honor that request.
	 */
	return False;
    }
    
    MATCH_COLOR(redBits);
    MATCH_COLOR(greenBits);
    MATCH_COLOR(blueBits);
    MATCH_COLOR(alphaBits);

    MATCH_MINIMUM( depthBits );
    MATCH_MINIMUM( stencilBits );
    MATCH_MINIMUM( accumRedBits );
    MATCH_MINIMUM( accumGreenBits );
    MATCH_MINIMUM( accumBlueBits );
    MATCH_MINIMUM( accumAlphaBits );
    MATCH_MINIMUM( sampleBuffers );
    MATCH_MINIMUM( maxPbufferWidth );
    MATCH_MINIMUM( maxPbufferHeight );
    MATCH_MINIMUM( maxPbufferPixels );
    MATCH_MINIMUM( samples );

    if(a->stereoMode != b->stereoMode)
	return False;

    MATCH_EXACT( level );

    if ( ((a->drawableType & b->drawableType) == 0)
	 || ((a->renderType & b->renderType) == 0) ) {
	return False;
    }


    /* There is a bug in a few of the XFree86 DDX drivers.  They contain
     * visuals with a "transparent type" of 0 when they really mean GLX_NONE.
     * Technically speaking, it is a bug in the DDX driver, but there is
     * enough of an installed base to work around the problem here.  In any
     * case, 0 is not a valid value of the transparent type, so we'll treat 0 
     * from the app as GLX_DONT_CARE. We'll consider GLX_NONE from the app and
     * 0 from the server to be a match to maintain backward compatibility with
     * the (broken) drivers.
     */

    /* gstaplin: We don't support transparent pixels yet, and may never.  
     * I haven't been able to find CGL support for such things.
     */
     
#if 0
    if ( a->transparentPixel != GLX_DONT_CARE
         && a->transparentPixel != 0 ) {
        if ( a->transparentPixel == GLX_NONE ) {
            if ( b->transparentPixel != GLX_NONE && b->transparentPixel != 0 )
                return False;
        } else {
            MATCH_EXACT( transparentPixel );
        }

	switch ( a->transparentPixel ) {
	  case GLX_TRANSPARENT_RGB:
	    MATCH_DONT_CARE( transparentRed );
	    MATCH_DONT_CARE( transparentGreen );
	    MATCH_DONT_CARE( transparentBlue );
	    MATCH_DONT_CARE( transparentAlpha );
	    break;

	  case GLX_TRANSPARENT_INDEX:
	    MATCH_DONT_CARE( transparentIndex );
	    break;

	  default:
	    break;
	}
    }
#endif

#ifdef DEBUG
    puts("compatible");
#endif
   
    return True;
}


#define PREFER_LARGER(comp) \
    do { \
	if ( ((*a)-> comp) != ((*b)-> comp) ) { \
	    return ((*b)-> comp) - ((*a)-> comp) ; \
	} \
    } while( 0 )

#define PREFER_SMALLER(comp) \
    do { \
	if ( ((*a)-> comp) != ((*b)-> comp) ) { \
	    return ((*a)-> comp) - ((*b)-> comp) ; \
	} \
    } while( 0 )

/**
 * Compare two GLXFBConfigs.  This function is intended to be used as the
 * compare function passed in to qsort.
 * 
 * \returns If \c a is a "better" config, according to the specification of
 *          SGIX_fbconfig, a number less than zero is returned.  If \c b is
 *          better, then a number greater than zero is return.  If both are
 *          equal, zero is returned.
 * \sa qsort, glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX
 */

/*
 * a is a configuration that is based on the req.
 * b is a visual config.
 * req is the actual request.
 */
static int
visual_mode_compare( const __GLcontextModes * const * const a,
		  const __GLcontextModes * const * const b, 
		  const __GLcontextModes * const req)
{
    /* The order of these comparisons must NOT change.  It is defined by
     * SGIX_fbconfig, SGIX_pbuffer, and ARB_multisample.
     */

    //PREFER_SMALLER( visualSelectGroup );

#ifdef DEBUG
    printf("%p (*a)->visualRating fast? %s\n", 
	   (void *)*a, ((*a)->visualRating == GLX_NONE) ? "yes" : "no");
    printf("%p (*b)->visualRating fast? %s\n", 
	   (void *)*b, ((*b)->visualRating == GLX_NONE) ? "yes": "no");
#endif

    if(GLX_NONE == (*a)->visualRating && GLX_NONE == (*b)->visualRating) {
	/* They are a good match -- continue. */
    } else if(GLX_SLOW_VISUAL_EXT == (*a)->visualRating
	      && GLX_SLOW_VISUAL_EXT == (*b)->visualRating) {
	/* They are the same -- slow. */
    } else if((*b)->visualRating != GLX_SLOW_VISUAL_EXT) {
	/* Choose b, because it should be faster. */
	return 1;
    } else if((*a)->visualRating != GLX_SLOW_VISUAL_EXT) {
	/* Choose a, because it should be faster. */
	return -1;
    }

    //PREFER_SMALLER( rgbBits );

#ifdef DEBUG
    printf("req->doubleBufferMode %d\n", req->doubleBufferMode);
#endif
    /*
     * The fbconfigs_compatible() above should only indicate the visuals
     * a or b are compatible if they have the exact same stereoMode.
     *
     * Use !! to make sure we are comparing boolean values.
     */
    assert(!!req->stereoMode == !!(*a)->stereoMode);
    assert(!!req->stereoMode == !!(*b)->stereoMode);

    if ( ((*a)->doubleBufferMode != (*b)->doubleBufferMode) ) {
	/* Prefer single-buffer.
	 */
	return ( !(*a)->doubleBufferMode ) ? -1 : 1;
    }

    /*
     * This is bound by fbconfig_compatible (above).
     * The behavior is such that we try to find the lowest numAuxBuffers
     * that is not less than 0 or the request.
     */
    PREFER_SMALLER( numAuxBuffers );

    /* 
     * According to the OpenGL.org/GLX documentation:
     * When the value is 0 in the request we should try to
     * prefer the smallest value.  Otherwise try to find 
     * the >= value.  We do this for the RGBA bits.
     */

#define HANDLE_COLOR(typeBits) do { \
	if(0 == req->typeBits) { \
	    PREFER_SMALLER(typeBits); \
	} else if((*a)->typeBits != (*b)->typeBits) { \
	    int adelta = (*a)->typeBits - req->typeBits; \
	    int bdelta = (*b)->typeBits - req->typeBits; \
	    if(adelta > bdelta) { \
		/* Choose a */ \
		return -1; \
	    } else { \
		/* Choose b */ \
		return 1; \
	    } \
	} \
} while(0)

#ifdef DEBUG
    puts("handling colors");
#endif

    HANDLE_COLOR(redBits);
    HANDLE_COLOR(greenBits);
    HANDLE_COLOR(blueBits);
    HANDLE_COLOR(alphaBits);

#undef HANDLE_COLOR    
    /*
     * If the stencil size is 0, visuals with no stencil are preferred.
     * Otherwise the stencilSize should be > 0 and the smallest that is
     * >= req->stencilBits is preferred.
     */

    if(GLX_DONT_CARE == req->stencilBits) {
	/* Accept anything. */
    } else if(0 == req->stencilBits) {
	PREFER_SMALLER(stencilBits);
    } else if((*a)->stencilBits != (*b)->stencilBits) {
	if (((*b)->stencilBits >= req->stencilBits)
	    && ((*a)->stencilBits < req->stencilBits)) {
	    return /* Choose the b config.*/ 1;
	} else {
	    /* choose a */
	    return -1;
	}
    }

#define HANDLE_ACCUM(typeBits) do { \
	if(GLX_DONT_CARE ==  req->typeBits) { \
	    /* Accept anything. */ \
	} else if(0 == req->typeBits) { \
	    PREFER_SMALLER(typeBits); \
	} else if((*a)->typeBits != (*b)->typeBits) { \
	    if((*a)->typeBits < req->typeBits) { \
		PREFER_LARGER(typeBits); \
	    } else { \
		PREFER_SMALLER(typeBits); \
	    } \
	} \
    } while(0)
    
    /* 
     * If the accum size requested is 0 then try to find the smallest. 
     * If accum is > 0 then try to find an accum >= the request.
     */

    HANDLE_ACCUM(accumRedBits);
    HANDLE_ACCUM(accumGreenBits);
    HANDLE_ACCUM(accumBlueBits);
    HANDLE_ACCUM(accumAlphaBits);

#undef HANDLE_ACCUM

    PREFER_SMALLER( sampleBuffers );
    PREFER_SMALLER( samples );

    PREFER_LARGER( maxPbufferWidth );
    PREFER_LARGER( maxPbufferHeight );
    PREFER_LARGER( maxPbufferPixels );

    PREFER_LARGER( drawableType );
    PREFER_LARGER( renderType );
   
    return 0;
}

static int
fbconfig_compare(const void *aptr, const void *bptr) {
    const __GLcontextModes * const * const a = aptr;
    const __GLcontextModes * const * const b = bptr;

  /* The order of these comparisons must NOT change.  It is defined by
     * SGIX_fbconfig, SGIX_pbuffer, and ARB_multisample.
     */

    //PREFER_SMALLER( visualSelectGroup );

    if(GLX_NONE == (*a)->visualRating && GLX_NONE == (*b)->visualRating) {
	/* They are a good match -- continue. */
    } else if(GLX_SLOW_VISUAL_EXT == (*a)->visualRating
	      && GLX_SLOW_VISUAL_EXT == (*b)->visualRating) {
	/* They are the same -- slow. */
    } else if((*b)->visualRating != GLX_SLOW_VISUAL_EXT) {
	/* Choose b, because it should be faster. */
	return 1;
    } else if((*a)->visualRating != GLX_SLOW_VISUAL_EXT) {
	/* Choose a, because it should be faster. */
	return -1;
    }

    PREFER_SMALLER( rgbBits );

#ifdef DEBUG
    printf("req->doubleBufferMode %d\n", req->doubleBufferMode);
#endif

    if ( ((*a)->doubleBufferMode != (*b)->doubleBufferMode) ) {
	/* Prefer single-buffer.
	 */
	return ( !(*a)->doubleBufferMode ) ? -1 : 1;
    }

    PREFER_SMALLER( numAuxBuffers );

    PREFER_LARGER( redBits );
    PREFER_LARGER( greenBits );
    PREFER_LARGER( blueBits );
    PREFER_LARGER( alphaBits );
    PREFER_LARGER( stencilBits );
    PREFER_LARGER( accumRedBits );
    PREFER_LARGER( accumGreenBits );
    PREFER_LARGER( accumBlueBits );
    PREFER_LARGER( accumAlphaBits );

    PREFER_SMALLER( sampleBuffers );
    PREFER_SMALLER( samples );

    PREFER_LARGER( maxPbufferWidth );
    PREFER_LARGER( maxPbufferHeight );
    PREFER_LARGER( maxPbufferPixels );

    PREFER_LARGER( drawableType );
    PREFER_LARGER( renderType );
   
    return 0;
}


/**
 * Selects and sorts a subset of the supplied configs based on the attributes.
 * This function forms to basis of \c glXChooseVisual, \c glXChooseFBConfig,
 * and \c glXChooseFBConfigSGIX.
 * 
 * \param configs   Array of pointers to possible configs.  The elements of
 *                  this array that do not meet the criteria will be set to
 *                  NULL.  The remaining elements will be sorted according to
 *                  the various visual / FBConfig selection rules.
 * \param num_configs  Number of elements in the \c configs array.
 * \param attribList   Attributes used select from \c configs.  This array is
 *                     terminated by a \c None tag.  The array can either take
 *                     the form expected by \c glXChooseVisual (where boolean
 *                     tags do not have a value) or by \c glXChooseFBConfig
 *                     (where every tag has a value).
 * \param fbconfig_style_tags  Selects whether \c attribList is in
 *                             \c glXChooseVisual style or
 *                             \c glXChooseFBConfig style.
 * \returns The number of valid elements left in \c configs.
 * 
 * \sa glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX
 */
static int
choose_visual( __GLcontextModes ** configs, int num_configs,
	       const int *attribList, GLboolean fbconfig_style_tags )
{
    __GLcontextModes    test_config;
    int   base;
    int   i;

    /* This is a fairly direct implementation of the selection method
     * described by GLX_SGIX_fbconfig.  Start by culling out all the
     * configs that are not compatible with the selected parameter
     * list.
     */

    __glXInitializeVisualConfigFromTags( & test_config, 512, 
					 (const INT32 *) attribList,
					 GL_TRUE, fbconfig_style_tags );

    base = 0;
    for ( i = 0 ; i < num_configs ; i++ ) {
	if ( fbconfigs_compatible( & test_config, configs[i] ) ) {
	    configs[ base ] = configs[ i ];
	    base++;
	}
    }

    if ( base == 0 ) {
	return 0;
    }
 
    if ( base < num_configs ) {
	(void) memset( & configs[ base ], 0, 
		       sizeof( void * ) * (num_configs - base) );
    }

    /* After the incompatible configs are removed, the resulting
     * list is sorted according to the rules set out in the various
     * specifications.
     */
    
    qsort( configs, base, sizeof( __GLcontextModes * ),
	   (int (*)(const void*, const void*)) fbconfig_compare );
    return base;
}




/*
** Return the visual that best matches the template.  Return None if no
** visual matches the template.
*/
XVisualInfo *GLX_PREFIX(glXChooseVisual)(Display *dpy, int screen, int *attribList)
{
    XVisualInfo visualTemplate;
    XVisualInfo *visualList;
    __GLXdisplayPrivate *priv;
    __GLXscreenConfigs *psc;
    __GLcontextModes test_config;
    const __GLcontextModes *best_config = NULL;
    int i;
 
    /*
    ** Get a list of all visuals, return if list is empty
    */
    if ( GetGLXPrivScreenConfig( dpy, screen, & priv, & psc ) != Success ) {
	return NULL;
    }

#if 0
    i = 0;
    do {
	switch(attribList[i++]) {
	case GLX_RGBA:
	    break;
	case GLX_RED_SIZE:
	    printf("R bits %d\n", attribList[i]);
	    ++i;
	    break;
	case GLX_GREEN_SIZE:
	    printf("G bits %d\n", attribList[i]);
	    ++i;
	    break;
	case GLX_BLUE_SIZE:
	    printf("B bits %d\n", attribList[i]);
	    ++i;
	    break;
	case GLX_ALPHA_SIZE:
	    printf("alpha bits %d\n", attribList[i]);
	    ++i;
	    break;
	default:
	    ++i;
	}
    } while(attribList[i] != None);
#endif
 
    /*
    ** Build a template from the defaults and the attribute list
    ** Free visual list and return if an unexpected token is encountered
    */
    __glXInitializeVisualConfigFromTags(&test_config, 512,
					 (const INT32 *) attribList,
					 /*tagged only*/ GL_TRUE,
					 /*fbconfig style tags*/ GL_FALSE);

#ifdef DEBUG
    printf("test_config.doubleBufferMode %d\n", test_config.doubleBufferMode);
#endif

    /*
    ** Eliminate visuals that don't meet minimum requirements
    ** Compute a score for those that do
    ** Remember which visual, if any, got the highest score
    */
    for (i = 0; i < psc->numConfigs; i++) {
#ifdef DEBUG
	printf("%s is test_config compatible with server visualID: %x?  ",
	       __func__, psc->configs[i].visualID);
#endif

	if (fbconfigs_compatible( &test_config, &psc->configs[i] ) ) {
#ifdef DEBUG
	    puts("yes.");
#endif
	    const __GLcontextModes * const temp = &psc->configs[i];
	    
	    if(NULL == best_config) {
		best_config = temp;
	    } else {
#ifdef DEBUG
		printf("%s temp->visualID %x\n", __func__, temp->visualID);
#endif
		int cmp = visual_mode_compare( &temp, &best_config, &test_config);
	
#ifdef DEBUG
		printf("%s cmp %d\n", __func__, cmp);
#endif
		if (cmp < 0) {
#ifdef DEBUG
		    printf("%s new best_config visualID %x\n", __func__,
			   psc->configs[i].visualID);
#endif

		    /* The current best_config is less of a match than temp. */
		    best_config = &psc->configs[i];
		}
	    }
	} else {
#ifdef DEBUG
	    puts("no.");
#endif
	}
    }

    /*
    ** If no visual is acceptable, return NULL (as per the documentation).
    ** Otherwise, create an XVisualInfo list with just the selected X visual
    **   and return this after freeing the original list
    */
    visualList = NULL;
    if (best_config != NULL) {
	visualTemplate.screen = screen;
	visualTemplate.visualid = best_config->visualID;
	
#ifdef DEBUG
	printf("best_config->visualID %x\n", best_config->visualID);
#endif

	visualList = XGetVisualInfo( dpy, VisualScreenMask|VisualIDMask,
				     &visualTemplate, &i );
    }

    if(visualList && getenv("LIBGL_DUMP_VISUAL_ID")) {
	printf("visualid %lx\n", visualList[0].visualid);
    }

    return visualList;
}

/*
** Query the Server GLX string and cache it in the display private.
** This routine will allocate the necessay space for the string.
*/
char *__glXInternalQueryServerString( Display *dpy, int opcode,
				      int screen, int name )
{
    xGLXQueryServerStringReq *req;
    xGLXQueryServerStringReply reply;
    int length, numbytes, slop;
    char *buf;

    /* Send the glXQueryServerString request */
    LockDisplay(dpy);
    GetReq(GLXQueryServerString,req);
    req->reqType = opcode;
    req->glxCode = X_GLXQueryServerString;
    req->screen = screen;
    req->name = name;
    _XReply(dpy, (xReply*) &reply, 0, False);

    length = reply.length;
    numbytes = reply.n;
    slop = numbytes * __GLX_SIZE_INT8 & 3;
    buf = (char *)Xmalloc(numbytes);
    if (!buf) {
        /* Throw data on the floor */
        _XEatData(dpy, length);
    } else {
        _XRead(dpy, (char *)buf, numbytes);
        if (slop) _XEatData(dpy,4-slop);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return buf;
}

#define SEPARATOR " "

char *__glXCombineExtensionStrings( const char *cext_string, const char *sext_string )
{
   int clen, slen;
   char *combo_string, *token, *s1;
   const char *s2, *end;

   /*
   ** String can't be longer than min(cstring, sstring)
   ** pull tokens out of shortest string
   ** include space in combo_string for final separator and null terminator
   */
   if ( (clen = strlen( cext_string)) > (slen = strlen( sext_string)) ) {
        combo_string = (char *) Xmalloc( slen + 2 );
	s1 = (char *) Xmalloc( slen + 2 ); strcpy( s1, sext_string );
        s2 = cext_string;
   } else {
        combo_string = (char *) Xmalloc( clen + 2 );
	s1 = (char *) Xmalloc( clen + 2 ); strcpy( s1, cext_string);
        s2 = sext_string;
   }
   if (!combo_string || !s1) {
	if (combo_string) Xfree(combo_string);
	if (s1) Xfree(s1);
        return NULL;
   }
   combo_string[0] = '\0';

   /* Get first extension token */
   token = strtok( s1, SEPARATOR);
   while ( token != NULL ) {

	/*
	** if token in second string then save it
	** beware of extension names which are prefixes of other extension names
	*/
	const char *p = s2;
	end = p + strlen(p);
	while (p < end) {
	    int n = strcspn(p, SEPARATOR);
	    if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) {
		combo_string = strcat( combo_string, token);
		combo_string = strcat( combo_string, SEPARATOR);
	    }
	    p += (n + 1);
	}

        /* Get next extension token */
        token = strtok( NULL, SEPARATOR);
   }
   Xfree(s1);
   return combo_string;
}

const char *GLX_PREFIX(glXQueryExtensionsString)( Display *dpy, int screen )
{
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;

    if ( GetGLXPrivScreenConfig( dpy, screen, & priv, & psc ) != Success ) {
	return NULL;
    }

    if (!psc->effectiveGLXexts) {
        if (!psc->serverGLXexts) {
	    psc->serverGLXexts = __glXInternalQueryServerString(dpy, priv->majorOpcode,
					  	   screen, GLX_EXTENSIONS);
	}

	__glXCalculateUsableExtensions(psc,
#ifdef GLX_DIRECT_RENDERING
				       (priv->driDisplay.private != NULL),
#else
				       GL_FALSE,
#endif
				       priv->minorVersion);
    }

    return psc->effectiveGLXexts;
}

const char *GLX_PREFIX(glXGetClientString)( Display *dpy, int name )
{
    switch(name) {
	case GLX_VENDOR:
	    return (__glXGLXClientVendorName);
	case GLX_VERSION:
	    return (__glXGLXClientVersion);
	case GLX_EXTENSIONS:
	    return (__glXGetClientExtensions());
	default:
	    return NULL;
    }
}

const char *GLX_PREFIX(glXQueryServerString)( Display *dpy, int screen, int name )
{
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;


    if ( GetGLXPrivScreenConfig( dpy, screen, & priv, & psc ) != Success ) {
	return NULL;
    }

    switch(name) {
	case GLX_VENDOR:
	    if (!priv->serverGLXvendor) {
	 	priv->serverGLXvendor = 
			__glXInternalQueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_VENDOR);
	    }
	    return(priv->serverGLXvendor);
	case GLX_VERSION:
	    if (!priv->serverGLXversion) {
	 	priv->serverGLXversion = 
			__glXInternalQueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_VERSION);
	    }
	    return(priv->serverGLXversion);
	case GLX_EXTENSIONS:
	    if (!psc->serverGLXexts) {
	 	psc->serverGLXexts = 
			__glXInternalQueryServerString(dpy, priv->majorOpcode,
					  screen, GLX_EXTENSIONS);
	    }
	    return(psc->serverGLXexts);
	default:
	    return NULL;
    }
}

void __glXClientInfo (  Display *dpy, int opcode  )
{
    xGLXClientInfoReq *req;
    int size;

    /* Send the glXClientInfo request */
    LockDisplay(dpy);
    GetReq(GLXClientInfo,req);
    req->reqType = opcode;
    req->glxCode = X_GLXClientInfo;
    req->major = GLX_MAJOR_VERSION;
    req->minor = GLX_MINOR_VERSION;

    size = strlen(__glXGLClientExtensions) + 1;
    req->length += (size + 3) >> 2;
    req->numbytes = size;
    Data(dpy, __glXGLClientExtensions, size);

    UnlockDisplay(dpy);
    SyncHandle();
}


/*
** EXT_import_context
*/

Display *glXGetCurrentDisplay(void)
{
    GLXContext gc = __glXGetCurrentContext();
    if (NULL == gc) return NULL;
    return gc->currentDpy;
}

GLX_ALIAS(Display *, glXGetCurrentDisplayEXT, (void), (),
	  glXGetCurrentDisplay)

static int __glXQueryContextInfo(Display *dpy, GLXContext ctx)
{
    xGLXVendorPrivateReq *vpreq;
    xGLXQueryContextInfoEXTReq *req;
    xGLXQueryContextInfoEXTReply reply;
    CARD8 opcode;
    GLuint numValues;
    int retval;

    if (ctx == NULL) {
	return GLX_BAD_CONTEXT;
    }
    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return 0;
    }

    /* Send the glXQueryContextInfoEXT request */
    LockDisplay(dpy);
    GetReqExtra(GLXVendorPrivate,
	sz_xGLXQueryContextInfoEXTReq-sz_xGLXVendorPrivateReq,vpreq);
    req = (xGLXQueryContextInfoEXTReq *)vpreq;
    req->reqType = opcode;
    req->glxCode = X_GLXVendorPrivateWithReply;
    req->vendorCode = X_GLXvop_QueryContextInfoEXT;
    req->context = (unsigned int)(ctx->xid);
    _XReply(dpy, (xReply*) &reply, 0, False);

    numValues = reply.n;
    if (numValues == 0)
	retval = Success;
    else if (numValues > __GLX_MAX_CONTEXT_PROPS)
	retval = 0;
    else
    {
	int *propList, *pProp;
	int nPropListBytes;
	int i;

	nPropListBytes = numValues << 3;
	propList = (int *) Xmalloc(nPropListBytes);
	if (NULL == propList) {
	    retval = 0;
	} else {
	    _XRead(dpy, (char *)propList, nPropListBytes);
	    pProp = propList;
	    for (i=0; i < numValues; i++) {
		switch (*pProp++) {
		case GLX_SHARE_CONTEXT_EXT:
		    ctx->share_xid = *pProp++;
		    break;
		case GLX_VISUAL_ID_EXT:
		    ctx->vid = *pProp++;
		    break;
		case GLX_SCREEN_EXT:
		    ctx->screen = *pProp++;
		    break;
		case GLX_FBCONFIG_ID_SGIX:
		    ctx->fbconfigID = *pProp++;
		    break;
		default:
		    pProp++;
		    continue;
		}
	    }
	    Xfree((char *)propList);
	    retval = Success;
	}
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return retval;
}

int GLX_PREFIX(glXQueryContextInfoEXT)(Display *dpy, GLXContext ctx, 
				int attribute, int *value)
{
    int retVal;

    /* get the information from the server if we don't have it already */
    if (!ctx->isDirect && (ctx->vid == None)) {
	retVal = __glXQueryContextInfo(dpy, ctx);
	if (Success != retVal) return retVal;
    }
    switch (attribute) {
    case GLX_SHARE_CONTEXT_EXT:
	*value = (int)(ctx->share_xid);
	break;
    case GLX_VISUAL_ID_EXT:
	*value = (int)(ctx->vid);
	break;
    case GLX_SCREEN_EXT:
	*value = (int)(ctx->screen);
	break;
    case GLX_FBCONFIG_ID_SGIX:
	*value = (int)(ctx->fbconfigID);
	break;
    default:
	return GLX_BAD_ATTRIBUTE;
    }
    return Success;
}

GLXContextID glXGetContextIDEXT(const GLXContext ctx)
{
    return ctx->xid;
}

GLXContext GLX_PREFIX(glXImportContextEXT)(Display *dpy, GLXContextID contextID)
{
    GLXContext ctx;

    if (contextID == None) {
	return NULL;
    }
    if (__glXIsDirect(dpy, contextID)) {
	return NULL;
    }

    ctx = CreateContext(dpy, NULL, NULL, NULL, False, contextID, False, 0);
    if (NULL != ctx) {
	if (Success != __glXQueryContextInfo(dpy, ctx)) {
	   return NULL;
	}
    }
    return ctx;
}

void GLX_PREFIX(glXFreeContextEXT)(Display *dpy, GLXContext ctx)
{
    DestroyContext(dpy, ctx);
}



/*
 * GLX 1.3 functions - these are just stubs for now!
 */

GLXFBConfig *GLX_PREFIX(glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems)
{
    __GLcontextModes ** config_list;
    int   list_size;


    config_list = (__GLcontextModes **) 
	GLX_PREFIX(glXGetFBConfigs)( dpy, screen, & list_size );

    if ( (config_list != NULL) && (list_size > 0) ) {
	list_size = choose_visual( config_list, list_size, attribList,
				   GL_TRUE );
	if ( list_size == 0 ) {
	    XFree( config_list );
	    config_list = NULL;
	}
    }

    *nitems = list_size;
    return (GLXFBConfig *) config_list;
}


GLXContext GLX_PREFIX(glXCreateNewContext)(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool allowDirect)
{
    return CreateContext( dpy, NULL, (__GLcontextModes *) config, shareList,
			  allowDirect, None, True, renderType );
}


GLXPbuffer GLX_PREFIX(glXCreatePbuffer)(Display *dpy, GLXFBConfig config, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) attribList;
    return 0;
}


GLXPixmap GLX_PREFIX(glXCreatePixmap)(Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) pixmap;
    (void) attribList;
    return 0;
}


GLXWindow GLX_PREFIX(glXCreateWindow)(Display *dpy, GLXFBConfig config, Window win, const int *attribList)
{
    (void) dpy;
    (void) config;
    (void) win;
    (void) attribList;
    return 0;
}


void GLX_PREFIX(glXDestroyPbuffer)(Display *dpy, GLXPbuffer pbuf)
{
    (void) dpy;
    (void) pbuf;
}


void GLX_PREFIX(glXDestroyPixmap)(Display *dpy, GLXPixmap pixmap)
{
    (void) dpy;
    (void) pixmap;
}


void GLX_PREFIX(glXDestroyWindow)(Display *dpy, GLXWindow window)
{
    (void) dpy;
    (void) window;
}


GLXDrawable GLX_PREFIX(glXGetCurrentReadDrawable)(void)
{
    GLXContext gc = __glXGetCurrentContext();
    return gc->currentReadable;
}


GLXFBConfig *GLX_PREFIX(glXGetFBConfigs)(Display *dpy, int screen, int *nelements)
{
    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
    __GLcontextModes ** config = NULL;
    int   i;

    if ( (priv->screenConfigs != NULL)
	 && (screen >= 0) && (screen <= ScreenCount(dpy))
	 && (priv->screenConfigs[screen].numConfigs > 0)
	 && (priv->screenConfigs[screen].configs->fbconfigID != ((XID)-1)) ) {
	config = (__GLcontextModes **) Xmalloc( sizeof(__GLcontextModes *)
				 * priv->screenConfigs[screen].numConfigs );
	if ( config != NULL ) {
	    *nelements = priv->screenConfigs[screen].numConfigs;
	    for ( i = 0 ; i < *nelements ; i++ ) {
		config[i] = & priv->screenConfigs[screen].configs[i];
	    }
	}
    }
    return (GLXFBConfig *) config;
}


int GLX_PREFIX(glXGetFBConfigAttrib)(Display *dpy, GLXFBConfig config, int attribute, int *value)
{
    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
    __GLcontextModes * fbconfig = (__GLcontextModes *) config;
    const int screen_count = ScreenCount(dpy);
    int  i;


    if ( priv->screenConfigs != NULL ) {
	for ( i = 0 ; i < screen_count ; i++ ) {
	    const int numConfigs = priv->screenConfigs[i].numConfigs;
	    if ( ( numConfigs > 0)
		 && (priv->screenConfigs[i].configs->fbconfigID != ((XID)-1))
		 && (fbconfig >= & priv->screenConfigs[i].configs[0])
		 && (fbconfig < & priv->screenConfigs[i].configs[numConfigs]) ) {
		return _gl_get_context_mode_data(fbconfig, attribute, value);
	    }
	}
    }

    return GLXBadFBConfig;
}


void GLX_PREFIX(glXGetSelectedEvent)(Display *dpy, GLXDrawable drawable, unsigned long *mask)
{
    (void) dpy;
    (void) drawable;
    (void) mask;
}


XVisualInfo *GLX_PREFIX(glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config)
{
    XVisualInfo visualTemplate;
    __GLcontextModes * fbconfig = (__GLcontextModes *) config;
    int  count;

    /*
    ** Get a list of all visuals, return if list is empty
    */
    visualTemplate.visualid = fbconfig->visualID;
    return XGetVisualInfo(dpy,VisualIDMask,&visualTemplate,&count);
}


int GLX_PREFIX(glXQueryContext)(Display *dpy, GLXContext ctx, int attribute, int *value)
{
    (void) dpy;
    (void) ctx;
    (void) attribute;
    (void) value;
    return 0;
}


void GLX_PREFIX(glXQueryDrawable)(Display *dpy, GLXDrawable draw, int attribute, unsigned int *value)
{
    (void) dpy;
    (void) draw;
    (void) attribute;
    (void) value;
}


void GLX_PREFIX(glXSelectEvent)(Display *dpy, GLXDrawable drawable, unsigned long mask)
{
    (void) dpy;
    (void) drawable;
    (void) mask;
}


/*
** GLX_SGI_make_current_read
*/

GLX_ALIAS(GLXDrawable, glXGetCurrentReadDrawableSGI, (void), (),
	  glXGetCurrentReadDrawable)


/*
** GLX_SGI_swap_control
*/
int GLX_PREFIX(glXSwapIntervalSGI)(int interval)
{
   xGLXVendorPrivateReq *req;
   GLXContext gc = __glXGetCurrentContext();
   Display * dpy;
   CARD32 * interval_ptr;
   CARD8 opcode;

   if ( gc == NULL ) {
      return GLX_BAD_CONTEXT;
   }
   
   if ( interval <= 0 ) {
      return GLX_BAD_VALUE;
   }

#ifdef GLX_DIRECT_RENDERING
   if ( gc->isDirect ) {
       __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy,
							     gc->screen );
       __DRIdrawable * const pdraw = GetDRIDrawable( gc->currentDpy,
						     gc->currentDrawable,
						     NULL );
       if ( __glXExtensionBitIsEnabled( psc, SGI_swap_control_bit )
	    && (pdraw != NULL) ) {
	   pdraw->swap_interval = interval;
	   return 0;
       }
       else {
	   return GLX_BAD_CONTEXT;
       }
   }
#endif
   dpy = gc->currentDpy;
   opcode = __glXSetupForCommand(dpy);
   if (!opcode) {
      return 0;
   }

   /* Send the glXSwapIntervalSGI request */
   LockDisplay(dpy);
   GetReqExtra(GLXVendorPrivate,sizeof(CARD32),req);
   req->reqType = opcode;
   req->glxCode = X_GLXVendorPrivate;
   req->vendorCode = X_GLXvop_SwapIntervalSGI;
   req->contextTag = gc->currentContextTag;

   interval_ptr = (CARD32 *) req + 1;
   *interval_ptr = interval;

   UnlockDisplay(dpy);
   SyncHandle();
   XFlush(dpy);

   return 0;
}


/*
** GLX_MESA_swap_control
*/
GLint GLX_PREFIX(glXSwapIntervalMESA)(unsigned interval)
{
#ifdef GLX_DIRECT_RENDERING
   GLXContext gc = __glXGetCurrentContext();

   if ( interval < 0 ) {
      return GLX_BAD_VALUE;
   }

   if ( (gc != NULL) && gc->isDirect ) {
      __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy,
							    gc->screen );
      
      if ( (psc != NULL) && (psc->driScreen.private != NULL)
	   && __glXExtensionBitIsEnabled( psc, MESA_swap_control_bit ) ) {
	 __DRIdrawable * const pdraw = 
	     (*psc->driScreen.getDrawable)(gc->currentDpy,
					   gc->currentDrawable,
					   psc->driScreen.private);
	 if ( pdraw != NULL ) {
	    pdraw->swap_interval = interval;
	    return 0;
	 }
      }
   }
#else
   (void) interval;
#endif

   return GLX_BAD_CONTEXT;
}
 
GLint GLX_PREFIX(glXGetSwapIntervalMESA)( void )
{
#ifdef GLX_DIRECT_RENDERING
   GLXContext gc = __glXGetCurrentContext();

   if ( (gc != NULL) && gc->isDirect ) {
      __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy,
							    gc->screen );
      
      if ( (psc != NULL) && (psc->driScreen.private != NULL)
	   && __glXExtensionBitIsEnabled( psc, MESA_swap_control_bit ) ) {
	 __DRIdrawable * const pdraw = 
	     (*psc->driScreen.getDrawable)(gc->currentDpy,
					   gc->currentDrawable,
					   psc->driScreen.private);
	 if ( pdraw != NULL ) {
	    return pdraw->swap_interval;
	 }
      }
   }
#endif

   return 0;
}


/*
** GLX_MESA_swap_frame_usage
*/

GLint GLX_PREFIX(glXBeginFrameTrackingMESA)(Display *dpy, GLXDrawable drawable)
{
   int   status = GLX_BAD_CONTEXT;
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable * const pdraw = GetDRIDrawable(dpy, drawable, & screen);
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);

   if ( (pdraw != NULL) && (pdraw->frameTracking != NULL)
	&& __glXExtensionBitIsEnabled( psc, MESA_swap_frame_usage_bit ) ) {
      status = pdraw->frameTracking( dpy, pdraw->private, GL_TRUE );
   }
#else
   (void) dpy;
   (void) drawable;
#endif
   return status;
}

    
GLint GLX_PREFIX(glXEndFrameTrackingMESA)(Display *dpy, GLXDrawable drawable)
{
   int   status = GLX_BAD_CONTEXT;
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable * const pdraw = GetDRIDrawable(dpy, drawable, & screen);
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);

   if ( (pdraw != NULL) && (pdraw->frameTracking != NULL)
	&& __glXExtensionBitIsEnabled( psc, MESA_swap_frame_usage_bit ) ) {
      status = pdraw->frameTracking( dpy, pdraw->private, GL_FALSE );
   }
#else
   (void) dpy;
   (void) drawable;
#endif
   return status;
}


GLint GLX_PREFIX(glXGetFrameUsageMESA)(Display *dpy, GLXDrawable drawable,
				       GLfloat *usage)
{
   int   status = GLX_BAD_CONTEXT;
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable * const pdraw = GetDRIDrawable(dpy, drawable, & screen);
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);

   if ( (pdraw != NULL ) && (pdraw->queryFrameTracking != NULL)
	&& __glXExtensionBitIsEnabled( psc, MESA_swap_frame_usage_bit ) ) {
      int64_t sbc, missedFrames;
      float   lastMissedUsage;

      status = pdraw->queryFrameTracking( dpy, pdraw->private, &sbc,
					  &missedFrames, &lastMissedUsage,
					  usage );
   }
#else
   (void) dpy;
   (void) drawable;
   (void) usage;
#endif
   return status;
}


GLint GLX_PREFIX(glXQueryFrameTrackingMESA)(Display *dpy, GLXDrawable drawable,
					    int64_t *sbc, int64_t *missedFrames,
					    GLfloat *lastMissedUsage)
{
   int   status = GLX_BAD_CONTEXT;
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable * const pdraw = GetDRIDrawable(dpy, drawable, & screen);
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);

   if ( (pdraw != NULL ) && (pdraw->queryFrameTracking != NULL)
	&& __glXExtensionBitIsEnabled( psc, MESA_swap_frame_usage_bit ) ) {
      float   usage;

      status = pdraw->queryFrameTracking( dpy, pdraw->private, sbc,
					  missedFrames, lastMissedUsage,
					  & usage );
   }
#else
   (void) dpy;
   (void) drawable;
   (void) sbc;
   (void) missedFrames;
   (void) lastMissedUsage;
#endif
   return status;
}


/*
** GLX_SGI_video_sync
*/
int GLX_PREFIX(glXGetVideoSyncSGI)(unsigned int *count)
{
   /* FIXME: Looking at the GLX_SGI_video_sync spec in the extension registry,
    * FIXME: there should be a GLX encoding for this call.  I can find no
    * FIXME: documentation for the GLX encoding.
    */
#ifdef GLX_DIRECT_RENDERING
   GLXContext gc = __glXGetCurrentContext();


   if ( (gc != NULL) && gc->isDirect ) {
      __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy,
							    gc->screen );
      if ( __glXExtensionBitIsEnabled( psc, SGI_video_sync_bit )
	   && psc->driScreen.private && psc->driScreen.getMSC) {
	 int       ret;
	 int64_t   temp;

	 ret = psc->driScreen.getMSC( psc->driScreen.private, & temp );
	 *count = (unsigned) temp;
	 return (ret == 0) ? 0 : GLX_BAD_CONTEXT;
      }
   }
#else
    (void) count;
#endif
   return GLX_BAD_CONTEXT;
}

int GLX_PREFIX(glXWaitVideoSyncSGI)(int divisor, int remainder, unsigned int *count)
{
#ifdef GLX_DIRECT_RENDERING
   GLXContext gc = __glXGetCurrentContext();

   if ( divisor <= 0 || remainder < 0 )
     return GLX_BAD_VALUE;

   if ( (gc != NULL) && gc->isDirect ) {
      __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy,
							    gc->screen );
      if ( __glXExtensionBitIsEnabled( psc, SGI_video_sync_bit )
	   && psc->driScreen.private ) {
	 __DRIdrawable * const pdraw = 
	     (*psc->driScreen.getDrawable)(gc->currentDpy,
					   gc->currentDrawable,
					   psc->driScreen.private);
	 if ( (pdraw != NULL) && (pdraw->waitForMSC != NULL) ) {
	    int       ret;
	    int64_t   msc;
	    int64_t   sbc;

	    ret = (*pdraw->waitForMSC)( gc->currentDpy, pdraw->private,
					0, divisor, remainder,
					& msc, & sbc );
	    *count = (unsigned) msc;
	    return (ret == 0) ? 0 : GLX_BAD_CONTEXT;
	 }
      }
   }
#else
   (void) count;
#endif
   return GLX_BAD_CONTEXT;
}


/*
** GLX_SGIS_video_source
*/
#if defined(_VL_H)

GLXVideoSourceSGIX GLX_PREFIX(glXCreateGLXVideoSourceSGIX)(Display *dpy, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode)
{
   (void) dpy;
   (void) screen;
   (void) server;
   (void) path;
   (void) nodeClass;
   (void) drainNode;
   return 0;
}

void GLX_PREFIX(glXDestroyGLXVideoSourceSGIX)(Display *dpy, GLXVideoSourceSGIX src)
{
   (void) dpy;
   (void) src;
}

#endif


/*
** GLX_SGIX_fbconfig
** Many of these functions are aliased to GLX 1.3 entry points in the 
** GLX_functions table.
*/

GLX_ALIAS(int, glXGetFBConfigAttribSGIX,
	  (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value),
	  (dpy, config, attribute, value),
	  glXGetFBConfigAttrib)

GLX_ALIAS(GLXFBConfigSGIX *, glXChooseFBConfigSGIX,
	  (Display *dpy, int screen, int *attrib_list, int *nelements),
	  (dpy, screen, attrib_list, nelements),
	  glXChooseFBConfig)

GLX_ALIAS(XVisualInfo *, glXGetVisualFromFBConfigSGIX,
	  (Display * dpy, GLXFBConfigSGIX config),
	  (dpy, config),
	  glXGetVisualFromFBConfig)

GLXPixmap GLX_PREFIX(glXCreateGLXPixmapWithConfigSGIX)(Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap)
{
    xGLXVendorPrivateReq *vpreq;
    xGLXCreateGLXPixmapWithConfigSGIXReq *req;
    GLXPixmap xid = None;
    CARD8 opcode;
    const __GLcontextModes * const fbconfig = (__GLcontextModes *) config;
    __GLXscreenConfigs * psc;


    if ( (dpy == NULL) || (config == NULL) ) {
	return None;
    }

    psc = GetGLXScreenConfigs( dpy, fbconfig->screen );
    if ( (psc != NULL) 
	 && __glXExtensionBitIsEnabled( psc, SGIX_fbconfig_bit ) ) {
	opcode = __glXSetupForCommand(dpy);
	if (!opcode) {
	    return None;
	}

	/* Send the glXCreateGLXPixmapWithConfigSGIX request */
	LockDisplay(dpy);
	GetReqExtra(GLXVendorPrivate,
		    sz_xGLXCreateGLXPixmapWithConfigSGIXReq-sz_xGLXVendorPrivateReq,vpreq);
	req = (xGLXCreateGLXPixmapWithConfigSGIXReq *)vpreq;
	req->reqType = opcode;
	req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX;
	req->screen = fbconfig->screen;
	req->fbconfig = fbconfig->fbconfigID;
	req->pixmap = pixmap;
	req->glxpixmap = xid = XAllocID(dpy);
	UnlockDisplay(dpy);
	SyncHandle();
    }

    return xid;
}

GLXContext GLX_PREFIX(glXCreateContextWithConfigSGIX)(Display *dpy, GLXFBConfigSGIX config, int renderType, GLXContext shareList, Bool allowDirect)
{
    GLXContext gc = NULL;
    const __GLcontextModes * const fbconfig = (__GLcontextModes *) config;
    __GLXscreenConfigs * psc;


    if ( (dpy == NULL) || (config == NULL) ) {
	return None;
    }

    psc = GetGLXScreenConfigs( dpy, fbconfig->screen );
    if ( (psc != NULL) 
	 && __glXExtensionBitIsEnabled( psc, SGIX_fbconfig_bit ) ) {
	gc = CreateContext( dpy, NULL, (__GLcontextModes *) config, shareList,
			    allowDirect, None, False, renderType );
    }

    return gc;
}


GLXFBConfigSGIX GLX_PREFIX(glXGetFBConfigFromVisualSGIX)(Display *dpy, XVisualInfo *vis)
{
    __GLXdisplayPrivate *priv;
    __GLXscreenConfigs *psc;
    int   i;

    if ( (GetGLXPrivScreenConfig( dpy, vis->screen, & priv, & psc ) != Success)
	 && __glXExtensionBitIsEnabled( psc, SGIX_fbconfig_bit )
	 && (psc->configs[0].fbconfigID != ((XID)-1)) ) {
	for ( i = 0 ; i < psc->numConfigs ; i++ ) {
	    if ( psc->configs[i].visualID == vis->visualid ) {
		return (GLXFBConfigSGIX) & (psc->configs[i]);
	    }
	}
    }

    return NULL;
}


/*
** GLX_SGIX_pbuffer
*/
GLXPbufferSGIX GLX_PREFIX(glXCreateGLXPbufferSGIX)(Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list)
{
   (void) dpy;
   (void) config;
   (void) width;
   (void) height;
   (void) attrib_list;
   return 0;
}

void GLX_PREFIX(glXDestroyGLXPbufferSGIX)(Display *dpy, GLXPbufferSGIX pbuf)
{
   (void) dpy;
   (void) pbuf;
}

int GLX_PREFIX(glXQueryGLXPbufferSGIX)(Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value)
{
   (void) dpy;
   (void) pbuf;
   (void) attribute;
   (void) value;
   return 0;
}

void GLX_PREFIX(glXSelectEventSGIX)(Display *dpy, GLXDrawable drawable, unsigned long mask)
{
   (void) dpy;
   (void) drawable;
   (void) mask;
}

void GLX_PREFIX(glXGetSelectedEventSGIX)(Display *dpy, GLXDrawable drawable, unsigned long *mask)
{
   (void) dpy;
   (void) drawable;
   (void) mask;
}


/*
** GLX_SGI_cushion
*/
void GLX_PREFIX(glXCushionSGI)(Display *dpy, Window win, float cushion)
{
   (void) dpy;
   (void) win;
   (void) cushion;
}


/*
** GLX_SGIX_video_resize
*/
int GLX_PREFIX(glXBindChannelToWindowSGIX)(Display *dpy, int screen, int channel , Window window)
{
   (void) dpy;
   (void) screen;
   (void) channel;
   (void) window;
   return 0;
}

int GLX_PREFIX(glXChannelRectSGIX)(Display *dpy, int screen, int channel, int x, int y, int w, int h)
{
   (void) dpy;
   (void) screen;
   (void) channel;
   (void) x;
   (void) y;
   (void) w;
   (void) h;
   return 0;
}

int GLX_PREFIX(glXQueryChannelRectSGIX)(Display *dpy, int screen, int channel, int *x, int *y, int *w, int *h)
{
   (void) dpy;
   (void) screen;
   (void) channel;
   (void) x;
   (void) y;
   (void) w;
   (void) h;
   return 0;
}

int GLX_PREFIX(glXQueryChannelDeltasSGIX)(Display *dpy, int screen, int channel, int *dx, int *dy, int *dw, int *dh)
{
   (void) dpy;
   (void) screen;
   (void) channel;
   (void) dx;
   (void) dy;
   (void) dw;
   (void) dh;
   return 0;
}

int GLX_PREFIX(glXChannelRectSyncSGIX)(Display *dpy, int screen, int channel, GLenum synctype)
{
   (void) dpy;
   (void) screen;
   (void) channel;
   (void) synctype;
   return 0;
}


#if defined(_DM_BUFFER_H_)

Bool GLX_PREFIX(glXAssociateDMPbufferSGIX)(Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer)
{
   (void) dpy;
   (void) pbuffer;
   (void) params;
   (void) dmbuffer;
   return False;
}

#endif


/*
** GLX_SGIX_swap_group
*/
void GLX_PREFIX(glXJoinSwapGroupSGIX)(Display *dpy, GLXDrawable drawable, GLXDrawable member)
{
   (void) dpy;
   (void) drawable;
   (void) member;
}


/*
** GLX_SGIX_swap_barrier
*/
void GLX_PREFIX(glXBindSwapBarrierSGIX)(Display *dpy, GLXDrawable drawable, int barrier)
{
   (void) dpy;
   (void) drawable;
   (void) barrier;
}

Bool GLX_PREFIX(glXQueryMaxSwapBarriersSGIX)(Display *dpy, int screen, int *max)
{
   (void) dpy;
   (void) screen;
   (void) max;
   return False;
}


/*
** GLX_SUN_get_transparent_index
*/
Status GLX_PREFIX(glXGetTransparentIndexSUN)(Display *dpy, Window overlay, Window underlay, long *pTransparent)
{
   (void) dpy;
   (void) overlay;
   (void) underlay;
   (void) pTransparent;
   return 0;
}


/*
** GLX_OML_sync_control
*/
Bool GLX_PREFIX(glXGetSyncValuesOML)(Display *dpy, GLXDrawable drawable,
				     int64_t *ust, int64_t *msc, int64_t *sbc)
{
#ifdef GLX_DIRECT_RENDERING
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);

    if ( priv != NULL ) {
	int   i;
	__DRIdrawable * const pdraw = GetDRIDrawable( dpy, drawable, & i );
	__GLXscreenConfigs * const psc = &priv->screenConfigs[i];

	assert( (pdraw == NULL) || (i != -1) );
	return ( (pdraw && pdraw->getSBC && psc->driScreen.getMSC)
		 && __glXExtensionBitIsEnabled( psc, OML_sync_control_bit )
		 && ((*psc->driScreen.getMSC)( psc->driScreen.private, msc ) == 0)
		 && ((*pdraw->getSBC)( dpy, psc->driScreen.private, sbc ) == 0)
		 && (__glXGetUST( ust ) == 0) );
    }
#else
   (void) dpy;
   (void) drawable;
   (void) ust;
   (void) msc;
   (void) sbc;
#endif
   return False;
}


/**
 * Determine the refresh rate of the specified drawable and display.
 * 
 * \param dpy          Display whose refresh rate is to be determined.
 * \param drawable     Drawable whose refresh rate is to be determined.
 * \param numerator    Numerator of the refresh rate.
 * \param demoninator  Denominator of the refresh rate.
 * \return  If the refresh rate for the specified display and drawable could
 *          be calculated, True is returned.  Otherwise False is returned.
 * 
 * \note This function is implemented entirely client-side.  A lot of other
 *       functionality is required to export GLX_OML_sync_control, so on
 *       XFree86 this function can be called for direct-rendering contexts
 *       when GLX_OML_sync_control appears in the client extension string.
 */

Bool GLX_PREFIX(glXGetMscRateOML)(Display * dpy, GLXDrawable drawable,
				  int32_t * numerator, int32_t * denominator)
{
#if defined( GLX_DIRECT_RENDERING ) && defined( XF86VIDMODE )
   __GLXdisplayPrivate * const priv = __glXInitialize(dpy);


   if ( priv != NULL ) {
      XF86VidModeModeLine   mode_line;
      int   dot_clock;
      int   screen_num;
      int   i;


      GetDRIDrawable( dpy, drawable, & screen_num );
      if ( (screen_num != -1)
	   && XF86VidModeQueryVersion( dpy, & i, & i )
	   && XF86VidModeGetModeLine( dpy, screen_num, & dot_clock,
				      & mode_line ) ) {
	 unsigned   n = dot_clock * 1000;
	 unsigned   d = mode_line.vtotal * mode_line.htotal;

# define V_INTERLACE 0x010
# define V_DBLSCAN   0x020

	 if ( (mode_line.flags & V_INTERLACE) ) {
	    n *= 2;
	 }
	 else if ( (mode_line.flags & V_DBLSCAN) ) {
	    d *= 2;
	 }

	 /* The OML_sync_control spec requires that if the refresh rate is a
	  * whole number, that the returned numerator be equal to the refresh
	  * rate and the denominator be 1.
	  */

	 if ( (n % d) == 0 ) {
	    n /= d;
	    d = 1;
	 }
	 else {
	    static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };


	    /* This is a poor man's way to reduce a fraction.  It's far from
	     * perfect, but it will work well enough for this situation.
	     */

	    for ( i = 0 ; f[i] != 0 ; i++ ) {
	       while ( ((n % f[i]) == 0) && ((d % f[i]) == 0) ) {
		  d /= f[i];
		  n /= f[i];
	       }
	    }
	 }

	 *numerator = n;
	 *denominator = d;

	 (void) drawable;
	 return True;
      }
   }
#else
   (void) dpy;
   (void) drawable;
   (void) numerator;
   (void) denominator;
#endif
   return False;
}


int64_t GLX_PREFIX(glXSwapBuffersMscOML)(Display *dpy, GLXDrawable drawable,
					 int64_t target_msc,
					 int64_t divisor, int64_t remainder)
{
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, & screen );
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, screen );

   /* The OML_sync_control spec says these should "generate a GLX_BAD_VALUE
    * error", but it also says "It [glXSwapBuffersMscOML] will return a value
    * of -1 if the function failed because of errors detected in the input
    * parameters"
    */
   if ( divisor < 0 || remainder < 0 || target_msc < 0 )
      return -1;
   if ( divisor > 0 && remainder >= divisor )
      return -1;

   if ( (pdraw != NULL) && (pdraw->swapBuffersMSC != NULL)
       && __glXExtensionBitIsEnabled( psc, OML_sync_control_bit ) ) {
      return (*pdraw->swapBuffersMSC)(dpy, pdraw->private, target_msc,
				      divisor, remainder);
   }
#else
   (void) dpy;
   (void) drawable;
   (void) target_msc;
   (void) divisor;
   (void) remainder;
#endif
   return 0;
}


Bool GLX_PREFIX(glXWaitForMscOML)(Display * dpy, GLXDrawable drawable,
				  int64_t target_msc,
				  int64_t divisor, int64_t remainder,
				  int64_t *ust, int64_t *msc, int64_t *sbc)
{
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, & screen );
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, screen );
   int  ret;

   /* The OML_sync_control spec says these should "generate a GLX_BAD_VALUE
    * error", but the return type in the spec is Bool.
    */
   if ( divisor < 0 || remainder < 0 || target_msc < 0 )
      return False;
   if ( divisor > 0 && remainder >= divisor )
      return False;

   if ( (pdraw != NULL) && (pdraw->waitForMSC != NULL)
	&& __glXExtensionBitIsEnabled( psc, OML_sync_control_bit ) ) {
      ret = (*pdraw->waitForMSC)( dpy, pdraw->private, target_msc,
				  divisor, remainder, msc, sbc );

      /* __glXGetUST returns zero on success and non-zero on failure.
       * This function returns True on success and False on failure.
       */
      return ( (ret == 0) && (__glXGetUST( ust ) == 0) );
   }
#else
   (void) dpy;
   (void) drawable;
   (void) target_msc;
   (void) divisor;
   (void) remainder;
   (void) ust;
   (void) msc;
   (void) sbc;
#endif
   return False;
}


Bool GLX_PREFIX(glXWaitForSbcOML)(Display * dpy, GLXDrawable drawable,
				  int64_t target_sbc,
				  int64_t *ust, int64_t *msc, int64_t *sbc )
{
#ifdef GLX_DIRECT_RENDERING
   int screen;
   __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, & screen );
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, screen );
   int  ret;

   /* The OML_sync_control spec says this should "generate a GLX_BAD_VALUE
    * error", but the return type in the spec is Bool.
    */
   if ( target_sbc < 0 )
      return False;

   if ( (pdraw != NULL) && (pdraw->waitForSBC != NULL)
	&& __glXExtensionBitIsEnabled( psc, OML_sync_control_bit )) {
      ret = (*pdraw->waitForSBC)( dpy, pdraw->private, target_sbc, msc, sbc );

      /* __glXGetUST returns zero on success and non-zero on failure.
       * This function returns True on success and False on failure.
       */
      return( (ret == 0) && (__glXGetUST( ust ) == 0) );
   }
#else
   (void) dpy;
   (void) drawable;
   (void) target_sbc;
   (void) ust;
   (void) msc;
   (void) sbc;
#endif
   return False;
}


/*
** GLX_MESA_allocate_memory
*/

void *GLX_PREFIX(glXAllocateMemoryMESA)(Display *dpy, int scrn,
					size_t size,
					float readFreq,
					float writeFreq,
					float priority)
{
#ifdef GLX_DIRECT_RENDERING
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, scrn );

   if ( __glXExtensionBitIsEnabled( psc, MESA_allocate_memory_bit ) ) {
      if (psc && psc->driScreen.private && psc->driScreen.allocateMemory) {
	 return (*psc->driScreen.allocateMemory)( dpy, scrn, size,
						  readFreq, writeFreq,
						  priority );
      }
   }
#else
   (void) dpy;
   (void) scrn;
   (void) size;
   (void) readFreq;
   (void) writeFreq;
   (void) priority;
#endif /* GLX_DIRECT_RENDERING */

   return NULL;
}


void GLX_PREFIX(glXFreeMemoryMESA)(Display *dpy, int scrn, void *pointer)
{
#ifdef GLX_DIRECT_RENDERING
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, scrn );

   if ( __glXExtensionBitIsEnabled( psc, MESA_allocate_memory_bit ) ) {
      if (psc && psc->driScreen.private && psc->driScreen.freeMemory) {
	 (*psc->driScreen.freeMemory)( dpy, scrn, pointer );
      }
   }
#else
   (void) dpy;
   (void) scrn;
   (void) pointer;
#endif /* GLX_DIRECT_RENDERING */
}


GLuint GLX_PREFIX(glXGetMemoryOffsetMESA)( Display *dpy, int scrn,
					   const void *pointer )
{
#ifdef GLX_DIRECT_RENDERING
   __GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, scrn );

   if ( __glXExtensionBitIsEnabled( psc, MESA_allocate_memory_bit ) ) {
      if (psc && psc->driScreen.private && psc->driScreen.memoryOffset) {
	 return (*psc->driScreen.memoryOffset)( dpy, scrn, pointer );
      }
   }
#else
   (void) dpy;
   (void) scrn;
   (void) pointer;
#endif /* GLX_DIRECT_RENDERING */

   return ~0L;
}


/*
** Mesa extension stubs.  These will help reduce portability problems.
*/

Bool GLX_PREFIX(glXReleaseBuffersMESA)( Display *dpy, GLXDrawable d )
{
   (void) dpy;
   (void) d;
   return False;
}


GLXPixmap GLX_PREFIX(glXCreateGLXPixmapMESA)( Display *dpy,
                                              XVisualInfo *visual,
                                              Pixmap pixmap, Colormap cmap )
{
   (void) dpy;
   (void) visual;
   (void) pixmap;
   (void) cmap;
   return 0;
}


void GLX_PREFIX(glXCopySubBufferMESA)( Display *dpy, GLXDrawable drawable,
                                       int x, int y, int width, int height )
{
   (void) dpy;
   (void) drawable;
   (void) x;
   (void) y;
   (void) width;
   (void) height;
}


Bool GLX_PREFIX(glXSet3DfxModeMESA)( int mode )
{
   (void) mode;
   return GL_FALSE;
}



/* strdup() is actually not a standard ANSI C or POSIX routine.
 * Irix will not define it if ANSI mode is in effect.
 */
char *
__glXstrdup(const char *str)
{
   char *copy;
   copy = (char *) Xmalloc(strlen(str) + 1);
   if (!copy)
      return NULL;
   strcpy(copy, str);
   return copy;
}

/*
** glXGetProcAddress support
*/

struct name_address_pair {
   const char *Name;
   GLvoid *Address;
};

#define GLX_FUNCTION(f) { # f, (GLvoid *) f }
#define GLX_FUNCTION2(n,f) { # n, (GLvoid *) f }

static const struct name_address_pair GLX_functions[] = {
   /*** GLX_VERSION_1_0 ***/
   GLX_FUNCTION( glXChooseVisual ),
   GLX_FUNCTION( glXCopyContext ),
   GLX_FUNCTION( glXCreateContext ),
   GLX_FUNCTION( glXCreateGLXPixmap ),
   GLX_FUNCTION( glXDestroyContext ),
   GLX_FUNCTION( glXDestroyGLXPixmap ),
   GLX_FUNCTION( glXGetConfig ),
   GLX_FUNCTION( glXGetCurrentContext ),
   GLX_FUNCTION( glXGetCurrentDrawable ),
   GLX_FUNCTION( glXIsDirect ),
   GLX_FUNCTION( glXMakeCurrent ),
   GLX_FUNCTION( glXQueryExtension ),
   GLX_FUNCTION( glXQueryVersion ),
   GLX_FUNCTION( glXSwapBuffers ),
   GLX_FUNCTION( glXUseXFont ),
   GLX_FUNCTION( glXWaitGL ),
   GLX_FUNCTION( glXWaitX ),

   /*** GLX_VERSION_1_1 ***/
   GLX_FUNCTION( glXGetClientString ),
   GLX_FUNCTION( glXQueryExtensionsString ),
   GLX_FUNCTION( glXQueryServerString ),

   /*** GLX_VERSION_1_2 ***/
   GLX_FUNCTION( glXGetCurrentDisplay ),

   /*** GLX_VERSION_1_3 ***/
   GLX_FUNCTION( glXChooseFBConfig ),
   GLX_FUNCTION( glXCreateNewContext ),
   GLX_FUNCTION( glXCreatePbuffer ),
   GLX_FUNCTION( glXCreatePixmap ),
   GLX_FUNCTION( glXCreateWindow ),
   GLX_FUNCTION( glXDestroyPbuffer ),
   GLX_FUNCTION( glXDestroyPixmap ),
   GLX_FUNCTION( glXDestroyWindow ),
   GLX_FUNCTION( glXGetCurrentReadDrawable ),
   GLX_FUNCTION( glXGetFBConfigAttrib ),
   GLX_FUNCTION( glXGetFBConfigs ),
   GLX_FUNCTION( glXGetSelectedEvent ),
   GLX_FUNCTION( glXGetVisualFromFBConfig ),
   GLX_FUNCTION( glXMakeContextCurrent ),
   GLX_FUNCTION( glXQueryContext ),
   GLX_FUNCTION( glXQueryDrawable ),
   GLX_FUNCTION( glXSelectEvent ),

   /*** GLX_SGI_swap_control ***/
   GLX_FUNCTION( glXSwapIntervalSGI ),

   /*** GLX_SGI_video_sync ***/
   GLX_FUNCTION( glXGetVideoSyncSGI ),
   GLX_FUNCTION( glXWaitVideoSyncSGI ),

   /*** GLX_SGI_make_current_read ***/
   GLX_FUNCTION2( glXMakeCurrentReadSGI, glXMakeContextCurrent ),
   GLX_FUNCTION2( glXGetCurrentReadDrawableSGI, glXGetCurrentReadDrawable ),

   /*** GLX_SGIX_video_source ***/
#if defined(_VL_H)
   GLX_FUNCTION( glXCreateGLXVideoSourceSGIX ),
   GLX_FUNCTION( glXDestroyGLXVideoSourceSGIX ),
#endif

   /*** GLX_EXT_import_context ***/
   GLX_FUNCTION( glXFreeContextEXT ),
   GLX_FUNCTION( glXGetContextIDEXT ),
   GLX_FUNCTION2( glXGetCurrentDisplayEXT, glXGetCurrentDisplay ),
   GLX_FUNCTION( glXImportContextEXT ),
   GLX_FUNCTION( glXQueryContextInfoEXT ),

   /*** GLX_SGIX_fbconfig ***/
   GLX_FUNCTION2( glXGetFBConfigAttribSGIX, glXGetFBConfigAttrib ),
   GLX_FUNCTION2( glXChooseFBConfigSGIX, glXChooseFBConfig ),
   GLX_FUNCTION( glXCreateGLXPixmapWithConfigSGIX ),
   GLX_FUNCTION( glXCreateContextWithConfigSGIX ),
   GLX_FUNCTION2( glXGetVisualFromFBConfigSGIX, glXGetVisualFromFBConfig ),
   GLX_FUNCTION( glXGetFBConfigFromVisualSGIX ),

   /*** GLX_SGIX_pbuffer ***/
   GLX_FUNCTION( glXCreateGLXPbufferSGIX ),
   GLX_FUNCTION( glXDestroyGLXPbufferSGIX ),
   GLX_FUNCTION( glXQueryGLXPbufferSGIX ),
   GLX_FUNCTION( glXSelectEventSGIX ),
   GLX_FUNCTION( glXGetSelectedEventSGIX ),

   /*** GLX_SGI_cushion ***/
   GLX_FUNCTION( glXCushionSGI ),

   /*** GLX_SGIX_video_resize ***/
   GLX_FUNCTION( glXBindChannelToWindowSGIX ),
   GLX_FUNCTION( glXChannelRectSGIX ),
   GLX_FUNCTION( glXQueryChannelRectSGIX ),
   GLX_FUNCTION( glXQueryChannelDeltasSGIX ),
   GLX_FUNCTION( glXChannelRectSyncSGIX ),

   /*** GLX_SGIX_dmbuffer **/
#if defined(_DM_BUFFER_H_)
   GLX_FUNCTION( glXAssociateDMPbufferSGIX ),
#endif

   /*** GLX_SGIX_swap_group ***/
   GLX_FUNCTION( glXJoinSwapGroupSGIX ),

   /*** GLX_SGIX_swap_barrier ***/
   GLX_FUNCTION( glXBindSwapBarrierSGIX ),
   GLX_FUNCTION( glXQueryMaxSwapBarriersSGIX ),

   /*** GLX_SUN_get_transparent_index ***/
   GLX_FUNCTION( glXGetTransparentIndexSUN ),

   /*** GLX_MESA_allocate_memory ***/
   GLX_FUNCTION( glXAllocateMemoryMESA ),
   GLX_FUNCTION( glXFreeMemoryMESA ),
   GLX_FUNCTION( glXGetMemoryOffsetMESA ),

   /*** GLX_MESA_copy_sub_buffer ***/
   GLX_FUNCTION( glXCopySubBufferMESA ),

   /*** GLX_MESA_pixmap_colormap ***/
   GLX_FUNCTION( glXCreateGLXPixmapMESA ),

   /*** GLX_MESA_release_buffers ***/
   GLX_FUNCTION( glXReleaseBuffersMESA ),

   /*** GLX_MESA_set_3dfx_mode ***/
   GLX_FUNCTION( glXSet3DfxModeMESA ),

   /*** GLX_MESA_swap_control ***/
   GLX_FUNCTION( glXSwapIntervalMESA ),
   GLX_FUNCTION( glXGetSwapIntervalMESA ),

   /*** GLX_MESA_swap_frame_usage ***/
   GLX_FUNCTION( glXBeginFrameTrackingMESA ),
   GLX_FUNCTION( glXEndFrameTrackingMESA ),
   GLX_FUNCTION( glXGetFrameUsageMESA ),
   GLX_FUNCTION( glXQueryFrameTrackingMESA ),

   /*** GLX_ARB_get_proc_address ***/
   GLX_FUNCTION( glXGetProcAddressARB ),

   /*** GLX 1.4 ***/
   GLX_FUNCTION2( glXGetProcAddress, glXGetProcAddressARB ),

   /*** GLX_OML_sync_control ***/
   GLX_FUNCTION( glXWaitForSbcOML ),
   GLX_FUNCTION( glXWaitForMscOML ),
   GLX_FUNCTION( glXSwapBuffersMscOML ),
   GLX_FUNCTION( glXGetMscRateOML ),
   GLX_FUNCTION( glXGetSyncValuesOML ),

#ifdef GLX_DIRECT_RENDERING
   /***
    *** Internal functions useful to DRI drivers
    *** With this, the DRI drivers shouldn't need dlopen()/dlsym() to
    *** access internal libGL functions which may or may not exist.
    ***/
   GLX_FUNCTION( __glXInitialize ),
   GLX_FUNCTION( __glXFindDRIScreen ),
   GLX_FUNCTION( __glXGetInternalVersion ),
   GLX_FUNCTION( __glXWindowExists ),
#endif

   GLX_FUNCTION( __glXScrEnableExtension ),

   GLX_FUNCTION( __glXGetUST ),

   { NULL, NULL }   /* end of list */
};


static const GLvoid *
get_glx_proc_address(const char *funcName)
{
   GLuint i;

   /* try static functions */
   for (i = 0; GLX_functions[i].Name; i++) {
      if (strcmp(GLX_functions[i].Name, funcName) == 0)
	 return GLX_functions[i].Address;
   }

   return NULL;
}


#ifndef GLX_BUILT_IN_XMESA
void (*glXGetProcAddressARB(const GLubyte *procName))( void )
{
   typedef void (*gl_function)( void );
   gl_function f;


   /* Search the table of GLX and internal functions first.  If that
    * fails and the supplied name could be a valid core GL name, try
    * searching the core GL function table.  This check is done to prevent
    * DRI based drivers from searching the core GL function table for
    * internal API functions.
    */

   f = (gl_function) get_glx_proc_address((const char *) procName);
   if ( (f == NULL) && (procName[0] == 'g') && (procName[1] == 'l')
	&& (procName[2] != 'X') ) {
      f = (gl_function) _glapi_get_proc_address((const char *) procName);
   }

   return f;
}

/* GLX 1.4 */
void (*glXGetProcAddress(const GLubyte *procName))( void )
#if defined(__GNUC__) && !defined(GLX_ALIAS_UNSUPPORTED)
    __attribute__ ((alias ("glXGetProcAddressARB")));
#else
{
   return glXGetProcAddressARB(procName);
}
#endif /* __GNUC__ */
#endif /* GLX_BUILT_IN_XMESA */


/*
 * Return our version number (YYYYMMDD format).  This might be used by
 * the DRI drivers to determine how new libGL is at runtime.
 */
int __glXGetInternalVersion(void)
{
    /* History:
     * 20021121 - Initial version
     * 20021128 - Added __glXWindowExists() function
     * 20021207 - Added support for dynamic GLX extensions,
     *            GLX_SGI_swap_control, GLX_SGI_video_sync,
     *            GLX_OML_sync_control, and GLX_MESA_swap_control.
     *            Never officially released.  Do NOT test against
     *            this version.  Use 20030317 instead.
     * 20030317 - Added support GLX_SGIX_fbconfig,
     *            GLX_MESA_swap_frame_usage, GLX_OML_swap_method,
     *            GLX_{ARB,SGIS}_multisample, and
     *            GLX_SGIX_visual_select_group.
     * 20030606 - Added support for GLX_SGI_make_current_read.
     * 20030813 - Made support for dynamic extensions multi-head aware.
     * 20030818 - Added support for GLX_MESA_allocate_memory in place of the
     *            deprecated GLX_NV_vertex_array_range & GLX_MESA_agp_offset
     *            interfaces.
     */
    return 20030818;
}



static Bool windowExistsFlag;

static int windowExistsErrorHandler(Display *dpy, XErrorEvent *xerr)
{
    if (xerr->error_code == BadWindow) {
        windowExistsFlag = GL_FALSE;
    }
    return 0;
}

/*
 * Utility function useful to DRI drivers.
 */
Bool __glXWindowExists(Display *dpy, GLXDrawable draw)
{
    XWindowAttributes xwa;
    int (*oldXErrorHandler)(Display *, XErrorEvent *);

    XSync(dpy, GL_FALSE);
    windowExistsFlag = GL_TRUE;
    oldXErrorHandler = XSetErrorHandler(windowExistsErrorHandler);
    XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */
    XSetErrorHandler(oldXErrorHandler);
    return windowExistsFlag;
}


/**
 * Get the unadjusted system time (UST).  Currently, the UST is measured in
 * microseconds since Epoc.  The actual resolution of the UST may vary from
 * system to system, and the units may vary from release to release.
 *
 * \param ust Location to store the 64-bit UST
 * \returns Zero on success or a negative errno value on failure.
 */
int __glXGetUST( int64_t * ust )
{
    struct timeval  tv;
    
    if ( ust == NULL ) {
	return -EFAULT;
    }

    if ( gettimeofday( & tv, NULL ) == 0 ) {
	ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
	return 0;
    } else {
	return -errno;
    }
}