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
41 struct gl_extensions _mesa_extension_override_enables;
42 struct gl_extensions _mesa_extension_override_disables;
43
44 #define MAX_UNRECOGNIZED_EXTENSIONS 16
45 static 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
56 static int
extension_name_compare(const void * name,const void * elem)57 extension_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 */
71 static int
name_to_index(const char * name)72 name_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 */
94 void
_mesa_override_extensions(struct gl_context * ctx)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 */
120 static size_t
set_extension(struct gl_extensions * ext,int i,GLboolean state)121 set_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 */
140 static void
free_unknown_extensions_strings(void)141 free_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 */
161 void
_mesa_one_time_init_extension_overrides(const char * override)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 */
246 void
_mesa_init_extensions(struct gl_extensions * extensions)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
307 typedef 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 */
316 static inline bool
_mesa_extension_supported(const struct gl_context * ctx,extension_index i)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 */
331 static int
extension_compare(const void * p1,const void * p2)332 extension_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 */
354 GLubyte*
_mesa_make_extension_string(struct gl_context * ctx)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 */
437 GLuint
_mesa_get_extension_count(struct gl_context * ctx)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 */
461 const GLubyte *
_mesa_get_enabled_extension(struct gl_context * ctx,GLuint index)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