<commit_before>/* $XFree86: xc/lib/GL/glx/glxext.c,v 1.22 2003/12/08 17:35:28 dawes 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.
**
*/

/**
 * \file glxext.c
 * GLX protocol interface boot-strap code.
 *
 * Direct rendering support added by Precision Insight, Inc.
 *
 * \author <NAME> <<EMAIL>>
 */     

#include "glxclient.h"
#include <stdio.h>
#include <Xext.h>
#include <extutil.h>
#include <assert.h>
#include "indirect_init.h"
#include "glapi.h"
#include "glxextensions.h"
#include "glcontextmodes.h"
#include "glheader.h"

#ifdef GLX_DIRECT_RENDERING
#include <inttypes.h>
#include <sys/mman.h>
#include "xf86dri.h"
#include "sarea.h"
#include "dri_glx.h"
#endif

#ifdef USE_XCB
#include <X11/xcl.h>
#include <X11/XCB/xcb.h>
#include <X11/XCB/glx.h>
#endif

#include <assert.h>

#ifdef DEBUG
void __glXDumpDrawBuffer(__GLXcontext *ctx);
#endif

#ifdef USE_SPARC_ASM
/*
 * This is where our dispatch table's bounds are.
 * And the static mesa_init is taken directly from
 * Mesa's 'sparc.c' initializer.
 *
 * We need something like this here, because this version
 * of openGL/glx never initializes a Mesa context, and so
 * the address of the dispatch table pointer never gets stuffed
 * into the dispatch jump table otherwise.
 *
 * It matters only on SPARC, and only if you are using assembler
 * code instead of C-code indirect dispatch.
 *
 * -- FEM, 04.xii.03
 */
extern unsigned int _mesa_sparc_glapi_begin;
extern unsigned int _mesa_sparc_glapi_end;
extern void __glapi_sparc_icache_flush(unsigned int *);
static void _glx_mesa_init_sparc_glapi_relocs(void);
static int _mesa_sparc_needs_init = 1;
#define INIT_MESA_SPARC { \
    if(_mesa_sparc_needs_init) { \
      _glx_mesa_init_sparc_glapi_relocs(); \
      _mesa_sparc_needs_init = 0; \
  } \
}
#else
#define INIT_MESA_SPARC
#endif

#ifdef GLX_DIRECT_RENDERING
static __DRIscreen *__glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn);
#endif /* GLX_DIRECT_RENDERING */

static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw,
    GLXDrawable read, GLXContext gc);

/*
** We setup some dummy structures here so that the API can be used
** even if no context is current.
*/

static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];

/*
** Dummy context used by small commands when there is no current context.
** All the
** gl and glx entry points are designed to operate as nop's when using
** the dummy context structure.
*/
static __GLXcontext dummyContext = {
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
    sizeof(dummyBuffer),
};


/*
** All indirect rendering contexts will share the same indirect dispatch table.
*/
static __GLapi *IndirectAPI = NULL;


/*
 * Current context management and locking
 */

#if defined( USE_XTHREADS )

/* thread safe */
static GLboolean TSDinitialized = GL_FALSE;
static xthread_key_t ContextTSD;

__GLXcontext *__glXGetCurrentContext(void)
{
   if (!TSDinitialized) {
      xthread_key_create(&ContextTSD, NULL);
      TSDinitialized = GL_TRUE;
      return &dummyContext;
   }
   else {
      void *p;
      xthread_get_specific(ContextTSD, &p);
      if (!p)
         return &dummyContext;
      else
         return (__GLXcontext *) p;
   }
}

void __glXSetCurrentContext(__GLXcontext *c)
{
   if (!TSDinitialized) {
      xthread_key_create(&ContextTSD, NULL);
      TSDinitialized = GL_TRUE;
   }
   xthread_set_specific(ContextTSD, c);
}


/* Used by the __glXLock() and __glXUnlock() macros */
xmutex_rec __glXmutex;

#elif defined( PTHREADS )

pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;

# if defined( GLX_USE_TLS )

/**
 * Per-thread GLX context pointer.
 * 
 * \c __glXSetCurrentContext is written is such a way that this pointer can
 * \b never be \c NULL.  This is important!  Because of this
 * \c __glXGetCurrentContext can be implemented as trivial macro.
 */
__thread void * __glX_tls_Context __attribute__((tls_model("initial-exec")))
    = &dummyContext;

void __glXSetCurrentContext( __GLXcontext * c )
{
    __glX_tls_Context = (c != NULL) ? c : &dummyContext;
}

# else

static pthread_once_t once_control = PTHREAD_ONCE_INIT;

/**
 * Per-thread data key.
 * 
 * Once \c init_thread_data has been called, the per-thread data key will
 * take a value of \c NULL.  As each new thread is created the default
 * value, in that thread, will be \c NULL.
 */
static pthread_key_t ContextTSD;

/**
 * Initialize the per-thread data key.
 * 
 * This function is called \b exactly once per-process (not per-thread!) to
 * initialize the per-thread data key.  This is ideally done using the
 * \c pthread_once mechanism.
 */
static void init_thread_data( void )
{
    if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) {
	perror( "pthread_key_create" );
	exit( -1 );
    }
}

void __glXSetCurrentContext( __GLXcontext * c )
{
    pthread_once( & once_control, init_thread_data );
    pthread_setspecific( ContextTSD, c );
}

