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
->ClientVersion
) {
54 bit
= EGL_OPENGL_ES_BIT
;
57 bit
= EGL_OPENGL_ES2_BIT
;
78 * Parse the list of context attributes and return the proper error code.
81 _eglParseContextAttribList(_EGLContext
*ctx
, const EGLint
*attrib_list
)
83 EGLenum api
= ctx
->ClientAPI
;
84 EGLint i
, err
= EGL_SUCCESS
;
89 for (i
= 0; attrib_list
[i
] != EGL_NONE
; i
++) {
90 EGLint attr
= attrib_list
[i
++];
91 EGLint val
= attrib_list
[i
];
94 case EGL_CONTEXT_CLIENT_VERSION
:
95 if (api
!= EGL_OPENGL_ES_API
) {
96 err
= EGL_BAD_ATTRIBUTE
;
99 if (val
!= 1 && val
!= 2) {
100 err
= EGL_BAD_ATTRIBUTE
;
103 ctx
->ClientVersion
= val
;
106 err
= EGL_BAD_ATTRIBUTE
;
110 if (err
!= EGL_SUCCESS
) {
111 _eglLog(_EGL_DEBUG
, "bad context attribute 0x%04x", attr
);
121 * Initialize the given _EGLContext object to defaults and/or the values
122 * in the attrib_list.
125 _eglInitContext(_EGLContext
*ctx
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
126 const EGLint
*attrib_list
)
128 const EGLenum api
= eglQueryAPI();
131 if (api
== EGL_NONE
) {
132 _eglError(EGL_BAD_MATCH
, "eglCreateContext(no client API)");
136 _eglInitResource(&ctx
->Resource
, sizeof(*ctx
), dpy
);
137 ctx
->ClientAPI
= api
;
139 ctx
->WindowRenderBuffer
= EGL_NONE
;
141 ctx
->ClientVersion
= 1; /* the default, per EGL spec */
143 err
= _eglParseContextAttribList(ctx
, attrib_list
);
144 if (err
== EGL_SUCCESS
&& ctx
->Config
) {
147 api_bit
= _eglGetContextAPIBit(ctx
);
148 if (!(ctx
->Config
->RenderableType
& api_bit
)) {
149 _eglLog(_EGL_DEBUG
, "context api is 0x%x while config supports 0x%x",
150 api_bit
, ctx
->Config
->RenderableType
);
151 err
= EGL_BAD_CONFIG
;
154 if (err
!= EGL_SUCCESS
)
155 return _eglError(err
, "eglCreateContext");
161 #ifdef EGL_VERSION_1_2
163 _eglQueryContextRenderBuffer(_EGLContext
*ctx
)
165 _EGLSurface
*surf
= ctx
->DrawSurface
;
170 if (surf
->Type
== EGL_WINDOW_BIT
&& ctx
->WindowRenderBuffer
!= EGL_NONE
)
171 rb
= ctx
->WindowRenderBuffer
;
173 rb
= surf
->RenderBuffer
;
176 #endif /* EGL_VERSION_1_2 */
180 _eglQueryContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*c
,
181 EGLint attribute
, EGLint
*value
)
187 return _eglError(EGL_BAD_PARAMETER
, "eglQueryContext");
192 return _eglError(EGL_BAD_ATTRIBUTE
, "eglQueryContext");
193 *value
= c
->Config
->ConfigID
;
195 case EGL_CONTEXT_CLIENT_VERSION
:
196 *value
= c
->ClientVersion
;
198 #ifdef EGL_VERSION_1_2
199 case EGL_CONTEXT_CLIENT_TYPE
:
200 *value
= c
->ClientAPI
;
202 case EGL_RENDER_BUFFER
:
203 *value
= _eglQueryContextRenderBuffer(c
);
205 #endif /* EGL_VERSION_1_2 */
207 return _eglError(EGL_BAD_ATTRIBUTE
, "eglQueryContext");
215 * Bind the context to the thread and return the previous context.
217 * Note that the context may be NULL.
220 _eglBindContextToThread(_EGLContext
*ctx
, _EGLThreadInfo
*t
)
226 _eglConvertApiToIndex(ctx
->ClientAPI
) : t
->CurrentAPIIndex
;
228 oldCtx
= t
->CurrentContexts
[apiIndex
];
231 oldCtx
->Binding
= NULL
;
235 t
->CurrentContexts
[apiIndex
] = ctx
;
243 * Return true if the given context and surfaces can be made current.
246 _eglCheckMakeCurrent(_EGLContext
*ctx
, _EGLSurface
*draw
, _EGLSurface
*read
)
248 _EGLThreadInfo
*t
= _eglGetCurrentThread();
251 EGLBoolean surfaceless
;
253 if (_eglIsCurrentThreadDummy())
254 return _eglError(EGL_BAD_ALLOC
, "eglMakeCurrent");
259 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
263 dpy
= ctx
->Resource
.Display
;
264 switch (_eglGetContextAPIBit(ctx
)) {
265 case EGL_OPENGL_ES_BIT
:
266 surfaceless
= dpy
->Extensions
.KHR_surfaceless_gles1
;
268 case EGL_OPENGL_ES2_BIT
:
269 surfaceless
= dpy
->Extensions
.KHR_surfaceless_gles2
;
272 surfaceless
= dpy
->Extensions
.KHR_surfaceless_opengl
;
275 surfaceless
= EGL_FALSE
;
279 if (!surfaceless
&& (draw
== NULL
|| read
== NULL
))
280 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
285 * "If ctx is current to some other thread, or if either draw or read are
286 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
291 * "at most one context may be bound to a particular surface at a given
294 if (ctx
->Binding
&& ctx
->Binding
!= t
)
295 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
296 if (draw
&& draw
->CurrentContext
&& draw
->CurrentContext
!= ctx
) {
297 if (draw
->CurrentContext
->Binding
!= t
||
298 draw
->CurrentContext
->ClientAPI
!= ctx
->ClientAPI
)
299 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
301 if (read
&& read
->CurrentContext
&& read
->CurrentContext
!= ctx
) {
302 if (read
->CurrentContext
->Binding
!= t
||
303 read
->CurrentContext
->ClientAPI
!= ctx
->ClientAPI
)
304 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
307 /* simply require the configs to be equal */
308 if ((draw
&& draw
->Config
!= ctx
->Config
) ||
309 (read
&& read
->Config
!= ctx
->Config
))
310 return _eglError(EGL_BAD_MATCH
, "eglMakeCurrent");
312 switch (ctx
->ClientAPI
) {
313 #ifdef EGL_VERSION_1_4
314 /* OpenGL and OpenGL ES are conflicting */
315 case EGL_OPENGL_ES_API
:
316 conflict_api
= EGL_OPENGL_API
;
319 conflict_api
= EGL_OPENGL_ES_API
;
327 if (conflict_api
>= 0 && _eglGetAPIContext(conflict_api
))
328 return _eglError(EGL_BAD_ACCESS
, "eglMakeCurrent");
335 * Bind the context to the current thread and given surfaces. Return the
336 * previous bound context and surfaces. The caller should unreference the
337 * returned context and surfaces.
339 * Making a second call with the resources returned by the first call
340 * unsurprisingly undoes the first call, except for the resouce reference
344 _eglBindContext(_EGLContext
*ctx
, _EGLSurface
*draw
, _EGLSurface
*read
,
345 _EGLContext
**old_ctx
,
346 _EGLSurface
**old_draw
, _EGLSurface
**old_read
)
348 _EGLThreadInfo
*t
= _eglGetCurrentThread();
349 _EGLContext
*prev_ctx
;
350 _EGLSurface
*prev_draw
, *prev_read
;
352 if (!_eglCheckMakeCurrent(ctx
, draw
, read
))
355 /* increment refcounts before binding */
357 _eglGetSurface(draw
);
358 _eglGetSurface(read
);
360 /* bind the new context */
361 prev_ctx
= _eglBindContextToThread(ctx
, t
);
363 /* break previous bindings */
365 prev_draw
= prev_ctx
->DrawSurface
;
366 prev_read
= prev_ctx
->ReadSurface
;
369 prev_draw
->CurrentContext
= NULL
;
371 prev_read
->CurrentContext
= NULL
;
373 prev_ctx
->DrawSurface
= NULL
;
374 prev_ctx
->ReadSurface
= NULL
;
377 prev_draw
= prev_read
= NULL
;
380 /* establish new bindings */
383 draw
->CurrentContext
= ctx
;
385 read
->CurrentContext
= ctx
;
387 ctx
->DrawSurface
= draw
;
388 ctx
->ReadSurface
= read
;
391 assert(old_ctx
&& old_draw
&& old_read
);
393 *old_draw
= prev_draw
;
394 *old_read
= prev_read
;