5 #include "eglcontext.h"
6 #include "egldisplay.h"
7 #include "eglcurrent.h"
8 #include "eglsurface.h"
13 * Return the API bit (one of EGL_xxx_BIT) of the context.
16 _eglGetContextAPIBit(_EGLContext *ctx)
20 switch (ctx->ClientAPI) {
21 case EGL_OPENGL_ES_API:
22 switch (ctx->ClientVersion) {
24 bit = EGL_OPENGL_ES_BIT;
27 bit = EGL_OPENGL_ES2_BIT;
48 * Parse the list of context attributes and return the proper error code.
51 _eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list)
53 EGLenum api = ctx->ClientAPI;
54 EGLint i, err = EGL_SUCCESS;
59 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
60 EGLint attr = attrib_list[i++];
61 EGLint val = attrib_list[i];
64 case EGL_CONTEXT_CLIENT_VERSION:
65 if (api != EGL_OPENGL_ES_API) {
66 err = EGL_BAD_ATTRIBUTE;
69 if (val != 1 && val != 2) {
70 err = EGL_BAD_ATTRIBUTE;
73 ctx->ClientVersion = val;
76 err = EGL_BAD_ATTRIBUTE;
80 if (err != EGL_SUCCESS) {
81 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
86 if (err == EGL_SUCCESS) {
87 EGLint renderable_type, api_bit;
89 renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE);
90 api_bit = _eglGetContextAPIBit(ctx);
91 if (!(renderable_type & api_bit))
100 * Initialize the given _EGLContext object to defaults and/or the values
101 * in the attrib_list.
104 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
105 const EGLint *attrib_list)
107 const EGLenum api = eglQueryAPI();
110 if (api == EGL_NONE) {
111 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
115 memset(ctx, 0, sizeof(_EGLContext));
116 ctx->Resource.Display = dpy;
117 ctx->ClientAPI = api;
119 ctx->WindowRenderBuffer = EGL_NONE;
121 ctx->ClientVersion = 1; /* the default, per EGL spec */
123 err = _eglParseContextAttribList(ctx, attrib_list);
124 if (err != EGL_SUCCESS)
125 return _eglError(err, "eglCreateContext");
132 * Just a placeholder/demo function. Real driver will never use this!
135 _eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
136 _EGLContext *share_list, const EGLint *attrib_list)
143 * Default fallback routine - drivers should usually override this.
146 _eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
148 if (!_eglIsContextBound(ctx))
154 #ifdef EGL_VERSION_1_2
156 _eglQueryContextRenderBuffer(_EGLContext *ctx)
158 _EGLSurface *surf = ctx->DrawSurface;
163 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
164 rb = ctx->WindowRenderBuffer;
166 rb = surf->RenderBuffer;
169 #endif /* EGL_VERSION_1_2 */
173 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
174 EGLint attribute, EGLint *value)
180 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
184 *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
186 case EGL_CONTEXT_CLIENT_VERSION:
187 *value = c->ClientVersion;
189 #ifdef EGL_VERSION_1_2
190 case EGL_CONTEXT_CLIENT_TYPE:
191 *value = c->ClientAPI;
193 case EGL_RENDER_BUFFER:
194 *value = _eglQueryContextRenderBuffer(c);
196 #endif /* EGL_VERSION_1_2 */
198 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
206 * Bind the context to the surfaces. Return the surfaces that are "orphaned".
207 * That is, when the context is not NULL, return the surfaces it previously
208 * bound to; when the context is NULL, the same surfaces are returned.
211 _eglBindContextToSurfaces(_EGLContext *newCtx,
212 _EGLSurface **draw, _EGLSurface **read)
214 _EGLSurface *newDraw = *draw, *newRead = *read;
218 * The goal is to bind a newCtx to newDraw. Since newDraw may already have
219 * a binding context (oldCtx), and newCtx may already be bound to another
220 * surface (oldDraw), the old bindings are broken first and the new one is
223 oldCtx = newDraw->CurrentContext;
224 if (newCtx != oldCtx) {
226 assert(oldCtx->DrawSurface == newDraw);
227 oldCtx->DrawSurface = NULL;
231 _EGLSurface *oldDraw = newCtx->DrawSurface;
233 oldDraw->CurrentContext = NULL;
235 newCtx->DrawSurface = newDraw;
239 newDraw->CurrentContext = newCtx;
243 if (newRead != newDraw)
244 oldCtx = newRead->CurrentContext;
245 if (newCtx != oldCtx) {
247 assert(oldCtx->ReadSurface == newRead);
248 oldCtx->ReadSurface = NULL;
252 _EGLSurface *oldRead = newCtx->ReadSurface;
254 oldRead->CurrentContext = NULL;
256 newCtx->ReadSurface = newRead;
260 newRead->CurrentContext = newCtx;
266 * Bind the context to the thread and return the previous context.
268 * Note that the context may be NULL.
271 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
277 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
279 oldCtx = t->CurrentContexts[apiIndex];
282 oldCtx->Binding = NULL;
286 t->CurrentContexts[apiIndex] = ctx;
294 * Return true if the given context and surfaces can be made current.
297 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
299 _EGLThreadInfo *t = _eglGetCurrentThread();
302 if (_eglIsCurrentThreadDummy())
303 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
308 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
312 /* ctx/draw/read must be all given */
313 if (draw == NULL || read == NULL)
314 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
316 /* context stealing from another thread is not allowed */
317 if (ctx->Binding && ctx->Binding != t)
318 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
323 * "If ctx is current to some other thread, or if either draw or read are
324 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
329 * "at most one context may be bound to a particular surface at a given
332 * The latter is more restrictive so we can check only the latter case.
334 if ((draw->CurrentContext && draw->CurrentContext != ctx) ||
335 (read->CurrentContext && read->CurrentContext != ctx))
336 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
338 /* simply require the configs to be equal */
339 if (draw->Config != ctx->Config || read->Config != ctx->Config)
340 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
342 switch (ctx->ClientAPI) {
343 #ifdef EGL_VERSION_1_4
344 /* OpenGL and OpenGL ES are conflicting */
345 case EGL_OPENGL_ES_API:
346 conflict_api = EGL_OPENGL_API;
349 conflict_api = EGL_OPENGL_ES_API;
357 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
358 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
365 * Bind the context to the current thread and given surfaces. Return the
366 * previously bound context and the surfaces it bound to. Each argument is
367 * both input and output.
370 _eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
372 _EGLThreadInfo *t = _eglGetCurrentThread();
373 _EGLContext *newCtx = *ctx, *oldCtx;
375 if (!_eglCheckMakeCurrent(newCtx, *draw, *read))
378 /* bind the new context */
379 oldCtx = _eglBindContextToThread(newCtx, t);
382 _eglBindContextToSurfaces(newCtx, draw, read);
384 /* unbind the old context from its binding surfaces */
385 if (oldCtx && oldCtx != newCtx) {
386 assert(!*draw && !*read);
388 *draw = oldCtx->DrawSurface;
389 *read = oldCtx->ReadSurface;
390 assert(*draw && *read);
392 _eglBindContextToSurfaces(NULL, draw, read);
396 /* draw and read have been updated in _eglBindContextToSurfaces */
403 * Just a placeholder/demo function. Drivers should override this.
406 _eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
407 _EGLSurface *read, _EGLContext *ctx)
414 * This is defined by the EGL_MESA_copy_context extension.
417 _eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
418 EGLContext dest, EGLint mask)
420 /* This function will always have to be overridden/implemented in the
421 * device driver. If the driver is based on Mesa, use _mesa_copy_context().