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