egl: deduplicate swap interval clamping logic
[mesa.git] / src / egl / main / eglsurface.c
index cc505045e12967a19faeacf2310638cdbdd0dda6..3bd14a8cd034e1c2d1583c4ef758cac6d65dafb1 100644 (file)
@@ -1,3 +1,33 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright 2010 LunarG, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
 /**
  * Surface-related functions.
  */
@@ -7,6 +37,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include "egldisplay.h"
+#include "egldriver.h"
 #include "eglcontext.h"
 #include "eglconfig.h"
 #include "eglcurrent.h"
 #include "eglsurface.h"
 
 
-static void
-_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
-{
-   EGLint bound = surf->Config->MaxSwapInterval;
-   if (interval >= bound) {
-      interval = bound;
-   }
-   else {
-      bound = surf->Config->MinSwapInterval;
-      if (interval < bound)
-         interval = bound;
-   }
-   surf->SwapInterval = interval;
-}
-
-
-#ifdef EGL_MESA_screen_surface
-static EGLint
-_eglParseScreenSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
-{
-   EGLint i, err = EGL_SUCCESS;
-
-   if (!attrib_list)
-      return EGL_SUCCESS;
-
-   for (i = 0; attrib_list[i] != EGL_NONE; i++) {
-      EGLint attr = attrib_list[i++];
-      EGLint val = attrib_list[i];
-
-      switch (attr) {
-      case EGL_WIDTH:
-         if (val < 0) {
-            err = EGL_BAD_PARAMETER;
-            break;
-         }
-         surf->Width = val;
-         break;
-      case EGL_HEIGHT:
-         if (val < 0) {
-            err = EGL_BAD_PARAMETER;
-            break;
-         }
-         surf->Height = val;
-         break;
-      default:
-         err = EGL_BAD_ATTRIBUTE;
-         break;
-      }
-
-      if (err != EGL_SUCCESS) {
-         _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
-         break;
-      }
-   }
-
-   return err;
-}
-#endif /* EGL_MESA_screen_surface */
-
-
 /**
  * Parse the list of surface attributes and return the proper error code.
  */
@@ -84,24 +55,37 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
    EGLint type = surf->Type;
    EGLint texture_type = EGL_PBUFFER_BIT;
    EGLint i, err = EGL_SUCCESS;
+   EGLint attr = EGL_NONE;
+   EGLint val = EGL_NONE;
 
    if (!attrib_list)
       return EGL_SUCCESS;
 
