X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Feglcontext.c;h=38e195f0446444175edcfd357fc47284ef1b394b;hb=f8e6d19f3f40931be741b44d3edf210c38e13f0f;hp=4496f76ecebb3991a28c31a3a42943b40410a8e7;hpb=6baa2c8d022e5dd1e305e7da2925c1e6f9370f35;p=mesa.git diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index 4496f76eceb..38e195f0446 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -1,89 +1,159 @@ +/************************************************************************** + * + * 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 #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; - } - - memset(ctx, 0, sizeof(_EGLContext)); - - ctx->ClientVersion = 1; /* the default, per EGL spec */ - - for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { - switch (attrib_list[i]) { - case EGL_CONTEXT_CLIENT_VERSION: - i++; - ctx->ClientVersion = attrib_list[i]; + switch (ctx->ClientAPI) { + case EGL_OPENGL_ES_API: + switch (ctx->ClientVersion) { + case 1: + bit = EGL_OPENGL_ES_BIT; + break; + case 2: + bit = EGL_OPENGL_ES2_BIT; break; default: - _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext"); - return EGL_FALSE; + break; } + break; + case EGL_OPENVG_API: + bit = EGL_OPENVG_BIT; + break; + case EGL_OPENGL_API: + bit = EGL_OPENGL_BIT; + break; + default: + break; } - ctx->Config = conf; - ctx->DrawSurface = EGL_NO_SURFACE; - ctx->ReadSurface = EGL_NO_SURFACE; - ctx->ClientAPI = api; - ctx->WindowRenderBuffer = EGL_NONE; - - return EGL_TRUE; + return bit; } /** - * Just a placeholder/demo function. Real driver will never use this! + * Parse the list of context attributes and return the proper error code. */ -_EGLContext * -_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, - _EGLContext *share_list, const EGLint *attrib_list) +static EGLint +_eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list) { -#if 0 /* example code */ - _EGLContext *context; + EGLenum api = ctx->ClientAPI; + EGLint i, err = EGL_SUCCESS; - context = (_EGLContext *) calloc(1, sizeof(_EGLContext)); - if (!context) - return NULL; + if (!attrib_list) + return EGL_SUCCESS; + + 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: + if (api != EGL_OPENGL_ES_API) { + err = EGL_BAD_ATTRIBUTE; + break; + } + if (val != 1 && val != 2) { + err = EGL_BAD_ATTRIBUTE; + break; + } + ctx->ClientVersion = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } - if (!_eglInitContext(drv, context, conf, attrib_list)) { - free(context); - return NULL; + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr); + break; + } } - 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->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"); + return EGL_TRUE; } @@ -118,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; @@ -139,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->Binding) - newDraw->Binding->DrawSurface = NULL; - newDraw->Binding = ctx; - - if (newRead->Binding) - newRead->Binding->ReadSurface = NULL; - newRead->Binding = 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. * @@ -183,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; } @@ -204,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"); @@ -216,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 @@ -231,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->Binding && draw->Binding != ctx) || - (read->Binding && read->Binding != 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) { @@ -270,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; }