egl: drop unused _EGLDriver & _EGLDisplay from _eglQueryContext()
[mesa.git] / src / egl / main / eglcontext.c
index ebc004d8cf2b839122c452a2a918d7aea8284fdd..65dc886abbb0fc53ac95090cd6a358e6e97ddac4 100644 (file)
@@ -37,6 +37,7 @@
 #include "eglcurrent.h"
 #include "eglsurface.h"
 #include "egllog.h"
+#include "util/macros.h"
 
 
 /**
@@ -81,7 +82,7 @@ _eglGetContextAPIBit(_EGLContext *ctx)
  * Parse the list of context attributes and return the proper error code.
  */
 static EGLint
-_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
+_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *disp,
                            const EGLint *attrib_list)
 {
    EGLenum api = ctx->ClientAPI;
@@ -118,7 +119,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
           *      generate an error."
           */
          if ((api != EGL_OPENGL_ES_API &&
-             (!dpy->Extensions.KHR_create_context || api != EGL_OPENGL_API))) {
+             (!disp->Extensions.KHR_create_context || api != EGL_OPENGL_API))) {
                err = EGL_BAD_ATTRIBUTE;
                break;
          }
@@ -135,7 +136,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
           *      contexts, and specifying them for other types of contexts will
           *      generate an error."
           */
