• 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 class MultisampleTest : public ANGLETest
20 {
21   protected:
testSetUp()22     void testSetUp() override
23     {
24         // Get display.
25         EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
26         mDisplay           = eglGetPlatformDisplayEXT(
27             EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
28         ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
29 
30         ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
31 
32         // Nexus 5X and 6P fail to eglMakeCurrent with a config they advertise they support.
33         // http://anglebug.com/3464
34         ANGLE_SKIP_TEST_IF(IsNexus5X() || IsNexus6P());
35 
36         // Find a config that uses RGBA8 and allows 4x multisampling.
37         const EGLint configAttributes[] = {
38             EGL_RED_SIZE,       8, EGL_GREEN_SIZE, 8,  EGL_BLUE_SIZE,    8,
39             EGL_ALPHA_SIZE,     8, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8,
40             EGL_SAMPLE_BUFFERS, 1, EGL_SAMPLES,    4,  EGL_NONE};
41 
42         EGLint configCount;
43         EGLConfig multisampledConfig;
44         EGLint ret =
45             eglChooseConfig(mDisplay, configAttributes, &multisampledConfig, 1, &configCount);
46         mMultisampledConfigExists = ret && configCount > 0;
47 
48         if (!mMultisampledConfigExists)
49         {
50             return;
51         }
52 
53         // Create a window, context and surface if multisampling is possible.
54         mOSWindow = OSWindow::New();
55         mOSWindow->initialize("MultisampleTest", kWindowSize, kWindowSize);
56         setWindowVisible(mOSWindow, true);
57 
58         EGLint contextAttributes[] = {
59             EGL_CONTEXT_MAJOR_VERSION_KHR,
60             GetParam().majorVersion,
61             EGL_CONTEXT_MINOR_VERSION_KHR,
62             GetParam().minorVersion,
63             EGL_NONE,
64         };
65 
66         mContext =
67             eglCreateContext(mDisplay, multisampledConfig, EGL_NO_CONTEXT, contextAttributes);
68         ASSERT_TRUE(mContext != EGL_NO_CONTEXT);
69 
70         mSurface = eglCreateWindowSurface(mDisplay, multisampledConfig,
71                                           mOSWindow->getNativeWindow(), nullptr);
72         ASSERT_EGL_SUCCESS();
73 
74         eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
75         ASSERT_EGL_SUCCESS();
76     }
77 
testTearDown()78     void testTearDown() override
79     {
80         if (mSurface)
81         {
82             eglSwapBuffers(mDisplay, mSurface);
83         }
84 
85         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
86 
87         if (mSurface)
88         {
89             eglDestroySurface(mDisplay, mSurface);
90             ASSERT_EGL_SUCCESS();
91         }
92 
93         if (mContext != EGL_NO_CONTEXT)
94         {
95             eglDestroyContext(mDisplay, mContext);
96             ASSERT_EGL_SUCCESS();
97         }
98 
99         if (mOSWindow)
100         {
101             OSWindow::Delete(&mOSWindow);
102         }
103 
104         eglTerminate(mDisplay);
105     }
106 
prepareVertexBuffer(GLBuffer & vertexBuffer,const Vector3 * vertices,size_t vertexCount,GLint positionLocation)107     void prepareVertexBuffer(GLBuffer &vertexBuffer,
108                              const Vector3 *vertices,
109                              size_t vertexCount,
110                              GLint positionLocation)
111     {
112         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
113         glBufferData(GL_ARRAY_BUFFER, sizeof(*vertices) * vertexCount, vertices, GL_STATIC_DRAW);
114         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
115         glEnableVertexAttribArray(positionLocation);
116     }
117 
118   protected:
119     static constexpr int kWindowSize = 8;
120 
121     OSWindow *mOSWindow            = nullptr;
122     EGLDisplay mDisplay            = EGL_NO_DISPLAY;
123     EGLContext mContext            = EGL_NO_CONTEXT;
124     EGLSurface mSurface            = EGL_NO_SURFACE;
125     bool mMultisampledConfigExists = false;
126 };
127 
128 // Test point rendering on a multisampled surface.  GLES2 section 3.3.1.
TEST_P(MultisampleTest,Point)129 TEST_P(MultisampleTest, Point)
130 {
131     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
132     // http://anglebug.com/3470
133     ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
134 
135     constexpr char kPointsVS[] = R"(precision highp float;
136 attribute vec4 a_position;
137 
138 void main()
139 {
140     gl_PointSize = 3.0;
141     gl_Position = a_position;
142 })";
143 
144     ANGLE_GL_PROGRAM(program, kPointsVS, essl1_shaders::fs::Red());
145     glUseProgram(program);
146     const GLint positionLocation = glGetAttribLocation(program, "a_position");
147 
148     GLBuffer vertexBuffer;
149     const Vector3 vertices[1] = {{0.0f, 0.0f, 0.0f}};
150     prepareVertexBuffer(vertexBuffer, vertices, 1, positionLocation);
151 
152     glClear(GL_COLOR_BUFFER_BIT);
153     glDrawArrays(GL_POINTS, 0, 1);
154 
155     ASSERT_GL_NO_ERROR();
156 
157     // The center pixels should be all red.
158     EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::red);
159     EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2 - 1, kWindowSize / 2, GLColor::red);
160     EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2 - 1, GLColor::red);
161     EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2 - 1, kWindowSize / 2 - 1, GLColor::red);
162 
163     // Border pixels should be between red and black, and not exactly either; corners are darker and
164     // sides are brighter.
165     const GLColor kSideColor   = {128, 0, 0, 128};
166     const GLColor kCornerColor = {64, 0, 0, 64};
167     constexpr int kErrorMargin = 16;
168     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 2, kWindowSize / 2 - 2, kCornerColor, kErrorMargin);
169     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 2, kWindowSize / 2 + 1, kCornerColor, kErrorMargin);
170     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 + 1, kWindowSize / 2 - 2, kCornerColor, kErrorMargin);
171     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 + 1, kWindowSize / 2 + 1, kCornerColor, kErrorMargin);
172 
173     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 2, kWindowSize / 2 - 1, kSideColor, kErrorMargin);
174     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 2, kWindowSize / 2, kSideColor, kErrorMargin);
175     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 1, kWindowSize / 2 - 2, kSideColor, kErrorMargin);
176     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 - 1, kWindowSize / 2 + 1, kSideColor, kErrorMargin);
177     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2, kWindowSize / 2 - 2, kSideColor, kErrorMargin);
178     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2, kWindowSize / 2 + 1, kSideColor, kErrorMargin);
179     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 + 1, kWindowSize / 2 - 1, kSideColor, kErrorMargin);
180     EXPECT_PIXEL_COLOR_NEAR(kWindowSize / 2 + 1, kWindowSize / 2, kSideColor, kErrorMargin);
181 }
182 
183 // Test line rendering on a multisampled surface.  GLES2 section 3.4.4.
TEST_P(MultisampleTest,Line)184 TEST_P(MultisampleTest, Line)
185 {
186     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
187     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
188 
189     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
190     glUseProgram(program);
191     const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
192 
193     GLBuffer vertexBuffer;
194     const Vector3 vertices[2] = {{-1.0f, -0.3f, 0.0f}, {1.0f, 0.3f, 0.0f}};
195     prepareVertexBuffer(vertexBuffer, vertices, 2, positionLocation);
196 
197     glClear(GL_COLOR_BUFFER_BIT);
198     glDrawArrays(GL_LINES, 0, 2);
199 
200     ASSERT_GL_NO_ERROR();
201 
202     // The line goes from left to right at about -17 degrees slope.  It renders as such (captured
203     // with renderdoc):
204     //
205     // D                    D = Dark Red (0.25) or (0.5)
206     //  BRA                 R = Red (1.0)
207     //     ARB              M = Middle Red (0.75)
208     //        D             B = Bright Red (1.0 or 0.75)
209     //                      A = Any red (0.5, 0.75 or 1.0)
210     //
211     // Verify that rendering is done as above.
212 
213     const GLColor kDarkRed     = {128, 0, 0, 128};
214     const GLColor kMidRed      = {192, 0, 0, 192};
215     constexpr int kErrorMargin = 16;
216     constexpr int kLargeMargin = 80;
217 
218     static_assert(kWindowSize == 8, "Verification code written for 8x8 window");
219     EXPECT_PIXEL_COLOR_NEAR(0, 2, kDarkRed, kLargeMargin);
220     EXPECT_PIXEL_COLOR_NEAR(1, 3, GLColor::red, kLargeMargin);
221     EXPECT_PIXEL_COLOR_NEAR(2, 3, GLColor::red, kErrorMargin);
222     EXPECT_PIXEL_COLOR_NEAR(3, 3, kMidRed, kLargeMargin);
223     EXPECT_PIXEL_COLOR_NEAR(4, 4, kMidRed, kLargeMargin);
224     EXPECT_PIXEL_COLOR_NEAR(5, 4, GLColor::red, kErrorMargin);
225     EXPECT_PIXEL_COLOR_NEAR(6, 4, GLColor::red, kLargeMargin);
226     EXPECT_PIXEL_COLOR_NEAR(7, 5, kDarkRed, kLargeMargin);
227 }
228 
229 // Test polygon rendering on a multisampled surface.  GLES2 section 3.5.3.
TEST_P(MultisampleTest,Triangle)230 TEST_P(MultisampleTest, Triangle)
231 {
232     ANGLE_SKIP_TEST_IF(!mMultisampledConfigExists);
233     // http://anglebug.com/3470
234     ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIAShield() && IsOpenGLES());
235 
236     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
237     glUseProgram(program);
238     const GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
239 
240     GLBuffer vertexBuffer;
241     const Vector3 vertices[3] = {{-1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}};
242     prepareVertexBuffer(vertexBuffer, vertices, 3, positionLocation);
243 
244     glClear(GL_COLOR_BUFFER_BIT);
245     glDrawArrays(GL_TRIANGLES, 0, 3);
246 
247     ASSERT_GL_NO_ERROR();
248 
249     // Top-left pixels should be all red.
250     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
251     EXPECT_PIXEL_COLOR_EQ(kWindowSize / 4, kWindowSize / 4, GLColor::red);
252 
253     // Diagonal pixels from bottom-left to top-right are between red and black.  Pixels above the
254     // diagonal are red and pixels below it are black.
255     const GLColor kMidRed      = {128, 0, 0, 128};
256     constexpr int kErrorMargin = 16;
257 
258     for (int i = 1; i + 1 < kWindowSize; ++i)
259     {
260         int j = kWindowSize - 1 - i;
261         EXPECT_PIXEL_COLOR_NEAR(i, j, kMidRed, kErrorMargin);
262         EXPECT_PIXEL_COLOR_EQ(i, j - 1, GLColor::red);
263         EXPECT_PIXEL_COLOR_EQ(i, j + 1, GLColor::transparentBlack);
264     }
265 }
266 
267 ANGLE_INSTANTIATE_TEST(MultisampleTest,
268                        WithNoFixture(ES2_D3D11()),
269                        WithNoFixture(ES3_D3D11()),
270                        WithNoFixture(ES31_D3D11()),
271                        WithNoFixture(ES2_OPENGL()),
272                        WithNoFixture(ES3_OPENGL()),
273                        WithNoFixture(ES31_OPENGL()),
274                        WithNoFixture(ES2_OPENGLES()),
275                        WithNoFixture(ES3_OPENGLES()),
276                        WithNoFixture(ES31_OPENGLES()),
277                        WithNoFixture(ES2_VULKAN()),
278                        WithNoFixture(ES3_VULKAN()));
279 }  // anonymous namespace
280