• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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