/** * Return true if the given context and surfaces can be made current. */ static EGLBoolean _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) { _EGLThreadInfo *t = _eglGetCurrentThread(); _EGLDisplay *dpy; 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; } dpy = ctx->Resource.Display; if (!dpy->Extensions.KHR_surfaceless_context && (draw == NULL || read == NULL)) return _eglError(EGL_BAD_MATCH, "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." * * and * * "at most one context may be bound to a particular surface at a given * time" */ if (ctx->Binding && ctx->Binding != t) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); if (draw && draw->CurrentContext && draw->CurrentContext != ctx) { if (draw->CurrentContext->Binding != t || draw->CurrentContext->ClientAPI != ctx->ClientAPI) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); } if (read && read->CurrentContext && read->CurrentContext != ctx) { if (read->CurrentContext->Binding != t || read->CurrentContext->ClientAPI != ctx->ClientAPI) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); } /* If the context has a config then it must match that of the two * surfaces */ if (ctx->Config) { if ((draw && draw->Config != ctx->Config) || (read && read->Config != ctx->Config)) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); } else { /* Otherwise we must be using the EGL_MESA_configless_context * extension */ assert(dpy->Extensions.MESA_configless_context); /* The extension doesn't permit binding draw and read buffers with * differing contexts */ if (draw && read && draw->Config != read->Config) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); } switch (ctx->ClientAPI) { /* 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; default: conflict_api = -1; break; } if (conflict_api >= 0 && _eglGetAPIContext(conflict_api)) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); return EGL_TRUE; }
/** * Return true if the given context and surfaces can be made current. */ static EGLBoolean _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) { _EGLThreadInfo *t = _eglGetCurrentThread(); _EGLDisplay *dpy; 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; } dpy = ctx->Resource.Display; if (!dpy->Extensions.KHR_surfaceless_context && (draw == NULL || read == NULL)) return _eglError(EGL_BAD_MATCH, "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." * * and * * "at most one context may be bound to a particular surface at a given * time" */ if (ctx->Binding && ctx->Binding != t) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); if (draw && draw->CurrentContext && draw->CurrentContext != ctx) { if (draw->CurrentContext->Binding != t || draw->CurrentContext->ClientAPI != ctx->ClientAPI) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); } if (read && read->CurrentContext && read->CurrentContext != ctx) { if (read->CurrentContext->Binding != t || read->CurrentContext->ClientAPI != ctx->ClientAPI) return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); } /* simply require the configs to be equal */ if ((draw && draw->Config != ctx->Config) || (read && read->Config != ctx->Config)) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); switch (ctx->ClientAPI) { /* 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; 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 IsBound and DeletePending flags. * Then, the driver will do its device-dependent Make-Current stuff. */ EGLBoolean _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, EGLSurface r, EGLContext context) { _EGLThreadInfo *t = _eglGetCurrentThread(); _EGLContext *ctx = _eglLookupContext(context); _EGLSurface *draw = _eglLookupSurface(d); _EGLSurface *read = _eglLookupSurface(r); _EGLContext *oldContext = _eglGetCurrentContext(); _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW); _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ); /* error checking */ if (ctx) { 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; } } /* * check if the old context or surfaces need to be deleted */ if (oldDrawSurface != NULL) { oldDrawSurface->IsBound = EGL_FALSE; if (oldDrawSurface->DeletePending) { /* 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); } } if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) { oldReadSurface->IsBound = EGL_FALSE; if (oldReadSurface->DeletePending) { /* 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 (oldContext != NULL) { oldContext->IsBound = EGL_FALSE; if (oldContext->DeletePending) { /* 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, oldContext->Handle); } } 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; } ctx->DrawSurface = draw; ctx->ReadSurface = read; ctx->IsBound = EGL_TRUE; draw->IsBound = EGL_TRUE; read->IsBound = EGL_TRUE; } t->CurrentContext = ctx; return EGL_TRUE; }
/** * Return the currently bound _EGLContext object, or NULL. */ _EGLContext * _eglGetCurrentContext(void) { _EGLThreadInfo *t = _eglGetCurrentThread(); return t->CurrentContext; }
/** * Returns the label set for the current thread. */ EGLLabelKHR _eglGetThreadLabel(void) { _EGLThreadInfo *t = _eglGetCurrentThread(); return t->Label; }
/** * 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. */ EGLBoolean _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; 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) 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); } else { if (draw != NULL || read != NULL) return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); apiIndex = t->CurrentAPIIndex; } 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; /* * 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; } return EGL_TRUE; }
/** * Record EGL error code and return EGL_FALSE. */ static EGLBoolean _eglInternalError(EGLint errCode, const char *msg) { _EGLThreadInfo *t = _eglGetCurrentThread(); if (t == &dummy_thread) return EGL_FALSE; t->LastError = errCode; if (errCode != EGL_SUCCESS) { const char *s; switch (errCode) { case EGL_BAD_ACCESS: s = "EGL_BAD_ACCESS"; break; case EGL_BAD_ALLOC: s = "EGL_BAD_ALLOC"; break; case EGL_BAD_ATTRIBUTE: s = "EGL_BAD_ATTRIBUTE"; break; case EGL_BAD_CONFIG: s = "EGL_BAD_CONFIG"; break; case EGL_BAD_CONTEXT: s = "EGL_BAD_CONTEXT"; break; case EGL_BAD_CURRENT_SURFACE: s = "EGL_BAD_CURRENT_SURFACE"; break; case EGL_BAD_DISPLAY: s = "EGL_BAD_DISPLAY"; break; case EGL_BAD_MATCH: s = "EGL_BAD_MATCH"; break; case EGL_BAD_NATIVE_PIXMAP: s = "EGL_BAD_NATIVE_PIXMAP"; break; case EGL_BAD_NATIVE_WINDOW: s = "EGL_BAD_NATIVE_WINDOW"; break; case EGL_BAD_PARAMETER: s = "EGL_BAD_PARAMETER"; break; case EGL_BAD_SURFACE: s = "EGL_BAD_SURFACE"; break; case EGL_NOT_INITIALIZED: s = "EGL_NOT_INITIALIZED"; break; default: s = "other EGL error"; } _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); } return EGL_FALSE; }
/** * Record EGL error code and return EGL_FALSE. */ EGLBoolean _eglError(EGLint errCode, const char *msg) { _EGLThreadInfo *t = _eglGetCurrentThread(); if (t == &dummy_thread) return EGL_FALSE; t->LastError = errCode; if (errCode != EGL_SUCCESS) { const char *s; switch (errCode) { case EGL_BAD_ACCESS: s = "EGL_BAD_ACCESS"; break; case EGL_BAD_ALLOC: s = "EGL_BAD_ALLOC"; break; case EGL_BAD_ATTRIBUTE: s = "EGL_BAD_ATTRIBUTE"; break; case EGL_BAD_CONFIG: s = "EGL_BAD_CONFIG"; break; case EGL_BAD_CONTEXT: s = "EGL_BAD_CONTEXT"; break; case EGL_BAD_CURRENT_SURFACE: s = "EGL_BAD_CURRENT_SURFACE"; break; case EGL_BAD_DISPLAY: s = "EGL_BAD_DISPLAY"; break; case EGL_BAD_MATCH: s = "EGL_BAD_MATCH"; break; case EGL_BAD_NATIVE_PIXMAP: s = "EGL_BAD_NATIVE_PIXMAP"; break; case EGL_BAD_NATIVE_WINDOW: s = "EGL_BAD_NATIVE_WINDOW"; break; case EGL_BAD_PARAMETER: s = "EGL_BAD_PARAMETER"; break; case EGL_BAD_SURFACE: s = "EGL_BAD_SURFACE"; break; #ifdef EGL_MESA_screen_surface case EGL_BAD_SCREEN_MESA: s = "EGL_BAD_SCREEN_MESA"; break; case EGL_BAD_MODE_MESA: s = "EGL_BAD_MODE_MESA"; break; #endif default: s = "other"; } _eglLog(_EGL_DEBUG, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); } return EGL_FALSE; }
/** * Return the currently bound context of the current API, or NULL. */ _EGLContext * _eglGetCurrentContext(void) { _EGLThreadInfo *t = _eglGetCurrentThread(); return t->CurrentContexts[t->CurrentAPIIndex]; }
/** * Return the currently bound context of the given API, or NULL. */ PUBLIC _EGLContext * _eglGetAPIContext(EGLenum api) { _EGLThreadInfo *t = _eglGetCurrentThread(); return t->CurrentContexts[_eglConvertApiToIndex(api)]; }
/** * 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->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 */ 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; }