Fix bugs in 2D Array Texture support.

This fixes assertion failures and other errors, reproducible
by running the dEQP Texture Format tests.

BUG=angle:813

Change-Id: I3b97f89323f9656b45f617211fb4579a24013951
Reviewed-on: https://chromium-review.googlesource.com/229351
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
diff --git a/tests/angle_tests/TextureTest.cpp b/tests/angle_tests/TextureTest.cpp
index f227457..d2e08e0 100644
--- a/tests/angle_tests/TextureTest.cpp
+++ b/tests/angle_tests/TextureTest.cpp
@@ -112,6 +112,89 @@
     GLint mTextureScaleUniformLocation;
 };
 
+ANGLE_TYPED_TEST_CASE(TextureTestES3, ES3_D3D11);
+
+template<typename T>
+class TextureTestES3 : public TextureTest<T>
+{
+  protected:
+    virtual void SetUp()
+    {
+        TextureTest::SetUp();
+
+        glGenTextures(1, &mTextureArray);
+        EXPECT_GL_NO_ERROR();
+
+        ASSERT_GL_NO_ERROR();
+
+        const std::string vertexShaderSource = SHADER_SOURCE
+        (
+            #version 300 es\n
+            precision highp float;
+            in vec4 position;
+            out vec2 texcoord;
+
+            uniform vec2 textureScale;
+
+            void main()
+            {
+                gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
+                texcoord = (position.xy * 0.5) + 0.5;
+            }
+        );
+
+        const std::string fragmentShaderSourceArray = SHADER_SOURCE
+        (
+            #version 300 es\n
+            precision highp float;
+            uniform sampler2DArray tex;
+            uniform int slice;
+            in vec2 texcoord;
+            out vec4 out_FragColor;
+
+            void main()
+            {
+                out_FragColor = texture(tex, vec3(texcoord, float(slice)));
+            }
+        );
+
+        mArrayProgram = CompileProgram(vertexShaderSource, fragmentShaderSourceArray);
+        if (mArrayProgram == 0)
+        {
+            FAIL() << "shader compilation failed.";
+        }
+
+        mTextureArrayUniformLocation = glGetUniformLocation(mArrayProgram, "tex");
+        ASSERT_NE(-1, mTextureArrayUniformLocation);
+
+        mTextureArrayScaleUniformLocation = glGetUniformLocation(mArrayProgram, "textureScale");
+        ASSERT_NE(-1, mTextureArrayScaleUniformLocation);
+
+        mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
+        ASSERT_NE(-1, mTextureArraySliceUniformLocation);
+
+        glUseProgram(mArrayProgram);
+        glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
+        glUseProgram(0);
+        ASSERT_GL_NO_ERROR();
+    }
+
+    virtual void TearDown()
+    {
+        glDeleteTextures(1, &mTextureArray);
+        glDeleteProgram(mArrayProgram);
+
+        TextureTest::TearDown();
+    }
+
+    GLuint mTextureArray;
+
+    GLuint mArrayProgram;
+    GLint mTextureArrayUniformLocation;
+    GLint mTextureArrayScaleUniformLocation;
+    GLint mTextureArraySliceUniformLocation;
+};
+
 TYPED_TEST(TextureTest, NegativeAPISubImage)
 {
     glBindTexture(GL_TEXTURE_2D, mTexture2D);
@@ -224,3 +307,86 @@
     EXPECT_GL_NO_ERROR();
     EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
 }
+
+// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
+// Then tests if the mipmaps are rendered correctly for all three layers.
+TYPED_TEST(TextureTestES3, MipmapsForTextureArray)
+{
+    int px = getWindowWidth() / 2;
+    int py = getWindowHeight() / 2;
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
+
+    glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
+
+    // Fill the first layer with red
+    std::vector<GLubyte> pixels(4 * 16 * 16);
+    for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
+    {
+        pixels[pixelId * 4 + 0] = 255;
+        pixels[pixelId * 4 + 1] = 0;
+        pixels[pixelId * 4 + 2] = 0;
+        pixels[pixelId * 4 + 3] = 255;
+    }
+
+    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+
+    // Fill the second layer with green
+    for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
+    {
+        pixels[pixelId * 4 + 0] = 0;
+        pixels[pixelId * 4 + 1] = 255;
+        pixels[pixelId * 4 + 2] = 0;
+        pixels[pixelId * 4 + 3] = 255;
+    }
+
+    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+
+    // Fill the third layer with blue
+    for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
+    {
+        pixels[pixelId * 4 + 0] = 0;
+        pixels[pixelId * 4 + 1] = 0;
+        pixels[pixelId * 4 + 2] = 255;
+        pixels[pixelId * 4 + 3] = 255;
+    }
+
+    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+
+    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    EXPECT_GL_NO_ERROR();
+
+    glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+
+    EXPECT_GL_NO_ERROR();
+
+    glUseProgram(mArrayProgram);
+    glUniform1i(mTextureArrayUniformLocation, 0);
+    glUniform2f(mTextureScaleUniformLocation, 0.0625f, 0.0625f);
+
+    EXPECT_GL_NO_ERROR();
+
+    // Draw the first slice
+    glUseProgram(mArrayProgram);
+    glUniform1i(mTextureArraySliceUniformLocation, 0);
+    drawQuad(mArrayProgram, "position", 0.5f);
+    EXPECT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
+
+    // Draw the second slice
+    glUseProgram(mArrayProgram);
+    glUniform1i(mTextureArraySliceUniformLocation, 1);
+    drawQuad(mArrayProgram, "position", 0.5f);
+    EXPECT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
+
+    // Draw the third slice
+    glUseProgram(mArrayProgram);
+    glUniform1i(mTextureArraySliceUniformLocation, 2);
+    drawQuad(mArrayProgram, "position", 0.5f);
+    EXPECT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
+}