Move more draw call validation to the API.

The GL expects us to reject invalid draw calls before we start
doing any work, so we can prevent internal unnecessary state
changes.

Also update the program binary's cached sampler data when we
validate. The previous patch was breaking draw calls in Google
Earth WebGL.

BUG=angle:571
BUG=390412

Change-Id: I1c4e204ae2467afc36b76af975a3a49e26349639
Reviewed-on: https://chromium-review.googlesource.com/206482
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/tests/angle_tests/TextureTest.cpp b/tests/angle_tests/TextureTest.cpp
index f5fff41..0fb046c 100644
--- a/tests/angle_tests/TextureTest.cpp
+++ b/tests/angle_tests/TextureTest.cpp
@@ -16,12 +16,17 @@
     virtual void SetUp()
     {
         ANGLETest::SetUp();
-        glGenTextures(1, &mTexture);
+        glGenTextures(1, &mTexture2D);
+        glGenTextures(1, &mTextureCube);
 
-        glBindTexture(GL_TEXTURE_2D, mTexture);
+        glBindTexture(GL_TEXTURE_2D, mTexture2D);
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
         EXPECT_GL_NO_ERROR();
 
+        glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
+        glTexStorage2DEXT(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, 1, 1);
+        EXPECT_GL_NO_ERROR();
+
         ASSERT_GL_NO_ERROR();
 
         const std::string vertexShaderSource = SHADER_SOURCE
@@ -37,7 +42,7 @@
             }
         );
 
-        const std::string fragmentShaderSource = SHADER_SOURCE
+        const std::string fragmentShaderSource2D = SHADER_SOURCE
         (
             precision highp float;
             uniform sampler2D tex;
@@ -49,32 +54,51 @@
             }
         );
 
-        mProgram = compileProgram(vertexShaderSource, fragmentShaderSource);
-        if (mProgram == 0)
+        const std::string fragmentShaderSourceCube = SHADER_SOURCE
+        (
+            precision highp float;
+            uniform sampler2D tex2D;
+            uniform samplerCube texCube;
+            varying vec2 texcoord;
+
+            void main()
+            {
+                gl_FragColor = texture2D(tex2D, texcoord);
+                gl_FragColor += textureCube(texCube, vec3(texcoord, 0));
+            }
+        );
+
+        m2DProgram = compileProgram(vertexShaderSource, fragmentShaderSource2D);
+        mCubeProgram = compileProgram(vertexShaderSource, fragmentShaderSourceCube);
+        if (m2DProgram == 0 || mCubeProgram == 0)
         {
             FAIL() << "shader compilation failed.";
         }
 
-        mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
+        mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
     }
 
     virtual void TearDown()
     {
-        glDeleteTextures(1, &mTexture);
-        glDeleteProgram(mProgram);
+        glDeleteTextures(1, &mTexture2D);
+        glDeleteTextures(1, &mTextureCube);
+        glDeleteProgram(m2DProgram);
+        glDeleteProgram(mCubeProgram);
 
         ANGLETest::TearDown();
     }
 
-    GLuint mTexture;
+    GLuint mTexture2D;
+    GLuint mTextureCube;
 
-    GLuint mProgram;
-    GLint mTextureUniformLocation;
+    GLuint m2DProgram;
+    GLuint mCubeProgram;
+    GLint mTexture2DUniformLocation;
 };
 
 TEST_F(TextureTest, negative_api_subimage)
 {
-    glBindTexture(GL_TEXTURE_2D, mTexture);
+    glBindTexture(GL_TEXTURE_2D, mTexture2D);
     EXPECT_GL_ERROR(GL_NO_ERROR);
 
     const GLubyte *pixels[20] = { 0 };
@@ -84,13 +108,13 @@
 
 TEST_F(TextureTest, zero_sized_uploads)
 {
-    glBindTexture(GL_TEXTURE_2D, mTexture);
+    glBindTexture(GL_TEXTURE_2D, mTexture2D);
     EXPECT_GL_ERROR(GL_NO_ERROR);
 
     // Use the texture first to make sure it's in video memory
-    glUseProgram(mProgram);
-    glUniform1i(mTextureUniformLocation, 0);
-    drawQuad(mProgram, "position", 0.5f);
+    glUseProgram(m2DProgram);
+    glUniform1i(mTexture2DUniformLocation, 0);
+    drawQuad(m2DProgram, "position", 0.5f);
 
     const GLubyte *pixel[4] = { 0 };
 
@@ -103,3 +127,23 @@
     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
     EXPECT_GL_NO_ERROR();
 }
+
+// Test drawing with two texture types, to trigger an ANGLE bug in validation
+TEST_F(TextureTest, cube_map_bug)
+{
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mTexture2D);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
+    EXPECT_GL_ERROR(GL_NO_ERROR);
+
+    glUseProgram(mCubeProgram);
+    GLint tex2DUniformLocation = glGetUniformLocation(mCubeProgram, "tex2D");
+    GLint texCubeUniformLocation = glGetUniformLocation(mCubeProgram, "texCube");
+    EXPECT_NE(-1, tex2DUniformLocation);
+    EXPECT_NE(-1, texCubeUniformLocation);
+    glUniform1i(tex2DUniformLocation, 0);
+    glUniform1i(texCubeUniformLocation, 1);
+    drawQuad(mCubeProgram, "position", 0.5f);
+    EXPECT_GL_NO_ERROR();
+}