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