__GLXcontext * __glXGetCurrentContext( void )
{
    void * v;

    pthread_once( & once_control, init_thread_data );

    v = pthread_getspecific( ContextTSD );
    return (v == NULL) ? & dummyContext : (__GLXcontext *) v;
}

# endif /* defined( GLX_USE_TLS ) */

#elif defined( THREADS )

#error Unknown threading method specified.

#else

/* not thread safe */
__GLXcontext *__glXcurrentContext = &dummyContext;

#endif


/*
** You can set this cell to 1 to force the gl drawing stuff to be
** one command per packet
*/
int __glXDebug = 0;

/*
** forward prototype declarations
*/
int __glXCloseDisplay(Display *dpy, XExtCodes *codes);


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

/* Extension required boiler plate */

static char *__glXExtensionName = GLX_EXTENSION_NAME;
XExtensionInfo *__glXExtensionInfo = NULL;

static /* const */ char *error_list[] = {
    "GLXBadContext",
    "GLXBadContextState",
    "GLXBadDrawable",
    "GLXBadPixmap",
    "GLXBadContextTag",
    "GLXBadCurrentWindow",
    "GLXBadRenderRequest",
    "GLXBadLargeRequest",
    "GLXUnsupportedPrivateRequest",
};

int __glXCloseDisplay(Display *dpy, XExtCodes *codes)
{
  GLXContext gc;

  gc = __glXGetCurrentContext();
  if (dpy == gc->currentDpy) {
    __glXSetCurrentContext(&dummyContext);
#ifdef GLX_DIRECT_RENDERING
    _glapi_set_dispatch(NULL);  /* no-op functions */
#endif
    __glXFreeContext(gc);
  }

  return XextRemoveDisplay(__glXExtensionInfo, dpy);
}


static XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName,
				  __GLX_NUMBER_ERRORS, error_list)

static /* const */ XExtensionHooks __glXExtensionHooks = {
    NULL,				/* create_gc */
    NULL,				/* copy_gc */
    NULL,				/* flush_gc */
    NULL,				/* free_gc */
    NULL,				/* create_font */
    NULL,				/* free_font */
    __glXCloseDisplay,			/* close_display */
    NULL,				/* wire_to_event */
    NULL,				/* event_to_wire */
    NULL,				/* error */
    __glXErrorString,			/* error_string */
};

static
XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
			   __glXExtensionName, &__glXExtensionHooks,
			   __GLX_NUMBER_EVENTS, NULL)

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

/*
** Free the per screen configs data as well as the array of
** __glXScreenConfigs.
*/
static void FreeScreenConfigs(__GLXdisplayPrivate *priv)
{
    __GLXscreenConfigs *psc;
    GLint i, screens;

    /* Free screen configuration information */
    psc = priv->screenConfigs;
    screens = ScreenCount(priv->dpy);
    for (i = 0; i < screens; i++, psc++) {
	if (psc->configs) {
	    _gl_context_modes_destroy( psc->configs );
	    if(psc->effectiveGLXexts)
		Xfree(psc->effectiveGLXexts);

	    psc->configs = NULL;	/* NOTE: just for paranoia */
	}

#ifdef GLX_DIRECT_RENDERING
	/* Free the direct rendering per screen data */
	if (psc->driScreen.private)
	    (*psc->driScreen.destroyScreen)(priv->dpy, i,
					    psc->driScreen.private);
	psc->driScreen.private = NULL;
#endif
    }
    XFree((char*) priv->screenConfigs);
}

/*
** Release the private memory referred to in a display private
** structure.  The caller will free the extension structure.
*/
static int __glXFreeDisplayPrivate(XExtData *extension)
{
    __GLXdisplayPrivate *priv;

    priv = (__GLXdisplayPrivate*) extension->private_data;
    FreeScreenConfigs(priv);
    if(priv->serverGLXvendor) {
	Xfree((char*)priv->serverGLXvendor);
	priv->serverGLXvendor = 0x0; /* to protect against double free's */
    }
    if(priv->serverGLXversion) {
	Xfree((char*)priv->serverGLXversion);
	priv->serverGLXversion = 0x0; /* to protect against double free's */
    }

#if 0 /* GLX_DIRECT_RENDERING */
    /* Free the direct rendering per display data */
    if (priv->driDisplay.private)
	(*priv->driDisplay.destroyDisplay)(priv->dpy,
					   priv->driDisplay.private);
    priv->driDisplay.private = NULL;
#endif

    Xfree((char*) priv);
    return 0;
}

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

/*
** Query the version of the GLX extension.  This procedure works even if
** the client extension is not completely set up.
*/
static Bool QueryVersion(Display *dpy, int opcode, int *major, int *minor)
{
    xGLXQueryVersionReq *req;
    xGLXQueryVersionReply reply;

    /* Send the glXQueryVersion request */
    LockDisplay(dpy);
    GetReq(GLXQueryVersion,req);
    req->reqType = opcode;
    req->glxCode = X_GLXQueryVersion;
    req->majorVersion = GLX_MAJOR_VERSION;
    req->minorVersion = GLX_MINOR_VERSION;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);
    SyncHandle();

    if (reply.majorVersion != GLX_MAJOR_VERSION) {
	/*
	** The server does not support the same major release as this
	** client.
	*/
	return GL_FALSE;
    }
    *major = reply.majorVersion;
    *minor = min(reply.minorVersion, GLX_MINOR_VERSION);
    return GL_TRUE;
}


