1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
34 #include "eglconfig.h"
35 #include "eglcontext.h"
36 #include "egldisplay.h"
37 #include "eglcurrent.h"
38 #include "eglsurface.h"
43 * Return the API bit (one of EGL_xxx_BIT) of the context.
46 _eglGetContextAPIBit(_EGLContext
*ctx
)
50 switch (ctx
->ClientAPI
) {
51 case EGL_OPENGL_ES_API
:
52 switch (ctx
->ClientMajorVersion
) {
54 bit
= EGL_OPENGL_ES_BIT
;
58 bit
= EGL_OPENGL_ES2_BIT
;
79 * Parse the list of context attributes and return the proper error code.
82 _eglParseContextAttribList(_EGLContext
*ctx
, _EGLDisplay
*dpy
,
83 const EGLint
*attrib_list
)
85 EGLenum api
= ctx
->ClientAPI
;
86 EGLint i
, err
= EGL_SUCCESS
;
91 if (api
== EGL_OPENVG_API
&& attrib_list
[0] != EGL_NONE
) {
92 _eglLog(_EGL_DEBUG
, "bad context attribute 0x%04x", attrib_list
[0]);
93 return EGL_BAD_ATTRIBUTE
;
96 for (i
= 0; attrib_list
[i
] != EGL_NONE
; i
++) {
97 EGLint attr
= attrib_list
[i
++];
98 EGLint val
= attrib_list
[i
];
101 case EGL_CONTEXT_CLIENT_VERSION
:
102 ctx
->ClientMajorVersion
= val
;
105 case EGL_CONTEXT_MINOR_VERSION_KHR
:
106 if (!dpy
->Extensions
.KHR_create_context
) {
107 err
= EGL_BAD_ATTRIBUTE
;
111 ctx
->ClientMinorVersion
= val
;
114 case EGL_CONTEXT_FLAGS_KHR
:
115 if (!dpy
->Extensions
.KHR_create_context
) {
116 err
= EGL_BAD_ATTRIBUTE
;
120 /* The EGL_KHR_create_context spec says:
122 * "Flags are only defined for OpenGL context creation, and
123 * specifying a flags value other than zero for other types of
124 * contexts, including OpenGL ES contexts, will generate an
127 if (api
!= EGL_OPENGL_API
&& val
!= 0) {
128 err
= EGL_BAD_ATTRIBUTE
;
135 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR
:
136 if (!dpy
->Extensions
.KHR_create_context
) {
137 err
= EGL_BAD_ATTRIBUTE
;
141 /* The EGL_KHR_create_context spec says:
143 * "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
144 * OpenGL contexts, and specifying it for other types of
145 * contexts, including OpenGL ES contexts, will generate an
148 if (api
!= EGL_OPENGL_API
) {
149 err
= EGL_BAD_ATTRIBUTE
;
156 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
:
157 /* The EGL_KHR_create_context spec says:
159 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
160 * meaningful for OpenGL contexts, and specifying it for other
161 * types of contexts, including OpenGL ES contexts, will generate
164 if (!dpy
->Extensions
.KHR_create_context
165 || api
!= EGL_OPENGL_API
) {
166 err
= EGL_BAD_ATTRIBUTE
;
170 ctx
->ResetNotificationStrategy
= val
;
173 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT
:
174 /* The EGL_EXT_create_context_robustness spec says:
176 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
177 * meaningful for OpenGL ES contexts, and specifying it for other
178 * types of contexts will generate an EGL_BAD_ATTRIBUTE error."
180 if (!dpy
->Extensions
.EXT_create_context_robustness
181 || api
!= EGL_OPENGL_ES_API
) {
182 err
= EGL_BAD_ATTRIBUTE
;
186 ctx
->ResetNotificationStrategy
= val
;
189 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT
:
190 if (!dpy
->Extensions
.EXT_create_context_robustness
) {
191 err
= EGL_BAD_ATTRIBUTE
;
195 ctx
->Flags
= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
;
199 err
= EGL_BAD_ATTRIBUTE
;
203 if (err
!= EGL_SUCCESS
) {
204 _eglLog(_EGL_DEBUG
, "bad context attribute 0x%04x", attr
);
209 if (api
== EGL_OPENGL_API
) {
210 /* The EGL_KHR_create_context spec says:
212 * "If the requested OpenGL version is less than 3.2,
213 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
214 * functionality of the context is determined solely by the
215 * requested version."
217 * Since the value is ignored, only validate the setting if the version
220 if (ctx
->ClientMajorVersion
>= 4
221 || (ctx
->ClientMajorVersion
== 3 && ctx
->ClientMinorVersion
>= 2)) {
222 switch (ctx
->Profile
) {
223 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
:
224 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
:
228 /* The EGL_KHR_create_context spec says:
230 * "* If an OpenGL context is requested, the requested version
231 * is greater than 3.2, and the value for attribute
232 * EGL_CONTEXT_PROFILE_MASK_KHR has no bits set; has any
233 * bits set other than EGL_CONTEXT_CORE_PROFILE_BIT_KHR and
234 * EGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_KHR; has more than
235 * one of these bits set; or if the implementation does not
236 * support the requested profile, then an
237 * EGL_BAD_PROFILE_KHR error is generated."
239 * However, it does not define EGL_BAD_PROFILE_KHR. For now use
242 err
= EGL_BAD_ATTRIBUTE
;
247 /* The EGL_KHR_create_context spec says:
249 * "* If an OpenGL context is requested and the values for
250 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
251 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
252 * the value for attribute
253 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
254 * version and feature set that are not defined, than an
255 * EGL_BAD_MATCH error is generated.
257 * ... Thus, examples of invalid combinations of attributes
260 * - Major version < 1 or > 4
261 * - Major version == 1 and minor version < 0 or > 5
262 * - Major version == 2 and minor version < 0 or > 1
263 * - Major version == 3 and minor version < 0 or > 2
264 * - Major version == 4 and minor version < 0 or > 2
265 * - Forward-compatible flag set and major version < 3"
267 if (ctx
->ClientMajorVersion
< 1 || ctx
->ClientMinorVersion
< 0)
270 switch (ctx
->ClientMajorVersion
) {
272 if (ctx
->ClientMinorVersion
> 5
273 || (ctx
->Flags
& EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
) != 0)
278 if (ctx
->ClientMinorVersion
> 1
279 || (ctx
->Flags
& EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
) != 0)
284 /* Note: The text above is incorrect. There *is* an OpenGL 3.3!
286 if (ctx
->ClientMinorVersion
> 3)
292 /* Don't put additional version checks here. We don't know that
293 * there won't be versions > 4.2.
297 } else if (api
== EGL_OPENGL_ES_API
) {
298 /* The EGL_KHR_create_context spec says:
300 * "* If an OpenGL ES context is requested and the values for
301 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
302 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
303 * is not defined, than an EGL_BAD_MATCH error is generated.
305 * ... Examples of invalid combinations of attributes include:
307 * - Major version < 1 or > 2
308 * - Major version == 1 and minor version < 0 or > 1
309 * - Major version == 2 and minor version != 0
311 if (ctx
->ClientMajorVersion
< 1 || ctx
->ClientMinorVersion
< 0)
314 switch (ctx
->ClientMajorVersion
) {
316 if (ctx
->ClientMinorVersion
> 1)
321 if (ctx
->ClientMinorVersion
> 0)
327 /* Don't put additional version checks here. We don't know that
328 * there won't be versions > 3.0.
334 switch (ctx
->ResetNotificationStrategy
) {
335 case EGL_NO_RESET_NOTIFICATION_KHR
:
336 case EGL_LOSE_CONTEXT_ON_RESET_KHR
:
340 err
= EGL_BAD_ATTRIBUTE
;
344 if ((ctx
->Flags
& ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
345 | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
346 | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
)) != 0) {
347 err
= EGL_BAD_ATTRIBUTE
;
355 * Initialize the given _EGLContext object to defaults and/or the values
356 * in the attrib_list.
359 _eglInitContext(_EGLContext
*ctx
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
360 const EGLint
*attrib_list
)
362 const EGLenum api
= eglQueryAPI();
365 if (api
== EGL_NONE
) {
366 _eglError(EGL_BAD_MATCH
, "eglCreateContext(no client API)");
370 _eglInitResource(&ctx
->Resource
, sizeof(*ctx
), dpy
);
371 ctx
->ClientAPI
= api
;
373 ctx
->WindowRenderBuffer
= EGL_NONE
;
374 ctx
->Profile
= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
;
376 ctx
->ClientMajorVersion
= 1; /* the default, per EGL spec */
377 ctx
->ClientMinorVersion
= 0;
379 ctx
->Profile
= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
;
380 ctx
->ResetNotificationStrategy
= EGL_NO_RESET_NOTIFICATION_KHR
;
382 err
= _eglParseContextAttribList(ctx
, dpy
, attrib_list
);
383 if (err
== EGL_SUCCESS
&& ctx
->Config
) {
386 api_bit
= _eglGetContextAPIBit(ctx
);
387 if (!(ctx
->Config
->RenderableType
& api_bit
)) {
388 _eglLog(_EGL_DEBUG
, "context api is 0x%x while config supports 0x%x",
389 api_bit
, ctx
->Config
->RenderableType
);
390 err
= EGL_BAD_CONFIG
;
393 if (err
!= EGL_SUCCESS
)
394 return _eglError(err
, "eglCreateContext");
401 _eglQueryContextRenderBuffer(_EGLContext
*ctx
)
403 _EGLSurface
*surf
= ctx
->DrawSurface
;
408 if (surf
->Type
== EGL_WINDOW_BIT
&& ctx
->WindowRenderBuffer
!= EGL_NONE
)
409 rb
= ctx
->WindowRenderBuffer
;
411 rb
= surf
->RenderBuffer
;
417 _eglQueryContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*c
,
418 EGLint attribute
, EGLint
*value
)
424 return _eglError(EGL_BAD_PARAMETER
, "eglQueryContext");
429 return _eglError(EGL_BAD_ATTRIBUTE
, "eglQueryContext");
430 *value
= c
->Config
->ConfigID
;
432 case EGL_CONTEXT_CLIENT_VERSION
:
433 *value
= c
->ClientMajorVersion
;
435 case EGL_CONTEXT_CLIENT_TYPE
:
436 *value
= c
->ClientAPI
;
438 case EGL_RENDER_BUFFER
:
439 *value
= _eglQueryContextRenderBuffer(c
);
442 return _eglError(EGL_BAD_ATTRIBUTE
, "eglQueryContext");
450 * Bind the context to the thread and return the previous context.
452 * Note that the context may be NULL.
455 _eglBindContextToThread(_EGLContext
*ctx
, _EGLThreadInfo
*t
)
461 _eglConvertApiToIndex(ctx
->ClientAPI
) : t
->CurrentAPIIndex
;
463 oldCtx
= t
->CurrentContexts
[apiIndex
];
466 oldCtx
->Binding
= NULL
;
470 t
->CurrentContexts
[apiIndex
] = ctx
;
478 * Return true if the given context and surfaces can be made current.
481 _eglCheckMakeCurrent(_EGLContext
*ctx
, _EGLSurface
*draw
, _EGLSurface
*read
)
483 _EGLThreadInfo
*t
= _eglGetCurrentThread();
487 if (_eglIsCurrentThreadDummy())
488 return _eglError(EGL_BAD_ALLOC
, "eglMakeCurrent");
493 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
497 dpy
= ctx
->Resource
.Display
;
498 if (!dpy
->Extensions
.KHR_surfaceless_context
499 && (draw
== NULL
|| read
== NULL
))
500 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
505 * "If ctx is current to some other thread, or if either draw or read are
506 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
511 * "at most one context may be bound to a particular surface at a given
514 if (ctx
->Binding
&& ctx
->Binding
!= t
)
515 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
516 if (draw
&& draw
->CurrentContext
&& draw
->CurrentContext
!= ctx
) {
517 if (draw
->CurrentContext
->Binding
!= t
||
518 draw
->CurrentContext
->ClientAPI
!= ctx
->ClientAPI
)
519 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
521 if (read
&& read
->CurrentContext
&& read
->CurrentContext
!= ctx
) {
522 if (read
->CurrentContext
->Binding
!= t
||
523 read
->CurrentContext
->ClientAPI
!= ctx
->ClientAPI
)
524 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
527 /* simply require the configs to be equal */
528 if ((draw
&& draw
->Config
!= ctx
->Config
) ||
529 (read
&& read
->Config
!= ctx
->Config
))
530 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
532 switch (ctx
->ClientAPI
) {
533 /* OpenGL and OpenGL ES are conflicting */
534 case EGL_OPENGL_ES_API
:
535 conflict_api
= EGL_OPENGL_API
;
538 conflict_api
= EGL_OPENGL_ES_API
;
545 if (conflict_api
>= 0 && _eglGetAPIContext(conflict_api
))
546 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
553 * Bind the context to the current thread and given surfaces. Return the
554 * previous bound context and surfaces. The caller should unreference the
555 * returned context and surfaces.
557 * Making a second call with the resources returned by the first call
558 * unsurprisingly undoes the first call, except for the resouce reference
562 _eglBindContext(_EGLContext
*ctx
, _EGLSurface
*draw
, _EGLSurface
*read
,
563 _EGLContext
**old_ctx
,
564 _EGLSurface
**old_draw
, _EGLSurface
**old_read
)
566 _EGLThreadInfo
*t
= _eglGetCurrentThread();
567 _EGLContext
*prev_ctx
;
568 _EGLSurface
*prev_draw
, *prev_read
;
570 if (!_eglCheckMakeCurrent(ctx
, draw
, read
))
573 /* increment refcounts before binding */
575 _eglGetSurface(draw
);
576 _eglGetSurface(read
);
578 /* bind the new context */
579 prev_ctx
= _eglBindContextToThread(ctx
, t
);
581 /* break previous bindings */
583 prev_draw
= prev_ctx
->DrawSurface
;
584 prev_read
= prev_ctx
->ReadSurface
;
587 prev_draw
->CurrentContext
= NULL
;
589 prev_read
->CurrentContext
= NULL
;
591 prev_ctx
->DrawSurface
= NULL
;
592 prev_ctx
->ReadSurface
= NULL
;
595 prev_draw
= prev_read
= NULL
;
598 /* establish new bindings */
601 draw
->CurrentContext
= ctx
;
603 read
->CurrentContext
= ctx
;
605 ctx
->DrawSurface
= draw
;
606 ctx
->ReadSurface
= read
;
609 assert(old_ctx
&& old_draw
&& old_read
);
611 *old_draw
= prev_draw
;
612 *old_read
= prev_read
;