Fix masked ClearBuffer.

We were not properly setting the masked channels for these APIs.
Since we use a std::vector for tracking the render targets for
a particular ClearBuffer call, we lose the indexing into the
clear parameters. Fix this by storing the information in the
std::vector along with the Render Target.

BUG=angle:702

Change-Id: Ie3b1e870aa04054411c4f155682b86a340ec00cf
Reviewed-on: https://chromium-review.googlesource.com/209103
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
index 1100656..656cd94 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
@@ -200,7 +200,7 @@
                                                              clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
                                                              clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height);
 
-    std::vector<RenderTarget11*> maskedClearRenderTargets;
+    std::vector<MaskedRenderTarget> maskedClearRenderTargets;
     RenderTarget11* maskedClearDepthStencil = NULL;
 
     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -249,7 +249,14 @@
                          (internalAlphaBits > 0 && !clearParams.colorMaskAlpha))
                 {
                     // A scissored or masked clear is required
-                    maskedClearRenderTargets.push_back(renderTarget);
+                    MaskedRenderTarget maskAndRt;
+                    bool clearColor = clearParams.clearColor[colorAttachment];
+                    maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed);
+                    maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen);
+                    maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue);
+                    maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha);
+                    maskAndRt.renderTarget = renderTarget;
+                    maskedClearRenderTargets.push_back(maskAndRt);
                 }
                 else
                 {
@@ -353,18 +360,19 @@
         std::vector<ID3D11RenderTargetView*> rtvs(maskedClearRenderTargets.size());
         for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++)
         {
-            ID3D11RenderTargetView *renderTarget = maskedClearRenderTargets[i]->getRenderTargetView();
-            if (!renderTarget)
+            RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget;
+            ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView();
+            if (!rtv)
             {
-                ERR("Render target pointer unexpectedly null.");
+                ERR("Render target view unexpectedly null.");
                 return;
             }
 
-            rtvs[i] = renderTarget;
+            rtvs[i] = rtv;
         }
         ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL;
 
-        ID3D11BlendState *blendState = getBlendState(clearParams, maskedClearRenderTargets);
+        ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets);
         const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
         const UINT sampleMask = 0xFFFFFFFF;
 
@@ -447,19 +455,20 @@
     }
 }
 
-ID3D11BlendState *Clear11::getBlendState(const gl::ClearParameters &clearParams, const std::vector<RenderTarget11*>& rts)
+ID3D11BlendState *Clear11::getBlendState(const std::vector<MaskedRenderTarget>& rts)
 {
     ClearBlendInfo blendKey = { 0 };
     for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
     {
         if (i < rts.size())
         {
-            GLint internalFormat = rts[i]->getInternalFormat();
+            RenderTarget11 *rt = rts[i].renderTarget;
+            GLint internalFormat = rt->getInternalFormat();
 
-            blendKey.maskChannels[i][0] = clearParams.clearColor ? (clearParams.colorMaskRed   && gl::GetRedBits(internalFormat)   > 0) : false;
-            blendKey.maskChannels[i][1] = clearParams.clearColor ? (clearParams.colorMaskGreen && gl::GetGreenBits(internalFormat) > 0) : false;
-            blendKey.maskChannels[i][2] = clearParams.clearColor ? (clearParams.colorMaskBlue  && gl::GetBlueBits(internalFormat)  > 0) : false;
-            blendKey.maskChannels[i][3] = clearParams.clearColor ? (clearParams.colorMaskAlpha && gl::GetAlphaBits(internalFormat) > 0) : false;
+            blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && gl::GetRedBits(internalFormat)   > 0);
+            blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && gl::GetGreenBits(internalFormat) > 0);
+            blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && gl::GetBlueBits(internalFormat)  > 0);
+            blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && gl::GetAlphaBits(internalFormat) > 0);
         }
         else
         {
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Clear11.h b/src/libGLESv2/renderer/d3d/d3d11/Clear11.h
index e8e4c9e..0cb9a85 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Clear11.h
+++ b/src/libGLESv2/renderer/d3d/d3d11/Clear11.h
@@ -41,7 +41,13 @@
     typedef std::map<ClearBlendInfo, ID3D11BlendState*, ClearBlendInfoComparisonFunction> ClearBlendStateMap;
     ClearBlendStateMap mClearBlendStates;
 
-    ID3D11BlendState *getBlendState(const gl::ClearParameters &clearParams, const std::vector<RenderTarget11*>& rts);
+    struct MaskedRenderTarget
+    {
+        bool colorMask[4];
+        RenderTarget11 *renderTarget;
+    };
+
+    ID3D11BlendState *getBlendState(const std::vector<MaskedRenderTarget> &rts);
 
     struct ClearShader
     {
diff --git a/tests/angle_tests/ClearTest.cpp b/tests/angle_tests/ClearTest.cpp
index 7da3337..50af0bf 100644
--- a/tests/angle_tests/ClearTest.cpp
+++ b/tests/angle_tests/ClearTest.cpp
@@ -12,6 +12,7 @@
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
         setConfigDepthBits(24);
+        setClientVersion(3);
     }
 
     virtual void SetUp()
@@ -44,22 +45,26 @@
         {
             FAIL() << "shader compilation failed.";
         }
+
+        glGenFramebuffers(1, &mFBO);
+
+        ASSERT_GL_NO_ERROR();
     }
 
     virtual void TearDown()
     {
         glDeleteProgram(mProgram);
+        glDeleteFramebuffers(1, &mFBO);
 
         ANGLETest::TearDown();
     }
 
     GLuint mProgram;
+    GLuint mFBO;
 };
 
 TEST_F(ClearTest, ClearIssue)
 {
-    EXPECT_GL_NO_ERROR();
-
     glEnable(GL_DEPTH_TEST);
     glDepthFunc(GL_LEQUAL);
 
@@ -69,9 +74,7 @@
 
     EXPECT_GL_NO_ERROR();
 
-    GLuint fbo;
-    glGenFramebuffers(1, &fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
 
     GLuint rbo;
     glGenRenderbuffers(1, &rbo);
@@ -97,3 +100,41 @@
 
     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
 }
+
+// Requires ES3
+// This tests a bug where in a masked clear when calling "ClearBuffer", we would
+// mistakenly clear every channel (including the masked-out ones)
+TEST_F(ClearTest, MaskedClearBufferBug)
+{
+    unsigned char pixelData[] = { 255, 255, 255, 255 };
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+
+    GLuint textures[2];
+    glGenTextures(2, &textures[0]);
+
+    glBindTexture(GL_TEXTURE_2D, textures[0]);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
+
+    glBindTexture(GL_TEXTURE_2D, textures[1]);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
+
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255);
+
+    float clearValue[] = { 0, 0.5f, 0.5f, 1.0f };
+    GLenum drawBuffers[] = { GL_NONE, GL_COLOR_ATTACHMENT1 };
+    glDrawBuffers(2, drawBuffers);
+    glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE);
+    glClearBufferfv(GL_COLOR, 1, clearValue);
+
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255);
+
+    // TODO: glReadBuffer support
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0);
+    EXPECT_PIXEL_EQ(0, 0, 0, 127, 255, 255);
+}