• 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 /**
118  * Enable all extensions suitable for a software-only renderer.
119  * This is a convenience function used by the mesa/swrast drivers.
120  */
121 void
_mesa_enable_sw_extensions(struct gl_context * ctx)122 _mesa_enable_sw_extensions(struct gl_context *ctx)
123 {
124    ctx->Extensions.ARB_depth_clamp = GL_TRUE;
125    ctx->Extensions.ARB_depth_texture = GL_TRUE;
126    ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
127    ctx->Extensions.ARB_draw_instanced = GL_TRUE;
128    ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
129    ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
130    ctx->Extensions.ARB_fragment_program = GL_TRUE;
131    ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
132    ctx->Extensions.ARB_fragment_shader = GL_TRUE;
133    ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
134    ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
135    ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
136    ctx->Extensions.ARB_occlusion_query = GL_TRUE;
137    ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
138    ctx->Extensions.ARB_point_sprite = GL_TRUE;
139    ctx->Extensions.ARB_shadow = GL_TRUE;
140    ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
141    ctx->Extensions.ARB_texture_compression_bptc = GL_TRUE;
142    ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
143    ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
144    ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
145    ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
146    ctx->Extensions.ARB_texture_filter_anisotropic = GL_TRUE;
147    ctx->Extensions.ARB_texture_float = GL_TRUE;
148    ctx->Extensions.ARB_texture_mirror_clamp_to_edge = GL_TRUE;
149    ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
150    ctx->Extensions.ARB_texture_rg = GL_TRUE;
151    ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE;
152    ctx->Extensions.ARB_vertex_program = GL_TRUE;
153    ctx->Extensions.ARB_vertex_shader = GL_TRUE;
154    ctx->Extensions.ARB_sync = GL_TRUE;
155    ctx->Extensions.APPLE_object_purgeable = GL_TRUE;
156    ctx->Extensions.ATI_fragment_shader = GL_TRUE;
157    ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE;
158    ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
159    ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
160    ctx->Extensions.EXT_blend_color = GL_TRUE;
161    ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
162    ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
163    ctx->Extensions.EXT_blend_minmax = GL_TRUE;
164    ctx->Extensions.EXT_depth_bounds_test = GL_TRUE;
165    ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
166    ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
167    ctx->Extensions.EXT_point_parameters = GL_TRUE;
168    ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
169    ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
170    ctx->Extensions.EXT_texture_array = GL_TRUE;
171    ctx->Extensions.EXT_texture_compression_latc = GL_TRUE;
172    ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
173    ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE;
174    ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
175    ctx->Extensions.EXT_texture_shared_exponent = GL_TRUE;
176    ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
177    ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
178    ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
179    /*ctx->Extensions.EXT_transform_feedback = GL_TRUE;*/
180    ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
181    ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
182    ctx->Extensions.NV_conditional_render = GL_TRUE;
183    ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
184    ctx->Extensions.NV_texture_rectangle = GL_TRUE;
185    ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
186    ctx->Extensions.OES_standard_derivatives = GL_TRUE;
187    ctx->Extensions.TDFX_texture_compression_FXT1 = GL_TRUE;
188    ctx->Extensions.ANGLE_texture_compression_dxt = GL_TRUE;
189    ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE;
190 }
191 
192 /**
193  * Either enable or disable the named extension.
194  * \return offset of extensions withint `ext' or 0 if extension is not known
195  */
196 static size_t
set_extension(struct gl_extensions * ext,int i,GLboolean state)197 set_extension(struct gl_extensions *ext, int i, GLboolean state)
198 {
199    size_t offset;
200 
201    offset = i < 0 ? 0 : _mesa_extension_table[i].offset;
202    if (offset != 0 && (offset != o(dummy_true) || state != GL_FALSE)) {
203       ((GLboolean *) ext)[offset] = state;
204    }
205 
206    return offset;
207 }
208 
209 
210 /**
211  * \brief Free string pointed by unrecognized_extensions
212  *
213  * This string is allocated early during the first context creation by
214  * _mesa_one_time_init_extension_overrides.
215  */
216 static void
free_unknown_extensions_strings(void)217 free_unknown_extensions_strings(void)
218 {
219    free(unrecognized_extensions.env);
220    for (int i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i)
221       unrecognized_extensions.names[i] = NULL;
222 }
223 
224 
225 /**
226  * \brief Initialize extension override tables based on \c MESA_EXTENSION_OVERRIDE
227  *
228  * This should be called one time early during first context initialization.
229 
230  * \c MESA_EXTENSION_OVERRIDE is a space-separated list of extensions to
231  * enable or disable. The list is processed thus:
232  *    - Enable recognized extension names that are prefixed with '+'.
233  *    - Disable recognized extension names that are prefixed with '-'.
234  *    - Enable recognized extension names that are not prefixed.
235  *    - Collect unrecognized extension names in a new string.
236  */
237 void
_mesa_one_time_init_extension_overrides(void)238 _mesa_one_time_init_extension_overrides(void)
239 {
240    const char *env_const = os_get_option("MESA_EXTENSION_OVERRIDE");
241    char *env;
242    char *ext;
243    size_t offset;
244    unsigned unknown_ext = 0;
245 
246    memset(&_mesa_extension_override_enables, 0, sizeof(struct gl_extensions));
247    memset(&_mesa_extension_override_disables, 0, sizeof(struct gl_extensions));
248 
249    if (env_const == NULL) {
250       return;
251    }
252 
253    /* Copy env_const because strtok() is destructive. */
254    env = strdup(env_const);
255 
256    if (env == NULL)
257       return;
258 
259    for (ext = strtok(env, " "); ext != NULL; ext = strtok(NULL, " ")) {
260       int enable;
261       int i;
262       bool recognized;
263       switch (ext[0]) {
264       case '+':
265          enable = 1;
266          ++ext;
267          break;
268       case '-':
269          enable = 0;
270          ++ext;
271          break;
272       default:
273          enable = 1;
274          break;
275       }
276 
277       i = name_to_index(ext);
278       offset = set_extension(&_mesa_extension_override_enables, i, enable);
279       offset = set_extension(&_mesa_extension_override_disables, i, !enable);
280       if (offset != 0)
281          recognized = true;
282       else
283          recognized = false;
284 
285       if (!recognized && enable) {
286          if (unknown_ext >= MAX_UNRECOGNIZED_EXTENSIONS) {
287             static bool warned;
288 
289             if (!warned) {
290                warned = true;
291                _mesa_problem(NULL, "Trying to enable too many unknown extension. "
292                                    "Only the first %d will be honoured",
293                                    MAX_UNRECOGNIZED_EXTENSIONS);
294             }
295          } else {
296             unrecognized_extensions.names[unknown_ext] = ext;
297             unknown_ext++;
298             _mesa_problem(NULL, "Trying to enable unknown extension: %s", ext);
299          }
300       }
301    }
302 
303    if (!unknown_ext) {
304       free(env);
305    } else {
306       unrecognized_extensions.env = env;
307       atexit(free_unknown_extensions_strings);
308    }
309 }
310 
311 
312 /**
313  * \brief Initialize extension tables and enable default extensions.
314  *
315  * This should be called during context initialization.
316  * Note: Sets gl_extensions.dummy_true to true.
317  */
318 void
_mesa_init_extensions(struct gl_extensions * extensions)319 _mesa_init_extensions(struct gl_extensions *extensions)
320 {
321    GLboolean *base = (GLboolean *) extensions;
322    GLboolean *sentinel = base + o(extension_sentinel);
323    GLboolean *i;
324 
325    /* First, turn all extensions off. */
326    for (i = base; i != sentinel; ++i)
327       *i = GL_FALSE;
328 
329    /* Then, selectively turn default extensions on. */
330    extensions->dummy_true = GL_TRUE;
331 }
332 
333 
334 typedef unsigned short extension_index;
335 
336 
337 /**
338  * Given an extension enum, return whether or not the extension is supported
339  * dependent on the following factors:
340  * There's driver support and the OpenGL/ES version is at least that
341  * specified in the _mesa_extension_table.
342  */
343 static inline bool
_mesa_extension_supported(const struct gl_context * ctx,extension_index i)344 _mesa_extension_supported(const struct gl_context *ctx, extension_index i)
345 {
346    const bool *base = (bool *) &ctx->Extensions;
347    const struct mesa_extension *ext = _mesa_extension_table + i;
348 
349    return (ctx->Version >= ext->version[ctx->API]) && base[ext->offset];
350 }
351 
352 /**
353  * Compare two entries of the extensions table.  Sorts first by year,
354  * then by name.
355  *
356  * Arguments are indices into _mesa_extension_table.
357  */
358 static int
extension_compare(const void * p1,const void * p2)359 extension_compare(const void *p1, const void *p2)
360 {
361    extension_index i1 = * (const extension_index *) p1;
362    extension_index i2 = * (const extension_index *) p2;
363    const struct mesa_extension *e1 = &_mesa_extension_table[i1];
364    const struct mesa_extension *e2 = &_mesa_extension_table[i2];
365    int res;
366 
367    res = (int)e1->year - (int)e2->year;
368 
369    if (res == 0) {
370       res = strcmp(e1->name, e2->name);
371    }
372 
373    return res;
374 }
375 
376 
377 /**
378  * Construct the GL_EXTENSIONS string.  Called the first time that
379  * glGetString(GL_EXTENSIONS) is called.
380  */
381 GLubyte*
_mesa_make_extension_string(struct gl_context * ctx)382 _mesa_make_extension_string(struct gl_context *ctx)
383 {
384    /* The extension string. */
385    char *exts = 0;
386    /* Length of extension string. */
387    size_t length = 0;
388    /* Number of extensions */
389    unsigned count;
390    /* Indices of the extensions sorted by year */
391    extension_index extension_indices[MESA_EXTENSION_COUNT];
392    unsigned k;
393    unsigned j;
394    unsigned maxYear = ~0;
395 
396    /* Check if the MESA_EXTENSION_MAX_YEAR env var is set */
397    {
398       const char *env = getenv("MESA_EXTENSION_MAX_YEAR");
399       if (env) {
400          maxYear = atoi(env);
401          _mesa_debug(ctx, "Note: limiting GL extensions to %u or earlier\n",
402                      maxYear);
403       }
404    }
405 
406    /* Compute length of the extension string. */
407    count = 0;
408    for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
409       const struct mesa_extension *i = _mesa_extension_table + k;
410 
411       if (i->year <= maxYear &&
412           _mesa_extension_supported(ctx, k)) {
413 	 length += strlen(i->name) + 1; /* +1 for space */
414 	 ++count;
415       }
416    }
417    for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; k++)
418       if (unrecognized_extensions.names[k])
419          length += 1 + strlen(unrecognized_extensions.names[k]); /* +1 for space */
420 
421    exts = calloc(ALIGN(length + 1, 4), sizeof(char));
422    if (exts == NULL) {
423       return NULL;
424    }
425 
426    /* Sort extensions in chronological order because idTech 2/3 games
427     * (e.g., Quake3 demo) store the extension list in a fixed size buffer.
428     * Some cases truncate, while others overflow the buffer. Resulting in
429     * misrendering and crashes, respectively.
430     * Address the former here, while the latter will be addressed by setting
431     * the MESA_EXTENSION_MAX_YEAR environment variable.
432     */
433    j = 0;
434    for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
435       if (_mesa_extension_table[k].year <= maxYear &&
436          _mesa_extension_supported(ctx, k)) {
437          extension_indices[j++] = k;
438       }
439    }
440    assert(j == count);
441    qsort(extension_indices, count,
442          sizeof *extension_indices, extension_compare);
443 
444    /* Build the extension string.*/
445    for (j = 0; j < count; ++j) {
446       const struct mesa_extension *i = &_mesa_extension_table[extension_indices[j]];
447       assert(_mesa_extension_supported(ctx, extension_indices[j]));
448       strcat(exts, i->name);
449       strcat(exts, " ");
450    }
451    for (j = 0; j < MAX_UNRECOGNIZED_EXTENSIONS; j++) {
452       if (unrecognized_extensions.names[j]) {
453          strcat(exts, unrecognized_extensions.names[j]);
454          strcat(exts, " ");
455       }
456    }
457 
458    return (GLubyte *) exts;
459 }
460 
461 /**
462  * Return number of enabled extensions.
463  */
464 GLuint
_mesa_get_extension_count(struct gl_context * ctx)465 _mesa_get_extension_count(struct gl_context *ctx)
466 {
467    unsigned k;
468 
469    /* only count once */
470    if (ctx->Extensions.Count != 0)
471       return ctx->Extensions.Count;
472 
473    for (k = 0; k < MESA_EXTENSION_COUNT; ++k) {
474       if (_mesa_extension_supported(ctx, k))
475 	 ctx->Extensions.Count++;
476    }
477 
478    for (k = 0; k < MAX_UNRECOGNIZED_EXTENSIONS; ++k) {
479       if (unrecognized_extensions.names[k])
480          ctx->Extensions.Count++;
481    }
482    return ctx->Extensions.Count;
483 }
484 
485 /**
486  * Return name of i-th enabled extension
487  */
488 const GLubyte *
_mesa_get_enabled_extension(struct gl_context * ctx,GLuint index)489 _mesa_get_enabled_extension(struct gl_context *ctx, GLuint index)
490 {
491    size_t n = 0;
492    unsigned i;
493 
494    for (i = 0; i < MESA_EXTENSION_COUNT; ++i) {
495       if (_mesa_extension_supported(ctx, i)) {
496          if (n == index)
497             return (const GLubyte*) _mesa_extension_table[i].name;
498          else
499             ++n;
500       }
501    }
502 
503    for (i = 0; i < MAX_UNRECOGNIZED_EXTENSIONS; ++i) {
504       if (unrecognized_extensions.names[i]) {
505          if (n == index)
506             return (const GLubyte*) unrecognized_extensions.names[i];
507          else
508             ++n;
509       }
510    }
511    return NULL;
512 }
513