xref: /third_party/mesa3d/src/mesa/main/extensions.c (revision bf215546)
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
41struct gl_extensions _mesa_extension_override_enables;
42struct gl_extensions _mesa_extension_override_disables;
43
44#define MAX_UNRECOGNIZED_EXTENSIONS 16
45static 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
56static int
57extension_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 */
71static int
72name_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 */
94void
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 */
120static size_t
121set_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 */
140static void
141free_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 */
161void
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 */
246void
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
307typedef 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 */
316static inline bool
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 */
331static int
332extension_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 */
354GLubyte*
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 */
437GLuint
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 */
461const GLubyte *
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