17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
54a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
273464ebd5Sriastradh/**
283464ebd5Sriastradh * \file
293464ebd5Sriastradh * \brief Extension handling
303464ebd5Sriastradh */
313464ebd5Sriastradh
321463c08dSmrg#include "util/os_misc.h"
333464ebd5Sriastradh
347117f1b4Smrg#include "glheader.h"
351463c08dSmrg
367117f1b4Smrg#include "context.h"
377117f1b4Smrg#include "extensions.h"
38af69d88dSmrg#include "macros.h"
397117f1b4Smrg#include "mtypes.h"
407117f1b4Smrg
41af69d88dSmrgstruct gl_extensions _mesa_extension_override_enables;
42af69d88dSmrgstruct gl_extensions _mesa_extension_override_disables;
433464ebd5Sriastradh
441463c08dSmrg#define MAX_UNRECOGNIZED_EXTENSIONS 16
451463c08dSmrgstatic struct {
461463c08dSmrg   char *env;
471463c08dSmrg   const char *names[MAX_UNRECOGNIZED_EXTENSIONS];
481463c08dSmrg} unrecognized_extensions;
493464ebd5Sriastradh
503464ebd5Sriastradh/**
513464ebd5Sriastradh * Given a member \c x of struct gl_extensions, return offset of
523464ebd5Sriastradh * \c x in bytes.
533464ebd5Sriastradh */
543464ebd5Sriastradh#define o(x) offsetof(struct gl_extensions, x)
553464ebd5Sriastradh
561463c08dSmrgstatic int
571463c08dSmrgextension_name_compare(const void *name, const void *elem)
581463c08dSmrg{
591463c08dSmrg   const struct mesa_extension *entry = elem;
601463c08dSmrg   return strcmp(name, entry->name);
611463c08dSmrg}
621463c08dSmrg
633464ebd5Sriastradh/**
643464ebd5Sriastradh * Given an extension name, lookup up the corresponding member of struct
657e995a2eSmrg * gl_extensions and return that member's index.  If the name is
667e995a2eSmrg * not found in the \c _mesa_extension_table, return -1.
673464ebd5Sriastradh *
683464ebd5Sriastradh * \param name Name of extension.
697e995a2eSmrg * \return Index of member in struct gl_extensions.
703464ebd5Sriastradh */
717e995a2eSmrgstatic int
727e995a2eSmrgname_to_index(const char* name)
733464ebd5Sriastradh{
741463c08dSmrg   const struct mesa_extension *entry;
753464ebd5Sriastradh
761463c08dSmrg   if (!name)
777e995a2eSmrg      return -1;
783464ebd5Sriastradh
791463c08dSmrg   entry = bsearch(name,
801463c08dSmrg                   _mesa_extension_table, MESA_EXTENSION_COUNT,
811463c08dSmrg                   sizeof(_mesa_extension_table[0]),
821463c08dSmrg                   extension_name_compare);
831463c08dSmrg
841463c08dSmrg   if (entry)
851463c08dSmrg      return entry - _mesa_extension_table;
863464ebd5Sriastradh
877e995a2eSmrg   return -1;
883464ebd5Sriastradh}
893464ebd5Sriastradh
903464ebd5Sriastradh/**
91af69d88dSmrg * Overrides extensions in \c ctx based on the values in
92af69d88dSmrg * _mesa_extension_override_enables and _mesa_extension_override_disables.
933464ebd5Sriastradh */
947e995a2eSmrgvoid
957e995a2eSmrg_mesa_override_extensions(struct gl_context *ctx)
96af69d88dSmrg{
977e995a2eSmrg   unsigned i;
98af69d88dSmrg   const GLboolean *enables =
99af69d88dSmrg      (GLboolean*) &_mesa_extension_override_enables;
100af69d88dSmrg   const GLboolean *disables =
101af69d88dSmrg      (GLboolean*) &_mesa_extension_override_disables;
102af69d88dSmrg   GLboolean *ctx_ext = (GLboolean*)&ctx->Extensions;
103af69d88dSmrg
1047e995a2eSmrg   for (i = 0; i < MESA_EXTENSION_COUNT; ++i) {
1057e995a2eSmrg      size_t offset = _mesa_extension_table[i].offset;
1067e995a2eSmrg
107af69d88dSmrg      assert(!enables[offset] || !disables[offset]);
108af69d88dSmrg      if (enables[offset]) {
109af69d88dSmrg         ctx_ext[offset] = 1;
110af69d88dSmrg      } else if (disables[offset]) {
111af69d88dSmrg         ctx_ext[offset] = 0;
112af69d88dSmrg      }
113af69d88dSmrg   }
114af69d88dSmrg}
1153464ebd5Sriastradh
1167117f1b4Smrg
1177117f1b4Smrg/**
1187117f1b4Smrg * Enable all extensions suitable for a software-only renderer.
1191463c08dSmrg * This is a convenience function used by the mesa/swrast drivers.
1207117f1b4Smrg */
1217117f1b4Smrgvoid
1223464ebd5Sriastradh_mesa_enable_sw_extensions(struct gl_context *ctx)
1237117f1b4Smrg{
1244a49301eSmrg   ctx->Extensions.ARB_depth_clamp = GL_TRUE;
1257117f1b4Smrg   ctx->Extensions.ARB_depth_texture = GL_TRUE;
1264a49301eSmrg   ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
1273464ebd5Sriastradh   ctx->Extensions.ARB_draw_instanced = GL_TRUE;
1283464ebd5Sriastradh   ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
129cdc920a0Smrg   ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
1307117f1b4Smrg   ctx->Extensions.ARB_fragment_program = GL_TRUE;
131c1f859d4Smrg   ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
1327117f1b4Smrg   ctx->Extensions.ARB_fragment_shader = GL_TRUE;
1334a49301eSmrg   ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
134cdc920a0Smrg   ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
1354a49301eSmrg   ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
1367117f1b4Smrg   ctx->Extensions.ARB_occlusion_query = GL_TRUE;
1373464ebd5Sriastradh   ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
1387117f1b4Smrg   ctx->Extensions.ARB_point_sprite = GL_TRUE;
1397117f1b4Smrg   ctx->Extensions.ARB_shadow = GL_TRUE;
1407117f1b4Smrg   ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
141af69d88dSmrg   ctx->Extensions.ARB_texture_compression_bptc = GL_TRUE;
1427117f1b4Smrg   ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
1437117f1b4Smrg   ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
1447117f1b4Smrg   ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
1457117f1b4Smrg   ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
1467e995a2eSmrg   ctx->Extensions.ARB_texture_filter_anisotropic = GL_TRUE;
147af69d88dSmrg   ctx->Extensions.ARB_texture_float = GL_TRUE;
148af69d88dSmrg   ctx->Extensions.ARB_texture_mirror_clamp_to_edge = GL_TRUE;
1497117f1b4Smrg   ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
1503464ebd5Sriastradh   ctx->Extensions.ARB_texture_rg = GL_TRUE;
1513464ebd5Sriastradh   ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE;
1527117f1b4Smrg   ctx->Extensions.ARB_vertex_program = GL_TRUE;
1537117f1b4Smrg   ctx->Extensions.ARB_vertex_shader = GL_TRUE;
1544a49301eSmrg   ctx->Extensions.ARB_sync = GL_TRUE;
155cdc920a0Smrg   ctx->Extensions.APPLE_object_purgeable = GL_TRUE;
1567117f1b4Smrg   ctx->Extensions.ATI_fragment_shader = GL_TRUE;
1573464ebd5Sriastradh   ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE;
1587117f1b4Smrg   ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
1597117f1b4Smrg   ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
1607117f1b4Smrg   ctx->Extensions.EXT_blend_color = GL_TRUE;
1617117f1b4Smrg   ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
1627117f1b4Smrg   ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
1637117f1b4Smrg   ctx->Extensions.EXT_blend_minmax = GL_TRUE;
1647117f1b4Smrg   ctx->Extensions.EXT_depth_bounds_test = GL_TRUE;
165cdc920a0Smrg   ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
1667117f1b4Smrg   ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
1677117f1b4Smrg   ctx->Extensions.EXT_point_parameters = GL_TRUE;
1684a49301eSmrg   ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
169c1f859d4Smrg   ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
170cdc920a0Smrg   ctx->Extensions.EXT_texture_array = GL_TRUE;
1713464ebd5Sriastradh   ctx->Extensions.EXT_texture_compression_latc = GL_TRUE;
1727117f1b4Smrg   ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
1733464ebd5Sriastradh   ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE;
1747117f1b4Smrg   ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
1753464ebd5Sriastradh   ctx->Extensions.EXT_texture_shared_exponent = GL_TRUE;
1767117f1b4Smrg   ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
1773464ebd5Sriastradh   ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
1784a49301eSmrg   ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
1793464ebd5Sriastradh   /*ctx->Extensions.EXT_transform_feedback = GL_TRUE;*/
1804a49301eSmrg   ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
1817117f1b4Smrg   ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
182cdc920a0Smrg   ctx->Extensions.NV_conditional_render = GL_TRUE;
1834a49301eSmrg   ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
1847117f1b4Smrg   ctx->Extensions.NV_texture_rectangle = GL_TRUE;
1857117f1b4Smrg   ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
186af69d88dSmrg   ctx->Extensions.OES_standard_derivatives = GL_TRUE;
187af69d88dSmrg   ctx->Extensions.TDFX_texture_compression_FXT1 = GL_TRUE;
1887e995a2eSmrg   ctx->Extensions.ANGLE_texture_compression_dxt = GL_TRUE;
1897e995a2eSmrg   ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE;
1907117f1b4Smrg}
1917117f1b4Smrg
1927117f1b4Smrg/**
1937117f1b4Smrg * Either enable or disable the named extension.
194af69d88dSmrg * \return offset of extensions withint `ext' or 0 if extension is not known
1957117f1b4Smrg */
196af69d88dSmrgstatic size_t
1977e995a2eSmrgset_extension(struct gl_extensions *ext, int i, GLboolean state)
1987117f1b4Smrg{
1993464ebd5Sriastradh   size_t offset;
2007117f1b4Smrg
2017e995a2eSmrg   offset = i < 0 ? 0 : _mesa_extension_table[i].offset;
202af69d88dSmrg   if (offset != 0 && (offset != o(dummy_true) || state != GL_FALSE)) {
203af69d88dSmrg      ((GLboolean *) ext)[offset] = state;
2047117f1b4Smrg   }
2057117f1b4Smrg
206af69d88dSmrg   return offset;
207af69d88dSmrg}
2087117f1b4Smrg
2097117f1b4Smrg
210cdc920a0Smrg/**
2117e995a2eSmrg * \brief Free string pointed by unrecognized_extensions
212af69d88dSmrg *
2137e995a2eSmrg * This string is allocated early during the first context creation by
214af69d88dSmrg * _mesa_one_time_init_extension_overrides.
215cdc920a0Smrg */
216d63b28c1Smartinstatic void __attribute__((__destructor__))
217af69d88dSmrgfree_unknown_extensions_strings(void)
218cdc920a0Smrg{
2191463c08dSmrg   free(unrecognized_extensions.env);
2201463c08dSmrg   for (int i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i)
2211463c08dSmrg      unrecognized_extensions.names[i] = NULL;
222cdc920a0Smrg}
223cdc920a0Smrg
224cdc920a0Smrg
2257117f1b4Smrg/**
2267e995a2eSmrg * \brief Initialize extension override tables based on \c MESA_EXTENSION_OVERRIDE
2273464ebd5Sriastradh *
228af69d88dSmrg * This should be called one time early during first context initialization.
2297e995a2eSmrg
2307e995a2eSmrg * \c MESA_EXTENSION_OVERRIDE is a space-separated list of extensions to
2317e995a2eSmrg * enable or disable. The list is processed thus:
2327e995a2eSmrg *    - Enable recognized extension names that are prefixed with '+'.
2337e995a2eSmrg *    - Disable recognized extension names that are prefixed with '-'.
2347e995a2eSmrg *    - Enable recognized extension names that are not prefixed.
2357e995a2eSmrg *    - Collect unrecognized extension names in a new string.
2367117f1b4Smrg */
237af69d88dSmrgvoid
2381463c08dSmrg_mesa_one_time_init_extension_overrides(void)
2397117f1b4Smrg{
2401463c08dSmrg   const char *env_const = os_get_option("MESA_EXTENSION_OVERRIDE");
2413464ebd5Sriastradh   char *env;
2423464ebd5Sriastradh   char *ext;
243af69d88dSmrg   size_t offset;
2447e995a2eSmrg   unsigned unknown_ext = 0;
245af69d88dSmrg
246af69d88dSmrg   memset(&_mesa_extension_override_enables, 0, sizeof(struct gl_extensions));
247af69d88dSmrg   memset(&_mesa_extension_override_disables, 0, sizeof(struct gl_extensions));
2483464ebd5Sriastradh
2493464ebd5Sriastradh   if (env_const == NULL) {
250af69d88dSmrg      return;
2513464ebd5Sriastradh   }
2527117f1b4Smrg
2533464ebd5Sriastradh   /* Copy env_const because strtok() is destructive. */
2543464ebd5Sriastradh   env = strdup(env_const);
2557e995a2eSmrg
2567e995a2eSmrg   if (env == NULL)
2577e995a2eSmrg      return;
2587e995a2eSmrg
2593464ebd5Sriastradh   for (ext = strtok(env, " "); ext != NULL; ext = strtok(NULL, " ")) {
2603464ebd5Sriastradh      int enable;
2617e995a2eSmrg      int i;
262af69d88dSmrg      bool recognized;
2633464ebd5Sriastradh      switch (ext[0]) {
2643464ebd5Sriastradh      case '+':
2653464ebd5Sriastradh         enable = 1;
2663464ebd5Sriastradh         ++ext;
2673464ebd5Sriastradh         break;
2683464ebd5Sriastradh      case '-':
2693464ebd5Sriastradh         enable = 0;
2703464ebd5Sriastradh         ++ext;
2713464ebd5Sriastradh         break;
2723464ebd5Sriastradh      default:
2733464ebd5Sriastradh         enable = 1;
2743464ebd5Sriastradh         break;
2753464ebd5Sriastradh      }
276af69d88dSmrg
2777e995a2eSmrg      i = name_to_index(ext);
2787e995a2eSmrg      offset = set_extension(&_mesa_extension_override_enables, i, enable);
2797e995a2eSmrg      offset = set_extension(&_mesa_extension_override_disables, i, !enable);
2807e995a2eSmrg      if (offset != 0)
281af69d88dSmrg         recognized = true;
2827e995a2eSmrg      else
283af69d88dSmrg         recognized = false;
284af69d88dSmrg
2857e995a2eSmrg      if (!recognized && enable) {
2867e995a2eSmrg         if (unknown_ext >= MAX_UNRECOGNIZED_EXTENSIONS) {
2877e995a2eSmrg            static bool warned;
2887e995a2eSmrg
2897e995a2eSmrg            if (!warned) {
2907e995a2eSmrg               warned = true;
2911463c08dSmrg               _mesa_problem(NULL, "Trying to enable too many unknown extension. "
2921463c08dSmrg                                   "Only the first %d will be honoured",
2931463c08dSmrg                                   MAX_UNRECOGNIZED_EXTENSIONS);
2947e995a2eSmrg            }
2957e995a2eSmrg         } else {
2961463c08dSmrg            unrecognized_extensions.names[unknown_ext] = ext;
2977e995a2eSmrg            unknown_ext++;
2981463c08dSmrg            _mesa_problem(NULL, "Trying to enable unknown extension: %s", ext);
299af69d88dSmrg         }
3007117f1b4Smrg      }
3017117f1b4Smrg   }
3027117f1b4Smrg
3037e995a2eSmrg   if (!unknown_ext) {
3047e995a2eSmrg      free(env);
3057e995a2eSmrg   } else {
3061463c08dSmrg      unrecognized_extensions.env = env;
307af69d88dSmrg   }
3084a49301eSmrg}
3094a49301eSmrg
3104a49301eSmrg
3114a49301eSmrg/**
3123464ebd5Sriastradh * \brief Initialize extension tables and enable default extensions.
3133464ebd5Sriastradh *
3143464ebd5Sriastradh * This should be called during context initialization.
3153464ebd5Sriastradh * Note: Sets gl_extensions.dummy_true to true.
3164a49301eSmrg */
3173464ebd5Sriastradhvoid
318af69d88dSmrg_mesa_init_extensions(struct gl_extensions *extensions)
3194a49301eSmrg{
320af69d88dSmrg   GLboolean *base = (GLboolean *) extensions;
3213464ebd5Sriastradh   GLboolean *sentinel = base + o(extension_sentinel);
3223464ebd5Sriastradh   GLboolean *i;
3233464ebd5Sriastradh
3243464ebd5Sriastradh   /* First, turn all extensions off. */
3253464ebd5Sriastradh   for (i = base; i != sentinel; ++i)
3263464ebd5Sriastradh      *i = GL_FALSE;
3273464ebd5Sriastradh
3283464ebd5Sriastradh   /* Then, selectively turn default extensions on. */
329af69d88dSmrg   extensions->dummy_true = GL_TRUE;
3303464ebd5Sriastradh}
3314a49301eSmrg
3324a49301eSmrg
3333464ebd5Sriastradhtypedef unsigned short extension_index;
3344a49301eSmrg
3354a49301eSmrg
3367e995a2eSmrg/**
3377e995a2eSmrg * Given an extension enum, return whether or not the extension is supported
3387e995a2eSmrg * dependent on the following factors:
3397e995a2eSmrg * There's driver support and the OpenGL/ES version is at least that
3407e995a2eSmrg * specified in the _mesa_extension_table.
3417e995a2eSmrg */
3427e995a2eSmrgstatic inline bool
3437e995a2eSmrg_mesa_extension_supported(const struct gl_context *ctx, extension_index i)
3447e995a2eSmrg{
3457e995a2eSmrg   const bool *base = (bool *) &ctx->Extensions;
3467e995a2eSmrg   const struct mesa_extension *ext = _mesa_extension_table + i;
3477e995a2eSmrg
3487e995a2eSmrg   return (ctx->Version >= ext->version[ctx->API]) && base[ext->offset];
3497e995a2eSmrg}
3507e995a2eSmrg
3517117f1b4Smrg/**
3523464ebd5Sriastradh * Compare two entries of the extensions table.  Sorts first by year,
3533464ebd5Sriastradh * then by name.
3543464ebd5Sriastradh *
3557e995a2eSmrg * Arguments are indices into _mesa_extension_table.
3567117f1b4Smrg */
3573464ebd5Sriastradhstatic int
3583464ebd5Sriastradhextension_compare(const void *p1, const void *p2)
3597117f1b4Smrg{
3603464ebd5Sriastradh   extension_index i1 = * (const extension_index *) p1;
3613464ebd5Sriastradh   extension_index i2 = * (const extension_index *) p2;
3627e995a2eSmrg   const struct mesa_extension *e1 = &_mesa_extension_table[i1];
3637e995a2eSmrg   const struct mesa_extension *e2 = &_mesa_extension_table[i2];
3643464ebd5Sriastradh   int res;
3657117f1b4Smrg
3663464ebd5Sriastradh   res = (int)e1->year - (int)e2->year;
3673464ebd5Sriastradh
3683464ebd5Sriastradh   if (res == 0) {
3693464ebd5Sriastradh      res = strcmp(e1->name, e2->name);
3707117f1b4Smrg   }
3713464ebd5Sriastradh
3723464ebd5Sriastradh   return res;
3737117f1b4Smrg}
3747117f1b4Smrg
3757117f1b4Smrg
3767117f1b4Smrg/**
3777117f1b4Smrg * Construct the GL_EXTENSIONS string.  Called the first time that
3787117f1b4Smrg * glGetString(GL_EXTENSIONS) is called.
3797117f1b4Smrg */
3803464ebd5SriastradhGLubyte*
3813464ebd5Sriastradh_mesa_make_extension_string(struct gl_context *ctx)
3827117f1b4Smrg{
3833464ebd5Sriastradh   /* The extension string. */
3843464ebd5Sriastradh   char *exts = 0;
3853464ebd5Sriastradh   /* Length of extension string. */
3863464ebd5Sriastradh   size_t length = 0;
3873464ebd5Sriastradh   /* Number of extensions */
3883464ebd5Sriastradh   unsigned count;
3893464ebd5Sriastradh   /* Indices of the extensions sorted by year */
3907e995a2eSmrg   extension_index extension_indices[MESA_EXTENSION_COUNT];
3917e995a2eSmrg   unsigned k;
3923464ebd5Sriastradh   unsigned j;
3933464ebd5Sriastradh   unsigned maxYear = ~0;
3943464ebd5Sriastradh
3953464ebd5Sriastradh   /* Check if the MESA_EXTENSION_MAX_YEAR env var is set */
3963464ebd5Sriastradh   {
3973464ebd5Sriastradh      const char *env = getenv("MESA_EXTENSION_MAX_YEAR");
3983464ebd5Sriastradh      if (env) {
3993464ebd5Sriastradh         maxYear = atoi(env);
4003464ebd5Sriastradh         _mesa_debug(ctx, "Note: limiting GL extensions to %u or earlier\n",
4013464ebd5Sriastradh                     maxYear);
4027117f1b4Smrg      }
4037117f1b4Smrg   }
4044a49301eSmrg
4053464ebd5Sriastradh   /* Compute length of the extension string. */
4063464ebd5Sriastradh   count = 0;
4077e995a2eSmrg   for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
4087e995a2eSmrg      const struct mesa_extension *i = _mesa_extension_table + k;
4097e995a2eSmrg
4107e995a2eSmrg      if (i->year <= maxYear &&
4117e995a2eSmrg          _mesa_extension_supported(ctx, k)) {
4123464ebd5Sriastradh	 length += strlen(i->name) + 1; /* +1 for space */
4133464ebd5Sriastradh	 ++count;
4143464ebd5Sriastradh      }
4153464ebd5Sriastradh   }
4167e995a2eSmrg   for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; k++)
4171463c08dSmrg      if (unrecognized_extensions.names[k])
4181463c08dSmrg         length += 1 + strlen(unrecognized_extensions.names[k]); /* +1 for space */
4194a49301eSmrg
420af69d88dSmrg   exts = calloc(ALIGN(length + 1, 4), sizeof(char));
4213464ebd5Sriastradh   if (exts == NULL) {
4224a49301eSmrg      return NULL;
4237117f1b4Smrg   }
4247117f1b4Smrg
4257e995a2eSmrg   /* Sort extensions in chronological order because idTech 2/3 games
4267e995a2eSmrg    * (e.g., Quake3 demo) store the extension list in a fixed size buffer.
4277e995a2eSmrg    * Some cases truncate, while others overflow the buffer. Resulting in
4287e995a2eSmrg    * misrendering and crashes, respectively.
4297e995a2eSmrg    * Address the former here, while the latter will be addressed by setting
4307e995a2eSmrg    * the MESA_EXTENSION_MAX_YEAR environment variable.
4313464ebd5Sriastradh    */
4323464ebd5Sriastradh   j = 0;
4337e995a2eSmrg   for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
4347e995a2eSmrg      if (_mesa_extension_table[k].year <= maxYear &&
4357e995a2eSmrg         _mesa_extension_supported(ctx, k)) {
4367e995a2eSmrg         extension_indices[j++] = k;
4373464ebd5Sriastradh      }
4383464ebd5Sriastradh   }
4393464ebd5Sriastradh   assert(j == count);
440af69d88dSmrg   qsort(extension_indices, count,
441af69d88dSmrg         sizeof *extension_indices, extension_compare);
4423464ebd5Sriastradh
4433464ebd5Sriastradh   /* Build the extension string.*/
4443464ebd5Sriastradh   for (j = 0; j < count; ++j) {
4457e995a2eSmrg      const struct mesa_extension *i = &_mesa_extension_table[extension_indices[j]];
4467e995a2eSmrg      assert(_mesa_extension_supported(ctx, extension_indices[j]));
4473464ebd5Sriastradh      strcat(exts, i->name);
4483464ebd5Sriastradh      strcat(exts, " ");
4493464ebd5Sriastradh   }
4507e995a2eSmrg   for (j = 0; j < MAX_UNRECOGNIZED_EXTENSIONS; j++) {
4511463c08dSmrg      if (unrecognized_extensions.names[j]) {
4521463c08dSmrg         strcat(exts, unrecognized_extensions.names[j]);
4537e995a2eSmrg         strcat(exts, " ");
4547e995a2eSmrg      }
4554a49301eSmrg   }
4564a49301eSmrg
4573464ebd5Sriastradh   return (GLubyte *) exts;
4587117f1b4Smrg}
459cdc920a0Smrg
460cdc920a0Smrg/**
461cdc920a0Smrg * Return number of enabled extensions.
462cdc920a0Smrg */
463cdc920a0SmrgGLuint
4643464ebd5Sriastradh_mesa_get_extension_count(struct gl_context *ctx)
465cdc920a0Smrg{
4667e995a2eSmrg   unsigned k;
467cdc920a0Smrg
468cdc920a0Smrg   /* only count once */
4693464ebd5Sriastradh   if (ctx->Extensions.Count != 0)
4703464ebd5Sriastradh      return ctx->Extensions.Count;
4713464ebd5Sriastradh
4727e995a2eSmrg   for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
4737e995a2eSmrg      if (_mesa_extension_supported(ctx, k))
4747e995a2eSmrg	 ctx->Extensions.Count++;
4757e995a2eSmrg   }
4767e995a2eSmrg
4777e995a2eSmrg   for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; ++k) {
4781463c08dSmrg      if (unrecognized_extensions.names[k])
4791463c08dSmrg         ctx->Extensions.Count++;
480cdc920a0Smrg   }
481cdc920a0Smrg   return ctx->Extensions.Count;
482cdc920a0Smrg}
483cdc920a0Smrg
484cdc920a0Smrg/**
485cdc920a0Smrg * Return name of i-th enabled extension
486cdc920a0Smrg */
487cdc920a0Smrgconst GLubyte *
4883464ebd5Sriastradh_mesa_get_enabled_extension(struct gl_context *ctx, GLuint index)
489cdc920a0Smrg{
4907e995a2eSmrg   size_t n = 0;
4917e995a2eSmrg   unsigned i;
4927e995a2eSmrg
4937e995a2eSmrg   for (i = 0; i < MESA_EXTENSION_COUNT; ++i) {
4947e995a2eSmrg      if (_mesa_extension_supported(ctx, i)) {
495af69d88dSmrg         if (n == index)
4967e995a2eSmrg            return (const GLubyte*) _mesa_extension_table[i].name;
497af69d88dSmrg         else
498af69d88dSmrg            ++n;
499cdc920a0Smrg      }
500cdc920a0Smrg   }
501cdc920a0Smrg
5027e995a2eSmrg   for (i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i) {
5031463c08dSmrg      if (unrecognized_extensions.names[i]) {
5047e995a2eSmrg         if (n == index)
5051463c08dSmrg            return (const GLubyte*) unrecognized_extensions.names[i];
5067e995a2eSmrg         else
5077e995a2eSmrg            ++n;
5087e995a2eSmrg      }
5097e995a2eSmrg   }
510cdc920a0Smrg   return NULL;
511cdc920a0Smrg}
512