Home | History | Annotate | Download | only in glx
      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 (at) precisioninsight.com>
     32  *   Brian Paul <brian (at) precisioninsight.com>
     33  *   Kristian Hgsberg (krh (at) 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 
     44 #ifndef RTLD_NOW
     45 #define RTLD_NOW 0
     46 #endif
     47 #ifndef RTLD_GLOBAL
     48 #define RTLD_GLOBAL 0
     49 #endif
     50 
     51 /**
     52  * Print informational message to stderr if LIBGL_DEBUG is set to
     53  * "verbose".
     54  */
     55 _X_HIDDEN void
     56 InfoMessageF(const char *f, ...)
     57 {
     58    va_list args;
     59    const char *env;
     60 
     61    if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
     62       fprintf(stderr, "libGL: ");
     63       va_start(args, f);
     64       vfprintf(stderr, f, args);
     65       va_end(args);
     66    }
     67 }
     68 
     69 /**
     70  * Print error message to stderr if LIBGL_DEBUG is set to anything but
     71  * "quiet", (do nothing if LIBGL_DEBUG is unset).
     72  */
     73 _X_HIDDEN void
     74 ErrorMessageF(const char *f, ...)
     75 {
     76    va_list args;
     77    const char *env;
     78 
     79    if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
     80       fprintf(stderr, "libGL error: ");
     81       va_start(args, f);
     82       vfprintf(stderr, f, args);
     83       va_end(args);
     84    }
     85 }
     86 
     87 /**
     88  * Print error message unless LIBGL_DEBUG is set to "quiet".
     89  *
     90  * The distinction between CriticalErrorMessageF and ErrorMessageF is
     91  * that critcial errors will be printed by default, (even when
     92  * LIBGL_DEBUG is unset).
     93  */
     94 _X_HIDDEN void
     95 CriticalErrorMessageF(const char *f, ...)
     96 {
     97    va_list args;
     98    const char *env;
     99 
    100    if (!(env = getenv("LIBGL_DEBUG")) || !strstr(env, "quiet")) {
    101       fprintf(stderr, "libGL error: ");
    102       va_start(args, f);
    103       vfprintf(stderr, f, args);
    104       va_end(args);
    105 
    106       if (!env || !strstr(env, "verbose"))
    107          fprintf(stderr, "libGL error: Try again with LIBGL_DEBUG=verbose for more details.\n");
    108    }
    109 }
    110 
    111 #ifndef DEFAULT_DRIVER_DIR
    112 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
    113 #define DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
    114 #endif
    115 
    116 /**
    117  * Try to \c dlopen the named driver.
    118  *
    119  * This function adds the "_dri.so" suffix to the driver name and searches the
    120  * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
    121  * order to find the driver.
    122  *
    123  * \param driverName - a name like "i965", "radeon", "nouveau", etc.
    124  *
    125  * \returns
    126  * A handle from \c dlopen, or \c NULL if driver file not found.
    127  */
    128 _X_HIDDEN void *
    129 driOpenDriver(const char *driverName)
    130 {
    131    void *glhandle, *handle;
    132    const char *libPaths, *p, *next;
    133    char realDriverName[200];
    134    int len;
    135 
    136    /* Attempt to make sure libGL symbols will be visible to the driver */
    137    glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
    138 
    139    libPaths = NULL;
    140    if (geteuid() == getuid()) {
    141       /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
    142       libPaths = getenv("LIBGL_DRIVERS_PATH");
    143       if (!libPaths)
    144          libPaths = getenv("LIBGL_DRIVERS_DIR");        /* deprecated */
    145    }
    146    if (libPaths == NULL)
    147       libPaths = DEFAULT_DRIVER_DIR;
    148 
    149    handle = NULL;
    150    for (p = libPaths; *p; p = next) {
    151       next = strchr(p, ':');
    152       if (next == NULL) {
    153          len = strlen(p);
    154          next = p + len;
    155       }
    156       else {
    157          len = next - p;
    158          next++;
    159       }
    160 
    161 #ifdef GLX_USE_TLS
    162       snprintf(realDriverName, sizeof realDriverName,
    163                "%.*s/tls/%s_dri.so", len, p, driverName);
    164       InfoMessageF("OpenDriver: trying %s\n", realDriverName);
    165       handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
    166 #endif
    167 
    168       if (handle == NULL) {
    169          snprintf(realDriverName, sizeof realDriverName,
    170                   "%.*s/%s_dri.so", len, p, driverName);
    171          InfoMessageF("OpenDriver: trying %s\n", realDriverName);
    172          handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
    173       }
    174 
    175       if (handle != NULL)
    176          break;
    177       else
    178          ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
    179    }
    180 
    181    if (!handle)
    182       ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
    183 
    184    if (glhandle)
    185       dlclose(glhandle);
    186 
    187    return handle;
    188 }
    189 
    190 static GLboolean
    191 __driGetMSCRate(__DRIdrawable *draw,
    192 		int32_t * numerator, int32_t * denominator,
    193 		void *loaderPrivate)
    194 {
    195    __GLXDRIdrawable *glxDraw = loaderPrivate;
    196 
    197    return __glxGetMscRate(glxDraw, numerator, denominator);
    198 }
    199 
    200 _X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = {
    201    {__DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION},
    202    __glXGetUST,
    203    __driGetMSCRate
    204 };
    205 
    206 #define __ATTRIB(attrib, field) \
    207     { attrib, offsetof(struct glx_config, field) }
    208 
    209 static const struct
    210 {
    211    unsigned int attrib, offset;
    212 } attribMap[] = {
    213    __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
    214       __ATTRIB(__DRI_ATTRIB_LEVEL, level),
    215       __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
    216       __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
    217       __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
    218       __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
    219       __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
    220       __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
    221       __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
    222       __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
    223       __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
    224       __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
    225       __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
    226       __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
    227       __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
    228       __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
    229       __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
    230 #if 0
    231       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
    232       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
    233       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
    234       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
    235       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
    236       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
    237       __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
    238       __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
    239       __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
    240       __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
    241 #endif
    242       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
    243       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
    244       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
    245       __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
    246       __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
    247 #if 0
    248       __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
    249 #endif
    250 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
    251       __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
    252       __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE,
    253                      bindToMipmapTexture),
    254       __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
    255       __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
    256 };
    257 
    258 static int
    259 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
    260 {
    261    unsigned int glxValue;
    262    int i;
    263 
    264    for (i = 0; i < ARRAY_SIZE(attribMap); i++)
    265       if (attribMap[i].attrib == attrib) {
    266          glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
    267          return glxValue == GLX_DONT_CARE || glxValue == value;
    268       }
    269 
    270    return GL_TRUE;              /* Is a non-existing attribute equal to value? */
    271 }
    272 
    273 static int
    274 driConfigEqual(const __DRIcoreExtension *core,
    275                struct glx_config *config, const __DRIconfig *driConfig)
    276 {
    277    unsigned int attrib, value, glxValue;
    278    int i;
    279 
    280    i = 0;
    281    while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
    282       switch (attrib) {
    283       case __DRI_ATTRIB_RENDER_TYPE:
    284          glxValue = 0;
    285          if (value & __DRI_ATTRIB_RGBA_BIT) {
    286             glxValue |= GLX_RGBA_BIT;
    287          }
    288          else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
    289             glxValue |= GLX_COLOR_INDEX_BIT;
    290          }
    291          if (glxValue != config->renderType)
    292             return GL_FALSE;
    293          break;
    294 
    295       case __DRI_ATTRIB_CONFIG_CAVEAT:
    296          if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
    297             glxValue = GLX_NON_CONFORMANT_CONFIG;
    298          else if (value & __DRI_ATTRIB_SLOW_BIT)
    299             glxValue = GLX_SLOW_CONFIG;
    300          else
    301             glxValue = GLX_NONE;
    302          if (glxValue != config->visualRating)
    303             return GL_FALSE;
    304          break;
    305 
    306       case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
    307          glxValue = 0;
    308          if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
    309             glxValue |= GLX_TEXTURE_1D_BIT_EXT;
    310          if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
    311             glxValue |= GLX_TEXTURE_2D_BIT_EXT;
    312          if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
    313             glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
    314          if (config->bindToTextureTargets != GLX_DONT_CARE &&
    315              glxValue != config->bindToTextureTargets)
    316             return GL_FALSE;
    317          break;
    318 
    319       default:
    320          if (!scalarEqual(config, attrib, value))
    321             return GL_FALSE;
    322       }
    323    }
    324 
    325    return GL_TRUE;
    326 }
    327 
    328 static struct glx_config *
    329 createDriMode(const __DRIcoreExtension * core,
    330 	      struct glx_config *config, const __DRIconfig **driConfigs)
    331 {
    332    __GLXDRIconfigPrivate *driConfig;
    333    int i;
    334 
    335    for (i = 0; driConfigs[i]; i++) {
    336       if (driConfigEqual(core, config, driConfigs[i]))
    337          break;
    338    }
    339 
    340    if (driConfigs[i] == NULL)
    341       return NULL;
    342 
    343    driConfig = Xmalloc(sizeof *driConfig);
    344    if (driConfig == NULL)
    345       return NULL;
    346 
    347    driConfig->base = *config;
    348    driConfig->driConfig = driConfigs[i];
    349 
    350    return &driConfig->base;
    351 }
    352 
    353 _X_HIDDEN struct glx_config *
    354 driConvertConfigs(const __DRIcoreExtension * core,
    355                   struct glx_config *configs, const __DRIconfig **driConfigs)
    356 {
    357    struct glx_config head, *tail, *m;
    358 
    359    tail = &head;
    360    head.next = NULL;
    361    for (m = configs; m; m = m->next) {
    362       tail->next = createDriMode(core, m, driConfigs);
    363       if (tail->next == NULL) {
    364          /* no matching dri config for m */
    365          continue;
    366       }
    367 
    368 
    369       tail = tail->next;
    370    }
    371 
    372    return head.next;
    373 }
    374 
    375 _X_HIDDEN void
    376 driDestroyConfigs(const __DRIconfig **configs)
    377 {
    378    int i;
    379 
    380    for (i = 0; configs[i]; i++)
    381       free((__DRIconfig *) configs[i]);
    382    free(configs);
    383 }
    384 
    385 _X_HIDDEN __GLXDRIdrawable *
    386 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
    387 {
    388    struct glx_display *const priv = __glXInitialize(gc->psc->dpy);
    389    __GLXDRIdrawable *pdraw;
    390    struct glx_screen *psc;
    391 
    392    if (priv == NULL)
    393       return NULL;
    394 
    395    psc = priv->screens[gc->screen];
    396    if (priv->drawHash == NULL)
    397       return NULL;
    398 
    399    if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
    400       pdraw->refcount ++;
    401       return pdraw;
    402    }
    403 
    404    pdraw = psc->driScreen->createDrawable(psc, glxDrawable,
    405                                           glxDrawable, gc->config);
    406 
    407    if (pdraw == NULL) {
    408       ErrorMessageF("failed to create drawable\n");
    409       return NULL;
    410    }
    411 
    412    if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
    413       (*pdraw->destroyDrawable) (pdraw);
    414       return NULL;
    415    }
    416    pdraw->refcount = 1;
    417 
    418    return pdraw;
    419 }
    420 
    421 _X_HIDDEN void
    422 driReleaseDrawables(struct glx_context *gc)
    423 {
    424    const struct glx_display *priv = gc->psc->display;
    425    __GLXDRIdrawable *pdraw;
    426 
    427    if (priv == NULL)
    428       return;
    429 
    430    if (__glxHashLookup(priv->drawHash,
    431 		       gc->currentDrawable, (void *) &pdraw) == 0) {
    432       if (pdraw->drawable == pdraw->xDrawable) {
    433 	 pdraw->refcount --;
    434 	 if (pdraw->refcount == 0) {
    435 	    (*pdraw->destroyDrawable)(pdraw);
    436 	    __glxHashDelete(priv->drawHash, gc->currentDrawable);
    437 	 }
    438       }
    439    }
    440 
    441    if (__glxHashLookup(priv->drawHash,
    442 		       gc->currentReadable, (void *) &pdraw) == 0) {
    443       if (pdraw->drawable == pdraw->xDrawable) {
    444 	 pdraw->refcount --;
    445 	 if (pdraw->refcount == 0) {
    446 	    (*pdraw->destroyDrawable)(pdraw);
    447 	    __glxHashDelete(priv->drawHash, gc->currentReadable);
    448 	 }
    449       }
    450    }
    451 
    452    gc->currentDrawable = None;
    453    gc->currentReadable = None;
    454 
    455 }
    456 
    457 _X_HIDDEN bool
    458 dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
    459 			 unsigned *major_ver, unsigned *minor_ver,
    460 			 uint32_t *flags, unsigned *api, int *reset,
    461                          unsigned *error)
    462 {
    463    unsigned i;
    464    bool got_profile = false;
    465    uint32_t profile;
    466    int render_type = GLX_RGBA_TYPE;
    467 
    468    if (num_attribs == 0) {
    469       *api = __DRI_API_OPENGL;
    470       return true;
    471    }
    472 
    473    /* This is actually an internal error, but what the heck.
    474     */
    475    if (attribs == NULL) {
    476       *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
    477       return false;
    478    }
    479 
    480    *major_ver = 1;
    481    *minor_ver = 0;
    482    *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
    483 
    484    for (i = 0; i < num_attribs; i++) {
    485       switch (attribs[i * 2]) {
    486       case GLX_CONTEXT_MAJOR_VERSION_ARB:
    487 	 *major_ver = attribs[i * 2 + 1];
    488 	 break;
    489       case GLX_CONTEXT_MINOR_VERSION_ARB:
    490 	 *minor_ver = attribs[i * 2 + 1];
    491 	 break;
    492       case GLX_CONTEXT_FLAGS_ARB:
    493 	 *flags = attribs[i * 2 + 1];
    494 	 break;
    495       case GLX_CONTEXT_PROFILE_MASK_ARB:
    496 	 profile = attribs[i * 2 + 1];
    497 	 got_profile = true;
    498 	 break;
    499       case GLX_RENDER_TYPE:
    500 	 render_type = attribs[i * 2 + 1];
    501 	 break;
    502       case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
    503          switch (attribs[i * 2 + 1]) {
    504          case GLX_NO_RESET_NOTIFICATION_ARB:
    505             *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
    506             break;
    507          case GLX_LOSE_CONTEXT_ON_RESET_ARB:
    508             *reset = __DRI_CTX_RESET_LOSE_CONTEXT;
    509             break;
    510          default:
    511             *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
    512             return false;
    513          }
    514          break;
    515       default:
    516 	 /* If an unknown attribute is received, fail.
    517 	  */
    518 	 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
    519 	 return false;
    520       }
    521    }
    522 
    523    *api = __DRI_API_OPENGL;
    524    if (!got_profile) {
    525       if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
    526 	 *api = __DRI_API_OPENGL_CORE;
    527    } else {
    528       switch (profile) {
    529       case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
    530 	 /* There are no profiles before OpenGL 3.2.  The
    531 	  * GLX_ARB_create_context_profile spec says:
    532 	  *
    533 	  *     "If the requested OpenGL version is less than 3.2,
    534 	  *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
    535 	  *     of the context is determined solely by the requested version."
    536 	  */
    537 	 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
    538 	    ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
    539 	 break;
    540       case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
    541 	 *api = __DRI_API_OPENGL;
    542 	 break;
    543       case GLX_CONTEXT_ES2_PROFILE_BIT_EXT:
    544 	 *api = __DRI_API_GLES2;
    545 	 break;
    546       default:
    547 	 *error = __DRI_CTX_ERROR_BAD_API;
    548 	 return false;
    549       }
    550    }
    551 
    552    /* Unknown flag value.
    553     */
    554    if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE
    555                   | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)) {
    556       *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
    557       return false;
    558    }
    559 
    560    /* There are no forward-compatible contexts before OpenGL 3.0.  The
    561     * GLX_ARB_create_context spec says:
    562     *
    563     *     "Forward-compatible contexts are defined only for OpenGL versions
    564     *     3.0 and later."
    565     */
    566    if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
    567       *error = __DRI_CTX_ERROR_BAD_FLAG;
    568       return false;
    569    }
    570 
    571    if (*major_ver >= 3 && render_type == GLX_COLOR_INDEX_TYPE) {
    572       *error = __DRI_CTX_ERROR_BAD_FLAG;
    573       return false;
    574    }
    575 
    576    /* The GLX_EXT_create_context_es2_profile spec says:
    577     *
    578     *     "... If the version requested is 2.0, and the
    579     *     GLX_CONTEXT_ES2_PROFILE_BIT_EXT bit is set in the
    580     *     GLX_CONTEXT_PROFILE_MASK_ARB attribute (see below), then the context
    581     *     returned will implement OpenGL ES 2.0. This is the only way in which
    582     *     an implementation may request an OpenGL ES 2.0 context."
    583     */
    584    if (*api == __DRI_API_GLES2 && (*major_ver != 2 || *minor_ver != 0)) {
    585       *error = __DRI_CTX_ERROR_BAD_API;
    586       return false;
    587    }
    588 
    589    *error = __DRI_CTX_ERROR_SUCCESS;
    590    return true;
    591 }
    592 
    593 #endif /* GLX_DIRECT_RENDERING */
    594