X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Feglcontext.c;h=38e195f0446444175edcfd357fc47284ef1b394b;hb=f8e6d19f3f40931be741b44d3edf210c38e13f0f;hp=f73cf2d0b354c93319ce5753736c041ffea9d06b;hpb=caa5c8dfe8e5857aa25b2a3fa649d553e651e144;p=mesa.git diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index f73cf2d0b35..38e195f0446 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -1,3 +1,33 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 @@ -83,15 +113,6 @@ _eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list) } } - if (err == EGL_SUCCESS) { - EGLint renderable_type, api_bit; - - renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE); - api_bit = _eglGetContextAPIBit(ctx); - if (!(renderable_type & api_bit)) - err = EGL_BAD_CONFIG; - } - return err; } @@ -101,8 +122,8 @@ _eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list) * in the attrib_list. */ EGLBoolean -_eglInitContext(_EGLDriver *drv, _EGLContext *ctx, - _EGLConfig *conf, const EGLint *attrib_list) +_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf, + const EGLint *attrib_list) { const EGLenum api = eglQueryAPI(); EGLint err; @@ -112,7 +133,7 @@ _eglInitContext(_EGLDriver *drv, _EGLContext *ctx, return EGL_FALSE; } - memset(ctx, 0, sizeof(_EGLContext)); + _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy); ctx->ClientAPI = api; ctx->Config = conf; ctx->WindowRenderBuffer = EGL_NONE; @@ -120,6 +141,16 @@ _eglInitContext(_EGLDriver *drv, _EGLContext *ctx, ctx->ClientVersion = 1; /* the default, per EGL spec */ err = _eglParseContextAttribList(ctx, 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"); @@ -127,29 +158,6 @@ _eglInitContext(_EGLDriver *drv, _EGLContext *ctx, } -/** - * 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) -{ - return NULL; -} - - -/** - * Default fallback routine - drivers should usually override this. - */ -EGLBoolean -_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) -{ - if (!_eglIsContextBound(ctx)) - free(ctx); - return EGL_TRUE; -} - - #ifdef EGL_VERSION_1_2 static EGLint _eglQueryContextRenderBuffer(_EGLContext *ctx) @@ -180,7 +188,9 @@ _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; @@ -201,35 +211,6 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, } -/** - * Bind the context to the surfaces. Return the surfaces that are "orphaned". - * That is, when the context is not NULL, return the surfaces it previously - * bound to; when the context is NULL, the same surfaces are returned. - */ -static void -_eglBindContextToSurfaces(_EGLContext *ctx, - _EGLSurface **draw, _EGLSurface **read) -{ - _EGLSurface *newDraw = *draw, *newRead = *read; - - if (newDraw->CurrentContext) - newDraw->CurrentContext->DrawSurface = NULL; - newDraw->CurrentContext = ctx; - - if (newRead->CurrentContext) - newRead->CurrentContext->ReadSurface = NULL; - newRead->CurrentContext = ctx; - - if (ctx) { - *draw = ctx->DrawSurface; - ctx->DrawSurface = newDraw; - - *read = ctx->ReadSurface; - ctx->ReadSurface = newRead; - } -} - - /** * Bind the context to the thread and return the previous context. * @@ -245,15 +226,14 @@ _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t) _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex; oldCtx = t->CurrentContexts[apiIndex]; - if (ctx == oldCtx) - return NULL; - - if (oldCtx) - oldCtx->Binding = NULL; - if (ctx) - ctx->Binding = t; + if (ctx != oldCtx) { + if (oldCtx) + oldCtx->Binding = NULL; + if (ctx) + ctx->Binding = t; - t->CurrentContexts[apiIndex] = ctx; + t->CurrentContexts[apiIndex] = ctx; + } return oldCtx; } @@ -266,7 +246,9 @@ static EGLBoolean _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) { _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLDisplay *dpy; EGLint conflict_api; + EGLBoolean surfaceless; if (_eglIsCurrentThreadDummy()) return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent"); @@ -278,13 +260,24 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) return EGL_TRUE; } - /* ctx/draw/read must be all given */ - if (draw == NULL || read == NULL) - return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + dpy = ctx->Resource.Display; + switch (_eglGetContextAPIBit(ctx)) { + case EGL_OPENGL_ES_BIT: + surfaceless = dpy->Extensions.KHR_surfaceless_gles1; + break; + case EGL_OPENGL_ES2_BIT: + surfaceless = dpy->Extensions.KHR_surfaceless_gles2; + break; + case EGL_OPENGL_BIT: + surfaceless = dpy->Extensions.KHR_surfaceless_opengl; + break; + default: + surfaceless = EGL_FALSE; + break; + } - /* context stealing from another thread is not allowed */ - if (ctx->Binding && ctx->Binding != t) - return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + if (!surfaceless && (draw == NULL || read == NULL)) + return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); /* * The spec says @@ -293,19 +286,27 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) * bound to contexts in another thread, an EGL_BAD_ACCESS error is * generated." * - * But it also says + * and * * "at most one context may be bound to a particular surface at a given * time" - * - * The latter is more restrictive so we can check only the latter case. */ - if ((draw->CurrentContext && draw->CurrentContext != ctx) || - (read->CurrentContext && read->CurrentContext != ctx)) + 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"); + } + if (read && read->CurrentContext && read->CurrentContext != ctx) { + if (read->CurrentContext->Binding != t || + read->CurrentContext->ClientAPI != ctx->ClientAPI) + return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); + } /* simply require the configs to be equal */ - if (draw->Config != ctx->Config || read->Config != ctx->Config) + if ((draw && draw->Config != ctx->Config) || + (read && read->Config != ctx->Config)) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); switch (ctx->ClientAPI) { @@ -332,65 +333,65 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) /** * Bind the context to the current thread and given surfaces. Return the - * previously bound context and the surfaces it bound to. Each argument is - * both input and output. + * 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 -_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read) +_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read, + _EGLContext **old_ctx, + _EGLSurface **old_draw, _EGLSurface **old_read) { _EGLThreadInfo *t = _eglGetCurrentThread(); - _EGLContext *newCtx = *ctx, *oldCtx; + _EGLContext *prev_ctx; + _EGLSurface *prev_draw, *prev_read; - if (!_eglCheckMakeCurrent(newCtx, *draw, *read)) + if (!_eglCheckMakeCurrent(ctx, draw, read)) return EGL_FALSE; + /* increment refcounts before binding */ + _eglGetContext(ctx); + _eglGetSurface(draw); + _eglGetSurface(read); + /* bind the new context */ - oldCtx = _eglBindContextToThread(newCtx, t); - *ctx = oldCtx; - if (newCtx) - _eglBindContextToSurfaces(newCtx, draw, read); - - /* unbind the old context from its binding surfaces */ - if (oldCtx) { - /* - * If the new context replaces some old context, the new one should not - * be current before the replacement and it should not be bound to any - * surface. - */ - if (newCtx) - assert(!*draw && !*read); - - *draw = oldCtx->DrawSurface; - *read = oldCtx->ReadSurface; - assert(*draw && *read); - - _eglBindContextToSurfaces(NULL, draw, read); - } + prev_ctx = _eglBindContextToThread(ctx, t); - return EGL_TRUE; -} + /* 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; -/** - * Just a placeholder/demo function. Drivers should override this. - */ -EGLBoolean -_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, - _EGLSurface *read, _EGLContext *ctx) -{ - return EGL_FALSE; -} + 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; -/** - * This is defined by the EGL_MESA_copy_context extension. - */ -EGLBoolean -_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, - EGLContext dest, EGLint mask) -{ - /* 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; + 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; }