+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
+ * 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 <assert.h>
#include <stdlib.h>
#include <string.h>
#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;
}
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;
}
-/**
- * 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.
*
_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;
}
_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");
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
* 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) {
/**
* 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;
}