dri_common.c revision 7e995a2e
1/*
2 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
3 * Copyright © 2008 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Soft-
7 * ware"), to deal in the Software without restriction, including without
8 * limitation the rights to use, copy, modify, merge, publish, distribute,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, provided that the above copyright
11 * notice(s) and this permission notice appear in all copies of the Soft-
12 * ware and that both the above copyright notice(s) and this permission
13 * notice appear in supporting documentation.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
18 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
19 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
20 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
23 * MANCE OF THIS SOFTWARE.
24 *
25 * Except as contained in this notice, the name of a copyright holder shall
26 * not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization of
28 * the copyright holder.
29 *
30 * Authors:
31 *   Kevin E. Martin <kevin@precisioninsight.com>
32 *   Brian Paul <brian@precisioninsight.com>
33 *   Kristian Høgsberg (krh@redhat.com)
34 */
35
36#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
37
38#include <unistd.h>
39#include <dlfcn.h>
40#include <stdarg.h>
41#include "glxclient.h"
42#include "dri_common.h"
43#include "loader.h"
44
45#ifndef RTLD_NOW
46#define RTLD_NOW 0
47#endif
48#ifndef RTLD_GLOBAL
49#define RTLD_GLOBAL 0
50#endif
51
52_X_HIDDEN void
53dri_message(int level, const char *f, ...)
54{
55   va_list args;
56   int threshold = _LOADER_WARNING;
57   const char *libgl_debug;
58
59   libgl_debug = getenv("LIBGL_DEBUG");
60   if (libgl_debug) {
61      if (strstr(libgl_debug, "quiet"))
62         threshold = _LOADER_FATAL;
63      else if (strstr(libgl_debug, "verbose"))
64         threshold = _LOADER_DEBUG;
65   }
66
67   /* Note that the _LOADER_* levels are lower numbers for more severe. */
68   if (level <= threshold) {
69      fprintf(stderr, "libGL%s: ", level <= _LOADER_WARNING ? " error" : "");
70      va_start(args, f);
71      vfprintf(stderr, f, args);
72      va_end(args);
73   }
74}
75
76#ifndef GL_LIB_NAME
77#define GL_LIB_NAME "libGL.so.1"
78#endif
79
80#ifndef DEFAULT_DRIVER_DIR
81/* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
82#define DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
83#endif
84
85/**
86 * Try to \c dlopen the named driver.
87 *
88 * This function adds the "_dri.so" suffix to the driver name and searches the
89 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
90 * order to find the driver.
91 *
92 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
93 *
94 * \returns
95 * A handle from \c dlopen, or \c NULL if driver file not found.
96 */
97_X_HIDDEN void *
98driOpenDriver(const char *driverName)
99{
100   void *glhandle, *handle;
101   const char *libPaths, *p, *next;
102   char realDriverName[200];
103   int len;
104
105   /* Attempt to make sure libGL symbols will be visible to the driver */
106   glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
107
108   libPaths = NULL;
109   if (geteuid() == getuid()) {
110      /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
111      libPaths = getenv("LIBGL_DRIVERS_PATH");
112      if (!libPaths)
113         libPaths = getenv("LIBGL_DRIVERS_DIR");        /* deprecated */
114   }
115   if (libPaths == NULL)
116      libPaths = DEFAULT_DRIVER_DIR;
117
118   handle = NULL;
119   for (p = libPaths; *p; p = next) {
120      next = strchr(p, ':');
121      if (next == NULL) {
122         len = strlen(p);
123         next = p + len;
124      }
125      else {
126         len = next - p;
127         next++;
128      }
129
130#ifdef GLX_USE_TLS
131      snprintf(realDriverName, sizeof realDriverName,
132               "%.*s/tls/%s_dri.so", len, p, driverName);
133      InfoMessageF("OpenDriver: trying %s\n", realDriverName);
134      handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
135#endif
136
137      if (handle == NULL) {
138         snprintf(realDriverName, sizeof realDriverName,
139                  "%.*s/%s_dri.so", len, p, driverName);
140         InfoMessageF("OpenDriver: trying %s\n", realDriverName);
141         handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
142      }
143
144      if (handle != NULL)
145         break;
146      else
147         InfoMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
148   }
149
150   if (!handle)
151      ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
152
153   if (glhandle)
154      dlclose(glhandle);
155
156   return handle;
157}
158
159_X_HIDDEN const __DRIextension **
160driGetDriverExtensions(void *handle, const char *driver_name)
161{
162   const __DRIextension **extensions = NULL;
163   const __DRIextension **(*get_extensions)(void);
164   char *get_extensions_name = loader_get_extensions_name(driver_name);
165
166   if (get_extensions_name) {
167      get_extensions = dlsym(handle, get_extensions_name);
168      if (get_extensions) {
169         free(get_extensions_name);
170         return get_extensions();
171      } else {
172         InfoMessageF("driver does not expose %s(): %s\n",
173                      get_extensions_name, dlerror());
174         free(get_extensions_name);
175      }
176   }
177
178   extensions = dlsym(handle, __DRI_DRIVER_EXTENSIONS);
179   if (extensions == NULL) {
180      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
181      return NULL;
182   }
183
184   return extensions;
185}
186
187static GLboolean
188__driGetMSCRate(__DRIdrawable *draw,
189		int32_t * numerator, int32_t * denominator,
190		void *loaderPrivate)
191{
192   __GLXDRIdrawable *glxDraw = loaderPrivate;
193
194   return __glxGetMscRate(glxDraw->psc, numerator, denominator);
195}
196
197_X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = {
198   .base = {__DRI_SYSTEM_TIME, 1 },
199
200   .getUST              = __glXGetUST,
201   .getMSCRate          = __driGetMSCRate
202};
203
204#define __ATTRIB(attrib, field) \
205    { attrib, offsetof(struct glx_config, field) }
206
207static const struct
208{
209   unsigned int attrib, offset;
210} attribMap[] = {
211   __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
212      __ATTRIB(__DRI_ATTRIB_LEVEL, level),
213      __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
214      __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
215      __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
216      __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
217      __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
218      __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
219      __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
220      __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
221      __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
222      __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
223      __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
224      __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
225      __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
226      __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
227      __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
228#if 0
229      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
230      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
231      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
232      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
233      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
234      __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
235      __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
236      __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
237      __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
238      __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
239#endif
240      __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
241      __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
242      __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
243      __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
244      __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
245      __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
246      __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
247      __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
248      __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE,
249                     bindToMipmapTexture),
250      __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
251      __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
252};
253
254static int
255scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
256{
257   unsigned glxValue, i;
258
259   for (i = 0; i < ARRAY_SIZE(attribMap); i++)
260      if (attribMap[i].attrib == attrib) {
261         glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
262         return glxValue == GLX_DONT_CARE || glxValue == value;
263      }
264
265   return GL_TRUE;              /* Is a non-existing attribute equal to value? */
266}
267
268static int
269driConfigEqual(const __DRIcoreExtension *core,
270               struct glx_config *config, const __DRIconfig *driConfig)
271{
272   unsigned int attrib, value, glxValue;
273   int i;
274
275   i = 0;
276   while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
277      switch (attrib) {
278      case __DRI_ATTRIB_RENDER_TYPE:
279         glxValue = 0;
280         if (value & __DRI_ATTRIB_RGBA_BIT) {
281            glxValue |= GLX_RGBA_BIT;
282         }
283         if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
284            glxValue |= GLX_COLOR_INDEX_BIT;
285         }
286         if (value & __DRI_ATTRIB_FLOAT_BIT) {
287            glxValue |= GLX_RGBA_FLOAT_BIT_ARB;
288         }
289         if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) {
290            glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
291         }
292         if (glxValue != config->renderType)
293            return GL_FALSE;
294         break;
295
296      case __DRI_ATTRIB_CONFIG_CAVEAT:
297         if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
298            glxValue = GLX_NON_CONFORMANT_CONFIG;
299         else if (value & __DRI_ATTRIB_SLOW_BIT)
300            glxValue = GLX_SLOW_CONFIG;
301         else
302            glxValue = GLX_NONE;
303         if (glxValue != config->visualRating)
304            return GL_FALSE;
305         break;
306
307      case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
308         glxValue = 0;
309         if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
310            glxValue |= GLX_TEXTURE_1D_BIT_EXT;
311         if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
312            glxValue |= GLX_TEXTURE_2D_BIT_EXT;
313         if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
314            glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
315         if (config->bindToTextureTargets != GLX_DONT_CARE &&
316             glxValue != config->bindToTextureTargets)
317            return GL_FALSE;
318         break;
319
320      case __DRI_ATTRIB_SWAP_METHOD:
321         if (value == __DRI_ATTRIB_SWAP_EXCHANGE)
322            glxValue = GLX_SWAP_EXCHANGE_OML;
323         else if (value == __DRI_ATTRIB_SWAP_COPY)
324            glxValue = GLX_SWAP_COPY_OML;
325         else
326            glxValue = GLX_SWAP_UNDEFINED_OML;
327
328         if (!scalarEqual(config, attrib, glxValue))
329            return GL_FALSE;
330
331         break;
332
333      default:
334         if (!scalarEqual(config, attrib, value))
335            return GL_FALSE;
336      }
337   }
338
339   return GL_TRUE;
340}
341
342static struct glx_config *
343createDriMode(const __DRIcoreExtension * core,
344	      struct glx_config *config, const __DRIconfig **driConfigs)
345{
346   __GLXDRIconfigPrivate *driConfig;
347   int i;
348
349   for (i = 0; driConfigs[i]; i++) {
350      if (driConfigEqual(core, config, driConfigs[i]))
351         break;
352   }
353
354   if (driConfigs[i] == NULL)
355      return NULL;
356
357   driConfig = malloc(sizeof *driConfig);
358   if (driConfig == NULL)
359      return NULL;
360
361   driConfig->base = *config;
362   driConfig->driConfig = driConfigs[i];
363
364   return &driConfig->base;
365}
366
367_X_HIDDEN struct glx_config *
368driConvertConfigs(const __DRIcoreExtension * core,
369                  struct glx_config *configs, const __DRIconfig **driConfigs)
370{
371   struct glx_config head, *tail, *m;
372
373   tail = &head;
374   head.next = NULL;
375   for (m = configs; m; m = m->next) {
376      tail->next = createDriMode(core, m, driConfigs);
377      if (tail->next == NULL) {
378         /* no matching dri config for m */
379         continue;
380      }
381
382
383      tail = tail->next;
384   }
385
386   return head.next;
387}
388
389_X_HIDDEN void
390driDestroyConfigs(const __DRIconfig **configs)
391{
392   int i;
393
394   for (i = 0; configs[i]; i++)
395      free((__DRIconfig *) configs[i]);
396   free(configs);
397}
398
399static struct glx_config *
400driInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw)
401{
402   unsigned int fbconfig = 0;
403
404   if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) {
405      return glx_config_find_fbconfig(psc->configs, fbconfig);
406   }
407
408   return NULL;
409}
410
411_X_HIDDEN __GLXDRIdrawable *
412driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
413{
414   struct glx_display *const priv = __glXInitialize(gc->psc->dpy);
415   __GLXDRIdrawable *pdraw;
416   struct glx_screen *psc;
417   struct glx_config *config = gc->config;
418
419   if (priv == NULL)
420      return NULL;
421
422   if (glxDrawable == None)
423      return NULL;
424
425   psc = priv->screens[gc->screen];
426   if (priv->drawHash == NULL)
427      return NULL;
428
429   if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
430      pdraw->refcount ++;
431      return pdraw;
432   }
433
434   if (config == NULL)
435      config = driInferDrawableConfig(gc->psc, glxDrawable);
436   if (config == NULL)
437      return NULL;
438
439   pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable,
440                                          config);
441
442   if (pdraw == NULL) {
443      ErrorMessageF("failed to create drawable\n");
444      return NULL;
445   }
446
447   if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
448      (*pdraw->destroyDrawable) (pdraw);
449      return NULL;
450   }
451   pdraw->refcount = 1;
452
453   return pdraw;
454}
455
456_X_HIDDEN void
457driReleaseDrawables(struct glx_context *gc)
458{
459   const struct glx_display *priv = gc->psc->display;
460   __GLXDRIdrawable *pdraw;
461
462   if (priv == NULL)
463      return;
464
465   if (__glxHashLookup(priv->drawHash,
466		       gc->currentDrawable, (void *) &pdraw) == 0) {
467      if (pdraw->drawable == pdraw->xDrawable) {
468	 pdraw->refcount --;
469	 if (pdraw->refcount == 0) {
470	    (*pdraw->destroyDrawable)(pdraw);
471	    __glxHashDelete(priv->drawHash, gc->currentDrawable);
472	 }
473      }
474   }
475
476   if (__glxHashLookup(priv->drawHash,
477		       gc->currentReadable, (void *) &pdraw) == 0) {
478      if (pdraw->drawable == pdraw->xDrawable) {
479	 pdraw->refcount --;
480	 if (pdraw->refcount == 0) {
481	    (*pdraw->destroyDrawable)(pdraw);
482	    __glxHashDelete(priv->drawHash, gc->currentReadable);
483	 }
484      }
485   }
486
487   gc->currentDrawable = None;
488   gc->currentReadable = None;
489
490}
491
492_X_HIDDEN bool
493dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
494                         unsigned *major_ver, unsigned *minor_ver,
495                         uint32_t *render_type, uint32_t *flags, unsigned *api,
496                         int *reset, int *release, unsigned *error)
497{
498   unsigned i;
499   bool got_profile = false;
500   uint32_t profile;
501
502   *major_ver = 1;
503   *minor_ver = 0;
504   *render_type = GLX_RGBA_TYPE;
505   *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
506   *release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
507   *flags = 0;
508   *api = __DRI_API_OPENGL;
509
510   if (num_attribs == 0) {
511      return true;
512   }
513
514   /* This is actually an internal error, but what the heck.
515    */
516   if (attribs == NULL) {
517      *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
518      return false;
519   }
520
521   for (i = 0; i < num_attribs; i++) {
522      switch (attribs[i * 2]) {
523      case GLX_CONTEXT_MAJOR_VERSION_ARB:
524	 *major_ver = attribs[i * 2 + 1];
525	 break;
526      case GLX_CONTEXT_MINOR_VERSION_ARB:
527	 *minor_ver = attribs[i * 2 + 1];
528	 break;
529      case GLX_CONTEXT_FLAGS_ARB:
530	 *flags = attribs[i * 2 + 1];
531	 break;
532      case GLX_CONTEXT_PROFILE_MASK_ARB:
533	 profile = attribs[i * 2 + 1];
534	 got_profile = true;
535	 break;
536      case GLX_RENDER_TYPE:
537         *render_type = attribs[i * 2 + 1];
538	 break;
539      case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
540         switch (attribs[i * 2 + 1]) {
541         case GLX_NO_RESET_NOTIFICATION_ARB:
542            *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
543            break;
544         case GLX_LOSE_CONTEXT_ON_RESET_ARB:
545            *reset = __DRI_CTX_RESET_LOSE_CONTEXT;
546            break;
547         default:
548            *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
549            return false;
550         }
551         break;
552      case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
553         switch (attribs[i * 2 + 1]) {
554         case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB:
555            *release = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
556            break;
557         case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB:
558            *release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
559            break;
560         default:
561            *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
562            return false;
563         }
564         break;
565      default:
566	 /* If an unknown attribute is received, fail.
567	  */
568	 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
569	 return false;
570      }
571   }
572
573   if (!got_profile) {
574      if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
575	 *api = __DRI_API_OPENGL_CORE;
576   } else {
577      switch (profile) {
578      case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
579	 /* There are no profiles before OpenGL 3.2.  The
580	  * GLX_ARB_create_context_profile spec says:
581	  *
582	  *     "If the requested OpenGL version is less than 3.2,
583	  *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
584	  *     of the context is determined solely by the requested version."
585	  */
586	 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
587	    ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
588	 break;
589      case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
590	 *api = __DRI_API_OPENGL;
591	 break;
592      case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
593         if (*major_ver >= 3)
594            *api = __DRI_API_GLES3;
595         else if (*major_ver == 2 && *minor_ver == 0)
596            *api = __DRI_API_GLES2;
597         else if (*major_ver == 1 && *minor_ver < 2)
598            *api = __DRI_API_GLES;
599         else {
600            *error = __DRI_CTX_ERROR_BAD_API;
601            return false;
602         }
603         break;
604      default:
605	 *error = __DRI_CTX_ERROR_BAD_API;
606	 return false;
607      }
608   }
609
610   /* Unknown flag value.
611    */
612   if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE
613                  | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)) {
614      *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
615      return false;
616   }
617
618   /* There are no forward-compatible contexts before OpenGL 3.0.  The
619    * GLX_ARB_create_context spec says:
620    *
621    *     "Forward-compatible contexts are defined only for OpenGL versions
622    *     3.0 and later."
623    */
624   if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
625      *error = __DRI_CTX_ERROR_BAD_FLAG;
626      return false;
627   }
628
629   if (*major_ver >= 3 && *render_type == GLX_COLOR_INDEX_TYPE) {
630      *error = __DRI_CTX_ERROR_BAD_FLAG;
631      return false;
632   }
633
634   *error = __DRI_CTX_ERROR_SUCCESS;
635   return true;
636}
637
638#endif /* GLX_DIRECT_RENDERING */
639