void 
__glXInitializeVisualConfigFromTags( __GLcontextModes *config, int count, 
				     const INT32 *bp, Bool tagged_only,
				     Bool fbconfig_style_tags )
{
    int i;

    if (!tagged_only) {
	/* Copy in the first set of properties */
	config->visualID = *bp++;

	config->visualType = _gl_convert_from_x_visual_type( *bp++ );

	config->rgbMode = *bp++;

	config->redBits = *bp++;
	config->greenBits = *bp++;
	config->blueBits = *bp++;
	config->alphaBits = *bp++;
	config->accumRedBits = *bp++;
	config->accumGreenBits = *bp++;
	config->accumBlueBits = *bp++;
	config->accumAlphaBits = *bp++;

	config->doubleBufferMode = *bp++;
	config->stereoMode = *bp++;

	config->rgbBits = *bp++;
	config->depthBits = *bp++;
	config->stencilBits = *bp++;
	config->numAuxBuffers = *bp++;
	config->level = *bp++;

	count -= __GLX_MIN_CONFIG_PROPS;
    }

    /*
    ** Additional properties may be in a list at the end
    ** of the reply.  They are in pairs of property type
    ** and property value.
    */

#define FETCH_OR_SET(tag) \
    config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1

    for (i = 0; i < count; i += 2 ) {
	switch(*bp++) {
	  case GLX_RGBA:
	    FETCH_OR_SET( rgbMode );
	    break;
	  case GLX_BUFFER_SIZE:
	    config->rgbBits = *bp++;
	    break;
	  case GLX_LEVEL:
	    config->level = *bp++;
	    break;
	  case GLX_DOUBLEBUFFER:
	    FETCH_OR_SET( doubleBufferMode );
	    break;
	  case GLX_STEREO:
	    FETCH_OR_SET( stereoMode );
	    break;
	  case GLX_AUX_BUFFERS:
	    config->numAuxBuffers = *bp++;
	    break;
	  case GLX_RED_SIZE:
	    config->redBits = *bp++;
	    break;
	  case GLX_GREEN_SIZE:
	    config->greenBits = *bp++;
	    break;
	  case GLX_BLUE_SIZE:
	    config->blueBits = *bp++;
	    break;
	  case GLX_ALPHA_SIZE:
	    config->alphaBits = *bp++;
	    break;
	  case GLX_DEPTH_SIZE:
	    config->depthBits = *bp++;
	    break;
	  case GLX_STENCIL_SIZE:
	    config->stencilBits = *bp++;
	    break;
	  case GLX_ACCUM_RED_SIZE:
	    config->accumRedBits = *bp++;
	    break;
	  case GLX_ACCUM_GREEN_SIZE:
	    config->accumGreenBits = *bp++;
	    break;
	  case GLX_ACCUM_BLUE_SIZE:
	    config->accumBlueBits = *bp++;
	    break;
	  case GLX_ACCUM_ALPHA_SIZE:
	    config->accumAlphaBits = *bp++;
	    break;
	  case GLX_VISUAL_CAVEAT_EXT:
	    config->visualRating = *bp++;    
	    break;
	  case GLX_X_VISUAL_TYPE:
	    config->visualType = *bp++;
	    break;
	  case GLX_TRANSPARENT_TYPE:
	    config->transparentPixel = *bp++;    
	    break;
	  case GLX_TRANSPARENT_INDEX_VALUE:
	    config->transparentIndex = *bp++;    
	    break;
	  case GLX_TRANSPARENT_RED_VALUE:
	    config->transparentRed = *bp++;    
	    break;
	  case GLX_TRANSPARENT_GREEN_VALUE:
	    config->transparentGreen = *bp++;    
	    break;
	  case GLX_TRANSPARENT_BLUE_VALUE:
	    config->transparentBlue = *bp++;    
	    break;
	  case GLX_TRANSPARENT_ALPHA_VALUE:
	    config->transparentAlpha = *bp++;    
	    break;
	  case GLX_VISUAL_ID:
	    config->visualID = *bp++;
	    break;
	  case GLX_DRAWABLE_TYPE:
	    config->drawableType = *bp++;
	    break;
	  case GLX_RENDER_TYPE:
	    config->renderType = *bp++;
	    break;
	  case GLX_X_RENDERABLE:
	    config->xRenderable = *bp++;
	    break;
	  case GLX_FBCONFIG_ID:
	    config->fbconfigID = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_WIDTH:
	    config->maxPbufferWidth = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_HEIGHT:
	    config->maxPbufferHeight = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_PIXELS:
	    config->maxPbufferPixels = *bp++;
	    break;
	  case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
	    config->optimalPbufferWidth = *bp++;
	    break;
	  case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
	    config->optimalPbufferHeight = *bp++;
	    break;
	  case GLX_VISUAL_SELECT_GROUP_SGIX:
	    config->visualSelectGroup = *bp++;
	    break;
	  case GLX_SWAP_METHOD_OML:
	    config->swapMethod = *bp++;
	    break;
	  case GLX_SAMPLE_BUFFERS_SGIS:
	    config->sampleBuffers = *bp++;
	    break;
	  case GLX_SAMPLES_SGIS:
	    config->samples = *bp++;
	    break;
	  case None:
	    i = count;
	    break;
	  default:
	    break;
	}
    }

    config->renderType = (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;

    config->haveAccumBuffer = ((config->accumRedBits +
			       config->accumGreenBits +
			       config->accumBlueBits +
			       config->accumAlphaBits) > 0);
    config->haveDepthBuffer = (config->depthBits > 0);
    config->haveStencilBuffer = (config->stencilBits > 0);
}


#ifdef GLX_DIRECT_RENDERING
static unsigned
filter_modes( __GLcontextModes ** server_modes,
	      const __GLcontextModes * driver_modes )
{
    __GLcontextModes * m;
    __GLcontextModes ** prev_next;
    const __GLcontextModes * check;
    unsigned modes_count = 0;

    if ( driver_modes == NULL ) {
	fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
	return 0;
    }

    /* For each mode in server_modes, check to see if a matching mode exists
     * in driver_modes.  If not, then the mode is not available.
     */

    prev_next = server_modes;
    for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
	GLboolean do_delete = GL_TRUE;

	for ( check = driver_modes ; check != NULL ; check = check->next ) {
	    if ( _gl_context_modes_are_same( m, check ) ) {
		do_delete = GL_FALSE;
		break;
	    }
	}

	/* The 3D has to support all the modes that match the GLX visuals
	 * sent from the X server.
	 */
	if ( do_delete && (m->visualID != 0) ) {
	    do_delete = GL_FALSE;

	    fprintf(stderr, "libGL warning: 3D driver claims to not support "
		    "visual 0x%02x\n", m->visualID);
	}

	if ( do_delete ) {
	    *prev_next = m->next;

	    m->next = NULL;
	    _gl_context_modes_destroy( m );
	}
	else {
	    modes_count++;
	    prev_next = & m->next;
	}
    }

    return modes_count;
}


