+static void
+setupLoaderExtensions(__DRIscreen *psp,
+ const __DRIextension **extensions)
+{
+ int i;
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
+ psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
+ psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
+ psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0)
+ psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_IMAGE_LOADER) == 0)
+ psp->image.loader = (__DRIimageLoaderExtension *) extensions[i];
+ }
+}
+
+/**
+ * This pointer determines which driver API we'll use in the case of the
+ * loader not passing us an explicit driver extensions list (that would,
+ * itself, contain a pointer to a driver API.)
+ *
+ * A driver's driDriverGetExtensions_drivername() can update this pointer to
+ * what it's returning, and a loader that is ignorant of createNewScreen2()
+ * will get the correct driver screen created, as long as no other
+ * driDriverGetExtensions() happened in between the first one and the
+ * createNewScreen().
+ *
+ * This allows the X Server to not require the significant dri_interface.h
+ * updates for doing createNewScreen2(), which would discourage backporting of
+ * the X Server patches to support the new loader interface.
+ */
+const struct __DriverAPIRec *globalDriverAPI = &driDriverAPI;
+
+/**
+ * This is the first entrypoint in the driver called by the DRI driver loader
+ * after dlopen()ing it.
+ *
+ * It's used to create global state for the driver across contexts on the same
+ * Display.
+ */
+static __DRIscreen *
+driCreateNewScreen2(int scrn, int fd,
+ const __DRIextension **extensions,
+ const __DRIextension **driver_extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ static const __DRIextension *emptyExtensionList[] = { NULL };
+ __DRIscreen *psp;
+
+ psp = calloc(1, sizeof(*psp));
+ if (!psp)
+ return NULL;
+
+ /* By default, use the global driDriverAPI symbol (non-megadrivers). */
+ psp->driver = globalDriverAPI;
+
+ /* If the driver exposes its vtable through its extensions list
+ * (megadrivers), use that instead.
+ */
+ if (driver_extensions) {
+ for (int i = 0; driver_extensions[i]; i++) {
+ if (strcmp(driver_extensions[i]->name, __DRI_DRIVER_VTABLE) == 0) {
+ psp->driver =
+ ((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;
+ }
+ }
+ }
+
+ setupLoaderExtensions(psp, extensions);
+
+ psp->loaderPrivate = data;
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+
+ *driver_configs = psp->driver->InitScreen(psp);
+ if (*driver_configs == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ struct gl_constants consts = { 0 };
+ gl_api api;
+ unsigned version;
+
+ api = API_OPENGLES2;
+ if (_mesa_override_gl_version_contextless(&consts, &api, &version))
+ psp->max_gl_es2_version = version;
+
+ api = API_OPENGL_COMPAT;
+ if (_mesa_override_gl_version_contextless(&consts, &api, &version)) {
+ if (api == API_OPENGL_CORE) {
+ psp->max_gl_core_version = version;
+ } else {
+ psp->max_gl_compat_version = version;
+ }
+ }
+
+ psp->api_mask = 0;
+ if (psp->max_gl_compat_version > 0)
+ psp->api_mask |= (1 << __DRI_API_OPENGL);
+ if (psp->max_gl_core_version > 0)
+ psp->api_mask |= (1 << __DRI_API_OPENGL_CORE);
+ if (psp->max_gl_es1_version > 0)
+ psp->api_mask |= (1 << __DRI_API_GLES);
+ if (psp->max_gl_es2_version > 0)
+ psp->api_mask |= (1 << __DRI_API_GLES2);
+ if (psp->max_gl_es2_version >= 30)
+ psp->api_mask |= (1 << __DRI_API_GLES3);
+
+ driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions);
+ driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri2");
+
+
+ return psp;
+}
+
+static __DRIscreen *
+dri2CreateNewScreen(int scrn, int fd,
+ const __DRIextension **extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ return driCreateNewScreen2(scrn, fd, extensions, NULL,
+ driver_configs, data);
+}
+
+/** swrast driver createNewScreen entrypoint. */
+static __DRIscreen *
+driSWRastCreateNewScreen(int scrn, const __DRIextension **extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ return driCreateNewScreen2(scrn, -1, extensions, NULL,
+ driver_configs, data);
+}
+
+static __DRIscreen *
+driSWRastCreateNewScreen2(int scrn, const __DRIextension **extensions,
+ const __DRIextension **driver_extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ return driCreateNewScreen2(scrn, -1, extensions, driver_extensions,
+ driver_configs, data);
+}
+
+/**
+ * Destroy the per-screen private information.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(__DRIscreen *psp)
+{
+ if (psp) {
+ /* No interaction with the X-server is possible at this point. This
+ * routine is called after XCloseDisplay, so there is no protocol
+ * stream open to the X-server anymore.
+ */
+
+ psp->driver->DestroyScreen(psp);
+
+ driDestroyOptionCache(&psp->optionCache);
+ driDestroyOptionInfo(&psp->optionInfo);
+
+ free(psp);
+ }
+}
+
+static const __DRIextension **driGetExtensions(__DRIscreen *psp)
+{
+ return psp->extensions;
+}
+
+/*@}*/
+
+
+static bool
+validate_context_version(__DRIscreen *screen,
+ int mesa_api,
+ unsigned major_version,
+ unsigned minor_version,
+ unsigned *dri_ctx_error)
+{
+ unsigned req_version = 10 * major_version + minor_version;
+ unsigned max_version = 0;
+
+ switch (mesa_api) {
+ case API_OPENGL_COMPAT:
+ max_version = screen->max_gl_compat_version;
+ break;
+ case API_OPENGL_CORE:
+ max_version = screen->max_gl_core_version;
+ break;
+ case API_OPENGLES:
+ max_version = screen->max_gl_es1_version;
+ break;
+ case API_OPENGLES2:
+ max_version = screen->max_gl_es2_version;
+ break;
+ default:
+ max_version = 0;
+ break;
+ }
+
+ if (max_version == 0) {
+ *dri_ctx_error = __DRI_CTX_ERROR_BAD_API;
+ return false;
+ } else if (req_version > max_version) {
+ *dri_ctx_error = __DRI_CTX_ERROR_BAD_VERSION;
+ return false;
+ }
+
+ return true;
+}
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+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.
+ *
+ * None of the other flags have any meaning in an ES context, so this seems safe.
+ */
+ if (mesa_api != API_OPENGL_COMPAT
+ && mesa_api != API_OPENGL_CORE
+ && (flags & ~__DRI_CTX_FLAG_DEBUG)) {
+ *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;
+}
+
+void
+driContextSetFlags(struct gl_context *ctx, uint32_t flags)
+{
+ if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
+ ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
+ if ((flags & __DRI_CTX_FLAG_DEBUG) != 0) {
+ _mesa_set_debug_state_int(ctx, GL_DEBUG_OUTPUT, GL_TRUE);
+ ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT;
+ }
+}
+
+static __DRIcontext *
+driCreateNewContextForAPI(__DRIscreen *screen, int api,
+ const __DRIconfig *config,
+ __DRIcontext *shared, void *data)
+{
+ unsigned error;
+
+ return driCreateContextAttribs(screen, api, config, shared, 0, NULL,
+ &error, data);
+}
+
+static __DRIcontext *
+driCreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
+ __DRIcontext *shared, void *data)
+{
+ return driCreateNewContextForAPI(screen, __DRI_API_OPENGL,
+ config, shared, data);
+}
+
+/**
+ * Destroy the per-context private information.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void
+driDestroyContext(__DRIcontext *pcp)
+{
+ if (pcp) {
+ pcp->driScreenPriv->driver->DestroyContext(pcp);
+ free(pcp);
+ }
+}
+
+static int
+driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
+{
+ (void) dest;
+ (void) src;
+ (void) mask;
+ return GL_FALSE;
+}
+
+/*@}*/