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 #include "util/test_utils.h"
15
16 using namespace angle;
17
18 namespace
19 {
20
21 using MultisampleTestParams = std::tuple<angle::PlatformParameters, bool>;
22
PrintToStringParamName(const::testing::TestParamInfo<MultisampleTestParams> & info)23 std::string PrintToStringParamName(const ::testing::TestParamInfo<MultisampleTestParams> &info)
24 {
25 ::std::stringstream ss;
26 ss << std::get<0>(info.param);
27 if (std::get<1>(info.param))
28 {
29 ss << "__NoStoreAndResolve";
30 }
31 return ss.str();
32 }
33
34 class MultisampleTest : public ANGLETestWithParam<MultisampleTestParams>
35 {
36 protected:
testSetUp()37 void testSetUp() override
38 {
39 const angle::PlatformParameters platform = ::testing::get<0>(GetParam());
40 std::vector<const char *> disabledFeatures;
41 if (::testing::get<1>(GetParam()))
42 {
43 disabledFeatures.push_back("allow_msaa_store_and_resolve");
44 }
45 disabledFeatures.push_back(nullptr);
46
47 // Get display.
48 EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, platform.getRenderer(),
49 EGL_FEATURE_OVERRIDES_DISABLED_ANGLE,
50 reinterpret_cast<EGLAttrib>(disabledFeatures.data()), EGL_NONE};
51 mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
52 reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
53 ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
54
55 ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
56
57 // Nexus 5X and 6P fail to eglMakeCurrent with a config they advertise they support.
58 // http://anglebug.com/3464
59 ANGLE_SKIP_TEST_IF(IsNexus5X());
60
61 // Find a config that uses RGBA8 and allows 4x multisampling.
62 const EGLint configAttributes[] = {EGL_SURFACE_TYPE,
63 EGL_WINDOW_BIT,
64 EGL_RED_SIZE,
65 8,
66 EGL_GREEN_SIZE,
67 8,
68 EGL_BLUE_SIZE,
69 8,
70 EGL_ALPHA_SIZE,
71 8,
72 EGL_DEPTH_SIZE,
73 24,
74 EGL_STENCIL_SIZE,
75 8,
76 EGL_SAMPLE_BUFFERS,
77 1,
78 EGL_SAMPLES,
79 4,
80 EGL_NONE};
81
82 EGLint configCount;
83 EGLConfig multisampledConfig;
84 EGLint ret =
85 eglChooseConfig(mDisplay, configAttributes, &multisampledConfig, 1, &configCount);
86 mMultisampledConfigExists = ret && configCount > 0;
87
88 if (!mMultisampledConfigExists)
89 {
90 return;
91 }
92
93 // Create a window, context and surface if multisampling is possible.
94 mOSWindow = OSWindow::New();
95 mOSWindow->initialize("MultisampleTest", kWindowWidth, kWindowHeight);
96 setWindowVisible(mOSWindow, true);
97
98 EGLint contextAttributes[] = {
99 EGL_CONTEXT_MAJOR_VERSION_KHR,
100 platform.majorVersion,
101 EGL_CONTEXT_MINOR_VERSION_KHR,
102 platform.minorVersion,
103 EGL_NONE,
104 };
105
106 mContext =
107 eglCreateContext(mDisplay, multisampledConfig, EGL_NO_CONTEXT, contextAttributes);
108 ASSERT_TRUE(mContext != EGL_NO_CONTEXT);
109
110 mSurface = eglCreateWindowSurface(mDisplay, multisampledConfig,
111 mOSWindow->getNativeWindow(), nullptr);
112 ASSERT_EGL_SUCCESS();
113
114 eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
115 ASSERT_EGL_SUCCESS();
116 }
117
testTearDown()118 void testTearDown() override
119 {
120 if (mSurface)
121 {
122 eglSwapBuffers(mDisplay, mSurface);
123 }
124
125 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
126
127 if (mSurface)
128 {
129 eglDestroySurface(mDisplay, mSurface);
130 ASSERT_EGL_SUCCESS();
131 }
132
133 if (mContext != EGL_NO_CONTEXT)
134 {
135 eglDestroyContext(mDisplay, mContext);
136 ASSERT_EGL_SUCCESS();
137 }
138
139 if (mOSWindow)
140 {
141 OSWindow::Delete(&mOSWindow);
142 }
143
144 eglTerminate(mDisplay);
145 }
146
prepareVertexBuffer(GLBuffer & vertexBuffer,const Vector3 * vertices,size_t vertexCount,GLint positionLocation)147 void prepareVertexBuffer(GLBuffer &vertexBuffer,
148 const Vector3 *vertices,
149 size_t vertexCount,
150 GLint positionLocation)
151 {
152 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
153 glBufferData(GL_ARRAY_BUFFER, sizeof(*vertices) * vertexCount, vertices, GL_STATIC_DRAW);
154 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
155 glEnableVertexAttribArray(positionLocation);
156 }
157
158 protected:
159 static constexpr int kWindowWidth = 16;
160 static constexpr int kWindowHeight = 8;
161
162 OSWindow *mOSWindow = nullptr;
163 EGLDisplay mDisplay = EGL_NO_DISPLAY;
164 EGLContext mContext = EGL_NO_CONTEXT;
165 EGLSurface mSurface = EGL_NO_SURFACE;
166 bool mMultisampledConfigExists = false;
167 };
168
169 class MultisampleTestES3 : public MultisampleTest
170 {};
171
172 // Test point rendering on a multisampled surface. GLES2 section 3.3.1.
TEST_P(MultisampleTest,Point)173 TEST_P(MultisampleTest, Point)
174 {
175 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
176 // http://anglebug.com/3470
177 ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
178 // http://anglebug.com/5727
179 ANGLE_SKIP_TEST_IF(IsOzone());
180
181 constexpr char kPointsVS[] = R"(precision highp float;
182 attribute vec4 a_position;
183
184 void main()
185 {
186 gl_PointSize = 3.0;
187 gl_Position = a_position;
188 })";
189
190 ANGLE_GL_PROGRAM(program, kPointsVS, essl1_shaders::fs::Red());
191 glUseProgram(program);
192 const GLint positionLocation = glGetAttribLocation(program, "a_position");
193
194 GLBuffer vertexBuffer;
195 const Vector3 vertices[1] = {{0.0f, 0.0f, 0.0f}};
196 prepareVertexBuffer(vertexBuffer, vertices, 1, positionLocation);
197
198 glClear(GL_COLOR_BUFFER_BIT);
199 glDrawArrays(GL_POINTS, 0, 1);
200
201 ASSERT_GL_NO_ERROR();
202
203 // The center pixels should be all red.
204 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2, GLColor::red);
205 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2, GLColor::red);
206 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2 - 1, GLColor::red);
207 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2 - 1, GLColor::red);
208
209 // Border pixels should be between red and black, and not exactly either; corners are darker and
210 // sides are brighter.
211 const GLColor kSideColor = {128, 0, 0, 128};
212 const GLColor kCornerColor = {64, 0, 0, 64};
213 constexpr int kErrorMargin = 16;
214 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 2, kCornerColor,
215 kErrorMargin);
216 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 + 1, kCornerColor,
217 kErrorMargin);
218 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 2, kCornerColor,
219 kErrorMargin);
220 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 + 1, kCornerColor,
221 kErrorMargin);
222
223 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 1, kSideColor, kErrorMargin);
224 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2, kSideColor, kErrorMargin);
225 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 - 2, kSideColor, kErrorMargin);
226 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 + 1, kSideColor, kErrorMargin);
227 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 - 2, kSideColor, kErrorMargin);
228 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 + 1, kSideColor, kErrorMargin);
229 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 1, kSideColor, kErrorMargin);
230 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2, kSideColor, kErrorMargin);
231 }
232
233 // Test line rendering on a multisampled surface. GLES2 section 3.4.4.
TEST_P(MultisampleTest,Line)234 TEST_P(MultisampleTest, Line)
235 {
236 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
237 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
238 // http://anglebug.com/5727
239 ANGLE_SKIP_TEST_IF(IsOzone());
240
241 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
242 glUseProgram(program);
243 const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
244
245 GLBuffer vertexBuffer;
246 const Vector3 vertices[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}};
247 prepareVertexBuffer(vertexBuffer, vertices, 2, positionLocation);
248
249 glClear(GL_COLOR_BUFFER_BIT);
250 glDrawArrays(GL_LINES, 0, 2);
251
252 ASSERT_GL_NO_ERROR();
253
254 // The line goes from left to right at about -17 degrees slope. It renders as such (captured
255 // with renderdoc):
256 //
257 // D D = Dark Red (0.25) or (0.5)
258 // BRA R = Red (1.0)
259 // ARB M = Middle Red (0.75)
260 // D B = Bright Red (1.0 or 0.75)
261 // A = Any red (0.5, 0.75 or 1.0)
262 //
263 // Verify that rendering is done as above.
264
265 const GLColor kDarkRed = {128, 0, 0, 128};
266 const GLColor kMidRed = {192, 0, 0, 192};
267 constexpr int kErrorMargin = 16;
268 constexpr int kLargeMargin = 80;
269
270 static_assert(kWindowWidth == 16, "Verification code written for 16x8 window");
271 EXPECT_PIXEL_COLOR_NEAR(0, 2, kDarkRed, kLargeMargin);
272 EXPECT_PIXEL_COLOR_NEAR(3, 3, GLColor::red, kLargeMargin);
273 EXPECT_PIXEL_COLOR_NEAR(4, 3, GLColor::red, kErrorMargin);
274 EXPECT_PIXEL_COLOR_NEAR(6, 3, kMidRed, kLargeMargin);
275 EXPECT_PIXEL_COLOR_NEAR(8, 4, kMidRed, kLargeMargin);
276 EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin);
277 EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin);
278 EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin);
279 }
280
281 // Test polygon rendering on a multisampled surface. GLES2 section 3.5.3.
TEST_P(MultisampleTest,Triangle)282 TEST_P(MultisampleTest, Triangle)
283 {
284 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
285 // http://anglebug.com/3470
286 ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
287 // http://anglebug.com/5727
288 ANGLE_SKIP_TEST_IF(IsOzone());
289
290 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
291 glUseProgram(program);
292 const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
293
294 GLBuffer vertexBuffer;
295 const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
296 prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation);
297
298 glClear(GL_COLOR_BUFFER_BIT);
299 glDrawArrays(GL_TRIANGLES, 0, 3);
300
301 ASSERT_GL_NO_ERROR();
302
303 // Top-left pixels should be all red.
304 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
305 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red);
306
307 // Diagonal pixels from bottom-left to top-right are between red and black. Pixels above the
308 // diagonal are red and pixels below it are black.
309 const GLColor kMidRed = {128, 0, 0, 128};
310 // D3D11 is off by 63 for red (191 instead of 128), where other back-ends get 128
311 constexpr int kErrorMargin = 64;
312
313 for (int i = 2; i + 2 < kWindowWidth; i += 2)
314 {
315 int j = kWindowHeight - 1 - (i / 2);
316 EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin);
317 EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red);
318 EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack);
319 }
320 }
321
322 // Test polygon rendering on a multisampled surface. And rendering is interrupted by a compute pass
323 // that converts the index buffer. Make sure the rendering's multisample result is preserved after
324 // interruption.
TEST_P(MultisampleTest,ContentPresevedAfterInterruption)325 TEST_P(MultisampleTest, ContentPresevedAfterInterruption)
326 {
327 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
328 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
329 // http://anglebug.com/3470
330 ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
331 // http://anglebug.com/4609
332 ANGLE_SKIP_TEST_IF(IsD3D11());
333 // http://anglebug.com/5727
334 ANGLE_SKIP_TEST_IF(IsOzone());
335
336 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
337 glUseProgram(program);
338 const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
339
340 if (IsGLExtensionEnabled("GL_EXT_discard_framebuffer"))
341 {
342 GLenum attachments[] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT};
343 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments);
344 }
345 // Draw triangle
346 GLBuffer vertexBuffer;
347 const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
348 prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation);
349
350 glClear(GL_COLOR_BUFFER_BIT);
351 glDrawArrays(GL_TRIANGLES, 0, 3);
352
353 ASSERT_GL_NO_ERROR();
354
355 // Draw a line
356 GLBuffer vertexBuffer2;
357 GLBuffer indexBuffer2;
358 const Vector3 vertices2[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}};
359 const GLubyte indices2[] = {0, 1};
360 prepareVertexBuffer(vertexBuffer2, vertices2, 2, positionLocation);
361 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer2);
362 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
363
364 glDrawElements(GL_LINES, 2, GL_UNSIGNED_BYTE, 0);
365
366 ASSERT_GL_NO_ERROR();
367
368 // Top-left pixels should be all red.
369 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
370 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red);
371
372 // Triangle edge:
373 // Diagonal pixels from bottom-left to top-right are between red and black. Pixels above the
374 // diagonal are red and pixels below it are black.
375 {
376 const GLColor kMidRed = {128, 0, 0, 128};
377 constexpr int kErrorMargin = 16;
378
379 for (int i = 2; i + 2 < kWindowWidth; i += 2)
380 {
381 // Exclude the middle pixel where the triangle and line cross each other.
382 if (abs(kWindowHeight / 2 - (i / 2)) <= 1)
383 {
384 continue;
385 }
386 int j = kWindowHeight - 1 - (i / 2);
387 EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin);
388 EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red);
389 EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack);
390 }
391 }
392
393 // Line edge:
394 {
395 const GLColor kDarkRed = {128, 0, 0, 128};
396 constexpr int kErrorMargin = 16;
397 constexpr int kLargeMargin = 80;
398
399 static_assert(kWindowWidth == 16, "Verification code written for 16x8 window");
400 // Exclude the triangle region.
401 EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin);
402 EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin);
403 EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin);
404 }
405 }
406
407 // Test that alpha to coverage is enabled works properly along with early fragment test.
TEST_P(MultisampleTest,AlphaToSampleCoverage)408 TEST_P(MultisampleTest, AlphaToSampleCoverage)
409 {
410 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
411 // http://anglebug.com/5727
412 ANGLE_SKIP_TEST_IF(IsOzone());
413
414 constexpr char kFS[] =
415 "precision highp float;\n"
416 "void main()\n"
417 "{\n"
418 " gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0);\n"
419 "}\n";
420 ANGLE_GL_PROGRAM(transparentRedProgram, essl1_shaders::vs::Simple(), kFS);
421 glUseProgram(transparentRedProgram);
422 glEnable(GL_DEPTH_TEST);
423 glDepthFunc(GL_LESS);
424 glClearDepthf(1.0f);
425 glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // clear to green
426 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
427 // This should pass depth test, but because of the alpha to coverage enabled, and alpha is 0,
428 // the fragment should be discarded. If early fragment test is disabled, no depth will be
429 // written. depth buffer should be 1.0.
430 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
431 // There was a bug in ANGLE that we are checking sampler coverage enabled or not instead of
432 // alpha to sample coverage enabled or not. This is specically try to trick ANGLE so that it
433 // will enable early fragment test. When early fragment test is accidentally enabled, then the
434 // depth test will occur before fragment shader, and depth buffer maybe written with value
435 // (0.0+1.0)/2.0=0.5.
436 glEnable(GL_SAMPLE_COVERAGE);
437 drawQuad(transparentRedProgram, essl1_shaders::PositionAttrib(), 0.0f);
438
439 // Now draw with blue color but to test against 0.0f. This should fail depth test
440 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
441 glDisable(GL_SAMPLE_COVERAGE);
442 glDepthFunc(GL_GREATER);
443 ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
444 // Zd = 0.5f means (0.5+1.0)/2.0=0.75. Depends on early fragment on or off this will pass or
445 // fail depth test.
446 drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
447 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
448
449 ASSERT_GL_NO_ERROR();
450 }
451
452 // Test that resolve from multisample default framebuffer works.
TEST_P(MultisampleTestES3,ResolveToFBO)453 TEST_P(MultisampleTestES3, ResolveToFBO)
454 {
455 ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
456
457 GLTexture resolveTexture;
458 glBindTexture(GL_TEXTURE_2D, resolveTexture);
459 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWindowWidth, kWindowHeight, 0, GL_RGBA,
460 GL_UNSIGNED_BYTE, nullptr);
461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
463
464 GLFramebuffer resolveFBO;
465 glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
466 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
467
468 // Clear the default framebuffer
469 glBindFramebuffer(GL_FRAMEBUFFER, 0);
470 glClearColor(0.25, 0.5, 0.75, 0.25);
471 glClear(GL_COLOR_BUFFER_BIT);
472
473 // Resolve into FBO
474 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
475 glClearColor(1, 0, 0, 1);
476 glClear(GL_COLOR_BUFFER_BIT);
477 glBlitFramebuffer(0, 0, kWindowWidth, kWindowHeight, 0, 0, kWindowWidth, kWindowHeight,
478 GL_COLOR_BUFFER_BIT, GL_NEAREST);
479 ASSERT_GL_NO_ERROR();
480
481 const GLColor kResult = GLColor(63, 127, 191, 63);
482 glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
483 EXPECT_PIXEL_COLOR_NEAR(0, 0, kResult, 1);
484 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, 0, kResult, 1);
485 EXPECT_PIXEL_COLOR_NEAR(0, kWindowHeight - 1, kResult, 1);
486 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, kWindowHeight - 1, kResult, 1);
487 EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2, kResult, 1);
488 }
489
490 class MultisampleResolveTest : public ANGLETest
491 {
492 protected:
493 static const GLColor kEXPECTED_R8;
494 static const GLColor kEXPECTED_RG8;
495 static const GLColor kEXPECTED_RGB8;
496 static const GLColor kEXPECTED_RGBA8;
497 static const GLColor32F kEXPECTED_RF;
498 static const GLColor32F kEXPECTED_RGF;
499 static const GLColor32F kEXPECTED_RGBF;
500 static const GLColor32F kEXPECTED_RGBAF;
501 static constexpr GLint kWidth = 13;
502 static constexpr GLint kHeight = 11;
503
MultisampleResolveTest()504 MultisampleResolveTest() {}
505
506 struct GLResources
507 {
508 GLFramebuffer fb;
509 GLRenderbuffer rb;
510 };
511
resolveToFBO(GLenum format,GLint samples,GLint width,GLint height,GLResources & resources)512 void resolveToFBO(GLenum format,
513 GLint samples,
514 GLint width,
515 GLint height,
516 GLResources &resources)
517 {
518 constexpr char kVS[] = R"(#version 300 es
519 layout(location = 0) in vec4 position;
520 void main() {
521 gl_Position = position;
522 }
523 )";
524
525 constexpr char kFS[] = R"(#version 300 es
526 precision highp float;
527 out vec4 color;
528 void main() {
529 color = vec4(0.5, 0.6, 0.7, 0.8);
530 }
531 )";
532
533 ANGLE_GL_PROGRAM(program, kVS, kFS);
534
535 // Make samples = 4 multi-sample framebuffer.
536 GLFramebuffer fb0;
537 glBindFramebuffer(GL_FRAMEBUFFER, fb0);
538
539 GLRenderbuffer rb0;
540 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
541 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
542 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb0);
543 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
544
545 // Make samples = 0 multi-sample framebuffer.
546 glBindFramebuffer(GL_FRAMEBUFFER, resources.fb);
547
548 glBindRenderbuffer(GL_RENDERBUFFER, resources.rb);
549 glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, width, height);
550 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
551 resources.rb);
552 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
553
554 // Draw quad to fb0.
555 glBindFramebuffer(GL_FRAMEBUFFER, fb0);
556 glViewport(0, 0, width, height);
557 glUseProgram(program);
558 GLBuffer buf;
559 glBindBuffer(GL_ARRAY_BUFFER, buf);
560
561 constexpr float vertices[] = {
562 -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
563 };
564 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
565 glEnableVertexAttribArray(0);
566 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
567 glDrawArrays(GL_TRIANGLES, 0, 6);
568
569 // Blit fb0 to fb1.
570 glBindFramebuffer(GL_READ_FRAMEBUFFER, fb0);
571 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resources.fb);
572 glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
573 GL_NEAREST);
574 ASSERT_GL_NO_ERROR();
575
576 // Prep for read pixels.
577 glBindFramebuffer(GL_READ_FRAMEBUFFER, resources.fb);
578 }
579
testResolveToUNormFBO(GLenum format,const GLColor & expected_color,GLint samples,GLint width,GLint height)580 void testResolveToUNormFBO(GLenum format,
581 const GLColor &expected_color,
582 GLint samples,
583 GLint width,
584 GLint height)
585 {
586 GLResources resources;
587 resolveToFBO(format, samples, width, height, resources);
588
589 // Check the results
590 for (GLint y = 0; y < kHeight; ++y)
591 {
592 for (GLint x = 0; x < kWidth; ++x)
593 {
594 EXPECT_PIXEL_COLOR_NEAR(x, y, expected_color, 2);
595 }
596 }
597 ASSERT_GL_NO_ERROR();
598 }
599
testResolveToHalfFBO(GLenum format,const GLColor32F & expected_color,GLint samples,GLint width,GLint height)600 void testResolveToHalfFBO(GLenum format,
601 const GLColor32F &expected_color,
602 GLint samples,
603 GLint width,
604 GLint height)
605 {
606 if (!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float"))
607 {
608 return;
609 }
610
611 GLResources resources;
612 resolveToFBO(format, samples, width, height, resources);
613
614 // Check the results
615 for (GLint y = 0; y < kHeight; ++y)
616 {
617 for (GLint x = 0; x < kWidth; ++x)
618 {
619 EXPECT_PIXEL_COLOR32F_NEAR(x, y, expected_color, 2.0f / 255.0f);
620 }
621 }
622 ASSERT_GL_NO_ERROR();
623 }
624
testResolveToFloatFBO(GLenum format,const GLColor32F & expected_color,GLint samples,GLint width,GLint height)625 void testResolveToFloatFBO(GLenum format,
626 const GLColor32F &expected_color,
627 GLint samples,
628 GLint width,
629 GLint height)
630 {
631 if (!IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"))
632 {
633 return;
634 }
635
636 GLResources resources;
637 resolveToFBO(format, samples, width, height, resources);
638
639 // Check the results
640 for (GLint y = 0; y < kHeight; ++y)
641 {
642 for (GLint x = 0; x < kWidth; ++x)
643 {
644 EXPECT_PIXEL_COLOR32F_NEAR(x, y, expected_color, 2.0f / 255.0f);
645 }
646 }
647 ASSERT_GL_NO_ERROR();
648 }
649
testResolveToRGBFloatFBO(GLenum format,const GLColor32F & expected_color,GLint samples,GLint width,GLint height)650 void testResolveToRGBFloatFBO(GLenum format,
651 const GLColor32F &expected_color,
652 GLint samples,
653 GLint width,
654 GLint height)
655 {
656 if (!IsGLExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb"))
657 {
658 return;
659 }
660
661 GLResources resources;
662 resolveToFBO(format, samples, width, height, resources);
663
664 // Check the results
665 for (GLint y = 0; y < kHeight; ++y)
666 {
667 for (GLint x = 0; x < kWidth; ++x)
668 {
669 EXPECT_PIXEL_COLOR32F_NEAR(x, y, expected_color, 2.0f / 255.0f);
670 }
671 }
672 ASSERT_GL_NO_ERROR();
673 }
674
peelDepth(GLint colorLoc)675 void peelDepth(GLint colorLoc)
676 {
677 // Draw full quads from front to back and increasing depths
678 // with depth test = less.
679 glDepthMask(GL_FALSE);
680 constexpr int steps = 64;
681 for (int i = 0; i < steps; ++i)
682 {
683 float l = float(i) / float(steps);
684 float c = l;
685 float z = c * 2.0f - 1.0f;
686 glVertexAttrib4f(1, 0, 0, z, 0);
687 glUniform4f(colorLoc, c, c, c, c);
688 glDrawArrays(GL_TRIANGLES, 0, 6);
689 }
690 glDepthMask(GL_TRUE);
691 }
692
testResolveDepthToFBO(GLenum format,GLenum attachment,GLint samples,GLint width,GLint height)693 void testResolveDepthToFBO(GLenum format,
694 GLenum attachment,
695 GLint samples,
696 GLint width,
697 GLint height)
698 {
699 constexpr char kVS[] = R"(#version 300 es
700 layout(location = 0) in vec4 position;
701 void main() {
702 gl_Position = position;
703 }
704 )";
705
706 constexpr char kFS[] = R"(#version 300 es
707 precision highp float;
708 out vec4 color;
709 void main() {
710 color = vec4(0.5, 0.6, 0.7, 0.8);
711 }
712 )";
713
714 constexpr char kDepthVS[] = R"(#version 300 es
715 layout(location = 0) in vec4 position;
716 layout(location = 1) in vec4 offset;
717 void main() {
718 gl_Position = position + offset;
719 }
720 )";
721
722 constexpr char kDepthFS[] = R"(#version 300 es
723 precision highp float;
724 uniform vec4 color;
725 out vec4 outColor;
726 void main() {
727 outColor = color;
728 }
729 )";
730
731 ANGLE_GL_PROGRAM(program, kVS, kFS);
732 ANGLE_GL_PROGRAM(depthProgram, kDepthVS, kDepthFS);
733
734 // Make samples = 4 multi-sample framebuffer.
735 GLFramebuffer fb0;
736 glBindFramebuffer(GL_FRAMEBUFFER, fb0);
737
738 GLRenderbuffer rb0;
739 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
740 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);
741 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb0);
742
743 GLRenderbuffer db0;
744 glBindRenderbuffer(GL_RENDERBUFFER, db0);
745 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
746 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, db0);
747
748 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
749
750 // Make samples = 0 multi-sample framebuffer.
751 GLFramebuffer fb1;
752 glBindFramebuffer(GL_FRAMEBUFFER, fb1);
753
754 GLRenderbuffer rb1;
755 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
756 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
757 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb1);
758 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
759
760 GLRenderbuffer db1;
761 glBindRenderbuffer(GL_RENDERBUFFER, db1);
762 glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
763 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, db1);
764
765 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
766
767 // Draw quad to fb0.
768 glBindFramebuffer(GL_FRAMEBUFFER, fb0);
769 glViewport(0, 0, width, height);
770 glClearColor(1, 1, 1, 1);
771 glUseProgram(program);
772
773 GLVertexArray va0;
774 glBindVertexArray(va0);
775
776 GLBuffer buf0;
777 glBindBuffer(GL_ARRAY_BUFFER, buf0);
778
779 // clang-format off
780 constexpr float vertices[] = {
781 -1.0f, -1.0f, -1.0,
782 1.0f, -1.0f, 0.0,
783 -1.0f, 1.0f, 0.0,
784 -1.0f, 1.0f, 0.0,
785 1.0f, -1.0f, 0.0,
786 1.0f, 1.0f, 1.0,
787 };
788 // clang-format on
789
790 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
791 glEnableVertexAttribArray(0);
792 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
793 glEnable(GL_DEPTH_TEST);
794 glDepthFunc(GL_ALWAYS);
795 glDrawArrays(GL_TRIANGLES, 0, 6);
796
797 // Blit fb0 to fb1.
798 glBindFramebuffer(GL_READ_FRAMEBUFFER, fb0);
799 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb1);
800 glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT,
801 GL_NEAREST);
802 ASSERT_GL_NO_ERROR();
803
804 GLVertexArray va1;
805 glBindVertexArray(va1);
806
807 // clang-format off
808 constexpr float depthVertices[] = {
809 -1.0f, -1.0f,
810 1.0f, -1.0f,
811 -1.0f, 1.0f,
812 -1.0f, 1.0f,
813 1.0f, -1.0f,
814 1.0f, 1.0f,
815 };
816 // clang-format on
817
818 GLBuffer buf1;
819 glBindBuffer(GL_ARRAY_BUFFER, buf1);
820 glBufferData(GL_ARRAY_BUFFER, sizeof(depthVertices), depthVertices, GL_STATIC_DRAW);
821 glEnableVertexAttribArray(0);
822 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
823
824 glUseProgram(depthProgram);
825 GLint colorLoc = glGetUniformLocation(depthProgram, "color");
826
827 // Extract the depth results.
828 glBindFramebuffer(GL_FRAMEBUFFER, fb1);
829 glClear(GL_COLOR_BUFFER_BIT);
830 glDepthFunc(GL_LESS);
831 peelDepth(colorLoc);
832 std::vector<GLColor> actual(width * height);
833 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, actual.data());
834
835 // Render what should be a similar result to the non-multi-sampled fb
836 glBindVertexArray(va0);
837 glDepthFunc(GL_ALWAYS);
838 glUseProgram(program);
839 glDrawArrays(GL_TRIANGLES, 0, 6);
840
841 // Extract the expected depth results.
842 glBindVertexArray(va1);
843 glUseProgram(depthProgram);
844 glClear(GL_COLOR_BUFFER_BIT);
845 glDepthFunc(GL_LESS);
846 peelDepth(colorLoc);
847 std::vector<GLColor> expected(width * height);
848 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, expected.data());
849
850 for (size_t i = 0; i < expected.size(); ++i)
851 {
852 EXPECT_NEAR(expected[i].R, actual[i].R, 8)
853 << "at " << (i % width) << "," << (i / width);
854 }
855
856 // Verify we read the depth buffer.
857 const GLint minDimension = std::min(width, height);
858 for (GLint i = 1; i < minDimension; ++i)
859 {
860 const GLColor &c1 = expected[i - 1];
861 const GLColor &c2 = expected[i * width + i];
862 EXPECT_LT(c1.R, c2.R);
863 }
864 ASSERT_GL_NO_ERROR();
865 }
866 };
867
868 // Test the multisampled optimized resolve subpass
TEST_P(MultisampleResolveTest,DISABLED_ResolveSubpassMSImage)869 TEST_P(MultisampleResolveTest, DISABLED_ResolveSubpassMSImage)
870 {
871 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
872
873 // Draw green.
874 drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
875 swapBuffers();
876
877 // Wait for visual verification.
878 angle::Sleep(2000);
879 }
880
881 // These colors match the shader in resolveToFBO which returns (0.5, 0.6, 0.7, 0.8).
882 const GLColor MultisampleResolveTest::kEXPECTED_R8(128, 0, 0, 255);
883 const GLColor MultisampleResolveTest::kEXPECTED_RG8(128, 153, 0, 255);
884 const GLColor MultisampleResolveTest::kEXPECTED_RGB8(128, 153, 178, 255);
885 const GLColor MultisampleResolveTest::kEXPECTED_RGBA8(128, 153, 178, 204);
886 const GLColor32F MultisampleResolveTest::kEXPECTED_RF(0.5f, 0.0f, 0.0f, 1.0f);
887 const GLColor32F MultisampleResolveTest::kEXPECTED_RGF(0.5f, 0.6f, 0.0f, 1.0f);
888 const GLColor32F MultisampleResolveTest::kEXPECTED_RGBF(0.5f, 0.6f, 0.7f, 1.0f);
889 const GLColor32F MultisampleResolveTest::kEXPECTED_RGBAF(0.5f, 0.6f, 0.7f, 0.8f);
890
891 // Test we can render to and resolve an RGBA8 renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGBA8ToFBO4Samples)892 TEST_P(MultisampleResolveTest, ResolveRGBA8ToFBO4Samples)
893 {
894 testResolveToUNormFBO(GL_RGBA8, kEXPECTED_RGBA8, 4, kWidth, kHeight);
895 }
896
897 // Test we can render to and resolve an RGB8 renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGB8ToFBO4Samples)898 TEST_P(MultisampleResolveTest, ResolveRGB8ToFBO4Samples)
899 {
900 testResolveToUNormFBO(GL_RGB8, kEXPECTED_RGB8, 4, kWidth, kHeight);
901 }
902
903 // Test we can render to and resolve an RG8 renderbuffer
TEST_P(MultisampleResolveTest,ResolveRG8ToFBO4Samples)904 TEST_P(MultisampleResolveTest, ResolveRG8ToFBO4Samples)
905 {
906 testResolveToUNormFBO(GL_RG8, kEXPECTED_RG8, 4, kWidth, kHeight);
907 }
908
909 // Test we can render to and resolve an R8 renderbuffer
TEST_P(MultisampleResolveTest,ResolveR8ToFBO4Samples)910 TEST_P(MultisampleResolveTest, ResolveR8ToFBO4Samples)
911 {
912 testResolveToUNormFBO(GL_R8, kEXPECTED_R8, 4, kWidth, kHeight);
913 }
914
915 // Test we can render to and resolve an R16F renderbuffer
TEST_P(MultisampleResolveTest,ResolveR16FToFBO4Samples)916 TEST_P(MultisampleResolveTest, ResolveR16FToFBO4Samples)
917 {
918 testResolveToHalfFBO(GL_R16F, kEXPECTED_RF, 4, kWidth, kHeight);
919 }
920
921 // Test we can render to and resolve an RG16F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRG16FToFBO4Samples)922 TEST_P(MultisampleResolveTest, ResolveRG16FToFBO4Samples)
923 {
924 testResolveToHalfFBO(GL_RG16F, kEXPECTED_RGF, 4, kWidth, kHeight);
925 }
926
927 // Test we can render to and resolve an RGB16F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGB16FToFBO4Samples)928 TEST_P(MultisampleResolveTest, ResolveRGB16FToFBO4Samples)
929 {
930 testResolveToHalfFBO(GL_RGB16F, kEXPECTED_RGBF, 4, kWidth, kHeight);
931 }
932
933 // Test we can render to and resolve an RGBA16F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGBA16FToFBO4Samples)934 TEST_P(MultisampleResolveTest, ResolveRGBA16FToFBO4Samples)
935 {
936 testResolveToHalfFBO(GL_RGBA16F, kEXPECTED_RGBAF, 4, kWidth, kHeight);
937 }
938
939 // Test we can render to and resolve an R32F renderbuffer
TEST_P(MultisampleResolveTest,ResolveR32FToFBO4Samples)940 TEST_P(MultisampleResolveTest, ResolveR32FToFBO4Samples)
941 {
942 testResolveToFloatFBO(GL_R32F, kEXPECTED_RF, 4, kWidth, kHeight);
943 }
944
945 // Test we can render to and resolve an RG32F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRG32FToFBO4Samples)946 TEST_P(MultisampleResolveTest, ResolveRG32FToFBO4Samples)
947 {
948 testResolveToFloatFBO(GL_RG32F, kEXPECTED_RGF, 4, kWidth, kHeight);
949 }
950
951 // Test we can render to and resolve an RGB32F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGB32FToFBO4Samples)952 TEST_P(MultisampleResolveTest, ResolveRGB32FToFBO4Samples)
953 {
954 testResolveToRGBFloatFBO(GL_RGB32F, kEXPECTED_RGBF, 4, kWidth, kHeight);
955 }
956
957 // Test we can render to and resolve an RGBA32F renderbuffer
TEST_P(MultisampleResolveTest,ResolveRGBA32FToFBO4Samples)958 TEST_P(MultisampleResolveTest, ResolveRGBA32FToFBO4Samples)
959 {
960 testResolveToFloatFBO(GL_RGBA32F, kEXPECTED_RGBAF, 4, kWidth, kHeight);
961 }
962
TEST_P(MultisampleResolveTest,ResolveD32FS8F4Samples)963 TEST_P(MultisampleResolveTest, ResolveD32FS8F4Samples)
964 {
965 testResolveDepthToFBO(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT, 4, kWidth, kHeight);
966 }
967
TEST_P(MultisampleResolveTest,ResolveD24S8Samples)968 TEST_P(MultisampleResolveTest, ResolveD24S8Samples)
969 {
970 testResolveDepthToFBO(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT, 4, kWidth, kHeight);
971 }
972
TEST_P(MultisampleResolveTest,ResolveD32FSamples)973 TEST_P(MultisampleResolveTest, ResolveD32FSamples)
974 {
975 testResolveDepthToFBO(GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT, 4, kWidth, kHeight);
976 }
977
TEST_P(MultisampleResolveTest,ResolveD24Samples)978 TEST_P(MultisampleResolveTest, ResolveD24Samples)
979 {
980 testResolveDepthToFBO(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT, 4, kWidth, kHeight);
981 }
982
TEST_P(MultisampleResolveTest,ResolveD16Samples)983 TEST_P(MultisampleResolveTest, ResolveD16Samples)
984 {
985 testResolveDepthToFBO(GL_DEPTH_COMPONENT16, GL_DEPTH_ATTACHMENT, 4, kWidth, kHeight);
986 }
987
drawRectAndBlit(GLuint msFramebuffer,GLuint resolveFramebuffer,GLint width,GLint height,GLint matLoc,GLint colorLoc,float x,float y,float w,float h,const GLColor & color)988 void drawRectAndBlit(GLuint msFramebuffer,
989 GLuint resolveFramebuffer,
990 GLint width,
991 GLint height,
992 GLint matLoc,
993 GLint colorLoc,
994 float x,
995 float y,
996 float w,
997 float h,
998 const GLColor &color)
999 {
1000 glBindFramebuffer(GL_FRAMEBUFFER, msFramebuffer);
1001 float matrix[16] = {
1002 w, 0, 0, 0, 0, h, 0, 0, 0, 0, 1, 0, x, y, 0, 1,
1003 };
1004 glUniformMatrix4fv(matLoc, 1, false, matrix);
1005 angle::Vector4 c(color.toNormalizedVector());
1006 glUniform4f(colorLoc, c[0], c[1], c[2], c[3]);
1007 glDrawArrays(GL_TRIANGLES, 0, 6);
1008
1009 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFramebuffer);
1010 glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1011 }
1012
1013 // Tests if we resolve(blit) a multisample renderbuffer that it
1014 // does not lose its contents.
TEST_P(MultisampleResolveTest,DrawAndResolveMultipleTimes)1015 TEST_P(MultisampleResolveTest, DrawAndResolveMultipleTimes)
1016 {
1017 constexpr GLint samples = 4;
1018 constexpr GLenum format = GL_RGBA8;
1019 constexpr GLint width = 16;
1020 constexpr GLint height = 16;
1021
1022 constexpr char kVS[] = R"(#version 300 es
1023 layout(location = 0) in vec4 position;
1024 uniform mat4 mat;
1025 void main() {
1026 gl_Position = mat * position;
1027 }
1028 )";
1029
1030 constexpr char kFS[] = R"(#version 300 es
1031 precision highp float;
1032 uniform vec4 color;
1033 out vec4 outColor;
1034 void main() {
1035 outColor = color;
1036 }
1037 )";
1038
1039 glViewport(0, 0, width, height);
1040
1041 ANGLE_GL_PROGRAM(program, kVS, kFS);
1042 GLint matLoc = glGetUniformLocation(program, "mat");
1043 GLint colorLoc = glGetUniformLocation(program, "color");
1044 glUseProgram(program);
1045
1046 GLBuffer buf;
1047 glBindBuffer(GL_ARRAY_BUFFER, buf);
1048
1049 constexpr float vertices[] = {
1050 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1051 };
1052 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
1053 glEnableVertexAttribArray(0);
1054 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
1055
1056 // Make samples = 4 multi-sample framebuffer.
1057 GLFramebuffer msFB;
1058 glBindFramebuffer(GL_FRAMEBUFFER, msFB);
1059
1060 GLRenderbuffer msRB;
1061 glBindRenderbuffer(GL_RENDERBUFFER, msRB);
1062 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
1063 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msRB);
1064 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1065
1066 // Make non-multi-sample framebuffer.
1067 GLFramebuffer drawFB;
1068 glBindFramebuffer(GL_FRAMEBUFFER, drawFB);
1069
1070 GLRenderbuffer drawRB;
1071 glBindRenderbuffer(GL_RENDERBUFFER, drawRB);
1072 glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
1073 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, drawRB);
1074 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1075
1076 drawRectAndBlit(msFB, drawFB, width, height, matLoc, colorLoc, -1, -1, 2, 2, GLColor::red);
1077 drawRectAndBlit(msFB, drawFB, width, height, matLoc, colorLoc, 0, -1, 1, 1, GLColor::green);
1078 drawRectAndBlit(msFB, drawFB, width, height, matLoc, colorLoc, -1, 0, 1, 1, GLColor::blue);
1079 drawRectAndBlit(msFB, drawFB, width, height, matLoc, colorLoc, 0, 0, 1, 1, GLColor::yellow);
1080 glEnable(GL_BLEND);
1081 glBlendFunc(GL_ONE, GL_ONE);
1082 drawRectAndBlit(msFB, drawFB, width, height, matLoc, colorLoc, -0.5, -0.5, 1, 1,
1083 GLColor(0x80, 0x80, 0x80, 0x80));
1084 glDisable(GL_BLEND);
1085 ASSERT_GL_NO_ERROR();
1086
1087 /*
1088 expected
1089 +-------------+--------------+
1090 | blue | yellow |
1091 | +---------+----------+ |
1092 | |.5,.5,1,1| 1,1,.5,1 | |
1093 +---+---------+----------+---+
1094 | |1,.5,.5,1| .5,1,.5,1| |
1095 | +---------+----------+ |
1096 | red | green |
1097 +-------------+--------------+
1098 0,0
1099 */
1100
1101 glBindFramebuffer(GL_FRAMEBUFFER, drawFB);
1102 EXPECT_PIXEL_RECT_EQ(0, 0, width / 2, height / 4, GLColor::red);
1103 EXPECT_PIXEL_RECT_EQ(width / 2, 0, width / 2, height / 4, GLColor::green);
1104 EXPECT_PIXEL_RECT_EQ(0, height * 3 / 4, width / 2, height / 4, GLColor::blue);
1105 EXPECT_PIXEL_RECT_EQ(width / 2, height * 3 / 4, width / 2, height / 4, GLColor::yellow);
1106
1107 EXPECT_PIXEL_RECT_EQ(width / 4, height / 4, width / 4, height / 4, GLColor(255, 128, 128, 255));
1108 EXPECT_PIXEL_RECT_EQ(width / 2, height / 4, width / 4, height / 4, GLColor(128, 255, 128, 255));
1109 EXPECT_PIXEL_RECT_EQ(width / 4, height / 2, width / 4, height / 4, GLColor(128, 128, 255, 255));
1110 EXPECT_PIXEL_RECT_EQ(width / 2, height / 2, width / 4, height / 4, GLColor(255, 255, 128, 255));
1111 }
1112
1113 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest,
1114 PrintToStringParamName,
1115 testing::Values(false),
1116 WithNoFixture(ES2_D3D11()),
1117 WithNoFixture(ES3_D3D11()),
1118 WithNoFixture(ES31_D3D11()),
1119 WithNoFixture(ES2_METAL()),
1120 WithNoFixture(ES2_OPENGL()),
1121 WithNoFixture(ES3_OPENGL()),
1122 WithNoFixture(ES31_OPENGL()),
1123 WithNoFixture(ES2_OPENGLES()),
1124 WithNoFixture(ES3_OPENGLES()),
1125 WithNoFixture(ES31_OPENGLES()),
1126 WithNoFixture(ES2_VULKAN()),
1127 WithNoFixture(ES3_VULKAN()),
1128 WithNoFixture(ES31_VULKAN()));
1129
1130 namespace store_and_resolve_feature_off
1131 {
1132 // Simulate missing msaa auto resolve feature in Metal.
1133 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest,
1134 PrintToStringParamName,
1135 testing::Values(true),
1136 WithNoFixture(ES2_METAL()));
1137 } // namespace store_and_resolve_feature_off
1138
1139 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultisampleTestES3);
1140 ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTestES3,
1141 PrintToStringParamName,
1142 testing::Values(false),
1143 WithNoFixture(ES3_D3D11()),
1144 WithNoFixture(ES31_D3D11()),
1145 WithNoFixture(ES3_OPENGL()),
1146 WithNoFixture(ES31_OPENGL()),
1147 WithNoFixture(ES3_OPENGLES()),
1148 WithNoFixture(ES31_OPENGLES()),
1149 WithNoFixture(ES3_VULKAN()),
1150 WithNoFixture(ES31_VULKAN()),
1151 WithNoFixture(ES3_METAL()));
1152
1153 ANGLE_INSTANTIATE_TEST_ES3(MultisampleResolveTest);
1154
1155 } // anonymous namespace
1156