/**
 * Implement \c __DRIinterfaceMethods::getProcAddress.
 */
static __DRIfuncPtr get_proc_address( const char * proc_name )
{
    if (strcmp( proc_name, "glxEnableExtension" ) == 0) {
	return (__DRIfuncPtr) __glXScrEnableExtension;
    }
    
    return NULL;
}


/**
 * Table of functions exported by the loader to the driver.
 */
static const __DRIinterfaceMethods interface_methods = {
    get_proc_address,

    _gl_context_modes_create,
    _gl_context_modes_destroy,
      
    __glXFindDRIScreen,
    __glXWindowExists,
      
    XF86DRICreateContextWithConfig,
    XF86DRIDestroyContext,

    XF86DRICreateDrawable,
    XF86DRIDestroyDrawable,
    XF86DRIGetDrawableInfo,

    __glXGetUST,
    glXGetMscRateOML,
};


/**
 * Perform the required libGL-side initialization and call the client-side
 * driver's \c __driCreateNewScreen function.
 * 
 * \param dpy    Display pointer.
 * \param scrn   Screen number on the display.
 * \param psc    DRI screen information.
 * \param driDpy DRI display information.
 * \param createNewScreen  Pointer to the client-side driver's
 *               \c __driCreateNewScreen function.
 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
 *          the client-side driver on success, or \c NULL on failure.
 * 
 * \todo This function needs to be modified to remove context-modes from the
 *       list stored in the \c __GLXscreenConfigsRec to match the list
 *       returned by the client-side driver.
 */
