#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
-#include "egldriver.h"
-#include "eglglobals.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;
+ }
+ }
+
+ 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;
+}
/**
* 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;
- }
- }
-
- ctx->Config = conf;
- ctx->DrawSurface = EGL_NO_SURFACE;
- ctx->ReadSurface = EGL_NO_SURFACE;
- ctx->ClientAPI = api;
- ctx->WindowRenderBuffer = EGL_NONE;
+ err = _eglParseContextAttribList(ctx, attrib_list);
+ if (err != EGL_SUCCESS)
+ return _eglError(err, "eglCreateContext");
return EGL_TRUE;
}
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
_EGLContext *share_list, const EGLint *attrib_list)
{
-#if 0 /* example code */
- _EGLContext *context;
-
- context = (_EGLContext *) calloc(1, sizeof(_EGLContext));
- if (!context)
- return NULL;
-
- if (!_eglInitContext(drv, context, conf, attrib_list)) {
- free(context);
- return NULL;
- }
-
- return context;
-#endif
return NULL;
}
/**
- * Bind the context to the surface as the draw or read surface. Return the
- * previous surface that the context is bound to.
- *
- * Note that the context may be NULL.
+ * 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 _EGLSurface *
-_eglBindContextToSurface(_EGLContext *ctx, _EGLSurface *surf, EGLint readdraw)
+static void
+_eglBindContextToSurfaces(_EGLContext *newCtx,
+ _EGLSurface **draw, _EGLSurface **read)
{
- _EGLSurface **attachment, *oldSurf;
+ _EGLSurface *newDraw = *draw, *newRead = *read;
+ _EGLContext *oldCtx;
- if (!ctx) {
- surf->Binding = NULL;
- return NULL;
+ /*
+ * The goal is to bind a newCtx to newDraw. Since newDraw may already have
+ * a binding context (oldCtx), and newCtx may already be bound to another
+ * surface (oldDraw), the old bindings are broken first and the new one is
+ * created.
+ */
+ oldCtx = newDraw->CurrentContext;
+ if (newCtx != oldCtx) {
+ if (oldCtx) {
+ assert(oldCtx->DrawSurface == newDraw);
+ oldCtx->DrawSurface = NULL;
+ }
+
+ if (newCtx) {
+ _EGLSurface *oldDraw = newCtx->DrawSurface;
+ if (oldDraw)
+ oldDraw->CurrentContext = NULL;
+
+ newCtx->DrawSurface = newDraw;
+ *draw = oldDraw;
+ }
+
+ newDraw->CurrentContext = newCtx;
}
- attachment = (readdraw == EGL_DRAW) ?
- &ctx->DrawSurface : &ctx->ReadSurface;
- oldSurf = *attachment;
+ /* likewise */
+ if (newRead != newDraw)
+ oldCtx = newRead->CurrentContext;
+ if (newCtx != oldCtx) {
+ if (oldCtx) {
+ assert(oldCtx->ReadSurface == newRead);
+ oldCtx->ReadSurface = NULL;
+ }
- if (oldSurf == surf)
- return NULL;
+ if (newCtx) {
+ _EGLSurface *oldRead = newCtx->ReadSurface;
+ if (oldRead)
+ oldRead->CurrentContext = NULL;
- if (oldSurf)
- oldSurf->Binding = NULL;
- surf->Binding = ctx;
- *attachment = surf;
+ newCtx->ReadSurface = newRead;
+ *read = oldRead;
+ }
- return oldSurf;
+ newRead->CurrentContext = newCtx;
+ }
}
_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;
}
*
* 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 ((draw->CurrentContext && draw->CurrentContext != ctx) ||
+ (read->CurrentContext && read->CurrentContext != ctx))
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
/* simply require the configs to be equal */
/**
- * 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 current thread and given surfaces. Return the
+ * previously bound context and the surfaces it bound to. Each argument is
+ * both input and output.
*/
EGLBoolean
-_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
- _EGLSurface *read, _EGLContext *ctx)
+_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
- _EGLSurface *oldDraw = NULL, *oldRead = NULL;
- _EGLContext *oldCtx;
+ _EGLContext *newCtx = *ctx, *oldCtx;
- if (!_eglCheckMakeCurrent(ctx, draw, read))
+ if (!_eglCheckMakeCurrent(newCtx, *draw, *read))
return EGL_FALSE;
- oldCtx = _eglBindContextToThread(ctx, t);
+ /* bind the new context */
+ oldCtx = _eglBindContextToThread(newCtx, t);
- if (ctx) {
- oldDraw = _eglBindContextToSurface(ctx, draw, EGL_DRAW);
- oldRead = _eglBindContextToSurface(ctx, read, EGL_READ);
- }
- else if (oldCtx) {
- /* unbind the old context from its binding surfaces */
- oldDraw = oldCtx->DrawSurface;
- oldRead = oldCtx->ReadSurface;
-
- if (oldDraw)
- _eglBindContextToSurface(NULL, oldDraw, EGL_DRAW);
- if (oldRead && oldRead != oldDraw)
- _eglBindContextToSurface(NULL, oldRead, EGL_READ);
- }
+ if (newCtx)
+ _eglBindContextToSurfaces(newCtx, draw, read);
+
+ /* unbind the old context from its binding surfaces */
+ if (oldCtx && oldCtx != newCtx) {
+ assert(!*draw && !*read);
- /* avoid double destroy */
- if (oldRead && oldRead == oldDraw)
- oldRead = NULL;
+ *draw = oldCtx->DrawSurface;
+ *read = oldCtx->ReadSurface;
+ assert(*draw && *read);
- if (oldCtx && !_eglIsContextLinked(oldCtx))
- drv->API.DestroyContext(drv, dpy, oldCtx);
- if (oldDraw && !_eglIsSurfaceLinked(oldDraw))
- drv->API.DestroySurface(drv, dpy, oldDraw);
- if (oldRead && !_eglIsSurfaceLinked(oldRead))
- drv->API.DestroySurface(drv, dpy, oldRead);
+ _eglBindContextToSurfaces(NULL, draw, read);
+ }
+
+ *ctx = oldCtx;
+ /* draw and read have been updated in _eglBindContextToSurfaces */
return EGL_TRUE;
}
+/**
+ * Just a placeholder/demo function. Drivers should override this.
+ */
+EGLBoolean
+_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
+ _EGLSurface *read, _EGLContext *ctx)
+{
+ return EGL_FALSE;
+}
+
+
/**
* This is defined by the EGL_MESA_copy_context extension.
*/