1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * \file 29 * \brief Extension handling 30 */ 31 32#include "util/os_misc.h" 33 34#include "glheader.h" 35 36#include "context.h" 37#include "extensions.h" 38#include "macros.h" 39#include "mtypes.h" 40 41struct gl_extensions _mesa_extension_override_enables; 42struct gl_extensions _mesa_extension_override_disables; 43 44#define MAX_UNRECOGNIZED_EXTENSIONS 16 45static struct { 46 char *env; 47 const char *names[MAX_UNRECOGNIZED_EXTENSIONS]; 48} unrecognized_extensions; 49 50/** 51 * Given a member \c x of struct gl_extensions, return offset of 52 * \c x in bytes. 53 */ 54#define o(x) offsetof(struct gl_extensions, x) 55 56static int 57extension_name_compare(const void *name, const void *elem) 58{ 59 const struct mesa_extension *entry = elem; 60 return strcmp(name, entry->name); 61} 62 63/** 64 * Given an extension name, lookup up the corresponding member of struct 65 * gl_extensions and return that member's index. If the name is 66 * not found in the \c _mesa_extension_table, return -1. 67 * 68 * \param name Name of extension. 69 * \return Index of member in struct gl_extensions. 70 */ 71static int 72name_to_index(const char* name) 73{ 74 const struct mesa_extension *entry; 75 76 if (!name) 77 return -1; 78 79 entry = bsearch(name, 80 _mesa_extension_table, MESA_EXTENSION_COUNT, 81 sizeof(_mesa_extension_table[0]), 82 extension_name_compare); 83 84 if (entry) 85 return entry - _mesa_extension_table; 86 87 return -1; 88} 89 90/** 91 * Overrides extensions in \c ctx based on the values in 92 * _mesa_extension_override_enables and _mesa_extension_override_disables. 93 */ 94void 95_mesa_override_extensions(struct gl_context *ctx) 96{ 97 unsigned i; 98 const GLboolean *enables = 99 (GLboolean*) &_mesa_extension_override_enables; 100 const GLboolean *disables = 101 (GLboolean*) &_mesa_extension_override_disables; 102 GLboolean *ctx_ext = (GLboolean*)&ctx->Extensions; 103 104 for (i = 0; i < MESA_EXTENSION_COUNT; ++i) { 105 size_t offset = _mesa_extension_table[i].offset; 106 107 assert(!enables[offset] || !disables[offset]); 108 if (enables[offset]) { 109 ctx_ext[offset] = 1; 110 } else if (disables[offset]) { 111 ctx_ext[offset] = 0; 112 } 113 } 114} 115 116/** 117 * Either enable or disable the named extension. 118 * \return offset of extensions withint `ext' or 0 if extension is not known 119 */ 120static size_t 121set_extension(struct gl_extensions *ext, int i, GLboolean state) 122{ 123 size_t offset; 124 125 offset = i < 0 ? 0 : _mesa_extension_table[i].offset; 126 if (offset != 0 && (offset != o(dummy_true) || state != GL_FALSE)) { 127 ((GLboolean *) ext)[offset] = state; 128 } 129 130 return offset; 131} 132 133 134/** 135 * \brief Free string pointed by unrecognized_extensions 136 * 137 * This string is allocated early during the first context creation by 138 * _mesa_one_time_init_extension_overrides. 139 */ 140static void 141free_unknown_extensions_strings(void) 142{ 143 free(unrecognized_extensions.env); 144 for (int i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i) 145 unrecognized_extensions.names[i] = NULL; 146} 147 148 149/** 150 * \brief Initialize extension override tables based on \c override 151 * 152 * This should be called one time early during first context initialization. 153 154 * \c override is a space-separated list of extensions to 155 * enable or disable. The list is processed thus: 156 * - Enable recognized extension names that are prefixed with '+'. 157 * - Disable recognized extension names that are prefixed with '-'. 158 * - Enable recognized extension names that are not prefixed. 159 * - Collect unrecognized extension names in a new string. 160 */ 161void 162_mesa_one_time_init_extension_overrides(const char *override) 163{ 164 char *env; 165 char *ext; 166 size_t offset; 167 unsigned unknown_ext = 0; 168 169 memset(&_mesa_extension_override_enables, 0, sizeof(struct gl_extensions)); 170 memset(&_mesa_extension_override_disables, 0, sizeof(struct gl_extensions)); 171 172 if (override == NULL || override[0] == '\0') { 173 return; 174 } 175 176 /* Copy 'override' because strtok() is destructive. */ 177 env = strdup(override); 178 179 if (env == NULL) 180 return; 181 182 for (ext = strtok(env, " "); ext != NULL; ext = strtok(NULL, " ")) { 183 int enable; 184 int i; 185 bool recognized; 186 switch (ext[0]) { 187 case '+': 188 enable = 1; 189 ++ext; 190 break; 191 case '-': 192 enable = 0; 193 ++ext; 194 break; 195 default: 196 enable = 1; 197 break; 198 } 199 200 i = name_to_index(ext); 201 offset = set_extension(&_mesa_extension_override_enables, i, enable); 202 offset = set_extension(&_mesa_extension_override_disables, i, !enable); 203 if (offset != 0) 204 recognized = true; 205 else 206 recognized = false; 207 208 if (!enable && recognized && offset <= 1) { 209 printf("Warning: extension '%s' cannot be disabled\n", ext); 210 offset = set_extension(&_mesa_extension_override_disables, i, 0); 211 } 212 213 if (!recognized && enable) { 214 if (unknown_ext >= MAX_UNRECOGNIZED_EXTENSIONS) { 215 static bool warned; 216 217 if (!warned) { 218 warned = true; 219 _mesa_problem(NULL, "Trying to enable too many unknown extension. " 220 "Only the first %d will be honoured", 221 MAX_UNRECOGNIZED_EXTENSIONS); 222 } 223 } else { 224 unrecognized_extensions.names[unknown_ext] = ext; 225 unknown_ext++; 226 _mesa_problem(NULL, "Trying to enable unknown extension: %s", ext); 227 } 228 } 229 } 230 231 if (!unknown_ext) { 232 free(env); 233 } else { 234 unrecognized_extensions.env = env; 235 atexit(free_unknown_extensions_strings); 236 } 237} 238 239 240/** 241 * \brief Initialize extension tables and enable default extensions. 242 * 243 * This should be called during context initialization. 244 * Note: Sets gl_extensions.dummy_true to true. 245 */ 246void 247_mesa_init_extensions(struct gl_extensions *extensions) 248{ 249 GLboolean *base = (GLboolean *) extensions; 250 GLboolean *sentinel = base + o(extension_sentinel); 251 GLboolean *i; 252 253 /* First, turn all extensions off. */ 254 for (i = base; i != sentinel; ++i) 255 *i = GL_FALSE; 256 257 /* Then, selectively turn default extensions on. */ 258 extensions->dummy_true = GL_TRUE; 259 260 /* Always enable these extensions for all drivers. 261 * We can't use dummy_true in extensions_table.h for these 262 * because this would make them non-disablable using 263 * _mesa_override_extensions. 264 */ 265 extensions->MESA_pack_invert = GL_TRUE; 266 extensions->MESA_window_pos = GL_TRUE; 267 268 extensions->ARB_ES2_compatibility = GL_TRUE; 269 extensions->ARB_draw_elements_base_vertex = GL_TRUE; 270 extensions->ARB_explicit_attrib_location = GL_TRUE; 271 extensions->ARB_explicit_uniform_location = GL_TRUE; 272 extensions->ARB_fragment_coord_conventions = GL_TRUE; 273 extensions->ARB_fragment_program = GL_TRUE; 274 extensions->ARB_fragment_shader = GL_TRUE; 275 extensions->ARB_half_float_vertex = GL_TRUE; 276 extensions->ARB_internalformat_query = GL_TRUE; 277 extensions->ARB_internalformat_query2 = GL_TRUE; 278 extensions->ARB_map_buffer_range = GL_TRUE; 279 extensions->ARB_occlusion_query = GL_TRUE; 280 extensions->ARB_sync = GL_TRUE; 281 extensions->ARB_vertex_program = GL_TRUE; 282 extensions->ARB_vertex_shader = GL_TRUE; 283 284 extensions->EXT_EGL_image_storage = GL_TRUE; 285 extensions->EXT_gpu_program_parameters = GL_TRUE; 286 extensions->EXT_pixel_buffer_object = GL_TRUE; 287 extensions->EXT_provoking_vertex = GL_TRUE; 288 extensions->EXT_stencil_two_side = GL_TRUE; 289 extensions->EXT_texture_env_dot3 = GL_TRUE; 290 291 extensions->ATI_fragment_shader = GL_TRUE; 292 extensions->ATI_texture_env_combine3 = GL_TRUE; 293 294 extensions->MESA_framebuffer_flip_y = GL_TRUE; 295 296 extensions->NV_copy_image = GL_TRUE; 297 extensions->NV_fog_distance = GL_TRUE; 298 extensions->NV_texture_env_combine4 = GL_TRUE; 299 extensions->NV_texture_rectangle = GL_TRUE; 300 301 extensions->OES_EGL_image = GL_TRUE; 302 extensions->OES_EGL_image_external = GL_TRUE; 303 extensions->OES_draw_texture = GL_TRUE; 304} 305 306 307typedef unsigned short extension_index; 308 309 310/** 311 * Given an extension enum, return whether or not the extension is supported 312 * dependent on the following factors: 313 * There's driver support and the OpenGL/ES version is at least that 314 * specified in the _mesa_extension_table. 315 */ 316static inline bool 317_mesa_extension_supported(const struct gl_context *ctx, extension_index i) 318{ 319 const bool *base = (bool *) &ctx->Extensions; 320 const struct mesa_extension *ext = _mesa_extension_table + i; 321 322 return (ctx->Version >= ext->version[ctx->API]) && base[ext->offset]; 323} 324 325/** 326 * Compare two entries of the extensions table. Sorts first by year, 327 * then by name. 328 * 329 * Arguments are indices into _mesa_extension_table. 330 */ 331static int 332extension_compare(const void *p1, const void *p2) 333{ 334 extension_index i1 = * (const extension_index *) p1; 335 extension_index i2 = * (const extension_index *) p2; 336 const struct mesa_extension *e1 = &_mesa_extension_table[i1]; 337 const struct mesa_extension *e2 = &_mesa_extension_table[i2]; 338 int res; 339 340 res = (int)e1->year - (int)e2->year; 341 342 if (res == 0) { 343 res = strcmp(e1->name, e2->name); 344 } 345 346 return res; 347} 348 349 350/** 351 * Construct the GL_EXTENSIONS string. Called the first time that 352 * glGetString(GL_EXTENSIONS) is called. 353 */ 354GLubyte* 355_mesa_make_extension_string(struct gl_context *ctx) 356{ 357 /* The extension string. */ 358 char *exts = NULL; 359 /* Length of extension string. */ 360 size_t length = 0; 361 /* Number of extensions */ 362 unsigned count; 363 /* Indices of the extensions sorted by year */ 364 extension_index extension_indices[MESA_EXTENSION_COUNT]; 365 unsigned k; 366 unsigned j; 367 unsigned maxYear = ~0; 368 369 /* Check if the MESA_EXTENSION_MAX_YEAR env var is set */ 370 { 371 const char *env = getenv("MESA_EXTENSION_MAX_YEAR"); 372 if (env) { 373 maxYear = atoi(env); 374 _mesa_debug(ctx, "Note: limiting GL extensions to %u or earlier\n", 375 maxYear); 376 } 377 } 378 379 /* Compute length of the extension string. */ 380 count = 0; 381 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) { 382 const struct mesa_extension *i = _mesa_extension_table + k; 383 384 if (i->year <= maxYear && 385 _mesa_extension_supported(ctx, k)) { 386 length += strlen(i->name) + 1; /* +1 for space */ 387 ++count; 388 } 389 } 390 for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; k++) 391 if (unrecognized_extensions.names[k]) 392 length += 1 + strlen(unrecognized_extensions.names[k]); /* +1 for space */ 393 394 exts = calloc(ALIGN(length + 1, 4), sizeof(char)); 395 if (exts == NULL) { 396 return NULL; 397 } 398 399 /* Sort extensions in chronological order because idTech 2/3 games 400 * (e.g., Quake3 demo) store the extension list in a fixed size buffer. 401 * Some cases truncate, while others overflow the buffer. Resulting in 402 * misrendering and crashes, respectively. 403 * Address the former here, while the latter will be addressed by setting 404 * the MESA_EXTENSION_MAX_YEAR environment variable. 405 */ 406 j = 0; 407 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) { 408 if (_mesa_extension_table[k].year <= maxYear && 409 _mesa_extension_supported(ctx, k)) { 410 extension_indices[j++] = k; 411 } 412 } 413 assert(j == count); 414 qsort(extension_indices, count, 415 sizeof *extension_indices, extension_compare); 416 417 /* Build the extension string.*/ 418 for (j = 0; j < count; ++j) { 419 const struct mesa_extension *i = &_mesa_extension_table[extension_indices[j]]; 420 assert(_mesa_extension_supported(ctx, extension_indices[j])); 421 strcat(exts, i->name); 422 strcat(exts, " "); 423 } 424 for (j = 0; j < MAX_UNRECOGNIZED_EXTENSIONS; j++) { 425 if (unrecognized_extensions.names[j]) { 426 strcat(exts, unrecognized_extensions.names[j]); 427 strcat(exts, " "); 428 } 429 } 430 431 return (GLubyte *) exts; 432} 433 434/** 435 * Return number of enabled extensions. 436 */ 437GLuint 438_mesa_get_extension_count(struct gl_context *ctx) 439{ 440 unsigned k; 441 442 /* only count once */ 443 if (ctx->Extensions.Count != 0) 444 return ctx->Extensions.Count; 445 446 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) { 447 if (_mesa_extension_supported(ctx, k)) 448 ctx->Extensions.Count++; 449 } 450 451 for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; ++k) { 452 if (unrecognized_extensions.names[k]) 453 ctx->Extensions.Count++; 454 } 455 return ctx->Extensions.Count; 456} 457 458/** 459 * Return name of i-th enabled extension 460 */ 461const GLubyte * 462_mesa_get_enabled_extension(struct gl_context *ctx, GLuint index) 463{ 464 size_t n = 0; 465 unsigned i; 466 467 for (i = 0; i < MESA_EXTENSION_COUNT; ++i) { 468 if (_mesa_extension_supported(ctx, i)) { 469 if (n == index) 470 return (const GLubyte*) _mesa_extension_table[i].name; 471 else 472 ++n; 473 } 474 } 475 476 for (i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i) { 477 if (unrecognized_extensions.names[i]) { 478 if (n == index) 479 return (const GLubyte*) unrecognized_extensions.names[i]; 480 else 481 ++n; 482 } 483 } 484 return NULL; 485} 486