static void *
CallCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc,
		    __DRIdisplay * driDpy,
		    PFNCREATENEWSCREENFUNC createNewScreen)
{
    __DRIscreenPrivate *psp = NULL;
#ifndef GLX_USE_APPLEGL
    drm_handle_t hSAREA;
    drmAddress pSAREA;
    char *BusID;
    __DRIversion   ddx_version;
    __DRIversion   dri_version;
    __DRIversion   drm_version;
    __DRIframebuffer  framebuffer;
    int   fd = -1;
    int   status;
    const char * err_msg;
    const char * err_extra;
    int api_ver = __glXGetInternalVersion();


    dri_version.major = driDpy->private->driMajor;
    dri_version.minor = driDpy->private->driMinor;
    dri_version.patch = driDpy->private->driPatch;


    err_msg = "XF86DRIOpenConnection";
    err_extra = NULL;

    framebuffer.dev_priv = NULL;

    if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
	fd = drmOpen(NULL,BusID);
	Xfree(BusID); /* No longer needed */

	err_msg = "open DRM";
	err_extra = strerror( -fd );

	if (fd >= 0) {
	    drm_magic_t magic;

	    err_msg = "drmGetMagic";
	    err_extra = NULL;

	    if (!drmGetMagic(fd, &magic)) {
		drmVersionPtr version = drmGetVersion(fd);
		if (version) {
		    drm_version.major = version->version_major;
		    drm_version.minor = version->version_minor;
		    drm_version.patch = version->version_patchlevel;
		    drmFreeVersion(version);
		}
		else {
		    drm_version.major = -1;
		    drm_version.minor = -1;
		    drm_version.patch = -1;
		}<commit_msg>Fixes bugzilla #1730.<commit_after>/* $XFree86: xc/lib/GL/glx/glxext.c,v 1.22 2003/12/08 17:35:28 dawes 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.
**
*/

/**
 * \file glxext.c
 * GLX protocol interface boot-strap code.
 *
 * Direct rendering support added by Precision Insight, Inc.
 *
 * \author <NAME> <<EMAIL>>
 */     

#include "glxclient.h"
#include <stdio.h>
#include <Xext.h>
#include <extutil.h>
#include <assert.h>
#include "indirect_init.h"
#include "glapi.h"
#include "glxextensions.h"
#include "glcontextmodes.h"
#include "glheader.h"

#ifdef GLX_DIRECT_RENDERING
#include <inttypes.h>
#include <sys/mman.h>
#include "xf86dri.h"
#include "sarea.h"
#include "dri_glx.h"
#endif

#ifdef USE_XCB
#include <X11/xcl.h>
#include <X11/XCB/xcb.h>
#include <X11/XCB/glx.h>
#endif

#include <assert.h>

#ifdef DEBUG
void __glXDumpDrawBuffer(__GLXcontext *ctx);
#endif

#ifdef USE_SPARC_ASM
/*
 * This is where our dispatch table's bounds are.
 * And the static mesa_init is taken directly from
 * Mesa's 'sparc.c' initializer.
 *
 * We need something like this here, because this version
 * of openGL/glx never initializes a Mesa context, and so
 * the address of the dispatch table pointer never gets stuffed
 * into the dispatch jump table otherwise.
 *
 * It matters only on SPARC, and only if you are using assembler
 * code instead of C-code indirect dispatch.
 *
 * -- FEM, 04.xii.03
 */
extern unsigned int _mesa_sparc_glapi_begin;
extern unsigned int _mesa_sparc_glapi_end;
extern void __glapi_sparc_icache_flush(unsigned int *);
static void _glx_mesa_init_sparc_glapi_relocs(void);
static int _mesa_sparc_needs_init = 1;
#define INIT_MESA_SPARC { \
    if(_mesa_sparc_needs_init) { \
      _glx_mesa_init_sparc_glapi_relocs(); \
      _mesa_sparc_needs_init = 0; \
  } \
}
#else
#define INIT_MESA_SPARC
#endif

#ifdef GLX_DIRECT_RENDERING
static __DRIscreen *__glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn);
#endif /* GLX_DIRECT_RENDERING */

static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw,
    GLXDrawable read, GLXContext gc);

/*
** We setup some dummy structures here so that the API can be used
** even if no context is current.
*/

static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];

/*
** Dummy context used by small commands when there is no current context.
** All the
** gl and glx entry points are designed to operate as nop's when using
** the dummy context structure.
*/
static __GLXcontext dummyContext = {
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[0],
    &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
    sizeof(dummyBuffer),
};


/*
** All indirect rendering contexts will share the same indirect dispatch table.
*/
static __GLapi *IndirectAPI = NULL;


/*
 * Current context management and locking
 */

#if defined( USE_XTHREADS )

/* thread safe */
static GLboolean TSDinitialized = GL_FALSE;
static xthread_key_t ContextTSD;

__GLXcontext *__glXGetCurrentContext(void)
{
   if (!TSDinitialized) {
      xthread_key_create(&ContextTSD, NULL);
      TSDinitialized = GL_TRUE;
      return &dummyContext;
   }
   else {
      void *p;
      xthread_get_specific(ContextTSD, &p);
      if (!p)
         return &dummyContext;
      else
         return (__GLXcontext *) p;
   }
}

void __glXSetCurrentContext(__GLXcontext *c)
{
   if (!TSDinitialized) {
      xthread_key_create(&ContextTSD, NULL);
      TSDinitialized = GL_TRUE;
   }
   xthread_set_specific(ContextTSD, c);
}


/* Used by the __glXLock() and __glXUnlock() macros */
xmutex_rec __glXmutex;

#elif defined( PTHREADS )

pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;

# if defined( GLX_USE_TLS )

/**
 * Per-thread GLX context pointer.
 * 
 * \c __glXSetCurrentContext is written is such a way that this pointer can
 * \b never be \c NULL.  This is important!  Because of this
 * \c __glXGetCurrentContext can be implemented as trivial macro.
 */
__thread void * __glX_tls_Context __attribute__((tls_model("initial-exec")))
    = &dummyContext;

void __glXSetCurrentContext( __GLXcontext * c )
{
    __glX_tls_Context = (c != NULL) ? c : &dummyContext;
}

# else

static pthread_once_t once_control = PTHREAD_ONCE_INIT;

/**
 * Per-thread data key.
 * 
 * Once \c init_thread_data has been called, the per-thread data key will
 * take a value of \c NULL.  As each new thread is created the default
 * value, in that thread, will be \c NULL.
 */
static pthread_key_t ContextTSD;

/**
 * Initialize the per-thread data key.
 * 
 * This function is called \b exactly once per-process (not per-thread!) to
 * initialize the per-thread data key.  This is ideally done using the
 * \c pthread_once mechanism.
 */
static void init_thread_data( void )
{
    if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) {
	perror( "pthread_key_create" );
	exit( -1 );
    }
}

void __glXSetCurrentContext( __GLXcontext * c )
{
    pthread_once( & once_control, init_thread_data );
    pthread_setspecific( ContextTSD, c );
}

__GLXcontext * __glXGetCurrentContext( void )
{
    void * v;

    pthread_once( & once_control, init_thread_data );

    v = pthread_getspecific( ContextTSD );
    return (v == NULL) ? & dummyContext : (__GLXcontext *) v;
}

