#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
-#include "egldriver.h"
#include "eglcurrent.h"
#include "eglsurface.h"
+#include "egllog.h"
+
+
+/**
+ * Return the API bit (one of EGL_xxx_BIT) of the context.
+ */
+static EGLint
+_eglGetContextAPIBit(_EGLContext *ctx)
+{
+ EGLint bit = 0;
+
+ 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:
+ break;
+ }
+ break;
+ case EGL_OPENVG_API:
+ bit = EGL_OPENVG_BIT;
+ break;
+ case EGL_OPENGL_API:
+ bit = EGL_OPENGL_BIT;
+ break;
+ default:
+ break;
+ }
+
+ return bit;
+}
+
+
+/**
+ * Parse the list of context attributes and return the proper error code.
+ */
+static EGLint
+_eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list)
+{
+ EGLenum api = ctx->ClientAPI;
+ EGLint i, err = EGL_SUCCESS;
+
+ 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 (err != EGL_SUCCESS) {
+ _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
+ break;
+ }
+ }
+
+ return err;
+}
/**
* 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)
{
- EGLint i;
const EGLenum api = eglQueryAPI();
+ EGLint err;
if (api == EGL_NONE) {
_eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
}
memset(ctx, 0, sizeof(_EGLContext));
+ ctx->Resource.Display = dpy;
+ ctx->ClientAPI = api;
+ ctx->Config = conf;
+ ctx->WindowRenderBuffer = EGL_NONE;
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];
- break;
- default:
- _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext");
- return EGL_FALSE;
+ err = _eglParseContextAttribList(ctx, attrib_list);
+ if (err == EGL_SUCCESS && ctx->Config) {
+ EGLint renderable_type, api_bit;
+
+ renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE);
+ api_bit = _eglGetContextAPIBit(ctx);
+ if (!(renderable_type & api_bit)) {
+ _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
+ api_bit, renderable_type);
+ err = EGL_BAD_CONFIG;
}
}
-
- ctx->Config = conf;
- ctx->DrawSurface = EGL_NO_SURFACE;
- ctx->ReadSurface = EGL_NO_SURFACE;
- ctx->ClientAPI = api;
- ctx->WindowRenderBuffer = EGL_NONE;
+ if (err != EGL_SUCCESS)
+ return _eglError(err, "eglCreateContext");
return EGL_TRUE;
}
}
-/**
- * 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.
*
_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)
+ 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;
+ }
+
+ if (!surfaceless && (draw == NULL || read == NULL))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
/* context stealing from another thread is not allowed */
*
* 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 ((draw && draw->CurrentContext && draw->CurrentContext != ctx) ||
+ (read && read->CurrentContext && read->CurrentContext != ctx))
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.
+ * "orphaned" context and surfaces. Each argument is both input and output.
*/
EGLBoolean
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLContext *newCtx = *ctx, *oldCtx;
+ _EGLSurface *newDraw = *draw, *newRead = *read;
- if (!_eglCheckMakeCurrent(newCtx, *draw, *read))
+ if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead))
return EGL_FALSE;
/* bind the new context */
oldCtx = _eglBindContextToThread(newCtx, t);
- *ctx = oldCtx;
- if (newCtx)
- _eglBindContextToSurfaces(newCtx, draw, read);
- /* unbind the old context from its binding surfaces */
+ /* break old bindings */
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);
-
+ *ctx = oldCtx;
*draw = oldCtx->DrawSurface;
*read = oldCtx->ReadSurface;
- assert(*draw && *read);
- _eglBindContextToSurfaces(NULL, draw, read);
+ if (*draw)
+ (*draw)->CurrentContext = NULL;
+ if (*read)
+ (*read)->CurrentContext = NULL;
+
+ oldCtx->DrawSurface = NULL;
+ oldCtx->ReadSurface = NULL;
}
+ /* establish new bindings */
+ if (newCtx) {
+ if (newDraw)
+ newDraw->CurrentContext = newCtx;
+ if (newRead)
+ newRead->CurrentContext = newCtx;
+
+ newCtx->DrawSurface = newDraw;
+ newCtx->ReadSurface = newRead;
+ }
+
+ /* an old context or surface is not orphaned if it is still bound */
+ if (*ctx == newCtx)
+ *ctx = NULL;
+ if (*draw == newDraw || *draw == newRead)
+ *draw = NULL;
+ if (*read == newDraw || *read == newRead)
+ *read = NULL;
+
return EGL_TRUE;
}