-#ifdef EGL_MESA_screen_surface
-   if (type == EGL_SCREEN_BIT_MESA)
-      return _eglParseScreenSurfaceAttribList(surf, attrib_list);
-#endif
-
    if (dpy->Extensions.NOK_texture_from_pixmap)
       texture_type |= EGL_PIXMAP_BIT;
 
    for (i = 0; attrib_list[i] != EGL_NONE; i++) {
-      EGLint attr = attrib_list[i++];
-      EGLint val = attrib_list[i];
+      attr = attrib_list[i++];
+      val = attrib_list[i];
 
       switch (attr) {
       /* common attributes */
+      case EGL_GL_COLORSPACE_KHR:
+         if (!dpy->Extensions.KHR_gl_colorspace) {
+            err = EGL_BAD_ATTRIBUTE;
+            break;
+         }
+         switch (val) {
+         case EGL_GL_COLORSPACE_SRGB_KHR:
+         case EGL_GL_COLORSPACE_LINEAR_KHR:
+            break;
+         default:
+            err = EGL_BAD_ATTRIBUTE;
+         }
+         if (err != EGL_SUCCESS)
+            break;
+         surf->GLColorspace = val;
+         break;
       case EGL_VG_COLORSPACE:
          switch (val) {
          case EGL_VG_COLORSPACE_sRGB:
@@ -140,6 +124,18 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
          }
          surf->RenderBuffer = val;
          break;
+      case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
+         if (!dpy->Extensions.NV_post_sub_buffer ||
+             type != EGL_WINDOW_BIT) {
+            err = EGL_BAD_ATTRIBUTE;
+            break;
+         }
+         if (val != EGL_TRUE && val != EGL_FALSE) {
+            err = EGL_BAD_PARAMETER;
+            break;
+         }
+         surf->PostSubBufferSupportedNV = val;
+         break;
       /* pbuffer surface attributes */
       case EGL_WIDTH:
          if (type != EGL_PBUFFER_BIT) {
@@ -176,6 +172,7 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
+
          switch (val) {
          case EGL_TEXTURE_RGB:
          case EGL_TEXTURE_RGBA:
@@ -194,6 +191,7 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
             err = EGL_BAD_ATTRIBUTE;
             break;
          }
+
          switch (val) {
          case EGL_TEXTURE_2D:
          case EGL_NO_TEXTURE:
@@ -219,12 +217,21 @@ _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
          break;
       }
 
-      if (err != EGL_SUCCESS) {
-         _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
+      if (err != EGL_SUCCESS)
          break;
+   }
+
+   if (err == EGL_SUCCESS && type == EGL_PBUFFER_BIT) {
+      if ((surf->TextureTarget == EGL_NO_TEXTURE && surf->TextureFormat != EGL_NO_TEXTURE) ||
+          (surf->TextureFormat == EGL_NO_TEXTURE && surf->TextureTarget != EGL_NO_TEXTURE)) {
+         attr = surf->TextureTarget == EGL_NO_TEXTURE ? EGL_TEXTURE_TARGET : EGL_TEXTURE_FORMAT;
+         err = EGL_BAD_MATCH;
       }
    }
 
+   if (err != EGL_SUCCESS)
+      _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
+
    return err;
 }
 
@@ -239,11 +246,17 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
 {
    const char *func;
    EGLint renderBuffer = EGL_BACK_BUFFER;
+   EGLint swapBehavior = EGL_BUFFER_DESTROYED;
    EGLint err;
 
+   /* Swap behavior can be preserved only if config supports this. */
+   if (conf->SurfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
+      swapBehavior = EGL_BUFFER_PRESERVED;
+
    switch (type) {
    case EGL_WINDOW_BIT:
       func = "eglCreateWindowSurface";
+      swapBehavior = EGL_BUFFER_DESTROYED;
       break;
    case EGL_PIXMAP_BIT:
       func = "eglCreatePixmapSurface";
@@ -252,26 +265,19 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
    case EGL_PBUFFER_BIT:
       func = "eglCreatePBufferSurface";
       break;
-#ifdef EGL_MESA_screen_surface
-   case EGL_SCREEN_BIT_MESA:
-      func = "eglCreateScreenSurface";
-      renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */
-      break;
-#endif
    default:
       _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
       return EGL_FALSE;
    }
 
-   if ((conf->SurfaceType & type) == 0) {
+   if ((conf->SurfaceType & type) == 0)
       /* The config can't be used to create a surface of this type */
-      _eglError(EGL_BAD_CONFIG, func);
-      return EGL_FALSE;
-   }
+      return _eglError(EGL_BAD_MATCH, func);
 
    _eglInitResource(&surf->Resource, sizeof(*surf), dpy);
    surf->Type = type;
    surf->Config = conf;
+   surf->Lost = EGL_FALSE;
 
    surf->Width = 0;
    surf->Height = 0;
@@ -282,22 +288,33 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
    surf->RenderBuffer = renderBuffer;
    surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
    surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
+   surf->GLColorspace = EGL_GL_COLORSPACE_LINEAR_KHR;
 
    surf->MipmapLevel = 0;
    surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
-   surf->SwapBehavior = EGL_BUFFER_DESTROYED;
+   surf->SwapBehavior = swapBehavior;
 
    surf->HorizontalResolution = EGL_UNKNOWN;
    surf->VerticalResolution = EGL_UNKNOWN;
    surf->AspectRatio = EGL_UNKNOWN;
 
+   surf->PostSubBufferSupportedNV = EGL_FALSE;
+   surf->SetDamageRegionCalled = EGL_FALSE;
+   surf->BufferAgeRead = EGL_FALSE;
+
    /* the default swap interval is 1 */
-   _eglClampSwapInterval(surf, 1);
+   surf->SwapInterval = 1;
 
    err = _eglParseSurfaceAttribList(surf, attrib_list);
    if (err != EGL_SUCCESS)
       return _eglError(err, func);
 
+   /* if EGL_LARGEST_PBUFFER in use, clamp width and height */
+   if (surf->LargestPbuffer) {
+      surf->Width = MIN2(surf->Width, _EGL_MAX_PBUFFER_WIDTH);
+      surf->Height = MIN2(surf->Height, _EGL_MAX_PBUFFER_HEIGHT);
+   }
+
    return EGL_TRUE;
 }
 
@@ -317,7 +334,8 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
       *value = surface->Config->ConfigID;
       break;
    case EGL_LARGEST_PBUFFER:
-      *value = surface->LargestPbuffer;
+      if (surface->Type == EGL_PBUFFER_BIT)
+         *value = surface->LargestPbuffer;
       break;
    case EGL_TEXTURE_FORMAT:
       /* texture attributes: only for pbuffers, no error otherwise */
@@ -360,9 +378,33 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
    case EGL_VG_COLORSPACE:
       *value = surface->VGColorspace;
       break;
+   case EGL_GL_COLORSPACE_KHR:
+      if (!dpy->Extensions.KHR_gl_colorspace)
+         return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
+
+      *value = surface->GLColorspace;
+      break;
+   case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
+      *value = surface->PostSubBufferSupportedNV;
+      break;
+   case EGL_BUFFER_AGE_EXT:
+      if (!dpy->Extensions.EXT_buffer_age)
+         return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
+
+      _EGLContext *ctx = _eglGetCurrentContext();
+      EGLint result = drv->API.QueryBufferAge(drv, dpy, surface);
+      /* error happened */
+      if (result < 0)
+         return EGL_FALSE;
+      if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+          ctx->DrawSurface != surface)
+         return _eglError(EGL_BAD_SURFACE, "eglQuerySurface");
+
+      *value = result;
+      surface->BufferAgeRead = EGL_TRUE;
+      break;
    default:
-      _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
-      return EGL_FALSE;
+      return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
    }
 
    return EGL_TRUE;
@@ -378,11 +420,14 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
 {
    EGLint confval;
    EGLint err = EGL_SUCCESS;
+   EGLint all_es_bits = EGL_OPENGL_ES_BIT |
+                        EGL_OPENGL_ES2_BIT |
+                        EGL_OPENGL_ES3_BIT_KHR;
 
    switch (attribute) {
    case EGL_MIPMAP_LEVEL:
       confval = surface->Config->RenderableType;
-      if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
+      if (!(confval & all_es_bits)) {
          err = EGL_BAD_PARAMETER;
          break;
       }
@@ -446,36 +491,63 @@ _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
    if (dpy->Extensions.NOK_texture_from_pixmap)
       texture_type |= EGL_PIXMAP_BIT;
 
-   if (!(surface->Type & texture_type)) {
-      _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
-      return EGL_FALSE;
-   }
+   if (!(surface->Type & texture_type))
+      return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
 
-   if (surface->TextureFormat == EGL_NO_TEXTURE) {
-      _eglError(EGL_BAD_MATCH, "eglBindTexImage");
-      return EGL_FALSE;
-   }
+   if (surface->TextureFormat == EGL_NO_TEXTURE)
+      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
 
-   if (surface->TextureTarget == EGL_NO_TEXTURE) {
-      _eglError(EGL_BAD_MATCH, "eglBindTexImage");
-      return EGL_FALSE;
-   }
+   if (surface->TextureTarget == EGL_NO_TEXTURE)
+      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
 
-   if (buffer != EGL_BACK_BUFFER) {
-      _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
-      return EGL_FALSE;
-   }
+   if (buffer != EGL_BACK_BUFFER)
+      return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
 
    surface->BoundToTexture = EGL_TRUE;
 
    return EGL_TRUE;
 }
 
+EGLBoolean
+_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
+                    EGLint buffer)
+{
+   /* Just do basic error checking and return success/fail.
+    * Drivers must implement the real stuff.
+    */
+
+   EGLint texture_type = EGL_PBUFFER_BIT;
+
+   if (surf == EGL_NO_SURFACE)
+      return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
+
+   if (!surf->BoundToTexture)
+   {
+      /* Not an error, simply nothing to do */
+      return EGL_TRUE;
+   }
+
+   if (surf->TextureFormat == EGL_NO_TEXTURE)
+      return _eglError(EGL_BAD_MATCH, "eglReleaseTexImage");
+
+   if (buffer != EGL_BACK_BUFFER)
+      return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
+
+   if (dpy->Extensions.NOK_texture_from_pixmap)
+      texture_type |= EGL_PIXMAP_BIT;
+
+   if (!(surf->Type & texture_type))
+      return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
+
+   surf->BoundToTexture = EGL_FALSE;
+
+   return EGL_TRUE;
+}
+
 
 EGLBoolean
 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
                  EGLint interval)
 {
-   _eglClampSwapInterval(surf, interval);
    return EGL_TRUE;
 }