Fixed incorrect multisample rendering when enable SAMPLE_COVERAGE on Win

In RendererD3D::createRenderTarget, we use getNearestSamples(samples)'s
result to assign D3D11_TEXTURE2D_DESC.SampleDesc.Count. However, in
renderer11::updateState, we used the original samples to calculate mask
by GetBlendSampleMask not the supported nearest samples. It would result
that multisample rendering result was incorrect when enable
AMPLE_COVERAGE and the samples is not in the suported list but less than
max samples. At least, on Intel Win platform, we can reproduce it.
The fixing is to use same samples in these two places.

BUG=angleproject:1610
TEST=MultisampleCompatibilityTest.DrawCoverageAndResolve

Change-Id: I255b12d1032317145adfcee94e65e88ae5307113
Reviewed-on: https://chromium-review.googlesource.com/408516
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 4bad459..34f9925 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1615,7 +1615,17 @@
     mStateManager.setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
 
     // Applying rasterizer state to D3D11 device
-    int samples                    = framebuffer->getSamples(data);
+    // Since framebuffer->getSamples will return the original samples which may be different with
+    // the sample counts that we set in render target view, here we use renderTarget->getSamples to
+    // get the actual samples.
+    GLsizei samples = 0;
+    if (firstColorAttachment)
+    {
+        ASSERT(firstColorAttachment->isAttached());
+        RenderTarget11 *renderTarget = nullptr;
+        ANGLE_TRY(firstColorAttachment->getRenderTarget(&renderTarget));
+        samples = renderTarget->getSamples();
+    }
     gl::RasterizerState rasterizer = glState.getRasterizerState();
     rasterizer.pointDrawMode       = (drawMode == GL_POINTS);
     rasterizer.multiSample         = (samples != 0);
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index bc9c4fc..7918d27 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -1007,7 +1007,18 @@
     setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
 
     // Setting blend, depth stencil, and rasterizer states
-    int samples                    = framebuffer->getSamples(data);
+    // Since framebuffer->getSamples will return the original samples which may be different with
+    // the sample counts that we set in render target view, here we use renderTarget->getSamples to
+    // get the actual samples.
+    GLsizei samples           = 0;
+    auto firstColorAttachment = framebuffer->getFirstColorbuffer();
+    if (firstColorAttachment)
+    {
+        ASSERT(firstColorAttachment->isAttached());
+        RenderTarget9 *renderTarget = nullptr;
+        ANGLE_TRY(firstColorAttachment->getRenderTarget(&renderTarget));
+        samples = renderTarget->getSamples();
+    }
     gl::RasterizerState rasterizer = glState.getRasterizerState();
     rasterizer.pointDrawMode       = (drawMode == GL_POINTS);
     rasterizer.multiSample         = (samples != 0);
@@ -1030,7 +1041,18 @@
     const auto &glState  = glData.getState();
     auto drawFramebuffer = glState.getDrawFramebuffer();
     ASSERT(!drawFramebuffer->hasAnyDirtyBit());
-    int samples                    = drawFramebuffer->getSamples(glData);
+    // Since framebuffer->getSamples will return the original samples which may be different with
+    // the sample counts that we set in render target view, here we use renderTarget->getSamples to
+    // get the actual samples.
+    GLsizei samples           = 0;
+    auto firstColorAttachment = drawFramebuffer->getFirstColorbuffer();
+    if (firstColorAttachment)
+    {
+        ASSERT(firstColorAttachment->isAttached());
+        RenderTarget9 *renderTarget = nullptr;
+        ANGLE_TRY(firstColorAttachment->getRenderTarget(&renderTarget));
+        samples = renderTarget->getSamples();
+    }
     gl::RasterizerState rasterizer = glState.getRasterizerState();
     rasterizer.pointDrawMode       = (drawMode == GL_POINTS);
     rasterizer.multiSample         = (samples != 0);
diff --git a/src/tests/gl_tests/MultisampleCompatibilityTest.cpp b/src/tests/gl_tests/MultisampleCompatibilityTest.cpp
index 30708ee..0edc221 100644
--- a/src/tests/gl_tests/MultisampleCompatibilityTest.cpp
+++ b/src/tests/gl_tests/MultisampleCompatibilityTest.cpp
@@ -9,6 +9,7 @@
 //
 
 #include "test_utils/ANGLETest.h"
+#include "test_utils/gl_raii.h"
 #include "shader_utils.h"
 
 using namespace angle;
@@ -296,5 +297,142 @@
     EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
 }
 
+ANGLE_INSTANTIATE_TEST(EXTMultisampleCompatibilityTest, ES2_OPENGL(), ES2_OPENGLES(), ES3_OPENGL());
 