# endif /* defined( GLX_USE_TLS ) */

#elif defined( THREADS )

#error Unknown threading method specified.

#else

/* not thread safe */
__GLXcontext *__glXcurrentContext = &dummyContext;

#endif


/*
** You can set this cell to 1 to force the gl drawing stuff to be
** one command per packet
*/
int __glXDebug = 0;

/*
** forward prototype declarations
*/
int __glXCloseDisplay(Display *dpy, XExtCodes *codes);


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

/* Extension required boiler plate */

static char *__glXExtensionName = GLX_EXTENSION_NAME;
XExtensionInfo *__glXExtensionInfo = NULL;

static /* const */ char *error_list[] = {
    "GLXBadContext",
    "GLXBadContextState",
    "GLXBadDrawable",
    "GLXBadPixmap",
    "GLXBadContextTag",
    "GLXBadCurrentWindow",
    "GLXBadRenderRequest",
    "GLXBadLargeRequest",
    "GLXUnsupportedPrivateRequest",
};

int __glXCloseDisplay(Display *dpy, XExtCodes *codes)
{
  GLXContext gc;

  gc = __glXGetCurrentContext();
  if (dpy == gc->currentDpy) {
    __glXSetCurrentContext(&dummyContext);
#ifdef GLX_DIRECT_RENDERING
    _glapi_set_dispatch(NULL);  /* no-op functions */
#endif
    __glXFreeContext(gc);
  }

  return XextRemoveDisplay(__glXExtensionInfo, dpy);
}


static XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName,
				  __GLX_NUMBER_ERRORS, error_list)

static /* const */ XExtensionHooks __glXExtensionHooks = {
    NULL,				/* create_gc */
    NULL,				/* copy_gc */
    NULL,				/* flush_gc */
    NULL,				/* free_gc */
    NULL,				/* create_font */
    NULL,				/* free_font */
    __glXCloseDisplay,			/* close_display */
    NULL,				/* wire_to_event */
    NULL,				/* event_to_wire */
    NULL,				/* error */
    __glXErrorString,			/* error_string */
};

static
XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
			   __glXExtensionName, &__glXExtensionHooks,
			   __GLX_NUMBER_EVENTS, NULL)

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

/*
** Free the per screen configs data as well as the array of
** __glXScreenConfigs.
*/
static void FreeScreenConfigs(__GLXdisplayPrivate *priv)
{
    __GLXscreenConfigs *psc;
    GLint i, screens;

    /* Free screen configuration information */
    psc = priv->screenConfigs;
    screens = ScreenCount(priv->dpy);
    for (i = 0; i < screens; i++, psc++) {
	if (psc->configs) {
	    _gl_context_modes_destroy( psc->configs );
	    if(psc->effectiveGLXexts)
		Xfree(psc->effectiveGLXexts);

	    psc->configs = NULL;	/* NOTE: just for paranoia */
	}

#ifdef GLX_DIRECT_RENDERING
	/* Free the direct rendering per screen data */
	if (psc->driScreen.private)
	    (*psc->driScreen.destroyScreen)(priv->dpy, i,
					    psc->driScreen.private);
	psc->driScreen.private = NULL;
#endif
    }
    XFree((char*) priv->screenConfigs);
}

/*
** Release the private memory referred to in a display private
** structure.  The caller will free the extension structure.
*/
static int __glXFreeDisplayPrivate(XExtData *extension)
{
    __GLXdisplayPrivate *priv;

    priv = (__GLXdisplayPrivate*) extension->private_data;
    FreeScreenConfigs(priv);
    if(priv->serverGLXvendor) {
	Xfree((char*)priv->serverGLXvendor);
	priv->serverGLXvendor = 0x0; /* to protect against double free's */
    }
    if(priv->serverGLXversion) {
	Xfree((char*)priv->serverGLXversion);
	priv->serverGLXversion = 0x0; /* to protect against double free's */
    }

#if 0 /* GLX_DIRECT_RENDERING */
    /* Free the direct rendering per display data */
    if (priv->driDisplay.private)
	(*priv->driDisplay.destroyDisplay)(priv->dpy,
					   priv->driDisplay.private);
    priv->driDisplay.private = NULL;
#endif

    Xfree((char*) priv);
    return 0;
}

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

/*
** Query the version of the GLX extension.  This procedure works even if
** the client extension is not completely set up.
*/
static Bool QueryVersion(Display *dpy, int opcode, int *major, int *minor)
{
    xGLXQueryVersionReq *req;
    xGLXQueryVersionReply reply;

    /* Send the glXQueryVersion request */
    LockDisplay(dpy);
    GetReq(GLXQueryVersion,req);
    req->reqType = opcode;
    req->glxCode = X_GLXQueryVersion;
    req->majorVersion = GLX_MAJOR_VERSION;
    req->minorVersion = GLX_MINOR_VERSION;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);
    SyncHandle();

    if (reply.majorVersion != GLX_MAJOR_VERSION) {
	/*
	** The server does not support the same major release as this
	** client.
	*/
	return GL_FALSE;
    }
    *major = reply.majorVersion;
    *minor = min(reply.minorVersion, GLX_MINOR_VERSION);
    return GL_TRUE;
}


