1 //
2 // Copyright 2015 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 // MultisampleCompatibilityTest.cpp:
7 // Tests for the EXT_multisample_compatibility extension.
8 //
9
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 const GLint kWidth = 64;
19 const GLint kHeight = 64;
20
21 // test drawing with GL_MULTISAMPLE_EXT enabled/disabled.
22 class EXTMultisampleCompatibilityTest : public ANGLETest
23 {
24
25 protected:
EXTMultisampleCompatibilityTest()26 EXTMultisampleCompatibilityTest()
27 {
28 setWindowWidth(64);
29 setWindowHeight(64);
30 setConfigRedBits(8);
31 setConfigBlueBits(8);
32 setConfigAlphaBits(8);
33 }
34
testSetUp()35 void testSetUp() override
36 {
37 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
38
39 GLuint position_loc = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
40 mColorLoc = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
41
42 glGenBuffers(1, &mVBO);
43 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
44 static float vertices[] = {
45 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
46 -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
47 };
48 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
49 glEnableVertexAttribArray(position_loc);
50 glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
51 }
52
testTearDown()53 void testTearDown() override
54 {
55 glDeleteBuffers(1, &mVBO);
56 glDeleteProgram(mProgram);
57 }
58
prepareForDraw()59 void prepareForDraw()
60 {
61 // Create a sample buffer.
62 GLsizei num_samples = 4, max_samples = 0;
63 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
64 num_samples = std::min(num_samples, max_samples);
65
66 glGenRenderbuffers(1, &mSampleRB);
67 glBindRenderbuffer(GL_RENDERBUFFER, mSampleRB);
68 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, num_samples, GL_RGBA8_OES, kWidth,
69 kHeight);
70 GLint param = 0;
71 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, ¶m);
72 EXPECT_GE(param, num_samples);
73
74 glGenFramebuffers(1, &mSampleFBO);
75 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
76 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleRB);
77 EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
78 glCheckFramebufferStatus(GL_FRAMEBUFFER));
79 glBindFramebuffer(GL_FRAMEBUFFER, 0);
80
81 // Create another FBO to resolve the multisample buffer into.
82 glGenTextures(1, &mResolveTex);
83 glBindTexture(GL_TEXTURE_2D, mResolveTex);
84 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
85 nullptr);
86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
87 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
88 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
90 glGenFramebuffers(1, &mResolveFBO);
91 glBindFramebuffer(GL_FRAMEBUFFER, mResolveFBO);
92 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mResolveTex, 0);
93 EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
94 glCheckFramebufferStatus(GL_FRAMEBUFFER));
95
96 glUseProgram(mProgram);
97 glViewport(0, 0, kWidth, kHeight);
98 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
99 glEnable(GL_BLEND);
100 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
101 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
102 glClear(GL_COLOR_BUFFER_BIT);
103 }
104
prepareForVerify()105 void prepareForVerify()
106 {
107 // Resolve.
108 glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleFBO);
109 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFBO);
110 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
111 glClear(GL_COLOR_BUFFER_BIT);
112 glBlitFramebufferANGLE(0, 0, kWidth, kHeight, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT,
113 GL_NEAREST);
114 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFBO);
115
116 ASSERT_GL_NO_ERROR();
117 }
118
cleanup()119 void cleanup()
120 {
121 glBindFramebuffer(GL_FRAMEBUFFER, 0);
122 glDeleteFramebuffers(1, &mResolveFBO);
123 glDeleteFramebuffers(1, &mSampleFBO);
124 glDeleteTextures(1, &mResolveTex);
125 glDeleteRenderbuffers(1, &mSampleRB);
126
127 ASSERT_GL_NO_ERROR();
128 }
129
isApplicable() const130 bool isApplicable() const
131 {
132 return IsGLExtensionEnabled("GL_EXT_multisample_compatibility") &&
133 IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample") &&
134 IsGLExtensionEnabled("GL_OES_rgb8_rgba8") && !IsAMD();
135 }
136 GLuint mSampleFBO;
137 GLuint mResolveFBO;
138 GLuint mSampleRB;
139 GLuint mResolveTex;
140
141 GLuint mColorLoc;
142 GLuint mProgram;
143 GLuint mVBO;
144 };
145
146 } // namespace
147
148 // Test simple state tracking
TEST_P(EXTMultisampleCompatibilityTest,TestStateTracking)149 TEST_P(EXTMultisampleCompatibilityTest, TestStateTracking)
150 {
151 if (!isApplicable())
152 return;
153
154 EXPECT_TRUE(glIsEnabled(GL_MULTISAMPLE_EXT));
155 glDisable(GL_MULTISAMPLE_EXT);
156 EXPECT_FALSE(glIsEnabled(GL_MULTISAMPLE_EXT));
157 glEnable(GL_MULTISAMPLE_EXT);
158 EXPECT_TRUE(glIsEnabled(GL_MULTISAMPLE_EXT));
159
160 EXPECT_FALSE(glIsEnabled(GL_SAMPLE_ALPHA_TO_ONE_EXT));
161 glEnable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
162 EXPECT_TRUE(glIsEnabled(GL_SAMPLE_ALPHA_TO_ONE_EXT));
163 glDisable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
164 EXPECT_FALSE(glIsEnabled(GL_SAMPLE_ALPHA_TO_ONE_EXT));
165
166 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
167 }
168
169 // Test that disabling GL_MULTISAMPLE_EXT is handled correctly.
TEST_P(EXTMultisampleCompatibilityTest,DrawAndResolve)170 TEST_P(EXTMultisampleCompatibilityTest, DrawAndResolve)
171 {
172 if (!isApplicable())
173 return;
174
175 // http://anglebug.com/5270
176 ANGLE_SKIP_TEST_IF(IsOSX() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
177
178 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
179 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
180 static const float kRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
181
182 // Different drivers seem to behave differently with respect to resulting
183 // values. These might be due to different MSAA sample counts causing
184 // different samples to hit. Other option is driver bugs. Just test that
185 // disabling multisample causes a difference.
186 std::unique_ptr<uint8_t[]> results[3];
187 const GLint kResultSize = kWidth * kHeight * 4;
188 for (int pass = 0; pass < 3; pass++)
189 {
190 prepareForDraw();
191 // Green: from top right to bottom left.
192 glUniform4fv(mColorLoc, 1, kGreen);
193 glDrawArrays(GL_TRIANGLES, 0, 3);
194
195 // Blue: from top left to bottom right.
196 glUniform4fv(mColorLoc, 1, kBlue);
197 glDrawArrays(GL_TRIANGLES, 3, 3);
198
199 // Red, with and without MSAA: from bottom left to top right.
200 if (pass == 1)
201 {
202 glDisable(GL_MULTISAMPLE_EXT);
203 }
204 glUniform4fv(mColorLoc, 1, kRed);
205 glDrawArrays(GL_TRIANGLES, 6, 3);
206 if (pass == 1)
207 {
208 glEnable(GL_MULTISAMPLE_EXT);
209 }
210 prepareForVerify();
211 results[pass].reset(new uint8_t[kResultSize]);
212 memset(results[pass].get(), 123u, kResultSize);
213 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
214
215 cleanup();
216 }
217 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
218 // Verify that rendering is deterministic, so that the pass above does not
219 // come from non-deterministic rendering.
220 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
221 }
222
223 // Test that enabling GL_SAMPLE_ALPHA_TO_ONE_EXT affects rendering.
TEST_P(EXTMultisampleCompatibilityTest,DrawAlphaOneAndResolve)224 TEST_P(EXTMultisampleCompatibilityTest, DrawAlphaOneAndResolve)
225 {
226 if (!isApplicable())
227 return;
228
229 // SAMPLE_ALPHA_TO_ONE is specified to transform alpha values of
230 // covered samples to 1.0. In order to detect it, we use non-1.0
231 // alpha.
232 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 0.5f};
233 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 0.5f};
234 static const float kRed[] = {1.0f, 0.0f, 0.0f, 0.5f};
235
236 // Different drivers seem to behave differently with respect to resulting
237 // alpha value. These might be due to different MSAA sample counts causing
238 // different samples to hit. Other option is driver bugs. Testing exact or
239 // even approximate sample values is not that easy. Thus, just test
240 // representative positions which have fractional pixels, inspecting that
241 // normal rendering is different to SAMPLE_ALPHA_TO_ONE rendering.
242 std::unique_ptr<uint8_t[]> results[3];
243 const GLint kResultSize = kWidth * kHeight * 4;
244
245 for (int pass = 0; pass < 3; ++pass)
246 {
247 prepareForDraw();
248 if (pass == 1)
249 {
250 glEnable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
251 }
252 glEnable(GL_MULTISAMPLE_EXT);
253 glUniform4fv(mColorLoc, 1, kGreen);
254 glDrawArrays(GL_TRIANGLES, 0, 3);
255
256 glUniform4fv(mColorLoc, 1, kBlue);
257 glDrawArrays(GL_TRIANGLES, 3, 3);
258
259 glDisable(GL_MULTISAMPLE_EXT);
260 glUniform4fv(mColorLoc, 1, kRed);
261 glDrawArrays(GL_TRIANGLES, 6, 3);
262
263 prepareForVerify();
264 results[pass].reset(new uint8_t[kResultSize]);
265 memset(results[pass].get(), 123u, kResultSize);
266 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
267 if (pass == 1)
268 {
269 glDisable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
270 }
271
272 cleanup();
273 }
274 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
275 // Verify that rendering is deterministic, so that the pass above does not
276 // come from non-deterministic rendering.
277 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
278 }
279
280 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(EXTMultisampleCompatibilityTest);
281
282 class MultisampleCompatibilityTest : public ANGLETest
283 {
284
285 protected:
MultisampleCompatibilityTest()286 MultisampleCompatibilityTest()
287 {
288 setWindowWidth(64);
289 setWindowHeight(64);
290 setConfigRedBits(8);
291 setConfigBlueBits(8);
292 setConfigAlphaBits(8);
293 }
294
prepareForDraw(GLsizei numSamples)295 void prepareForDraw(GLsizei numSamples)
296 {
297 // Create a sample buffer.
298 glGenRenderbuffers(1, &mSampleRB);
299 glBindRenderbuffer(GL_RENDERBUFFER, mSampleRB);
300 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, numSamples, GL_RGBA8, kWidth,
301 kHeight);
302 GLint param = 0;
303 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, ¶m);
304 EXPECT_GE(param, numSamples);
305 glGenFramebuffers(1, &mSampleFBO);
306 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
307 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleRB);
308 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
309 glBindFramebuffer(GL_FRAMEBUFFER, 0);
310 // Create another FBO to resolve the multisample buffer into.
311 glGenTextures(1, &mResolveTex);
312 glBindTexture(GL_TEXTURE_2D, mResolveTex);
313 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
314 nullptr);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
319 glGenFramebuffers(1, &mResolveFBO);
320 glBindFramebuffer(GL_FRAMEBUFFER, mResolveFBO);
321 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mResolveTex, 0);
322 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
323 glViewport(0, 0, kWidth, kHeight);
324 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
325 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
326 glClear(GL_COLOR_BUFFER_BIT);
327 ASSERT_GL_NO_ERROR();
328 }
329
prepareForVerify()330 void prepareForVerify()
331 {
332 // Resolve.
333 glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleFBO);
334 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFBO);
335 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
336 glClear(GL_COLOR_BUFFER_BIT);
337 glBlitFramebufferANGLE(0, 0, kWidth, kHeight, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT,
338 GL_NEAREST);
339 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFBO);
340
341 ASSERT_GL_NO_ERROR();
342 }
343
cleanup()344 void cleanup()
345 {
346 glBindFramebuffer(GL_FRAMEBUFFER, 0);
347 glDeleteFramebuffers(1, &mResolveFBO);
348 glDeleteFramebuffers(1, &mSampleFBO);
349 glDeleteTextures(1, &mResolveTex);
350 glDeleteRenderbuffers(1, &mSampleRB);
351
352 ASSERT_GL_NO_ERROR();
353 }
354
isApplicable() const355 bool isApplicable() const
356 {
357 return IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample") &&
358 IsGLExtensionEnabled("GL_OES_rgb8_rgba8");
359 }
360
361 GLuint mSampleFBO;
362 GLuint mResolveFBO;
363 GLuint mSampleRB;
364 GLuint mResolveTex;
365 };
366
367 // Test that enabling GL_SAMPLE_COVERAGE affects rendering.
TEST_P(MultisampleCompatibilityTest,DrawCoverageAndResolve)368 TEST_P(MultisampleCompatibilityTest, DrawCoverageAndResolve)
369 {
370 if (!isApplicable())
371 return;
372
373 // TODO: Figure out why this fails on Android.
374 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
375
376 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
377
378 GLsizei maxSamples = 0;
379 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
380 int iterationCount = maxSamples + 1;
381 for (int samples = 1; samples < iterationCount; samples++)
382 {
383 prepareForDraw(samples);
384 glEnable(GL_SAMPLE_COVERAGE);
385 glSampleCoverage(1.0, false);
386 drawQuad(drawRed.get(), essl1_shaders::PositionAttrib(), 0.5f);
387
388 prepareForVerify();
389 GLsizei pixelCount = kWidth * kHeight;
390 std::vector<GLColor> actual(pixelCount, GLColor::black);
391 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, actual.data());
392 glDisable(GL_SAMPLE_COVERAGE);
393 cleanup();
394
395 std::vector<GLColor> expected(pixelCount, GLColor::red);
396 EXPECT_EQ(expected, actual);
397 }
398 }
399
400 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MultisampleCompatibilityTest);
401