Implement robust initialization for image texture

This change fixes a bug that the image texture initialization time is not
correct. It happens when we use compute shader to write data to an
uninitialized texture, then use readPixels to read the result which
results that texture initialization falls behind image store and
covers the real result.

Bug: angleproject:2766

Change-Id: I4e986972096857afc975c40dfa4d559a2f31194c
Reviewed-on: https://chromium-review.googlesource.com/1170569
Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 834f737..bd05861 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -770,10 +770,11 @@
 }
 
 // ImageBinding implementation.
-ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0)
+ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0), unreferenced(false)
 {
 }
-ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
+ImageBinding::ImageBinding(GLuint imageUnit, size_t count, bool unreferenced)
+    : unreferenced(unreferenced)
 {
     for (size_t index = 0; index < count; ++index)
     {
@@ -861,6 +862,17 @@
     return uniformIndex - mSamplerUniformRange.low();
 }
 
+bool ProgramState::isImageUniformIndex(GLuint index) const
+{
+    return mImageUniformRange.contains(index);
+}
+
+GLuint ProgramState::getImageIndexFromUniformIndex(GLuint uniformIndex) const
+{
+    ASSERT(isImageUniformIndex(uniformIndex));
+    return uniformIndex - mImageUniformRange.low();
+}
+
 GLuint ProgramState::getAttributeLocation(const std::string &name) const
 {
     for (const sh::Attribute &attribute : mAttributes)
@@ -1291,10 +1303,12 @@
     updateLinkedShaderStages();
 
     // Mark implementation-specific unreferenced uniforms as ignored.
-    mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
+    mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings,
+                                         &mState.mImageBindings);
 
     // Must be called after markUnusedUniformLocations.
     mState.updateActiveSamplers();
+    mState.updateActiveImages();
 
     setUniformValuesFromBindingQualifiers();
 
@@ -1361,6 +1375,20 @@
     }
 }
 
+void ProgramState::updateActiveImages()
+{
+    for (ImageBinding &imageBinding : mImageBindings)
+    {
+        if (imageBinding.unreferenced)
+            continue;
+
+        for (GLint imageUnit : imageBinding.boundImageUnits)
+        {
+            mActiveImagesMask.set(imageUnit);
+        }
+    }
+}
+
 // Returns the program object to an unlinked state, before re-linking, or at destruction
 void Program::unlink()
 {
@@ -1383,6 +1411,7 @@
     mState.mComputeShaderLocalSize.fill(1);
     mState.mSamplerBindings.clear();
     mState.mImageBindings.clear();
+    mState.mActiveImagesMask.reset();
     mState.mNumViews                          = -1;
     mState.mGeometryShaderInputPrimitiveType  = PrimitiveMode::Triangles;
     mState.mGeometryShaderOutputPrimitiveType = PrimitiveMode::TriangleStrip;
@@ -2860,7 +2889,7 @@
         else
         {
             mState.mImageBindings.emplace_back(
-                ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount()));
+                ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount(), false));
         }
 
         GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u;