1 /**************************************************************************
2 *
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.
6 * All Rights Reserved.
7 *
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:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
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.
27 *
28 **************************************************************************/
29
30
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "eglconfig.h"
35 #include "eglcontext.h"
36 #include "egldisplay.h"
37 #include "eglcurrent.h"
38 #include "eglsurface.h"
39 #include "egllog.h"
40
41
42 /**
43 * Return the API bit (one of EGL_xxx_BIT) of the context.
44 */
45 static EGLint
_eglGetContextAPIBit(_EGLContext * ctx)46 _eglGetContextAPIBit(_EGLContext *ctx)
47 {
48 EGLint bit = 0;
49
50 switch (ctx->ClientAPI) {
51 case EGL_OPENGL_ES_API:
52 switch (ctx->ClientMajorVersion) {
53 case 1:
54 bit = EGL_OPENGL_ES_BIT;
55 break;
56 case 2:
57 case 3:
58 bit = EGL_OPENGL_ES2_BIT;
59 break;
60 default:
61 break;
62 }
63 break;
64 case EGL_OPENVG_API:
65 bit = EGL_OPENVG_BIT;
66 break;
67 case EGL_OPENGL_API:
68 bit = EGL_OPENGL_BIT;
69 break;
70 default:
71 break;
72 }
73
74 return bit;
75 }
76
77
78 /**
79 * Parse the list of context attributes and return the proper error code.
80 */
81 static EGLint
_eglParseContextAttribList(_EGLContext * ctx,_EGLDisplay * dpy,const EGLint * attrib_list)82 _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
83 const EGLint *attrib_list)
84 {
85 EGLenum api = ctx->ClientAPI;
86 EGLint i, err = EGL_SUCCESS;
87
88 if (!attrib_list)
89 return EGL_SUCCESS;
90
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;
94 }
95
96 for (i = 0; attrib_list[i] != EGL_NONE; i++) {
97 EGLint attr = attrib_list[i++];
98 EGLint val = attrib_list[i];
99
100 switch (attr) {
101 case EGL_CONTEXT_CLIENT_VERSION:
102 ctx->ClientMajorVersion = val;
103 break;
104
105 case EGL_CONTEXT_MINOR_VERSION_KHR:
106 if (!dpy->Extensions.KHR_create_context) {
107 err = EGL_BAD_ATTRIBUTE;
108 break;
109 }
110
111 ctx->ClientMinorVersion = val;
112 break;
113
114 case EGL_CONTEXT_FLAGS_KHR:
115 if (!dpy->Extensions.KHR_create_context) {
116 err = EGL_BAD_ATTRIBUTE;
117 break;
118 }
119
120 /* The EGL_KHR_create_context spec says:
121 *
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
125 * error."
126 */
127 if (api != EGL_OPENGL_API && val != 0) {
128 err = EGL_BAD_ATTRIBUTE;
129 break;
130 }
131
132 ctx->Flags = val;
133 break;
134
135 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
136 if (!dpy->Extensions.KHR_create_context) {
137 err = EGL_BAD_ATTRIBUTE;
138 break;
139 }
140
141 /* The EGL_KHR_create_context spec says:
142 *
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
146 * error."
147 */
148 if (api != EGL_OPENGL_API) {
149 err = EGL_BAD_ATTRIBUTE;
150 break;
151 }
152
153 ctx->Profile = val;
154 break;
155
156 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
157 /* The EGL_KHR_create_context spec says:
158 *
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
162 * an error."
163 */
164 if (!dpy->Extensions.KHR_create_context
165 || api != EGL_OPENGL_API) {
166 err = EGL_BAD_ATTRIBUTE;
167 break;
168 }
169
170 ctx->ResetNotificationStrategy = val;
171 break;
172
173 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
174 /* The EGL_EXT_create_context_robustness spec says:
175 *
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."
179 */
180 if (!dpy->Extensions.EXT_create_context_robustness
181 || api != EGL_OPENGL_ES_API) {
182 err = EGL_BAD_ATTRIBUTE;
183 break;
184 }
185
186 ctx->ResetNotificationStrategy = val;
187 break;
188
189 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
190 if (!dpy->Extensions.EXT_create_context_robustness) {
191 err = EGL_BAD_ATTRIBUTE;
192 break;
193 }
194
195 ctx->Flags = EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
196 break;
197
198 default:
199 err = EGL_BAD_ATTRIBUTE;
200 break;
201 }
202
203 if (err != EGL_SUCCESS) {
204 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
205 break;
206 }
207 }
208
209 if (api == EGL_OPENGL_API) {
210 /* The EGL_KHR_create_context spec says:
211 *
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."
216 *
217 * Since the value is ignored, only validate the setting if the version
218 * is >= 3.2.
219 */
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:
225 break;
226
227 default:
228 /* The EGL_KHR_create_context spec says:
229 *
230 * "* If an OpenGL context is requested, the requested version
231 * is greater than 3.2, and the value for attribute
232 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
233 * any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
234 * and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
235 * more than one of these bits set; or if the implementation does
236 * not support the requested profile, then an EGL_BAD_MATCH error
237 * is generated."
238 */
239 err = EGL_BAD_MATCH;
240 break;
241 }
242 }
243
244 /* The EGL_KHR_create_context spec says:
245 *
246 * "* If an OpenGL context is requested and the values for
247 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
248 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
249 * the value for attribute
250 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
251 * version and feature set that are not defined, than an
252 * EGL_BAD_MATCH error is generated.
253 *
254 * ... Thus, examples of invalid combinations of attributes
255 * include:
256 *
257 * - Major version < 1 or > 4
258 * - Major version == 1 and minor version < 0 or > 5
259 * - Major version == 2 and minor version < 0 or > 1
260 * - Major version == 3 and minor version < 0 or > 2
261 * - Major version == 4 and minor version < 0 or > 2
262 * - Forward-compatible flag set and major version < 3"
263 */
264 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
265 err = EGL_BAD_MATCH;
266
267 switch (ctx->ClientMajorVersion) {
268 case 1:
269 if (ctx->ClientMinorVersion > 5
270 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
271 err = EGL_BAD_MATCH;
272 break;
273
274 case 2:
275 if (ctx->ClientMinorVersion > 1
276 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
277 err = EGL_BAD_MATCH;
278 break;
279
280 case 3:
281 /* Note: The text above is incorrect. There *is* an OpenGL 3.3!
282 */
283 if (ctx->ClientMinorVersion > 3)
284 err = EGL_BAD_MATCH;
285 break;
286
287 case 4:
288 default:
289 /* Don't put additional version checks here. We don't know that
290 * there won't be versions > 4.2.
291 */
292 break;
293 }
294 } else if (api == EGL_OPENGL_ES_API) {
295 /* The EGL_KHR_create_context spec says:
296 *
297 * "* If an OpenGL ES context is requested and the values for
298 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
299 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
300 * is not defined, than an EGL_BAD_MATCH error is generated.
301 *
302 * ... Examples of invalid combinations of attributes include:
303 *
304 * - Major version < 1 or > 2
305 * - Major version == 1 and minor version < 0 or > 1
306 * - Major version == 2 and minor version != 0
307 */
308 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
309 err = EGL_BAD_MATCH;
310
311 switch (ctx->ClientMajorVersion) {
312 case 1:
313 if (ctx->ClientMinorVersion > 1)
314 err = EGL_BAD_MATCH;
315 break;
316
317 case 2:
318 if (ctx->ClientMinorVersion > 0)
319 err = EGL_BAD_MATCH;
320 break;
321
322 case 3:
323 default:
324 /* Don't put additional version checks here. We don't know that
325 * there won't be versions > 3.0.
326 */
327 break;
328 }
329 }
330
331 switch (ctx->ResetNotificationStrategy) {
332 case EGL_NO_RESET_NOTIFICATION_KHR:
333 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
334 break;
335
336 default:
337 err = EGL_BAD_ATTRIBUTE;
338 break;
339 }
340
341 if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
342 | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
343 | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
344 err = EGL_BAD_ATTRIBUTE;
345 }
346
347 return err;
348 }
349
350
351 /**
352 * Initialize the given _EGLContext object to defaults and/or the values
353 * in the attrib_list.
354 */
355 EGLBoolean
_eglInitContext(_EGLContext * ctx,_EGLDisplay * dpy,_EGLConfig * conf,const EGLint * attrib_list)356 _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
357 const EGLint *attrib_list)
358 {
359 const EGLenum api = eglQueryAPI();
360 EGLint err;
361
362 if (api == EGL_NONE) {
363 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
364 return EGL_FALSE;
365 }
366
367 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
368 ctx->ClientAPI = api;
369 ctx->Config = conf;
370 ctx->WindowRenderBuffer = EGL_NONE;
371 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
372
373 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
374 ctx->ClientMinorVersion = 0;
375 ctx->Flags = 0;
376 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
377 ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
378
379 err = _eglParseContextAttribList(ctx, dpy, attrib_list);
380 if (err == EGL_SUCCESS && ctx->Config) {
381 EGLint api_bit;
382
383 api_bit = _eglGetContextAPIBit(ctx);
384 if (!(ctx->Config->RenderableType & api_bit)) {
385 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
386 api_bit, ctx->Config->RenderableType);
387 err = EGL_BAD_CONFIG;
388 }
389 }
390 if (err != EGL_SUCCESS)
391 return _eglError(err, "eglCreateContext");
392
393 return EGL_TRUE;
394 }
395
396
397 static EGLint
_eglQueryContextRenderBuffer(_EGLContext * ctx)398 _eglQueryContextRenderBuffer(_EGLContext *ctx)
399 {
400 _EGLSurface *surf = ctx->DrawSurface;
401 EGLint rb;
402
403 if (!surf)
404 return EGL_NONE;
405 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
406 rb = ctx->WindowRenderBuffer;
407 else
408 rb = surf->RenderBuffer;
409 return rb;
410 }
411
412
413 EGLBoolean
_eglQueryContext(_EGLDriver * drv,_EGLDisplay * dpy,_EGLContext * c,EGLint attribute,EGLint * value)414 _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
415 EGLint attribute, EGLint *value)
416 {
417 (void) drv;
418 (void) dpy;
419
420 if (!value)
421 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
422
423 switch (attribute) {
424 case EGL_CONFIG_ID:
425 if (!c->Config)
426 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
427 *value = c->Config->ConfigID;
428 break;
429 case EGL_CONTEXT_CLIENT_VERSION:
430 *value = c->ClientMajorVersion;
431 break;
432 case EGL_CONTEXT_CLIENT_TYPE:
433 *value = c->ClientAPI;
434 break;
435 case EGL_RENDER_BUFFER:
436 *value = _eglQueryContextRenderBuffer(c);
437 break;
438 default:
439 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
440 }
441
442 return EGL_TRUE;
443 }
444
445
446 /**
447 * Bind the context to the thread and return the previous context.
448 *
449 * Note that the context may be NULL.
450 */
451 static _EGLContext *
_eglBindContextToThread(_EGLContext * ctx,_EGLThreadInfo * t)452 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
453 {
454 EGLint apiIndex;
455 _EGLContext *oldCtx;
456
457 apiIndex = (ctx) ?
458 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
459
460 oldCtx = t->CurrentContexts[apiIndex];
461 if (ctx != oldCtx) {
462 if (oldCtx)
463 oldCtx->Binding = NULL;
464 if (ctx)
465 ctx->Binding = t;
466
467 t->CurrentContexts[apiIndex] = ctx;
468 }
469
470 return oldCtx;
471 }
472
473
474 /**
475 * Return true if the given context and surfaces can be made current.
476 */
477 static EGLBoolean
_eglCheckMakeCurrent(_EGLContext * ctx,_EGLSurface * draw,_EGLSurface * read)478 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
479 {
480 _EGLThreadInfo *t = _eglGetCurrentThread();
481 _EGLDisplay *dpy;
482 EGLint conflict_api;
483
484 if (_eglIsCurrentThreadDummy())
485 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
486
487 /* this is easy */
488 if (!ctx) {
489 if (draw || read)
490 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
491 return EGL_TRUE;
492 }
493
494 dpy = ctx->Resource.Display;
495 if (!dpy->Extensions.KHR_surfaceless_context
496 && (draw == NULL || read == NULL))
497 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
498
499 /*
500 * The spec says
501 *
502 * "If ctx is current to some other thread, or if either draw or read are
503 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
504 * generated."
505 *
506 * and
507 *
508 * "at most one context may be bound to a particular surface at a given
509 * time"
510 */
511 if (ctx->Binding && ctx->Binding != t)
512 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
513 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
514 if (draw->CurrentContext->Binding != t ||
515 draw->CurrentContext->ClientAPI != ctx->ClientAPI)
516 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
517 }
518 if (read && read->CurrentContext && read->CurrentContext != ctx) {
519 if (read->CurrentContext->Binding != t ||
520 read->CurrentContext->ClientAPI != ctx->ClientAPI)
521 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
522 }
523
524 /* simply require the configs to be equal */
525 if ((draw && draw->Config != ctx->Config) ||
526 (read && read->Config != ctx->Config))
527 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
528
529 switch (ctx->ClientAPI) {
530 /* OpenGL and OpenGL ES are conflicting */
531 case EGL_OPENGL_ES_API:
532 conflict_api = EGL_OPENGL_API;
533 break;
534 case EGL_OPENGL_API:
535 conflict_api = EGL_OPENGL_ES_API;
536 break;
537 default:
538 conflict_api = -1;
539 break;
540 }
541
542 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
543 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
544
545 return EGL_TRUE;
546 }
547
548
549 /**
550 * Bind the context to the current thread and given surfaces. Return the
551 * previous bound context and surfaces. The caller should unreference the
552 * returned context and surfaces.
553 *
554 * Making a second call with the resources returned by the first call
555 * unsurprisingly undoes the first call, except for the resouce reference
556 * counts.
557 */
558 EGLBoolean
_eglBindContext(_EGLContext * ctx,_EGLSurface * draw,_EGLSurface * read,_EGLContext ** old_ctx,_EGLSurface ** old_draw,_EGLSurface ** old_read)559 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
560 _EGLContext **old_ctx,
561 _EGLSurface **old_draw, _EGLSurface **old_read)
562 {
563 _EGLThreadInfo *t = _eglGetCurrentThread();
564 _EGLContext *prev_ctx;
565 _EGLSurface *prev_draw, *prev_read;
566
567 if (!_eglCheckMakeCurrent(ctx, draw, read))
568 return EGL_FALSE;
569
570 /* increment refcounts before binding */
571 _eglGetContext(ctx);
572 _eglGetSurface(draw);
573 _eglGetSurface(read);
574
575 /* bind the new context */
576 prev_ctx = _eglBindContextToThread(ctx, t);
577
578 /* break previous bindings */
579 if (prev_ctx) {
580 prev_draw = prev_ctx->DrawSurface;
581 prev_read = prev_ctx->ReadSurface;
582
583 if (prev_draw)
584 prev_draw->CurrentContext = NULL;
585 if (prev_read)
586 prev_read->CurrentContext = NULL;
587
588 prev_ctx->DrawSurface = NULL;
589 prev_ctx->ReadSurface = NULL;
590 }
591 else {
592 prev_draw = prev_read = NULL;
593 }
594
595 /* establish new bindings */
596 if (ctx) {
597 if (draw)
598 draw->CurrentContext = ctx;
599 if (read)
600 read->CurrentContext = ctx;
601
602 ctx->DrawSurface = draw;
603 ctx->ReadSurface = read;
604 }
605
606 assert(old_ctx && old_draw && old_read);
607 *old_ctx = prev_ctx;
608 *old_draw = prev_draw;
609 *old_read = prev_read;
610
611 return EGL_TRUE;
612 }
613