Widen color state support on ES.

Indexed draw buffer (color state) support on ES is not core until 3.2.
Previously, we were failing (asserting) if color state was changed for
a non-zero attachment. This CL compares the state, and only asserts if the
color state actually differs per-attachment.

It also implements a disable_indexed_draw_buffers toggle, which allows a
test to check for the functionality in a platform-independent manner.

BUG=dawn:580, dawn:582

Change-Id: I11c67b0dd72f73e7302c06cad24e8a268fb37a76
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/34981
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/opengl/RenderPipelineGL.cpp b/src/dawn_native/opengl/RenderPipelineGL.cpp
index edabc71..9a5da5c 100644
--- a/src/dawn_native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn_native/opengl/RenderPipelineGL.cpp
@@ -106,44 +106,46 @@
                              ColorAttachmentIndex attachment,
                              const ColorStateDescriptor* descriptor) {
             GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
-            if (gl.IsAtLeastGL(3, 0) || gl.IsAtLeastGLES(3, 2)) {
-                if (BlendEnabled(descriptor)) {
-                    gl.Enablei(GL_BLEND, colorBuffer);
-                    gl.BlendEquationSeparatei(colorBuffer,
-                                              GLBlendMode(descriptor->colorBlend.operation),
-                                              GLBlendMode(descriptor->alphaBlend.operation));
-                    gl.BlendFuncSeparatei(colorBuffer,
-                                          GLBlendFactor(descriptor->colorBlend.srcFactor, false),
-                                          GLBlendFactor(descriptor->colorBlend.dstFactor, false),
-                                          GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
-                                          GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
-                } else {
-                    gl.Disablei(GL_BLEND, colorBuffer);
-                }
-                gl.ColorMaski(colorBuffer, descriptor->writeMask & wgpu::ColorWriteMask::Red,
-                              descriptor->writeMask & wgpu::ColorWriteMask::Green,
-                              descriptor->writeMask & wgpu::ColorWriteMask::Blue,
-                              descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
+            if (BlendEnabled(descriptor)) {
+                gl.Enablei(GL_BLEND, colorBuffer);
+                gl.BlendEquationSeparatei(colorBuffer,
+                                          GLBlendMode(descriptor->colorBlend.operation),
+                                          GLBlendMode(descriptor->alphaBlend.operation));
+                gl.BlendFuncSeparatei(colorBuffer,
+                                      GLBlendFactor(descriptor->colorBlend.srcFactor, false),
+                                      GLBlendFactor(descriptor->colorBlend.dstFactor, false),
+                                      GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
+                                      GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
             } else {
-                // TODO(crbug.com/dawn/582): Add validation to prevent this as it is not supported
-                // on GLES < 3.2.
-                DAWN_ASSERT(colorBuffer == 0);
-                if (BlendEnabled(descriptor)) {
-                    gl.Enable(GL_BLEND);
-                    gl.BlendEquationSeparate(GLBlendMode(descriptor->colorBlend.operation),
-                                             GLBlendMode(descriptor->alphaBlend.operation));
-                    gl.BlendFuncSeparate(GLBlendFactor(descriptor->colorBlend.srcFactor, false),
-                                         GLBlendFactor(descriptor->colorBlend.dstFactor, false),
-                                         GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
-                                         GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
-                } else {
-                    gl.Disable(GL_BLEND);
-                }
-                gl.ColorMask(descriptor->writeMask & wgpu::ColorWriteMask::Red,
-                             descriptor->writeMask & wgpu::ColorWriteMask::Green,
-                             descriptor->writeMask & wgpu::ColorWriteMask::Blue,
-                             descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
+                gl.Disablei(GL_BLEND, colorBuffer);
             }
+            gl.ColorMaski(colorBuffer, descriptor->writeMask & wgpu::ColorWriteMask::Red,
+                          descriptor->writeMask & wgpu::ColorWriteMask::Green,
+                          descriptor->writeMask & wgpu::ColorWriteMask::Blue,
+                          descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
+        }
+
+        void ApplyColorState(const OpenGLFunctions& gl, const ColorStateDescriptor* descriptor) {
+            if (BlendEnabled(descriptor)) {
+                gl.Enable(GL_BLEND);
+                gl.BlendEquationSeparate(GLBlendMode(descriptor->colorBlend.operation),
+                                         GLBlendMode(descriptor->alphaBlend.operation));
+                gl.BlendFuncSeparate(GLBlendFactor(descriptor->colorBlend.srcFactor, false),
+                                     GLBlendFactor(descriptor->colorBlend.dstFactor, false),
+                                     GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
+                                     GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
+            } else {
+                gl.Disable(GL_BLEND);
+            }
+            gl.ColorMask(descriptor->writeMask & wgpu::ColorWriteMask::Red,
+                         descriptor->writeMask & wgpu::ColorWriteMask::Green,
+                         descriptor->writeMask & wgpu::ColorWriteMask::Blue,
+                         descriptor->writeMask & wgpu::ColorWriteMask::Alpha);
+        }
+
+        bool Equal(const BlendDescriptor& lhs, const BlendDescriptor& rhs) {
+            return lhs.operation == rhs.operation && lhs.srcFactor == rhs.srcFactor &&
+                   lhs.dstFactor == rhs.dstFactor;
         }
 
         GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {
@@ -298,8 +300,25 @@
             gl.Disable(GL_POLYGON_OFFSET_FILL);
         }
 
-        for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
-            ApplyColorState(gl, attachmentSlot, GetColorStateDescriptor(attachmentSlot));
+        if (!GetDevice()->IsToggleEnabled(Toggle::DisableIndexedDrawBuffers)) {
+            for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
+                ApplyColorState(gl, attachmentSlot, GetColorStateDescriptor(attachmentSlot));
+            }
+        } else {
+            const ColorStateDescriptor* prevDescriptor = nullptr;
+            for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
+                const ColorStateDescriptor* descriptor = GetColorStateDescriptor(attachmentSlot);
+                if (!prevDescriptor) {
+                    ApplyColorState(gl, descriptor);
+                    prevDescriptor = descriptor;
+                } else if (!Equal(descriptor->alphaBlend, prevDescriptor->alphaBlend) ||
+                           !Equal(descriptor->colorBlend, prevDescriptor->colorBlend) ||
+                           descriptor->writeMask != prevDescriptor->writeMask) {
+                    // TODO(crbug.com/dawn/582): Add validation to prevent this as it is not
+                    // supported on GLES < 3.2.
+                    ASSERT(false);
+                }
+            }
         }
     }