• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // MultisampleTest: Tests of multisampled default framebuffer
8 
9 #include "test_utils/ANGLETest.h"
10 
11 #include "test_utils/gl_raii.h"
12 #include "util/OSWindow.h"
13 #include "util/shader_utils.h"
14 
15 using namespace angle;
16 
17 namespace
18 {
19 
20 using MultisampleTestParams = std::tuple<angle::PlatformParameters, bool>;
21 
PrintToStringParamName(const::testing::TestParamInfo<MultisampleTestParams> & info)22 std::string PrintToStringParamName(const ::testing::TestParamInfo<MultisampleTestParams> &info)
23 {
24     ::std::stringstream ss;
25     ss << std::get<0>(info.param);
26     if (std::get<1>(info.param))
27     {
28         ss << "__NoStoreAndResolve";
29     }
30     return ss.str();
31 }
32 
33 class MultisampleTest : public ANGLETestWithParam<MultisampleTestParams>
34 {
35   protected:
testSetUp()36     void testSetUp() override
37     {
38         const angle::PlatformParameters platform = ::testing::get<0>(GetParam());
39         std::vector<const char *> disabledFeatures;
40         if (::testing::get<1>(GetParam()))
41         {
42             disabledFeatures.push_back("allow_msaa_store_and_resolve");
43         }
44         disabledFeatures.push_back(nullptr);
45 
46         // Get display.
47         EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, platform.getRenderer(),
48                                  EGL_FEATURE_OVERRIDES_DISABLED_ANGLE,
49                                  reinterpret_cast<EGLAttrib>(disabledFeatures.data()), EGL_NONE};
50         mDisplay              = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
51                                          reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
52         ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
53 
54         ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
55 
56         // Nexus 5X and 6P fail to eglMakeCurrent with a config they advertise they support.
57         // http://anglebug.com/3464
58         ANGLE_SKIP_TEST_IF(IsNexus5X());
59 
60         // Find a config that uses RGBA8 and allows 4x multisampling.
61         const EGLint configAttributes[] = {EGL_SURFACE_TYPE,
62                                            EGL_WINDOW_BIT,
63                                            EGL_RED_SIZE,
64                                            8,
65                                            EGL_GREEN_SIZE,
66                                            8,
67                                            EGL_BLUE_SIZE,
68                                            8,
69                                            EGL_ALPHA_SIZE,
70                                            8,
71                                            EGL_DEPTH_SIZE,
72                                            24,
73                                            EGL_STENCIL_SIZE,
74                                            8,
75                                            EGL_SAMPLE_BUFFERS,
76                                            1,
77                                            EGL_SAMPLES,
78                                            4,
79                                            EGL_NONE};
80 
81         EGLint configCount;
82         EGLConfig multisampledConfig;
83         EGLint ret =
84             eglChooseConfig(mDisplay, configAttributes, &multisampledConfig, 1, &configCount);
85         mMultisampledConfigExists = ret && configCount > 0;
86 
87         if (!mMultisampledConfigExists)
88         {
89             return;
90         }
91 
92         // Create a window, context and surface if multisampling is possible.
93         mOSWindow = OSWindow::New();
94         mOSWindow->initialize("MultisampleTest", kWindowWidth, kWindowHeight);
95         setWindowVisible(mOSWindow, true);
96 
97         EGLint contextAttributes[] = {
98             EGL_CONTEXT_MAJOR_VERSION_KHR,
99             platform.majorVersion,
100             EGL_CONTEXT_MINOR_VERSION_KHR,
101             platform.minorVersion,
102             EGL_NONE,
103         };
104 
105         mContext =
106             eglCreateContext(mDisplay, multisampledConfig, EGL_NO_CONTEXT, contextAttributes);
107         ASSERT_TRUE(mContext != EGL_NO_CONTEXT);
108 
109         mSurface = eglCreateWindowSurface(mDisplay, multisampledConfig,
110                                           mOSWindow->getNativeWindow(), nullptr);
111         ASSERT_EGL_SUCCESS();
112 
113         eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
114         ASSERT_EGL_SUCCESS();
115     }
116 
testTearDown()117     void testTearDown() override
118     {
119         if (mSurface)
120         {
121             eglSwapBuffers(mDisplay, mSurface);
122         }
123 
124         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
125 
126         if (mSurface)
127         {
128             eglDestroySurface(mDisplay, mSurface);
129             ASSERT_EGL_SUCCESS();
130         }
131 
132         if (mContext != EGL_NO_CONTEXT)
133         {
134             eglDestroyContext(mDisplay, mContext);
135             ASSERT_EGL_SUCCESS();
136         }
137 
138         if (mOSWindow)
139         {
140             OSWindow::Delete(&mOSWindow);
141         }
142 
143         eglTerminate(mDisplay);
144     }
145 
prepareVertexBuffer(GLBuffer & vertexBuffer,const Vector3 * vertices,size_t vertexCount,GLint positionLocation)146     void prepareVertexBuffer(GLBuffer &vertexBuffer,
147                              const Vector3 *vertices,
148                              size_t vertexCount,
149                              GLint positionLocation)
150     {
151         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
152         glBufferData(GL_ARRAY_BUFFER, sizeof(*vertices) * vertexCount, vertices, GL_STATIC_DRAW);
153         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
154         glEnableVertexAttribArray(positionLocation);
155     }
156 
157   protected:
158     static constexpr int kWindowWidth  = 16;
159     static constexpr int kWindowHeight = 8;
160 
161     OSWindow *mOSWindow            = nullptr;
162     EGLDisplay mDisplay            = EGL_NO_DISPLAY;
163     EGLContext mContext            = EGL_NO_CONTEXT;
164     EGLSurface mSurface            = EGL_NO_SURFACE;
165     bool mMultisampledConfigExists = false;
166 };
167 
168 class MultisampleTestES3 : public MultisampleTest
169 {};
170 
171 // Test point rendering on a multisampled surface.  GLES2 section 3.3.1.
TEST_P(MultisampleTest,Point)172 TEST_P(MultisampleTest, Point)
173 {
174     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
175     // http://anglebug.com/3470
176     ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
177     // http://anglebug.com/5727
178     ANGLE_SKIP_TEST_IF(IsOzone());
179 
180     constexpr char kPointsVS[] = R"(precision highp float;
181 attribute vec4 a_position;
182 
183 void main()
184 {
185     gl_PointSize = 3.0;
186     gl_Position = a_position;
187 })";
188 
189     ANGLE_GL_PROGRAM(program, kPointsVS, essl1_shaders::fs::Red());
190     glUseProgram(program);
191     const GLint positionLocation = glGetAttribLocation(program, "a_position");
192 
193     GLBuffer vertexBuffer;
194     const Vector3 vertices[1] = {{0.0f, 0.0f, 0.0f}};
195     prepareVertexBuffer(vertexBuffer, vertices, 1, positionLocation);
196 
197     glClear(GL_COLOR_BUFFER_BIT);
198     glDrawArrays(GL_POINTS, 0, 1);
199 
200     ASSERT_GL_NO_ERROR();
201 
202     // The center pixels should be all red.
203     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2, GLColor::red);
204     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2, GLColor::red);
205     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2 - 1, GLColor::red);
206     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2 - 1, GLColor::red);
207 
208     // Border pixels should be between red and black, and not exactly either; corners are darker and
209     // sides are brighter.
210     const GLColor kSideColor   = {128, 0, 0, 128};
211     const GLColor kCornerColor = {64, 0, 0, 64};
212     constexpr int kErrorMargin = 16;
213     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 2, kCornerColor,
214                             kErrorMargin);
215     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 + 1, kCornerColor,
216                             kErrorMargin);
217     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 2, kCornerColor,
218                             kErrorMargin);
219     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 + 1, kCornerColor,
220                             kErrorMargin);
221 
222     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 1, kSideColor, kErrorMargin);
223     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2, kSideColor, kErrorMargin);
224     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 - 2, kSideColor, kErrorMargin);
225     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 + 1, kSideColor, kErrorMargin);
226     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 - 2, kSideColor, kErrorMargin);
227     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 + 1, kSideColor, kErrorMargin);
228     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 1, kSideColor, kErrorMargin);
229     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2, kSideColor, kErrorMargin);
230 }
231 
232 // Test line rendering on a multisampled surface.  GLES2 section 3.4.4.
TEST_P(MultisampleTest,Line)233 TEST_P(MultisampleTest, Line)
234 {
235     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
236     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
237     // http://anglebug.com/5727
238     ANGLE_SKIP_TEST_IF(IsOzone());
239 
240     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
241     glUseProgram(program);
242     const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
243 
244     GLBuffer vertexBuffer;
245     const Vector3 vertices[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}};
246     prepareVertexBuffer(vertexBuffer, vertices, 2, positionLocation);
247 
248     glClear(GL_COLOR_BUFFER_BIT);
249     glDrawArrays(GL_LINES, 0, 2);
250 
251     ASSERT_GL_NO_ERROR();
252 
253     // The line goes from left to right at about -17 degrees slope.  It renders as such (captured
254     // with renderdoc):
255     //
256     // D                    D = Dark Red (0.25) or (0.5)
257     //  BRA                 R = Red (1.0)
258     //     ARB              M = Middle Red (0.75)
259     //        D             B = Bright Red (1.0 or 0.75)
260     //                      A = Any red (0.5, 0.75 or 1.0)
261     //
262     // Verify that rendering is done as above.
263 
264     const GLColor kDarkRed     = {128, 0, 0, 128};
265     const GLColor kMidRed      = {192, 0, 0, 192};
266     constexpr int kErrorMargin = 16;
267     constexpr int kLargeMargin = 80;
268 
269     static_assert(kWindowWidth == 16, "Verification code written for 16x8 window");
270     EXPECT_PIXEL_COLOR_NEAR(0, 2, kDarkRed, kLargeMargin);
271     EXPECT_PIXEL_COLOR_NEAR(3, 3, GLColor::red, kLargeMargin);
272     EXPECT_PIXEL_COLOR_NEAR(4, 3, GLColor::red, kErrorMargin);
273     EXPECT_PIXEL_COLOR_NEAR(6, 3, kMidRed, kLargeMargin);
274     EXPECT_PIXEL_COLOR_NEAR(8, 4, kMidRed, kLargeMargin);
275     EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin);
276     EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin);
277     EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin);
278 }
279 
280 // Test polygon rendering on a multisampled surface.  GLES2 section 3.5.3.
TEST_P(MultisampleTest,Triangle)281 TEST_P(MultisampleTest, Triangle)
282 {
283     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
284     // http://anglebug.com/3470
285     ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
286     // http://anglebug.com/5727
287     ANGLE_SKIP_TEST_IF(IsOzone());
288 
289     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
290     glUseProgram(program);
291     const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
292 
293     GLBuffer vertexBuffer;
294     const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
295     prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation);
296 
297     glClear(GL_COLOR_BUFFER_BIT);
298     glDrawArrays(GL_TRIANGLES, 0, 3);
299 
300     ASSERT_GL_NO_ERROR();
301 
302     // Top-left pixels should be all red.
303     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
304     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red);
305 
306     // Diagonal pixels from bottom-left to top-right are between red and black.  Pixels above the
307     // diagonal are red and pixels below it are black.
308     const GLColor kMidRed = {128, 0, 0, 128};
309     // D3D11 is off by 63 for red (191 instead of 128), where other back-ends get 128
310     constexpr int kErrorMargin = 64;
311 
312     for (int i = 2; i + 2 < kWindowWidth; i += 2)
313     {
314         int j = kWindowHeight - 1 - (i / 2);
315         EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin);
316         EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red);
317         EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack);
318     }
319 }
320 
321 // Test polygon rendering on a multisampled surface. And rendering is interrupted by a compute pass
322 // that converts the index buffer. Make sure the rendering's multisample result is preserved after
323 // interruption.
TEST_P(MultisampleTest,ContentPresevedAfterInterruption)324 TEST_P(MultisampleTest, ContentPresevedAfterInterruption)
325 {
326     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
327     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
328     // http://anglebug.com/3470
329     ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
330     // http://anglebug.com/4609
331     ANGLE_SKIP_TEST_IF(IsD3D11());
332     // http://anglebug.com/5727
333     ANGLE_SKIP_TEST_IF(IsOzone());
334 
335     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
336     glUseProgram(program);
337     const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
338 
339     if (IsGLExtensionEnabled("GL_EXT_discard_framebuffer"))
340     {
341         GLenum attachments[] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT};
342         glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments);
343     }
344     // Draw triangle
345     GLBuffer vertexBuffer;
346     const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
347     prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation);
348 
349     glClear(GL_COLOR_BUFFER_BIT);
350     glDrawArrays(GL_TRIANGLES, 0, 3);
351 
352     ASSERT_GL_NO_ERROR();
353 
354     // Draw a line
355     GLBuffer vertexBuffer2;
356     GLBuffer indexBuffer2;
357     const Vector3 vertices2[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}};
358     const GLubyte indices2[]   = {0, 1};
359     prepareVertexBuffer(vertexBuffer2, vertices2, 2, positionLocation);
360     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer2);
361     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
362 
363     glDrawElements(GL_LINES, 2, GL_UNSIGNED_BYTE, 0);
364 
365     ASSERT_GL_NO_ERROR();
366 
367     // Top-left pixels should be all red.
368     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
369     EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red);
370 
371     // Triangle edge:
372     // Diagonal pixels from bottom-left to top-right are between red and black.  Pixels above the
373     // diagonal are red and pixels below it are black.
374     {
375         const GLColor kMidRed      = {128, 0, 0, 128};
376         constexpr int kErrorMargin = 16;
377 
378         for (int i = 2; i + 2 < kWindowWidth; i += 2)
379         {
380             // Exclude the middle pixel where the triangle and line cross each other.
381             if (abs(kWindowHeight / 2 - (i / 2)) <= 1)
382             {
383                 continue;
384             }
385             int j = kWindowHeight - 1 - (i / 2);
386             EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin);
387             EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red);
388             EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack);
389         }
390     }
391 
392     // Line edge:
393     {
394         const GLColor kDarkRed     = {128, 0, 0, 128};
395         constexpr int kErrorMargin = 16;
396         constexpr int kLargeMargin = 80;
397 
398         static_assert(kWindowWidth == 16, "Verification code written for 16x8 window");
399         // Exclude the triangle region.
400         EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin);
401         EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin);
402         EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin);
403     }
404 }
405 
406 // Test that alpha to coverage is enabled works properly along with early fragment test.
TEST_P(MultisampleTest,AlphaToSampleCoverage)407 TEST_P(MultisampleTest, AlphaToSampleCoverage)
408 {
409     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
410     // http://anglebug.com/5727
411     ANGLE_SKIP_TEST_IF(IsOzone());
412 
413     constexpr char kFS[] =
414         "precision highp float;\n"
415         "void main()\n"
416         "{\n"
417         "    gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0);\n"
418         "}\n";
419     ANGLE_GL_PROGRAM(transparentRedProgram, essl1_shaders::vs::Simple(), kFS);
420     glUseProgram(transparentRedProgram);
421     glEnable(GL_DEPTH_TEST);
422     glDepthFunc(GL_LESS);
423     glClearDepthf(1.0f);
424     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);  // clear to green
425     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
426     // This should pass depth test, but because of the alpha to coverage enabled, and alpha is 0,
427     // the fragment should be discarded. If early fragment test is disabled, no depth will be
428     // written. depth buffer should be 1.0.
429     glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
430     // There was a bug in ANGLE that we are checking sampler coverage enabled or not instead of
431     // alpha to sample coverage enabled or not. This is specically try to trick ANGLE so that it
432     // will enable early fragment test. When early fragment test is accidentally enabled, then the
433     // depth test will occur before fragment shader, and depth buffer maybe written with value
434     // (0.0+1.0)/2.0=0.5.
435     glEnable(GL_SAMPLE_COVERAGE);
436     drawQuad(transparentRedProgram, essl1_shaders::PositionAttrib(), 0.0f);
437 
438     // Now draw with blue color but to test against 0.0f. This should fail depth test
439     glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
440     glDisable(GL_SAMPLE_COVERAGE);
441     glDepthFunc(GL_GREATER);
442     ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
443     // Zd = 0.5f means (0.5+1.0)/2.0=0.75. Depends on early fragment on or off this will pass or
444     // fail depth test.
445     drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
446     EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
447 
448     ASSERT_GL_NO_ERROR();
449 }
450 
451 // Test that resolve from multisample default framebuffer works.
TEST_P(MultisampleTestES3,ResolveToFBO)452 TEST_P(MultisampleTestES3, ResolveToFBO)
453 {
454     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
455 
456     GLTexture resolveTexture;
457     glBindTexture(GL_TEXTURE_2D, resolveTexture);
458     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWindowWidth, kWindowHeight, 0, GL_RGBA,
459                  GL_UNSIGNED_BYTE, nullptr);
460     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
461     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
462 
463     GLFramebuffer resolveFBO;
464     glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
465     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
466 
467     // Clear the default framebuffer
468     glBindFramebuffer(GL_FRAMEBUFFER, 0);
469     glClearColor(0.25, 0.5, 0.75, 0.25);
470     glClear(GL_COLOR_BUFFER_BIT);
471 
472     // Resolve into FBO
473     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
474     glClearColor(1, 0, 0, 1);
475     glClear(GL_COLOR_BUFFER_BIT);
476     glBlitFramebuffer(0, 0, kWindowWidth, kWindowHeight, 0, 0, kWindowWidth, kWindowHeight,
477                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
478     ASSERT_GL_NO_ERROR();
479 
480     const GLColor kResult = GLColor(63, 127, 191, 63);
481     glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
482     EXPECT_PIXEL_COLOR_NEAR(0, 0, kResult, 1);
483     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, 0, kResult, 1);
484     EXPECT_PIXEL_COLOR_NEAR(0, kWindowHeight - 1, kResult, 1);
485     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, kWindowHeight - 1, kResult, 1);
486     EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2, kResult, 1);
487 }
488 
489 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest,
490                                  PrintToStringParamName,
491                                  testing::Values(false),
492                                  WithNoFixture(ES2_D3D11()),
493                                  WithNoFixture(ES3_D3D11()),
494                                  WithNoFixture(ES31_D3D11()),
495                                  WithNoFixture(ES2_METAL()),
496                                  WithNoFixture(ES2_OPENGL()),
497                                  WithNoFixture(ES3_OPENGL()),
498                                  WithNoFixture(ES31_OPENGL()),
499                                  WithNoFixture(ES2_OPENGLES()),
500                                  WithNoFixture(ES3_OPENGLES()),
501                                  WithNoFixture(ES31_OPENGLES()),
502                                  WithNoFixture(ES2_VULKAN()),
503                                  WithNoFixture(ES3_VULKAN()),
504                                  WithNoFixture(ES31_VULKAN()));
505 
506 namespace store_and_resolve_feature_off
507 {
508 // Simulate missing msaa auto resolve feature in Metal.
509 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest,
510                                  PrintToStringParamName,
511                                  testing::Values(true),
512                                  WithNoFixture(ES2_METAL()));
513 }  // namespace store_and_resolve_feature_off
514 
515 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultisampleTestES3);
516 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTestES3,
517                                  PrintToStringParamName,
518                                  testing::Values(false),
519                                  WithNoFixture(ES3_D3D11()),
520                                  WithNoFixture(ES31_D3D11()),
521                                  WithNoFixture(ES3_OPENGL()),
522                                  WithNoFixture(ES31_OPENGL()),
523                                  WithNoFixture(ES3_OPENGLES()),
524                                  WithNoFixture(ES31_OPENGLES()),
525                                  WithNoFixture(ES3_VULKAN()),
526                                  WithNoFixture(ES31_VULKAN()),
527                                  WithNoFixture(ES3_METAL()));
528 }  // anonymous namespace
529