summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChia-I Wu <[email protected]>2009-08-03 11:35:14 -0600
committerBrian Paul <[email protected]>2009-08-03 11:35:14 -0600
commit8cdc6c66f9d8ede00d02108070d269d3aca8b130 (patch)
treeae673cec2416ff8e8d12e98c56d55b136536b0f9
parent07ee01365a8bddf6f50821ecd585784498a25ff0 (diff)
egl: Make eglMakeCurrent more robust.
Now that a current surface points back to its binding context, and a current context points back to its binding thread, make sure there is no dangling pointers. This commit reworks eglMakeCurrent, adds more checks to avoid stealing context or surfaces from another thread, and correctly destroys unlinked context and surfaces. Signed-off-by: Chia-I Wu <[email protected]>
-rw-r--r--src/egl/main/eglcontext.c98
1 files changed, 46 insertions, 52 deletions
diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c
index f8d5687f87c..88de60d69bb 100644
--- a/src/egl/main/eglcontext.c
+++ b/src/egl/main/eglcontext.c
@@ -146,10 +146,11 @@ _eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx,
* Then, the driver will do its device-dependent Make-Current stuff.
*/
EGLBoolean
-_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
+_eglMakeCurrent(_EGLDriver *drv, EGLDisplay display, EGLSurface d,
EGLSurface r, EGLContext context)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
+ _EGLDisplay *dpy = _eglLookupDisplay(display);
_EGLContext *ctx = _eglLookupContext(context);
_EGLSurface *draw = _eglLookupSurface(d);
_EGLSurface *read = _eglLookupSurface(r);
@@ -160,21 +161,23 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
if (_eglIsCurrentThreadDummy())
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
+ if (dpy == NULL)
+ return _eglError(EGL_BAD_DISPLAY, "eglMakeCurrent");
- /* error checking */
if (ctx) {
+ /* error checking */
+ if (ctx->Binding && ctx->Binding != t)
+ return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw == NULL || read == NULL) {
- _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- return EGL_FALSE;
- }
- if (draw->Config != ctx->Config) {
- _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- return EGL_FALSE;
- }
- if (read->Config != ctx->Config) {
- _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- return EGL_FALSE;
+ EGLint err = (d == EGL_NO_SURFACE || r == EGL_NO_SURFACE)
+ ? EGL_BAD_MATCH : EGL_BAD_SURFACE;
+ return _eglError(err, "eglMakeCurrent");
}
+ if (draw->Config != ctx->Config || read->Config != ctx->Config)
+ 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");
#ifdef EGL_VERSION_1_4
/* OpenGL and OpenGL ES are conflicting */
@@ -194,6 +197,10 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
}
else {
+ if (context != EGL_NO_CONTEXT)
+ return _eglError(EGL_BAD_CONTEXT, "eglMakeCurrent");
+ if (draw != NULL || read != NULL)
+ return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
apiIndex = t->CurrentAPIIndex;
}
@@ -201,60 +208,47 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
if (oldContext) {
oldDrawSurface = oldContext->DrawSurface;
oldReadSurface = oldContext->ReadSurface;
- }
+ assert(oldDrawSurface);
+ assert(oldReadSurface);
- /*
- * check if the old context or surfaces need to be deleted
- */
- if (oldDrawSurface != NULL) {
+ /* break old bindings */
+ t->CurrentContexts[apiIndex] = NULL;
+ oldContext->Binding = NULL;
+ oldContext->DrawSurface = NULL;
+ oldContext->ReadSurface = NULL;
oldDrawSurface->Binding = NULL;
+ oldReadSurface->Binding = NULL;
+
+ /*
+ * check if the old context or surfaces need to be deleted
+ * FIXME They are linked so that they can be unlinked. This is ugly.
+ */
if (!_eglIsSurfaceLinked(oldDrawSurface)) {
- /* make sure we don't try to rebind a deleted surface */
- if (draw == oldDrawSurface || draw == oldReadSurface) {
- draw = NULL;
- }
- /* really delete surface now */
- drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle);
+ assert(draw != oldDrawSurface && read != oldDrawSurface);
+ drv->API.DestroySurface(drv, display,
+ _eglLinkSurface(oldDrawSurface, dpy));
}
- }
- if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) {
- oldReadSurface->Binding = NULL;
- if (!_eglIsSurfaceLinked(oldReadSurface)) {
- /* make sure we don't try to rebind a deleted surface */
- if (read == oldDrawSurface || read == oldReadSurface) {
- read = NULL;
- }
- /* really delete surface now */
- drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle);
+ if (oldReadSurface != oldDrawSurface &&
+ !_eglIsSurfaceLinked(oldReadSurface)) {
+ assert(draw != oldReadSurface && read != oldReadSurface);
+ drv->API.DestroySurface(drv, display,
+ _eglLinkSurface(oldReadSurface, dpy));
}
- }
- if (oldContext != NULL) {
- oldContext->Binding = NULL;
if (!_eglIsContextLinked(oldContext)) {
- /* make sure we don't try to rebind a deleted context */
- if (ctx == oldContext) {
- ctx = NULL;
- }
- /* really delete context now */
- drv->API.DestroyContext(drv, dpy, _eglGetContextHandle(oldContext));
+ assert(ctx != oldContext);
+ drv->API.DestroyContext(drv, display,
+ _eglLinkContext(oldContext, dpy));
}
}
+ /* build new bindings */
if (ctx) {
- /* check read/draw again, in case we deleted them above */
- if (draw == NULL || read == NULL) {
- _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
- return EGL_FALSE;
- }
+ t->CurrentContexts[apiIndex] = ctx;
+ ctx->Binding = t;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
- ctx->Binding = t;
draw->Binding = ctx;
read->Binding = ctx;
- t->CurrentContexts[apiIndex] = ctx;
- }
- else {
- t->CurrentContexts[apiIndex] = NULL;
}
return EGL_TRUE;