• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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