2005-04-22 22:09:39 +01:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "eglconfig.h"
|
|
|
|
#include "eglcontext.h"
|
2005-11-27 23:57:19 +00:00
|
|
|
#include "egldisplay.h"
|
2010-01-29 01:00:30 +00:00
|
|
|
#include "eglcurrent.h"
|
2005-04-22 22:09:39 +01:00
|
|
|
#include "eglsurface.h"
|
2010-01-31 04:57:53 +00:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
2005-04-22 22:09:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2008-05-27 21:21:25 +01:00
|
|
|
* Initialize the given _EGLContext object to defaults and/or the values
|
|
|
|
* in the attrib_list.
|
2005-04-22 22:09:39 +01:00
|
|
|
*/
|
2005-11-27 23:57:19 +00:00
|
|
|
EGLBoolean
|
2010-01-31 05:33:57 +00:00
|
|
|
_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
|
|
const EGLint *attrib_list)
|
2005-04-22 22:09:39 +01:00
|
|
|
{
|
2008-05-30 20:45:40 +01:00
|
|
|
const EGLenum api = eglQueryAPI();
|
2010-01-31 04:57:53 +00:00
|
|
|
EGLint err;
|
2008-05-30 20:45:40 +01:00
|
|
|
|
|
|
|
if (api == EGL_NONE) {
|
|
|
|
_eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
|
|
|
|
return EGL_FALSE;
|
|
|
|
}
|
2005-11-27 23:57:19 +00:00
|
|
|
|
2008-06-20 04:19:33 +01:00
|
|
|
memset(ctx, 0, sizeof(_EGLContext));
|
2010-01-31 05:33:57 +00:00
|
|
|
ctx->Resource.Display = dpy;
|
2010-01-31 04:57:53 +00:00
|
|
|
ctx->ClientAPI = api;
|
|
|
|
ctx->Config = conf;
|
|
|
|
ctx->WindowRenderBuffer = EGL_NONE;
|
2008-06-20 04:19:33 +01:00
|
|
|
|
2008-06-19 23:06:56 +01:00
|
|
|
ctx->ClientVersion = 1; /* the default, per EGL spec */
|
|
|
|
|
2010-01-31 04:57:53 +00:00
|
|
|
err = _eglParseContextAttribList(ctx, attrib_list);
|
2010-08-20 06:19:10 +01:00
|
|
|
if (err == EGL_SUCCESS && ctx->Config) {
|
|
|
|
EGLint renderable_type, api_bit;
|
|
|
|
|
|
|
|
renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE);
|
|
|
|
api_bit = _eglGetContextAPIBit(ctx);
|
|
|
|
if (!(renderable_type & api_bit)) {
|
|
|
|
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
|
|
|
|
api_bit, renderable_type);
|
|
|
|
err = EGL_BAD_CONFIG;
|
|
|
|
}
|
|
|
|
}
|
2010-01-31 04:57:53 +00:00
|
|
|
if (err != EGL_SUCCESS)
|
|
|
|
return _eglError(err, "eglCreateContext");
|
2005-11-27 23:57:19 +00:00
|
|
|
|
|
|
|
return EGL_TRUE;
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Just a placeholder/demo function. Real driver will never use this!
|
|
|
|
*/
|
2009-08-11 10:09:39 +01:00
|
|
|
_EGLContext *
|
|
|
|
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
|
|
_EGLContext *share_list, const EGLint *attrib_list)
|
2005-04-22 22:09:39 +01:00
|
|
|
{
|
2009-08-11 10:09:39 +01:00
|
|
|
return NULL;
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default fallback routine - drivers should usually override this.
|
|
|
|
*/
|
|
|
|
EGLBoolean
|
2009-08-11 10:09:39 +01:00
|
|
|
_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
|
2005-04-22 22:09:39 +01:00
|
|
|
{
|
2009-08-11 10:09:39 +01:00
|
|
|
if (!_eglIsContextBound(ctx))
|
|
|
|
free(ctx);
|
|
|
|
return EGL_TRUE;
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-27 10:00:51 +01:00
|
|
|
#ifdef EGL_VERSION_1_2
|
|
|
|
static EGLint
|
|
|
|
_eglQueryContextRenderBuffer(_EGLContext *ctx)
|
|
|
|
{
|
|
|
|
_EGLSurface *surf = ctx->DrawSurface;
|
|
|
|
EGLint rb;
|
|
|
|
|
|
|
|
if (!surf)
|
|
|
|
return EGL_NONE;
|
|
|
|
if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
|
|
|
|
rb = ctx->WindowRenderBuffer;
|
|
|
|
else
|
|
|
|
rb = surf->RenderBuffer;
|
|
|
|
return rb;
|
|
|
|
}
|
|
|
|
#endif /* EGL_VERSION_1_2 */
|
|
|
|
|
|
|
|
|
2005-04-22 22:09:39 +01:00
|
|
|
EGLBoolean
|
2009-08-11 10:09:39 +01:00
|
|
|
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
|
2005-11-27 23:57:19 +00:00
|
|
|
EGLint attribute, EGLint *value)
|
2005-04-22 22:09:39 +01:00
|
|
|
{
|
|
|
|
(void) drv;
|
|
|
|
(void) dpy;
|
|
|
|
|
2009-09-27 10:00:51 +01:00
|
|
|
if (!value)
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
|
|
|
|
|
2005-04-22 22:09:39 +01:00
|
|
|
switch (attribute) {
|
|
|
|
case EGL_CONFIG_ID:
|
|
|
|
*value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
|
2009-09-27 10:00:51 +01:00
|
|
|
break;
|
|
|
|
case EGL_CONTEXT_CLIENT_VERSION:
|
|
|
|
*value = c->ClientVersion;
|
|
|
|
break;
|
2006-01-30 00:10:55 +00:00
|
|
|
#ifdef EGL_VERSION_1_2
|
|
|
|
case EGL_CONTEXT_CLIENT_TYPE:
|
|
|
|
*value = c->ClientAPI;
|
2009-09-27 10:00:51 +01:00
|
|
|
break;
|
|
|
|
case EGL_RENDER_BUFFER:
|
|
|
|
*value = _eglQueryContextRenderBuffer(c);
|
|
|
|
break;
|
2006-01-30 00:10:55 +00:00
|
|
|
#endif /* EGL_VERSION_1_2 */
|
2005-04-22 22:09:39 +01:00
|
|
|
default:
|
2009-09-27 10:00:51 +01:00
|
|
|
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
2009-09-27 10:00:51 +01:00
|
|
|
|
|
|
|
return EGL_TRUE;
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 08:53:40 +00:00
|
|
|
/**
|
|
|
|
* 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)
|
2005-04-22 22:09:39 +01:00
|
|
|
{
|
2009-07-17 18:42:04 +01:00
|
|
|
EGLint apiIndex;
|
2010-01-26 08:53:40 +00:00
|
|
|
_EGLContext *oldCtx;
|
|
|
|
|
|
|
|
apiIndex = (ctx) ?
|
|
|
|
_eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
|
|
|
|
|
|
|
|
oldCtx = t->CurrentContexts[apiIndex];
|
2010-03-27 18:11:16 +00:00
|
|
|
if (ctx != oldCtx) {
|
|
|
|
if (oldCtx)
|
|
|
|
oldCtx->Binding = NULL;
|
|
|
|
if (ctx)
|
|
|
|
ctx->Binding = t;
|
2010-01-26 08:53:40 +00:00
|
|
|
|
2010-03-27 18:11:16 +00:00
|
|
|
t->CurrentContexts[apiIndex] = ctx;
|
|
|
|
}
|
2010-01-26 08:53:40 +00:00
|
|
|
|
|
|
|
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();
|
2010-07-29 04:54:16 +01:00
|
|
|
_EGLDisplay *dpy;
|
2010-01-26 08:53:40 +00:00
|
|
|
EGLint conflict_api;
|
2010-06-03 03:48:06 +01:00
|
|
|
EGLBoolean surfaceless;
|
2005-04-22 22:09:39 +01:00
|
|
|
|
2009-07-17 18:41:02 +01:00
|
|
|
if (_eglIsCurrentThreadDummy())
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
|
|
|
|
|
2010-01-26 08:53:40 +00:00
|
|
|
/* this is easy */
|
|
|
|
if (!ctx) {
|
|
|
|
if (draw || read)
|
2009-08-03 18:35:14 +01:00
|
|
|
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
2010-01-26 08:53:40 +00:00
|
|
|
return EGL_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-07-29 04:54:16 +01:00
|
|
|
dpy = ctx->Resource.Display;
|
2010-06-03 03:48:06 +01:00
|
|
|
switch (_eglGetContextAPIBit(ctx)) {
|
|
|
|
case EGL_OPENGL_ES_BIT:
|
|
|
|
surfaceless = dpy->Extensions.KHR_surfaceless_gles1;
|
|
|
|
break;
|
|
|
|
case EGL_OPENGL_ES2_BIT:
|
|
|
|
surfaceless = dpy->Extensions.KHR_surfaceless_gles2;
|
|
|
|
break;
|
|
|
|
case EGL_OPENGL_BIT:
|
|
|
|
surfaceless = dpy->Extensions.KHR_surfaceless_opengl;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
surfaceless = EGL_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!surfaceless && (draw == NULL || read == NULL))
|
2010-01-26 08:53:40 +00:00
|
|
|
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.
|
|
|
|
*/
|
2010-06-03 03:48:06 +01:00
|
|
|
if ((draw && draw->CurrentContext && draw->CurrentContext != ctx) ||
|
|
|
|
(read && read->CurrentContext && read->CurrentContext != ctx))
|
2010-01-26 08:53:40 +00:00
|
|
|
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
|
|
|
|
|
|
|
/* simply require the configs to be equal */
|
2010-06-03 03:48:06 +01:00
|
|
|
if ((draw && draw->Config != ctx->Config) ||
|
|
|
|
(read && read->Config != ctx->Config))
|
2010-01-26 08:53:40 +00:00
|
|
|
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
2009-07-17 18:42:04 +01:00
|
|
|
|
2010-01-26 08:53:40 +00:00
|
|
|
switch (ctx->ClientAPI) {
|
2009-07-17 18:42:04 +01:00
|
|
|
#ifdef EGL_VERSION_1_4
|
2010-01-26 08:53:40 +00:00
|
|
|
/* 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;
|
2009-07-17 18:42:04 +01:00
|
|
|
#endif
|
2010-01-26 08:53:40 +00:00
|
|
|
default:
|
|
|
|
conflict_api = -1;
|
|
|
|
break;
|
2009-07-17 18:42:04 +01:00
|
|
|
}
|
|
|
|
|
2010-01-26 08:53:40 +00:00
|
|
|
if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
|
|
|
|
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 15:31:20 +00:00
|
|
|
/**
|
|
|
|
* Bind the context to the current thread and given surfaces. Return the
|
2010-09-10 11:26:03 +01:00
|
|
|
* "orphaned" context and surfaces. Each argument is both input and output.
|
2010-01-27 15:31:20 +00:00
|
|
|
*/
|
|
|
|
EGLBoolean
|
|
|
|
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
|
|
|
|
{
|
|
|
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
|
|
|
_EGLContext *newCtx = *ctx, *oldCtx;
|
2010-09-10 11:26:03 +01:00
|
|
|
_EGLSurface *newDraw = *draw, *newRead = *read;
|
2010-01-27 15:31:20 +00:00
|
|
|
|
2010-09-10 11:26:03 +01:00
|
|
|
if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead))
|
2010-01-27 15:31:20 +00:00
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
/* bind the new context */
|
|
|
|
oldCtx = _eglBindContextToThread(newCtx, t);
|
2010-04-05 14:26:34 +01:00
|
|
|
|
2010-09-10 11:26:03 +01:00
|
|
|
/* break old bindings */
|
|
|
|
if (oldCtx) {
|
|
|
|
*ctx = oldCtx;
|
2010-04-06 04:51:25 +01:00
|
|
|
*draw = oldCtx->DrawSurface;
|
|
|
|
*read = oldCtx->ReadSurface;
|
|
|
|
|
2010-09-10 11:26:03 +01:00
|
|
|
if (*draw)
|
|
|
|
(*draw)->CurrentContext = NULL;
|
|
|
|
if (*read)
|
|
|
|
(*read)->CurrentContext = NULL;
|
|
|
|
|
|
|
|
oldCtx->DrawSurface = NULL;
|
|
|
|
oldCtx->ReadSurface = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* establish new bindings */
|
|
|
|
if (newCtx) {
|
|
|
|
if (newDraw)
|
|
|
|
newDraw->CurrentContext = newCtx;
|
|
|
|
if (newRead)
|
|
|
|
newRead->CurrentContext = newCtx;
|
|
|
|
|
|
|
|
newCtx->DrawSurface = newDraw;
|
|
|
|
newCtx->ReadSurface = newRead;
|
2010-01-27 15:31:20 +00:00
|
|
|
}
|
|
|
|
|
2010-09-10 11:26:03 +01:00
|
|
|
/* an old context or surface is not orphaned if it is still bound */
|
|
|
|
if (*ctx == newCtx)
|
|
|
|
*ctx = NULL;
|
|
|
|
if (*draw == newDraw || *draw == newRead)
|
|
|
|
*draw = NULL;
|
|
|
|
if (*read == newDraw || *read == newRead)
|
|
|
|
*read = NULL;
|
2010-04-05 14:26:34 +01:00
|
|
|
|
2010-01-27 15:31:20 +00:00
|
|
|
return EGL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-26 08:53:40 +00:00
|
|
|
/**
|
2010-01-28 08:57:49 +00:00
|
|
|
* Just a placeholder/demo function. Drivers should override this.
|
2010-01-26 08:53:40 +00:00
|
|
|
*/
|
|
|
|
EGLBoolean
|
|
|
|
_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
|
|
|
|
_EGLSurface *read, _EGLContext *ctx)
|
|
|
|
{
|
2010-01-28 08:57:49 +00:00
|
|
|
return EGL_FALSE;
|
2005-04-22 22:09:39 +01:00
|
|
|
}
|
2005-05-14 15:54:38 +01:00
|
|
|
|
|
|
|
|
2005-05-16 03:21:08 +01:00
|
|
|
/**
|
|
|
|
* This is defined by the EGL_MESA_copy_context extension.
|
|
|
|
*/
|
2005-05-14 15:54:38 +01:00
|
|
|
EGLBoolean
|
2005-05-16 03:21:08 +01:00
|
|
|
_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
|
|
|
|
EGLContext dest, EGLint mask)
|
2005-05-14 15:54:38 +01:00
|
|
|
{
|
2005-05-16 03:21:08 +01:00
|
|
|
/* This function will always have to be overridden/implemented in the
|
|
|
|
* device driver. If the driver is based on Mesa, use _mesa_copy_context().
|
|
|
|
*/
|
2005-05-14 15:54:38 +01:00
|
|
|
return EGL_FALSE;
|
|
|
|
}
|