summaryrefslogtreecommitdiff
path: root/src/egl/main/eglcontext.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/main/eglcontext.c')
-rw-r--r--src/egl/main/eglcontext.c249
1 files changed, 158 insertions, 91 deletions
diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c
index ee4b1b59f5..d0c6b1b64c 100644
--- a/src/egl/main/eglcontext.c
+++ b/src/egl/main/eglcontext.c
@@ -5,7 +5,7 @@
#include "eglcontext.h"
#include "egldisplay.h"
#include "egldriver.h"
-#include "eglglobals.h"
+#include "eglcurrent.h"
#include "eglsurface.h"
@@ -58,20 +58,6 @@ _EGLContext *
_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;
}
@@ -140,99 +126,169 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
/**
- * 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 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.
*/
-EGLBoolean
-_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
- _EGLSurface *read, _EGLContext *ctx)
+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.
+ *
+ * Note that the context may be NULL.
+ */
+static _EGLContext *
+_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
{
- _EGLThreadInfo *t = _eglGetCurrentThread();
- _EGLContext *oldContext = NULL;
- _EGLSurface *oldDrawSurface = NULL;
- _EGLSurface *oldReadSurface = NULL;
EGLint apiIndex;
+ _EGLContext *oldCtx;
+
+ apiIndex = (ctx) ?
+ _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
+
+ oldCtx = t->CurrentContexts[apiIndex];
+ if (ctx == oldCtx)
+ return NULL;
+
+ if (oldCtx)
+ oldCtx->Binding = NULL;
+ if (ctx)
+ ctx->Binding = t;
+
+ t->CurrentContexts[apiIndex] = ctx;
+
+ return oldCtx;
+}
+
+
+/**
+ * Return true if the given context and surfaces can be made current.
+ */
+static EGLBoolean
+_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
+{
+ _EGLThreadInfo *t = _eglGetCurrentThread();
+ EGLint conflict_api;
if (_eglIsCurrentThreadDummy())
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
- if (ctx) {
- /* error checking */
- if (ctx->Binding && ctx->Binding != t)
- return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
- if (draw == NULL || read == NULL)
- return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- if (draw->Config != ctx->Config || read->Config != ctx->Config)
+ /* this is easy */
+ if (!ctx) {
+ if (draw || read)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- if ((draw->Binding && draw->Binding->Binding != t) ||
- (read->Binding && read->Binding->Binding != t))
- return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
+ return EGL_TRUE;
+ }
+
+ /* ctx/draw/read must be all given */
+ if (draw == NULL || read == NULL)
+ return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
+
+ /* context stealing from another thread is not allowed */
+ if (ctx->Binding && ctx->Binding != t)
+ return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
+
+ /*
+ * The spec says
+ *
+ * "If ctx is current to some other thread, or if either draw or read are
+ * bound to contexts in another thread, an EGL_BAD_ACCESS error is
+ * generated."
+ *
+ * But it also says
+ *
+ * "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))
+ return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
+ /* simply require the configs to be equal */
+ if (draw->Config != ctx->Config || read->Config != ctx->Config)
+ return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
+
+ switch (ctx->ClientAPI) {
#ifdef EGL_VERSION_1_4
- /* OpenGL and OpenGL ES are conflicting */
- switch (ctx->ClientAPI) {
- case EGL_OPENGL_ES_API:
- if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_API)])
- return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
- break;
- case EGL_OPENGL_API:
- if (t->CurrentContexts[_eglConvertApiToIndex(EGL_OPENGL_ES_API)])
- return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
- break;
- default:
- break;
- }
+ /* OpenGL and OpenGL ES are conflicting */
+ case EGL_OPENGL_ES_API:
+ conflict_api = EGL_OPENGL_API;
+ break;
+ case EGL_OPENGL_API:
+ conflict_api = EGL_OPENGL_ES_API;
+ break;
#endif
- apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
- }
- else {
- if (draw != NULL || read != NULL)
- return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- apiIndex = t->CurrentAPIIndex;
+ default:
+ conflict_api = -1;
+ break;
}
- oldContext = t->CurrentContexts[apiIndex];
- if (oldContext) {
- oldDrawSurface = oldContext->DrawSurface;
- oldReadSurface = oldContext->ReadSurface;
- assert(oldDrawSurface);
- assert(oldReadSurface);
-
- /* break old bindings */
- t->CurrentContexts[apiIndex] = NULL;
- oldContext->Binding = NULL;
- oldContext->DrawSurface = NULL;
- oldContext->ReadSurface = NULL;
- oldDrawSurface->Binding = NULL;
- oldReadSurface->Binding = NULL;
+ if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
+ return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * 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
+_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
+{
+ _EGLThreadInfo *t = _eglGetCurrentThread();
+ _EGLContext *newCtx = *ctx, *oldCtx;
+
+ if (!_eglCheckMakeCurrent(newCtx, *draw, *read))
+ 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 */
+ if (oldCtx) {
/*
- * check if the old context or surfaces need to be deleted
+ * 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 (!_eglIsSurfaceLinked(oldDrawSurface)) {
- assert(draw != oldDrawSurface && read != oldDrawSurface);
- drv->API.DestroySurface(drv, dpy, oldDrawSurface);
- }
- if (oldReadSurface != oldDrawSurface &&
- !_eglIsSurfaceLinked(oldReadSurface)) {
- assert(draw != oldReadSurface && read != oldReadSurface);
- drv->API.DestroySurface(drv, dpy, oldReadSurface);
- }
- if (!_eglIsContextLinked(oldContext)) {
- assert(ctx != oldContext);
- drv->API.DestroyContext(drv, dpy, oldContext);
- }
- }
+ if (newCtx)
+ assert(!*draw && !*read);
- /* build new bindings */
- if (ctx) {
- t->CurrentContexts[apiIndex] = ctx;
- ctx->Binding = t;
- ctx->DrawSurface = draw;
- ctx->ReadSurface = read;
- draw->Binding = ctx;
- read->Binding = ctx;
+ *draw = oldCtx->DrawSurface;
+ *read = oldCtx->ReadSurface;
+ assert(*draw && *read);
+
+ _eglBindContextToSurfaces(NULL, draw, read);
}
return EGL_TRUE;
@@ -240,6 +296,17 @@ _eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
/**
+ * 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.
*/
EGLBoolean