Add texture rectangle extension.

This is needed to support binding IOSurfaces to textures on OSX. This
commit adds support in the API and tests, but didn't need to implement
compiler changes as it already supported ARB_texture_rectangle.

Implementation of CHROMIUM_opy_texture for rectangle texture and the
spec are left for follow-up commits.

Change-Id: I45c66be763a9d3f6f619640f9f95f39b05c70867
Reviewed-on: https://chromium-review.googlesource.com/559106
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index c98e52a..2810c11 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -314,8 +314,9 @@
         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             return textureType == GL_TEXTURE_CUBE_MAP;
 
-        // TODO(geofflang): accept GL_TEXTURE_RECTANGLE_ARB if the texture_rectangle extension is
-        // supported
+        case GL_TEXTURE_RECTANGLE_ANGLE:
+            return textureType == GL_TEXTURE_RECTANGLE_ANGLE &&
+                   context->getExtensions().textureRectangle;
 
         default:
             return false;
@@ -328,9 +329,8 @@
     {
         case GL_TEXTURE_2D:
             return true;
-
-        // TODO(geofflang): accept GL_TEXTURE_RECTANGLE_ARB if the texture_rectangle extension is
-        // supported
+        case GL_TEXTURE_RECTANGLE_ANGLE:
+            return context->getExtensions().textureRectangle;
 
         // TODO(geofflang): accept GL_TEXTURE_EXTERNAL_OES if the texture_external extension is
         // supported
@@ -375,6 +375,15 @@
             return false;
         }
     }
+    else if (target == GL_TEXTURE_RECTANGLE_ANGLE)
+    {
+        ASSERT(level == 0);
+        if (static_cast<GLuint>(width) > caps.maxRectangleTextureSize ||
+            static_cast<GLuint>(height) > caps.maxRectangleTextureSize)
+        {
+            return false;
+        }
+    }
     else if (IsCubeMapTextureTarget(target))
     {
         if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level) ||
@@ -1002,6 +1011,22 @@
             return false;
         }
     }
+    else if (target == GL_TEXTURE_RECTANGLE_ANGLE)
+    {
+        ASSERT(level == 0);
+        if (static_cast<GLuint>(width) > caps.maxRectangleTextureSize ||
+            static_cast<GLuint>(height) > caps.maxRectangleTextureSize)
+        {
+            context->handleError(InvalidValue());
+            return false;
+        }
+        if (isCompressed)
+        {
+            context->handleError(InvalidEnum()
+                                 << "Rectangle texture cannot have a compressed format.");
+            return false;
+        }
+    }
     else if (IsCubeMapTextureTarget(target))
     {
         if (!isSubImage && width != height)
@@ -1480,7 +1505,8 @@
                                      GLsizei width,
                                      GLsizei height)
 {
-    if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
+    if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP &&
+        target != GL_TEXTURE_RECTANGLE_ANGLE)
     {
         context->handleError(InvalidEnum());
         return false;
@@ -1523,6 +1549,20 @@
                 return false;
             }
             break;
+        case GL_TEXTURE_RECTANGLE_ANGLE:
+            if (static_cast<GLuint>(width) > caps.maxRectangleTextureSize ||
+                static_cast<GLuint>(height) > caps.maxRectangleTextureSize || levels != 1)
+            {
+                context->handleError(InvalidValue());
+                return false;
+            }
+            if (formatInfo.compressed)
+            {
+                context->handleError(InvalidEnum()
+                                     << "Rectangle texture cannot have a compressed format.");
+                return false;
+            }
+            break;
         case GL_TEXTURE_CUBE_MAP:
             if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize ||
                 static_cast<GLuint>(height) > caps.maxCubeMapTextureSize)
@@ -2601,6 +2641,12 @@
         return false;
     }
 
+    if (target == GL_TEXTURE_RECTANGLE_ANGLE)
+    {
+        context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format.");
+        return false;
+    }
+
     return true;
 }
 
@@ -2796,6 +2842,15 @@
         case GL_TEXTURE_CUBE_MAP:
             break;
 
+        case GL_TEXTURE_RECTANGLE_ANGLE:
+            if (!context->getExtensions().textureRectangle)
+            {
+                context->handleError(InvalidEnum()
+                                     << "Context does not support GL_ANGLE_texture_rectangle");
+                return false;
+            }
+            break;
+
         case GL_TEXTURE_3D:
         case GL_TEXTURE_2D_ARRAY:
             if (context->getClientMajorVersion() < 3)
@@ -5807,6 +5862,22 @@
             }
             break;
 
+            case GL_TEXTURE_RECTANGLE_ANGLE:
+            {
+                if (level != 0)
+                {
+                    context->handleError(InvalidValue());
+                    return false;
+                }
+                if (tex->getTarget() != GL_TEXTURE_RECTANGLE_ANGLE)
+                {
+                    context->handleError(InvalidOperation()
+                                         << "Textarget must match the texture target type.");
+                    return false;
+                }
+            }
+            break;
+
             case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
             case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
             case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -5954,7 +6025,8 @@
         (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
          !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
     {
-        ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
+        ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ANGLE ||
+               target == GL_TEXTURE_CUBE_MAP);
         ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotPow2);
         return false;
     }