egl: Refactor _eglMakeCurrent.
Refactor _eglMakeCurrent into _eglCheckMakeCurrent, _eglBindContextToSurface, and _eglBindContextToThread.
This commit is contained in:
parent
6f6f3e4227
commit
7c09296d4c
|
@ -139,6 +139,138 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static _EGLSurface *
|
||||
_eglBindContextToSurface(_EGLContext *ctx, _EGLSurface *surf, EGLint readdraw)
|
||||
{
|
||||
_EGLSurface **attachment, *oldSurf;
|
||||
|
||||
if (!ctx) {
|
||||
surf->Binding = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attachment = (readdraw == EGL_DRAW) ?
|
||||
&ctx->DrawSurface : &ctx->ReadSurface;
|
||||
oldSurf = *attachment;
|
||||
|
||||
if (oldSurf == surf)
|
||||
return NULL;
|
||||
|
||||
if (oldSurf)
|
||||
oldSurf->Binding = NULL;
|
||||
surf->Binding = ctx;
|
||||
*attachment = surf;
|
||||
|
||||
return oldSurf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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");
|
||||
|
||||
/* this is easy */
|
||||
if (!ctx) {
|
||||
if (draw || read)
|
||||
return _eglError(EGL_BAD_MATCH, "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->Binding && draw->Binding != ctx) ||
|
||||
(read->Binding && read->Binding != 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 */
|
||||
case EGL_OPENGL_ES_API:
|
||||
conflict_api = EGL_OPENGL_API;
|
||||
break;
|
||||
case EGL_OPENGL_API:
|
||||
conflict_api = EGL_OPENGL_ES_API;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
conflict_api = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
|
||||
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drivers will typically call this to do the error checking and
|
||||
* update the various flags.
|
||||
|
@ -149,91 +281,39 @@ _eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
|
|||
_EGLSurface *read, _EGLContext *ctx)
|
||||
{
|
||||
_EGLThreadInfo *t = _eglGetCurrentThread();
|
||||
_EGLContext *oldContext = NULL;
|
||||
_EGLSurface *oldDrawSurface = NULL;
|
||||
_EGLSurface *oldReadSurface = NULL;
|
||||
EGLint apiIndex;
|
||||
_EGLSurface *oldDraw = NULL, *oldRead = NULL;
|
||||
_EGLContext *oldCtx;
|
||||
|
||||
if (_eglIsCurrentThreadDummy())
|
||||
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
|
||||
if (!_eglCheckMakeCurrent(ctx, draw, read))
|
||||
return EGL_FALSE;
|
||||
|
||||
oldCtx = _eglBindContextToThread(ctx, t);
|
||||
|
||||
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)
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
apiIndex = _eglConvertApiToIndex(ctx->ClientAPI);
|
||||
oldDraw = _eglBindContextToSurface(ctx, draw, EGL_DRAW);
|
||||
oldRead = _eglBindContextToSurface(ctx, read, EGL_READ);
|
||||
}
|
||||
else {
|
||||
if (draw != NULL || read != NULL)
|
||||
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
||||
apiIndex = t->CurrentAPIIndex;
|
||||
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);
|
||||
}
|
||||
|
||||
oldContext = t->CurrentContexts[apiIndex];
|
||||
if (oldContext) {
|
||||
oldDrawSurface = oldContext->DrawSurface;
|
||||
oldReadSurface = oldContext->ReadSurface;
|
||||
assert(oldDrawSurface);
|
||||
assert(oldReadSurface);
|
||||
/* avoid double destroy */
|
||||
if (oldRead && oldRead == oldDraw)
|
||||
oldRead = 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
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* build new bindings */
|
||||
if (ctx) {
|
||||
t->CurrentContexts[apiIndex] = ctx;
|
||||
ctx->Binding = t;
|
||||
ctx->DrawSurface = draw;
|
||||
ctx->ReadSurface = read;
|
||||
draw->Binding = ctx;
|
||||
read->Binding = ctx;
|
||||
}
|
||||
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);
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue