1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 #include "eglcontext.h"
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "util/macros.h"
35 #include "eglconfig.h"
36 #include "eglcurrent.h"
37 #include "egldisplay.h"
38 #include "egllog.h"
39 #include "eglsurface.h"
40
41 /**
42 * Return the API bit (one of EGL_xxx_BIT) of the context.
43 */
44 static EGLint
_eglGetContextAPIBit(_EGLContext * ctx)45 _eglGetContextAPIBit(_EGLContext *ctx)
46 {
47 EGLint bit = 0;
48
49 switch (ctx->ClientAPI) {
50 case EGL_OPENGL_ES_API:
51 switch (ctx->ClientMajorVersion) {
52 case 1:
53 bit = EGL_OPENGL_ES_BIT;
54 break;
55 case 2:
56 bit = EGL_OPENGL_ES2_BIT;
57 break;
58 case 3:
59 bit = EGL_OPENGL_ES3_BIT_KHR;
60 break;
61 default:
62 break;
63 }
64 break;
65 case EGL_OPENVG_API:
66 bit = EGL_OPENVG_BIT;
67 break;
68 case EGL_OPENGL_API:
69 bit = EGL_OPENGL_BIT;
70 break;
71 default:
72 break;
73 }
74
75 return bit;
76 }
77
78 /**
79 * Parse the list of context attributes and return the proper error code.
80 */
81 static EGLint
_eglParseContextAttribList(_EGLContext * ctx,_EGLDisplay * disp,const EGLint * attrib_list)82 _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *disp,
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 /* The EGL 1.4 spec says:
103 *
104 * "attribute EGL_CONTEXT_CLIENT_VERSION is only valid when the
105 * current rendering API is EGL_OPENGL_ES_API"
106 *
107 * The EGL_KHR_create_context spec says:
108 *
109 * "EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
110 * (this token is an alias for EGL_CONTEXT_CLIENT_VERSION)"
111 *
112 * "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
113 * EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
114 * version. They are only meaningful for OpenGL and OpenGL ES
115 * contexts, and specifying them for other types of contexts will
116 * generate an error."
117 */
118 if ((api != EGL_OPENGL_ES_API &&
119 (!disp->Extensions.KHR_create_context ||
120 api != EGL_OPENGL_API))) {
121 err = EGL_BAD_ATTRIBUTE;
122 break;
123 }
124
125 ctx->ClientMajorVersion = val;
126 break;
127
128 case EGL_CONTEXT_MINOR_VERSION_KHR:
129 /* The EGL_KHR_create_context spec says:
130 *
131 * "The values for attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
132 * EGL_CONTEXT_MINOR_VERSION_KHR specify the requested client API
133 * version. They are only meaningful for OpenGL and OpenGL ES
134 * contexts, and specifying them for other types of contexts will
135 * generate an error."
136 */
137 if (!disp->Extensions.KHR_create_context ||
138 (api != EGL_OPENGL_ES_API && api != EGL_OPENGL_API)) {
139 err = EGL_BAD_ATTRIBUTE;
140 break;
141 }
142
143 ctx->ClientMinorVersion = val;
144 break;
145
146 case EGL_CONTEXT_FLAGS_KHR:
147 if (!disp->Extensions.KHR_create_context) {
148 err = EGL_BAD_ATTRIBUTE;
149 break;
150 }
151
152 /* The EGL_KHR_create_context spec says:
153 *
154 * "If the EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR flag bit is set in
155 * EGL_CONTEXT_FLAGS_KHR, then a <debug context> will be created.
156 * [...]
157 * In some cases a debug context may be identical to a non-debug
158 * context. This bit is supported for OpenGL and OpenGL ES
159 * contexts."
160 */
161 if ((val & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) &&
162 (api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API)) {
163 err = EGL_BAD_ATTRIBUTE;
164 break;
165 }
166
167 /* The EGL_KHR_create_context spec says:
168 *
169 * "If the EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR flag bit
170 * is set in EGL_CONTEXT_FLAGS_KHR, then a <forward-compatible>
171 * context will be created. Forward-compatible contexts are
172 * defined only for OpenGL versions 3.0 and later. They must not
173 * support functionality marked as <deprecated> by that version of
174 * the API, while a non-forward-compatible context must support
175 * all functionality in that version, deprecated or not. This bit
176 * is supported for OpenGL contexts, and requesting a
177 * forward-compatible context for OpenGL versions less than 3.0
178 * will generate an error."
179 *
180 * Note: since the forward-compatible flag can be set more than one
181 * way, the OpenGL version check is performed once, below.
182 */
183 if ((val & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) &&
184 api != EGL_OPENGL_API) {
185 err = EGL_BAD_ATTRIBUTE;
186 break;
187 }
188
189 if ((val & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) &&
190 api != EGL_OPENGL_API) {
191 /* The EGL_KHR_create_context spec says:
192 *
193 * 10) Which error should be generated if robust buffer access
194 * or reset notifications are requested under OpenGL ES?
195 *
196 * As per Issue 6, this extension does not support creating
197 * robust contexts for OpenGL ES. This is only supported via
198 * the EGL_EXT_create_context_robustness extension.
199 *
200 * Attempting to use this extension to create robust OpenGL
201 * ES context will generate an EGL_BAD_ATTRIBUTE error. This
202 * specific error is generated because this extension does
203 * not define the EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
204 * and EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
205 * bits for OpenGL ES contexts. Thus, use of these bits fall
206 * under condition described by: "If an attribute is
207 * specified that is not meaningful for the client API
208 * type.." in the above specification.
209 *
210 * The spec requires that we emit the error even if the display
211 * supports EGL_EXT_create_context_robustness. To create a robust
212 * GLES context, the *attribute*
213 * EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT must be used, not the
214 * *flag* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR.
215 */
216 err = EGL_BAD_ATTRIBUTE;
217 break;
218 }
219
220 ctx->Flags |= val;
221 break;
222
223 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
224 if (!disp->Extensions.KHR_create_context) {
225 err = EGL_BAD_ATTRIBUTE;
226 break;
227 }
228
229 /* The EGL_KHR_create_context spec says:
230 *
231 * "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
232 * OpenGL contexts, and specifying it for other types of
233 * contexts, including OpenGL ES contexts, will generate an
234 * error."
235 */
236 if (api != EGL_OPENGL_API) {
237 err = EGL_BAD_ATTRIBUTE;
238 break;
239 }
240
241 ctx->Profile = val;
242 break;
243
244 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
245 /* The EGL_KHR_create_context spec says:
246 *
247 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
248 * meaningful for OpenGL contexts, and specifying it for other
249 * types of contexts, including OpenGL ES contexts, will generate
250 * an error."
251 *
252 * EGL 1.5 defines EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
253 * (without a suffix) which has the same value as the KHR token,
254 * and specifies that it now works with both GL and ES contexts:
255 *
256 * "This attribute is supported only for OpenGL and OpenGL ES
257 * contexts."
258 */
259 if (!(disp->Extensions.KHR_create_context && api == EGL_OPENGL_API) &&
260 !(disp->Version >= 15 &&
261 (api == EGL_OPENGL_API || api == EGL_OPENGL_ES_API))) {
262 err = EGL_BAD_ATTRIBUTE;
263 break;
264 }
265
266 ctx->ResetNotificationStrategy = val;
267 break;
268
269 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
270 /* The EGL_EXT_create_context_robustness spec says:
271 *
272 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
273 * meaningful for OpenGL ES contexts, and specifying it for other
274 * types of contexts will generate an EGL_BAD_ATTRIBUTE error."
275 */
276 if (!disp->Extensions.EXT_create_context_robustness ||
277 api != EGL_OPENGL_ES_API) {
278 err = EGL_BAD_ATTRIBUTE;
279 break;
280 }
281
282 ctx->ResetNotificationStrategy = val;
283 break;
284
285 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
286 if (!disp->Extensions.EXT_create_context_robustness) {
287 err = EGL_BAD_ATTRIBUTE;
288 break;
289 }
290
291 /* The EGL_EXT_create_context_robustness spec says:
292 *
293 * "EGL_BAD_CONFIG is generated if
294 * [EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT] is set to EGL_TRUE and
295 * no GL context supporting the GL_EXT_robustness extension and
296 * robust access as described therein can be created."
297 */
298 if (val == EGL_TRUE && !disp->RobustBufferAccess) {
299 err = EGL_BAD_CONFIG;
300 break;
301 }
302
303 if (val == EGL_TRUE)
304 ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
305 break;
306
307 case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
308 if (disp->Version < 15) {
309 err = EGL_BAD_ATTRIBUTE;
310 break;
311 }
312
313 if (val == EGL_TRUE)
314 ctx->Flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
315 break;
316
317 case EGL_CONTEXT_OPENGL_DEBUG:
318 if (disp->Version < 15) {
319 err = EGL_BAD_ATTRIBUTE;
320 break;
321 }
322
323 if (val == EGL_TRUE)
324 ctx->Flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
325 break;
326
327 case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE:
328 if (disp->Version < 15) {
329 err = EGL_BAD_ATTRIBUTE;
330 break;
331 }
332
333 if (val == EGL_TRUE)
334 ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
335 break;
336
337 case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
338 if (disp->Version < 14 ||
339 !disp->Extensions.KHR_create_context_no_error) {
340 err = EGL_BAD_ATTRIBUTE;
341 break;
342 }
343
344 /* The KHR_no_error spec only applies against OpenGL 2.0+ and
345 * OpenGL ES 2.0+
346 */
347 if (((api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API) ||
348 ctx->ClientMajorVersion < 2) &&
349 val == EGL_TRUE) {
350 err = EGL_BAD_ATTRIBUTE;
351 break;
352 }
353
354 /* Canonicalize value to EGL_TRUE/EGL_FALSE definitions */
355 ctx->NoError = !!val;
356 break;
357
358 case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
359 /* The EGL_IMG_context_priority spec says:
360 *
361 * "EGL_CONTEXT_PRIORITY_LEVEL_IMG determines the priority level of
362 * the context to be created. This attribute is a hint, as an
363 * implementation may not support multiple contexts at some
364 * priority levels and system policy may limit access to high
365 * priority contexts to appropriate system privilege level. The
366 * default value for EGL_CONTEXT_PRIORITY_LEVEL_IMG is
367 * EGL_CONTEXT_PRIORITY_MEDIUM_IMG."
368 */
369 {
370 int bit;
371
372 switch (val) {
373 case EGL_CONTEXT_PRIORITY_HIGH_IMG:
374 bit = __EGL_CONTEXT_PRIORITY_HIGH_BIT;
375 break;
376 case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
377 bit = __EGL_CONTEXT_PRIORITY_MEDIUM_BIT;
378 break;
379 case EGL_CONTEXT_PRIORITY_LOW_IMG:
380 bit = __EGL_CONTEXT_PRIORITY_LOW_BIT;
381 break;
382 default:
383 bit = -1;
384 break;
385 }
386
387 if (bit < 0) {
388 err = EGL_BAD_ATTRIBUTE;
389 break;
390 }
391
392 /* "This extension allows an EGLContext to be created with a
393 * priority hint. It is possible that an implementation will not
394 * honour the hint, especially if there are constraints on the
395 * number of high priority contexts available in the system, or
396 * system policy limits access to high priority contexts to
397 * appropriate system privilege level. A query is provided to find
398 * the real priority level assigned to the context after creation."
399 *
400 * We currently assume that the driver applies the priority hint
401 * and filters out any it cannot handle during the screen setup,
402 * e.g. dri2_setup_screen(). As such we can mask any change that
403 * the driver would fail, and ctx->ContextPriority matches the
404 * hint applied to the driver/hardware backend.
405 */
406 if (disp->Extensions.IMG_context_priority & (1 << bit))
407 ctx->ContextPriority = val;
408
409 break;
410 }
411
412 case EGL_CONTEXT_RELEASE_BEHAVIOR_KHR:
413 if (val == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR ||
414 val == EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR) {
415 ctx->ReleaseBehavior = val;
416 } else {
417 err = EGL_BAD_ATTRIBUTE;
418 }
419 break;
420
421 case EGL_PROTECTED_CONTENT_EXT:
422 if (!disp->Extensions.EXT_protected_content) {
423 err = EGL_BAD_ATTRIBUTE;
424 break;
425 }
426 ctx->Protected = val == EGL_TRUE;
427 break;
428
429 default:
430 err = EGL_BAD_ATTRIBUTE;
431 break;
432 }
433
434 if (err != EGL_SUCCESS) {
435 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
436 break;
437 }
438 }
439
440 if (api == EGL_OPENGL_API) {
441 /* The EGL_KHR_create_context spec says:
442 *
443 * "If the requested OpenGL version is less than 3.2,
444 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
445 * functionality of the context is determined solely by the
446 * requested version."
447 *
448 * Since the value is ignored, only validate the setting if the version
449 * is >= 3.2.
450 */
451 if (ctx->ClientMajorVersion >= 4 ||
452 (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
453 switch (ctx->Profile) {
454 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
455 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
456 break;
457
458 default:
459 /* The EGL_KHR_create_context spec says:
460 *
461 * "* If an OpenGL context is requested, the requested version
462 * is greater than 3.2, and the value for attribute
463 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
464 * any bits set other than
465 * EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR and
466 * EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has more than
467 * one of these bits set; or if the implementation does not support
468 * the requested profile, then an EGL_BAD_MATCH error is generated."
469 */
470 err = EGL_BAD_MATCH;
471 break;
472 }
473 }
474
475 /* The EGL_KHR_create_context spec says:
476 *
477 * "* If an OpenGL context is requested and the values for
478 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
479 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
480 * the value for attribute
481 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
482 * version and feature set that are not defined, than an
483 * EGL_BAD_MATCH error is generated.
484 *
485 * ... Thus, examples of invalid combinations of attributes
486 * include:
487 *
488 * - Major version < 1 or > 4
489 * - Major version == 1 and minor version < 0 or > 5
490 * - Major version == 2 and minor version < 0 or > 1
491 * - Major version == 3 and minor version < 0 or > 2
492 * - Major version == 4 and minor version < 0 or > 2
493 * - Forward-compatible flag set and major version < 3"
494 */
495 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
496 err = EGL_BAD_MATCH;
497
498 switch (ctx->ClientMajorVersion) {
499 case 1:
500 if (ctx->ClientMinorVersion > 5 ||
501 (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
502 err = EGL_BAD_MATCH;
503 break;
504
505 case 2:
506 if (ctx->ClientMinorVersion > 1 ||
507 (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
508 err = EGL_BAD_MATCH;
509 break;
510
511 case 3:
512 /* Note: The text above is incorrect. There *is* an OpenGL 3.3!
513 */
514 if (ctx->ClientMinorVersion > 3)
515 err = EGL_BAD_MATCH;
516 break;
517
518 case 4:
519 default:
520 /* Don't put additional version checks here. We don't know that
521 * there won't be versions > 4.2.
522 */
523 break;
524 }
525 } else if (api == EGL_OPENGL_ES_API) {
526 /* The EGL_KHR_create_context spec says:
527 *
528 * "* If an OpenGL ES context is requested and the values for
529 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
530 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
531 * is not defined, than an EGL_BAD_MATCH error is generated.
532 *
533 * ... Examples of invalid combinations of attributes include:
534 *
535 * - Major version < 1 or > 2
536 * - Major version == 1 and minor version < 0 or > 1
537 * - Major version == 2 and minor version != 0
538 */
539 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
540 err = EGL_BAD_MATCH;
541
542 switch (ctx->ClientMajorVersion) {
543 case 1:
544 if (ctx->ClientMinorVersion > 1)
545 err = EGL_BAD_MATCH;
546 break;
547
548 case 2:
549 if (ctx->ClientMinorVersion > 0)
550 err = EGL_BAD_MATCH;
551 break;
552
553 case 3:
554 /* Don't put additional version checks here. We don't know that
555 * there won't be versions > 3.0.
556 */
557 break;
558
559 default:
560 err = EGL_BAD_MATCH;
561 break;
562 }
563 }
564
565 switch (ctx->ResetNotificationStrategy) {
566 case EGL_NO_RESET_NOTIFICATION_KHR:
567 case EGL_LOSE_CONTEXT_ON_RESET_KHR:
568 break;
569
570 default:
571 err = EGL_BAD_ATTRIBUTE;
572 break;
573 }
574
575 /* The EGL_KHR_create_context_no_error spec says:
576 *
577 * "BAD_MATCH is generated if the EGL_CONTEXT_OPENGL_NO_ERROR_KHR is TRUE
578 * at the same time as a debug or robustness context is specified."
579 */
580 if (ctx->NoError &&
581 (ctx->Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR ||
582 ctx->Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) {
583 err = EGL_BAD_MATCH;
584 }
585
586 if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR |
587 EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR |
588 EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
589 err = EGL_BAD_ATTRIBUTE;
590 }
591
592 return err;
593 }
594
595 /**
596 * Initialize the given _EGLContext object to defaults and/or the values
597 * in the attrib_list.
598 *
599 * According to EGL 1.5 Section 3.7:
600 *
601 * "EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all
602 * purposes except eglCreateContext."
603 *
604 * And since we only support GL and GLES, this is the only place where the
605 * bound API matters at all. We look up the current API from the current
606 * thread, and stash that in the context we're initializing. Our caller is
607 * responsible for determining whether that's an API it supports.
608 */
609 EGLBoolean
_eglInitContext(_EGLContext * ctx,_EGLDisplay * disp,_EGLConfig * conf,_EGLContext * share_list,const EGLint * attrib_list)610 _eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, _EGLConfig *conf,
611 _EGLContext *share_list, const EGLint *attrib_list)
612 {
613 const EGLenum api = eglQueryAPI();
614 EGLint err;
615
616 if (api == EGL_NONE)
617 return _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
618
619 _eglInitResource(&ctx->Resource, sizeof(*ctx), disp);
620 ctx->ClientAPI = api;
621 ctx->Config = conf;
622 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
623
624 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
625 ctx->ClientMinorVersion = 0;
626 ctx->Flags = 0;
627 ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
628 ctx->ContextPriority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
629 ctx->ReleaseBehavior = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR;
630
631 err = _eglParseContextAttribList(ctx, disp, attrib_list);
632 if (err == EGL_SUCCESS && ctx->Config) {
633 EGLint api_bit;
634
635 api_bit = _eglGetContextAPIBit(ctx);
636 if (!(ctx->Config->RenderableType & api_bit)) {
637 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
638 api_bit, ctx->Config->RenderableType);
639 err = EGL_BAD_CONFIG;
640 }
641 }
642 if (err != EGL_SUCCESS)
643 return _eglError(err, "eglCreateContext");
644
645 /* The EGL_EXT_create_context_robustness spec says:
646 *
647 * "Add to the eglCreateContext context creation errors: [...]
648 *
649 * * If the reset notification behavior of <share_context> and the
650 * newly created context are different then an EGL_BAD_MATCH error is
651 * generated."
652 */
653 if (share_list && share_list->ResetNotificationStrategy !=
654 ctx->ResetNotificationStrategy) {
655 return _eglError(
656 EGL_BAD_MATCH,
657 "eglCreateContext() share list notification strategy mismatch");
658 }
659
660 /* The EGL_KHR_create_context_no_error spec says:
661 *
662 * "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
663 * used to create <share_context> does not match the value of
664 * EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
665 */
666 if (share_list && share_list->NoError != ctx->NoError) {
667 return _eglError(EGL_BAD_MATCH,
668 "eglCreateContext() share list no-error mismatch");
669 }
670
671 return EGL_TRUE;
672 }
673
674 static EGLint
_eglQueryContextRenderBuffer(_EGLContext * ctx)675 _eglQueryContextRenderBuffer(_EGLContext *ctx)
676 {
677 _EGLSurface *surf = ctx->DrawSurface;
678
679 /* From the EGL 1.5 spec:
680 *
681 * - If the context is not bound to a surface, then EGL_NONE will be
682 * returned.
683 */
684 if (!surf)
685 return EGL_NONE;
686
687 switch (surf->Type) {
688 default:
689 unreachable("bad EGLSurface type");
690 case EGL_PIXMAP_BIT:
691 /* - If the context is bound to a pixmap surface, then EGL_SINGLE_BUFFER
692 * will be returned.
693 */
694 return EGL_SINGLE_BUFFER;
695 case EGL_PBUFFER_BIT:
696 /* - If the context is bound to a pbuffer surface, then EGL_BACK_BUFFER
697 * will be returned.
698 */
699 return EGL_BACK_BUFFER;
700 case EGL_WINDOW_BIT:
701 /* - If the context is bound to a window surface, then either
702 * EGL_BACK_BUFFER or EGL_SINGLE_BUFFER may be returned. The value
703 * returned depends on both the buffer requested by the setting of the
704 * EGL_RENDER_BUFFER property of the surface [...], and on the client
705 * API (not all client APIs support single-buffer Rendering to window
706 * surfaces). Some client APIs allow control of whether rendering goes
707 * to the front or back buffer. This client API-specific choice is not
708 * reflected in the returned value, which only describes the buffer
709 * that will be rendered to by default if not overridden by the client
710 * API.
711 */
712 return surf->ActiveRenderBuffer;
713 }
714 }
715
716 EGLBoolean
_eglQueryContext(_EGLContext * c,EGLint attribute,EGLint * value)717 _eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
718 {
719 _EGLDisplay *disp = c->Resource.Display;
720
721 if (!value)
722 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
723
724 switch (attribute) {
725 case EGL_CONFIG_ID:
726 /*
727 * From EGL_KHR_no_config_context:
728 *
729 * "Querying EGL_CONFIG_ID returns the ID of the EGLConfig with
730 * respect to which the context was created, or zero if created
731 * without respect to an EGLConfig."
732 */
733 *value = c->Config ? c->Config->ConfigID : 0;
734 break;
735 case EGL_CONTEXT_CLIENT_VERSION:
736 *value = c->ClientMajorVersion;
737 break;
738 case EGL_CONTEXT_CLIENT_TYPE:
739 *value = c->ClientAPI;
740 break;
741 case EGL_RENDER_BUFFER:
742 *value = _eglQueryContextRenderBuffer(c);
743 break;
744 case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
745 *value = c->ContextPriority;
746 break;
747 case EGL_PROTECTED_CONTENT_EXT:
748 if (!disp->Extensions.EXT_protected_content)
749 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
750 *value = c->Protected;
751 break;
752 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
753 if (!disp->Extensions.EXT_query_reset_notification_strategy)
754 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
755 *value = c->ResetNotificationStrategy;
756 break;
757 default:
758 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
759 }
760
761 return EGL_TRUE;
762 }
763
764 /**
765 * Bind the context to the thread and return the previous context.
766 *
767 * Note that the context may be NULL.
768 */
769 _EGLContext *
_eglBindContextToThread(_EGLContext * ctx,_EGLThreadInfo * t)770 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
771 {
772 _EGLContext *oldCtx;
773
774 oldCtx = t->CurrentContext;
775 if (ctx != oldCtx) {
776 if (oldCtx)
777 oldCtx->Binding = NULL;
778 if (ctx)
779 ctx->Binding = t;
780
781 t->CurrentContext = ctx;
782 }
783
784 return oldCtx;
785 }
786
787 /**
788 * Return true if the given context and surfaces can be made current.
789 */
790 static EGLBoolean
_eglCheckMakeCurrent(_EGLContext * ctx,_EGLSurface * draw,_EGLSurface * read)791 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
792 {
793 _EGLThreadInfo *t = _eglGetCurrentThread();
794 _EGLDisplay *disp;
795
796 /* this is easy */
797 if (!ctx) {
798 if (draw || read)
799 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
800 return EGL_TRUE;
801 }
802
803 disp = ctx->Resource.Display;
804 if (!disp->Extensions.KHR_surfaceless_context &&
805 (draw == NULL || read == NULL))
806 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
807
808 /*
809 * The spec says
810 *
811 * "If ctx is current to some other thread, or if either draw or read are
812 * bound to contexts in another thread, an EGL_BAD_ACCESS error is
813 * generated."
814 *
815 * and
816 *
817 * "at most one context may be bound to a particular surface at a given
818 * time"
819 */
820 if (ctx->Binding && ctx->Binding != t)
821 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
822 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
823 if (draw->CurrentContext->Binding != t)
824 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
825 }
826 if (read && read->CurrentContext && read->CurrentContext != ctx) {
827 if (read->CurrentContext->Binding != t)
828 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
829 }
830
831 /* If the context has a config then it must match that of the two
832 * surfaces */
833 if (ctx->Config) {
834 if ((draw && draw->Config != ctx->Config) ||
835 (read && read->Config != ctx->Config))
836 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
837 } else {
838 /* Otherwise we must be using the EGL_KHR_no_config_context
839 * extension */
840 assert(disp->Extensions.KHR_no_config_context);
841 }
842
843 return EGL_TRUE;
844 }
845
846 /**
847 * Bind the context to the current thread and given surfaces. Return the
848 * previous bound context and surfaces. The caller should unreference the
849 * returned context and surfaces.
850 *
851 * Making a second call with the resources returned by the first call
852 * unsurprisingly undoes the first call, except for the resource reference
853 * counts.
854 */
855 EGLBoolean
_eglBindContext(_EGLContext * ctx,_EGLSurface * draw,_EGLSurface * read,_EGLContext ** old_ctx,_EGLSurface ** old_draw,_EGLSurface ** old_read)856 _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
857 _EGLContext **old_ctx, _EGLSurface **old_draw,
858 _EGLSurface **old_read)
859 {
860 _EGLThreadInfo *t = _eglGetCurrentThread();
861 _EGLContext *prev_ctx;
862 _EGLSurface *prev_draw, *prev_read;
863
864 if (!_eglCheckMakeCurrent(ctx, draw, read))
865 return EGL_FALSE;
866
867 /* increment refcounts before binding */
868 _eglGetContext(ctx);
869 _eglGetSurface(draw);
870 _eglGetSurface(read);
871
872 /* bind the new context */
873 prev_ctx = _eglBindContextToThread(ctx, t);
874
875 /* break previous bindings */
876 if (prev_ctx) {
877 prev_draw = prev_ctx->DrawSurface;
878 prev_read = prev_ctx->ReadSurface;
879
880 if (prev_draw)
881 prev_draw->CurrentContext = NULL;
882 if (prev_read)
883 prev_read->CurrentContext = NULL;
884
885 prev_ctx->DrawSurface = NULL;
886 prev_ctx->ReadSurface = NULL;
887 } else {
888 prev_draw = prev_read = NULL;
889 }
890
891 /* establish new bindings */
892 if (ctx) {
893 if (draw)
894 draw->CurrentContext = ctx;
895 if (read)
896 read->CurrentContext = ctx;
897
898 ctx->DrawSurface = draw;
899 ctx->ReadSurface = read;
900 }
901
902 assert(old_ctx && old_draw && old_read);
903 *old_ctx = prev_ctx;
904 *old_draw = prev_draw;
905 *old_read = prev_read;
906
907 return EGL_TRUE;
908 }
909