示例#1
0
static __DRIcontext *
driCreateContextAttribs(__DRIscreen *screen, int api,
                        const __DRIconfig *config,
                        __DRIcontext *shared,
                        unsigned num_attribs,
                        const uint32_t *attribs,
                        unsigned *error,
                        void *data)
{
    __DRIcontext *context;
    const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
    void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
    gl_api mesa_api;
    unsigned major_version = 1;
    unsigned minor_version = 0;
    uint32_t flags = 0;
    bool notify_reset = false;

    assert((num_attribs == 0) || (attribs != NULL));

    if (!(screen->api_mask & (1 << api))) {
	*error = __DRI_CTX_ERROR_BAD_API;
	return NULL;
    }

    switch (api) {
    case __DRI_API_OPENGL:
	mesa_api = API_OPENGL_COMPAT;
	break;
    case __DRI_API_GLES:
	mesa_api = API_OPENGLES;
	break;
    case __DRI_API_GLES2:
    case __DRI_API_GLES3:
	mesa_api = API_OPENGLES2;
	break;
    case __DRI_API_OPENGL_CORE:
        mesa_api = API_OPENGL_CORE;
        break;
    default:
	*error = __DRI_CTX_ERROR_BAD_API;
	return NULL;
    }

    for (unsigned i = 0; i < num_attribs; i++) {
	switch (attribs[i * 2]) {
	case __DRI_CTX_ATTRIB_MAJOR_VERSION:
	    major_version = attribs[i * 2 + 1];
	    break;
	case __DRI_CTX_ATTRIB_MINOR_VERSION:
	    minor_version = attribs[i * 2 + 1];
	    break;
	case __DRI_CTX_ATTRIB_FLAGS:
	    flags = attribs[i * 2 + 1];
	    break;
        case __DRI_CTX_ATTRIB_RESET_STRATEGY:
            notify_reset = (attribs[i * 2 + 1]
                            != __DRI_CTX_RESET_NO_NOTIFICATION);
            break;
	default:
	    /* We can't create a context that satisfies the requirements of an
	     * attribute that we don't understand.  Return failure.
	     */
	    assert(!"Should not get here.");
	    *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
	    return NULL;
	}
    }

    /* Mesa does not support the GL_ARB_compatibilty extension or the
     * compatibility profile.  This means that we treat a API_OPENGL_COMPAT 3.1 as
     * API_OPENGL_CORE and reject API_OPENGL_COMPAT 3.2+.
     */
    if (mesa_api == API_OPENGL_COMPAT && major_version == 3 && minor_version == 1)
       mesa_api = API_OPENGL_CORE;

    if (mesa_api == API_OPENGL_COMPAT
        && ((major_version > 3)
            || (major_version == 3 && minor_version >= 2))) {
       *error = __DRI_CTX_ERROR_BAD_API;
       return NULL;
    }

    /* The latest version of EGL_KHR_create_context spec says:
     *
     *     "If the EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR flag bit is set in
     *     EGL_CONTEXT_FLAGS_KHR, then a <debug context> will be created.
     *     [...] This bit is supported for OpenGL and OpenGL ES contexts.
     *
     * No other EGL_CONTEXT_OPENGL_*_BIT is legal for an ES context.
     *
     * However, Mesa's EGL layer translates the context attribute
     * EGL_CONTEXT_OPENGL_ROBUST_ACCESS into the context flag
     * __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS.  That attribute is legal for ES
     * (with EGL 1.5 or EGL_EXT_create_context_robustness) and GL (only with
     * EGL 1.5).
     *
     * From the EGL_EXT_create_context_robustness spec:
     *
     *     This extension is written against the OpenGL ES 2.0 Specification
     *     but can apply to OpenGL ES 1.1 and up.
     *
     * From the EGL 1.5 (2014.08.27) spec, p55:
     *
     *     If the EGL_CONTEXT_OPENGL_ROBUST_ACCESS attribute is set to
     *     EGL_TRUE, a context supporting robust buffer access will be created.
     *     OpenGL contexts must support the GL_ARB_robustness extension, or
     *     equivalent core API functional- ity. OpenGL ES contexts must support
     *     the GL_EXT_robustness extension, or equivalent core API
     *     functionality.
     */
    if (mesa_api != API_OPENGL_COMPAT
        && mesa_api != API_OPENGL_CORE
        && (flags & ~(__DRI_CTX_FLAG_DEBUG |
	              __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS))) {
	*error = __DRI_CTX_ERROR_BAD_FLAG;
	return NULL;
    }

    /* There are no forward-compatible contexts before OpenGL 3.0.  The
     * GLX_ARB_create_context spec says:
     *
     *     "Forward-compatible contexts are defined only for OpenGL versions
     *     3.0 and later."
     *
     * Forward-looking contexts are supported by silently converting the
     * requested API to API_OPENGL_CORE.
     *
     * In Mesa, a debug context is the same as a regular context.
     */
    if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
       mesa_api = API_OPENGL_CORE;
    }

    const uint32_t allowed_flags = (__DRI_CTX_FLAG_DEBUG
                                    | __DRI_CTX_FLAG_FORWARD_COMPATIBLE
                                    | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS);
    if (flags & ~allowed_flags) {
	*error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
	return NULL;
    }

    if (!validate_context_version(screen, mesa_api,
                                  major_version, minor_version, error))
       return NULL;

    context = calloc(1, sizeof *context);
    if (!context) {
	*error = __DRI_CTX_ERROR_NO_MEMORY;
	return NULL;
    }

    context->loaderPrivate = data;

    context->driScreenPriv = screen;
    context->driDrawablePriv = NULL;
    context->driReadablePriv = NULL;

    if (!screen->driver->CreateContext(mesa_api, modes, context,
                                       major_version, minor_version,
                                       flags, notify_reset, error, shareCtx)) {
        free(context);
        return NULL;
    }

    *error = __DRI_CTX_ERROR_SUCCESS;
    return context;
}
示例#2
0
bool
intelInitContext(struct intel_context *intel,
                 int api,
                 unsigned major_version,
                 unsigned minor_version,
                 const struct gl_config * mesaVis,
                 __DRIcontext * driContextPriv,
                 void *sharedContextPrivate,
                 struct dd_function_table *functions,
                 unsigned *dri_ctx_error)
{
   struct gl_context *ctx = &intel->ctx;
   struct gl_context *shareCtx = (struct gl_context *) sharedContextPrivate;
   __DRIscreen *sPriv = driContextPriv->driScreenPriv;
   struct intel_screen *intelScreen = sPriv->driverPrivate;
   int bo_reuse_mode;
   struct gl_config visual;

   /* we can't do anything without a connection to the device */
   if (intelScreen->bufmgr == NULL) {
      *dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
      return false;
   }

   if (!validate_context_version(intelScreen,
                                 api, major_version, minor_version,
                                 dri_ctx_error))
      return false;

   /* Can't rely on invalidate events, fall back to glViewport hack */
   if (!driContextPriv->driScreenPriv->dri2.useInvalidate) {
      intel->saved_viewport = functions->Viewport;
      functions->Viewport = intel_viewport;
   }

   if (mesaVis == NULL) {
      memset(&visual, 0, sizeof visual);
      mesaVis = &visual;
   }

   intel->intelScreen = intelScreen;

   if (!_mesa_initialize_context(&intel->ctx, api, mesaVis, shareCtx,
                                 functions)) {
      *dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
      printf("%s: failed to init mesa context\n", __FUNCTION__);
      return false;
   }

   driContextPriv->driverPrivate = intel;
   intel->driContext = driContextPriv;
   intel->driFd = sPriv->fd;

   intel->gen = intelScreen->gen;

   const int devID = intelScreen->deviceID;
   if (IS_SNB_GT1(devID) || IS_IVB_GT1(devID) || IS_HSW_GT1(devID))
      intel->gt = 1;
   else if (IS_SNB_GT2(devID) || IS_IVB_GT2(devID) || IS_HSW_GT2(devID))
      intel->gt = 2;
   else
      intel->gt = 0;

   if (IS_HASWELL(devID)) {
      intel->is_haswell = true;
   } else if (IS_G4X(devID)) {
      intel->is_g4x = true;
   } else if (IS_945(devID)) {
      intel->is_945 = true;
   }

   if (intel->gen >= 5) {
      intel->needs_ff_sync = true;
   }

   intel->has_separate_stencil = intel->intelScreen->hw_has_separate_stencil;
   intel->must_use_separate_stencil = intel->intelScreen->hw_must_use_separate_stencil;
   intel->has_hiz = intel->gen >= 6 && !intel->is_haswell;
   intel->has_llc = intel->intelScreen->hw_has_llc;
   intel->has_swizzling = intel->intelScreen->hw_has_swizzling;

   memset(&ctx->TextureFormatSupported,
	  0, sizeof(ctx->TextureFormatSupported));

   driParseConfigFiles(&intel->optionCache, &intelScreen->optionCache,
                       sPriv->myNum, (intel->gen >= 4) ? "i965" : "i915");
   if (intel->gen < 4)
      intel->maxBatchSize = 4096;
   else
      intel->maxBatchSize = BATCH_SZ;

   intel->bufmgr = intelScreen->bufmgr;

   bo_reuse_mode = driQueryOptioni(&intel->optionCache, "bo_reuse");
   switch (bo_reuse_mode) {
   case DRI_CONF_BO_REUSE_DISABLED:
      break;
   case DRI_CONF_BO_REUSE_ALL:
      intel_bufmgr_gem_enable_reuse(intel->bufmgr);
      break;
   }

   ctx->Const.MinLineWidth = 1.0;
   ctx->Const.MinLineWidthAA = 1.0;
   ctx->Const.MaxLineWidth = 5.0;
   ctx->Const.MaxLineWidthAA = 5.0;
   ctx->Const.LineWidthGranularity = 0.5;

   ctx->Const.MinPointSize = 1.0;
   ctx->Const.MinPointSizeAA = 1.0;
   ctx->Const.MaxPointSize = 255.0;
   ctx->Const.MaxPointSizeAA = 3.0;
   ctx->Const.PointSizeGranularity = 1.0;

   if (intel->gen >= 6)
      ctx->Const.MaxClipPlanes = 8;

   ctx->Const.StripTextureBorder = GL_TRUE;

   /* reinitialize the context point state.
    * It depend on constants in __struct gl_contextRec::Const
    */
   _mesa_init_point(ctx);

   if (intel->gen >= 4) {
      ctx->Const.MaxRenderbufferSize = 8192;
   } else {
      ctx->Const.MaxRenderbufferSize = 2048;
   }

   /* Initialize the software rasterizer and helper modules.
    *
    * As of GL 3.1 core, the gen4+ driver doesn't need the swrast context for
    * software fallbacks (which we have to support on legacy GL to do weird
    * glDrawPixels(), glBitmap(), and other functions).
    */
   if (intel->gen <= 3 || api != API_OPENGL_CORE) {
      _swrast_CreateContext(ctx);
   }

   _vbo_CreateContext(ctx);
   if (ctx->swrast_context) {
      _tnl_CreateContext(ctx);
      _swsetup_CreateContext(ctx);

      /* Configure swrast to match hardware characteristics: */
      _swrast_allow_pixel_fog(ctx, false);
      _swrast_allow_vertex_fog(ctx, true);
   }

   _mesa_meta_init(ctx);

   intel->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24;
   intel->hw_stipple = 1;

   /* XXX FBO: this doesn't seem to be used anywhere */
   switch (mesaVis->depthBits) {
   case 0:                     /* what to do in this case? */
   case 16:
      intel->polygon_offset_scale = 1.0;
      break;
   case 24:
      intel->polygon_offset_scale = 2.0;     /* req'd to pass glean */
      break;
   default:
      assert(0);
      break;
   }

   if (intel->gen >= 4)
      intel->polygon_offset_scale /= 0xffff;

   intel->RenderIndex = ~0;

   intelInitExtensions(ctx);

   INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
   if (INTEL_DEBUG & DEBUG_BUFMGR)
      dri_bufmgr_set_debug(intel->bufmgr, true);
   if ((INTEL_DEBUG & DEBUG_SHADER_TIME) && intel->gen < 7) {
      fprintf(stderr,
              "shader_time debugging requires gen7 (Ivybridge) or better.\n");
      INTEL_DEBUG &= ~DEBUG_SHADER_TIME;
   }
   if (INTEL_DEBUG & DEBUG_PERF)
      intel->perf_debug = true;

   if (INTEL_DEBUG & DEBUG_AUB)
      drm_intel_bufmgr_gem_set_aub_dump(intel->bufmgr, true);

   intel_batchbuffer_init(intel);

   intel_fbo_init(intel);

   intel->use_texture_tiling = driQueryOptionb(&intel->optionCache,
					       "texture_tiling");
   intel->use_early_z = driQueryOptionb(&intel->optionCache, "early_z");

   if (!driQueryOptionb(&intel->optionCache, "hiz")) {
       intel->has_hiz = false;
       /* On gen6, you can only do separate stencil with HIZ. */
       if (intel->gen == 6)
	  intel->has_separate_stencil = false;
   }

   intel->prim.primitive = ~0;

   /* Force all software fallbacks */
#ifdef I915
   if (driQueryOptionb(&intel->optionCache, "no_rast")) {
      fprintf(stderr, "disabling 3D rasterization\n");
      intel->no_rast = 1;
   }
#endif

   if (driQueryOptionb(&intel->optionCache, "always_flush_batch")) {
      fprintf(stderr, "flushing batchbuffer before/after each draw call\n");
      intel->always_flush_batch = 1;
   }

   if (driQueryOptionb(&intel->optionCache, "always_flush_cache")) {
      fprintf(stderr, "flushing GPU caches before/after each draw call\n");
      intel->always_flush_cache = 1;
   }

   if (driQueryOptionb(&intel->optionCache, "disable_throttling")) {
      fprintf(stderr, "disabling flush throttling\n");
      intel->disable_throttling = 1;
   }

   return true;
}
示例#3
0
bool
intelInitContext(struct brw_context *brw,
                 int api,
                 unsigned major_version,
                 unsigned minor_version,
                 const struct gl_config * mesaVis,
                 __DRIcontext * driContextPriv,
                 void *sharedContextPrivate,
                 struct dd_function_table *functions,
                 unsigned *dri_ctx_error)
{
   struct gl_context *ctx = &brw->ctx;
   struct gl_context *shareCtx = (struct gl_context *) sharedContextPrivate;
   __DRIscreen *sPriv = driContextPriv->driScreenPriv;
   struct intel_screen *intelScreen = sPriv->driverPrivate;
   int bo_reuse_mode;
   struct gl_config visual;

   /* we can't do anything without a connection to the device */
   if (intelScreen->bufmgr == NULL) {
      *dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
      return false;
   }

   if (!validate_context_version(intelScreen,
                                 api, major_version, minor_version,
                                 dri_ctx_error))
      return false;

   /* Can't rely on invalidate events, fall back to glViewport hack */
   if (!driContextPriv->driScreenPriv->dri2.useInvalidate) {
      brw->saved_viewport = functions->Viewport;
      functions->Viewport = intel_viewport;
   }

   if (mesaVis == NULL) {
      memset(&visual, 0, sizeof visual);
      mesaVis = &visual;
   }

   brw->intelScreen = intelScreen;

   if (!_mesa_initialize_context(&brw->ctx, api, mesaVis, shareCtx,
                                 functions)) {
      *dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
      printf("%s: failed to init mesa context\n", __FUNCTION__);
      return false;
   }

   driContextPriv->driverPrivate = brw;
   brw->driContext = driContextPriv;

   brw->gen = intelScreen->gen;

   const int devID = intelScreen->deviceID;
   if (IS_SNB_GT1(devID) || IS_IVB_GT1(devID) || IS_HSW_GT1(devID))
      brw->gt = 1;
   else if (IS_SNB_GT2(devID) || IS_IVB_GT2(devID) || IS_HSW_GT2(devID))
      brw->gt = 2;
   else if (IS_HSW_GT3(devID))
      brw->gt = 3;
   else
      brw->gt = 0;

   if (IS_HASWELL(devID)) {
      brw->is_haswell = true;
   } else if (IS_BAYTRAIL(devID)) {
      brw->is_baytrail = true;
      brw->gt = 1;
   } else if (IS_G4X(devID)) {
      brw->is_g4x = true;
   }

   brw->has_separate_stencil = brw->intelScreen->hw_has_separate_stencil;
   brw->must_use_separate_stencil = brw->intelScreen->hw_must_use_separate_stencil;
   brw->has_hiz = brw->gen >= 6;
   brw->has_llc = brw->intelScreen->hw_has_llc;
   brw->has_swizzling = brw->intelScreen->hw_has_swizzling;

   memset(&ctx->TextureFormatSupported,
	  0, sizeof(ctx->TextureFormatSupported));

   driParseConfigFiles(&brw->optionCache, &intelScreen->optionCache,
                       sPriv->myNum, "i965");

   /* Estimate the size of the mappable aperture into the GTT.  There's an
    * ioctl to get the whole GTT size, but not one to get the mappable subset.
    * It turns out it's basically always 256MB, though some ancient hardware
    * was smaller.
    */
   uint32_t gtt_size = 256 * 1024 * 1024;

   /* We don't want to map two objects such that a memcpy between them would
    * just fault one mapping in and then the other over and over forever.  So
    * we would need to divide the GTT size by 2.  Additionally, some GTT is
    * taken up by things like the framebuffer and the ringbuffer and such, so
    * be more conservative.
    */
   brw->max_gtt_map_object_size = gtt_size / 4;

   brw->bufmgr = intelScreen->bufmgr;

   bo_reuse_mode = driQueryOptioni(&brw->optionCache, "bo_reuse");
   switch (bo_reuse_mode) {
   case DRI_CONF_BO_REUSE_DISABLED:
      break;
   case DRI_CONF_BO_REUSE_ALL:
      intel_bufmgr_gem_enable_reuse(brw->bufmgr);
      break;
   }

   /* Initialize the software rasterizer and helper modules.
    *
    * As of GL 3.1 core, the gen4+ driver doesn't need the swrast context for
    * software fallbacks (which we have to support on legacy GL to do weird
    * glDrawPixels(), glBitmap(), and other functions).
    */
   if (api != API_OPENGL_CORE && api != API_OPENGLES2) {
      _swrast_CreateContext(ctx);
   }

   _vbo_CreateContext(ctx);
   if (ctx->swrast_context) {
      _tnl_CreateContext(ctx);
      _swsetup_CreateContext(ctx);

      /* Configure swrast to match hardware characteristics: */
      _swrast_allow_pixel_fog(ctx, false);
      _swrast_allow_vertex_fog(ctx, true);
   }

   _mesa_meta_init(ctx);

   intelInitExtensions(ctx);

   INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
   if (INTEL_DEBUG & DEBUG_BUFMGR)
      dri_bufmgr_set_debug(brw->bufmgr, true);
   if ((INTEL_DEBUG & DEBUG_SHADER_TIME) && brw->gen < 7) {
      fprintf(stderr,
              "shader_time debugging requires gen7 (Ivybridge) or better.\n");
      INTEL_DEBUG &= ~DEBUG_SHADER_TIME;
   }
   if (INTEL_DEBUG & DEBUG_PERF)
      brw->perf_debug = true;

   if (INTEL_DEBUG & DEBUG_AUB)
      drm_intel_bufmgr_gem_set_aub_dump(brw->bufmgr, true);

   intel_batchbuffer_init(brw);

   intel_fbo_init(brw);

   if (!driQueryOptionb(&brw->optionCache, "hiz")) {
       brw->has_hiz = false;
       /* On gen6, you can only do separate stencil with HIZ. */
       if (brw->gen == 6)
	  brw->has_separate_stencil = false;
   }

   if (driQueryOptionb(&brw->optionCache, "always_flush_batch")) {
      fprintf(stderr, "flushing batchbuffer before/after each draw call\n");
      brw->always_flush_batch = 1;
   }

   if (driQueryOptionb(&brw->optionCache, "always_flush_cache")) {
      fprintf(stderr, "flushing GPU caches before/after each draw call\n");
      brw->always_flush_cache = 1;
   }

   if (driQueryOptionb(&brw->optionCache, "disable_throttling")) {
      fprintf(stderr, "disabling flush throttling\n");
      brw->disable_throttling = 1;
   }

   return true;
}
示例#4
0
static __DRIcontext *
driCreateContextAttribs(__DRIscreen *screen, int api,
                        const __DRIconfig *config,
                        __DRIcontext *shared,
                        unsigned num_attribs,
                        const uint32_t *attribs,
                        unsigned *error,
                        void *data)
{
    __DRIcontext *context;
    const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
    void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
    gl_api mesa_api;
    unsigned major_version = 1;
    unsigned minor_version = 0;
    uint32_t flags = 0;
    bool notify_reset = false;

    assert((num_attribs == 0) || (attribs != NULL));

    if (!(screen->api_mask & (1 << api))) {
	*error = __DRI_CTX_ERROR_BAD_API;
	return NULL;
    }

    switch (api) {
    case __DRI_API_OPENGL:
	mesa_api = API_OPENGL_COMPAT;
	break;
    case __DRI_API_GLES:
	mesa_api = API_OPENGLES;
	break;
    case __DRI_API_GLES2:
    case __DRI_API_GLES3:
	mesa_api = API_OPENGLES2;
	break;
    case __DRI_API_OPENGL_CORE:
        mesa_api = API_OPENGL_CORE;
        break;
    default:
	*error = __DRI_CTX_ERROR_BAD_API;
	return NULL;
    }

    for (unsigned i = 0; i < num_attribs; i++) {
	switch (attribs[i * 2]) {
	case __DRI_CTX_ATTRIB_MAJOR_VERSION:
	    major_version = attribs[i * 2 + 1];
	    break;
	case __DRI_CTX_ATTRIB_MINOR_VERSION:
	    minor_version = attribs[i * 2 + 1];
	    break;
	case __DRI_CTX_ATTRIB_FLAGS:
	    flags = attribs[i * 2 + 1];
	    break;
        case __DRI_CTX_ATTRIB_RESET_STRATEGY:
            notify_reset = (attribs[i * 2 + 1]
                            != __DRI_CTX_RESET_NO_NOTIFICATION);
            break;
	default:
	    /* We can't create a context that satisfies the requirements of an
	     * attribute that we don't understand.  Return failure.
	     */
	    assert(!"Should not get here.");
	    *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
	    return NULL;
	}
    }

    /* Mesa does not support the GL_ARB_compatibilty extension or the
     * compatibility profile.  This means that we treat a API_OPENGL_COMPAT 3.1 as
     * API_OPENGL_CORE and reject API_OPENGL_COMPAT 3.2+.
     */
    if (mesa_api == API_OPENGL_COMPAT && major_version == 3 && minor_version == 1)
       mesa_api = API_OPENGL_CORE;

    if (mesa_api == API_OPENGL_COMPAT
        && ((major_version > 3)
            || (major_version == 3 && minor_version >= 2))) {
       *error = __DRI_CTX_ERROR_BAD_API;
       return NULL;
    }

    /* The EGL_KHR_create_context spec says:
     *
     *     "Flags are only defined for OpenGL context creation, and specifying
     *     a flags value other than zero for other types of contexts,
     *     including OpenGL ES contexts, will generate an error."
     *
     * The GLX_EXT_create_context_es2_profile specification doesn't say
     * anything specific about this case.  However, none of the known flags
     * have any meaning in an ES context, so this seems safe.
     */
    if (mesa_api != API_OPENGL_COMPAT
        && mesa_api != API_OPENGL_CORE
        && flags != 0) {
	*error = __DRI_CTX_ERROR_BAD_FLAG;
	return NULL;
    }

    /* There are no forward-compatible contexts before OpenGL 3.0.  The
     * GLX_ARB_create_context spec says:
     *
     *     "Forward-compatible contexts are defined only for OpenGL versions
     *     3.0 and later."
     *
     * Forward-looking contexts are supported by silently converting the
     * requested API to API_OPENGL_CORE.
     *
     * In Mesa, a debug context is the same as a regular context.
     */
    if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
       mesa_api = API_OPENGL_CORE;
    }

    if ((flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE))
        != 0) {
	*error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
	return NULL;
    }

    if (!validate_context_version(screen, mesa_api,
                                  major_version, minor_version, error))
       return NULL;

    context = calloc(1, sizeof *context);
    if (!context) {
	*error = __DRI_CTX_ERROR_NO_MEMORY;
	return NULL;
    }

    context->loaderPrivate = data;

    context->driScreenPriv = screen;
    context->driDrawablePriv = NULL;
    context->driReadablePriv = NULL;

    if (!screen->driver->CreateContext(mesa_api, modes, context,
                                       major_version, minor_version,
                                       flags, notify_reset, error, shareCtx)) {
        free(context);
        return NULL;
    }

    struct gl_context *ctx = context->driverPrivate;
    if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
        ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
    if ((flags & __DRI_CTX_FLAG_DEBUG) != 0) {
        ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT;
        ctx->Debug.DebugOutput = GL_TRUE;
    }

    *error = __DRI_CTX_ERROR_SUCCESS;
    return context;
}