From: Jon Smirl Date: Tue, 21 Oct 2003 06:05:39 +0000 (+0000) Subject: Update DRI drivers to current DRI CVS and make them work. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bcc6eddd335e97d49ed2ef3a1440f94d58dce12d;p=mesa.git Update DRI drivers to current DRI CVS and make them work. --- diff --git a/Make-config b/Make-config index 0e3f55d0f45..bb6b153b9c5 100644 --- a/Make-config +++ b/Make-config @@ -721,7 +721,7 @@ linux-solo: "CFLAGS = -g -std=c99 -pedantic -fPIC -ffast-math -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE" \ "CXXFLAGS = -g -std=c99 -pedantic -fPIC -ffast-math -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE" \ "GLUT_CFLAGS = -fexceptions" \ - "GL_LIB_DEPS = -lm -lpthread" \ + "GL_LIB_DEPS = -lm -lpthread -lexpat" \ "GLU_LIB_DEPS = -L$(TOP)/lib -lGL -lm -Wl,-rpath,$(TOP)/lib" \ "GLUT_LIB_DEPS = -L$(TOP)/lib -lGLU -lGL -lm -Wl,-rpath,$(TOP)/lib" \ "APP_LIB_DEPS = -L$(TOP)/lib -lglut -lGLU -lGL -lm -lpthread -Wl,-rpath,$(TOP)/lib" diff --git a/src/glx/mini/dri_util.h b/src/glx/mini/dri_util.h index b653b3c4316..7c0a640e555 100644 --- a/src/glx/mini/dri_util.h +++ b/src/glx/mini/dri_util.h @@ -488,6 +488,12 @@ struct __DRIscreenPrivateRec { * the drawable that was bound. Otherwise, this is NULL. */ __DRIdrawablePrivate *fullscreen; + + + /** + * \brief Screen number for when multiple screens are supported + */ + int myNum; }; extern void diff --git a/src/glx/mini/miniglx.c b/src/glx/mini/miniglx.c index 25c7b963624..15563df3f3e 100644 --- a/src/glx/mini/miniglx.c +++ b/src/glx/mini/miniglx.c @@ -31,7 +31,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* $Id: miniglx.c,v 1.1 2003/08/22 20:11:43 brianp Exp $ */ +/* $Id: miniglx.c,v 1.2 2003/10/21 06:05:40 jonsmirl Exp $ */ /** * \mainpage Mini GLX @@ -732,7 +732,7 @@ static int get_chipset_from_busid( Display *dpy ) nr = sscanf(buf, "%04x\t%04x%04x", &encode, &vendor, &device); - bus = encode >> 16; + bus = encode >> 8; dev = (encode & 0xFF) >> 3; fn = encode & 0x7; diff --git a/src/mesa/drivers/dri/common/mm.c b/src/mesa/drivers/dri/common/mm.c index b3be95471d5..6572ccd9914 100644 --- a/src/mesa/drivers/dri/common/mm.c +++ b/src/mesa/drivers/dri/common/mm.c @@ -27,14 +27,13 @@ #include #include "mm.h" -#include "hwlog.h" void mmDumpMemInfo( memHeap_t *heap ) { TMemBlock *p; - fprintf(stderr, "Memory heap %p:\n", heap); + fprintf(stderr, "Memory heap %p:\n", (void *)heap); if (heap == 0) { fprintf(stderr, " heap == 0\n"); } else { diff --git a/src/mesa/drivers/dri/common/texmem.c b/src/mesa/drivers/dri/common/texmem.c index a8878b694d6..4ed05219db9 100644 --- a/src/mesa/drivers/dri/common/texmem.c +++ b/src/mesa/drivers/dri/common/texmem.c @@ -1,6 +1,6 @@ /* * Copyright 2000-2001 VA Linux Systems, Inc. - * (c) Copyright IBM Corporation 2002 + * (C) Copyright IBM Corporation 2002, 2003 * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -46,6 +46,7 @@ #include "texmem.h" #include "simple_list.h" #include "imports.h" +#include "macros.h" #include @@ -156,22 +157,22 @@ static void printLocalLRU( driTexHeap * heap, const char *callername ) continue; if (!t->tObj) { fprintf( stderr, "Placeholder (%p) %d at 0x%x sz 0x%x\n", - t, + (void *)t, t->memBlock->ofs / sz, t->memBlock->ofs, t->memBlock->size ); } else { fprintf( stderr, "Texture (%p) at 0x%x sz 0x%x\n", - t, + (void *)t, t->memBlock->ofs, t->memBlock->size ); } } foreach ( t, heap->swapped_objects ) { if (!t->tObj) { - fprintf( stderr, "Swapped Placeholder (%p)\n", t ); + fprintf( stderr, "Swapped Placeholder (%p)\n", (void *)t ); } else { - fprintf( stderr, "Swapped Texture (%p)\n", t ); + fprintf( stderr, "Swapped Texture (%p)\n", (void *)t ); } } @@ -190,7 +191,7 @@ static void printGlobalLRU( driTexHeap * heap, const char *callername ) int i, j; fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n", - __FUNCTION__, callername, heap->heapId, list ); + __FUNCTION__, callername, heap->heapId, (void *)list ); for ( i = 0, j = heap->nrRegions ; i < heap->nrRegions ; i++ ) { fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n", @@ -323,9 +324,9 @@ void driDestroyTextureObject( driTextureObject * t ) if ( 0 ) { fprintf( stderr, "[%s:%d] freeing %p (tObj = %p, DriverData = %p)\n", __FILE__, __LINE__, - t, - (t != NULL) ? t->tObj : NULL, - (t != NULL && t->tObj != NULL) ? t->tObj->DriverData : NULL ); + (void *)t, + (void *)((t != NULL) ? t->tObj : NULL), + (void *)((t != NULL && t->tObj != NULL) ? t->tObj->DriverData : NULL )); } if ( t != NULL ) { @@ -355,7 +356,7 @@ void driDestroyTextureObject( driTextureObject * t ) } if ( 0 ) { - fprintf( stderr, "[%s:%d] done freeing %p\n", __FILE__, __LINE__, t ); + fprintf( stderr, "[%s:%d] done freeing %p\n", __FILE__, __LINE__, (void *)t ); } } @@ -645,7 +646,7 @@ driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, if ( 0 ) fprintf( stderr, "%s( %u, %p, %u, %u, %u )\n", __FUNCTION__, - heap_id, context, size, alignmentShift, nr_regions ); + heap_id, (void *)context, size, alignmentShift, nr_regions ); heap = (driTexHeap *) CALLOC( sizeof( driTexHeap ) ); if ( heap != NULL ) { @@ -688,7 +689,7 @@ driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, if ( 0 ) - fprintf( stderr, "%s returning %p\n", __FUNCTION__, heap ); + fprintf( stderr, "%s returning %p\n", __FUNCTION__, (void *)heap ); return heap; } @@ -894,7 +895,7 @@ get_max_size( unsigned nr_heaps, /** * Given the amount of texture memory, the number of texture units, and the * maximum size of a texel, calculate the maximum texture size the driver can - * adverteise. + * advertise. * * \param heaps Texture heaps for this card * \param nr_heap Number of texture heaps @@ -1097,7 +1098,7 @@ driValidateTextureHeaps( driTexHeap * const * texture_heaps, if ( !check_in_heap( t, heap ) ) { fprintf( stderr, "%s memory block for texture object @ %p not " "found in heap #%d\n", - __FUNCTION__, t, i ); + __FUNCTION__, (void *)t, i ); return GL_FALSE; } @@ -1105,7 +1106,7 @@ driValidateTextureHeaps( driTexHeap * const * texture_heaps, if ( t->totalSize > t->memBlock->size ) { fprintf( stderr, "%s: Memory block for texture object @ %p is " "only %u bytes, but %u are required\n", - __FUNCTION__, t, t->totalSize, t->memBlock->size ); + __FUNCTION__, (void *)t, t->totalSize, t->memBlock->size ); return GL_FALSE; } @@ -1159,15 +1160,76 @@ driValidateTextureHeaps( driTexHeap * const * texture_heaps, foreach ( t, swapped ) { if ( t->memBlock != NULL ) { fprintf( stderr, "%s: Swapped texobj %p has non-NULL memblock %p\n", - __FUNCTION__, t, t->memBlock ); + __FUNCTION__, (void *)t, (void *)t->memBlock ); return GL_FALSE; } i++; } #if 0 - fprintf( stderr, "%s: swapped texture count = %u\n", i ); + fprintf( stderr, "%s: swapped texture count = %u\n", __FUNCTION__, i ); #endif return GL_TRUE; } + + + + +/****************************************************************************/ +/** + * Compute which mipmap levels that really need to be sent to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + */ + +void +driCalculateTextureFirstLastLevel( driTextureObject * t ) +{ + struct gl_texture_object * const tObj = t->tObj; + const struct gl_texture_image * const baseImage = + tObj->Image[tObj->BaseLevel]; + + /* These must be signed values. MinLod and MaxLod can be negative numbers, + * and having firstLevel and lastLevel as signed prevents the need for + * extra sign checks. + */ + int firstLevel; + int lastLevel; + + /* Yes, this looks overly complicated, but it's all needed. + */ + + switch (tObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { + /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. + */ + + firstLevel = lastLevel = tObj->BaseLevel; + } + else { + firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5); + firstLevel = MAX2(firstLevel, tObj->BaseLevel); + lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); + lastLevel = MAX2(lastLevel, t->tObj->BaseLevel); + lastLevel = MIN2(lastLevel, t->tObj->BaseLevel + baseImage->MaxLog2); + lastLevel = MIN2(lastLevel, t->tObj->MaxLevel); + lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */ + } + break; + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_4D_SGIS: + firstLevel = lastLevel = 0; + break; + default: + return; + } + + /* save these values */ + t->firstLevel = firstLevel; + t->lastLevel = lastLevel; +} diff --git a/src/mesa/drivers/dri/common/texmem.h b/src/mesa/drivers/dri/common/texmem.h index 7199704612a..9afbb0c865b 100644 --- a/src/mesa/drivers/dri/common/texmem.h +++ b/src/mesa/drivers/dri/common/texmem.h @@ -290,4 +290,6 @@ void driInitTextureObjects( GLcontext *ctx, driTextureObject * swapped, GLboolean driValidateTextureHeaps( driTexHeap * const * texture_heaps, unsigned nr_heaps, const driTextureObject * swapped ); +extern void driCalculateTextureFirstLastLevel( driTextureObject * t ); + #endif /* DRI_TEXMEM_H */ diff --git a/src/mesa/drivers/dri/common/vblank.c b/src/mesa/drivers/dri/common/vblank.c index e91dd65260c..d20f743bc9a 100644 --- a/src/mesa/drivers/dri/common/vblank.c +++ b/src/mesa/drivers/dri/common/vblank.c @@ -33,6 +33,7 @@ #include "macros.h" #include "dd.h" #include "vblank.h" +#include "xmlpool.h" /****************************************************************************/ @@ -127,7 +128,7 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv, if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) { /* FIXME: This doesn't seem like the right thing to return here. */ -#ifndef _SOLO +#ifndef _SOLO return GLX_BAD_CONTEXT; #else return -1; @@ -163,9 +164,9 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv, /* FIXME: This doesn't seem like the right thing to return here. */ #ifndef _SOLO - return GLX_BAD_CONTEXT; + return GLX_BAD_CONTEXT; #else - return -1; + return -1; #endif } } @@ -183,25 +184,56 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv, /****************************************************************************/ /** * Gets a set of default vertical-blank-wait flags based on the internal GLX - * API version and several environment variables. + * API version and several configuration options. */ -GLuint driGetDefaultVBlankFlags( void ) +GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache ) { GLuint flags = 0; - + int vblank_mode; flags |= (driCompareGLXAPIVersion( 20030317 ) >= 0) ? VBLANK_FLAG_INTERVAL : 0; - flags |= (getenv("LIBGL_SYNC_REFRESH") != NULL) - ? VBLANK_FLAG_SYNC : 0; - flags |= (getenv("LIBGL_THROTTLE_REFRESH") != NULL) - ? VBLANK_FLAG_THROTTLE : 0; + + if ( driCheckOption( optionCache, "vblank_mode", DRI_ENUM ) ) + vblank_mode = driQueryOptioni( optionCache, "vblank_mode" ); + else + vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; + + switch (vblank_mode) { + case DRI_CONF_VBLANK_NEVER: + flags = 0; + break; + case DRI_CONF_VBLANK_DEF_INTERVAL_0: + break; + case DRI_CONF_VBLANK_DEF_INTERVAL_1: + flags |= VBLANK_FLAG_THROTTLE; + break; + case DRI_CONF_VBLANK_ALWAYS_SYNC: + flags |= VBLANK_FLAG_SYNC; + break; + } return flags; } +/****************************************************************************/ +/** + * Sets the default swap interval when the drawable is first bound to a + * direct rendering context. + */ + +void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags ) +{ +#ifndef _SOLO + if ( priv->pdraw->swap_interval == (unsigned)-1 ) { + priv->pdraw->swap_interval = (flags & VBLANK_FLAG_THROTTLE) != 0 ? 1 : 0; + } +#endif +} + + /****************************************************************************/ /** * Wrapper to call \c drmWaitVBlank. The main purpose of this function is to @@ -265,7 +297,10 @@ driWaitForVBlank( const __DRIdrawablePrivate *priv, GLuint * vbl_seq, *missed_deadline = GL_FALSE; - if ( (flags & VBLANK_FLAG_NO_IRQ) != 0 ) { + if ( (flags & (VBLANK_FLAG_INTERVAL | + VBLANK_FLAG_THROTTLE | + VBLANK_FLAG_SYNC)) == 0 || + (flags & VBLANK_FLAG_NO_IRQ) != 0 ) { return 0; } @@ -293,11 +328,14 @@ driWaitForVBlank( const __DRIdrawablePrivate *priv, GLuint * vbl_seq, vbl.request.type = DRM_VBLANK_ABSOLUTE; if ( (flags & VBLANK_FLAG_INTERVAL) != 0 ) { -#ifndef _SOLO +#ifndef _SOLO interval = priv->pdraw->swap_interval; #else interval = 0; -#endif +#endif + /* this must have been initialized when the drawable was first bound + * to a direct rendering context. */ + assert ( interval != (unsigned)-1 ); } else if ( (flags & VBLANK_FLAG_THROTTLE) != 0 ) { interval = 1; diff --git a/src/mesa/drivers/dri/common/vblank.h b/src/mesa/drivers/dri/common/vblank.h index 3dab4ead3c2..d460d7a84ad 100644 --- a/src/mesa/drivers/dri/common/vblank.h +++ b/src/mesa/drivers/dri/common/vblank.h @@ -32,6 +32,7 @@ #include "context.h" #include "dri_util.h" +#include "xmlconfig.h" #define VBLANK_FLAG_INTERVAL (1U << 0) /* Respect the swap_interval setting */ @@ -45,7 +46,8 @@ extern int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count ); extern int driWaitForMSC32( __DRIdrawablePrivate *priv, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t * msc ); -extern GLuint driGetDefaultVBlankFlags( void ); +extern GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache ); +extern void driDrawableInitVBlank ( __DRIdrawablePrivate *priv, GLuint flags ); extern int driWaitForVBlank( const __DRIdrawablePrivate *priv, GLuint * vbl_seq, GLuint flags, GLboolean * missed_deadline ); diff --git a/src/mesa/drivers/dri/common/xmlconfig.c b/src/mesa/drivers/dri/common/xmlconfig.c new file mode 100644 index 00000000000..a6d4c8ab941 --- /dev/null +++ b/src/mesa/drivers/dri/common/xmlconfig.c @@ -0,0 +1,862 @@ +/* + * XML DRI client-side driver configuration + * Copyright (C) 2003 Felix Kuehling + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +/** + * \file xmlconfig.c + * \brief Driver-independent client-side part of the XML configuration + * \author Felix Kuehling + */ + +#include "glheader.h" + +#include +#include +#include +#include +#include +#include +#include "imports.h" +#include "dri_util.h" +#include "xmlconfig.h" + +/* + * OS dependent ways of getting the name of the running program + */ +#if (defined(__unix__) || defined(unix)) && !defined(USG) +#include +#endif + +#undef GET_PROGRAM_NAME + +#if defined(__GNU_LIBRARY__) || defined(__GLIBC__) +# define GET_PROGRAM_NAME() program_invocation_short_name +#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2) +# include +# if (__FreeBSD_version >= 440000) +# include +# define GET_PROGRAM_NAME() getprogname() +# endif +#elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100) +# include +# define GET_PROGRAM_NAME() getprogname() +#endif + +#if !defined(GET_PROGRAM_NAME) +# if defined(OpenBSD) || defined(NetBSD) +/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU. It's + * used as a last resort, if there is no documented facility available. */ +static const char *__getProgramName () { + extern const char *__progname; + return progname; +} +# define GET_PROGRAM_NAME() __getProgramName() +# else +# define GET_PROGRAM_NAME() "" +# warning "Per application configuration won't with your OS version work." +# endif +#endif + +/** \brief Find an option in an option cache with the name as key */ +static GLuint findOption (const driOptionCache *cache, const char *name) { + GLuint len = strlen (name); + GLuint size = 1 << cache->tableSize, mask = size - 1; + GLuint hash = 0; + GLuint i, shift; + + /* compute a hash from the variable length name */ + for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31) + hash += (GLuint)name[i] << shift; + hash *= hash; + hash = (hash >> (16-cache->tableSize/2)) & mask; + + /* this is just the starting point of the linear search for the option */ + for (i = 0; i < size; ++i, hash = (hash+1) & mask) { + /* if we hit an empty entry then the option is not defined (yet) */ + if (cache->info[hash].name == 0) + break; + else if (!strcmp (name, cache->info[hash].name)) + break; + } + /* this assertion fails if the hash table is full */ + assert (i < size); + + return hash; +} + +/** \brief Count the real number of options in an option cache */ +static GLuint countOptions (const driOptionCache *cache) { + GLuint size = 1 << cache->tableSize; + GLuint i, count = 0; + for (i = 0; i < size; ++i) + if (cache->info[i].name) + count++; + return count; +} + +/** \brief Like strdup but using MALLOC and with error checking. */ +#define XSTRDUP(dest,source) do { \ + GLuint len = strlen (source); \ + if (!(dest = MALLOC (len+1))) { \ + fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \ + abort(); \ + } \ + memcpy (dest, source, len+1); \ +} while (0) + +static int compare (const void *a, const void *b) { + return strcmp (*(char *const*)a, *(char *const*)b); +} +/** \brief Binary search in a string array. */ +static GLuint bsearchStr (const XML_Char *name, + const XML_Char *elems[], GLuint count) { + const XML_Char **found; + found = bsearch (&name, elems, count, sizeof (XML_Char *), compare); + if (found) + return found - elems; + else + return count; +} + +/** \brief Parse a value of a given type. */ +static GLboolean parseValue (driOptionValue *v, driOptionType type, + const XML_Char *string) { + const XML_Char *tail; + /* skip leading white-space */ + string += strspn (string, " \f\n\r\t\v"); + switch (type) { + case DRI_BOOL: + if (!strcmp (string, "false")) { + v->_bool = GL_FALSE; + tail = string + 5; + } else if (!strcmp (string, "true")) { + v->_bool = GL_TRUE; + tail = string + 4; + } + else + return GL_FALSE; + break; + case DRI_ENUM: /* enum is just a special integer */ + case DRI_INT: + v->_int = strtol (string, (char **)&tail, 0); + break; + case DRI_FLOAT: + v->_float = strtod (string, (char **)&tail); + break; + } + + if (tail == string) + return GL_FALSE; /* empty string (or containing only white-space) */ + /* skip trailing white space */ + if (*tail) + tail += strspn (tail, " \f\n\r\t\v"); + if (*tail) + return GL_FALSE; /* something left over that is not part of value */ + + return GL_TRUE; +} + +/** \brief Parse a list of ranges of type info->type. */ +static GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) { + XML_Char *cp, *range; + GLuint nRanges, i; + driOptionRange *ranges; + + XSTRDUP (cp, string); + /* pass 1: determine the number of ranges (number of commas + 1) */ + range = cp; + for (nRanges = 1; *range; ++range) + if (*range == ',') + ++nRanges; + + if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) { + fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); + abort(); + } + + /* pass 2: parse all ranges into preallocated array */ + range = cp; + for (i = 0; i < nRanges; ++i) { + XML_Char *end, *sep; + assert (range); + end = strchr (range, ','); + if (end) + *end = '\0'; + sep = strchr (range, ':'); + if (sep) { /* non-empty interval */ + *sep = '\0'; + if (!parseValue (&ranges[i].start, info->type, range) || + !parseValue (&ranges[i].end, info->type, sep+1)) + break; + if (info->type == DRI_INT && + ranges[i].start._int > ranges[i].end._int) + break; + if (info->type == DRI_FLOAT && + ranges[i].start._float > ranges[i].end._float) + break; + } else { /* empty interval */ + if (!parseValue (&ranges[i].start, info->type, range)) + break; + ranges[i].end = ranges[i].start; + } + if (end) + range = end+1; + else + range = NULL; + } + FREE (cp); + if (i < nRanges) { + FREE (ranges); + return GL_FALSE; + } else + assert (range == NULL); + + info->nRanges = nRanges; + info->ranges = ranges; + return GL_TRUE; +} + +/** \brief Check if a value is in one of info->ranges. */ +static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) { + GLuint i; + assert (info->type != DRI_BOOL); /* should be caught by the parser */ + if (info->nRanges == 0) + return GL_TRUE; + switch (info->type) { + case DRI_ENUM: /* enum is just a special integer */ + case DRI_INT: + for (i = 0; i < info->nRanges; ++i) + if (v->_int >= info->ranges[i].start._int && + v->_int <= info->ranges[i].end._int) + return GL_TRUE; + break; + case DRI_FLOAT: + for (i = 0; i < info->nRanges; ++i) + if (v->_float >= info->ranges[i].start._float && + v->_float <= info->ranges[i].end._float) + return GL_TRUE; + break; + default: + assert (0); /* should never happen */ + } + return GL_FALSE; +} + +/** \brief Output a warning message. */ +#define XML_WARNING1(msg) do {\ + __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser)); \ +} while (0) +#define XML_WARNING(msg,args...) do { \ + __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser), \ + args); \ +} while (0) +/** \brief Output an error message. */ +#define XML_ERROR1(msg) do { \ + __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser)); \ +} while (0) +#define XML_ERROR(msg,args...) do { \ + __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser), \ + args); \ +} while (0) +/** \brief Output a fatal error message and abort. */ +#define XML_FATAL1(msg) do { \ + fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \ + data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser)); \ + abort();\ +} while (0) +#define XML_FATAL(msg,args...) do { \ + fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \ + data->name, \ + XML_GetCurrentLineNumber(data->parser), \ + XML_GetCurrentColumnNumber(data->parser), \ + args); \ + abort();\ +} while (0) + +/** \brief Parser context for __driConfigOptions. */ +struct OptInfoData { + const char *name; + XML_Parser parser; + driOptionCache *cache; + GLboolean inDriInfo; + GLboolean inSection; + GLboolean inDesc; + GLboolean inOption; + GLboolean inEnum; + int curOption; +}; + +/** \brief Elements in __driConfigOptions. */ +enum OptInfoElem { + OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT +}; +static const XML_Char *OptInfoElems[] = { + "description", "driinfo", "enum", "option", "section" +}; + +/** \brief Parse attributes of an enum element. + * + * We're not actually interested in the data. Just make sure this is ok + * for external configuration tools. + */ +static void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) { + GLuint i; + const XML_Char *value = NULL, *text = NULL; + driOptionValue v; + GLuint opt = data->curOption; + for (i = 0; attr[i]; i += 2) { + if (!strcmp (attr[i], "value")) value = attr[i+1]; + else if (!strcmp (attr[i], "text")) text = attr[i+1]; + else XML_FATAL("illegal enum attribute: %s.", attr[i]); + } + if (!value) XML_FATAL1 ("value attribute missing in enum."); + if (!text) XML_FATAL1 ("text attribute missing in enum."); + if (!parseValue (&v, data->cache->info[opt].type, value)) + XML_FATAL ("illegal enum value: %s.", value); + if (!checkValue (&v, &data->cache->info[opt])) + XML_FATAL ("enum value out of valid range: %s.", value); +} + +/** \brief Parse attributes of a description element. + * + * We're not actually interested in the data. Just make sure this is ok + * for external configuration tools. + */ +static void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) { + GLuint i; + const XML_Char *lang = NULL, *text = NULL; + for (i = 0; attr[i]; i += 2) { + if (!strcmp (attr[i], "lang")) lang = attr[i+1]; + else if (!strcmp (attr[i], "text")) text = attr[i+1]; + else XML_FATAL("illegal description attribute: %s.", attr[i]); + } + if (!lang) XML_FATAL1 ("lang attribute missing in description."); + if (!text) XML_FATAL1 ("text attribute missing in description."); +} + +/** \brief Parse attributes of an option element. */ +static void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) { + enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT}; + static const XML_Char *optAttr[] = {"default", "name", "type", "valid"}; + const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL}; + const char *defaultVal; + driOptionCache *cache = data->cache; + GLuint opt, i; + for (i = 0; attr[i]; i += 2) { + GLuint attrName = bsearchStr (attr[i], optAttr, OA_COUNT); + if (attrName >= OA_COUNT) + XML_FATAL ("illegal option attribute: %s", attr[i]); + attrVal[attrName] = attr[i+1]; + } + if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option."); + if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option."); + if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option."); + + opt = findOption (cache, attrVal[OA_NAME]); + if (cache->info[opt].name) + XML_FATAL ("option %s redefined.", attrVal[OA_NAME]); + data->curOption = opt; + + XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]); + + if (!strcmp (attrVal[OA_TYPE], "bool")) + cache->info[opt].type = DRI_BOOL; + else if (!strcmp (attrVal[OA_TYPE], "enum")) + cache->info[opt].type = DRI_ENUM; + else if (!strcmp (attrVal[OA_TYPE], "int")) + cache->info[opt].type = DRI_INT; + else if (!strcmp (attrVal[OA_TYPE], "float")) + cache->info[opt].type = DRI_FLOAT; + else + XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]); + + defaultVal = getenv (cache->info[opt].name); + if (defaultVal != NULL) { + /* don't use XML_WARNING, we want the user to see this! */ + fprintf (stderr, + "ATTENTION: default value of option %s overridden by environment.\n", + cache->info[opt].name); + } else + defaultVal = attrVal[OA_DEFAULT]; + if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal)) + XML_FATAL ("illegal default value: %s.", defaultVal); + + if (attrVal[OA_VALID]) { + if (cache->info[opt].type == DRI_BOOL) + XML_FATAL1 ("boolean option with valid attribute."); + if (!parseRanges (&cache->info[opt], attrVal[OA_VALID])) + XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]); + if (!checkValue (&cache->values[opt], &cache->info[opt])) + XML_FATAL ("default value out of valid range '%s': %s.", + attrVal[OA_VALID], defaultVal); + } else if (cache->info[opt].type == DRI_ENUM) { + XML_FATAL1 ("valid attribute missing in option (mandatory for enums)."); + } else { + cache->info[opt].nRanges = 0; + cache->info[opt].ranges = NULL; + } +} + +/** \brief Handler for start element events. */ +static void optInfoStartElem (void *userData, const XML_Char *name, + const XML_Char **attr) { + struct OptInfoData *data = (struct OptInfoData *)userData; + enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT); + switch (elem) { + case OI_DRIINFO: + if (data->inDriInfo) + XML_FATAL1 ("nested elements."); + if (attr[0]) + XML_FATAL1 ("attributes specified on element."); + data->inDriInfo = GL_TRUE; + break; + case OI_SECTION: + if (!data->inDriInfo) + XML_FATAL1 ("
must be inside ."); + if (data->inSection) + XML_FATAL1 ("nested
elements."); + if (attr[0]) + XML_FATAL1 ("attributes specified on
element."); + data->inSection = GL_TRUE; + break; + case OI_DESCRIPTION: + if (!data->inSection && !data->inOption) + XML_FATAL1 (" must be inside or inDesc) + XML_FATAL1 ("nested elements."); + data->inDesc = GL_TRUE; + parseDescAttr (data, attr); + break; + case OI_OPTION: + if (!data->inSection) + XML_FATAL1 ("