Update the texture storage after generateMipmaps and setStorage.

Also adds a few assert in SetData and various places to ensure that
images are not dirty before modifying the storage.

BUG=angle:873

Change-Id: I7cc922b33da0d79a1b5aefe216e9ccfaaf86a306
Reviewed-on: https://chromium-review.googlesource.com/241880
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Gregoire Payen de La Garanderie <Gregory.Payen@imgtec.com>
diff --git a/tests/angle_tests/TextureTest.cpp b/tests/angle_tests/TextureTest.cpp
index ee93170..1a496d3 100644
--- a/tests/angle_tests/TextureTest.cpp
+++ b/tests/angle_tests/TextureTest.cpp
@@ -242,3 +242,95 @@
 
     EXPECT_GL_NO_ERROR();
 }
+
+// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a default color.
+TYPED_TEST(TextureTest, TexStorage)
+{
+    int width = getWindowWidth();
+    int height = getWindowHeight();
+
+    GLuint tex2D;
+    glGenTextures(1, &tex2D);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, tex2D);
+
+    // Fill with red
+    std::vector<GLubyte> pixels(3 * 16 * 16);
+    for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
+    {
+        pixels[pixelId * 3 + 0] = 255;
+        pixels[pixelId * 3 + 1] = 0;
+        pixels[pixelId * 3 + 2] = 0;
+    }
+
+    // ANGLE internally uses RGBA as the DirectX format for RGB images
+    // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
+    // The data is kept in a CPU-side image and the image is marked as dirty.
+    glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
+
+    // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
+    // glTexSubImage2D should take into account that the image is dirty.
+    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    glUseProgram(m2DProgram);
+    glUniform1i(mTexture2DUniformLocation, 0);
+    glUniform2f(mTextureScaleUniformLocation, 1.f, 1.f);
+    drawQuad(m2DProgram, "position", 0.5f);
+    glDeleteTextures(1, &tex2D);
+    EXPECT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(3*width/4, 3*height/4, 0, 0, 0, 255);
+    EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
+}
+
+// Test that glTexSubImage2D combined with a PBO works properly when glTexStorage2DEXT has initialized the image with a default color.
+TYPED_TEST(TextureTest, TexStorageWithPBO)
+{
+    if (extensionEnabled("NV_pixel_buffer_object"))
+    {
+        int width = getWindowWidth();
+        int height = getWindowHeight();
+
+        GLuint tex2D;
+        glGenTextures(1, &tex2D);
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, tex2D);
+
+        // Fill with red
+        std::vector<GLubyte> pixels(3 * 16 * 16);
+        for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
+        {
+            pixels[pixelId * 3 + 0] = 255;
+            pixels[pixelId * 3 + 1] = 0;
+            pixels[pixelId * 3 + 2] = 0;
+        }
+
+        // Read 16x16 region from red backbuffer to PBO
+        GLuint pbo;
+        glGenBuffers(1, &pbo);
+        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+        glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * 16 * 16, pixels.data(), GL_STATIC_DRAW);
+
+        // ANGLE internally uses RGBA as the DirectX format for RGB images
+        // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
+        // The data is kept in a CPU-side image and the image is marked as dirty.
+        glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
+
+        // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
+        // glTexSubImage2D should take into account that the image is dirty.
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        glUseProgram(m2DProgram);
+        glUniform1i(mTexture2DUniformLocation, 0);
+        glUniform2f(mTextureScaleUniformLocation, 1.f, 1.f);
+        drawQuad(m2DProgram, "position", 0.5f);
+        glDeleteTextures(1, &tex2D);
+        glDeleteTextures(1, &pbo);
+        EXPECT_GL_NO_ERROR();
+        EXPECT_PIXEL_EQ(3 * width / 4, 3 * height / 4, 0, 0, 0, 255);
+        EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
+    }
+}