• 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 "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