X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Feglcontext.c;h=588f48921f2d28c177bec9e8bc4a826e0efb1910;hb=c59ad265df655a19285d813144f6b76d7f49d7fd;hp=ee4b1b59f5b3f1cbc2e5ac3a68ad7e28711307f9;hpb=b605f4ff11c894500f2d0273c5d4653ff413448d;p=mesa.git diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index ee4b1b59f5b..588f48921f2 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -1,94 +1,466 @@ +/************************************************************************** + * + * Copyright 2008 VMware, Inc. + * Copyright 2009-2010 Chia-I Wu + * Copyright 2010-2011 LunarG, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + #include #include #include #include "eglconfig.h" #include "eglcontext.h" #include "egldisplay.h" -#include "egldriver.h" -#include "eglglobals.h" +#include "eglcurrent.h" #include "eglsurface.h" +#include "egllog.h" /** - * Initialize the given _EGLContext object to defaults and/or the values - * in the attrib_list. + * Return the API bit (one of EGL_xxx_BIT) of the context. */ -EGLBoolean -_eglInitContext(_EGLDriver *drv, _EGLContext *ctx, - _EGLConfig *conf, const EGLint *attrib_list) +static EGLint +_eglGetContextAPIBit(_EGLContext *ctx) { - EGLint i; - const EGLenum api = eglQueryAPI(); + EGLint bit = 0; - if (api == EGL_NONE) { - _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)"); - return EGL_FALSE; + switch (ctx->ClientAPI) { + case EGL_OPENGL_ES_API: + switch (ctx->ClientMajorVersion) { + case 1: + bit = EGL_OPENGL_ES_BIT; + break; + case 2: + bit = EGL_OPENGL_ES2_BIT; + break; + case 3: + bit = EGL_OPENGL_ES3_BIT_KHR; + break; + default: + break; + } + break; + case EGL_OPENVG_API: + bit = EGL_OPENVG_BIT; + break; + case EGL_OPENGL_API: + bit = EGL_OPENGL_BIT; + break; + default: + break; } - memset(ctx, 0, sizeof(_EGLContext)); + return bit; +} + + +/** + * Parse the list of context attributes and return the proper error code. + */ +static EGLint +_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy, + const EGLint *attrib_list) +{ + EGLenum api = ctx->ClientAPI; + EGLint i, err = EGL_SUCCESS; - ctx->ClientVersion = 1; /* the default, per EGL spec */ + if (!attrib_list) + return EGL_SUCCESS; - for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { - switch (attrib_list[i]) { + if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) { + _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]); + return EGL_BAD_ATTRIBUTE; + } + + for (i = 0; attrib_list[i] != EGL_NONE; i++) { + EGLint attr = attrib_list[i++]; + EGLint val = attrib_list[i]; + + switch (attr) { case EGL_CONTEXT_CLIENT_VERSION: - i++; - ctx->ClientVersion = attrib_list[i]; + /* The EGL 1.4 spec says: + * + * "attribute EGL_CONTEXT_CLIENT_VERSION is only valid when the + * current rendering API is EGL_OPENGL_ES_API" + * + * The EGL_KHR_create_context spec says: + * + * "EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 + * (this token is an alias for EGL_CONTEXT_CLIENT_VERSION)" + * + * "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and + * EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API + * version. They are only meaningful for OpenGL and OpenGL ES + * contexts, and specifying them for other types of contexts will + * generate an error." + */ + if ((api != EGL_OPENGL_ES_API && + (!dpy->Extensions.KHR_create_context || api != EGL_OPENGL_API))) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->ClientMajorVersion = val; + break; + + case EGL_CONTEXT_MINOR_VERSION_KHR: + /* The EGL_KHR_create_context spec says: + * + * "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and + * EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API + * version. They are only meaningful for OpenGL and OpenGL ES + * contexts, and specifying them for other types of contexts will + * generate an error." + */ + if (!dpy->Extensions.KHR_create_context || + (api != EGL_OPENGL_ES_API && api != EGL_OPENGL_API)) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->ClientMinorVersion = val; + break; + + case EGL_CONTEXT_FLAGS_KHR: + if (!dpy->Extensions.KHR_create_context) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + /* 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." + */ + if (api != EGL_OPENGL_API && val != 0) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->Flags |= val; + break; + + case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: + if (!dpy->Extensions.KHR_create_context) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + /* The EGL_KHR_create_context spec says: + * + * "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for + * OpenGL contexts, and specifying it for other types of + * contexts, including OpenGL ES contexts, will generate an + * error." + */ + if (api != EGL_OPENGL_API) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->Profile = val; + break; + + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: + /* The EGL_KHR_create_context spec says: + * + * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only + * meaningful for OpenGL contexts, and specifying it for other + * types of contexts, including OpenGL ES contexts, will generate + * an error." + */ + if (!dpy->Extensions.KHR_create_context + || api != EGL_OPENGL_API) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->ResetNotificationStrategy = val; + break; + + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + /* The EGL_EXT_create_context_robustness spec says: + * + * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only + * meaningful for OpenGL ES contexts, and specifying it for other + * types of contexts will generate an EGL_BAD_ATTRIBUTE error." + */ + if (!dpy->Extensions.EXT_create_context_robustness + || api != EGL_OPENGL_ES_API) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + ctx->ResetNotificationStrategy = val; + break; + + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (!dpy->Extensions.EXT_create_context_robustness) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (val == EGL_TRUE) + ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; break; + + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS: + if (dpy->Version < 15) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (val == EGL_TRUE) + ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + break; + + case EGL_CONTEXT_OPENGL_DEBUG: + if (dpy->Version < 15) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (val == EGL_TRUE) + ctx->Flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + break; + + case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE: + if (dpy->Version < 15) { + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (val == EGL_TRUE) + ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + break; + default: - _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext"); - return EGL_FALSE; + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr); + break; } } - ctx->Config = conf; - ctx->DrawSurface = EGL_NO_SURFACE; - ctx->ReadSurface = EGL_NO_SURFACE; - ctx->ClientAPI = api; - ctx->WindowRenderBuffer = EGL_NONE; + if (api == EGL_OPENGL_API) { + /* The EGL_KHR_create_context spec says: + * + * "If the requested OpenGL version is less than 3.2, + * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the + * functionality of the context is determined solely by the + * requested version." + * + * Since the value is ignored, only validate the setting if the version + * is >= 3.2. + */ + if (ctx->ClientMajorVersion >= 4 + || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) { + switch (ctx->Profile) { + case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR: + case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR: + break; + + default: + /* The EGL_KHR_create_context spec says: + * + * "* If an OpenGL context is requested, the requested version + * is greater than 3.2, and the value for attribute + * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has + * any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR + * and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has + * more than one of these bits set; or if the implementation does + * not support the requested profile, then an EGL_BAD_MATCH error + * is generated." + */ + err = EGL_BAD_MATCH; + break; + } + } - return EGL_TRUE; -} + /* The EGL_KHR_create_context spec says: + * + * "* If an OpenGL context is requested and the values for + * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and + * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with + * the value for attribute + * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL + * version and feature set that are not defined, than an + * EGL_BAD_MATCH error is generated. + * + * ... Thus, examples of invalid combinations of attributes + * include: + * + * - Major version < 1 or > 4 + * - Major version == 1 and minor version < 0 or > 5 + * - Major version == 2 and minor version < 0 or > 1 + * - Major version == 3 and minor version < 0 or > 2 + * - Major version == 4 and minor version < 0 or > 2 + * - Forward-compatible flag set and major version < 3" + */ + if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0) + err = EGL_BAD_MATCH; + + switch (ctx->ClientMajorVersion) { + case 1: + if (ctx->ClientMinorVersion > 5 + || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0) + err = EGL_BAD_MATCH; + break; + case 2: + if (ctx->ClientMinorVersion > 1 + || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0) + err = EGL_BAD_MATCH; + break; -/** - * Just a placeholder/demo function. Real driver will never use this! - */ -_EGLContext * -_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, - _EGLContext *share_list, const EGLint *attrib_list) -{ -#if 0 /* example code */ - _EGLContext *context; + case 3: + /* Note: The text above is incorrect. There *is* an OpenGL 3.3! + */ + if (ctx->ClientMinorVersion > 3) + err = EGL_BAD_MATCH; + break; + + case 4: + default: + /* Don't put additional version checks here. We don't know that + * there won't be versions > 4.2. + */ + break; + } + } else if (api == EGL_OPENGL_ES_API) { + /* The EGL_KHR_create_context spec says: + * + * "* If an OpenGL ES context is requested and the values for + * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and + * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that + * is not defined, than an EGL_BAD_MATCH error is generated. + * + * ... Examples of invalid combinations of attributes include: + * + * - Major version < 1 or > 2 + * - Major version == 1 and minor version < 0 or > 1 + * - Major version == 2 and minor version != 0 + */ + if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0) + err = EGL_BAD_MATCH; + + switch (ctx->ClientMajorVersion) { + case 1: + if (ctx->ClientMinorVersion > 1) + err = EGL_BAD_MATCH; + break; + + case 2: + if (ctx->ClientMinorVersion > 0) + err = EGL_BAD_MATCH; + break; + + case 3: + /* Don't put additional version checks here. We don't know that + * there won't be versions > 3.0. + */ + break; + + default: + err = EGL_BAD_MATCH; + break; + } + } + + switch (ctx->ResetNotificationStrategy) { + case EGL_NO_RESET_NOTIFICATION_KHR: + case EGL_LOSE_CONTEXT_ON_RESET_KHR: + break; - context = (_EGLContext *) calloc(1, sizeof(_EGLContext)); - if (!context) - return NULL; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } - if (!_eglInitContext(drv, context, conf, attrib_list)) { - free(context); - return NULL; + if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR + | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR + | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) { + err = EGL_BAD_ATTRIBUTE; } - return context; -#endif - return NULL; + return err; } /** - * Default fallback routine - drivers should usually override this. + * Initialize the given _EGLContext object to defaults and/or the values + * in the attrib_list. */ EGLBoolean -_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) +_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf, + const EGLint *attrib_list) { - if (!_eglIsContextBound(ctx)) - free(ctx); + const EGLenum api = eglQueryAPI(); + EGLint err; + + if (api == EGL_NONE) { + _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)"); + return EGL_FALSE; + } + + _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy); + ctx->ClientAPI = api; + ctx->Config = conf; + ctx->WindowRenderBuffer = EGL_NONE; + ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + + ctx->ClientMajorVersion = 1; /* the default, per EGL spec */ + ctx->ClientMinorVersion = 0; + ctx->Flags = 0; + ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR; + + err = _eglParseContextAttribList(ctx, dpy, attrib_list); + if (err == EGL_SUCCESS && ctx->Config) { + EGLint api_bit; + + api_bit = _eglGetContextAPIBit(ctx); + if (!(ctx->Config->RenderableType & api_bit)) { + _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x", + api_bit, ctx->Config->RenderableType); + err = EGL_BAD_CONFIG; + } + } + if (err != EGL_SUCCESS) + return _eglError(err, "eglCreateContext"); + return EGL_TRUE; } -#ifdef EGL_VERSION_1_2 static EGLint _eglQueryContextRenderBuffer(_EGLContext *ctx) { @@ -103,7 +475,6 @@ _eglQueryContextRenderBuffer(_EGLContext *ctx) rb = surf->RenderBuffer; return rb; } -#endif /* EGL_VERSION_1_2 */ EGLBoolean @@ -118,19 +489,19 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, switch (attribute) { case EGL_CONFIG_ID: - *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID); + if (!c->Config) + return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); + *value = c->Config->ConfigID; break; case EGL_CONTEXT_CLIENT_VERSION: - *value = c->ClientVersion; + *value = c->ClientMajorVersion; break; -#ifdef EGL_VERSION_1_2 case EGL_CONTEXT_CLIENT_TYPE: *value = c->ClientAPI; break; case EGL_RENDER_BUFFER: *value = _eglQueryContextRenderBuffer(c); break; -#endif /* EGL_VERSION_1_2 */ default: return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); } @@ -140,114 +511,181 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, /** - * Drivers will typically call this to do the error checking and - * update the various flags. - * Then, the driver will do its device-dependent Make-Current stuff. + * Bind the context to the thread and return the previous context. + * + * Note that the context may be NULL. */ -EGLBoolean -_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, - _EGLSurface *read, _EGLContext *ctx) +static _EGLContext * +_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t) { - _EGLThreadInfo *t = _eglGetCurrentThread(); - _EGLContext *oldContext = NULL; - _EGLSurface *oldDrawSurface = NULL; - _EGLSurface *oldReadSurface = NULL; EGLint apiIndex; + _EGLContext *oldCtx; + + apiIndex = (ctx) ? + _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex; + + oldCtx = t->CurrentContexts[apiIndex]; + if (ctx != oldCtx) { + if (oldCtx) + oldCtx->Binding = NULL; + if (ctx) + ctx->Binding = t; + + t->CurrentContexts[apiIndex] = ctx; + } + + return oldCtx; +} + + +/** + * Return true if the given context and surfaces can be made current. + */ +static EGLBoolean +_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLDisplay *dpy; + EGLint conflict_api; if (_eglIsCurrentThreadDummy()) return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent"); - if (ctx) { - /* error checking */ - if (ctx->Binding && ctx->Binding != t) - return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); - if (draw == NULL || read == NULL) - return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); - if (draw->Config != ctx->Config || read->Config != ctx->Config) + /* this is easy */ + if (!ctx) { + if (draw || read) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); - if ((draw->Binding && draw->Binding->Binding != t) || - (read->Binding && read->Binding->Binding != t)) - return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + return EGL_TRUE; + } -#ifdef EGL_VERSION_1_4 - /* OpenGL and OpenGL ES are conflicting */ - switch (ctx->ClientAPI) { - case EGL_OPENGL_ES_API: - if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)]) - return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); - break; - case EGL_OPENGL_API: - if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)]) - return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); - break; - default: - break; - } -#endif - apiIndex = _eglConvertApiToIndex(ctx->ClientAPI); + dpy = ctx->Resource.Display; + if (!dpy->Extensions.KHR_surfaceless_context + && (draw == NULL || read == NULL)) + return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + + /* + * The spec says + * + * "If ctx is current to some other thread, or if either draw or read are + * bound to contexts in another thread, an EGL_BAD_ACCESS error is + * generated." + * + * and + * + * "at most one context may be bound to a particular surface at a given + * time" + */ + if (ctx->Binding && ctx->Binding != t) + return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + if (draw && draw->CurrentContext && draw->CurrentContext != ctx) { + if (draw->CurrentContext->Binding != t || + draw->CurrentContext->ClientAPI != ctx->ClientAPI) + return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); } - else { - if (draw != NULL || read != NULL) + if (read && read->CurrentContext && read->CurrentContext != ctx) { + if (read->CurrentContext->Binding != t || + read->CurrentContext->ClientAPI != ctx->ClientAPI) + return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + } + + /* If the context has a config then it must match that of the two + * surfaces */ + if (ctx->Config) { + if ((draw && draw->Config != ctx->Config) || + (read && read->Config != ctx->Config)) + return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + } else { + /* Otherwise we must be using the EGL_MESA_configless_context + * extension */ + assert(dpy->Extensions.MESA_configless_context); + + /* The extension doesn't permit binding draw and read buffers with + * differing contexts */ + if (draw && read && draw->Config != read->Config) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); - apiIndex = t->CurrentAPIIndex; - } - - oldContext = t->CurrentContexts[apiIndex]; - if (oldContext) { - oldDrawSurface = oldContext->DrawSurface; - oldReadSurface = oldContext->ReadSurface; - assert(oldDrawSurface); - assert(oldReadSurface); - - /* break old bindings */ - t->CurrentContexts[apiIndex] = NULL; - oldContext->Binding = NULL; - oldContext->DrawSurface = NULL; - oldContext->ReadSurface = NULL; - oldDrawSurface->Binding = NULL; - oldReadSurface->Binding = NULL; - - /* - * check if the old context or surfaces need to be deleted - */ - if (!_eglIsSurfaceLinked(oldDrawSurface)) { - assert(draw != oldDrawSurface && read != oldDrawSurface); - drv->API.DestroySurface(drv, dpy, oldDrawSurface); - } - if (oldReadSurface != oldDrawSurface && - !_eglIsSurfaceLinked(oldReadSurface)) { - assert(draw != oldReadSurface && read != oldReadSurface); - drv->API.DestroySurface(drv, dpy, oldReadSurface); - } - if (!_eglIsContextLinked(oldContext)) { - assert(ctx != oldContext); - drv->API.DestroyContext(drv, dpy, oldContext); - } } - /* build new bindings */ - if (ctx) { - t->CurrentContexts[apiIndex] = ctx; - ctx->Binding = t; - ctx->DrawSurface = draw; - ctx->ReadSurface = read; - draw->Binding = ctx; - read->Binding = ctx; + switch (ctx->ClientAPI) { + /* OpenGL and OpenGL ES are conflicting */ + case EGL_OPENGL_ES_API: + conflict_api = EGL_OPENGL_API; + break; + case EGL_OPENGL_API: + conflict_api = EGL_OPENGL_ES_API; + break; + default: + conflict_api = -1; + break; } + if (conflict_api >= 0 && _eglGetAPIContext(conflict_api)) + return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + return EGL_TRUE; } /** - * This is defined by the EGL_MESA_copy_context extension. + * Bind the context to the current thread and given surfaces. Return the + * previous bound context and surfaces. The caller should unreference the + * returned context and surfaces. + * + * Making a second call with the resources returned by the first call + * unsurprisingly undoes the first call, except for the resouce reference + * counts. */ EGLBoolean -_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, - EGLContext dest, EGLint mask) +_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read, + _EGLContext **old_ctx, + _EGLSurface **old_draw, _EGLSurface **old_read) { - /* This function will always have to be overridden/implemented in the - * device driver. If the driver is based on Mesa, use _mesa_copy_context(). - */ - return EGL_FALSE; + _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLContext *prev_ctx; + _EGLSurface *prev_draw, *prev_read; + + if (!_eglCheckMakeCurrent(ctx, draw, read)) + return EGL_FALSE; + + /* increment refcounts before binding */ + _eglGetContext(ctx); + _eglGetSurface(draw); + _eglGetSurface(read); + + /* bind the new context */ + prev_ctx = _eglBindContextToThread(ctx, t); + + /* break previous bindings */ + if (prev_ctx) { + prev_draw = prev_ctx->DrawSurface; + prev_read = prev_ctx->ReadSurface; + + if (prev_draw) + prev_draw->CurrentContext = NULL; + if (prev_read) + prev_read->CurrentContext = NULL; + + prev_ctx->DrawSurface = NULL; + prev_ctx->ReadSurface = NULL; + } + else { + prev_draw = prev_read = NULL; + } + + /* establish new bindings */ + if (ctx) { + if (draw) + draw->CurrentContext = ctx; + if (read) + read->CurrentContext = ctx; + + ctx->DrawSurface = draw; + ctx->ReadSurface = read; + } + + assert(old_ctx && old_draw && old_read); + *old_ctx = prev_ctx; + *old_draw = prev_draw; + *old_read = prev_read; + + return EGL_TRUE; }