| // |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // MultisampleTest: Tests of multisampled default framebuffer |
| |
| #include "test_utils/ANGLETest.h" |
| |
| #include "test_utils/gl_raii.h" |
| #include "util/OSWindow.h" |
| #include "util/shader_utils.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| |
| using MultisampleTestParams = std::tuple<angle::PlatformParameters, bool>; |
| |
| std::string PrintToStringParamName(const ::testing::TestParamInfo<MultisampleTestParams> &info) |
| { |
| ::std::stringstream ss; |
| ss << std::get<0>(info.param); |
| if (std::get<1>(info.param)) |
| { |
| ss << "__NoStoreAndResolve"; |
| } |
| return ss.str(); |
| } |
| |
| class MultisampleTest : public ANGLETestWithParam<MultisampleTestParams> |
| { |
| protected: |
| void testSetUp() override |
| { |
| const angle::PlatformParameters platform = ::testing::get<0>(GetParam()); |
| std::vector<const char *> disabledFeatures; |
| if (::testing::get<1>(GetParam())) |
| { |
| disabledFeatures.push_back("allow_msaa_store_and_resolve"); |
| } |
| disabledFeatures.push_back(nullptr); |
| |
| // Get display. |
| EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, platform.getRenderer(), |
| EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, |
| reinterpret_cast<EGLAttrib>(disabledFeatures.data()), EGL_NONE}; |
| mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, |
| reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs); |
| ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); |
| |
| ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE); |
| |
| // Nexus 5X and 6P fail to eglMakeCurrent with a config they advertise they support. |
| // http://anglebug.com/3464 |
| ANGLE_SKIP_TEST_IF(IsNexus5X()); |
| |
| // Find a config that uses RGBA8 and allows 4x multisampling. |
| const EGLint configAttributes[] = {EGL_SURFACE_TYPE, |
| EGL_WINDOW_BIT, |
| EGL_RED_SIZE, |
| 8, |
| EGL_GREEN_SIZE, |
| 8, |
| EGL_BLUE_SIZE, |
| 8, |
| EGL_ALPHA_SIZE, |
| 8, |
| EGL_DEPTH_SIZE, |
| 24, |
| EGL_STENCIL_SIZE, |
| 8, |
| EGL_SAMPLE_BUFFERS, |
| 1, |
| EGL_SAMPLES, |
| 4, |
| EGL_NONE}; |
| |
| EGLint configCount; |
| EGLConfig multisampledConfig; |
| EGLint ret = |
| eglChooseConfig(mDisplay, configAttributes, &multisampledConfig, 1, &configCount); |
| mMultisampledConfigExists = ret && configCount > 0; |
| |
| if (!mMultisampledConfigExists) |
| { |
| return; |
| } |
| |
| // Create a window, context and surface if multisampling is possible. |
| mOSWindow = OSWindow::New(); |
| mOSWindow->initialize("MultisampleTest", kWindowWidth, kWindowHeight); |
| setWindowVisible(mOSWindow, true); |
| |
| EGLint contextAttributes[] = { |
| EGL_CONTEXT_MAJOR_VERSION_KHR, |
| platform.majorVersion, |
| EGL_CONTEXT_MINOR_VERSION_KHR, |
| platform.minorVersion, |
| EGL_NONE, |
| }; |
| |
| mContext = |
| eglCreateContext(mDisplay, multisampledConfig, EGL_NO_CONTEXT, contextAttributes); |
| ASSERT_TRUE(mContext != EGL_NO_CONTEXT); |
| |
| mSurface = eglCreateWindowSurface(mDisplay, multisampledConfig, |
| mOSWindow->getNativeWindow(), nullptr); |
| ASSERT_EGL_SUCCESS(); |
| |
| eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); |
| ASSERT_EGL_SUCCESS(); |
| } |
| |
| void testTearDown() override |
| { |
| if (mSurface) |
| { |
| eglSwapBuffers(mDisplay, mSurface); |
| } |
| |
| eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| |
| if (mSurface) |
| { |
| eglDestroySurface(mDisplay, mSurface); |
| ASSERT_EGL_SUCCESS(); |
| } |
| |
| if (mContext != EGL_NO_CONTEXT) |
| { |
| eglDestroyContext(mDisplay, mContext); |
| ASSERT_EGL_SUCCESS(); |
| } |
| |
| if (mOSWindow) |
| { |
| OSWindow::Delete(&mOSWindow); |
| } |
| |
| eglTerminate(mDisplay); |
| } |
| |
| void prepareVertexBuffer(GLBuffer &vertexBuffer, |
| const Vector3 *vertices, |
| size_t vertexCount, |
| GLint positionLocation) |
| { |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(*vertices) * vertexCount, vertices, GL_STATIC_DRAW); |
| glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| glEnableVertexAttribArray(positionLocation); |
| } |
| |
| protected: |
| static constexpr int kWindowWidth = 16; |
| static constexpr int kWindowHeight = 8; |
| |
| OSWindow *mOSWindow = nullptr; |
| EGLDisplay mDisplay = EGL_NO_DISPLAY; |
| EGLContext mContext = EGL_NO_CONTEXT; |
| EGLSurface mSurface = EGL_NO_SURFACE; |
| bool mMultisampledConfigExists = false; |
| }; |
| |
| class MultisampleTestES3 : public MultisampleTest |
| {}; |
| |
| // Test point rendering on a multisampled surface. GLES2 section 3.3.1. |
| TEST_P(MultisampleTest, Point) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| // http://anglebug.com/3470 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES()); |
| // http://anglebug.com/5727 |
| ANGLE_SKIP_TEST_IF(IsOzone()); |
| |
| constexpr char kPointsVS[] = R"(precision highp float; |
| attribute vec4 a_position; |
| |
| void main() |
| { |
| gl_PointSize = 3.0; |
| gl_Position = a_position; |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kPointsVS, essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| const GLint positionLocation = glGetAttribLocation(program, "a_position"); |
| |
| GLBuffer vertexBuffer; |
| const Vector3 vertices[1] = {{0.0f, 0.0f, 0.0f}}; |
| prepareVertexBuffer(vertexBuffer, vertices, 1, positionLocation); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDrawArrays(GL_POINTS, 0, 1); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // The center pixels should be all red. |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight / 2 - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2 - 1, kWindowHeight / 2 - 1, GLColor::red); |
| |
| // Border pixels should be between red and black, and not exactly either; corners are darker and |
| // sides are brighter. |
| const GLColor kSideColor = {128, 0, 0, 128}; |
| const GLColor kCornerColor = {64, 0, 0, 64}; |
| constexpr int kErrorMargin = 16; |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 2, kCornerColor, |
| kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 + 1, kCornerColor, |
| kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 2, kCornerColor, |
| kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 + 1, kCornerColor, |
| kErrorMargin); |
| |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2 - 1, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 2, kWindowHeight / 2, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 - 2, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 - 1, kWindowHeight / 2 + 1, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 - 2, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2 + 1, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2 - 1, kSideColor, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2 + 1, kWindowHeight / 2, kSideColor, kErrorMargin); |
| } |
| |
| // Test line rendering on a multisampled surface. GLES2 section 3.4.4. |
| TEST_P(MultisampleTest, Line) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D()); |
| // http://anglebug.com/5727 |
| ANGLE_SKIP_TEST_IF(IsOzone()); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| |
| GLBuffer vertexBuffer; |
| const Vector3 vertices[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}}; |
| prepareVertexBuffer(vertexBuffer, vertices, 2, positionLocation); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDrawArrays(GL_LINES, 0, 2); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // The line goes from left to right at about -17 degrees slope. It renders as such (captured |
| // with renderdoc): |
| // |
| // D D = Dark Red (0.25) or (0.5) |
| // BRA R = Red (1.0) |
| // ARB M = Middle Red (0.75) |
| // D B = Bright Red (1.0 or 0.75) |
| // A = Any red (0.5, 0.75 or 1.0) |
| // |
| // Verify that rendering is done as above. |
| |
| const GLColor kDarkRed = {128, 0, 0, 128}; |
| const GLColor kMidRed = {192, 0, 0, 192}; |
| constexpr int kErrorMargin = 16; |
| constexpr int kLargeMargin = 80; |
| |
| static_assert(kWindowWidth == 16, "Verification code written for 16x8 window"); |
| EXPECT_PIXEL_COLOR_NEAR(0, 2, kDarkRed, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(3, 3, GLColor::red, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(4, 3, GLColor::red, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(6, 3, kMidRed, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(8, 4, kMidRed, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin); |
| } |
| |
| // Test polygon rendering on a multisampled surface. GLES2 section 3.5.3. |
| TEST_P(MultisampleTest, Triangle) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| // http://anglebug.com/3470 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES()); |
| // http://anglebug.com/5727 |
| ANGLE_SKIP_TEST_IF(IsOzone()); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| |
| GLBuffer vertexBuffer; |
| const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}}; |
| prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Top-left pixels should be all red. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red); |
| |
| // Diagonal pixels from bottom-left to top-right are between red and black. Pixels above the |
| // diagonal are red and pixels below it are black. |
| const GLColor kMidRed = {128, 0, 0, 128}; |
| // D3D11 is off by 63 for red (191 instead of 128), where other back-ends get 128 |
| constexpr int kErrorMargin = 64; |
| |
| for (int i = 2; i + 2 < kWindowWidth; i += 2) |
| { |
| int j = kWindowHeight - 1 - (i / 2); |
| EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin); |
| EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack); |
| } |
| } |
| |
| // Test polygon rendering on a multisampled surface. And rendering is interrupted by a compute pass |
| // that converts the index buffer. Make sure the rendering's multisample result is preserved after |
| // interruption. |
| TEST_P(MultisampleTest, ContentPresevedAfterInterruption) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8")); |
| // http://anglebug.com/3470 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES()); |
| // http://anglebug.com/4609 |
| ANGLE_SKIP_TEST_IF(IsD3D11()); |
| // http://anglebug.com/5727 |
| ANGLE_SKIP_TEST_IF(IsOzone()); |
| |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| |
| if (IsGLExtensionEnabled("GL_EXT_discard_framebuffer")) |
| { |
| GLenum attachments[] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT}; |
| glDiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments); |
| } |
| // Draw triangle |
| GLBuffer vertexBuffer; |
| const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}}; |
| prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw a line |
| GLBuffer vertexBuffer2; |
| GLBuffer indexBuffer2; |
| const Vector3 vertices2[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}}; |
| const GLubyte indices2[] = {0, 1}; |
| prepareVertexBuffer(vertexBuffer2, vertices2, 2, positionLocation); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer2); |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW); |
| |
| glDrawElements(GL_LINES, 2, GL_UNSIGNED_BYTE, 0); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Top-left pixels should be all red. |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 4, kWindowHeight / 4, GLColor::red); |
| |
| // Triangle edge: |
| // Diagonal pixels from bottom-left to top-right are between red and black. Pixels above the |
| // diagonal are red and pixels below it are black. |
| { |
| const GLColor kMidRed = {128, 0, 0, 128}; |
| constexpr int kErrorMargin = 16; |
| |
| for (int i = 2; i + 2 < kWindowWidth; i += 2) |
| { |
| // Exclude the middle pixel where the triangle and line cross each other. |
| if (abs(kWindowHeight / 2 - (i / 2)) <= 1) |
| { |
| continue; |
| } |
| int j = kWindowHeight - 1 - (i / 2); |
| EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin); |
| EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack); |
| } |
| } |
| |
| // Line edge: |
| { |
| const GLColor kDarkRed = {128, 0, 0, 128}; |
| constexpr int kErrorMargin = 16; |
| constexpr int kLargeMargin = 80; |
| |
| static_assert(kWindowWidth == 16, "Verification code written for 16x8 window"); |
| // Exclude the triangle region. |
| EXPECT_PIXEL_COLOR_NEAR(11, 4, GLColor::red, kErrorMargin); |
| EXPECT_PIXEL_COLOR_NEAR(12, 4, GLColor::red, kLargeMargin); |
| EXPECT_PIXEL_COLOR_NEAR(15, 5, kDarkRed, kLargeMargin); |
| } |
| } |
| |
| // Test that alpha to coverage is enabled works properly along with early fragment test. |
| TEST_P(MultisampleTest, AlphaToSampleCoverage) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| // http://anglebug.com/5087 |
| ANGLE_SKIP_TEST_IF(IsMetal()); |
| // http://anglebug.com/5727 |
| ANGLE_SKIP_TEST_IF(IsOzone()); |
| |
| constexpr char kFS[] = |
| "precision highp float;\n" |
| "void main()\n" |
| "{\n" |
| " gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0);\n" |
| "}\n"; |
| ANGLE_GL_PROGRAM(transparentRedProgram, essl1_shaders::vs::Simple(), kFS); |
| glUseProgram(transparentRedProgram); |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LESS); |
| glClearDepthf(1.0f); |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // clear to green |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| // This should pass depth test, but because of the alpha to coverage enabled, and alpha is 0, |
| // the fragment should be discarded. If early fragment test is disabled, no depth will be |
| // written. depth buffer should be 1.0. |
| glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); |
| // There was a bug in ANGLE that we are checking sampler coverage enabled or not instead of |
| // alpha to sample coverage enabled or not. This is specically try to trick ANGLE so that it |
| // will enable early fragment test. When early fragment test is accidentally enabled, then the |
| // depth test will occur before fragment shader, and depth buffer maybe written with value |
| // (0.0+1.0)/2.0=0.5. |
| glEnable(GL_SAMPLE_COVERAGE); |
| drawQuad(transparentRedProgram, essl1_shaders::PositionAttrib(), 0.0f); |
| |
| // Now draw with blue color but to test against 0.0f. This should fail depth test |
| glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); |
| glDisable(GL_SAMPLE_COVERAGE); |
| glDepthFunc(GL_GREATER); |
| ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue()); |
| // Zd = 0.5f means (0.5+1.0)/2.0=0.75. Depends on early fragment on or off this will pass or |
| // fail depth test. |
| drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that resolve from multisample default framebuffer works. |
| TEST_P(MultisampleTestES3, ResolveToFBO) |
| { |
| ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists); |
| |
| GLTexture resolveTexture; |
| glBindTexture(GL_TEXTURE_2D, resolveTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWindowWidth, kWindowHeight, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| GLFramebuffer resolveFBO; |
| glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0); |
| |
| // Clear the default framebuffer |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| glClearColor(0.25, 0.5, 0.75, 0.25); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Resolve into FBO |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); |
| glClearColor(1, 0, 0, 1); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glBlitFramebuffer(0, 0, kWindowWidth, kWindowHeight, 0, 0, kWindowWidth, kWindowHeight, |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| const GLColor kResult = GLColor(63, 127, 191, 63); |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO); |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, kResult, 1); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, 0, kResult, 1); |
| EXPECT_PIXEL_COLOR_NEAR(0, kWindowHeight - 1, kResult, 1); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth - 1, kWindowHeight - 1, kResult, 1); |
| EXPECT_PIXEL_COLOR_NEAR(kWindowWidth / 2, kWindowHeight / 2, kResult, 1); |
| } |
| |
| ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest, |
| PrintToStringParamName, |
| testing::Values(false), |
| WithNoFixture(ES2_D3D11()), |
| WithNoFixture(ES3_D3D11()), |
| WithNoFixture(ES31_D3D11()), |
| WithNoFixture(ES2_METAL()), |
| WithNoFixture(ES2_OPENGL()), |
| WithNoFixture(ES3_OPENGL()), |
| WithNoFixture(ES31_OPENGL()), |
| WithNoFixture(ES2_OPENGLES()), |
| WithNoFixture(ES3_OPENGLES()), |
| WithNoFixture(ES31_OPENGLES()), |
| WithNoFixture(ES2_VULKAN()), |
| WithNoFixture(ES3_VULKAN()), |
| WithNoFixture(ES31_VULKAN())); |
| |
| namespace store_and_resolve_feature_off |
| { |
| // Simulate missing msaa auto resolve feature in Metal. |
| ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTest, |
| PrintToStringParamName, |
| testing::Values(true), |
| WithNoFixture(ES2_METAL())); |
| } // namespace store_and_resolve_feature_off |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultisampleTestES3); |
| ANGLE_INSTANTIATE_TEST_COMBINE_1(MultisampleTestES3, |
| PrintToStringParamName, |
| testing::Values(false), |
| WithNoFixture(ES3_D3D11()), |
| WithNoFixture(ES31_D3D11()), |
| WithNoFixture(ES3_OPENGL()), |
| WithNoFixture(ES31_OPENGL()), |
| WithNoFixture(ES3_OPENGLES()), |
| WithNoFixture(ES31_OPENGLES()), |
| WithNoFixture(ES3_VULKAN()), |
| WithNoFixture(ES31_VULKAN()), |
| WithNoFixture(ES3_METAL())); |
| } // anonymous namespace |