-ANGLE_INSTANTIATE_TEST(EXTMultisampleCompatibilityTest, ES2_OPENGL(), ES2_OPENGLES(), ES3_OPENGL());
\ No newline at end of file
+class MultisampleCompatibilityTest : public ANGLETest
+{
+
+  protected:
+    MultisampleCompatibilityTest()
+    {
+        setWindowWidth(64);
+        setWindowHeight(64);
+        setConfigRedBits(8);
+        setConfigBlueBits(8);
+        setConfigAlphaBits(8);
+    }
+
+    void prepareForDraw(GLsizei numSamples)
+    {
+        // Create a sample buffer.
+        glGenRenderbuffers(1, &mSampleRB);
+        glBindRenderbuffer(GL_RENDERBUFFER, mSampleRB);
+        glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, numSamples, GL_RGBA8, kWidth,
+                                              kHeight);
+        GLint param = 0;
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &param);
+        EXPECT_GE(param, numSamples);
+        glGenFramebuffers(1, &mSampleFBO);
+        glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleRB);
+        EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        // Create another FBO to resolve the multisample buffer into.
+        glGenTextures(1, &mResolveTex);
+        glBindTexture(GL_TEXTURE_2D, mResolveTex);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     NULL);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glGenFramebuffers(1, &mResolveFBO);
+        glBindFramebuffer(GL_FRAMEBUFFER, mResolveFBO);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mResolveTex, 0);
+        EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+        glViewport(0, 0, kWidth, kHeight);
+        glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
+        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        ASSERT_GL_NO_ERROR();
+    }
+
+    void prepareForVerify()
+    {
+        // Resolve.
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleFBO);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFBO);
+        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glBlitFramebufferANGLE(0, 0, kWidth, kHeight, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT,
+                               GL_NEAREST);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFBO);
+
+        ASSERT_GL_NO_ERROR();
+    }
+
+    void cleanup()
+    {
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glDeleteFramebuffers(1, &mResolveFBO);
+        glDeleteFramebuffers(1, &mSampleFBO);
+        glDeleteTextures(1, &mResolveTex);
+        glDeleteRenderbuffers(1, &mSampleRB);
+
+        ASSERT_GL_NO_ERROR();
+    }
+
+    bool isApplicable() const
+    {
+        return extensionEnabled("GL_ANGLE_framebuffer_multisample") &&
+               extensionEnabled("GL_OES_rgb8_rgba8");
+    }
+
+    GLuint mSampleFBO;
+    GLuint mResolveFBO;
+    GLuint mSampleRB;
+    GLuint mResolveTex;
+};
+
+// Test that enabling GL_SAMPLE_COVERAGE affects rendering.
+TEST_P(MultisampleCompatibilityTest, DrawCoverageAndResolve)
+{
+    if (!isApplicable())
+        return;
+
+    // TODO: Figure out why this fails on Android.
+    if (IsAndroid())
+    {
+        std::cout << "Test skipped on Android." << std::endl;
+        return;
+    }
+
+    const std::string &vertex =
+        "attribute vec4 position;\n"
+        "void main()\n"
+        "{ gl_Position = position; }";
+    const std::string &fragment =
+        "void main()\n"
+        "{ gl_FragColor =  vec4(1.0, 0.0, 0.0, 1.0); }";
+
+    ANGLE_GL_PROGRAM(drawRed, vertex, fragment);
+
+    GLsizei maxSamples = 0;
+    glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
+    int iterationCount = maxSamples + 1;
+    for (int samples = 1; samples < iterationCount; samples++)
+    {
+        prepareForDraw(samples);
+        glEnable(GL_SAMPLE_COVERAGE);
+        glSampleCoverage(1.0, false);
+        drawQuad(drawRed.get(), "position", 0.5f);
+
+        prepareForVerify();
+        GLsizei pixelCount = kWidth * kHeight;
+        std::vector<GLColor> actual(pixelCount, GLColor::black);
+        glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, actual.data());
+        glDisable(GL_SAMPLE_COVERAGE);
+        cleanup();
+
+        std::vector<GLColor> expected(pixelCount, GLColor::red);
+        EXPECT_EQ(expected, actual);
+    }
+}
+
+ANGLE_INSTANTIATE_TEST(MultisampleCompatibilityTest,
+                       ES2_D3D9(),
+                       ES2_OPENGL(),
+                       ES2_OPENGLES(),
+                       ES3_D3D11(),
+                       ES3_OPENGL(),
+                       ES3_OPENGLES());
\ No newline at end of file