void 
__glXInitializeVisualConfigFromTags( __GLcontextModes *config, int count, 
				     const INT32 *bp, Bool tagged_only,
				     Bool fbconfig_style_tags )
{
    int i;

    if (!tagged_only) {
	/* Copy in the first set of properties */
	config->visualID = *bp++;

	config->visualType = _gl_convert_from_x_visual_type( *bp++ );

	config->rgbMode = *bp++;

	config->redBits = *bp++;
	config->greenBits = *bp++;
	config->blueBits = *bp++;
	config->alphaBits = *bp++;
	config->accumRedBits = *bp++;
	config->accumGreenBits = *bp++;
	config->accumBlueBits = *bp++;
	config->accumAlphaBits = *bp++;

	config->doubleBufferMode = *bp++;
	config->stereoMode = *bp++;

	config->rgbBits = *bp++;
	config->depthBits = *bp++;
	config->stencilBits = *bp++;
	config->numAuxBuffers = *bp++;
	config->level = *bp++;

	count -= __GLX_MIN_CONFIG_PROPS;
    }

    /*
    ** Additional properties may be in a list at the end
    ** of the reply.  They are in pairs of property type
    ** and property value.
    */

#define FETCH_OR_SET(tag) \
    config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1

    for (i = 0; i < count; i += 2 ) {
	switch(*bp++) {
	  case GLX_RGBA:
	    FETCH_OR_SET( rgbMode );
	    break;
	  case GLX_BUFFER_SIZE:
	    config->rgbBits = *bp++;
	    break;
	  case GLX_LEVEL:
	    config->level = *bp++;
	    break;
	  case GLX_DOUBLEBUFFER:
	    FETCH_OR_SET( doubleBufferMode );
	    break;
	  case GLX_STEREO:
	    FETCH_OR_SET( stereoMode );
	    break;
	  case GLX_AUX_BUFFERS:
	    config->numAuxBuffers = *bp++;
	    break;
	  case GLX_RED_SIZE:
	    config->redBits = *bp++;
	    break;
	  case GLX_GREEN_SIZE:
	    config->greenBits = *bp++;
	    break;
	  case GLX_BLUE_SIZE:
	    config->blueBits = *bp++;
	    break;
	  case GLX_ALPHA_SIZE:
	    config->alphaBits = *bp++;
	    break;
	  case GLX_DEPTH_SIZE:
	    config->depthBits = *bp++;
	    break;
	  case GLX_STENCIL_SIZE:
	    config->stencilBits = *bp++;
	    break;
	  case GLX_ACCUM_RED_SIZE:
	    config->accumRedBits = *bp++;
	    break;
	  case GLX_ACCUM_GREEN_SIZE:
	    config->accumGreenBits = *bp++;
	    break;
	  case GLX_ACCUM_BLUE_SIZE:
	    config->accumBlueBits = *bp++;
	    break;
	  case GLX_ACCUM_ALPHA_SIZE:
	    config->accumAlphaBits = *bp++;
	    break;
	  case GLX_VISUAL_CAVEAT_EXT:
	    config->visualRating = *bp++;    
	    break;
	  case GLX_X_VISUAL_TYPE:
	    config->visualType = *bp++;
	    break;
	  case GLX_TRANSPARENT_TYPE:
	    config->transparentPixel = *bp++;    
	    break;
	  case GLX_TRANSPARENT_INDEX_VALUE:
	    config->transparentIndex = *bp++;    
	    break;
	  case GLX_TRANSPARENT_RED_VALUE:
	    config->transparentRed = *bp++;    
	    break;
	  case GLX_TRANSPARENT_GREEN_VALUE:
	    config->transparentGreen = *bp++;    
	    break;
	  case GLX_TRANSPARENT_BLUE_VALUE:
	    config->transparentBlue = *bp++;    
	    break;
	  case GLX_TRANSPARENT_ALPHA_VALUE:
	    config->transparentAlpha = *bp++;    
	    break;
	  case GLX_VISUAL_ID:
	    config->visualID = *bp++;
	    break;
	  case GLX_DRAWABLE_TYPE:
	    config->drawableType = *bp++;
	    break;
	  case GLX_RENDER_TYPE:
	    config->renderType = *bp++;
	    break;
	  case GLX_X_RENDERABLE:
	    config->xRenderable = *bp++;
	    break;
	  case GLX_FBCONFIG_ID:
	    config->fbconfigID = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_WIDTH:
	    config->maxPbufferWidth = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_HEIGHT:
	    config->maxPbufferHeight = *bp++;
	    break;
	  case GLX_MAX_PBUFFER_PIXELS:
	    config->maxPbufferPixels = *bp++;
	    break;
	  case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
	    config->optimalPbufferWidth = *bp++;
	    break;
	  case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
	    config->optimalPbufferHeight = *bp++;
	    break;
	  case GLX_VISUAL_SELECT_GROUP_SGIX:
	    config->visualSelectGroup = *bp++;
	    break;
	  case GLX_SWAP_METHOD_OML:
	    config->swapMethod = *bp++;
	    break;
	  case GLX_SAMPLE_BUFFERS_SGIS:
	    config->sampleBuffers = *bp++;
	    break;
	  case GLX_SAMPLES_SGIS:
	    config->samples = *bp++;
	    break;
	  case None:
	    i = count;
	    break;
	  default:
	    break;
	}
    }

    config->renderType = (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;

    config->haveAccumBuffer = ((config->accumRedBits +
			       config->accumGreenBits +
			       config->accumBlueBits +
			       config->accumAlphaBits) > 0);
    config->haveDepthBuffer = (config->depthBits > 0);
    config->haveStencilBuffer = (config->stencilBits > 0);
}


#ifdef GLX_DIRECT_RENDERING
static unsigned
filter_modes( __GLcontextModes ** server_modes,
	      const __GLcontextModes * driver_modes )
{
    __GLcontextModes * m;
    __GLcontextModes ** prev_next;
    const __GLcontextModes * check;
    unsigned modes_count = 0;

    if ( driver_modes == NULL ) {
	fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
	return 0;
    }

    /* For each mode in server_modes, check to see if a matching mode exists
     * in driver_modes.  If not, then the mode is not available.
     */

    prev_next = server_modes;
    for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
	GLboolean do_delete = GL_TRUE;

	for ( check = driver_modes ; check != NULL ; check = check->next ) {
	    if ( _gl_context_modes_are_same( m, check ) ) {
		do_delete = GL_FALSE;
		break;
	    }
	}

	/* The 3D has to support all the modes that match the GLX visuals
	 * sent from the X server.
	 */
	if ( do_delete && (m->visualID != 0) ) {
	    do_delete = GL_FALSE;

	    fprintf(stderr, "libGL warning: 3D driver claims to not support "
		    "visual 0x%02x\n", m->visualID);
	}

	if ( do_delete ) {
	    *prev_next = m->next;

	    m->next = NULL;
	    _gl_context_modes_destroy( m );
	}
	else {
	    modes_count++;
	    prev_next = & m->next;
	}
    }

    return modes_count;
}


