Clear glColorMask at the start of a RenderPass for LoadOp::Clear attachments

Bug: dawn:133
Change-Id: Id8c6180f7a9ef2f7901aca6690d611fad4f13beb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6560
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 5b7e968..b2fecc4 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -657,6 +657,7 @@
 
                 // Load op - color
                 if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
+                    glColorMaski(i, true, true, true, true);
                     glClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r);
                 }
             }
diff --git a/src/tests/end2end/ColorStateTests.cpp b/src/tests/end2end/ColorStateTests.cpp
index e83a57a..f71a5de 100644
--- a/src/tests/end2end/ColorStateTests.cpp
+++ b/src/tests/end2end/ColorStateTests.cpp
@@ -1001,4 +1001,64 @@
     }
 }
 
+// This tests a problem in the OpenGL backend where a previous color write mask
+// persisted and prevented a render pass loadOp from fully clearing the output
+// attachment.
+TEST_P(ColorStateTest, ColorWriteMaskDoesNotAffectRenderPassLoadOpClear) {
+    dawn::ShaderModule fsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
+        #version 450
+        layout(set = 0, binding = 0) uniform myBlock {
+            vec4 color;
+        } myUbo;
+
+        layout(location = 0) out vec4 fragColor;
+
+        void main() {
+            fragColor = myUbo.color;
+        }
+    )");
+
+    utils::ComboRenderPipelineDescriptor baseDescriptor(device);
+    baseDescriptor.layout = pipelineLayout;
+    baseDescriptor.cVertexStage.module = vsModule;
+    baseDescriptor.cFragmentStage.module = fsModule;
+    baseDescriptor.cColorStates[0]->format = renderPass.colorFormat;
+
+    basePipeline = device.CreateRenderPipeline(&baseDescriptor);
+
+    utils::ComboRenderPipelineDescriptor testDescriptor(device);
+    testDescriptor.layout = pipelineLayout;
+    testDescriptor.cVertexStage.module = vsModule;
+    testDescriptor.cFragmentStage.module = fsModule;
+    testDescriptor.cColorStates[0]->format = renderPass.colorFormat;
+    testDescriptor.cColorStates[0]->colorWriteMask = dawn::ColorWriteMask::Red;
+
+    testPipeline = device.CreateRenderPipeline(&testDescriptor);
+
+    RGBA8 base(32, 64, 128, 192);
+    RGBA8 expected(0, 0, 0, 0);
+
+    dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+    {
+        // Clear the output attachment to |base|
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+        pass.SetPipeline(basePipeline);
+        pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})), 0, nullptr);
+        pass.Draw(3, 1, 0, 0);
+
+        // Set a pipeline that will dirty the color write mask
+        pass.SetPipeline(testPipeline);
+        pass.EndPass();
+    }
+    {
+        // This renderpass' loadOp should clear all channels of the output attachment
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+        pass.EndPass();
+    }
+    dawn::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
+}
+
 DAWN_INSTANTIATE_TEST(ColorStateTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);