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