/**
 * Implement \c __DRIinterfaceMethods::getProcAddress.
 */
static __DRIfuncPtr get_proc_address( const char * proc_name )
{
    if (strcmp( proc_name, "glxEnableExtension" ) == 0) {
	return (__DRIfuncPtr) __glXScrEnableExtension;
    }
    
    return NULL;
}


/**
 * Table of functions exported by the loader to the driver.
 */
static const __DRIinterfaceMethods interface_methods = {
    get_proc_address,

    _gl_context_modes_create,
    _gl_context_modes_destroy,
      
    __glXFindDRIScreen,
    __glXWindowExists,
      
    XF86DRICreateContextWithConfig,
    XF86DRIDestroyContext,

    XF86DRICreateDrawable,
    XF86DRIDestroyDrawable,
    XF86DRIGetDrawableInfo,

    __glXGetUST,
    glXGetMscRateOML,
};


/**
 * Perform the required libGL-side initialization and call the client-side
 * driver's \c __driCreateNewScreen function.
 * 
 * \param dpy    Display pointer.
 * \param scrn   Screen number on the display.
 * \param psc    DRI screen information.
 * \param driDpy DRI display information.
 * \param createNewScreen  Pointer to the client-side driver's
 *               \c __driCreateNewScreen function.
 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
 *          the client-side driver on success, or \c NULL on failure.
 * 
 * \todo This function needs to be modified to remove context-modes from the
 *       list stored in the \c __GLXscreenConfigsRec to match the list
 *       returned by the client-side driver.
 */
static void *
CallCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc,
		    __DRIdisplay * driDpy,
		    PFNCREATENEWSCREENFUNC createNewScreen)
{
    __DRIscreenPrivate *psp = NULL;
#ifndef GLX_USE_APPLEGL
    drm_handle_t hSAREA;
    drmAddress pSAREA = MAP_FAILED;
    char *BusID;
    __DRIversion   ddx_version;
    __DRIversion   dri_version;
    __DRIversion   drm_version;
    __DRIframebuffer  framebuffer;
    int   fd = -1;
    int   status;
    const char * err_msg;
    const char * err_extra;
    int api_ver = __glXGetInternalVersion();


    dri_version.major = driDpy->private->driMajor;
    dri_version.minor = driDpy->private->driMinor;
    dri_version.patch = driDpy->private->driPatch;


    err_msg = "XF86DRIOpenConnection";
    err_extra = NULL;

    framebuffer.base = MAP_FAILED;
    framebuffer.dev_priv = NULL;

    if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
	fd = drmOpen(NULL,BusID);
	Xfree(BusID); /* No longer needed */

	err_msg = "open DRM";
	err_extra = strerror( -fd );

	if (fd >= 0) {
	    drm_magic_t magic;

	    err_msg = "drmGetMagic";
	    err_extra = NULL;

	    if (!drmGetMagic(fd, &magic)) {
		drmVersionPtr version = drmGetVersion(fd);
		if (version) {
		    drm_version.major = version->version_major;
		    drm_version.minor = version->version_minor;
		    drm_version.patch = version->version_patchlevel;
		    drmFreeVersion(version);
		}
		else {
		    drm_version.major = -1;
		    drm_version.minor = -1;
		    drm_version.patch = -1;
		}
{'fraction_non_alphanumeric': 0.11878237076126258, 'fraction_numerical': 0.007231505912244698, 'mean_word_length': 3.4482721147576614, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 257, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6397388', 'n_tokens_mistral': 14757, 'n_tokens_neox': 13752, 'n_words': 3601}