-         if (!dpy->Extensions.KHR_create_context ||
+         if (!disp->Extensions.KHR_create_context ||
              (api != EGL_OPENGL_ES_API && api != EGL_OPENGL_API)) {
             err = EGL_BAD_ATTRIBUTE;
             break;
@@ -145,7 +146,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_FLAGS_KHR:
-         if (!dpy->Extensions.KHR_create_context) {
+         if (!disp->Extensions.KHR_create_context) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -177,26 +178,43 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
           *     is supported for OpenGL contexts, and requesting a
           *     forward-compatible context for OpenGL versions less than 3.0
           *     will generate an error."
+          *
+          * Note: since the forward-compatible flag can be set more than one way,
+          *       the OpenGL version check is performed once, below.
           */
          if ((val & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) &&
-             (api != EGL_OPENGL_API || ctx->ClientMajorVersion < 3)) {
+              api != EGL_OPENGL_API) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
 
-         /* The EGL_KHR_create_context_spec says:
-          *
-          *     "If the EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR bit is set in
-          *     EGL_CONTEXT_FLAGS_KHR, then a context supporting <robust buffer
-          *     access> will be created. Robust buffer access is defined in the
-          *     GL_ARB_robustness extension specification, and the resulting
-          *     context must also support either the GL_ARB_robustness
-          *     extension, or a version of OpenGL incorporating equivalent
-          *     functionality. This bit is supported for OpenGL contexts.
-          */
          if ((val & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) &&
-             (api != EGL_OPENGL_API ||
-              !dpy->Extensions.EXT_create_context_robustness)) {
+             api != EGL_OPENGL_API) {
+            /* The EGL_KHR_create_context spec says:
+             *
+             *   10) Which error should be generated if robust buffer access
+             *       or reset notifications are requested under OpenGL ES?
+             *
+             *       As per Issue 6, this extension does not support creating
+             *       robust contexts for OpenGL ES. This is only supported via
+             *       the EGL_EXT_create_context_robustness extension.
+             *
+             *       Attempting to use this extension to create robust OpenGL
+             *       ES context will generate an EGL_BAD_ATTRIBUTE error. This
+             *       specific error is generated because this extension does
+             *       not define the EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR
+             *       and EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR
+             *       bits for OpenGL ES contexts. Thus, use of these bits fall
+             *       under condition described by: "If an attribute is
+             *       specified that is not meaningful for the client API
+             *       type.." in the above specification.
+             *
+             * The spec requires that we emit the error even if the display
+             * supports EGL_EXT_create_context_robustness. To create a robust
+             * GLES context, the *attribute*
+             * EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT must be used, not the
+             * *flag* EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR.
+             */
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -205,7 +223,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
-         if (!dpy->Extensions.KHR_create_context) {
+         if (!disp->Extensions.KHR_create_context) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -232,9 +250,17 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
           *     meaningful for OpenGL contexts, and specifying it for other
           *     types of contexts, including OpenGL ES contexts, will generate
           *     an error."
+          *
+          * EGL 1.5 defines EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
+          * (without a suffix) which has the same value as the KHR token,
+          * and specifies that it now works with both GL and ES contexts:
+          *
+          *    "This attribute is supported only for OpenGL and OpenGL ES
+          *     contexts."
           */
-           if (!dpy->Extensions.KHR_create_context
-               || api != EGL_OPENGL_API) {
+           if (!(disp->Extensions.KHR_create_context && api == EGL_OPENGL_API)
+               && !(disp->Version >= 15 && (api == EGL_OPENGL_API ||
+                                            api == EGL_OPENGL_ES_API))) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -249,7 +275,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
           *     meaningful for OpenGL ES contexts, and specifying it for other
           *     types of contexts will generate an EGL_BAD_ATTRIBUTE error."
           */
-         if (!dpy->Extensions.EXT_create_context_robustness
+         if (!disp->Extensions.EXT_create_context_robustness
              || api != EGL_OPENGL_ES_API) {
             err = EGL_BAD_ATTRIBUTE;
             break;
@@ -259,7 +285,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
-         if (!dpy->Extensions.EXT_create_context_robustness) {
+         if (!disp->Extensions.EXT_create_context_robustness) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -269,7 +295,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_OPENGL_ROBUST_ACCESS:
-         if (dpy->Version < 15) {
+         if (disp->Version < 15) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -279,7 +305,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_OPENGL_DEBUG:
-         if (dpy->Version < 15) {
+         if (disp->Version < 15) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -289,7 +315,7 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
          break;
 
       case EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE:
-         if (dpy->Version < 15) {
+         if (disp->Version < 15) {
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
@@ -298,6 +324,89 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
             ctx->Flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
          break;
 
+      case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
+         if (disp->Version < 14 ||
+             !disp->Extensions.KHR_create_context_no_error) {
+            err = EGL_BAD_ATTRIBUTE;
+            break;
+         }
+
+         /* The KHR_no_error spec only applies against OpenGL 2.0+ and
+          * OpenGL ES 2.0+
+          */
+         if ((api != EGL_OPENGL_API && api != EGL_OPENGL_ES_API) ||
+             ctx->ClientMajorVersion < 2) {
+            err = EGL_BAD_ATTRIBUTE;
+            break;
+         }
+
+         /* Canonicalize value to EGL_TRUE/EGL_FALSE definitions */
+         ctx->NoError = !!val;
+         break;
+
+      case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
+         /* The  EGL_IMG_context_priority spec says:
+          *
+          * "EGL_CONTEXT_PRIORITY_LEVEL_IMG determines the priority level of
+          * the context to be created. This attribute is a hint, as an
+          * implementation may not support multiple contexts at some
+          * priority levels and system policy may limit access to high
+          * priority contexts to appropriate system privilege level. The
+          * default value for EGL_CONTEXT_PRIORITY_LEVEL_IMG is
+          * EGL_CONTEXT_PRIORITY_MEDIUM_IMG."
+          */
+         {
+            int bit;
+
+            switch (val) {
+            case EGL_CONTEXT_PRIORITY_HIGH_IMG:
+               bit = __EGL_CONTEXT_PRIORITY_HIGH_BIT;
+               break;
+            case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
+               bit = __EGL_CONTEXT_PRIORITY_MEDIUM_BIT;
+               break;
+            case EGL_CONTEXT_PRIORITY_LOW_IMG:
+               bit = __EGL_CONTEXT_PRIORITY_LOW_BIT;
+               break;
+            default:
+               bit = -1;
+               break;
+            }
+
+            if (bit < 0) {
+               err = EGL_BAD_ATTRIBUTE;
+               break;
+            }
+
+            /* "This extension allows an EGLContext to be created with a
+             * priority hint. It is possible that an implementation will not
+             * honour the hint, especially if there are constraints on the
+             * number of high priority contexts available in the system, or
+             * system policy limits access to high priority contexts to
+             * appropriate system privilege level. A query is provided to find
+             * the real priority level assigned to the context after creation."
+             *
+             * We currently assume that the driver applies the priority hint
+             * and filters out any it cannot handle during the screen setup,
+             * e.g. dri2_setup_screen(). As such we can mask any change that
+             * the driver would fail, and ctx->ContextPriority matches the
+             * hint applied to the driver/hardware backend.
+             */
+            if (disp->Extensions.IMG_context_priority & (1 << bit))
+               ctx->ContextPriority = val;
+
+            break;
+         }
+
+      case EGL_CONTEXT_RELEASE_BEHAVIOR_KHR:
+         if (val == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR ||
+             val == EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR) {
+            ctx->ReleaseBehavior = val;
+         } else {
+            err = EGL_BAD_ATTRIBUTE;
+         }
+         break;
+
       default:
          err = EGL_BAD_ATTRIBUTE;
          break;
@@ -444,6 +553,16 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
       break;
    }
 
+   /* The EGL_KHR_create_context_no_error spec says:
+    *
+    *    "BAD_MATCH is generated if the EGL_CONTEXT_OPENGL_NO_ERROR_KHR is TRUE at
+    *    the same time as a debug or robustness context is specified."
+    */
+   if (ctx->NoError && (ctx->Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR ||
+                        ctx->Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) {
+      err = EGL_BAD_MATCH;
+   }
+
    if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
                       | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
                       | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
@@ -457,32 +576,40 @@ _eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
 /**
  * Initialize the given _EGLContext object to defaults and/or the values
  * in the attrib_list.
+ *
+ * According to EGL 1.5 Section 3.7:
+ *
+ *     "EGL_OPENGL_API and EGL_OPENGL_ES_API are interchangeable for all
+ *     purposes except eglCreateContext."
+ *
+ * And since we only support GL and GLES, this is the only place where the
+ * bound API matters at all. We look up the current API from the current
+ * thread, and stash that in the context we're initializing. Our caller is
+ * responsible for determining whether that's an API it supports.
  */
 EGLBoolean
-_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
+_eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, _EGLConfig *conf,
                 const EGLint *attrib_list)
 {
    const EGLenum api = eglQueryAPI();
    EGLint err;
 
-   if (api == EGL_NONE) {
-      _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
-      return EGL_FALSE;
-   }
+   if (api == EGL_NONE)
+      return _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
 
-   _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
+   _eglInitResource(&ctx->Resource, sizeof(*ctx), disp);
    ctx->ClientAPI = api;
    ctx->Config = conf;
-   ctx->WindowRenderBuffer = EGL_NONE;
    ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
 
    ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
    ctx->ClientMinorVersion = 0;
    ctx->Flags = 0;
-   ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
    ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
+   ctx->ContextPriority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
+   ctx->ReleaseBehavior = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR;
 
-   err = _eglParseContextAttribList(ctx, dpy, attrib_list);
+   err = _eglParseContextAttribList(ctx, disp, attrib_list);
    if (err == EGL_SUCCESS && ctx->Config) {
       EGLint api_bit;
 
@@ -504,33 +631,61 @@ static EGLint
 _eglQueryContextRenderBuffer(_EGLContext *ctx)
 {
    _EGLSurface *surf = ctx->DrawSurface;
-   EGLint rb;
 
+   /* From the EGL 1.5 spec:
+    *
+    *    - If the context is not bound to a surface, then EGL_NONE will be
+    *      returned.
+    */
    if (!surf)
       return EGL_NONE;
-   if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
-      rb = ctx->WindowRenderBuffer;
-   else
-      rb = surf->RenderBuffer;
-   return rb;
+
+   switch (surf->Type) {
+   default:
+      unreachable("bad EGLSurface type");
+   case EGL_PIXMAP_BIT:
+      /* - If the context is bound to a pixmap surface, then EGL_SINGLE_BUFFER
+       *   will be returned.
+       */
+      return EGL_SINGLE_BUFFER;
+   case EGL_PBUFFER_BIT:
+      /* - If the context is bound to a pbuffer surface, then EGL_BACK_BUFFER
+       *   will be returned.
+       */
+      return EGL_BACK_BUFFER;
+   case EGL_WINDOW_BIT:
+      /* - If the context is bound to a window surface, then either
+       *   EGL_BACK_BUFFER or EGL_SINGLE_BUFFER may be returned. The value
+       *   returned depends on both the buffer requested by the setting of the
+       *   EGL_RENDER_BUFFER property of the surface [...], and on the client
+       *   API (not all client APIs support single-buffer Rendering to window
+       *   surfaces). Some client APIs allow control of whether rendering goes
+       *   to the front or back buffer. This client API-specific choice is not
+       *   reflected in the returned value, which only describes the buffer
+       *   that will be rendered to by default if not overridden by the client
+       *   API.
+       */
+      return surf->ActiveRenderBuffer;
+   }
 }
 
 
 EGLBoolean
-_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
-                 EGLint attribute, EGLint *value)
+_eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value)
 {
-   (void) drv;
-   (void) dpy;
-
    if (!value)
       return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
 
    switch (attribute) {
    case EGL_CONFIG_ID:
-      if (!c->Config)
-         return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
-      *value = c->Config->ConfigID;
+      /*
+       * From EGL_KHR_no_config_context:
+       *
+       *    "Querying EGL_CONFIG_ID returns the ID of the EGLConfig with
+       *     respect to which the context was created, or zero if created
+       *     without respect to an EGLConfig."
+       */
+      *value = c->Config ? c->Config->ConfigID : 0;
       break;
    case EGL_CONTEXT_CLIENT_VERSION:
       *value = c->ClientMajorVersion;
@@ -541,6 +696,9 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
    case EGL_RENDER_BUFFER:
       *value = _eglQueryContextRenderBuffer(c);
       break;
+   case EGL_CONTEXT_PRIORITY_LEVEL_IMG:
+      *value = c->ContextPriority;
+      break;
    default:
       return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
    }
@@ -554,7 +712,7 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
  *
  * Note that the context may be NULL.
  */
-static _EGLContext *
+_EGLContext *
 _eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
 {
    _EGLContext *oldCtx;
@@ -580,7 +738,7 @@ static EGLBoolean
 _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
 {
    _EGLThreadInfo *t = _eglGetCurrentThread();
-   _EGLDisplay *dpy;
+   _EGLDisplay *disp;
 
    if (_eglIsCurrentThreadDummy())
       return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
@@ -592,8 +750,8 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
       return EGL_TRUE;
    }
 
-   dpy = ctx->Resource.Display;
-   if (!dpy->Extensions.KHR_surfaceless_context
+   disp = ctx->Resource.Display;
+   if (!disp->Extensions.KHR_surfaceless_context
        && (draw == NULL || read == NULL))
       return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
 
@@ -627,9 +785,9 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
           (read && read->Config != ctx->Config))
          return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
    } else {
-      /* Otherwise we must be using the EGL_MESA_configless_context
+      /* Otherwise we must be using the EGL_KHR_no_config_context
        * extension */
-      assert(dpy->Extensions.MESA_configless_context);
+      assert(disp->Extensions.KHR_no_config_context);
 
       /* The extension doesn't permit binding draw and read buffers with
        * differing contexts */