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 "util/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_provoking_vertex = GL_TRUE;
287 extensions->EXT_stencil_two_side = GL_TRUE;
288 extensions->EXT_texture_env_dot3 = GL_TRUE;
289
290 extensions->ATI_fragment_shader = GL_TRUE;
291 extensions->ATI_texture_env_combine3 = GL_TRUE;
292
293 extensions->MESA_framebuffer_flip_y = GL_TRUE;
294
295 extensions->NV_copy_image = GL_TRUE;
296 extensions->NV_fog_distance = GL_TRUE;
297 extensions->NV_texture_env_combine4 = GL_TRUE;
298 extensions->NV_texture_rectangle = GL_TRUE;
299
300 extensions->OES_EGL_image = GL_TRUE;
301 extensions->OES_EGL_image_external = GL_TRUE;
302 extensions->OES_draw_texture = GL_TRUE;
303 }
304
305
306 typedef unsigned short extension_index;
307
308
309 /**
310 * Given an extension enum, return whether or not the extension is supported
311 * dependent on the following factors:
312 * There's driver support and the OpenGL/ES version is at least that
313 * specified in the _mesa_extension_table.
314 */
315 static inline bool
_mesa_extension_supported(const struct gl_context * ctx,extension_index i)316 _mesa_extension_supported(const struct gl_context *ctx, extension_index i)
317 {
318 const bool *base = (bool *) &ctx->Extensions;
319 const struct mesa_extension *ext = _mesa_extension_table + i;
320
321 return (ctx->Version >= ext->version[ctx->API]) && base[ext->offset];
322 }
323
324 /**
325 * Compare two entries of the extensions table. Sorts first by year,
326 * then by name.
327 *
328 * Arguments are indices into _mesa_extension_table.
329 */
330 static int
extension_compare(const void * p1,const void * p2)331 extension_compare(const void *p1, const void *p2)
332 {
333 extension_index i1 = * (const extension_index *) p1;
334 extension_index i2 = * (const extension_index *) p2;
335 const struct mesa_extension *e1 = &_mesa_extension_table[i1];
336 const struct mesa_extension *e2 = &_mesa_extension_table[i2];
337 int res;
338
339 res = (int)e1->year - (int)e2->year;
340
341 if (res == 0) {
342 res = strcmp(e1->name, e2->name);
343 }
344
345 return res;
346 }
347
348
349 /**
350 * Construct the GL_EXTENSIONS string. Called the first time that
351 * glGetString(GL_EXTENSIONS) is called.
352 */
353 GLubyte*
_mesa_make_extension_string(struct gl_context * ctx)354 _mesa_make_extension_string(struct gl_context *ctx)
355 {
356 /* The extension string. */
357 char *exts = NULL;
358 /* Length of extension string. */
359 size_t length = 0;
360 /* Number of extensions */
361 unsigned count;
362 /* Indices of the extensions sorted by year */
363 extension_index extension_indices[MESA_EXTENSION_COUNT];
364 unsigned k;
365 unsigned j;
366 unsigned maxYear = ~0;
367
368 /* Check if the MESA_EXTENSION_MAX_YEAR env var is set */
369 {
370 const char *env = getenv("MESA_EXTENSION_MAX_YEAR");
371 if (env) {
372 maxYear = atoi(env);
373 _mesa_debug(ctx, "Note: limiting GL extensions to %u or earlier\n",
374 maxYear);
375 }
376 }
377
378 /* Compute length of the extension string. */
379 count = 0;
380 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
381 const struct mesa_extension *i = _mesa_extension_table + k;
382
383 if (i->year <= maxYear &&
384 _mesa_extension_supported(ctx, k)) {
385 length += strlen(i->name) + 1; /* +1 for space */
386 ++count;
387 }
388 }
389 for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; k++)
390 if (unrecognized_extensions.names[k])
391 length += 1 + strlen(unrecognized_extensions.names[k]); /* +1 for space */
392
393 exts = calloc(align_uintptr(length + 1, 4), sizeof(char));
394 if (exts == NULL) {
395 return NULL;
396 }
397
398 /* Sort extensions in chronological order because idTech 2/3 games
399 * (e.g., Quake3 demo) store the extension list in a fixed size buffer.
400 * Some cases truncate, while others overflow the buffer. Resulting in
401 * misrendering and crashes, respectively.
402 * Address the former here, while the latter will be addressed by setting
403 * the MESA_EXTENSION_MAX_YEAR environment variable.
404 */
405 j = 0;
406 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
407 if (_mesa_extension_table[k].year <= maxYear &&
408 _mesa_extension_supported(ctx, k)) {
409 extension_indices[j++] = k;
410 }
411 }
412 assert(j == count);
413 qsort(extension_indices, count,
414 sizeof *extension_indices, extension_compare);
415
416 /* Build the extension string.*/
417 for (j = 0; j < count; ++j) {
418 const struct mesa_extension *i = &_mesa_extension_table[extension_indices[j]];
419 assert(_mesa_extension_supported(ctx, extension_indices[j]));
420 strcat(exts, i->name);
421 strcat(exts, " ");
422 }
423 for (j = 0; j < MAX_UNRECOGNIZED_EXTENSIONS; j++) {
424 if (unrecognized_extensions.names[j]) {
425 strcat(exts, unrecognized_extensions.names[j]);
426 strcat(exts, " ");
427 }
428 }
429
430 return (GLubyte *) exts;
431 }
432
433 /**
434 * Return number of enabled extensions.
435 */
436 GLuint
_mesa_get_extension_count(struct gl_context * ctx)437 _mesa_get_extension_count(struct gl_context *ctx)
438 {
439 unsigned k;
440
441 /* only count once */
442 if (ctx->Extensions.Count != 0)
443 return ctx->Extensions.Count;
444
445 for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
446 if (_mesa_extension_supported(ctx, k))
447 ctx->Extensions.Count++;
448 }
449
450 for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; ++k) {
451 if (unrecognized_extensions.names[k])
452 ctx->Extensions.Count++;
453 }
454 return ctx->Extensions.Count;
455 }
456
457 /**
458 * Return name of i-th enabled extension
459 */
460 const GLubyte *
_mesa_get_enabled_extension(struct gl_context * ctx,GLuint index)461 _mesa_get_enabled_extension(struct gl_context *ctx, GLuint index)
462 {
463 size_t n = 0;
464 unsigned i;
465
466 for (i = 0; i < MESA_EXTENSION_COUNT; ++i) {
467 if (_mesa_extension_supported(ctx, i)) {
468 if (n == index)
469 return (const GLubyte*) _mesa_extension_table[i].name;
470 else
471 ++n;
472 }
473 }
474
475 for (i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i) {
476 if (unrecognized_extensions.names[i]) {
477 if (n == index)
478 return (const GLubyte*) unrecognized_extensions.names[i];
479 else
480 ++n;
481 }
482 }
483 return NULL;
484 }
485